Surfaced by the dev delivering #18491 (PR #18675) as an out-of-scope finding, then re-measured by the dispatching seat on origin/main before filing — ⛔ not taken from the report. Readings at 62d830e54.
The asymmetry
os build runs the artifact's authoring rules twice: once over the union-folded stack, and then a second runAuthoringRules('build', …) pass over each artifactPackages(…) entry, with packageBodyAsStack(…) as resolution context, de-duplicated against the union run. os validate runs the union pass and stops — it imports neither artifactPackages nor packageBodyAsStack.
compile.ts's own comment says what survives that de-duplication is "exactly the set the union could not see". So that set is, by the file's own description, findings os build reports and os validate structurally cannot — the false-clean direction.
Measured by symbol (⛔ not by line number), on origin/main:
| symbol |
commands/compile.ts |
commands/validate.ts |
runAuthoringRules(…) call sites |
2 (union, then per package) |
1 (union only) |
artifactPackages( |
present |
absent |
packageBodyAsStack |
present |
absent |
authoringRuleUnionStack |
present |
present |
⭐ The last row is the control that could have failed: the same sweep finds authoringRuleUnionStack in both files, so the instrument does reach validate.ts and would have shown a package walk there if one existed. The zero is measured, not a dead search.
⚠️ This is the RESIDUE of #17069, not a re-report of it
#17069 — "os validate and os lint judge an EMPTY stack when a project declares its metadata only in packages[] — the ADR-0130 D4 union fold (authoringRuleUnionStack) is wired into os build alone" — is closed/completed, and the tree agrees: authoringRuleUnionStack is now in both commands. That half is genuinely fixed.
What #17069 did not reach is the pass that runs after the union fold. One layer past it, the same false-clean direction is still open. ⇒ this card is about the per-package walk only; ⛔ it makes no claim about the union fold.
What this card deliberately does NOT decide
⛔ Not asserted: that the walk should simply be wired into os validate. Wiring a real gate into the other door changes what os validate refuses, which is a decision about the contract between the two commands, not a test fix. That is why PR #18675 recorded it in its new NOT_A_GATE ledger beside the two names rather than acting on it — visible instead of silent — and why it is a card rather than a line in that PR.
Also unmeasured here, and ⛔ not assumed either way: whether any authoring rule actually fires only under packageBodyAsStack resolution today. The structural gap is measured; its live blast radius is not.
Adjacent, read and cleared
Dedupe words: per-package authoring rules · artifactPackages · packageBodyAsStack · runAuthoringRules per package · os validate package walk · residue of #17069.
Generated by Claude Code
Surfaced by the dev delivering #18491 (PR #18675) as an out-of-scope finding, then re-measured by the dispatching seat on
origin/mainbefore filing — ⛔ not taken from the report. Readings at62d830e54.The asymmetry
os buildruns the artifact's authoring rules twice: once over the union-folded stack, and then a secondrunAuthoringRules('build', …)pass over eachartifactPackages(…)entry, withpackageBodyAsStack(…)as resolution context, de-duplicated against the union run.os validateruns the union pass and stops — it imports neitherartifactPackagesnorpackageBodyAsStack.compile.ts's own comment says what survives that de-duplication is "exactly the set the union could not see". So that set is, by the file's own description, findingsos buildreports andos validatestructurally cannot — the false-clean direction.Measured by symbol (⛔ not by line number), on
origin/main:commands/compile.tscommands/validate.tsrunAuthoringRules(…)call sitesartifactPackages(packageBodyAsStackauthoringRuleUnionStack⭐ The last row is the control that could have failed: the same sweep finds
authoringRuleUnionStackin both files, so the instrument does reachvalidate.tsand would have shown a package walk there if one existed. The zero is measured, not a dead search.#17069 — "
os validateandos lintjudge an EMPTY stack when a project declares its metadata only inpackages[]— the ADR-0130 D4 union fold (authoringRuleUnionStack) is wired intoos buildalone" — is closed/completed, and the tree agrees:authoringRuleUnionStackis now in both commands. That half is genuinely fixed.What #17069 did not reach is the pass that runs after the union fold. One layer past it, the same false-clean direction is still open. ⇒ this card is about the per-package walk only; ⛔ it makes no claim about the union fold.
What this card deliberately does NOT decide
⛔ Not asserted: that the walk should simply be wired into
os validate. Wiring a real gate into the other door changes whatos validaterefuses, which is a decision about the contract between the two commands, not a test fix. That is why PR #18675 recorded it in its newNOT_A_GATEledger beside the two names rather than acting on it — visible instead of silent — and why it is a card rather than a line in that PR.Also unmeasured here, and ⛔ not assumed either way: whether any authoring rule actually fires only under
packageBodyAsStackresolution today. The structural gap is measured; its live blast radius is not.Adjacent, read and cleared
os build/os devper-package author-time rules refuse an action param's record-pickerreferenceto a dependency's object (object-reference-unknown), while the composed pass accepts it and ADR-0130 R1 accepts the field-level equivalent #18204 (closed) — per-package author-time rules refusing an action param's record-pickerreferencewhere the composed pass accepts it. A disagreement within the per-package pass's verdicts, not about which command runs it.os build --jsonalso drops the capability-provider and package-docs warnings thatos validate --jsoncarries #11727 (closed) —os build --jsondropping warningsos validate --jsoncarries. The opposite direction, and about--jsonrendering.Dedupe words:
per-package authoring rules·artifactPackages·packageBodyAsStack·runAuthoringRules per package·os validate package walk·residue of #17069.Generated by Claude Code