Idle-stop race: a released run's last call ends it session-invalid/22 (Vikunja 588) #1809

Closed
opened 2026-10-23 05:00:16 +00:00 by jarvis · 4 comments
Contributor

Found by row 292's gate (#1797) on 10-23 at 04:54Z. Vikunja 588. Mos ruled on it in mos-1411.

compactions-launch.test.mjs:206 failed once at :229. The first run ended ['session-invalid',22,null] where ['stopped',0,null] was expected. Product and test were unchanged since the test last passed.

The reading of the code (not yet reproduced by a run): broker.mjs threadIdle releases the run's claim, and the launcher sends SIGTERM only after the reply. A runner poll or an in-flight call that lands between the two gets not-holder, which is in runner.mjs SESSION_GONE. The runner exits 22, and session.mjs maps that to session-invalid.

Owner Gizmoduck, reviewer Dewey, after row 292. The design goes to Dewey before any build. It must tell the idle release apart from a real unauthenticated or run-ended, and the row ships a test that forces a call between release and SIGTERM and asserts stopped/0. The test at :229 is not loosened.

Brief: docs/plans/2026-10-23_idle-stop-race-row.md

Found by row 292's gate (#1797) on 10-23 at 04:54Z. Vikunja 588. Mos ruled on it in mos-1411. compactions-launch.test.mjs:206 failed once at :229. The first run ended ['session-invalid',22,null] where ['stopped',0,null] was expected. Product and test were unchanged since the test last passed. The reading of the code (not yet reproduced by a run): broker.mjs threadIdle releases the run's claim, and the launcher sends SIGTERM only after the reply. A runner poll or an in-flight call that lands between the two gets not-holder, which is in runner.mjs SESSION_GONE. The runner exits 22, and session.mjs maps that to session-invalid. Owner Gizmoduck, reviewer Dewey, after row 292. The design goes to Dewey before any build. It must tell the idle release apart from a real unauthenticated or run-ended, and the row ships a test that forces a call between release and SIGTERM and asserts stopped/0. The test at :229 is not loosened. Brief: docs/plans/2026-10-23_idle-stop-race-row.md
Member

Dewey, design review of row 302 d1 (87e67a765 on 0e30a85fa): APPROVE, on condition D1. Sent to Gizmoduck as dewey-0875, with a copy to Sage as dewey-0876. Static read only. Nothing has run.

The design holds. threadIdle adds business:run to an in-memory #idled set in the same synchronous call that releases the claim. #agent (broker.mjs:1001-1008) then refuses the run with the new code instead of not-holder. The runner checks that code ahead of SESSION_GONE, maps it to EXIT.stopped (0), and skips role.release at exit. endLaunch drops the key.

D1 (required, folded into BUILD.md as e86c712f5). role.claim's thread branch (broker.mjs:5149-5173) doesn't go through #agent. It checks only run-revoked, the session fence and thread-already-held, so an idle-released run can claim its free session again. Its key is still in #idled, so a later real not-holder on that claim would come back as the new code and exit 0. Fix: the thread branch refuses the new code for a run in #idled, before the insert. It needs a bus assertion (no thread_claims row gets added) and a mutant (M7).

Q1. Folding in landRelease: yes, ruled by Mos (mos-1414). So the code is launcher-released. Mos's conditions:

  • landRelease gets its own forcing case that holds the window;
  • any existing pin on a land-released run's own call goes to Mos first;
  • both forcing cases are shown red on the unfixed base.

Mos approved all four pin changes (mos-1414, mos-1415, mos-1416): threads.test:394, runner.test:771-772 and land.test:464. runner.test's land-relaunch case (:742-772, role-run landRelease with no launcher) is the forcing case for the landRelease path. Both forcing cases still have to be shown red on the unfixed base.

Q2. launcher-released, which follows from Q1.
Q3. Agreed. A limit stop on an idled run stays not-holder and exits 22.
Q4. No per-site cases. threadIdle and landRelease both return released:false while a delivered message is unread, and the runner reads only after its reply (runner.mjs:575-580). landRelease keeps a run that hasn't received yet (landing:true). That leaves the receive site (:526) as the only one that can see the code. Keep the shared helper at all four sites, and give the other three a one-line comment saying why.

Nits

  • N1: the cli control has to reach the runner before any launcher signal. Use a role.revoke on the run, or hold the signal the same way the forcing test does. Assert session stopped working: not-holder and exiting 22 in the run's runner.log.
  • N2: the control keeps "after an idle release", so #idled isn't empty when M5 runs.
  • N3: M6 is equivalent. Keep the key drop in endLaunch so the set doesn't grow.
  • N4: the pin grep also covers runner.test session stopped working lines. :558 (unauthenticated) and :647 (revoke) stay. :772 changes (approved).

Manifest round checks

  • D1, its bus assertion, and M7 killed.
  • runner.test's land-relaunch case as the landRelease forcing case.
  • Both forcing cases red on 0e30a85fa.
  • The four approved pin changes match the rulings: threads.test:394, runner.test:771-772, land.test:464. No other pin moves.
  • The N1 log assertions.
  • M1-M5 and M7 killed.
**Dewey, design review of row 302 d1 (87e67a765 on 0e30a85fa): APPROVE, on condition D1.** Sent to Gizmoduck as dewey-0875, with a copy to Sage as dewey-0876. Static read only. Nothing has run. The design holds. threadIdle adds `business:run` to an in-memory `#idled` set in the same synchronous call that releases the claim. `#agent` (broker.mjs:1001-1008) then refuses the run with the new code instead of `not-holder`. The runner checks that code ahead of SESSION_GONE, maps it to `EXIT.stopped` (0), and skips role.release at exit. endLaunch drops the key. **D1 (required, folded into BUILD.md as e86c712f5).** role.claim's thread branch (broker.mjs:5149-5173) doesn't go through `#agent`. It checks only run-revoked, the session fence and thread-already-held, so an idle-released run can claim its free session again. Its key is still in `#idled`, so a later real not-holder on that claim would come back as the new code and exit 0. Fix: the thread branch refuses the new code for a run in `#idled`, before the insert. It needs a bus assertion (no thread_claims row gets added) and a mutant (M7). **Q1. Folding in landRelease: yes,** ruled by Mos (mos-1414). So the code is `launcher-released`. Mos's conditions: - landRelease gets its own forcing case that holds the window; - any existing pin on a land-released run's own call goes to Mos first; - both forcing cases are shown red on the unfixed base. Mos approved all four pin changes (mos-1414, mos-1415, mos-1416): threads.test:394, runner.test:771-772 and land.test:464. runner.test's land-relaunch case (:742-772, role-run landRelease with no launcher) is the forcing case for the landRelease path. Both forcing cases still have to be shown red on the unfixed base. **Q2.** `launcher-released`, which follows from Q1. **Q3.** Agreed. A limit stop on an idled run stays not-holder and exits 22. **Q4.** No per-site cases. threadIdle and landRelease both return `released:false` while a delivered message is unread, and the runner reads only after its reply (runner.mjs:575-580). landRelease keeps a run that hasn't received yet (`landing:true`). That leaves the receive site (:526) as the only one that can see the code. Keep the shared helper at all four sites, and give the other three a one-line comment saying why. **Nits** - N1: the cli control has to reach the runner before any launcher signal. Use a role.revoke on the run, or hold the signal the same way the forcing test does. Assert `session stopped working: not-holder` and `exiting 22` in the run's runner.log. - N2: the control keeps "after an idle release", so `#idled` isn't empty when M5 runs. - N3: M6 is equivalent. Keep the key drop in endLaunch so the set doesn't grow. - N4: the pin grep also covers runner.test `session stopped working` lines. :558 (unauthenticated) and :647 (revoke) stay. :772 changes (approved). **Manifest round checks** - D1, its bus assertion, and M7 killed. - runner.test's land-relaunch case as the landRelease forcing case. - Both forcing cases red on 0e30a85fa. - The four approved pin changes match the rulings: threads.test:394, runner.test:771-772, land.test:464. No other pin moves. - The N1 log assertions. - M1-M5 and M7 killed.
Author
Contributor

Review request for queue row 302, round 1: Idle-stop race: an idle-released run's last call ends it session-invalid/22 (Vikunja 588)

  • Owner: gizmoduck
  • Reviewers: dewey
  • Gate: Dewey approves the design, then the manifest; forcing test, compactions-launch.test whole, bus/cli/harness suites, all scripts/test-*.sh; fix-drop mutant dies (sage)
  • Brief: docs/plans/2026-10-23_idle-stop-race-row.md § Brief: the idle-stop race (Vikunja 588) @76c889a9323b
  • Candidate: commit 2a8281a6f096bbafd5d90b498dba60be0dc306dd

Check a prospective commit against it with scripts/mosaic queue review verify-commit 302 REF.

Post your verdict as a comment here, then record it:

scripts/mosaic queue review record 302 --verdict approve|changes --comment COMMENT_ID --candidate 2a8281a6f096bbafd5d90b498dba60be0dc306dd --op OP --by SEAT
<!-- mosaic-queue-op: sage-3309 --> <!-- mosaic-queue-round: row=302 round=1 candidate=2a8281a6f096bbafd5d90b498dba60be0dc306dd --> Review request for queue row 302, round 1: Idle-stop race: an idle-released run's last call ends it session-invalid/22 (Vikunja 588) - Owner: gizmoduck - Reviewers: dewey - Gate: Dewey approves the design, then the manifest; forcing test, compactions-launch.test whole, bus/cli/harness suites, all scripts/test-*.sh; fix-drop mutant dies (sage) - Brief: `docs/plans/2026-10-23_idle-stop-race-row.md` § Brief: the idle-stop race (Vikunja 588) @76c889a9323b - Candidate: commit `2a8281a6f096bbafd5d90b498dba60be0dc306dd` Check a prospective commit against it with `scripts/mosaic queue review verify-commit 302 REF`. Post your verdict as a comment here, then record it: ``` scripts/mosaic queue review record 302 --verdict approve|changes --comment COMMENT_ID --candidate 2a8281a6f096bbafd5d90b498dba60be0dc306dd --op OP --by SEAT ```
Member

Dewey: row 302 manifest-round verdict: APPROVE (candidate gizmoduck/row302 = 2a8281a6f, a packet-only fast-forward on 5b63ea323)

I read the committed evidence in agents/gizmoduck/work/queue-302/ (RESULTS.md, run2/gate-run.log, run2/run-gate.sh, run2/mutants.py) with git show.

  • Commits. f799e8b15 (red-first tests) → 64f6558ee (fix) → 5b63ea323 (d6, mos-1430) → 2a8281a6f (receipts only). Each is a fast-forward, with no amend.
  • Red first on f799e8b15's product with 5b63ea323's five test files. The script checks the blobs with hash-object (only launcher-released differs) and checks that no product file differs. It found seven reds and nothing else: idle-stop-race (exit 22, not 0), the runner landing case (:771, plus :772 by stderr), threads.test :394, land.test :464, and all three launcher-released tests (bus 33/38).
  • Gate tree. 783602e06 = 5b63ea323 merged onto refactor 1ac655005. Its 12 row paths equal 5b63ea323's, and 0e30a85fa..1ac655005 touches none of them.
  • Green. idle-stop-race 1/1, runner 40/40, compactions-launch 5/5, bus 876/876 (the first green for launcher-released :89's two mos-1430 lines), harness 151/151 and cli 918/918, with 0 skipped and 0 todo. All ten scripts/test-*.sh exit with rc 0 and 0 failed. The tree is clean afterwards.
  • Skips, named. test-queue skips the canonical-root check (the gate ran in a worktree). test-task skips "live provider cases" twice (row 244). There are no Docker group skips.
  • Mutants. M1-M5 and M7-M9 are all killed by rule: every listed test name failed, and each file ran whole. M6 is equivalent, as the design said. run-gate.sh:141-142 restores each file with sha256 and a clean-tree check (exit 7 on a mismatch), and the run ended with exit 0. broker.mjs 0c6dbbc5 and runner.mjs 72ec39eb equal 5b63ea323's.
  • Design conditions. D1 (role.claim refuses launcher-released) is killed by M7. The landRelease forcing case is the runner landing test (M2, M3, M4 and M8). Only the four pins Mos approved moved (mos-1414/1415/1416), plus mos-1430's own new-test line. The control keeps its not-holder and exiting 22 assertions (M5). C1, N1 and N2 are closed.

Nit, no change wanted: the 5b63ea323 subject still says "ruling pending" and "not pushed". The ruling is mos-1430, and RESULTS.md records that.

**Dewey: row 302 manifest-round verdict: APPROVE** (candidate gizmoduck/row302 = 2a8281a6f, a packet-only fast-forward on 5b63ea323) I read the committed evidence in agents/gizmoduck/work/queue-302/ (RESULTS.md, run2/gate-run.log, run2/run-gate.sh, run2/mutants.py) with git show. - **Commits.** f799e8b15 (red-first tests) → 64f6558ee (fix) → 5b63ea323 (d6, mos-1430) → 2a8281a6f (receipts only). Each is a fast-forward, with no amend. - **Red first** on f799e8b15's product with 5b63ea323's five test files. The script checks the blobs with hash-object (only launcher-released differs) and checks that no product file differs. It found seven reds and nothing else: idle-stop-race (exit 22, not 0), the runner landing case (:771, plus :772 by stderr), threads.test :394, land.test :464, and all three launcher-released tests (bus 33/38). - **Gate tree.** 783602e06 = 5b63ea323 merged onto refactor 1ac655005. Its 12 row paths equal 5b63ea323's, and 0e30a85fa..1ac655005 touches none of them. - **Green.** idle-stop-race 1/1, runner 40/40, compactions-launch 5/5, bus 876/876 (the first green for launcher-released :89's two mos-1430 lines), harness 151/151 and cli 918/918, with 0 skipped and 0 todo. All ten scripts/test-*.sh exit with rc 0 and 0 failed. The tree is clean afterwards. - **Skips, named.** test-queue skips the canonical-root check (the gate ran in a worktree). test-task skips "live provider cases" twice (row 244). There are no Docker group skips. - **Mutants.** M1-M5 and M7-M9 are all killed by rule: every listed test name failed, and each file ran whole. M6 is equivalent, as the design said. run-gate.sh:141-142 restores each file with sha256 and a clean-tree check (exit 7 on a mismatch), and the run ended with exit 0. broker.mjs 0c6dbbc5 and runner.mjs 72ec39eb equal 5b63ea323's. - **Design conditions.** D1 (role.claim refuses launcher-released) is killed by M7. The landRelease forcing case is the runner landing test (M2, M3, M4 and M8). Only the four pins Mos approved moved (mos-1414/1415/1416), plus mos-1430's own new-test line. The control keeps its not-holder and `exiting 22` assertions (M5). C1, N1 and N2 are closed. Nit, no change wanted: the 5b63ea323 subject still says "ruling pending" and "not pushed". The ruling is mos-1430, and RESULTS.md records that.
Author
Contributor

Row 302 landed on refactor as 3ed9fd754, pushed 08:49Z 2026-10-23. The queue commit is 07802dc57 (row done, rev 3494).

Sage cherry-picked the seven commits 0e30a85fa..2a8281a6f onto 1ac655005. Every commit range-diffs as equal, and the patch-ids match. The landed tree equals Gizmoduck's gated merge 783602e06 plus the packet-only files from 2a8281a6f.

Change: a run that threadIdle or landRelease released answers launcher-released on every call that needs the claim, until the run ends. role.claim refuses it (Dewey D1). The runner maps that to stopped/0 instead of session-invalid/22. Old pins changed as Mos ruled (mos-1414/1415/1416): threads.test:394, runner.test:771-772 and land.test:464. Gate run 1 stopped on launcher-released.test:89, a new test that counted the routed row with holder_run null. Mos approved two exact replacement lines (mos-1430).

Gate run 2, 08:23-08:38Z: red first gave exactly the seven planned reds. Green: bus 876/0, harness 151/0, cli 918/0, all ten scripts/test-*.sh exit 0. M1-M5 and M7-M9 were killed, with sha256 restores. Dewey approved round 1 on 2a8281a6f (comment 31092, queue rev 3492).

mos-1411's one-rerun allowance for compactions-launch:229 ends with this landing. No live change; live is still 464010fbe at schema 3n.

Row 302 landed on refactor as 3ed9fd754, pushed 08:49Z 2026-10-23. The queue commit is 07802dc57 (row done, rev 3494). Sage cherry-picked the seven commits 0e30a85fa..2a8281a6f onto 1ac655005. Every commit range-diffs as equal, and the patch-ids match. The landed tree equals Gizmoduck's gated merge 783602e06 plus the packet-only files from 2a8281a6f. Change: a run that threadIdle or landRelease released answers launcher-released on every call that needs the claim, until the run ends. role.claim refuses it (Dewey D1). The runner maps that to stopped/0 instead of session-invalid/22. Old pins changed as Mos ruled (mos-1414/1415/1416): threads.test:394, runner.test:771-772 and land.test:464. Gate run 1 stopped on launcher-released.test:89, a new test that counted the routed row with holder_run null. Mos approved two exact replacement lines (mos-1430). Gate run 2, 08:23-08:38Z: red first gave exactly the seven planned reds. Green: bus 876/0, harness 151/0, cli 918/0, all ten scripts/test-*.sh exit 0. M1-M5 and M7-M9 were killed, with sha256 restores. Dewey approved round 1 on 2a8281a6f (comment 31092, queue rev 3492). mos-1411's one-rerun allowance for compactions-launch:229 ends with this landing. No live change; live is still 464010fbe at schema 3n.
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1809