Repository navigation
test(core): the room-external stop tests give the child a fixed ~170ms window, so any loaded box fails them - #3104
Conversation
…hinkFlowLab#3103) Fixes ThinkFlowLab#3103 Owner: Dev-1 Written-by: Dev-1 Bot: FlyBot Dev-1 Tier: T1 **What changed.** `core/test/room-external.test.js` assumed this box starts a child process in under 120 ms. On a pinned core with two CPU hogs the same file fails deterministically: `not ok 5` ("a stop is asked for on the protocol before the signal"), `timed out waiting for the child`, 4150 ms and 4143 ms — `120 ms` sleep plus the 4 s `waitFor` budget. The child was still booting when `cancel` wrote the stop line and `TERM_GRACE_MS = 50` ended the process, so the line never reached it. The test now waits for what the child already reports: before `cancel` it waits for `"type":"turn"` in `SEEN`, the same file the assertion reads. `ThinkFlowLab#2634` and `ThinkFlowLab#2689` had the stricter version of the same bet — a 300 ms and a 700 ms reply window that started while the process was still starting — so their inline children append `ready` to a marker file after attaching the stdin handler, and the test opens the seat and waits for that marker before it writes the turn. The wait condition is an event, never a bigger budget: the 4 s `waitFor` only bounds the failure, and its message now names the handshake (`timed out waiting for the child to read the turn line`), which is what made the original red anonymous. **What did not change.** No product code. `core/src/host/room-participant-external.js` is untouched, `TERM_GRACE_MS = 50` stays, no timeout is raised, and every inline child is the test's own `-e` script. Every assertion is kept, including `turn` landing before `stop` and the pid checks. **Baseline.** The mirrors under `patches/ds-bot/files/` follow from `generate` (only `files/test/room-external.test.js` changes); `check` reports the three `ok` lines and `canonical` is a no-op. **Evidence.** Pinned to one core with two hogs (`taskset -c 0`, two `while :` shells): base 2/2 red, both `not ok 5`, `timed out waiting for the child`, 4150 ms / 4143 ms; fixed file 3/3 green, 20/20 each, exit 0.
Ready for queue — T1Written-by: FlyBot Lead Checks at this tip: 16 success + 2 skipped.
@Birfy — this one is ready for the queue at the tip above. |
|
Verdict: PASS at 35fac6e Red first, then the precondition is real — not a wider window. Base
Ran: Metadata: the body gains the missing |
… file is red on every non-UTC machine (ThinkFlowLab#3107) Fixes ThinkFlowLab#3106 Owner: Dev-1 Written-by: Dev-1 Bot: FlyBot Dev-1 Tier: T1 (test-only, `plugins/social/test/**`; no product code) Claim-Id: b8416b79222d43199c9183fce882b342 Base: 5cb1692 Verified commit: 9ba6d08a9a253882976c0ecc3f67c4cfb8d38252 (tree 2c6ec41) Pushed head: efb2676 Tree: 2c6ec41 ## What was wrong `plugins/social/test/face-rooms.test.js` wrote its fixture instants as UTC (`2026-10-17T14:38:00.000Z`) and then asserted the rendered title as `Oct 17 14:38`. The title prints the wall clock of the box that draws it — `core/src/shared/face-title.js` `formatFaceWhen` reads `getHours()` / `getMinutes()` / `getMonth()` / `getDate()` — so that pair only agrees on a UTC box. Nothing is wrong with the product: the test pinned a local rendering to a UTC expectation, and the file is red on every non-UTC machine. ## Rebase onto the live main, and why the shas in this body differ The branch was cut from `5cb16923` (the `Base:` line above). While the push ran, upstream main moved to `fc32c5fe8d4a1ad480a78d2f470e5d6f25dc7807` (ThinkFlowLab#3104, a `core/test/**` change; no file of this PR is touched by it), so the push path overlaid this one-file change onto the new main. The branch was then rebased onto `fc32c5fe`, giving the verified commit `9ba6d08a`; its tree, `2c6ec41c0bd457082aed0df5c4bd57237e0fe000`, is bit-for-bit the tree of the pushed head `efb26767`. Every reading below was re-taken on the rebased tree. ## Red first, before the change `cd plugins/social && TZ=<zone> node --import ./test/resolve.mjs --test test/face-rooms.test.js` On the cut base `5cb16923`, and again on the rebased base `fc32c5fe8`, two runs per zone, every run identical: `# tests 38 # pass 36 # fail 2`, exit 1. `TZ=Asia/Shanghai`: ``` not ok 9 - owner-typed face-room lines encode as a human envelope location: '.../plugins/social/test/face-rooms.test.js:232:1' expected: 'Face-to-face · UiA1415, UiB1415 · Oct 17 14:38' actual: 'Face-to-face · UiA1415, UiB1415 · Oct 17 22:38' operator: 'strictEqual' stack: TestContext.<anonymous> (.../face-rooms.test.js:254:10) not ok 28 - \ThinkFlowLab#194: a face room title shows one time, the creation time, before and after Enter chat location: '.../plugins/social/test/face-rooms.test.js:644:1' error: The input did not match the regular expression /12:56$/. Input: 'Face-to-face · Alice · Oct 17 20:56' actual: 'Face-to-face · Alice · Oct 17 20:56' operator: 'match' stack: TestContext.<anonymous> (.../face-rooms.test.js:649:10) ``` `TZ=America/New_York`, same two cases, same expectation, different offset: `actual: 'Face-to-face · UiA1415, UiB1415 · Oct 17 10:38'` (against the `Oct 17 14:38` expectation) and `actual: 'Face-to-face · Alice · Oct 17 08:56'` (against `/12:56$/`); `# tests 38 # pass 36 # fail 2`. Two zones with different offsets move the rendering by exactly their offset, which pins the cause to "local rendering vs UTC expectation", not to one zone. ## The fix The fixtures are built from the same local parts the title prints, with one helper at the top of the file: ```js const localIso = (year, month, day, hour, minute, second = 0) => new Date(year, month - 1, day, hour, minute, second).toISOString() ``` - `:256` the human-envelope fixture: `const at = localIso(2026, 10, 17, 14, 38)`. - `ThinkFlowLab#194` (`:652`): `deadline = localIso(2026, 10, 17, 13, 6)`, `created = localIso(2026, 10, 17, 12, 40)`, `startedAt: localIso(2026, 10, 17, 13, 1, 30)`. The expected strings did not change and no assertion was relaxed, skipped or turned into a regex. It cannot pass vacuously: the case still asserts the exact title `Face-to-face · UiA1415, UiB1415 · Oct 17 14:38`, still asserts two members in handle order (`titleA === titleB`), still asserts two different starts give different titles (`assert.notEqual(...)`), and `ThinkFlowLab#194` still asserts `candidate === open`, `/12:56$/` and the `isGenericFaceTitle` branch. ## Green after, same commands, on the rebased tree | TZ | runs | result | | --- | --- | --- | | `UTC` | 2 | 38/38, `# fail 0`, exit 0 | | `Asia/Shanghai` | 2 | 38/38, `# fail 0`, exit 0 | | `Europe/Berlin` | 2 | 38/38, `# fail 0`, exit 0 | Whole social package under a non-UTC zone on this tree: `TZ=Asia/Shanghai npm --prefix plugins/social test` → `# tests 701 # pass 701 # fail 0`. No second place in this file pins a local rendering to a fixed string (grepped the file; `social.test.js:4076/4086` carries the same literal but reuses the stored stamp instead of re-rendering, so it is not red and is out of scope). ## verify `unset ARCH_DOCS_BASE; TZ=UTC npm run verify` → exit 0 (log sha256 `656794a5b736ad6cd607e6ecb105c17ce164f0fef70a8c02dd6b40dca73370f9`): core 3255, social 701, tree 149, timeline 172, workflow 535, project 147, gate/policy 681, interop 37, live-e2e 34 — `# fail 0` everywhere; core lint 88 warnings / 0 errors, plugin lint 0 errors; `arch-docs: OK (1 changed file(s))`; `build-client --check` exit 0, `patches check` three `ok` lines, `canonical` a no-op. ## Files 1 file, `+13/−5`: `plugins/social/test/face-rooms.test.js`. `git diff` against the base touches no product file (`git diff 5cb1692 HEAD -- core plugins/social/src patches` = 0 lines), no `core/client.js`, no `patches/**`. Docs-not-needed: test-only; only how the fixture instant is built changed, and the title behaviour it pins is untouched. Not run: the test bench / smoke — no product code changed. <!-- flybot:checkpoint --> ```json { "pr": 3107, "claim": "Dev-1", "issue": 3106, "summary": "face-rooms wrote its fixture instants as UTC strings and then asserted locally rendered titles, so the file was red on every non-UTC box (Asia/Shanghai drew 22:38, New York 10:38). The fixtures now come from local parts through one localIso helper, so the same exact-string assertions hold in any zone; no assertion was relaxed, skipped or removed, and the two-different-starts notEqual plus the isGenericFaceTitle branch keep the case from passing vacuously. Test-only, one file.", "files": [ "plugins/social/test/face-rooms.test.js" ], "checks": { "ran": "unset ARCH_DOCS_BASE; TZ=UTC npm run verify; face-rooms.test.js under TZ=UTC/Asia_Shanghai/Europe_Berlin x2; whole social package under TZ=Asia_Shanghai", "result": "green", "at": "efb26767ce0ca483d0dae9cfbb64905fd7b06f9a" }, "next": "ready for review at this tip" } ``` <!-- /flybot:checkpoint -->
Fixes #3103
Owner: Dev-1
Reviewer: Reviewer
Written-by: Dev-1
Bot: FlyBot Dev-1
Claim-Id: 9f5365489b1d425a846a20406cdc141b
Tier: T1 (
core/test/**and itspatches/ds-bot/files/test/mirror; no product code)Base: 5cb1692
Verified commit: a2b9188961cac29d2412e07918a4b693f58885fc
Tree: 045484ca596f13c8b358dda432873217693bb6f3
Pushed head: 35fac6e
What was wrong
core/test/room-external.test.js:109slept a fixed 120 ms and then asked the driver to cancel, so the child had ~120 ms to start, plusTERM_GRACE_MS = 50to drain the stop line before SIGTERM. On a loaded box it is still starting,SEENstays empty, and the test burns its full 4 s budget —4150 msobserved. The driver is right: the stop line is a courtesy and the signal is the fallback, so this is a test-side assumption, not a product defect.:191(#2634) and:382(#2689) carry the stricter form of the same bet: a 300 ms and a 700 ms reply window that starts while the process is still booting.The change
:109waits for"type":"turn"inSEEN— the child proving it is already reading — before it cancels. Theturnbeforestoporder assertions are unchanged.:191and:382get a marker the inline child writes right after it attaches its stdin handler; the test opens the seat (driver.open) and waits for that marker before it writes the turn, so the reply window measures the answer and not the boot.waitForcalls, and everywaitForfailure now names the handshake it waited for (timed out waiting for the child to read the turn line) instead oftimed out waiting for the child.waitForstill defaults to 4000 ms and only a real event ends a wait.Red first, at
5cb16923, twicetaskset -c 0with two CPU hogs, base source: both runs exit 1,# tests 20 # pass 19 # fail 1.The second run is the same failure at
duration_ms: 4143.621558.Green after, three runs, same load
Same command on this tree: 3/3 exit 0,
# tests 20 # pass 20 # fail 0on each.verify
unset ARCH_DOCS_BASE; TZ=UTC npm run verify→ exit 0 (log sha256dc87a46b7aa7feaf06e5ff66f6d3c073384752d81f0f2a51a52856c037cfbcdd): core 3255, social 701, tree 149, timeline 172, workflow 535, project 147, gate/policy 681, interop 37, live-e2e 34 —fail 0everywhere; core lint 88 warnings / 0 errors (the same count as the base), plugin lint 0 errors;arch-docs: OK (2 changed file(s)). Alsobuild-client --checkexit 0,patches checkthreeoklines,canonicala no-op,changelog check6 fragments well formed,testing-layers --checkandcheck-mojibake --checkclean.Files
2 files,
+126/−70:core/test/room-external.test.js(+63/−35) and its generated mirrorpatches/ds-bot/files/test/room-external.test.js(+63/−35, written bygenerate).Scope
Test-only.
core/src/host/room-participant-external.jsis untouched (git diff origin/main HEAD -- core/src= 0 lines),TERM_GRACE_MSstays 50, and every child that writes thereadymarker is one of this test's own inline-escripts.Not run: the test bench / smoke — this changes no product code.
{ "pr": 3104, "claim": "Dev-1", "issue": 3103, "summary": "core/test/room-external.test.js gave the external child a fixed 120 ms before cancel and 300/700 ms reply windows, so a loaded box failed it before the child finished booting. The stop test now waits for the turn the child already records; the #2634 and #2689 cases wait for a ready marker the inline child writes; every waitFor failure names the handshake. No product code, no budget raised, every original assertion kept.", "files": [ "core/test/room-external.test.js", "patches/ds-bot/files/test/room-external.test.js" ], "checks": { "ran": "unset ARCH_DOCS_BASE; TZ=UTC npm run verify; node --test core/test/room-external.test.js under taskset -c 0 + 2 hogs x3", "result": "green", "at": "35fac6ecd313114cde8510b2ba3a5c4cd1cda410" }, "next": "ready for review at this tip" }