Commit 9c7237c
test(packages): gate that a package door's field allowlist cannot silently drop a stamped or declared key (#14830)
* test(packages): gate that a package door's allowlist cannot silently drop a stamped key
Both `/packages` doors project the installed-package record through a
hand-written field allowlist. The trade that bought was explicit: drift
shows up as a missing field, never a 500. Within one day of it landing,
an ADR-0070 D2 `writable` verdict started reaching both doors and both
would have dropped it — a 200 with the field simply absent. One door was
saved by someone reading a sibling pin, the other by a merge conflict.
The field-specific pins that followed cover `writable` and nothing else.
These two gates cover the general case, deriving both sides from real
code rather than a hand-kept key list:
- REST door: `served ⊇ getMetaItems({type:'package'}) keys`, measured
through the real `ObjectStackProtocolImplementation` over a real
`SchemaRegistry`.
- runtime door: `served ⊇ record keys`, plus a set-equality register
for the keys the door stamps AFTER the projection — measured as
`served − record`, so a reorder empties it and reds.
The two doors solved the near-miss differently (the REST allowlist
contains `writable`; the runtime one deliberately does not and orders
instead), so the invariants are stated separately rather than assumed
symmetric. Only hand-kept artifacts are the annotated exclusion and
stamp registers, both compared loudly.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
* test(packages): measure key sets by DEFINED value, not by property presence
`SchemaRegistry.installPackage` seats the optional record fields as own
properties holding `undefined`, so `'settings' in record` is true for a
package installed without settings. Both doors omit undefined-valued
fields deliberately and JSON.stringify drops them anyway, so counting
them made the gate red on every package for a key no consumer could have
observed — measured on the first run, six false drops.
Also drops the fixture's `findOne` double: `getMetaItems` never reaches
that verb, and `check:engine-double-contract` is right that a fake looser
than ObjectQL.findOne is worth refusing rather than stubbing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
* test(packages): seat every declared record field, so the gate can see all of them
The ablation caught this and it is the more useful of the two findings:
deleting `installedVersion` from EITHER door's allowlist left both gates
GREEN. `installPackage` leaves 8 of the 12 declared fields as own
properties holding `undefined`, and a key the wire cannot carry is
correctly invisible to the detector — so the coverage assertion was
exercising 4 fields while reading as if it covered the record.
`seatDeclaredFields` fills every own key whose value is `undefined`,
derived from the record's own key set rather than from a list of field
names, so a field added tomorrow is seated without an edit. A control
assertion now fails if any declared slot is unobservable again.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
* test(packages): seat the DECLARED key set, read from InstalledPackageSchema
The first ablation's most useful reading: deleting `installedVersion`
from either allowlist left both gates GREEN. Six of the twelve declared
record fields are ABSENT from a freshly installed record (installPackage
writes only what an install can know), so a gate watching only the
producer's live output cannot see them dropped.
The card asks for `served ⊇ the producer's stamped/DECLARED key set`, so
the declared half is derived from the record schema — in the TEST's
expectation, never in the production allowlist, which stays hand-written
and untouched. That distinction is the one the originating card ruled on
and it is spelled out at DECLARED_RECORD_KEYS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 6d178a4 commit 9c7237c
2 files changed
Lines changed: 883 additions & 0 deletions
File tree
- packages
- rest/src
- runtime/src/domains
0 commit comments