Skip to content

fix(cli): the package-docs step line reports what it collected, not what it attempted - #18445

Merged
os-support-ai merged 3 commits into
mainfrom
claude/issue-18432-docs-step-line-reports-count
Sep 16, 2026
Merged

os-support-ai merged 3 commits into
mainfrom
claude/issue-18432-docs-step-line-reports-count

Conversation

@os-support-ai

@os-support-ai os-support-ai commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Fixes #18432

Clause-②: no — this PR puts no new key on a published payload. It changes only a progress line's text and the doc transcript that quotes it; no input the build accepts or refuses changes. Declared by the dispatching seat in claim 5696261079.

What changed

os build / os compile printed its package-docs step line before the call it announces, and the line carried no count:

if (!flags.json) printStep('Collecting package docs (ADR-0046)...');
const docsResult = collectAndLintDocs(...)

So a build that collected nothing emitted the same reassuring sentence as one that collected four documents. The print now happens after the collection and reports it:

  → Collecting package docs (ADR-0046)... 0 collected
  → Collecting package docs (ADR-0046)... 4 collected

This is the reassurance half of #18170. #18428 landed the audible half, where an uncollected docs directory speaks for itself; this card was fenced out of that PR because the transcript quoting the step line lived on a page PR #18416 had staked. That page merged at 2026-09-16T10:48Z, so the fence is lifted.

The doc half is a measurement, not a copy-edit

content/docs/deployment/cli.mdx carries the step line inside a fence tagged transcript=os-build. The number written there is the sample fixture's real count, measured, not chosen:

  • N = 0, read off a real os build run.
  • Where measured: the fixture the page's own callout names — the blank starter from packages/create-objectstack/src/templates/blank (the two-field my_app_note object and the three connector plugins) plus the four-field ticket object, the view and the action from content/docs/getting-started/build-with-claude-code.mdx §3, renamed out of that page's support_desk_ namespace into my_app_, with the support app deliberately not added. Built out-of-tree in the session scratchpad against this branch's packages/, run through packages/cli/bin/run-dev.js.
  • The reconstruction is corroborated by the page's other numbers, which reproduce exactly on the same run and were not touched: Running author-time rules (45), Data: 2 Objects 6 Fields, UI: 1 Views 1 Actions, Runtime: 3 plugins.
  • Why 0: neither the blank template nor the walkthrough ships a src/docs/ directory, and the stack declares no inline docs:. The measured run is the transcript's own case of the sentence the card drafted.

Measured run, verbatim:

  → Checking capability providers (#3366)...
  → Collecting package docs (ADR-0046)... 0 collected
  → Writing artifact...

  ✓ Build complete (118ms)

The transcript-drift gate does NOT hold this number — and that is correct

Dispatch Zone 2 assumed check:docs-transcript-drift would hold the new value. Measured and falsified, so it is reported rather than relied on: that gate's TOKENS array in scripts/docs-audit/check-docs-transcript-drift.mjs carries exactly one row, author-time-rule-count, matching author-time rules \((\d+)\). It compares the 45 in this block and nothing else.

That is not a hole this PR opens. The gate is scoped by design to values a live registry derives; 0 collected is fixture identity, in the same class as 2 Objects 6 Fields and 1 Views 1 Actions, which the page's existing callout already covers ("everything else is fixture identity and reproduces"). A TOKENS row here would have to build a sample project rather than import a registry, which is a different gate. Named so the next author does not read the drift gate's green as vouching for this digit.

The number that gate does hold is unchanged by this PR, and check:docs-transcript-drift was run.

Tests

packages/cli/test/build-docs-step-count.e2e.test.ts pins the behaviour as a pair, because a test that only asserted "the step line was printed" passes on the defective tree — the defective tree printed it unconditionally:

fixture step line
no src/docs/ at all 0 collected
src/docs/ present and empty 0 collected
two docs 2 collected

Each run's printed count is also compared against the emitted dist/objectstack.json, so a number that drifted away from the set it describes cannot pass as text. The pre-fix spelling — the sentence with nothing after the ellipsis — is pinned absent. --json is asserted to stay one JSON document carrying no step text.

The suite spawns the CLI, so it reuses childEnv() and the bin/run-dev.js + tsx shape of build-json-advisory-parity.e2e.test.ts rather than inventing one.

⚠️ Where this pin runs, stated so nobody reads "tests added" as "gated on every PR". The .e2e.test.ts name puts it in this package's nightly tier: packages/cli/vitest.config.ts routes the population through OS_TEST_TIERS, so the queue and per-PR runs collect the 212 non-tier files and this file is not among them; the nightly on main collects the tier files, where it lands in integration by vitest-tiers.ts's SPAWN predicate. That is the package's own measured cost design — every one of its 60 spawners lives there — so a new spawner follows it rather than having me make a unilateral call about the Test Core critical path. Locally it was run under that switch, and pnpm check:tier-file-adoption is green.

Declared deviation from the claim's file surface

Claim 5696261079 declares a two-file surface. This PR carries four files, and the two extra ones are declared rather than quiet:

  • packages/cli/test/build-docs-step-count.e2e.test.ts — the pin the dispatching seat itself asked for in its suggested route ("the assertion that would have caught the original defect"), and what AGENTS.md's Post-Task Checklist step 1 owes.
  • .changeset/18432-docs-step-line-reports-count.md@objectstack/cli is a published package and this moves user-visible build output, so a patch changeset is owed and skip-changeset would be wrong.

No production file outside the two the claim names is touched. content/docs/releases/ and packages/spec/ are untouched.

Verification

Gate derivation is from the actual changed files, recomputed by the tool from the merge base rather than a hand-written list, and reconciled back with --ran carrying each command's own exit code (captured before any pipe):

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack
  -> 93 command(s), change set: the 4 files above, merge base 55fd5ee43

node scripts/pm/dispatch-gates.mjs --ran RAN_RECORD_FILE --repo objectstack-ai/objectstack
  -> 93 derived famil(ies) accounted for — 93 run, 0 NOT-MEASURED, 0 UNRUN
     (a DERIVED zero — all 93 recorded an exit code and none of them is 3)

92 of 93 green. The one non-zero is the known pre-existing red:

gate exit reading
pnpm check:cross-package-test-inputs 1 Pre-existing, not this PR. Its only finding is rooted in packages/cli/test/init-created-files-summary.e2e.test.ts descending packages/spec/dist/ — a file this diff never touches, and the new test file appears nowhere in the report. Filed as #18353 / #18348.

Five gates first answered PREREQUISITE NOT MET against a partly-built tree (check:skill-examples exit 1 on a missing packages/client-react/dist, check:dual-build-cjs-loads / check:i18n / check:i18n-coverage / check:i18n-walk-parity exit 3). Those are nothing was measured, not passes and not findings, so they were re-run after pnpm build and all five are exit 0. pnpm check:docs-transcript-drift, pnpm check:doc-anchors, pnpm check:doc-authoring, pnpm check:docs-single-h1 and pnpm check:nul-bytes are green on the edited page.

pnpm lint — the repo-wide eslint . --no-inline-config, which the derivation never names — was run whole, not narrowed: exit 0, no findings. No .cache/objectui-* existed in this worktree to pollute it.

Tests

pnpm --filter @objectstack/cli typecheck                     exit 0
  (check:test-typecheck: the test layer compiles under tsconfig.test.json;
   debt unchanged at 3 file(s) / 28 error(s) / 6 pinned signature(s))

pnpm --filter @objectstack/cli exec vitest run --project unit --shard=N/4
  shard 1  53 files / 883 tests passed
  shard 2  53 files / 750 tests passed
  shard 3  52 files / 622 tests passed
  shard 4  52 files / 737 tests passed          210 files / 2992 tests, all green

OS_TEST_TIERS=nightly pnpm --filter @objectstack/cli exec vitest run \
  --project integration test/build-docs-step-count.e2e.test.ts
  Test Files  1 passed (1)        Tests  5 passed (5)

Reverse verification — the pin can fail, proved rather than asserted. The fix was committed first, then the pre-fix ordering was restored on disk and the suite re-run:

HEAD blob:     a1c7dafe6eedaebf57e35c7ba865b6146b351f4e
ON-DISK PROOF: fixed-spelling count 1 -> 0; pre-fix-spelling count now 1
mutated hash:  a2b25a52a3bd89486f9266f0bd5e9de03de65d2c
result:        Tests  4 failed | 1 passed (5)
restored:      hash matches HEAD blob and `git diff HEAD` is empty

⚠️ The predicted direction, stated before the run and then observed: four red, one green. The --json case is a control, not a regression detector — --json prints no step line on either tree, so a run in which it also went red would mean the ablation had hit something other than the ordering. The four behavioural pins are the ones that must move, and they did. The mutation was proved to reach disk by occurrence count on the text being replaced, not by the editor's exit code; the restore is proved by blob-hash equality plus an empty git diff HEAD, not by a return code, and it runs from an EXIT INT TERM trap with an absolute path.

Where the measurement of N happened, reproducibly

$ cd FIXTURE_DIR        # blank starter + ticket object/view/action, my_app_ namespace
$ tsx packages/cli/bin/run-dev.js build
  → Running author-time rules (45)...
  → Checking capability providers (#3366)...
  → Collecting package docs (ADR-0046)... 0 collected
  → Writing artifact...
  ✓ Build complete (118ms)
  Data: 2 Objects  6 Fields
  UI: 1 Views  1 Actions
  Runtime: 3 plugins

The fixture was built in the session scratchpad, outside the repository, and deleted; nothing of it is in this diff.

Acceptance notes

Authored by Claude Code in session session_01DvvamiacK328idtBYJBxV3.


Generated by Claude Code

…hat it attempted

`os build`/`os compile` printed `Collecting package docs (ADR-0046)...`
unconditionally and BEFORE the call it announces, so a build that collected
nothing emitted the same reassuring sentence as one that collected four
documents. Move the print after `collectAndLintDocs` and carry
`docsResult.docs.length` in it.

Pinned from both ends (absent `src/docs/`, empty `src/docs/`, two docs) so a
test asserting only that the sentence was printed cannot pass on the defective
tree, and the printed count is compared against the emitted artifact's `docs`
set rather than read as text alone.

Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3
Co-authored-by: Claude <[email protected]>
The `transcript=os-build` block on `content/docs/deployment/cli.mdx` quotes the
docs step line. The sample fixture behind that page ships no `src/docs/`, so the
line it now prints is `0 collected` — measured by rebuilding the fixture the
page's own callout names (blank starter + the ticket object, view and action
from `build-with-claude-code`, renamed into `my_app_`) and reading the count off
the run, not by picking a plausible number.

Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3
Co-authored-by: Claude <[email protected]>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Sep 16, 2026
@github-actions

github-actions Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 1 documentable anchor(s).

17 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json b6fe311a9ab7bebdfb22631030ac19ebeb87c6a5.

3 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • 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 — 24 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 b6fe311a9ab7bebdfb22631030ac19ebeb87c6a5packageMentionDocs.

Which tree this was computed on

This run read content/docs from 351fca64fc7621e68cfbf6ec182de81b924c1349 — the merge of head 1d2d6946bb7cb2c03a11cea6b0691d601a70f22e into base b6fe311a9ab7bebdfb22631030ac19ebeb87c6a5, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 351fca64fc7621e68cfbf6ec182de81b924c1349 && git checkout 351fca64fc7621e68cfbf6ec182de81b924c1349
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin b6fe311a9ab7bebdfb22631030ac19ebeb87c6a5 1d2d6946bb7cb2c03a11cea6b0691d601a70f22e && git checkout -B drift-repro b6fe311a9ab7bebdfb22631030ac19ebeb87c6a5 && git merge --no-ff 1d2d6946bb7cb2c03a11cea6b0691d601a70f22e

node scripts/docs-audit/affected-docs.mjs --json b6fe311a9ab7bebdfb22631030ac19ebeb87c6a5

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs b6fe311a9ab7bebdfb22631030ac19ebeb87c6a5 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

A CLI spawn through tsx costs seconds, so the five cases timed out against
vitest's 5s default. Same per-test spellings the sibling spawners in this
directory use (120_000, and 180_000 for the three-run case).

Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3
Co-authored-by: Claude <[email protected]>
@os-support-ai
os-support-ai marked this pull request as ready for review September 16, 2026 11:50
@os-support-ai
os-support-ai added this pull request to the merge queue Sep 16, 2026
Merged via the queue into main with commit c2815a2 Sep 16, 2026
51 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-18432-docs-step-line-reports-count branch September 16, 2026 12:14
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/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cli: os build's package-docs step line prints before the collection it announces, so a build that collected nothing reads identically to one that did

2 participants