test(cli): hold content/docs/deployment/cli.mdx's two enumerations to their declarations - #18206
Merged
Merged
Conversation
`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
Contributor
📓 Docs Drift CheckNothing 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
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
`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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #17723
Clause-②: no
No
packages/speccontract, no published schema and no declared API shape moves here; the diff is one new test file underpackages/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 lintflags, all three scripts and the--manifest-idcondition 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.mdxstates 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 lintdeclares 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
**Options.**table under#### os lint(eleven flags + one positional)Lint.flags/Lint.argsinpackages/cli/src/commands/lint.ts, importedObject.keysof the imported classos inittemplates, four scaffolders, three npm scripts)TEMPLATESinpackages/cli/src/commands/init.tspluspackages/create-objectstack/src/templates/blank/package.json, imported / readNeither 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,lint—typecheck(tsc --noEmit) is declared by all four and is not CLI-invoking;dev,startandtestare 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'
descriptionstrings:--jsonis declared "Output as JSON" and documented "Output as JSON, for CI. The verdict fields are described below"; the--include-platformrow names the hint that sends a reader there;configlinks 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-*.mjsEvery 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/clideclarescontent/docs/deployment/cli.mdxandpackages/create-objectstack/src/templates/blank/package.jsonas cross-package test inputs (scripts/cross-package-test-inputs.mjs, mirrored intoturbo.json),ci.yml'scrosspkgfilter carriescontent/**, and thetestjob's--union-intostep 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
--manifest-idcondition (docs(deployment/cli): two under-documented enumerations — the scaffolded-scripts mapping names two of three, andos lintdocuments 4 of its 11 declared flags #16892 item ③) and every statement of the form "X applies when Y". A condition is not an enumeration; there is no set to compare it with.os lintexample fence above the table — a sample, not a claim of totality.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 extendscripts/check-cli-examples-parity.mjs:os lintdeclares noexamples, 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 agrep -o | wc -ldelta and a blob-hash change before its reading was taken; every restore was proven bygit hash-objectequal to theHEADblob plus an emptygit diff HEAD, never by an exit code.HEADblob for the page:9a34d83634a7a401b96c1260812ba3cd91febf66--include-platformrow (#16892 ② shape)--include-platform3 to 1; blob to8e857878os lintdocuments exactly the flags and positionals it declaresnpm run lintfrom the callout (#16892 ① shape)npm run lint1 to 0; blob to597e12c9emptytemplate from the list (#16350 shape)empty3 to 2; blob toef8ffca2os inittemplates that exist**Options.**table underos info, unbound**Options.**1 to 2; blob to977644ae9a34d83634a7a401b96c1260812ba3cd91febf66The mutations are a one-time proof; no mutated bytes and no ablation harness are in this diff.
Acceptance notes
--generator's documented row and its declareddescriptionboth say "Requires--eval", and the runtime enforces it ([finding, STATIC ONLY]os lint --generator's description says "Requires --eval." and nothing enforces it — the flag is referenced only insiderunEval, whichrun()reaches only when--evalis set #15550). Noted while reading, unchanged, and out of scope here.**Options.**shape exists on exactly one section of this 2109-line page today. The pin's roster refusal is what makes the second one arrive held rather than unheld.Second commit: the declaration the pin's own header forced
check:cross-package-test-inputsreads a test's source for quoted paths without parsing, so the pin's header namingscripts/check-cli-examples-parity.mjsmade that path an undeclared cross-package input for@objectstack/cli— the gate went red on it. Settled the way the fourcheck-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 intoturbo.json's@objectstack/cli#testinputs, 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/objectstackderived 68 commands (up from 50 before theturbo.json/ roster edits — a new declaration widens the derived set, which is correct). All 68 exit 0. Reconciled:dispatch-gates --ranreports "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-inputsexit 1 — the undeclared path above. Green after the second commit.check:dual-build-cjs-loadsexit 3 —PREREQUISITE NOT MET, nodist/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^...' buildexit 0 (dependency closure), thenpnpm build --concurrency=2exit 0 — 73 successful, 73 total.Tests.
pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2— 207 files / 2971 tests passed. Theintegrationtier is declared to CI: nothing in this diff touches a spawn entry,test/helpers/serve-process.tsor a driver/kernel boot path, and the new file carries none of the tier predicate's signals, so it lands inunit(test/vitest-tiers-partition.test.tsis inside that green run and would red if it landed in both tiers or neither).Typecheck.
pnpm --filter @objectstack/cli typecheckexit 0 —tsc --noEmitpluscheck: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 jsonwas 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 isfiles: ["dist", "README.md", "CHANGELOG.md"]. Afterpnpm --filter @objectstack/cli build, grepping those three paths:SCAFFOLDED_EVERYWHERE0 hits,docs-cli-enumeration-parity0 hits,GOVERNED_FLOOR0 hits — against a positive control from the same paths,include-platform33 hits andeval-min6 hits.scripts/andturbo.jsonare root files in no package'sfiles[]. Nothing published moves. Label applied and read back:size/m,tests,skip-changeset.Generated by Claude Code
Generated by Claude Code