Skip to content

test(cli): hold content/docs/deployment/cli.mdx's two enumerations to their declarations - #18206

Merged
claude[bot] merged 2 commits into
mainfrom
claude/issue-17723-cli-doc-enumerations
Sep 14, 2026
Merged

claude[bot] merged 2 commits into
mainfrom
claude/issue-17723-cli-doc-enumerations

Conversation

@claude

@claude claude Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #17723

Clause-②: no
No packages/spec contract, no published schema and no declared API shape moves here; the diff is one new test file under packages/cli/test/, and both declarations it reads are imported rather than changed.

What the card asked for, and what this is not

The page is correct today — PR #17722 documented all eleven os lint flags, all three scripts and the --manifest-id condition accurately. This card is not "fix the page"; it is that the next drift has nothing to stop it. So this PR changes no prose and adds an instrument.

content/docs/deployment/cli.mdx states two enumerations whose sources live in code, and nothing read either one. Three measured drifts, all under-inclusive, all repaired by hand: #8965, #16892 item ① (the scaffolded-scripts sentence said "these" of three commands and named two npm scripts), and #16892 item ② (os lint declares eleven flags; the page documented four — including --include-platform, which the command names in its own hint).

The two sources the page is now bound to, and that both are machine-enumerable

Page enumeration Source it is held to Machine-enumerable?
The **Options.** table under #### os lint (eleven flags + one positional) Lint.flags / Lint.args in packages/cli/src/commands/lint.ts, imported Yes — oclif object literals, read as Object.keys of the imported class
The scaffolded-wiring callout (three os init templates, four scaffolders, three npm scripts) TEMPLATES in packages/cli/src/commands/init.ts plus packages/create-objectstack/src/templates/blank/package.json, imported / read Yes — a map whose keys are the template names, and four script maps

Neither source is transcribed and neither is parsed out of source text. The script list is derived, not listed: it is the set of scripts that every scaffolder declares and whose command line runs the ObjectStack CLI. Today that is exactly build, validate, linttypecheck (tsc --noEmit) is declared by all four and is not CLI-invoking; dev, start and test are CLI-invoking in some scaffolders and not all. A fourth such script reddens the sentence that omits it.

Why a pin and not a generator

The standing repair order puts a check last, so generation (the card's route A) was measured against what the table carries before being set aside. The page's rows are not the declarations' description strings: --json is declared "Output as JSON" and documented "Output as JSON, for CI. The verdict fields are described below"; the --include-platform row names the hint that sends a reader there; config links to the auto-detection section of the same page. Generation reaches the table's membership and none of that text, and pushing the text into the declarations would put doc-site cross-references into --help.

Membership is also exactly what drifted all three times — not one of the three was a wrong description. So the residue generation cannot reach is empty, and the membership it can reach is held here instead.

Why a vitest pin and not a root scripts/check-*.mjs

Every sibling check: gate is invoked by its own step in .github/workflows/lint.yml, and .github/workflows/** is out of scope for this seat. The in-surface route is the one this repo already built for exactly this coupling: packages/cli declares content/docs/deployment/cli.mdx and packages/create-objectstack/src/templates/blank/package.json as cross-package test inputs (scripts/cross-package-test-inputs.mjs, mirrored into turbo.json), ci.yml's crosspkg filter carries content/**, and the test job's --union-into step pulls the declaring package back into the affected set. So a docs-only PR runs this pin, which is the failure mode it exists for — and no workflow diff is needed. Both paths were already declared; this PR adds none.

What it does not cover, stated so the gate's own reason stays true

It also does not duplicate packages/cli/test/scaffold-ci-script-parity.test.ts, which holds the scaffolders to each other and to the workflow the on-ramp ships — the source side, green through all three drifts, and unable to see a sentence. Nor does it extend scripts/check-cli-examples-parity.mjs: os lint declares no examples, and a flag need not appear in any example, so that gate is structurally blind to a missing flag.

Firing controls and the red/green ablation

Every comparison here can pass by reading nothing, so each parser is asserted non-empty before it is asserted equal, the governed-command roster carries a floor (lint), and an **Options.** table for a command the file does not bind is itself a failure — a new table cannot arrive unheld.

Four mutations of content/docs/deployment/cli.mdx, each reproducing a shape the card measured. Every mutation was proven on disk by a grep -o | wc -l delta and a blob-hash change before its reading was taken; every restore was proven by git hash-object equal to the HEAD blob plus an empty git diff HEAD, never by an exit code.

HEAD blob for the page: 9a34d83634a7a401b96c1260812ba3cd91febf66

Ablation On-disk proof Pin exit Case that fired
(green, unmutated) 0 — 13 passed
A · delete the --include-platform row (#16892 ② shape) --include-platform 3 to 1; blob to 8e857878 1 — 1 failed, 12 passed os lint documents exactly the flags and positionals it declares
B · drop npm run lint from the callout (#16892 ① shape) npm run lint 1 to 0; blob to 597e12c9 1 — 1 failed, 12 passed names exactly the CLI scripts every scaffolder declares
C · drop the empty template from the list (#16350 shape) backticked empty 3 to 2; blob to ef8ffca2 1 — 1 failed, 12 passed names exactly the os init templates that exist
D · add an **Options.** table under os info, unbound **Options.** 1 to 2; blob to 977644ae 1 — 1 failed, 12 passed no command documents an options table this pin does not bind
(green again, restored) blob back to 9a34d83634a7a401b96c1260812ba3cd91febf66 0 — 13 passed

The mutations are a one-time proof; no mutated bytes and no ablation harness are in this diff.

Acceptance notes

Second commit: the declaration the pin's own header forced

check:cross-package-test-inputs reads a test's source for quoted paths without parsing, so the pin's header naming scripts/check-cli-examples-parity.mjs made that path an undeclared cross-package input for @objectstack/cli — the gate went red on it. Settled the way the four check-nul-bytes.mjs-shaped entries above it in the roster are settled, and for the reason that roster records: declaring one rarely touched file is cheaper than rewording prose to dodge a scanner, and over-collection can only widen a re-run radius, never narrow one. Mirrored into turbo.json's @objectstack/cli#test inputs, as every declared glob must be.

The alternative — rewording the header so the scanner cannot see the path — would have made the gate's own stated reason vaguer to satisfy a scanner, which is the direction this repo refuses.

Verification

All readings at 3492199df, working tree clean. Exit codes captured to disk before any pipe.

Gate sweep. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 68 commands (up from 50 before the turbo.json / roster edits — a new declaration widens the derived set, which is correct). All 68 exit 0. Reconciled: dispatch-gates --ran reports "68 derived famil(ies) accounted for — 68 run, 0 NOT-MEASURED (a DERIVED zero — all 68 recorded an exit code and none of them is 3)".

Two were red on the first sweep and both were fixed, not excused:

  • check:cross-package-test-inputs exit 1 — the undeclared path above. Green after the second commit.
  • check:dual-build-cjs-loads exit 3PREREQUISITE NOT MET, no dist/ on 12 packages. Not a failure and not a pass: pnpm build (73 tasks, 0 failed), then the whole sweep re-run.

Build. pnpm --filter '@objectstack/cli^...' build exit 0 (dependency closure), then pnpm build --concurrency=2 exit 0 — 73 successful, 73 total.

Tests. pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2207 files / 2971 tests passed. The integration tier is declared to CI: nothing in this diff touches a spawn entry, test/helpers/serve-process.ts or a driver/kernel boot path, and the new file carries none of the tier predicate's signals, so it lands in unit (test/vitest-tiers-partition.test.ts is inside that green run and would red if it landed in both tiers or neither).

Typecheck. pnpm --filter @objectstack/cli typecheck exit 0 — tsc --noEmit plus check:test-typecheck ("@objectstack/cli's test layer compiles under packages/cli/tsconfig.test.json", debt ledger unmoved at 3 files / 28 errors / 6 pinned signatures).

Lint. eslint . --no-inline-config --format json was run over the whole repo, not narrowed: 6754 files linted, 0 errors, 0 warnings, exit 0. The file count is read from eslint's own JSON output, and the population is eslint's own config resolution rather than a path list of mine.

changeset: skip-changeset, measured rather than asserted. packages/cli's publish surface is files: ["dist", "README.md", "CHANGELOG.md"]. After pnpm --filter @objectstack/cli build, grepping those three paths: SCAFFOLDED_EVERYWHERE 0 hits, docs-cli-enumeration-parity 0 hits, GOVERNED_FLOOR 0 hits — against a positive control from the same paths, include-platform 33 hits and eval-min 6 hits. scripts/ and turbo.json are root files in no package's files[]. Nothing published moves. Label applied and read back: size/m, tests, skip-changeset.


Generated by Claude Code


Generated by Claude Code

`content/docs/deployment/cli.mdx` states two enumerations whose sources
live in code, and nothing read either one. Three measured drifts, all
under-inclusive, all repaired by hand: an earlier one on this page, the
scaffolded-scripts sentence that said "these" of three commands and named
two npm scripts, and the `os lint` options table that documented four of
eleven declared flags — including `--include-platform`, which the command
names in its own hint.

The page is correct today; this pin is what keeps it correct.

Two bindings, both to imported declarations rather than to parsed source
text or a transcription:

  - the `**Options.**` table under `#### os lint` against `Lint.flags`
    and `Lint.args`, in both directions, plus the positional count its
    lead-in spells out;
  - the scaffolded-wiring callout against `TEMPLATES` and the
    `create-objectstack` blank template's own `package.json` — the script
    list is compared with the CLI-invoking scripts every scaffolder
    declares, derived, so a fourth such script reddens the sentence that
    omits it.

Generation of the options table was measured against what the rows carry
and set aside: the documented text is not the declarations' `description`
strings, and membership — the thing that drifted all three times — is
what a pin can hold without pushing doc-site cross-references into
`--help`.

Every comparison is preceded by a non-emptiness assertion, the governed
roster carries a floor, and an options table for a command this file does
not bind is itself a failure, so a new table cannot arrive unheld.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
@github-actions

github-actions Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json d285bf0fbcfdaac89edfcc6e8f5bdca943cfd921packageMentionDocs.

@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 14, 2026
`check:cross-package-test-inputs` reads a test's source for quoted paths
without parsing, so naming `scripts/check-cli-examples-parity.mjs` in the
new pin's header forces a declaration. The header names it to state why
the pin does not extend that gate — `os lint` declares no `examples`, and
an example set and a flag set are different populations — and that
sentence is the gate's own stated reason, so it has to name what it is
about.

Settled the way the four `check-nul-bytes.mjs`-shaped entries above it
are: declaring one rarely touched file is cheaper than rewording prose to
dodge a scanner, and over-collection can only widen a re-run radius,
never narrow one. Mirrored into turbo.json's `@objectstack/cli#test`
inputs, as every declared glob must be.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
@claude
claude Bot marked this pull request as ready for review September 14, 2026 16:26
@claude
claude Bot enabled auto-merge September 14, 2026 16:26
@claude
claude Bot added this pull request to the merge queue Sep 14, 2026
Merged via the queue into main with commit 2d3d1c9 Sep 14, 2026
43 checks passed
@claude
claude Bot deleted the claude/issue-17723-cli-doc-enumerations branch September 14, 2026 16:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

1 participant