Uh oh!
There was an error while loading. Please reload this page.
fix(cli): os build names the author-time warnings it withheld instead of stopping dead at 50 - #11645
Conversation
The author-time advisory printer emitted a fixed 50 detailed entries and then stopped, with nothing in the output saying the list had been cut. Measured on objectstack-ai/hotcrm with the published 17.1.0 CLI: two `objectstack build` runs over the same tree, before and after a five-warning fix, printed 50 detailed entries each (184 output lines, 52 warning lines both times) while the summary line counted 80 and then 75. The defect is the silence, not the cap: truncated output carrying no notice is indistinguishable from complete output. The cap stays; over it the printer now names the exact remainder and points at `--json`, which already publishes the whole set. At or under the cap the rendering is byte-for-byte unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019siH5jDmk5hrayvfyojUqR
📓 Docs Drift CheckThis PR changes 1 package(s): 17 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 4 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 23 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 3f7de223580fa07e0ba22432e3e63f94d98cc2a1 && git checkout 3f7de223580fa07e0ba22432e3e63f94d98cc2a1
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e3f056fce5e7137e82e9ca25206db16b2a112866 81dbb44a5cbd739e26bc2dda4c3b4e3aa6c475be && git checkout -B drift-repro e3f056fce5e7137e82e9ca25206db16b2a112866 && git merge --no-ff 81dbb44a5cbd739e26bc2dda4c3b4e3aa6c475be
node scripts/docs-audit/affected-docs.mjs --json e3f056fce5e7137e82e9ca25206db16b2a112866
|
os-zhuang
commented
Aug 24, 2026
ACCEPT — PM seat review ( |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#11529
os buildprinted a fixed 50 author-time advisories and then stopped, with nothing in the output saying the list had been cut. The card measured it onobjectstack-ai/hotcrmwith the published 17.1.0 CLI: two runs over the same tree, before and after a five-warning fix, printed 50 detailed entries each — 184 output lines and 52 warning lines both times — while the summary line counted 80 and then 75. Removing five warnings did not shorten the list, it made room, and five advisories that had been present all along appeared for the first time.The defect is the silence, not the cap. Truncated output carrying no notice is not merely incomplete, it is indistinguishable from complete: an author who reads the report and sees their file is clean has read a list that stopped early. Same shape as the two summary-row fixes this lane closed earlier in the round (
UI: 0 Appsand thenext: nulloverload) — output that cannot distinguish "none" from "not shown".What changed
Three files plus a changeset.
packages/cli/src/utils/format.tsprintAuthoringAdvisories(advisories, limit), plus theAuthoringAdvisoryrecord type andAUTHORING_ADVISORY_PRINT_LIMIT = 50. Renders the list and, when it cut one, names the exact remainder.packages/cli/src/commands/compile.tsbuildis an alias ofcompile, so this is the single printer for both.packages/cli/test/build-warning-truncation-notice.test.ts.changeset/build-warning-truncation-notice.md@objectstack/cli.Over the cap the output now reads:
At or under the cap no such line appears and the detail entries are byte-for-byte what they were. The pointer is
--json, which already publishes the whole set underwarnings(compile.ts:466) — an existing complete-output path rather than a new flag.Scope held. No new verbosity tier, no paging, no configuration surface, no redesign of the warning system — triage ruled that out and nothing here reaches for it. The cap itself is unchanged at 50.
Premise check against
origin/main— one claim in the card does not reproduceThe card says "
objectstack validateprints the same truncated set". Onorigin/mainat50fb191dit does not:validate.tscollects every advisory into onewarningsarray (lines 268-301, includingfor (const f of ruleAdvisories)at 291) and prints all of it uncapped at line 321. Only its error lists are capped (ruleErrorsat 140,docErrorsat 212), and both exit 1. So the truncation is abuild/compiledefect only, and this PR touchescompile.tsalone. The changeset says so too, so the release notes do not repeat the claim.The central premise holds and is fixed here.
The pins assert the pair, not the cap
A test that only checked "50 entries printed" passes on today's silent tree and pins nothing. So each end is pinned:
and N more author-time warning(s) not shown, plus the(shown of total)pair);Plus the tightest edge (one over the cap reads exactly
1), an exact-remainder check at a non-default limit, and two controls: the detail entries are unchanged and the 51st is still absent, and an empty set prints nothing at all.Altitude: this pins
printAuthoringAdvisories, which is now the whole ofos build's advisory block, rather than spawning the CLI — the precedent set byprint-metadata-stats-zero-row.test.tsfor the sibling fixes in this family and byformat-zod-union.test.tsbefore it. No child process, so nothing here goes nearcheck:cli-test-child-env's spawner rule, and no baseline entry was added or edited.Anti-vacuity: shown failing without the fix
Prediction recorded before running — deleting the notice block turns 3 tests red (
OVER the limit,ONE over the limit,the remainder is the EXACT count) and leaves 4 green (AT the limit,UNDER the limit, and both controls), because the green half is what makes the pair an assertion rather than a count.Observed, exactly that:
with the three failures being the three predicted ones. The mutation was proven on disk before the run, anchored on the exact text in both directions — injected marker
1(want 1), removed notice line0(want 0) — because an editor's exit code proves nothing and a zero-hit replace exits 0. The script carriedtrap … EXIT INT TERM; the trap fired from the wrong working directory and did not restore, which was caught by re-reading the file rather than by trusting the trap, and the tree was restored explicitly (marker=0 notice=1,git statusclean) and re-measured green at 7/7.No rebuild leg was needed and none is claimed: the test resolves
../src/utils/format.jsrelatively into this package's ownsrc/, so vitest transforms the mutated source directly. The ablation's dist condition — subject resolved through a dependency'sexports— does not apply here, and no mutated artifact could survive into a later run.Clause-②: measurednoThe dispatch expected
no; measured rather than inherited.packages/clideclares noexportsmap,mainisdist/index.js, andsrc/index.tsre-exports command classes only — it does not re-exportutils/format.js. The three new symbols are therefore internal to the package. No accept set moves, no schema or spec change, exit codes and the emitted artifact are untouched, and--jsonpayloads are unchanged. The only user-visible movement is one added line of human-readable stdout, which is what the changeset declares.Verification — union run at
81dbb44a, the final commitGate set derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(it read the change set from git itself: 4 paths vs merge base50fb191dc), not from a hand-built path list. Each gate's own verdict line:check:nul-bytescheck-nul-bytes: OK (scanned 6504 text file(s) ... no raw ASCII control bytes)check:cli-test-child-env✓ check:cli-test-child-env: 28 spawner source(s) among 84 under packages/cli/test/**; no new bulk process.env copy reaches a spawned child (18 baselined in 17 file(s), SHRINK-ONLY; 2 deliberate site(s) still pinned)check:cross-package-test-inputsOK: 16 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.check:test-source-aliascheck-test-source-alias OK — 72 packages with tests scannedcheck:type-source-resolutioncheck-type-source-resolution OK — 77 packages with a tsconfig.json scannedcheck:published-files✓ check:published-files — 69 publishable package(s) of 78 workspace member(s) declare a files whitelist ...check:slot-lookup✓ slot-lookup ratchet holds: 107 unswept site(s) in 25 file(s), none newcheck:query-options-erasure✓ query-options-erasure ratchet holds: 67 unswept non-test site(s) in 17 file(s), none newcheck:where-matcher✓ where-matcher conformance holds: 292 matcher(s) discovered ... none newcheck:engine-double-contractcheck-engine-double-contract: OK — 397 pinned, 133 in the DEBT ledger, 2 exempt.check:plugin-teardown-shape✓ check:plugin-teardown-shape: 63 Plugin implementation(s) across 4584 source(s) ...check:ci-filter-parityOK: all 95 declared cross-package glob(s) (80 unique) are covered ...check:changeset-gate-self-tests✓ check-empty-changeset / check-adr-0087-registration / check-changeset-no-major --self-testall passcheck-adr-0087-registration✓ this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen).check-changeset-no-major✓ This diff introduces no major bump.check-empty-changeset✓ No empty-frontmatter changeset introduced by this diff (1 declaring changeset(s) added).check:objectui-changeset✓ objectui-range --self-test: all checks passedrelease-rehearsal-clone --self-test✓ self-test passeddocs-audit/check-affected-docs✓ affected-docs self-test: 381 cases pass.check:type-check-coveragecheck:i18ncheck-i18n-bundles: OK (9 package(s) — all bundles in sync, no undeclared authoring keys).check:i18n-coveragecheck-i18n-coverage: OK (12 config(s), 602 baselined untranslated string(s), none new).check:type-check-debtcheck-type-check-coverage --re-measure: OK — 32 ledger entr(ies) re-measured in 274.4s, 1897 raw tsc error(s) total, none above its recorded number.Two gates refused on the first attempt and are reported as re-run to a real verdict, not as passes.
check:i18n-coveragereturnedCOULD NOT MEASURE — 1 of 12 config(s) failed to lintbecause@objectstack/connector-mcphad no build output in this worktree, andcheck:type-check-debtneeds the workspace closure built. Both were re-run afterpnpm exec turbo run build --concurrency=2 --filter=./packages/* --filter=./packages/*/*finished green (Tasks: 70 successful, 70 total), and the verdicts above are from those second runs.git statuswas clean after that build — no generated-artifact drift.Package checks:
pnpm --filter @objectstack/cli typecheck—tsc --noEmit, clean (VERDICT command-exit 0).pnpm --filter @objectstack/cli build— clean.packages/clisuite, run in three shards to fit the container's foreground limit, all green: 57 files / 783 tests, 56 / 565, 56 / 567 — 169 files, 1915 tests, 0 failures. No narrowing.Every heavy command went through
scripts/pm/os-verify-lock.sh; the verdicts quoted are the wrapper's ownVERDICTlines, never a bare exit status.Findings filed, not fixed here
build/validate/initprinters #11642 — eight more silent 50-entry truncations in the same CLI (compile.ts235/293/333/360,validate.ts140/212,init.ts893/908). Two of them are the same advisory-class defect as this card;compile.ts:293even prints the true total in its header and then shows 50. Left alone deliberately: triage scoped this card to the author-time warning printer and said widening was not asked for.os build --jsondrops the undeclared-authoring-key warnings thatos validate --jsoncarries #11643 —os build --jsonomits the undeclared-authoring-key warnings thatos validate --jsoncarries. This is why the notice added here points at--jsonfor the authoring-rule advisories only: for the second list that pointer would be false, so that list was left without a notice rather than given a broken remedy.Neither is addressed in this PR, and both were filed unassigned. In-flight #11485 also lives in
packages/cli(i18n-coverage.jsandos i18n extract); no file it touches is touched here.Generated by Claude Code