test(the-framework): bind a topic run only once it is up (#1165)#1171
Merged
Conversation
The #1122 re-home test seeded the bind the instant `onStart` returned, so the re-home it triggers could terminate a child that had not finished booting. On a loaded runner that SIGTERM landed before the stub recorded its argv, and the run looked like it never spawned: a bare `1 !== 2` after the whole poll budget. A real bind cannot arrive that early. The run writes it into its own event log (`recordBind`, cli.ts), so a bind the daemon sees always comes from a process that is already running. The test now waits for that start before binding. Also: the stub installs its SIGTERM handler before its first write, so a signal in between cannot take the default disposition and kill it silently; the #1166 diagnostic prints the recorded starts, since "which spawn is missing" was the first question it could not answer; and the poll ceiling drops to 10s, which is a backstop rather than a slowness allowance -- 6s, 30s and 15s all failed the same way, because the re-home either lands in under a second or has gone wrong. Closes #1165
suleimansh
marked this pull request as ready for review
July 25, 2026 16:10
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.
Closes #1165.
What it actually was
Not a poll budget, and not the
settle()teardown the issue's working theory pointed at. I reproduced the exact CI signature locally and it is a test artifact, not a production bug.tearDownTopicScratchonly removes a scratch whose meta readsdone; the test's meta readsrunning, so that path is a no-op here and could never have producedscratch removed: true. The only other remover is the success path ofrehomeTopicRun. So on the failing runs the re-home worked: worktree allocated, history moved, continued run spawned, scratch removed. The missing start was the topic run's own.Why it went missing: the test seeds the bind the instant
onStartreturns, which fires a re-home that callsterminate(child.pid)on a child that may still be booting. Under load the SIGTERM lands before the stub reaches its first write, the process dies on the default disposition, and its argv line never appears. One line in the log, the whole budget burnt,1 !== 2.Reproduction, and the proof it is fixed
Making the stub take 1.5s to reach its first write reproduces CI exactly on this Mac, where it had never failed:
With this change, that same simulation passes 3/3.
Why the wait is the right fix, not a sleep
A real bind cannot arrive before the run is up: the run writes it into its own event log (
recordBind,cli.ts:1540; the dashboard only appends to the control file, which the run reads and then records). So a bind the daemon tails always comes from a live process. The test now models that by waiting for the topic run's start before binding it.Also in here:
Not changed
No production change.
spawnDetachedrunsprocess.execPath <bin>directly, so there is no intermediary child that can exit while the run lives on, and the "only tear down when the run has ended" guard the issue asks for already exists as thedonecheck intearDownTopicScratch.Test-only, so no changeset.
pnpm testinpackages/the-framework: 1302 pass, 0 fail.