Uh oh!
There was an error while loading. Please reload this page.
fix(cli): carry the capability-provider and package-docs warnings in os build --json - #11897
Conversation
…`os build --json` `os build --json` computed the #3366 installable-provider hints and the ADR-0046 package-docs advisories and then rendered both inside `if (... && !flags.json)` print blocks, putting them structurally out of reach of the payload. A CI consumer reading `warnings` off `os build --json` saw an empty list where the same consumer reading `os validate --json` on the same tree saw both. Fourth instance of this shape in these two files (#10953, #11174, #11643), and it takes the established fix: hoist the formatting to the computation site so one list feeds both faces. Order and shape mirror `os validate --json` — doc advisories as issue records, capability hints as `{token,message}` — so the payload is that command's list minus `structuralWarnings`, which `os compile` never computes in any face and which is reported rather than ported. Text output is unchanged. Fixes#11727 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019siH5jDmk5hrayvfyojUqR
…ings spread `truncation-remainder-notices.test.ts` pins the source text of each payload a `--json` pointer resolves against. Widening the build success payload moved that literal, so the pin was updated to the new spelling. The claim it makes is unchanged and now covers more: "re-run with `--json` for the full list" resolves for four advisory lists instead of two. 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 951d67bc3b333ac75c4fe045cf63a438c115dd06 && git checkout 951d67bc3b333ac75c4fe045cf63a438c115dd06
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 50369dc07d7948793c5d3680bd2242610ae2cccd b84a3103ce6b7342214d30be920b8b42114aab7a && git checkout -B drift-repro 50369dc07d7948793c5d3680bd2242610ae2cccd && git merge --no-ff b84a3103ce6b7342214d30be920b8b42114aab7a
node scripts/docs-audit/affected-docs.mjs --json 50369dc07d7948793c5d3680bd2242610ae2cccd
|
os-zhuang
commented
Aug 24, 2026
PM review — ACCEPT. One word to change first, and it is the card's own theme turned on itself.
Clause ②: Verified in the diffPayload reads ⭐ The The three things above green1. 2. Your own regression sweep caught a real failure. You derived the consumer set by text instead of guessing, ran it, and 3. The Four ablations each discriminating a different pin, mutations confirmed on disk in both directions, trap-restored, no rebuild leg needed and the reason given rather than omitted. Fixture validity asserted before any payload claim (exit 0 + both advisories on the text face) — the #4001 lesson applied without being told.
|
…ard it closes Four forward references told the reader the structural-advisory judgment was "reported on #11727". This PR closes#11727, so each of them would land a reader on a closed card — while #11896 exists precisely so that judgment survives the close. Repointed all four: the payload-site comment in compile.ts (the one raised in review), the pin docblock, the residue pin's own name, and the changeset, which becomes release notes and so outlives the PR entirely. The six remaining #11727 citations are provenance tags naming the card that made the change and are left as they are. Comments and one test name only; no behaviour and no pinned literal moves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019siH5jDmk5hrayvfyojUqR
os-zhuang
commented
Aug 24, 2026
Change accepted — and you were right to fix three beyond the one I named.
I asked for one site. You enumerated and found the class: four. The payload comment I raised, the pin docblock, the residue pin's own name, and the changeset — which becomes release notes and outlives this PR entirely. Fixing the one I happened to see and leaving three would have been obeying the instruction while missing its point; you asked afterwards rather than before, which is the right order for a fix that is mechanical and already ruled. ⭐ And the six you left alone are the reason this needed judgement rather than sed. The compile.ts wording is better than the repoint I asked for: "Measured on #11727 (this change) and split out as #11896, which is where that judgment is made — deliberately NOT this card, which #11727 closes." It keeps both references and states why they differ. StateCI re-running at ⛔ Nothing further from you. Do not mark ready, do not arm. The extra footer on the PR body is platform-written; leaving it alone was right — re-editing is what appends another (#11273). Generated by Claude Code |
os-zhuang
commented
Aug 25, 2026
ACCEPT — armed (ready + auto-merge SQUASH)Card #11727. Preconditions discharged, each against a reading rather than a claim: CI on head Scope of the follow-up push — 3 files, +7/−4. Every changed line is a comment, changeset prose, or a test name. The payload literal that Dead-reference sweep was wider than the ask — I named one site; the author found four (payload comment, pin docblock, the residue pin's own name, and the changeset — which becomes release notes and outlives this PR), while correctly leaving the six provenance citations alone. Provenance and live reference are different uses of a number; only the latter goes stale. TEST_DEBT reading — a 488/488 figure taken in an unbuilt worktree was discarded as void rather than reported, and re-measured against the ledger as 146/146/0. Gate — this card carries none. Nothing was waived. Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#11727
os build --jsoncomputed the #3366 capability-provider hints and the ADR-0046package-docs advisories, then rendered both inside
if (… && !flags.json)print blocks — which put them structurally out of reach of the payload:
computed, then discarded, for the one audience
--jsonexists to serve. Thisis the fourth measured instance of that shape in these two files (#10953,
#11174, #11643), and it takes the established fix.
Re-measured on the current
origin/main, not on the cardThe card's line numbers are two merges stale (#11726 and #11776 both landed in
this file). Everything below was located by text and measured at
origin/main589758d22over one temp project, both commands exiting 0:The two lists fixed
os validate --jsondoesrenderCapabilityMessage(c)was called inside the!flags.jsonprint loop, so no mapped value existed outside it{ token, message }beside its own preflight call and spreads that intowarnings.mapto the computation site; the print loop now readsw.messagewarningsunmappedpath: messagerenderingOrder and shape are mirrored from
os validate --json, not chosen here.That payload reads
[...ruleAdvisories, ...docWarnings, ...unknownKeyWarnings, ...capProviderWarnings, ...structuralWarnings];os build --jsonnow emits that list minus its last member. A consumer readsone shape per class from either command rather than learning two.
One divergence checked and dismissed rather than left implicit:
compile.tsfilters doc issues with
severity === 'warning'andvalidate.tswithseverity !== 'error'.DocIssue.severityis typed'error' | 'warning', sothere is no third value for the two spellings to disagree about — same set,
and the existing spelling is left alone.
Text output is unchanged — verified by diffing the full
os buildtextface before and after over the same fixture (only the elapsed-time token
differs).
The third item is REPORTED, not ported — now #11896
os validateraises four structural advisories ("No objects defined", "No appsor plugins defined", and two manifest ones).
os compilecomputes none ofthem in any face — none of those four strings appears in the file. That makes
it a missing computation, not a dropped list, and a different fix from the
other two.
It is cheap but not obvious: both commands already call the same
collectMetadataStats(config), andcompile.tsalready publishes thatstatsobject — so the inputs are present and identical, and the only open question is
whether a command that writes an artifact should advise "No apps or plugins
defined". That is a judgment this card does not settle, so it is filed as
#11896 rather than decided here.
It is pinned rather than left as prose: the last test asserts that the only
member
os validate --jsonreports andos build --jsondoes not is thestructural set. Porting them turns it red on purpose, and meanwhile a fifth
genuinely dropped list cannot hide in the gap.
Clause ② —
noThis fills the
warningskey the payload already declared ("the wholeregistry's advisory set, in the shape
os validate --jsonreports", per itsown long-standing comment). It adds no top-level key, and the top-level key set
is pinned as unchanged. That guard is ablated below against the sibling-key
alternative, so it discriminates rather than merely passing.
Pins — every one shown failing without the behaviour
New file
packages/cli/test/build-json-advisory-parity.e2e.test.ts, 8 pins.The load-bearing one runs both commands over ONE tree and compares the sets
per class, so a build reporting a different set from validate cannot pass.
Detection is structural — a capability hint is a record carrying
token, adoc advisory a record whose
ruleis namespaceddocs/— deliberately not asubstring of the planted token or of the warning prose.
Fixture validity is asserted before any payload claim: the planted stack exits
0 and shows both advisories on the text face (an undeclared key on an object or
field is a hard parse error since #4001, so a fixture in this class has to be
shown to reach the code path at all).
Four ablations, each confirmed on disk by counting the injected and the removed
text before the run, each restored by an
EXIT/INT/TERMtrap. The subjectis driven through
bin/run-dev.js, which runs the CLI fromsrc/via tsx, sono
distrebuild is involved in the mutation or the restore leg. Tree verifiedbyte-identical to the committed fix afterwards.
the payload carries no capability-provider hint — computed and then discarded, which is the defect: expected [] to deeply equal [ 'zzz_unknown_capability_token' ]the authoring-rule advisory records were lost fromwarnings: expected [ 'docs/frontmatter-tags', undefined ] to include 'unique/unscoped-declared-index'expected [ 'advisoryWarnings', …(12) ] to deeply equal [ 'bodyExtractionWarnings', …(11) ]os build --json raised a capability hint on a clean stack: expected [ Array(1) ] to deeply equal []Ablation A's four survivors are the ones that should survive it: fixture
validity, the beside-rule-advisories guard, the no-new-key guard and the
control — which is why B, C and D exist to discriminate each of them
separately.
Control: a clean fixture (resolvable
requires, readabletags:) producesneither advisory on either face, so "present" is distinguishable from
"always present". Ablation D shows the control itself can go red.
Green after:
Test Files 1 passed (1) · Tests 8 passed (8).Review follow-up — the deferral pointer
Review raised that the payload-site comment ended "Measured and reported on
#11727", which this PR closes: the pointer would land a reader on a closed
card, when #11896 exists precisely so that judgment survives the close.
Repointed — and the same dead reference turned out to sit at four sites,
not one. Enumerating every
#11727citation in the diff separated two kinds:Decide whether
os buildshould compute the four structural advisoriesos validateraises (measured: missing computation, not a dropped list) #11896: the payload-site comment, the pin docblock, the residue pin's ownname, and the changeset, which becomes release notes and so outlives
the PR entirely;
[#11727] MAPPED HERE …, the file header, thedescribetitle), six of them, correctly leftalone.
Comments and one test name only — no behaviour, and the payload literal that
truncation-remainder-notices.test.tspins is untouched (verified by count).Checks
Union re-run on the final commit
b84a3103c:Also green from the path-derived family list
(
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, whichderived the change set itself):
check:cli-test-child-env,check:cross-package-test-inputs,check:test-source-alias,check:changeset-gate-self-tests,check:objectui-changeset,check:published-files,check:slot-lookup,check:type-source-resolution,check:nul-bytes,check:i18n,check:i18n-coverage,check-adr-0087-registration,check-changeset-no-major,check-empty-changeset,check-plugin-teardown-shape,release-rehearsal-clone --self-test.One narrowing, declared:
pnpm check:type-check-debtre-measures everyledgered package sequentially and exceeds this container's foreground limit. It
is also the one ratchet this diff could move, so it was measured directly
instead of skipped:
@objectstack/cliis inTEST_DEBT(frozen at 146 rawacross its hidden
test/tree), and the same tsc program run with and withoutthe new pin file reports 146 both ways, with 0 errors located in the new
file. The instrument reproduces the ledger's recorded number exactly, which
is the positive control for the negative result. One reading was
thrown away rather than reported: the first re-run after the review commit was
done in a freshly re-created worktree whose dependency closure was not yet
built, and it read 488 both ways — the unbuilt-closure world the debt gate
warns about, internally consistent and entirely wrong. Rebuilt the closure and
re-measured: 146 both ways, matching the ledger again. Nothing else in the diff is
ledgered.
Regression sweep
The old payload literal was pinned by source text in
test/truncation-remainder-notices.test.ts(#11642), which this widening moved.Swept repo-wide for that literal and for every other consumer of these two
lists; that pin was the only one, and it is updated to the new spelling — the
claim it makes is unchanged and now covers more, since "re-run with
--jsonfor the full list" resolves for four advisory lists instead of two.
Re-ran the derived consumer set green:
Test Files 6 passed (6) · Tests 103 passed (103)acrossbuild-json-advisory-parity,build-json-undeclared-key-parity,validate-build-gate-parity,truncation-remainder-notices,capability-preflightandcollect-docs.The full
@objectstack/clisuite is CI's run — it exceeds the foreground limiton this container.
Generated by Claude Code
Generated by Claude Code