Skip to content

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

Merged
os-support-ai merged 1 commit into
mainfrom
claude/issue-18815-four-doors-table-stack-tiers
Sep 18, 2026
Merged

os-support-ai merged 1 commit into
mainfrom
claude/issue-18815-four-doors-table-stack-tiers

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

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 short
scoping paragraphs: one above the table naming what the table's two axes are, one
under the one-directional parenthetical saying which scope that sentence is
written 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 fb2bccfc96 by reading the call sites, not by trusting the card:

door call site wired by
os build packages/cli/src/commands/compile.ts:482 #16611
os validate packages/cli/src/commands/validate.ts:421 #18677 (PR #18769, merged 2026-09-17T21:18:28Z)
os lint packages/cli/src/commands/lint.ts:722 #18778 (PR #18813, merged 2026-09-17T23:32:18Z)

All three reach the one loop, runPerPackageAuthoringRules at
packages/cli/src/utils/artifact-packages.ts:189. Both PRs are merged and are
ancestors 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-parity and union-fold-command-parity (spawned, real
binaries) — 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 structural
read rather than a keyword miss, and widened to the whole docs tree:

  • on the page, every occurrence of "tier" is a rule tier — pre-parse tier
    (:519), react tier (:335), tier findings (:63), the ADR-0049 tier programme
    (:241). None is a stack shape.
  • across content/docs/**: zero hits for the per-package pass or the union fold in
    that sense (the 13 per-package hits are changelogs, doc-book grouping, capability
    prefixes, one-app-per-package ADRs), against a lit control of 64 files naming
    the three commands. Same probe over the published skills/ catalog: zero, lit
    control 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 in
    hand when it runs the registry"
    , documenting AuthoringRuleRun, whose members are
    normalized and parsed;
  • :215 — "Which tier of the stack a rule reads", for the same two;
  • :213 — and AuthoringRuleTier is a third sense again, 'gating' | 'advisory'.

Those are not near-synonyms of the axis this card is about; they are orthogonal to
it
. runPerPackageAuthoringRules hands BOTH stack tiers the same per-package stack
(artifact-packages.ts:230-231, normalized: asStack, parsed: asStack), and
lint.ts:653 says the mirror thing for the other pass — "Both tiers are handed the
UNION-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 and
another at this one, and the runtime publish column says neither. Sourced from
packages/lint/src/runtime-gate.ts:208-259, not from the card, which explicitly did
not assert what that row should say.

Evidence

  • Derived gate families — node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack
    derived 39; all 39 run, exit codes recorded and reconciled:
    --ran => "39 derived famil(ies) accounted for — 39 run, 0 NOT-MEASURED (a DERIVED
    zero — 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 0
    after building @objectstack/spec, @objectstack/formula, @objectstack/lint and
    @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 family dispatch-gates.mjs does not name. Run whole, not
    narrowed: eslint . --no-inline-config, exit 0, 82s, at 777cd9aeca.
  • MDX compiles — @mdx-js/mdx 3.1.1 compile() on the edited page, exit 0.
  • Anchors — pnpm check:doc-anchors exit 0; the new heading adds
    #what-each-door-hands-the-rule-table and renames nothing, so the existing inbound
    links to #the-one-gate-four-doors (cli.mdx:650, deployment/index.mdx:153) are
    untouched.
  • Control bytes — grep -naP over the edited file: no hits; pnpm check:nul-bytes exit 0.
  • Publishing surface, measured with controls both ways — 83 manifests, 70
    non-private. Manifests whose files[] mentions content: 0. Positive control,
    dist: 70 of 70. Manifests with no files[] at all (whole dir ships): 0.
    content/docs is at the repo root, outside every package directory, and the one
    manifest that names a content/docs path at all does so in its description string
    (plugin-webhooks), not in files[]. ⇒ 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 home
    for 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.mdx carries the doors in two places (:649, :668,
    :1485) and defers to this page's matrix by link for the detail. Those three
    statements 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

…, 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>
@os-support-ai os-support-ai added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 18, 2026 — with Claude
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 18, 2026
@os-support-ai
os-support-ai marked this pull request as ready for review September 18, 2026 03:23
@os-support-ai
os-support-ai added this pull request to the merge queue Sep 18, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 18, 2026
@os-support-ai
os-support-ai added this pull request to the merge queue Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Evicted from the merge queue, re-enqueued once — the check that took it out is NOT MEASURED, and is not this PR's

domain:cli execution PM seat · reading 2026-09-18T04:09Z · every value below read from the API, not recalled

What happened. The timeline — the decisive membership reading, not auto_merge — reads:

added_to_merge_queue      2026-09-18T03:24:16Z
removed_from_merge_queue  2026-09-18T04:04:23Z   by github-merge-queue[bot]
added_to_merge_queue      2026-09-18T04:09:15Z   ← this act

Why the eviction is not this PR's failure. Four readings:

  1. There is no failing assertion. On the queue branch 933fac7ffd, 26 check NAMEs: 25 green and one — Temporal Conformance (live PG + MySQL) — with conclusion cancelled. ⛔ cancelled is neither green nor red; it is NOT MEASURED. Nothing asserted anything and lost.
  2. It ran far outside its own envelope. That instance ran 2026-09-18T03:28:52Z → 2026-09-18T04:03:52Z = 35 minutes, and was then cancelled. The same check on the base this PR was queued onto (0b31d90fb3) has three runs around the same window, all success, at 10m43s, 10m37s and 5m49s. The queue dropped the entry 31 seconds after the cancellation.
  3. The diff cannot reach it. This PR is one file, content/docs/deployment/validating-metadata.mdx, +69 / −0. No source, no schema, no migration, no service config — nothing a live PostgreSQL + MySQL temporal conformance suite reads.
  4. The PR head is clean. Re-read before re-arming, on head 777cd9aeca: 32 check NAMEs, 32 green, 0 pending, 0 red. check-governed-merges.mjs --pr 18872 on the final file list: 0 of 1 path hits the governed register ⇒ ordinary queue landing. mergeable_state: clean, not draft.

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 777cd9aeca, and re-arming auto_merge is what puts the same commit back in line.

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

Merged via the queue into main with commit 600b1e2 Sep 18, 2026
38 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-18815-four-doors-table-stack-tiers branch September 18, 2026 04:27
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants