Found while measuring #14454 (PR #14549). Same defect class as #14367 (registerObject's bare Error) and #14474 (NamespaceConflictError without envelope), one door over.
What was measured
validateCrossReferences (packages/spec/src/stack.zod.ts, reached through defineStack) refuses a stack whose item names an object the stack does not define. All five refusals measured in the ADR-0130 matrix are new Error(message) with code === undefined and status === undefined:
| Item class | Message (verbatim shape) |
|---|
action objectName | Action 'NAME' references object 'OBJECT' which is not defined in objects. |
view data.object | View[0].list references object 'OBJECT' which is not defined in objects. |
permission set objects | Permission 'NAME' grants on object 'OBJECT' which is not defined in objects. |
seed dataset object | Seed data references object 'OBJECT' which is not defined in objects. |
import mapping targetObject | Mapping 'NAME' targets object 'OBJECT' which is not defined in objects. |
Pinned, including the envelope's absence, in packages/objectql/src/registry-cross-package-item-classes.test.ts (ENVELOPE ABSENCE — the authoring gate carries no ADR-0112 code / status). A red on that pin means an envelope arrived: update the pin and the #14122 §4 row rather than deleting the assertion.
Why it matters
ADR-0112 makes code/status the machine-readable half of every refusal. Without them, os validate, os build and any AI author reading the refusal can only pattern-match prose — and the message text is now load-bearing for five pins, which is the fragile shape the envelope exists to remove.
Ask
Give these refusals an ADR-0112 envelope (one code per rule family, e.g. STACK_CROSS_REFERENCE_UNDEFINED_OBJECT, status: 422) at the one place they are raised, keep the message text unchanged, and update the envelope-absence pin to assert presence. Fold hooks[].object (#14122 §4 rule R4, same raiser) into the same change.
Not release-gating for the ADR-0130 chain.
Found while measuring #14454 (PR #14549). Same defect class as #14367 (
registerObject's bareError) and #14474 (NamespaceConflictErrorwithout envelope), one door over.What was measured
validateCrossReferences(packages/spec/src/stack.zod.ts, reached throughdefineStack) refuses a stack whose item names an object the stack does not define. All five refusals measured in the ADR-0130 matrix arenew Error(message)withcode === undefinedandstatus === undefined:objectNameAction 'NAME' references object 'OBJECT' which is not defined in objects.data.objectView[0].list references object 'OBJECT' which is not defined in objects.objectsPermission 'NAME' grants on object 'OBJECT' which is not defined in objects.objectSeed data references object 'OBJECT' which is not defined in objects.targetObjectMapping 'NAME' targets object 'OBJECT' which is not defined in objects.Pinned, including the envelope's absence, in
packages/objectql/src/registry-cross-package-item-classes.test.ts(ENVELOPE ABSENCE — the authoring gate carries no ADR-0112 code / status). A red on that pin means an envelope arrived: update the pin and the #14122 §4 row rather than deleting the assertion.Why it matters
ADR-0112 makes
code/statusthe machine-readable half of every refusal. Without them,os validate,os buildand any AI author reading the refusal can only pattern-match prose — and the message text is now load-bearing for five pins, which is the fragile shape the envelope exists to remove.Ask
Give these refusals an ADR-0112 envelope (one
codeper rule family, e.g.STACK_CROSS_REFERENCE_UNDEFINED_OBJECT,status: 422) at the one place they are raised, keep the message text unchanged, and update the envelope-absence pin to assert presence. Foldhooks[].object(#14122 §4 rule R4, same raiser) into the same change.Not release-gating for the ADR-0130 chain.