Repository navigation
docs(deployment): the four-doors matrix names rule families and doors, so the input each door hands them is written as its own axis - #18872
Conversation
…, so the input each door hands them is written as its own axis The "one gate, four doors" table has two axes -- rule FAMILIES down, doors across -- and no cell of it can say what each door hands those families to judge. So the two-pass shape the three CLI doors actually run (the union fold over the artifact's collections, then the same table once per `packages[]` entry) was documented nowhere, for any door, across three landings that wired it: #16611 (`os build`), #18677 (`os validate`) and #18778 (`os lint`). The two axes read identically in prose, which is the failure this closes rather than a side note: a sentence scoped to the table's ROWS and the same sentence scoped to the INPUT are different claims, and the row-scoped one was read as evidence for the input-scoped one. The paragraph where that happened now says which scope it is written at and points at the new section for the other. Also written out: the fourth door is on neither pass -- a write is one item, so the publish gate evaluates differentially and narrows its resolution context to the written item's package closure (#9612), which is a third thing again and not a per-package walk. Docs-only. `content/docs/**` reaches no published package's `files[]`. Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3 Co-authored-by: Claude <noreply@anthropic.com>
Evicted from the merge queue, re-enqueued once — the check that took it out is NOT MEASURED, and is not this PR's
What happened. The timeline — the decisive membership reading, not Why the eviction is not this PR's failure. Four readings:
What was done, and what was not. The queue entry was re-armed once — that is the single re-run this failure class is entitled to, and a second one would be a real failure to root-cause rather than to retry. ⛔ No test was skipped, disabled or quarantined. ⛔ No empty commit and no close-and-reopen: the head is unchanged at If the next queue build reproduces the same 35-minute cancellation on a docs-only diff, that is a finding about the check's own stability under the merge queue, and it will be filed as one rather than retried again. Generated by Claude Code |
…the source states it (objectstack-ai#19241) Fixes objectstack-ai#18893 `content/docs/deployment/validating-metadata.mdx` was the last place in the tree still asserting, as a claim, the sentence the CLI source explicitly forbids restating — of the per-package walk: *"what it reports is exactly the set the union could not see"*. PR objectstack-ai#18878 (card objectstack-ai#18779) removed that sentence from eight code carriers because it is false, and the two notes that replaced it are this page's acceptance baseline: - `packages/cli/src/utils/artifact-packages.ts` — the `findingKey` docblock records that the claim the pass is entitled to make *"is narrower than"* that sentence, and that the key is *"position-insensitive, ⛔ not collision-proof"*. - `packages/cli/src/commands/compile.ts` — *"⛔ Do not re-inflate that to"* it, beside the settled statement of what does survive. ## What changed One sentence, one file. The page now states the bound in the source's own settled words — the set of per-package findings no union finding already carried under the same rule, `where`, message and non-top-level position — says why the leading collection index is neutralised (a package body re-bases its collections from 0, so one finding would otherwise get two keys), and carries the narrowness note the source wrote down so the next reader does not re-inflate it. The surrounding paragraph's teaching is untouched. ⛔ No source file was changed. The source is the authority here; the page is what was wrong. ## Measurement Whitespace-normalised, because the target sentence **wraps across two lines** and a line-oriented `grep -F` returns `0` on it — a zero triage and two seats each paid for once on this very card: | needle | base `e233db9` | after | |:--|--:|--:| | `exactly the set the union could not see` | 1 | **0** | | lit control `one gate, four doors` | 2 | 2 | | dark control `zzzNotARealToken` | 0 | 0 | The lit control still fires after the edit, so that `0` is a reading and ⛔ not an instrument artefact. The naive line-oriented `grep -F` reads `0` both before and after — recorded here so nobody re-derives a clearance from it. ## Gates 39 families derived from the **actual diff** (`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, change set taken by the script itself from the merge base), every one run, every one exit `0`, reconciled `39 derived / 39 run / 0 UNRUN`. Plus the full `pnpm lint` union, which `dispatch-gates` does not name. Four of the 39 first exited `3`/`1` carrying PREREQUISITE-NOT-MET text — *"Nothing was measured: this gate exited before running a single check"* — because workspace packages were unbuilt. They were re-run to a real verdict after building `@objectstack/spec`, `@objectstack/formula`, `@objectstack/lint` and `@objectstack/client-react`. ⛔ Those refusals are recorded as not-measured-then-measured, never as a failed measurement. ## Changeset `skip-changeset`, **derived rather than assumed**: the one changed path lives under no package directory except the private monorepo root (`@objectstack/spec-monorepo`, `private: true`), so no published package's tarball can contain it whatever decides its contents; and no published package names `content/docs` in its `files[]`. ⛔ No label was written — this dispatch forbids label writes, so the label is the seat's to apply. ## Acceptance notes - **Only one carrier on this page.** The card asked for a grep rather than an assumption, since PR objectstack-ai#18872 introduced the whole section in one landing: probed whitespace-normalised for `de-duplicat`, `union could not`, `could not see`, `only what`, `echo` and `duplicate` across the page — the corrected sentence was the single restatement. No second one exists. - **The "only place in the repo" premise is true of source code and ⛔ not of the tree.** Re-derived at the branch base, whitespace-normalised: 13 non-doc occurrences across 13 files. Eleven are the settled shapes — one bound declaration, one prohibition, and nine quoted corrections in `compile.ts`, `lint.ts`, `validate.ts` and five CLI pin tests. **Two are still assertions**: `.changeset/18677-validate-per-package-authoring-pass.md` states *"By `compile.ts`' own description the survivors of that second pass are …"* and `.changeset/18778-lint-per-package-authoring-pass.md` states *"every finding that pass produces — … — in the build command's own words"*. Both attribute the sentence to source text that no longer says it, both are unreleased, and a changeset body ships verbatim into `CHANGELOG.md` as the text an upgrading agent greps. ⛔ Not fixed here — out of this card's declared one-file surface, and `.changeset/18677-…` is the claimed surface of in-flight card objectstack-ai#18823 (PR objectstack-ai#18867) for a different defect. Reported for filing. Clause-②: no --- _Generated by [Claude Code](https://claude.ai/code/session_01QCdUBjM47SxioST9z5Zwdf)_ Co-authored-by: Claude <noreply@anthropic.com>
Fixes #18815
Clause-②: no
Docs-only. One file, +69 / -0:
content/docs/deployment/validating-metadata.mdx.The gap, restated at the scope it is actually at
The "one gate, four doors" table has exactly two axes: its rows are rule
families, its columns are the four doors. A check mark says that door runs
that family. It cannot say what that door hands the family to judge — and that
input is where the three CLI doors have drifted three separate times. So the
two-pass shape they run (the union fold over the artifact's collections, then the
same table once per
packages[]entry) was documented nowhere, for any door,across the three landings that wired it.
This PR adds a third axis to the page as its own
###section, plus two shortscoping paragraphs: one above the table naming what the table's two axes are, one
under the
one-directionalparenthetical saying which scope that sentence iswritten at.
The card's gating claim, re-derived rather than relayed
The card rests on "all three doors now run the per-package pass". Verified on the
branch base
fb2bccfc96by reading the call sites, not by trusting the card:os buildpackages/cli/src/commands/compile.ts:482os validatepackages/cli/src/commands/validate.ts:421os lintpackages/cli/src/commands/lint.ts:722All three reach the one loop,
runPerPackageAuthoringRulesatpackages/cli/src/utils/artifact-packages.ts:189. Both PRs are merged and areancestors of this branch's base. The successor condition holds.
Measured end to end as well, not only read:
validate-per-package-authoring-parity,lint-per-package-authoring-parityandunion-fold-command-parity(spawned, realbinaries) — 3 files, 15 tests, exit 0.
The seat's premise probe, re-run structurally
The dispatch handed one grep (
per-package | union fold | union-folded | stack tier=> 0 hits, lit control
os build|os validate|os lint=> 25). Re-run as a structuralread rather than a keyword miss, and widened to the whole docs tree:
pre-parse tier(:519),
react tier(:335),tier findings(:63), the ADR-0049tier programme(:241). None is a stack shape.
content/docs/**: zero hits for the per-package pass or the union fold inthat sense (the 13
per-packagehits are changelogs, doc-book grouping, capabilityprefixes, one-app-per-package ADRs), against a lit control of 64 files naming
the three commands. Same probe over the published
skills/catalog: zero, litcontrol 14.
So the gap is real and is repo-wide, not just table-shaped.
Falsification — the card's own word for the axis is already taken, and for a DIFFERENT axis
The card and the dispatch both name the second axis the stack TIER. That phrase is
already spent in this repo, on something else:
packages/lint/src/authoring-rules.ts:1671— "The stack tiers a command has inhand when it runs the registry", documenting
AuthoringRuleRun, whose members arenormalizedandparsed;:215— "Which tier of the stack a rule reads", for the same two;:213— andAuthoringRuleTieris a third sense again,'gating' | 'advisory'.Those are not near-synonyms of the axis this card is about; they are orthogonal to
it.
runPerPackageAuthoringRuleshands BOTH stack tiers the same per-package stack(
artifact-packages.ts:230-231,normalized: asStack, parsed: asStack), andlint.ts:653says the mirror thing for the other pass — "Both tiers are handed theUNION-FOLDED stack". A page that wrote "stack tier" for the union-vs-per-package axis
would therefore have created a new collision, in the very module the table cites as
its source, of exactly the class this card exists to close.
⇒ the page names the axis for what it is — the input each door hands the rule
table — and names the two passes what the code already calls them: the union fold
and the per-package walk. The card's requirement is met (family and input are
kept apart, explicitly, at the one paragraph where they were conflated); its wording
is deliberately not adopted. Flagging it rather than quietly diverging.
Also written out, because it is a third thing again
The fourth door is on neither pass. A runtime write is one item, so the publish
gate evaluates differentially (context alone, then with the item grafted in, #4463)
and narrows its resolution context to the written item's package closure (#9612) —
which changes what a rule can resolve, never what it judges, and iterates no
packages[]. "Runs per package" therefore names one thing at the three CLI doors andanother at this one, and the
runtime publishcolumn says neither. Sourced frompackages/lint/src/runtime-gate.ts:208-259, not from the card, which explicitly didnot assert what that row should say.
Evidence
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 39; all 39 run, exit codes recorded and reconciled:
--ran=> "39 derived famil(ies) accounted for — 39 run, 0 NOT-MEASURED (a DERIVEDzero — all 39 recorded an exit code and none of them is 3)". Five first reported
PREREQUISITE NOT MET(exit 3 / exit 1, nothing measured) and were re-run to exit 0after building
@objectstack/spec,@objectstack/formula,@objectstack/lintand@objectstack/client-react:check:doc-formula-expressions,check:doc-security-posture,spec check:docs,spec check:skill-examples,check:docs-transcript-drift.pnpm lint— the familydispatch-gates.mjsdoes not name. Run whole, notnarrowed:
eslint . --no-inline-config, exit 0, 82s, at777cd9aeca.@mdx-js/mdx3.1.1compile()on the edited page, exit 0.pnpm check:doc-anchorsexit 0; the new heading adds#what-each-door-hands-the-rule-tableand renames nothing, so the existing inboundlinks to
#the-one-gate-four-doors(cli.mdx:650,deployment/index.mdx:153) areuntouched.
grep -naPover the edited file: no hits;pnpm check:nul-bytesexit 0.non-private. Manifests whose
files[]mentionscontent: 0. Positive control,dist: 70 of 70. Manifests with nofiles[]at all (whole dir ships): 0.content/docsis at the repo root, outside every package directory, and the onemanifest that names a
content/docspath at all does so in itsdescriptionstring(
plugin-webhooks), not infiles[]. ⇒ nothing published moves ⇒skip-changeset,applied to this PR.
Acceptance notes
Out of scope, noted and not filed:
content/docs/getting-started/examples.mdx§"A project is a multi-package artifact"is the page that teaches
packages[]to authors and would be the natural second homefor a one-line pointer at the per-package pass. It does not enumerate the doors
and contradicts nothing here, so triage's escalation condition ("a second page that
cannot express the axis ⇒ p1 plus a structural card") is not met — measured, not
assumed. Successor: none; noted for whoever next edits that section.
content/docs/deployment/cli.mdxcarries the doors in two places (:649,:668,:1485) and defers to this page's matrix by link for the detail. Those threestatements are true at both passes now, so nothing there is falsified by this PR and
nothing was edited there. Successor: none.
Generated by Claude Code