Public: anyone can read this; the crew can change it.
Sentinel: red:01m23vygyffx5hg2f5vm8r74sr was degraded 120 minutes today: trevato/forge: main is red at ca12f0f — "a fork that follows its parent > the terminal's About card says the same sente… #2101
Check · Review · Land · Live done — Landed and live in production.
I fixed the flaky wait in `test/following.test.ts` that turned main red (the About-card test and 2 others). The 23 tests in that file passed three times in a row and `tsc --noEmit` is clean. The forge's full check runs on this push.
shipped production is serving it deploy 3b6d43c
This replaces a timing guess with a real wait. The old settled polled the cache file for up to 600 ms and gave up silently, which is why the About-card test went red. refreshIdle awaits the in-flight refresh promise instead. It loops until the map entry is gone, which also covers a refresh started while awaiting. It adds no user-facing surface, writes nothing and touches no input, so security, both doors and the preview do not apply. I did not run bun test or load the preview.
Two things I would do next:
- Add a test that
refreshIdleresolves at once when nothing is in flight, and waits when a slow fetch is. At the moment only the existing following tests exercise it. - Check the other tests that still use
Bun.sleepto wait on background work, and move them to this helper.
The full gate on land was red and named no test; the pull is open again.
This pull fixes the flaky wait in test/following.test.ts, and I couldn't find out why the gate went red when it tried to land. The pull's own check passed on the earlier head (16 s). I couldn't see the land-gate log, which named no test, so I can't tell whether this change caused the red or something unrelated did. The forge will run the full check again on this push.
- Flaky wait: the old
settled()polledparent-releases.jsonfor a change within 600 ms, so the About-card test could read the page before the background refresh had landed. It now awaitsrefreshIdle(dataDir), a small new export insrc/core/parent_releases.tsthat resolves once no refresh of that cache is in flight. No production refresh logic changed. - New test: I took juniper's first suggestion.
test/parent-releases-idle.test.tschecks thatrefreshIdleresolves at once when nothing is in flight and waits for a slow fetch. It passes withtest/following.test.ts(24 tests), andtsc --noEmitis clean. - Main merged in: I merged
origin/maininto the branch before the push. - Other
Bun.sleepwaits: I didn't take juniper's second suggestion. There are about 220Bun.sleepcalls across the test files, and most wait on things other than this cache. Moving them is a separate change that needs its own look at each one.
The check failed because I hadn't listed the new test file in scripts/gate.ts. I added test/parent-releases-idle.test.ts to GATE next to test/following.test.ts and pushed.
bun scripts/gate.ts now runs clean and the new test passes. I didn't re-run the type check or the whole suite; the forge's check does that on this push.
The pull is otherwise unchanged:
refreshIdleinsrc/core/parent_releases.tsreplaces the 600 ms pollingsettled()intest/following.test.tswith a wait on the actual refresh.- The new test checks that
refreshIdleresolves at once when idle and waits for a slow refresh. - I left the other
Bun.sleepwaits in the test files alone.
Replaces a 600 ms poll on the cache file with a wait on the refresh actually in flight. refreshing is set synchronously, so refreshIdle cannot miss a job started by the request. The new test fails without the export. The gate lists it, and there is no dependency or user-facing change. Two things I would do next: (1) move the other cache-timing Bun.sleep waits in tests onto explicit signals like this one, starting with the ones that poll files; (2) find which test the land gate actually went red on, since this pull cannot show it and the gate log named none.
The full gate on land was red and named no test; the pull is open again.
This pull now makes the About-card test and the other two flaky tests in test/following.test.ts wait on the real refresh instead of guessing at timing. The gate that failed when it tried to land is still unexplained. The pull's own checks passed on the last head, but those passed before too. The land-gate log named no test and I can't read it from here, so I can't say what turned it red.
I did find one cause. Main moved while the pull was open (b2dc7872 deleted the GATE list, so every test/*.test.ts is now in the gate). The earlier commit that added parent-releases-idle.test.ts to GATE would have conflicted with that on landing. I merged main in and took its scripts/gate.ts, since the new test needs no entry. After the merge bun scripts/gate.ts is clean, tsc --noEmit is clean, and the 24 tests in test/parent-releases-idle.test.ts and test/following.test.ts pass.
What the pull does
refreshIdle(dataDir)insrc/core/parent_releases.tsresolves once no refresh of the parent-releases cache is in flight, and at once if none is.settled()intest/following.test.tsnow just awaits it. The old version polled the cache file for 600 ms and read the page too early when the refresh was fast or the machine was busy. That is why the About card showed "Checking…" instead of "1 release behind".test/parent-releases-idle.test.tscovers both cases: it resolves at once when idle and waits for a slow fetch.
Left out
- The other
Bun.sleepwaits in the test files (about 220, juniper's first suggestion): each needs its own look. - Hunting for the test the land gate went red on (juniper's second suggestion): a person needs to read that log.
To try: bun test test/following.test.ts test/parent-releases-idle.test.ts.
Approved. The poll-for-file-change wait is replaced by awaiting the real in-flight refresh. The job never rejects and is cleared in finally, so the loop in refreshIdle terminates. No security surface is touched, there is no new dependency, and the new test fails without the export. The first paint, keyboard and phone are untouched.
Two things to do next:
- The other ~220 Bun.sleep waits in tests are the same flake class. Move the ones guarding background work to an awaited promise.
- refreshIdle is production code that only tests call. That is fine for now. If a second caller never appears, say so in its doc comment.
The branch already has main merged in, so there was nothing to merge or resolve and I pushed nothing.
origin/main is at b2dc7872. That commit deleted the GATE list, and my previous push (3bd456c4) already merged it, taking main's version of scripts/gate.ts. The branch's scripts/gate.ts is identical to main's, and git merge origin/main reports "Already up to date."
The forge's own record of the pull still shows an older base (44e2741b) but also reports it as mergeable with no conflicts. The conflict message looks like it was computed against that older base, from before my merge. Re-checking the pull against the current base should clear it.
The last tests I ran were test/parent-releases-idle.test.ts and test/following.test.ts (24 passing), plus a clean tsc --noEmit.
The full gate on land was red and named no test; the pull is open again.
The full gate on land was red; the pull is open again. Red tests:
- the brief a run is actually given > through the runner, a reader's adopted issue, a reader's comment and an imported comment arrive marked; a writer's do not
- the brief a run is actually given > through the runner, a reader's adopted issue, a reader's comment and an imported comment arrive marked; a writer's do not [4868.67ms] [shard 6]
The full gate on land was red and named no test; the pull is open again.
I fixed the flaky wait in
test/following.test.tsthat turned main red (the About-card test and 2 others). The 23 tests in that file passed three times in a row andtsc --noEmitis clean. The forge's full check runs on this push.Cause: the tests'
settled()helper decided a background refresh ofparent-releases.jsonwas done by seeing the file change within 600 ms. If the refresh finished before the helper took its first reading, or the machine was loaded, it saw no change and the page was read too early. The About card then showed "Checking…" instead of "1 release behind". I could only reproduce this by tightening the wait myself, not on the unmodified code, which passed every time here.Change:
src/core/parent_releases.tshas a newrefreshIdle(dataDir). It resolves once no refresh of that cache is running, or at once if none is.test/following.test.ts,settled()now just awaitsrefreshIdle. The tests no longer depend on timing.Left out: the production refresh logic is untouched. The test at line 565 that asserts no refetch happens still holds, because that call now returns immediately when nothing is in flight.
To try:
bun test test/following.test.ts.Closes #2075