fix(spec): mirror FrameStatusKind/FrameStatusKinds into openapi.yaml #26
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/mirror-frame-status-kinds-into-openapi"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Scope
frame_wire1.5 addedFrameStatusKindandFrameStatusKindstoschemas/frame_wire.json— and only there. For two minor versions the contract's twodocuments disagreed about what the contract contains: 40 of 42
$defswere mirroredin
openapi.yaml'scomponents.schemas, and these two were not.Nothing here could see it.
test_the_two_spec_files_agreeasks about exactly twonames,
FrameStatusandFrameType, because those are what the generator owns. The broadquestion — is every
$defmirrored — was never asked, so this suite stayed greenthroughout (46 passed, 1 xfailed on
maintoday).It was caught downstream, and late.
ritual-enginevendors this contract, and itsframe-wire-contractcrate does assert full$defsparity. But it runs against avendored snapshot, and that snapshot was two minor versions behind — so it was
asserting parity for 1.4 and passing. The disagreement surfaced only when the snapshot was
refreshed, days after 1.6 merged, and it surfaced as two red tests in a re-vendor PR that
had copied everything correctly.
What the gap cost.
FrameStatusKindscarriesis_terminal,is_active_pickup,is_pre_admissionandsurfaces_in_queueper status as a generatedconst, and its owndescription says why it exists:
A client generated from
openapi.yamlcould not reach any of it, and would have towrite exactly that switch. That is not hypothetical:
ritual-enginehad written it eighttimes over, in four mutually inconsistent lists, none matching the table — see
ritual-engine#1157, measured the same week.What this changes
openapi.yaml0.69.0 → 0.70.0. Additive: two new components, no endpoint, request orresponse change.
The mirrored copies were generated from
frame_wire.jsonwith$defsrefs repointedat
components/schemas, not retyped — so they are identical up to the ref prefix byconstruction rather than by proofreading.
Two tests, each mutation-checked:
test_every_wire_def_is_mirrored_in_openapi$defexists incomponents.schemasFrameStatusKindfromopenapi.yamltest_the_generated_status_metadata_is_identical_in_both_documentsis_terminalinopenapi.yaml's copyThe first has no documented-gap set, deliberately — unlike the
ForgeBlockunion,which lags for a stated reason and is pinned as such. A
$defon the wire thatopenapi.yamldoes not define means a client generated from one document cannot parsewhat a server generated from the other emits, and there is no version of that worth
tolerating.
The second exists because
constis regenerated fromcore.frame_status_kinds.Without it, this PR would be a one-time fix that drifts again the next time a row is added
to that table — the same class as the five-versus-nine
frame_typedisagreement thismodule's docstring already records.
Testing
Both new tests were confirmed red before the fix —
test_every_wire_def_is_mirrored_in_openapiwas written first and failed with exactly
schemas/frame_wire.json defines ['FrameStatusKind', 'FrameStatusKinds'], openapi.yaml does not, which is the whole reasonthis PR exists.
openapi.yamlre-parses andcomponents.schemasgoes 167 → 169.Deliberately NOT added: a broad content-parity test, and the reason is written into
the test file rather than left as an omission. The two documents express the same schemas
differently — OpenAPI wraps a bare
$refinallOf, folded scalars add trailing newlines— so 36 of the 42 shared defs differ textually while agreeing semantically. I measured
that rather than assuming it, and confirmed whitespace normalisation alone does not close
it. Comparing them properly needs the reducer in
ritual-engine'sframe-wire-contract/tests/parity.rs, which collapses those wrappers. Half-porting ithere would be a weak test wearing a strong name, which is the failure mode this contract's
own history keeps producing.
One self-correction worth recording: the first draft of
test_the_status_metadata_const_covers_every_listed_statusassertedkinds == sorted(kinds, key=lambda s: kinds.index(s))— which always holds. A check thatcannot fail was removed rather than left in; the surviving assertion compares the
const'sstatus set against the
FrameStatusenum, which can and does differ.Impact Statement
No breaking change. Two components added; nothing removed, renamed or re-typed. A
client generated from 0.69.0 keeps working — it simply had no way to name these schemas.
Who should regenerate: any client generated from
openapi.yamlthat wants the statusmetadata. Clients generated from
schemas/frame_wire.jsonalready had it.This unblocks a
ritual-enginere-vendor that is currently red on these two tests.That PR copies this repo verbatim, so it cannot be fixed on its side — editing a vendored
file is what
MANIFEST.sha256exists to catch, and the vendoring README forbids it byname. The order is: merge this, then re-vendor at the resulting
maincommit.What this does not touch:
schemas/frame_wire.jsonandschemas/forge_block.jsonareunchanged, so
frame_wirestays 1.6 andforge_blockstays 1.3. TheForgeBlockunion'sdocumented 15-versus-20 mirror gap is untouched and still pinned by its own test — it lags
for a stated reason, which is a different thing from lagging unnoticed.