Repository navigation
feat(cli): Boot diagnostics noise budget, printer half: the line that needs the author first with its fix, stack traces only at debug - #22236
Conversation
The default banner's Boot diagnostics block now prints a record from a closed table of actionable classes first, once, highlighted, with the producer's own one-line fix under it (today: action-governance's declared script actions with no handler). The header counts the actionable records apart from the informational ones. A captured record's stack trace is withheld and counted; --log-level debug streams the same record live, stack included, because serve never opens the quiet window at that level. Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU Co-Authored-By: Claude <noreply@anthropic.com>
The dead-button record from objectql's real action inventory, logged by the real ObjectLogger in all three formats, prints once, first, highlighted, with the producer's own fix line, and the header counts it apart. A captured record's stack is withheld at the default level with its message kept; at --log-level debug the same record streams live, stack included. The three header strings the earlier print-once legs asserted move to the new header, their withheld counts unchanged. Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU Co-Authored-By: Claude <noreply@anthropic.com>
…e line The blank starter from the real on-ramp, given the tutorial's ticket object and its handler-less Resolve action, boots real os serve; Boot diagnostics highlights exactly that one record with a fix line, counts it as the one needing attention, and carries no stack trace. No informational count is pinned. Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU Co-Authored-By: Claude <noreply@anthropic.com>
Also drops the header wording the pending one-line-per-class entry quoted verbatim, which this change replaces; its withheld count stays. Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU Co-Authored-By: Claude <noreply@anthropic.com>
The tutorial now writes Resolve as a declarative update with no handler, so the boot pin carries it beside a handler-less Escalate script action: exactly one line is highlighted, and Resolve is named on none. The unit pin and the changeset stop calling the handler-less shape the tutorial's. Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU Co-Authored-By: Claude <noreply@anthropic.com>
📓 Docs Drift Check9 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 28 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 17c9816e10866aa0d2aea71af270a2ada7ae378b && git checkout 17c9816e10866aa0d2aea71af270a2ada7ae378b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 0e9371f0c6104922e19b9bdaabc993b4d3dbca61 f8a80640b09ada72e2ed4ac36199166cab5fcc89 && git checkout -B drift-repro 0e9371f0c6104922e19b9bdaabc993b4d3dbca61 && git merge --no-ff f8a80640b09ada72e2ed4ac36199166cab5fcc89
node scripts/docs-audit/affected-docs.mjs --json 0e9371f0c6104922e19b9bdaabc993b4d3dbca61 |
|
Confirmation from the The edit to
|
Part of #22160 (the printer half; owners' levels routed)
Clause-②: no
The maintainer's ruling, quoted on the card: 「建议给 dev 模式定一个"噪音预算":预期中的降级记 info,堆栈只在
--log-level debug出现,真正需要动手的那条单独高亮并给一行修法。」 This PR is the printer's half, per the seat's scope cut (claim6053785493). The level each other lane's line is logged at stays with its owner. The table below names each owner.What changes (
packages/cli/src/utils/format.ts,printBootDiagnosticsonly)ACTIONABLE_BOOT_CLASSES, holds one row today:@objectstack/objectql's[action-governance] declared script actions with NO handler(a dead button). It is matched the way fix(cli,plugin-auth): one boot line per warning class, each printed once, and the loopback OAuth notice at info #22097'srestatedAbovematches. The highlighted line is the record's statement plus its subjects (theactionslist from the record's structured tail). The fix is derived from the producer's own message: the text after its;, asleadSentencederives a flow reason. Nothing is hand-copied. A reworded producer that drops the;still prints highlighted and whole. It is never dropped.⚠ Boot diagnostics — 1 needs your attention · 2 informational:. With nothing actionable the header readsℹ Boot diagnostics — 4 informational (2 more already listed above):, with no alarm glyph. The exception is a capture that dropped records: the printer has not read those, so the header keeps the⚠.stackproperty whose value is a V8 trace is dropped. Astackkey that names something stays. The message stays. A record without a trace prints byte-identical. The last line counts what was withheld and points at--log-level debug.--log-level debug(andinfo),servenever opens the boot-quiet window (isVerboseBootLevel). The same record streams live asObjectLoggerrendered it, stack included, and no replay block prints. Measured both before and after (below).serve.tsis untouched.restatedAboverules are unchanged.Measured (
origin/main7d7943dd, builtpackages/cli/dist,os dev --fresh)Blank starter (from
packages/create-objectstack/src/templates/blank, namespacesupport_desk) plus the tutorial's four files, extracted verbatim frombuild-with-claude-code.mdxas it stood at7d7943dd,--ui. At that commit Resolve was a script action with an unregisteredtarget. #22204 has since made it a declarative update, which needs no handler (see the re-measure after the merge, below):examples/app-showcase(dev --seed-admin --fresh): before,⚠ Boot diagnostics — 4 warnings logged during startup (2 more already listed above):with thesys_migrationstack. After,ℹ Boot diagnostics — 4 informational (2 more already listed above):with the stack withheld. The four records are[Analytics],[SettingsService],sys_migrationand[sharing-rule], none actionable. The banner's twoFlows:class lines are unchanged.--log-level debugon the blank project, before and after: 0 replay blocks; thesys_migrationrecord streams live 1 time, carrying"stack":"SqliteError…1 time.On
mainthe blank project shows 3 records, not the card's 4. The loopback OAuth line moved toinfoin #22097 and is gone at the default level.Re-measured after merging
origin/main(7b926f76, which carries #22204), at headf8a80640. The blank starter plus the tutorial's current four files (Resolve is nowoperation: 'update'+patch) printsℹ Boot diagnostics — 2 informational:, which is[Analytics]and thesys_migrationinsert with its stack withheld, plus the hint line. Nothing there needs the author any more. The two remaining lines are #22154's and #22099's to lower.Each non-actionable line and its owner (H5)
[Analytics] No admitObjectRead configured and no "security" service registered at init …packages/services/service-analytics/src/plugin.ts:1450domain:servicesInsert operation failed {"object":"sys_migration", …}packages/objectql/src/engine.ts:14006. The duplicate insert is plugin-auth's default-org owner bind recording idadr-0093-default-org-owner-bindtwice (debug stream, blank project)domain:services(plugin-auth)[SettingsService] Pre-bind READ of namespace 'auth' …packages/services/service-settings/src/settings-service.ts:774domain:services[sharing-rule] active business-unit rule expands to NO recipients …packages/plugins/plugin-sharing/src/sharing-rule-service.ts:1524N flow(s) declare a 'schedule' / 'time_relative' trigger but are NOT bound — disabled by deployment policy …⚠), restatingservice-automation'swarnprintAutomationSummary(this file) restatingpackages/services/service-automation/src/plugin.ts:1533service-automation; see the open question in the reportThe dev did not search the tracker for the three "none known" rows. The role file reserves search for the filing seat. Dedupe words are in the report.
Pins
packages/cli/src/utils/format.boot-warning-classes.test.ts(unit tier; 11 existing + 7 new legs):it.eachover pretty / text / json): a realObjectLoggerwrites through the realBootLogCapture. The realrunActionGovernanceInventoryruns over a ticket whose Resolve is a script action with an unregisteredtarget. The dead button prints once, first, highlighted, ending: support_desk_ticket:resolve_ticket. The next line isfix:plus the inventory's own message after its;, read off the producer at call time. The header carries1 needs your attention · 2 informational.Erroris captured with its escaped stack (premise asserted). It prints withobjectanderror.messageand no"stack". No escaped frame is anywhere on screen. One hint line names the count and--log-level debug.--log-level debug:isVerboseBootLevel('debug')holds. A debug-levelObjectLoggerwrites the same record to the terminal with its stack.stackkey that is not a trace prints unchanged. A capture with dropped records keeps the⚠.(3 more already listed above),(1 more …)), and every class and print-once assertion is untouched.packages/cli/test/serve-boot-diagnostics-noise-budget.e2e.test.ts(new; integration tier by behaviour, nightly by name). The blank starter is scaffolded through the real on-rampbin/. Added to it: the tutorial's ticket object, its current declarative Resolve, and oneEscalatescript action whosetargetnothing registers. Realos servethen boots. Boot diagnostics highlights exactly Escalate's record, with onefix:line. Its header says1 needs your attention. Resolve, the control in the same boot, is named on no line, and no stack trace reaches the block. No informational count is pinned, because the owners above are moving those.Ablations
Each ran on the committed fix through
scripts/ablation-replace.mjs(WRAP mode). The unit legs ran at77f6a48c. The boot-pin leg ran at77f6a48cand again atf8a80640, red both times;format.tsis the same blob at both. Each anchor hit 1 time, the write was verified on disk by blob change, and each restore was provenblob == HEADwith an emptygit diff HEAD. The test subjects importformat.ts/boot-log-capture.tsfrom source, so nodistis involved. Expected direction: red. Observed: red every time.stacktraces keptat = -1)stackwithheld, trace or notisVerboseBootLevelwithoutdebugFinal restore proof:
format.tsblob9dc1b9d9andboot-log-capture.tsblobd2545d2eequalHEAD's, andgit diff HEADis empty.Tests and gates
All readings at head
f8a80640, after mergingorigin/main7b926f76; the merge had no conflicts and the CLI closure was rebuilt, 59/59.pnpm --filter @objectstack/cli typecheck: exit 0.tsc --noEmitpassed, thencheck:test-typecheck: OK … 3 file(s) / 28 error(s) / 6 pinned signature(s), unchanged. Both test files are in a tsc program (--listFilesOnly): the unit pin undertsconfig.json, the e2e undertsconfig.test.json.pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2:Test Files 263 passed (263),Tests 3881 passed (3881).OS_TEST_TIERS=nightly pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2 test/serve-boot-diagnostics-noise-budget.e2e.test.tsgaveTests 3 passed (3). The rest of the integration tier is declared to CI.node scripts/pm/dispatch-gates.mjs --commandsderives 65 for this change set (5 paths vs merge base7b926f76). Against the order's list, that addscheck:cli-test-child-envand dropscheck:dispatcher-error-vocabularyandcheck:route-envelope, which no path here reaches. I ran the union of 68, fullpnpm lintincluded. 67 exit 0.node scripts/check-empty-changeset.mjs --base origin/mainexits 1: that is the release-note correction named under Changeset.dispatch-gates --ran:65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN.pnpm lint(eslint . --no-inline-config): exit 0.e1a46a46, before the merge,check:dual-build-cjs-loadsprinted PREREQUISITE NOT MET because eight packages had nodist, so it measured nothing. After building them it was green (106 require entries across 66 packages load), and it is green atf8a80640.Changeset
.changeset/22160-boot-diagnostics-noise-budget.md,@objectstack/clipatch.A pending release note is corrected here, and that needs a person's confirmation. One sentence in
.changeset/22073-boot-warning-one-line-per-class.md(pending, not yet released) quoted the old header verbatim:⚠ Boot diagnostics — 5 warnings logged during startup (8 more already listed above):. This PR changes that header, so the sentence would publish false. It now quotes only the withheld count,(8 more already listed above), which stays true; nothing else in that note moved.node scripts/check-empty-changeset.mjs --base origin/mainis red on this PR by its own design. It refuses any edit to a changeset the PR did not add, and for a deliberate correction it asks the PR to name the note and get it confirmed. The alternative is to restore the note from base and let the superseded sentence publish.Acceptance notes
0 warnings; the showcase boots with no non-actionable line aboveinfo) depends on the owners in the table above.--log-level infothe quiet window does not open either, so a record's stack streams there too. Changing whatObjectLoggerrenders atinfoispackages/core's, not this printer's.[action-governance] registered handlers with NO declaration …(its fix is hedged, not;-shaped), and the runtime-assetsBranding asset not served … To fix, …(its fix is introduced byTo fix,, not by;). Neither appeared on the measured boots.docs/qa/platform-checklist/areas/platform-core.json's showcase boot-health reading classifies theFlows:banner's⚠lines and needs no change. On a stock showcase the Boot diagnostics header is nowℹ.Generated by Claude Code