advanced · review

Review: The “Internal” Rename That Broke Three Partners

Three partner integrations broke on Monday: dashboards render blank order states and one partner's automation cancelled valid orders. The team is reviewing how a “refactor-only” change shipped to production consumers.

Evidence

PR #4182 "Consistency: rename status->state across order responses"  (merged Friday 16:40)
  - "status" removed from GET /orders/{id}, GET /orders list, order webhooks
  - reviewer comment: "API is internal-ish, partners use the SDK anyway" -> approved

reality check:
  gateway logs: 3 partner API keys hitting /orders directly (no SDK), ~410K req/day reading .status
  partner B automation: order.status == undefined -> treated as "stale" -> auto-cancel
  changelog entry: none    deprecation header: none    consumer usage query: never run
  rollback: not clean — new mobile release already depends on "state"

Investigate

Inspect Change classification
A field rename is a removal plus an addition; removal of a read field is on every breaking-change list. The PR template had no compatibility question to force that classification.
Inspect The “internal” assumption
The belief that consumers were SDK-only was checkable and false: gateway telemetry shows three partners parsing raw JSON — nobody queried per-field consumer usage before merging.
Inspect Process and sequencing
The rename shipped as a single atomic swap with no dual-serve period, no deprecation signal, no changelog, and on a Friday — every stage that could have caught or softened it was skipped.
Inspect Failure mode severity
Partner B's automation interpreted the missing field as a state (“stale”) rather than an error and destroyed data — silent breaks compound in consumers' logic, not just their rendering.