You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A factory memory receipt that lands after Quit is missing from the ledger or the header (TestMemoryLateReceiptReachesFactoryHeaderAfterQuit fails ~1 in 3) #2566
cmd/codeafTestMemoryLateReceiptReachesFactoryHeaderAfterQuit fails roughly a third of the time when it runs alone, on app/v3 and on the landing candidate alike. The failure is an accounting mismatch: a memory worker's receipt that arrives after Quit is missing from the ledger, or it reaches the ledger while the factory header stays behind. Example lines from failing runs:
It first surfaced in the full check of the app/v3 → dev landing candidate (#2561), where the full suite runs under load.
Replication
Deterministic (no model). At app/v3a687c92b2:
CODEAF_TELEMETRY=off DO_NOT_TRACK=1 go test -count=20 -run '^TestMemoryLateReceiptReachesFactoryHeaderAfterQuit$' ./cmd/codeaf/
On 2026-11-10 that run gave 13 pass / 7 fail on app/v3, and 11 pass / 9 fail on the landing candidate (land/app-v3). There were no skips. Most failures are the accounting assertion in appfactory_memory_worker_test.go; one candidate run failed earlier with memory did not start.
Field (real models). Not needed. The test drives the real public ledger and header through a scripted provider.
Where
The test is TestMemoryLateReceiptReachesFactoryHeaderAfterQuit in cmd/codeaf/appfactory_memory_worker_test.go; search for late receipt.
The boundary is where a factory job's memory-worker receipt is booked after the job's chat quits: the ledger row, then the stored factory cost and header.
The fix
A receipt that arrives after Quit is booked exactly once, and both the ledger and the factory's header show it. The test should pass 100 of 100 runs alone and under the full suite. This is not caused by the landing merge, because app/v3 fails the same way. It is filed on its own because failing 35–45% of standalone runs is a defect, not load noise.
Bisect on one machine with a focused run each time: -run '^TestMemoryLateReceiptReachesFactoryHeaderAfterQuit$', nice -n 19, -p 1, GOMAXPROCS=2. Every failure was the same line, provider=0.0400 memory=0.0000 ledger=0.0200 header=0.0200.
The bug existed before #2583. Merging #2583 onto app/v3 makes it about twice as likely.
Checked for the embedded engine (furrow). The first two rows were built in a worktree without internal/furrowbin/cache/furrow-linux-amd64.gz; the third was built with it. The pin is the same. Holding that constant:
The first run in a fresh process fails at the same rate as later runs, so state left over by an earlier iteration in the same process is not what drives it.
A profile's pool-errand tracker now refuses new errands once it has been stopped.
It added defer stopPoolErrands(...) to the run, exec and subharness roads.
What to check next: whether a stage that ends inside the app closes the shared profile's tracker before the memory worker books its late receipt. That link is not proven.
Activity
app: the engine closes where RunApp closes it, and every Close tears …
AbirAbbas commentedon Nov 10, 2026
Bisect on one machine with a focused run each time:
-run '^TestMemoryLateReceiptReachesFactoryHeaderAfterQuit$',nice -n 19,-p 1,GOMAXPROCS=2. Every failure was the same line,provider=0.0400 memory=0.0000 ledger=0.0200 header=0.0200.land/app-v3beforedev's #2583dev15d40fd (#2583)land/app-v3now, which also carries #2588 and the Close fixesCombined with this issue's own counts (7 of 20 on
app/v3a687c92, and 9 of 20 on the earlier landing candidate), the failure rate is:The bug existed before #2583. Merging #2583 onto
app/v3makes it about twice as likely.Checked for the embedded engine (furrow). The first two rows were built in a worktree without
internal/furrowbin/cache/furrow-linux-amd64.gz; the third was built with it. The pin is the same. Holding that constant:app/v3a687c92 against 2c5e083The first run in a fresh process fails at the same rate as later runs, so state left over by an earlier iteration in the same process is not what drives it.
#2583 did two things that may matter here:
defer stopPoolErrands(...)to the run, exec and subharness roads.What to check next: whether a stage that ends inside the app closes the shared profile's tracker before the memory worker books its late receipt. That link is not proven.