fix(review HIGH 3): restore statusUrl on RunScenarioResponse + document 202→200 wire break (#3207)

Commit 7 silently shifted /api/scenario/v1/run-scenario's response
contract in two ways that the commit message covered only partially:

1. HTTP 202 Accepted → HTTP 200 OK
2. Dropped `statusUrl` string from the response body

The `statusUrl` drop was mentioned as "unused by SupplyChainPanel" but
not framed as a contract change. The 202 → 200 shift was not mentioned
at all. This is a same-version (v1 → v1) migration, so external callers
that key off either signal — `response.status === 202` or
`response.body.statusUrl` — silently branch incorrectly.

Evaluated options:
  (a) sebuf per-RPC status-code config — not available. sebuf's
      HttpConfig only models `path` and `method`; no status annotation.
  (b) Bump to scenario/v2 — judged heavier than the break itself for
      a single status-code shift. No in-repo caller uses 202 or
      statusUrl; the docs-level impact is containable.
  (c) Accept the break, document explicitly, partially restore.

Took option (c):

- Restored `statusUrl` in the proto (new field `string status_url = 3`
  on RunScenarioResponse). Server computes
  `/api/scenario/v1/get-scenario-status?jobId=<encoded job_id>` and
  populates it on every successful enqueue. External callers that
  followed this URL keep working unchanged.
- 202 → 200 is not recoverable inside the sebuf generator, so it is
  called out explicitly in two places:
    - docs/api-scenarios.mdx now includes a prominent `<Warning>` block
      documenting the v1→v1 contract shift + the suggested migration
      (branch on response body shape, not HTTP status).
    - RunScenarioResponse proto comment explains why 200 is the new
      success status on enqueue.
  OpenAPI bundle regenerated to reflect the restored statusUrl field.

- Regression test added in tests/scenario-handler.test.mjs pinning
  `statusUrl` to the exact URL-encoded shape — locks the invariant so
  a future proto rename or handler refactor can't silently drop it
  again.

From koala73 review (#3242 second-pass, HIGH new #3).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sebastien Melki
2026-04-21 22:56:53 +03:00
parent 209e369585
commit 23c821a189
8 changed files with 58 additions and 3 deletions

View File

@@ -165,9 +165,24 @@ components:
status:
type: string
description: Always "pending" at enqueue time.
statusUrl:
type: string
description: |-
Convenience URL the caller can use to poll this job's status.
Server-computed as `/api/scenario/v1/get-scenario-status?jobId=<job_id>`.
Restored after the v1 → v1 sebuf migration because external callers
may key off this field.
description: |-
RunScenarioResponse carries the enqueued job id. Clients poll
GetScenarioStatus with this id until status != "pending".
NOTE: the legacy (pre-sebuf) endpoint returned HTTP 202 Accepted on
enqueue; the sebuf-generated server emits 200 OK for all successful
responses (no per-RPC status-code configuration is available in the
current sebuf HTTP annotations). The 202 → 200 shift on a same-version
(v1 → v1) migration is called out in docs/api-scenarios.mdx and the
OpenAPI bundle; external consumers keying off `response.status === 202`
need to branch on response body shape instead.
GetScenarioStatusRequest:
type: object
properties: