Repository navigation
pnpm demo prints its "now create the three requesters" instruction ~290 lines and 120 ERROR lines before the ready banner, so nobody reads it - #51
Merged
Conversation
…rest `pnpm demo` printed the "create the three business requesters" instruction inline, just before handing the terminal to the demo boot. Measured on main @ a7b7db5, one clean-database run: the note was log line 12 of 172, `✓ Server is ready` was line 147, and the last line was 172 — the one instruction that decides whether the app has anything in it scrolled 160 lines out of sight before the terminal stopped moving. Print it after the boot instead, and say what the seed's `owner_id` errors are while the same reader is still looking at them: one per contract row, expected on a first boot, row written with `owner_id` NULL, upstream cause objectstack#17177. The errors themselves are untouched — the boot keeps its inherited TTY and its colour, which is why the ready signal is a port probe and not a pipe over the child's output. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R3n3GGzobdegM4HUzah1iR
Measured on this branch: the ready banner is where the BOOT comes to rest, but not always the SEED. On a contended box the inline seed overran its 8000ms budget, the boot printed `WARN [Seeder] … continuing in background`, and the 120 `ERROR [SeedLoader]` lines arrived from that continuation 82s AFTER the banner — and so after the note. A second run never emitted them inside a 150s window while seeding the same 820 rows. The note therefore no longer claims the errors are "above" it. It names the clock that puts them above (seed inside its inline budget) and the one that puts them below (the background continuation), and it stays the frame either way. It also carries the number that actually reassures: the loader signs off with `120 dropped record(s)` while all 820 rows are in the database — measured, and the contradiction objectstack#17177 is about. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R3n3GGzobdegM4HUzah1iR
The comment credited a second branch run for a window that was measured on `main`. Same seed path either way, but the claim names a measurement and so has to name the right one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R3n3GGzobdegM4HUzah1iR
The note printed measured counts — the number of ERROR lines, the row totals per object, the figure the loader's summary quotes. Every one was true on the boot it was measured on and none is defended by anything: no gate reads printed prose, so a card that deals owners differently or changes what the fixture seeds falsifies them in silence. #47 is in flight doing exactly that. Printed to an operator as reassurance, a stale census is the demo telling a stranger a false number about its own health. State the shape instead, which is true at any count: one error line per contract whose requester account does not exist yet, every seeded row present with only owner_id NULL, and the loader's summary contradicting the database quoted as its own accounting rather than as a figure. Also drops the platform's 8s seed budget from the text — the boot prints the real number in its own WARN line. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R3n3GGzobdegM4HUzah1iR
zhuangjianguo
marked this pull request as ready for review
September 10, 2026 07:25
This was referenced Sep 10, 2026
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 #49
What changed
scripts/demo.mjsonly. The operator instruction — create the three business-requester accounts, run again — used to print inline, immediately beforestartDemo()handed the terminal to the demo boot. It now prints after that boot has come to rest, and it says what the seed'sowner_iderrors are while the same reader is still looking at them.The defect, measured (not repeated from the card)
Clean-database
pnpm demoruns (rm -rf .objectstack distfirst), captured to a file. Baseorigin/main@a7b7db5; branch at405d67f:✓ Server is readyat linePress Ctrl+C to stop)ERRORlines in the bootsys_oauth_resourceUNIQUE, unrelated to the seed)ERROR [SeedLoader]linesThe card's magnitudes are different from mine and the report on #49 says why. The defect is confirmed either way: 157 lines of boot output stood between the instruction and the resting point. The cause the card names is confirmed straight from the seeded database — every
clm_contractrow landed withowner_idNULL — and from the loader's own error text:Deferred reference UNRESOLVED after pass 2 — clm_contract.owner_id stays NULL … no such sys_user row exists, once per contract row.The measurement that shaped the fix
The ready banner is where the boot comes to rest. On a first boot it is not always where the seed does:
82 seconds after the banner. The same command on
main, held open for 150s past its banner, never emitted those lines at all while seeding the same corpus — same code, same fixture, two different clocks. Nothing the script can observe tells the cases apart (the WARN, the errors and the summary are all in the child's inherited stream), so the note does not claim the errors are above it. It names the clock that puts them above — seed inside its inline budget, which is what the dogfood pass saw — and the one that puts them below, and it is the frame either way. It is not printed twice to cover both.Adjudicated by the seat: the strict ordering is a platform gap (nothing an app can observe says the boot has come to rest), filed upstream by the seat and not closed here. No authenticated poll, no pipe.
What the note does NOT print: a census
Earlier revisions of this note printed the counts I had measured — the number of
ERRORlines, the per-object row totals, the figure in the loader's summary. Those are out. Every one was true on the boot it was measured on and none is defended by anything, since no gate reads printed prose: #47, in flight in this same batch, dealslegal_owneracross the seeded corpus and would falsify the error-line count in silence; #41 would move the row census. A stale census printed to an operator as reassurance is the demo telling a stranger a false number about its own health.So the note states the shape, which is true at any count: one error line per contract whose requester account does not exist yet, every seeded row present with only
owner_idNULL, and the loader's summary contradicting the database quoted as its own accounting rather than as a figure. The one number the file still prints is derived at runtime (Math.min(log.length, LOG_TAIL_LINES)), which is the pattern. A three-line rule in the note's doc block says why, so the census does not come back.How the note reaches the resting point
stdio: 'inherit'is kept and the boot's own output is untouched — not filtered, not reformatted, not dimmed. Piping the child would give an exact "it stopped printing" signal at the cost of the child's TTY, and a boot behind a pipe loses its colour: the seed'sERRORlines would have arrived dimmed by the very edit meant to explain them. So readiness is a TCP probe on the portos devwill bind — resolved the wayos devresolves it (--port, thenOS_PORT, thenPORT, then 3000) — plus a 2.5s settle for the 22-line banner tail. Both blind cases degrade to the pre-fix behaviour (a note printed mid-stream), never to a lost note; a boot that dies gets no note at all, becauseos devhas already said why.Before / after, as a reader experiences it
Before (
origin/main, last lines on screen — the instruction is 157 lines above this):After (this branch at
405d67f, last lines on screen, copied from the capture):Gates — exit codes captured before any pipe
Re-run on the reworked tree (
405d67f), each gate redirected to a file first and$?read after, so no exit code passes through a pipe:Plus
node --check scripts/demo.mjs→ 0, and a control-character self-scan of the file (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') → no matches.Acceptance notes
main.README.md(README.mdopens withStatus: M0 — scaffold and configuration domainon an M1/M2/M3-complete tree, and its setup section never says the position assignment binds by name #46),DESIGN.md(PR Record four maintainer rulings in DESIGN.md §03, §06 and §09 #40) andsrc/untouched. Diff isscripts/demo.mjsonly.pnpm demo's stdout, and it is measured above.我的合同, a zh-CN view label inside English default-locale output. Preserved verbatim rather than rewritten under a card whose surface is print order. Follow-up owner: [Decision]pnpm demo开箱即用时没有任何账号能打开「我的合同」——要不要让脚本建账号,与 #11 第一问耦合 #28 (same text), orREADME.mdopens withStatus: M0 — scaffold and configuration domainon an M1/M2/M3-complete tree, and its setup section never says the position assignment binds by name #46 if the README half is localised first.ERRORlines on every clean start ([sql-driver] DATABASE_ERRORplus ansys_oauth_resourceUNIQUE constraint insert failure). Identical onmain, so not caused here, but a reader counting red lines counts these too. No queued card touches that path.🤖 Generated with Claude Code
https://claude.ai/code/session_01R3n3GGzobdegM4HUzah1iR