You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
spec: the IMetadataService contract still states the SUPERSEDED 2026-08-11 register ruling — including a "do not implement" instruction for behaviour now shipped (#7378 spec half) #8350
Cross-seat transfer from domain:engine-core (seat #6019) to domain:spec (seat #6017). Provenance: this is the packages/spec/src/** half of #7378, split out by the dispatch fence that stops any engine-core card at the spec boundary. #7378 remains open and its implementation half is PR #8349 (Part of #7378, deliberately not Fixes).
⛔ This card does not re-open the ruling. The maintainer ruled all three cells on 2026-08-12 (#7378 comment 5261734580). This is the transfer the fence prescribes, nothing more.
Why this is urgent-ish, and it is not the case table
⭐ packages/spec/src/contracts/metadata-service.ts currently instructs readers NOT to implement the behaviour that is now ruled and shipped. Its register / get TSDoc still presents the superseded 2026-08-11 option-(a) ruling as current, and includes a paragraph to the effect of "(c) PARKED for v18 — do not implement" — where (c) is exactly what the 2026-08-12 ruling adopted and what PR #8349 implements across three packages.
A stale table is a lagging fact. A "do not implement" instruction pointed at shipped behaviour is a live trap for the next agent that opens the contract — it reads authoritative, it is recent, and following it would mean writing code that contradicts main. That is the half worth doing promptly.
The three pieces (all under packages/spec/src/**)
contracts/metadata-service.ts — TSDoc for register / get: replace the superseded option-(a) text and delete the "PARKED — do not implement" paragraph. State the ruled contract: a name argument disagreeing with data.name is refused loudly; a non-object (or array) data is refused, not accepted-and-dropped; type stores key on the canonical type.
contracts/metadata-service-roundtrip-conformance.ts — METADATA_ROUNDTRIP_CASES' expected for five rows still states pre-ruling reference semantics: key-is-the-name-argument-object, key-is-the-name-argument-nonobject, primitive-data-roundtrips, array-data-roundtrips (all → refused) and plural-objects-type-is-its-own-store (→ readable; ⚠️ the case name is now a misnomer and should be renamed with the fix).
contracts/metadata-service-roundtrip-conformance.test.ts — the contract's own reference double must refuse rows 1/3 and fold row 2, like the three shipped implementations now do.
⭐ There is a mechanical handoff signal — you do not have to coordinate by hand
PR #8349 carries RULED_CONTRACT_ANSWERS in the objectql conformance driver, overriding the (still pre-ruling) shared table for exactly those five rows, plus a wiring test asserting "the table still lags the 2026-08-12 ruling".
That test goes RED the moment you update the table — which is the signal to delete the overrides. ⛔ It is not a defect when it fires on your PR; it is the handoff working. Delete RULED_CONTRACT_ANSWERS and its wiring test in the same PR that lands the table.
Model tier
⚠️ This is the domain:spec semantic lane: it changes the reference implementation's accept/reject behaviour and the contract's declared acceptance text. By the mandatory clause that is claude-fable-5, with no downward discretion. Flagging it so the tier decision is not re-derived from the card's small diff size.
What the implementation half already settled, so you need not re-derive it
The shared guard lives at packages/core/src/metadata-service-contract.ts (exported from @objectstack/core, the lowest common dependency) — assertMetadataRegisterContract (rows 1/3) and canonicalMetadataServiceType (row 2). The reference double can converge with the same semantics; ⛔ whether it should import that guard or restate it is your seat's call, not mine.
Refusals use the standard catalog's VALIDATION_ERROR + status 400, with a locating message naming the type, the argument, and — on mismatch rows — both disagreeing spellings. No ERROR_CODE_LEDGER entry was needed.
Arrays are refused with primitives, reasoned rather than assumed: an array carries no document identity and { ...[a, b] } is { 0: a, 1: b } corruption, so the ruling's ban on coercion-into-storability decides the array row with the primitive one.
Boundary: registerInMemory shares the row-2 fold but not the rows-1/3 refusals — the ruling names register, and registerInMemory is the boot-time seeding primitive.
Filed unassigned by the domain:engine-core seat (#6019), session session_01RDTnVvsgA6cUZ4xFVtPZRy. ⛔ Not graded by me — domain:spec + pm:queue reflect the mechanical routing (it lands in packages/spec, whose sole owner is that seat), and the triage seat should correct the type/priority if it disagrees.
Cross-seat transfer from
domain:engine-core(seat #6019) todomain:spec(seat #6017). Provenance: this is thepackages/spec/src/**half of #7378, split out by the dispatch fence that stops any engine-core card at the spec boundary. #7378 remains open and its implementation half is PR #8349 (Part of #7378, deliberately notFixes).⛔ This card does not re-open the ruling. The maintainer ruled all three cells on 2026-08-12 (#7378 comment 5261734580). This is the transfer the fence prescribes, nothing more.
Why this is urgent-ish, and it is not the case table
⭐
packages/spec/src/contracts/metadata-service.tscurrently instructs readers NOT to implement the behaviour that is now ruled and shipped. Itsregister/getTSDoc still presents the superseded 2026-08-11 option-(a) ruling as current, and includes a paragraph to the effect of "(c) PARKED for v18 — do not implement" — where (c) is exactly what the 2026-08-12 ruling adopted and what PR #8349 implements across three packages.A stale table is a lagging fact. A "do not implement" instruction pointed at shipped behaviour is a live trap for the next agent that opens the contract — it reads authoritative, it is recent, and following it would mean writing code that contradicts main. That is the half worth doing promptly.
The three pieces (all under
packages/spec/src/**)contracts/metadata-service.ts— TSDoc forregister/get: replace the superseded option-(a) text and delete the "PARKED — do not implement" paragraph. State the ruled contract: anameargument disagreeing withdata.nameis refused loudly; a non-object (or array)datais refused, not accepted-and-dropped; type stores key on the canonical type.contracts/metadata-service-roundtrip-conformance.ts—METADATA_ROUNDTRIP_CASES'expectedfor five rows still states pre-ruling reference semantics:key-is-the-name-argument-object,key-is-the-name-argument-nonobject,primitive-data-roundtrips,array-data-roundtrips(all → refused) andplural-objects-type-is-its-own-store(→ readable;contracts/metadata-service-roundtrip-conformance.test.ts— the contract's own reference double must refuse rows 1/3 and fold row 2, like the three shipped implementations now do.⭐ There is a mechanical handoff signal — you do not have to coordinate by hand
PR #8349 carries
RULED_CONTRACT_ANSWERSin the objectql conformance driver, overriding the (still pre-ruling) shared table for exactly those five rows, plus a wiring test asserting "the table still lags the 2026-08-12 ruling".That test goes RED the moment you update the table — which is the signal to delete the overrides. ⛔ It is not a defect when it fires on your PR; it is the handoff working. Delete
RULED_CONTRACT_ANSWERSand its wiring test in the same PR that lands the table.Model tier
domain:specsemantic lane: it changes the reference implementation's accept/reject behaviour and the contract's declared acceptance text. By the mandatory clause that isclaude-fable-5, with no downward discretion. Flagging it so the tier decision is not re-derived from the card's small diff size.What the implementation half already settled, so you need not re-derive it
packages/core/src/metadata-service-contract.ts(exported from@objectstack/core, the lowest common dependency) —assertMetadataRegisterContract(rows 1/3) andcanonicalMetadataServiceType(row 2). The reference double can converge with the same semantics; ⛔ whether it should import that guard or restate it is your seat's call, not mine.VALIDATION_ERROR+ status 400, with a locating message naming the type, the argument, and — on mismatch rows — both disagreeing spellings. NoERROR_CODE_LEDGERentry was needed.{ ...[a, b] }is{ 0: a, 1: b }corruption, so the ruling's ban on coercion-into-storability decides the array row with the primitive one.PLURAL_TO_SINGULARfrom@objectstack/spec/shared, converging withcheck:meta-type-normalized's existing direction (the ruling requires the two to cross-reference each other, and fix(core,metadata,objectql): enforce the #7378 three-cell IMetadataService register ruling in every shipped implementation #8349's guard header quotes the ruling at the gate).registerInMemoryshares the row-2 fold but not the rows-1/3 refusals — the ruling namesregister, andregisterInMemoryis the boot-time seeding primitive.Filed unassigned by the
domain:engine-coreseat (#6019), sessionsession_01RDTnVvsgA6cUZ4xFVtPZRy. ⛔ Not graded by me —domain:spec+pm:queuereflect the mechanical routing (it lands inpackages/spec, whose sole owner is that seat), and the triage seat should correct the type/priority if it disagrees.