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
[finding] The two artifact registrars' collection coverage is wrong in mirror-image ways: policies is a dead pointer in BOTH, and capabilities is declared but covered by only ONE #12894
Filed unassigned and ungraded by the domain:cli seat (#6024), session session_01UjujZN219uFzBhSYfMykCd, on behalf of the #12844 dev — the pre-file dedup channel is 403 from that seat. ⭐ It reported rather than filing blind. ⛔ Not graded, not routed. Both halves re-measured independently by this seat before filing, with positive controls.
Two observations arrived separately; they are filed together because they are the same question — which collections each artifact registrar covers — failing in opposite directions, and a fix for either that does not look at the other will leave the map half-wrong again.
Half 1 — policies: a dead pointer in both registrars
The artifact door's field-to-type map (packages/metadata/src/plugin.ts) contains policies: 'policy', and AppPlugin's security-field list (packages/runtime/src/app-plugin.ts) contains the matching entry. ⛔ Neither can ever match.
ObjectStackDefinitionSchema (packages/spec/src/stack.zod.ts) is a strictObject, and it declares no top-level policies key. Measured, with controls:
probe (top-level key in the stack schema)
hits
policies
0
permissions (control)
2
capabilities (control)
2
sharingRules (control)
2
⛔ The zero is a finding, not a broken pattern — three controls answer in the same file with the same instrument. And policies appears nowhere in that schema file at all.
⭐ Where the word actually lives: inside the permission-set schema, as an alias for the row-level-security key (packages/spec/src/security/permission.zod.ts:453). ⇒ it is a key on an item, never a top-level collection. A definition carrying a top-level policies array is refused outright by the strict door, so it reaches neither registry.
⚠️ This is the same class the map already documents as removed — it carries in-line notes retiring a themes mapping and a roles mapping for exactly this reason (the second one "matched nothing and silently dropped compiled positions"). ⇒ ⭐ a third instance of a pattern this file has twice recognised and fixed, still standing.
Half 2 — capabilities: declared, but only one registrar covers it
The mirror image. capabilitiesis a declared top-level collection in the stack schema (an authorable ADR-0066 surface), and AppPlugin's list covers it — ⛔ but the artifact door's map does not.
⇒ on an artifact boot, AppPlugin is that collection's sole registrar, and the door never registers a capability item at all. ⇒ every property the door adds and the bundle path does not — the strict parse, schema defaults, the ADR-0010 provenance stamp — is structurally unavailable to capabilities on that path, not merely order-dependent.
⚠️This collection has been caught in a registration gap before: #5870 (closed) recorded that capabilities sat outside ObjectQL's registration seam, so app-declared capabilities never received registry provenance. ⛔ That is a different map in a different package, so this is not a duplicate — ⭐ but it is the second time this same collection has been found missing from a registration path, which is itself the argument for closing the class rather than the instance.
Why the two halves belong on one card
⭐ They are the same map question answered wrongly in opposite directions:
policies — both registrars point at something the schema refuses ⇒ two dead pointers;
capabilities — the schema declares it and one registrar ignores it ⇒ a silent single-writer.
⇒ ⛔ A fix that only deletes the dead policies entries leaves capabilities half-registered; a fix that only adds capabilities to the door leaves two dead pointers that the next reader will take as evidence the map is complete. ⚠️ And whichever is done, the map is also what any route-ownership decision (#12892) has to be measured against — ⭐ option 1 there ("the door owns the route") is not implementable today precisely because of half 2.
Options, ⛔ not prejudged
Fix both, with reasons in-line — retire the policies entries the way this map already retires its two predecessors (a note saying what it matched and why it cannot), and add capabilities to the door's map. ⚠️ Adding capabilities to the door changes what gets registered on an artifact boot; that is a behaviour change and needs its own measurement, ⛔ not a drive-by.
Record both as deliberate — if the capabilities asymmetry is intended (a reason the door must not register them), write it where the next reader looks. ⛔ This seat found no such note.
Re-check
git grep -n -A 25 "ARTIFACT_FIELD_TO_TYPE" -- packages/metadata/src/plugin.ts
git grep -n -A 10 "SECURITY_FIELDS" -- packages/runtime/src/app-plugin.ts
git show HEAD:packages/spec/src/stack.zod.ts | grep -cE "^ policies:" # expect 0
git show HEAD:packages/spec/src/stack.zod.ts | grep -cE "^ permissions:" # positive control
⚠️Instrument warning, from this seat's own near-miss while verifying this card: a git grep -rl for the schema's export name returns a test file first. Every probe against it — including the positive control — came back 0. ⭐ The control is what caught it. ⛔ Confirm you are reading the schema and not a test before drawing any conclusion from a zero here.
Duplicate check
Searched this round; 4 matches, all closed. Nearest is #5870 (same collection, adjacent registration seam in ObjectQL — different map, different package, not a duplicate); the others (#10588, #9538, #4781) are different subjects. ⭐ The search reached the right corpus (it returned the capabilities-registration card). ⛔ No open card covers either half. ⚠️ Not exhaustively deduped outside domain:cli / domain:engine.
Filed unassigned and ungraded by the
domain:cliseat (#6024), sessionsession_01UjujZN219uFzBhSYfMykCd, on behalf of the #12844 dev — the pre-file dedup channel is 403 from that seat. ⭐ It reported rather than filing blind. ⛔ Not graded, not routed. Both halves re-measured independently by this seat before filing, with positive controls.Two observations arrived separately; they are filed together because they are the same question — which collections each artifact registrar covers — failing in opposite directions, and a fix for either that does not look at the other will leave the map half-wrong again.
Half 1 —
policies: a dead pointer in both registrarsThe artifact door's field-to-type map (
packages/metadata/src/plugin.ts) containspolicies: 'policy', andAppPlugin's security-field list (packages/runtime/src/app-plugin.ts) contains the matching entry. ⛔ Neither can ever match.ObjectStackDefinitionSchema(packages/spec/src/stack.zod.ts) is astrictObject, and it declares no top-levelpolicieskey. Measured, with controls:policiespermissions(control)capabilities(control)sharingRules(control)⛔ The zero is a finding, not a broken pattern — three controls answer in the same file with the same instrument. And
policiesappears nowhere in that schema file at all.⭐ Where the word actually lives: inside the permission-set schema, as an alias for the row-level-security key (
packages/spec/src/security/permission.zod.ts:453). ⇒ it is a key on an item, never a top-level collection. A definition carrying a top-levelpoliciesarray is refused outright by the strict door, so it reaches neither registry.Half 2 —
capabilities: declared, but only one registrar covers itThe mirror image.
capabilitiesis a declared top-level collection in the stack schema (an authorable ADR-0066 surface), andAppPlugin's list covers it — ⛔ but the artifact door's map does not.⇒ on an artifact boot,
AppPluginis that collection's sole registrar, and the door never registers a capability item at all. ⇒ every property the door adds and the bundle path does not — the strict parse, schema defaults, the ADR-0010 provenance stamp — is structurally unavailable to capabilities on that path, not merely order-dependent.Why the two halves belong on one card
⭐ They are the same map question answered wrongly in opposite directions:
policies— both registrars point at something the schema refuses ⇒ two dead pointers;capabilities— the schema declares it and one registrar ignores it ⇒ a silent single-writer.⇒ ⛔ A fix that only deletes the dead⚠️ And whichever is done, the map is also what any route-ownership decision (#12892) has to be measured against — ⭐ option 1 there ("the door owns the route") is not implementable today precisely because of half 2.
policiesentries leaves capabilities half-registered; a fix that only adds capabilities to the door leaves two dead pointers that the next reader will take as evidence the map is complete.Options, ⛔ not prejudged
policiesentries the way this map already retires its two predecessors (a note saying what it matched and why it cannot), and add capabilities to the door's map.policiesonly (pure removal of two dead pointers, no behaviour change) and hand capabilities to Route ownership for the five artifact security collections — MEASURED: the two registrars' copies differ in TYPE on a key a consumer can read today, not just on some future retired key #12892 as part of the ownership decision. ⭐ Smallest safe increment;Re-check
git grep -rlfor the schema's export name returns a test file first. Every probe against it — including the positive control — came back 0. ⭐ The control is what caught it. ⛔ Confirm you are reading the schema and not a test before drawing any conclusion from a zero here.Duplicate check
Searched this round; 4 matches, all closed. Nearest is #5870 (same collection, adjacent registration seam in ObjectQL — different map, different package, not a duplicate); the others (#10588, #9538, #4781) are different subjects. ⭐ The search reached the right corpus (it returned the capabilities-registration card). ⛔ No open card covers either half.⚠️ Not exhaustively deduped outside
domain:cli/domain:engine.Refs
capabilities不在 ObjectQLmetadataArrayKeys注册缝里 —— app 声明的 capability 永远拿不到 registry provenance(#4967 Part 2 拆出) #5870 — closed; the same collection missing from a different registration seam