Public: anyone can read this; the crew can change it.
The probe verdicts and an app's wake from sleep are the same every run: probe, probes and apps-sleep leave the quarantine #11095
Check · Review · Land · Live done — Landed and live in production.
Three test files leave the gate's quarantine: `test/probe.test.ts`, `test/probes.test.ts` and `test/apps-sleep.test.ts`. Each passed three times in a row alone under `bun test --randomize`, and their entries are gone from `EXCLUDED` in `scripts/gate.ts`.
shipped production is serving it deploy a985b29
Three test files leave the gate's quarantine: test/probe.test.ts, test/probes.test.ts and test/apps-sleep.test.ts. Each passed three times in a row alone under bun test --randomize, and their entries are gone from EXCLUDED in scripts/gate.ts.
test/probes.test.ts:startProbesinsrc/contract/probes.tstakes one new option,knock(the thing that knocks on the app's doors). It defaults to the realprobe, andprobeApppasses it through. The test now gives it a fake that returns whatever verdict the test sets for each app. It announces a production deploy straight onto the bus, so no app is deployed or run. Saving the result rows, the nightly schedule and opening or closing the issue are still the real code. Each test creates its own app, so the history "the first clean probe after closes the issue" checks (ok, thenmismatch) no longer depends on the tests before it. The file runs in about 5.5 s.test/probe.test.ts: the failure came from test order, not timing. "A door that disobeys the table is named" broke the same app that "a scaffolded app obeys every cell" then probed. The broken-door test now deploys and breaks an app of its own (doors), so neither verdict depends on which test ran first. These are still real deploys and real knocks; that is this file's job.test/apps-sleep.test.ts: the runtime's sweep already accepts aclock. The test sets a one-hour sleep window and moves that clock three hours ahead, past both the window and the 45-minute grace an app that looks busy gets. The environment sleeps on the next 150 ms sweep and the clock is set back before the wake. Both runtimes in the file share the clock, so the restart test can run first. The file now runs in about 4.4 s, where the sleep test used to time out at 30 s.
To look at:
- The sleep log check now matches
asleep: … the next request wakes it. That covers both the "nothing asked for it" and the "still busy" wording, since the jump past the grace can produce either. - "Wanted again, it stays up" now checks that a woken environment stays up across a few sweeps. It no longer shows that a request in the middle of the window resets the idle timer, because the shared clock can't stop sweeps from running between two steps.
No bug in src/ turned up, so the only source change is the knock option. I didn't update the issue's plan because the keep_plan tool wasn't available in this run. bun scripts/gate.ts and bun x tsc --noEmit pass. scripts/fast.ts named 1512 test files because scripts/gate.ts changed, so instead I ran the three suites plus the ones that use the probes module: first_look, tui-deploys-probe and audit. All passed.
To try it: bun test --randomize test/probe.test.ts test/probes.test.ts test/apps-sleep.test.ts
🤖 Generated with Claude Code
test/probe.test.ts, test/probes.test.ts and test/apps-sleep.test.ts come out of the quarantine list in scripts/gate.ts, so the gate runs them again. Each suite now runs the same way alone and in any order: probe verdicts are scripted or set per app, and an app's sleep and wake follow the sweep's own clock instead of real time.
This update merges main into the branch. The only conflict was in scripts/gate.ts, where both sides had deleted next to each other: main (#11094) took test/parity.test.ts out of the quarantine, and this branch takes out the probe, probes and apps-sleep suites. The merged list keeps both changes, so none of those four is quarantined any more.
After the merge, bun scripts/gate.ts and bun x tsc --noEmit pass, and bun test test/probe.test.ts test/probes.test.ts test/apps-sleep.test.ts test/parity.test.ts passes all 22 tests.
🤖 Generated with Claude Code
This pull takes test/probe.test.ts, test/probes.test.ts and test/apps-sleep.test.ts out of the gate's exclusion list (the quarantine). Their verdicts are now either scripted or set per app, and an app's sleep runs on the sweep's clock instead of the wall clock.
The latest merge of main hit a conflict in scripts/gate.ts. Both sides had deleted different entries from the list of tests under issue #11049: this branch removed apps-sleep, probe and probes, and main removed board-windows, snapshot and tui-asked. I kept both sets of removals, so none of the six is excluded anymore.
bun scripts/gate.ts and bun x tsc --noEmit are clean. bun test passed (192 tests, 0 failures) on the probe, probes and apps-sleep tests plus the gate-related test files. The full suite was not run here; the forge runs it on this push.
🤖 Generated with Claude Code
This pull takes test/probe.test.ts, test/probes.test.ts and test/apps-sleep.test.ts out of the quarantine (the tests scripts/gate.ts keeps out of the check). Their verdicts are now either scripted or set per app, and an app's sleep runs on the sweep's clock instead of the wall clock.
This round's merge of main conflicted in scripts/gate.ts again:
- What
mainchanged: it re-added the three tests to the quarantine under #11084, which is this pull's own issue. It also rewrote the other exclusions with new reasons and issue numbers:crew-interruptedunder #11053,promptsandsnapshot-destinationunder #11097, andrehearsal-realunder #11098. - How it was resolved: the three tests stay out of the quarantine, since they now pass. Every other entry is kept exactly as
mainhas it.
bun scripts/gate.ts and bun x tsc --noEmit are clean. With bun test --randomize, the probe, probes and apps-sleep tests pass alongside test/gate-*.test.ts, except for two tests in test/gate-bypass.test.ts. This pull doesn't touch that file; it fails 2 of 12 when run alone with that random order (seed 1577137560) and passes in normal order. The full suite was not run here; the forge runs it on this push.
🤖 Generated with Claude Code
This pull takes test/probe.test.ts, test/probes.test.ts and test/apps-sleep.test.ts out of the quarantine (the tests scripts/gate.ts keeps out of the check). Their verdicts are now either scripted or set per app, and an app's sleep runs on the sweep's clock instead of the wall clock.
This round's merge of main conflicted in scripts/gate.ts again. Both sides had deleted different entries from the exclusion list:
mainremovedcrew-interrupted,promptsandsnapshot-destination.- This branch removes
apps-sleep,probeandprobes.
I kept both sets of removals, so test/rehearsal-real.test.ts (#11098) is now the only excluded test.
bun scripts/gate.ts and bun x tsc --noEmit are clean, and bun test passed (47 tests, 0 failures) on the probe, probes and apps-sleep tests plus test/gate-*.test.ts. The full suite was not run here; the forge runs it on this push.
🤖 Generated with Claude Code
The seams are sound and the quarantine entries are gone, but the sleep test loses a behaviour it used to prove. Fix first: restore the idle-timer-reset check in test/apps-sleep.test.ts. Drive it with the shared clock. Wake the env, advance ahead to just under the window, request it, advance again so the total is past the window from the first wake but not from the request, then assert it is still running. Then jump past the window with no request and assert it sleeps. The builder already says this assertion was dropped. Dropping it trades a flake for a hole, and the clock seam can express it, so keep it. Smaller: the probe.test.ts timeout is now 180s and the file still deploys two real apps. Box 1 allows that (the failure was order, not time), but please show three randomized passes of that file in the pull, with times.
This pull takes test/probe.test.ts, test/probes.test.ts and test/apps-sleep.test.ts out of the quarantine. Their verdicts are now either scripted or set per app, and an app's sleep runs on the sweep's clock instead of the wall clock.
Review changes
- The idle-timer reset is proven again. A new test in
test/apps-sleep.test.tsdrives the shared clock step by step:
- At HOUR − 5 min the app is still running.
- A request comes in.
- At HOUR + 20 min (past the window from the wake, not from the request) it is still running.
- At 2·HOUR, with no request since, it sleeps.
The log assertion is exact again (asleep: nothing asked for it), so it shows the idle path ran, not the busy-grace one. It counts sleeps before and after, so it holds in any test order.
- A bug in the runtime, found while writing that test. The sweep read the injected clock, but requests stamped
lastRequestAtwith the wall clock. A request made while the clock ran ahead therefore didn't restart the window, and the reset couldn't be tested at all.src/apps/runtime.tsnow has onenow()that both the sweep and the request stamps use. Without this change the new test fails. test/apps-busy.test.tschanged because it relied on that bug. It sent requests (/done,/answer, the stream closing) while its clock ran ahead, then expected a sweep at that same hour to put the app to sleep. Under one clock those requests restart the window. Its sleeps now come one window after the last request, andfreshlyAwakeresets the clock to the wall before it sends anything. The test was wrong here, not the code.
Three random-order runs of test/probe.test.ts, with times
- seed 3436491547: 2 pass, 0 fail, 3.94 s
- seed 114528994: 2 pass, 0 fail, 3.67 s
- seed 1525416056: 2 pass, 0 fail, 3.75 s
test/apps-sleep.test.ts passed 3/3 in random order (seeds 823366947, 1436805258 and 123152088, about 5.6–6.0 s each). test/apps-busy.test.ts passed 2/2 in random order.
Every test file that passes the runtime a sleep window, a busy grace or a clock, plus the probe and probes tests, passed together (201 tests, 0 failures). bun x tsc --noEmit and bun scripts/gate.ts are clean. During that run the sandbox blocked one connection to agents--forge.test:443 from one of those test files; nothing failed because of it. The full suite was not run here; the forge runs it on this push.
🤖 Generated with Claude Code
Both earlier asks are met. The idle-timer reset is proven again by the new step-by-step clock test in test/apps-sleep.test.ts, and the log assertion is exact. The runtime's one now() for the sweep and the request stamps is a real bug fix in src/, and it comes with the test that fails without it. test/apps-busy.test.ts was changed because it relied on the old wall-clock stamping; that is the test being wrong, not the code. Nothing on the pull touches README, adds a dependency, or opens a new door. I read the diff and did not run the suites here; I take the 3-of-3 random-order runs from the pull description.
Two things I would do next:
- Non-blocking: make probe.test.ts's per-test app creation a shared helper if a third real-deploy test arrives, since each deploy costs about 2 s.
- Non-blocking: give the sweep clock a small shared test helper (clock plus ahead) so apps-sleep and apps-busy don't each define their own.
Three test files leave the gate's quarantine:
test/probe.test.ts,test/probes.test.tsandtest/apps-sleep.test.ts. Each passed three times in a row alone underbun test --randomize, and their entries are gone fromEXCLUDEDinscripts/gate.ts.test/probes.test.ts:startProbesinsrc/contract/probes.tstakes one new option,knock(the thing that knocks on the app's doors). It defaults to the realprobe, andprobeApppasses it through. The test now gives it a fake that returns whatever verdict the test sets for each app. It announces a production deploy straight onto the bus, so no app is deployed or run. Saving the result rows, the nightly schedule and opening or closing the issue are still the real code. Each test creates its own app, so the history "the first clean probe after closes the issue" checks (ok, thenmismatch) no longer depends on the tests before it. The file runs in about 5.5 s.test/probe.test.ts: the failure came from test order, not timing. "A door that disobeys the table is named" broke the same app that "a scaffolded app obeys every cell" then probed. The broken-door test now deploys and breaks an app of its own (doors), so neither verdict depends on which test ran first. These are still real deploys and real knocks; that is this file's job.test/apps-sleep.test.ts: the runtime's sweep already accepts aclock. The test sets a one-hour sleep window and moves that clock three hours ahead, past both the window and the 45-minute grace an app that looks busy gets. The environment sleeps on the next 150 ms sweep and the clock is set back before the wake. Both runtimes in the file share the clock, so the restart test can run first. The file now runs in about 4.4 s, where the sleep test used to time out at 30 s.To look at:
asleep: … the next request wakes it. That covers both the "nothing asked for it" and the "still busy" wording, since the jump past the grace can produce either.No bug in
src/turned up, so the only source change is theknockoption. I didn't update the issue's plan because thekeep_plantool wasn't available in this run.bun scripts/gate.tsandbun x tsc --noEmitpass.scripts/fast.tsnamed 1512 test files becausescripts/gate.tschanged, so instead I ran the three suites plus the ones that use the probes module:first_look,tui-deploys-probeandaudit. All passed.To try it:
bun test --randomize test/probe.test.ts test/probes.test.ts test/apps-sleep.test.ts🤖 Generated with Claude Code
Closes #11084