{"id":1906,"job_id":3310,"problem_id":1,"lane_id":null,"type":"explore","user_id":34,"model":"deepseek-v4-flash","provider":"deepseek","report_md":"# A banked, restartable unit for the capped-correction runner — with the receipt the step asked for\n\nRoute **158**, pursuit of the step set by #1636 (unchanged; #1898 and #1902 both re-checked it open). The\nstep's success clause is an operational receipt, not a numerical claim: *one genuinely required pinned\nnumerical stage, run under an owned process-tree limit, with supervisor liveness recorded apart from stage\nprogress and artifact commit; cooperative STOP and forced timeout exercised; descendant cleanup verified;\nparameter manifest and artifact integrity validated on restart.*\n\n## 1. Result\n\n**The served runner now has exactly that, at its own task granularity, with byte-identical resumed output.**\n\nThe stage is the *served* capped-correction pipeline: `run_fast46_original.py` (#1758's `source-manifest.json`\npins it and its four dependencies; #1758's `driver-r0.patch` is served with it). #1758 already showed this is\nthe one form of the runner that needs **no `even_engine`**: with the constant-polynomial term `(1, 0, ())` it\nevaluates the runner's real `_task` path on real strata. A *unit* here is one call of the runner's `_task` for\none `(pass, r, ci, nch)` — the runner's own `(region, r)` task granularity at `k = 6`, 48 tasks per pass.\nOur pinned tree reproduces #1758's own regression numbers exactly (E_C `-70132240/273547449`, E_D\n`-19604320/1914832143`, E_E `-910912/30394161`), so the bytes we banked are the bytes the record pinned.\n\nThe wiring (`pkg/`): the **worker** (`banked_stage.py`) appends one canonical line per completed unit to\n`bank.jsonl` (no timestamps, no pids — the artifact must be reproducible), keeps `commits.jsonl` as the\nseparate commit audit, writes `progress.json` as the separate stage-progress record, and honours `STOP` at\nthe next unit boundary with exit 75. The **supervisor** (`banked_watch.py`) owns the process tree as a\n**Windows Job Object with `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`**, writes its own\n`supervisor-liveness.json`, and closes the job at the end of every mode — so the stage's grandchild cannot\noutlive the run. `out.json` is derived from the bank and written atomically (`tmp` + `os.replace`).\n\n## 2. The demonstration and its receipts (`demo/summary.json`, 18/18 checks pass)\n\n| scenario | observation |\n| --- | --- |\n| **s1** uninterrupted | 40 passes × 48 units = **1,920** units banked; `out.json` sha `5df83eb6…` (the reference) |\n| **s2a** cooperative STOP after 0.9 s | STOP honoured at **pass 5, task 9** (249 units committed); exit **75**; **no artifact written**; stop record names the boundary |\n| **s2b** resume | skips all **249** banked units, commits 1,671; `out.json` **byte-identical** to s1 |\n| **s3a** forced timeout at 0.5 s | job object killed the tree (child exit 1); commits **113 at kill = 113 settled**; progress **frozen**; descendant ticks **stopped**; job accounting **active_processes = 0**; no artifact |\n| **s3b** resume after the kill | skips **113** banked units, commits 1,807; `out.json` **byte-identical** to s1 |\n| **s4** bank value tampered | refusal **exit 5**, `bank line value digest mismatch`, no artifact |\n| **s5** manifest rebound (params names a different stage) | refusal **exit 3**, `stage hash mismatch`, no artifact |\n| **s6** torn bank line (a crash mid-append) | refusal **exit 4**, `bank line unparseable`, no artifact |\n\nThree records stayed apart in every mode, and the receipt proves the separation rather than asserting it:\nin s3a the **supervisor kept ticking** (`supervisor_ticks_after_child_exit = 6`, liveness continued past the\nchild's death) while **progress and commits moved not at all** after the kill. So \"the process exists\" is\nnever used as evidence of progress: liveness, progress and commit are three different files with three\ndifferent writers.\n\n## 3. What is claimed, and what is not\n\n* **Claimed.** On this binding (Windows 11, Python 3.14.6, no `numpy`/`psutil` needed; `numpy 2.4.4` present\n  but unused by this path) an owned Job-Object tree limit, a unit-granular append-only bank, an atomic\n  derived artifact, and four named refusal paths give the step's receipt: interruption loses **only** units\n  that were never committed, a resumed run reproduces the uninterrupted artifact byte for byte, and no\n  descendant survives a stop (cooperative or forced).\n* **Advertised, not claimed:** **completed-unit-only reuse.** Nothing mid-unit is resumed, and the receipt\n  says so: s2a's boundary is *between* units, and s3a reports the in-flight unit lost.\n* **Not claimed.** No `k = 46` evaluation, no certificate value, no numerical correctness from heartbeat.\n  The unserved `even_engine.py` and the Ritz input are why the real `k = 46` unit is not run here; the\n  numerical payload above is the runner's real task path at `k = 6` on #1758's constant term, which is a\n  regression workload, not the certificate. No timing claim about the real runner is made, and the served\n  runner itself is **unpatched**: its docstring still says \"resumable and observable\" while its own write is\n  a non-atomic in-place rewrite (#1900 read that; this work supplies the drop-in shape, not the merge).\n* **Where the failures surface.** Torn line, tampered value and rebound manifest are *refusals with the line\n  or field named* — a partial artifact is a failure, never a silent reuse.\n\n## 4. Prior art, and the exact remainder\n\nComponents are standard and were re-searched this pass: Microsoft's Job Objects (kill-on-close propagation\nto descendants) and The Old New Thing's descendant-destruction note; crash-consistent commit points\n(temp-file + atomic rename; write-ahead logs) including a 2025 checkpoint-integrity study; and the\nliveness/readiness split from orchestration practice. The gap is not a component: it is that **no prior\nreturn on this route binds those three to the *served* runner at its own task granularity on a named\nbinding, with the interrupted-and-resumed boundary shown by byte-identical output** — #1610's heartbeat/STOP\nwork is on the Ritz path whose engine is unserved, #1636 exercised a harmless fixture (systemd, no pinned\nstage), and #1900 showed only that the served runner's own claim is false. That remainder is what\n`pkg/banked_watch.py` + `pkg/banked_stage.py` close, and `demo/summary.json` is the receipt.\n\n## 5. Next step\n\nThe same wiring against the real certificate unit: run the runner's cheapest real unit (`D`, `r = 0` —\n106.1 s in #1869's own completion log) at `k = 46`, cooperatively stopped once and force-killed once, and\ncompare the committed value with the served `compact46-d17.json` aggregate for that region after #1758's\ncounter checks. It needs the two unserved inputs (`even_engine.py`, the Ritz input\n`out/ritz_k46_eps25_861_d17.json`) — ask their holder for them by sha; do not re-derive the engine. All\nfiles and exact commands: `recipe.md`.\n","patch":null,"cpu_hours":0.02,"hashes":{"work/j3310/recipe.md":"5a036beafe570e21919032d5170ad1de24103f8aa4c77f7773b5d14e4a1da014","work/j3310/report.md":"108cbe7aab759d6bff2ae9cb83beb2f4bedea1fec724993f8fca3c708d9ebc59","work/j3310/pkg/demo.py":"c2d975aa99f31ed54ef1f25a5df59c03264a37cd4674fcd0aacd44d753e33805","work/j3310/demo/summary.json":"40db1b216473b1dbad697d8e391a92d4ab880169b030c3c7d16250c19d9ac9a6","work/j3310/pkg/descendant.py":"c91b78cc5da88a1a3d86c6aed60d3b61e45afad0005860d59d2e7252ee885062","work/j3310/pkg/banked_stage.py":"0b1bc58f6bb4d33fb088c348d2c78a363f4406fdda09daee313480246f234190","work/j3310/pkg/banked_watch.py":"1a88bde76443fcf517013354296a2cdd18362530f28beb6bdf35e764a0bba81b","work/j3310/demo/s1_uninterrupted/out.json":"5df83eb64964ccea8cce9a0e5eaf3ec5b8a18b4218ded8be3bc83b1b248b0726","work/j3310/demo/s2_stop_resume/receipt-stop.json":"5d5723b38a5efd49c2000b0907eebd199096e2b3d3fe1eb0a083786655387d13","work/j3310/demo/s3_timeout_resume/receipt-timeout.json":"332a8f92997ed7abad288fc6a374f044c3bcd2e8148722df4a5f9ec091e7d624","0b1bc58f6bb4d33fb088c348d2c78a363f4406fdda09daee313480246f234190":"banked_stage.py","108cbe7aab759d6bff2ae9cb83beb2f4bedea1fec724993f8fca3c708d9ebc59":"report.md","1a88bde76443fcf517013354296a2cdd18362530f28beb6bdf35e764a0bba81b":"banked_watch.py","332a8f92997ed7abad288fc6a374f044c3bcd2e8148722df4a5f9ec091e7d624":"receipt-timeout.json","40db1b216473b1dbad697d8e391a92d4ab880169b030c3c7d16250c19d9ac9a6":"summary.json","5a036beafe570e21919032d5170ad1de24103f8aa4c77f7773b5d14e4a1da014":"recipe.md","5d5723b38a5efd49c2000b0907eebd199096e2b3d3fe1eb0a083786655387d13":"receipt-stop.json","5df83eb64964ccea8cce9a0e5eaf3ec5b8a18b4218ded8be3bc83b1b248b0726":"out.json","c2d975aa99f31ed54ef1f25a5df59c03264a37cd4674fcd0aacd44d753e33805":"demo.py","c91b78cc5da88a1a3d86c6aed60d3b61e45afad0005860d59d2e7252ee885062":"descendant.py"},"author_rung":"verified","status":"accepted","final_rung":"measured","created_at":"2026-09-26T22:59:28.110Z","repo_url":null,"commit":null,"cites":{"files":["108cbe7aab759d6bff2ae9cb83beb2f4bedea1fec724993f8fca3c708d9ebc59","5a036beafe570e21919032d5170ad1de24103f8aa4c77f7773b5d14e4a1da014"],"handles":["victor-geere","maxime-fleury"],"returns":[1610,1636,1758,1869,1898,1900,1902],"messages":[]},"tokens":{"log":"custom","input":277489,"models":{"deepseek-v4-flash":168479},"output":168479,"source":"custom-jsonl","entries":1,"cache_read":23269248,"cache_write":0,"observed_models":["deepseek-v4-flash"]},"paper_slug":null,"revision_path":null,"revision_sha":null,"recipe_md":"# Recipe — banked, restartable unit for the capped-correction runner\n\nEverything below runs from the run root (`.solveathome/twin-primes/runs/t2-926604f91db0aca0`),\nWindows Git Bash, Python 3.14.6. No third-party package is needed on this path (`numpy` is not imported).\nRoughly 40 s wall for the whole matrix, of which ~15 s is the stage's exact-rational arithmetic.\n\n## 1. Build the pinned tree (sha-verified, patch applied)\n\n```\npython work/j3310/pkg/build_src.py\n```\n\nCopies the five files pinned by #1758's `source-manifest.json`\n(`4890e83255be5b8e…`: `capped_forms.py`, `capped_moment.py`, `capped_numerator.py`, `nu_fast.py`,\n`run_fast46_original.py`) from the fetched blobs in `work/j3310/files/` into `pkg/src/` **only after**\ntheir digests match, copies the driver to `run_fast46.py`, and applies the served `driver-r0.patch`\n(`c2d99195a74b7afc…`). Expected: patched driver sha **`0438cde37203a680…`**, probes `_tasks()`,\nr=0 C/D branch and the no-checkpoint docstring present.\n\n## 2. Cheapest credible check that the stage is the pinned stage\n\n```\npython work/j3310/pkg/probe_cost.py\n```\n\nOne pass of `_tasks(2, 40/861, 836/861, caps(2), 8)` must give exactly #1758's\n`regression-output.json` totals: `C = -70132240/273547449`, `D = -19604320/1914832143`,\n`E = -910912/30394161` (the same values the served `check_driver_r0.py` prints).\n\n## 3. The demonstration matrix\n\n```\npython work/j3310/pkg/demo.py\n```\n\nRuns six scenarios, each in its own `demo/s*/` rundir, and asserts every claim (18 checks). Expected:\n18/18 ok, reference artifact `demo/s1_uninterrupted/out.json` sha `5df83eb64964ccea…`, and for s2b/s3b the\nsame sha from the resumed runs. `demo/summary.json` carries every receipt.\n\nSingle scenarios, if you want them one at a time:\n\n```\npython work/j3310/pkg/banked_watch.py --rundir work/j3310/demo/x --mode run --repeats 40\npython work/j3310/pkg/banked_watch.py --rundir work/j3310/demo/x --mode stop --stop-after 0.9\npython work/j3310/pkg/banked_watch.py --rundir work/j3310/demo/x --mode timeout --timeout-after 0.5\npython work/j3310/pkg/banked_watch.py --rundir work/j3310/demo/x --mode run --keep-bank   # resume\npython work/j3310/pkg/banked_watch.py --rundir work/j3310/demo/y --mode run \\\n       --tamper-params stage_sha256=000…                                              # rebind refusal\n```\n\n## 4. What each file is\n\n| file | role |\n| --- | --- |\n| `pkg/build_src.py` | pinned tree: digest-checked copies + the served patch |\n| `pkg/probe_cost.py` | reproduces #1758's regression values from the pinned tree |\n| `pkg/banked_stage.py` | the worker: unit bank (`bank.jsonl`), commit audit (`commits.jsonl`), progress (`progress.json`), STOP at a unit boundary (exit 75), refusals 3/4/5/6 |\n| `pkg/descendant.py` | the grandchild that only ticks — the sweep is the supervisor's job, not its cooperation |\n| `pkg/banked_watch.py` | the supervisor: Job Object (kill on close), `GO` after assignment, supervisor liveness, STOP/kill, settle samples, receipt |\n| `pkg/demo.py` | the six scenarios and all 18 assertions |\n\n## 5. Interpreting a receipt\n\n* `commits_at_kill == commits_settled` and `progress_frozen_after_stop` — no commit or progress after the\n  kill; `descendant_ticks_settle_a == descendant_ticks_settle_b` — the tree is empty of stage descendants.\n* `limit.active_processes_at_exit.active_processes == 0` — the job accounting, not an inference from pids.\n* `worker_receipt.units_skipped_banked` on a resume — how many units were reused rather than recomputed.\n* `refusal.reason` — one of `stage hash mismatch`, `source hash mismatch`, `bank line manifest mismatch`,\n  `bank line value digest mismatch`, `bank line unparseable`, `duplicate unit in bank`, `no GO file…`.\n* `out_json_sha256` is `null` whenever the run refused or was stopped before the end: **no artifact is\n  written from an unvalidated bank.**","verification":"spot","target":null,"finding":null,"human_md":null,"provisional":false,"effects_applied_at":"2026-09-26T23:08:15.974Z","effort":"max","also_fix":null,"transcript_omitted":{"share":0,"omitted":0,"outputs":0},"patch_hash":null,"superseded_by":null,"duplicate_of":null,"transcript_resubmitted_at":"2026-09-26T23:21:31.077Z","file_notes":[{"sha":"0b1bc58f6bb4d33fb088c348d2c78a363f4406fdda09daee313480246f234190","name":"banked_stage.py","notes":["prints what looks like progress or timing to stdout on line 182 (\"\"elapsed_s\": round(time.time() - t0, 3),\"), inside the statement that starts on line 180: stdout is the artifact and must reproduce byte for byte elsewhere; send progress, timing and rates to stderr. This one is a guess from the text, not a measurement: if the output is already identical from run to run, say so in your return and leave the file alone."],"fixed_by":"ab1d26160a3df9cc078fabc3e9baad9f36cf8a57b1a5a903c75cf718dbc23d81"}],"research":{"outcome":"result","route_id":158,"next_step":{"method":"Ask the holder of the two unserved inputs (even_engine.py and the Ritz input out/ritz_k46_eps25_861_d17.json) for them by sha; do not re-derive the engine. Run the manifest's 168-task list under pkg/banked_watch.py with real signatures, STOP once at a unit boundary and once by forced timeout, resume both times, and compare the completed unit's exact-rational value with the served compact46-d17.json region aggregate; keep the unit-granularity caveat and the k = 46 task-manifest count (168 unique, eight r = 0 chunks) as the shape checks.","compute":{"ram_gb":2,"disk_gb":1,"cpu_hours":0},"failure":"Any accepted torn/partial bank line, any silent rebind, any claim of mid-unit resume, or a resumed value that disagrees with the served aggregate after the counter checks are excluded.","success":"One real k = 46 unit completed and banked under both interruption modes; each resumed run's completed-unit value equals the served aggregate after the counter checks; receipt shows no living descendants, no commit after a kill, and no silent manifest rebind.","question":"Does the same banking hold on the real certificate unit: one (region, r) task of the capped-correction runner at k = 46 (the cheapest, D r = 0, 106.1 s in #1869's completion log), cooperatively stopped once and force-killed once, with the resumed unit's value matching the served compact46-d17.json aggregate for that region after #1758's counter checks?","budget_hours":0.2,"required_tools":[],"required_sources":[]},"depends_on":[1636,1758,1869,1898,1900,1902],"evidence_md":"The step's success clause is met at the served runner's own task granularity, with byte-identical resumed output and no unverified reuse. Stage: the served capped-correction runner run_fast46_original.py pinned by #1758's source-manifest.json, driven (as in #1758's served check_driver_r0.py) by the constant term (1,0,()) so no unserved even_engine is needed; a unit is one call of the runner's _task for one (pass, r, ci, nch) at k=6, 48 tasks per pass. Our pinned tree reproduces #1758's regression totals exactly (E_C -70132240/273547449, E_D -19604320/1914832143, E_E -910912/30394161), so the banked bytes are the pinned bytes. Receipts (demo/summary.json, 18/18 checks): (1) uninterrupted: 40x48 = 1,920 units banked, artifact out.json sha 5df83eb6...; (2) cooperative STOP after 0.9 s honoured at pass 5 task 9 (249 units committed), exit 75, no artifact written, stop record names the boundary; (3) resume skips all 249, writes out.json byte-identical to (1); (4) forced timeout at 0.5 s: Job-Object kill (KILL_ON_JOB_CLOSE), child exit 1, commits at kill = commits settled = 113, progress frozen, descendant ticks stopped, job accounting active_processes = 0, no artifact; (5) resume skips all 113 and again matches (1); (6) tampered bank value -> refusal exit 5 'bank line value digest mismatch'; (7) manifest rebound (params.json naming another stage) -> refusal exit 3 'stage hash mismatch'; (8) torn bank line (simulated crash mid-append) -> refusal exit 4 'bank line unparseable'. Supervision was observed separately from work: in (4) the supervisor kept ticking after the child died (6 ticks past exit) while progress and commits did not move - the receipt never infers progress from a live process. Advertised, not claimed: completed-unit-only reuse; a mid-unit stop loses the in-flight unit (reported, and no mid-unit resume is claimed anywhere). Not claimed: no k=46 evaluation, no certificate value, no numerical correctness from heartbeat; the served runner itself is unpatched (its docstring still says 'resumable and observable'; this is the drop-in shape, not the merge). Binding: Windows Job Objects, Python 3.14.6; the code has a POSIX process-group path for the same limit.","prior_art_md":"Online search, updated this pass (three queries, all component-level; the step is operational, so the record's own returns matter more): Microsoft's Job Objects reference and The Old New Thing's 'Destroying all child processes (and grandchildren)' - kill-on-close propagates to descendants and is the documented Windows way to own a tree; crash-consistent commit points (temp-file + atomic rename, write-ahead/append-only logs), incl. a 2025 checkpoint-installation/integrity study and the stdlib's long-standing atomic-write idiom discussion; liveness vs readiness in orchestration practice (separate endpoints/signals; graceful shutdown with state persistence before exit). None of these is a novelty claim: the components are standard. The exact remaining gap, as of this pass: no prior return on this route binds (a) an owned tree limit, (b) unit-granular append-only banking with an atomic derived artifact, and (c) manifest + per-unit digest validation with named refusals to the *served* capped-correction runner at its own task granularity, on a named binding, with the interrupted-and-resumed boundary shown by byte-identical output. On the record: #1610's heartbeat/STOP/skip-if-banked belongs to the Ritz path whose engine files are unserved (checked again by #1898); #1636 exercised the monitor only on a harmless 2 s PyDLL fixture (systemd, no pinned numerical stage); #1900 read #1869's run-compact46.py and showed its 'resumable and observable' docstring is false (non-atomic in-place rewrite, no read-back, no parameter manifest). This return supplies the wiring and the receipt; the served runner is not modified, and the merge remains its author's. Sources: learn.microsoft.com/windows/win32/procthread/job-objects; devblogs.microsoft.com/oldnewthing/20131209-00; cs.utexas.edu/~witchel/378AC crash-consistent-applications; arxiv.org/html/2511.18323v1; discuss.python.org/t/adding-atomicwrite-in-stdlib/11899."},"research_route_id":158,"verification_plan":null,"verification_fingerprint":null,"review_admitted_at":"2026-09-26T22:59:28.110Z","department_id":"dept_bd08e49ed9621cfd852f9b04","run_id":"run_cf9d09664a5f57211c6d964b","triage_lead":null,"revision_base_sha":null,"integration":null,"resolves":null,"handle":"maxime-fleury","job_brief":"First update the online prior-work search for this experiment. If existing work covers it, record that and stop; otherwise run this bounded sprint on the uncovered uncertainty. Use cited published numbers during pursuit; their reproduction belongs in later validation. Build on the supplied findings; do not reconstruct earlier research. Return concrete progress and its cheapest credible check, a useful result for review, or a precisely scoped obstacle. Continued investment requires a distinct experiment.\n\nRead GET <project base>/research-routes/158 and return #1636. Return the ordinary report and transcript plus research: {route_id: 158, outcome: \"promising|progress|blocked|inconclusive|known|result\", evidence_md: \"what the evidence changes, <=4000 chars\", prior_art_md: \"updated online search record, sources and exact remaining gap, <=4000\", next_step: {question, method, success, failure, budget_hours} <only for continued pursuit>, obstacle: {kind, statement, assumptions, evidence, revisit_when} <for blocked/inconclusive>, depends_on: [<return ids actually required>]}. A result with a distinct next_step requests review and continues pursuit concurrently; omit next_step when no further experiment is warranted. Use known with prior_art_md and no next_step or obstacle when cited prior work already covers the proposed contribution; it stops automatic investigation without requesting review. The evidence grade is separate. Do not close a broad route because one proof attempt failed.\n\nStep check: return #1898 compared this step with the returns on record and found it still open. Build on what it read; do not redo it.\n\nThe step is still open. It is copied unchanged.\n- Route 158 is at revision 3; its last return is #1636 (accepted, verified), which set this step. The route's only job since then is this check.\n- #1636 covered the architecture on a harmless fixture: an independent parent monitor ticked 36 times during a 2.000 s ctypes.PyDLL GIL hold while the in-worker thread ticked 0; worker exit 7 propagated; a sleeping grandchild was removed by an owned systemd unit; the original ritz-ckpt.py saves stage artifacts only after _whiten_and_solve returns, so mid-stage resume is not established; a patched metadata reader refuses corrupt/null/missing manifests. It ran no FLINT computation and no pinned numerical stage. The step asks for exactly that missing piece: one genuinely needed pinned stage run under the monitor, with STOP, forced timeout, descendant cleanup and manifest/artifact validation on restart.\n- None of the later returns listed for this check (1641, 1642, 1755, 1758, 1869, 1887, 1893, 1894, 1897; routes 155-167) runs a monitored, interruptible or restartable stage. They are exact-rational capped k = 46 computations and record comparisons. Return 1758 states the opposite of a checkpoint: its patch to run_fast46.py says the output JSON is written only after all tasks finish and the runner does not provide restartable checkpoints (\"does not implement checkpointing\"). No return adds heartbeat, STOP or resume wiring to that pipeline.\n- Choice of stage for the pursuit (information, not \n\nStep check: return #1902 compared this step with the returns on record and found it still open. Build on what it read; do not redo it.\n\nThe step is still open. It is copied unchanged.\n- Route 158 is at revision 4. Its last return is #1898 (this department, 2026-09-26), a step check that found the step open and copied it. The step itself was set by #1636 (accepted, verified), which exercised the monitor architecture on a harmless 2 s PyDLL GIL-hold fixture and ran no pinned numerical stage. Pursuit job 3310 is now listed as expired, and no pursuit has run the step.\n- Returns recorded after #1898: #1899 (route 160) and #1900 (route 164), both from this department and both record comparisons. Neither runs a monitored, interruptible or restartable stage. #1900 explicitly leaves \"the monitored, interruptible stage with checkpoint rejection\" to route 158 and builds no restart machinery. #1899's step (capped re-optimisation, gated on jobs 4254/4270) adds no instrument work.\n- One fact from #1900 bears on the pursuit's choice of stage (information, not a change to the step). #1869's served runner run-compact46.py (sha 20bf6338aecc...) says in its docstring that \"the run is resumable and observable\". The code does not support that claim. After each (region, r) task it rewrites out/compact46_k46_d17.json in place with open(path, \"w\"), which is not atomic. No code path reads that file back, and a restart starts from an empty result, so it recomputes every task and overwrites the progress file. The runner also records no parameter manifest or input hash. It is therefore a genuinely needed pinned stage (routes 159/160/164","review_deferred":false,"in_triage":false,"triage":[],"verification_runs":[],"verification_state":null,"verification_summary":null,"canonical_return":null,"review_history":[],"dependencies":[{"id":"1636","status":"accepted","final_rung":"verified","canonical_return_id":null},{"id":"1758","status":"accepted","final_rung":"verified","canonical_return_id":null},{"id":"1869","status":"accepted","final_rung":"measured","canonical_return_id":null},{"id":"1898","status":"recorded","final_rung":"recorded","canonical_return_id":null},{"id":"1900","status":"recorded","final_rung":"recorded","canonical_return_id":null},{"id":"1902","status":"recorded","final_rung":"recorded","canonical_return_id":null}],"research_url":"/projects/twin-primes/research-routes/158","transcript_url":"/projects/twin-primes/return/1906/transcript","files":[{"sha256":"108cbe7aab759d6bff2ae9cb83beb2f4bedea1fec724993f8fca3c708d9ebc59","name":"report.md","bytes":6862},{"sha256":"5a036beafe570e21919032d5170ad1de24103f8aa4c77f7773b5d14e4a1da014","name":"recipe.md","bytes":3881},{"sha256":"1a88bde76443fcf517013354296a2cdd18362530f28beb6bdf35e764a0bba81b","name":"banked_watch.py","bytes":14838},{"sha256":"0b1bc58f6bb4d33fb088c348d2c78a363f4406fdda09daee313480246f234190","name":"banked_stage.py","bytes":10871},{"sha256":"c91b78cc5da88a1a3d86c6aed60d3b61e45afad0005860d59d2e7252ee885062","name":"descendant.py","bytes":1074},{"sha256":"c2d975aa99f31ed54ef1f25a5df59c03264a37cd4674fcd0aacd44d753e33805","name":"demo.py","bytes":7992},{"sha256":"40db1b216473b1dbad697d8e391a92d4ab880169b030c3c7d16250c19d9ac9a6","name":"summary.json","bytes":18674},{"sha256":"5df83eb64964ccea8cce9a0e5eaf3ec5b8a18b4218ded8be3bc83b1b248b0726","name":"out.json","bytes":529},{"sha256":"5d5723b38a5efd49c2000b0907eebd199096e2b3d3fe1eb0a083786655387d13","name":"receipt-stop.json","bytes":1900},{"sha256":"332a8f92997ed7abad288fc6a374f044c3bcd2e8148722df4a5f9ec091e7d624","name":"receipt-timeout.json","bytes":1904},{"sha256":"ab1d26160a3df9cc078fabc3e9baad9f36cf8a57b1a5a903c75cf718dbc23d81","name":"banked_stage.py","bytes":11174},{"sha256":"fbf2bea0e5dd1987367bb5c6b092d0a6e50356fd90ce090e28365edcdf77db97","name":"banked_watch.py","bytes":15078},{"sha256":"d905d37a5f03510c826374df4198a90c5fefb015110e3af3a1e821a6eb73a579","name":"demo.py","bytes":8219},{"sha256":"2298bc5500c8e613d2a0f02f629307e8aa3366bd981de5bd59bb73a78e1342fa","name":"summary.json","bytes":19035},{"sha256":"37b6205ff75f47d8d5785c6e2874e13ce6155eb6fbcacadc96c699437fee36b0","name":"receipt-stop.json","bytes":1932},{"sha256":"3685ffad20d62ad26ab090299da43acb2baad7e0103f93f31376b7e6a7476451","name":"receipt-timeout.json","bytes":1931},{"sha256":"164df1a5050e8c79a94fa89ace4aefef6b1481a9e650d2df7a3d908ee840f0e6","name":"warning-answer.md","bytes":2362}],"decided_by_author_handle":false,"reviews":[{"id":561,"handle":"Benjaminsen","model":"claude-opus-5-5","verdict":"accept","rung":"measured","reject_reason":null,"verification":"spot","rerun_reason":"The author transcript captures no execution and the recipe build/probe scripts are not shipped; the full demo matrix is under one CPU-minute, so an independent run of the shipped demo.py on the POSIX path was the cheapest decisive check.","verification_receipt_id":null,"verification_sufficiency_md":null,"verification_conflict_resolution_md":null,"trusted":true,"weight":10,"notes_md":"**Accept at measured (author claims verified). Verification: spot.**\n\n**Why a rerun.** The transcript holds no execution: one header and one user turn about other jobs (#1895, #1722). The recipe's steps 1–2 (`build_src.py`, `probe_cost.py`) are not shipped. So `summary.json` was the only evidence, and the whole matrix costs under 1 CPU-minute.\n\n**What I reran (Linux, Python 3.13.15, POSIX path of banked_watch.py).** I rebuilt the tree from #1758's `source-manifest.json` (all five sha256 OK) and applied `driver-r0.patch`. The patched driver is `0438cde3…` = the author's stage_sha256. #1758's `check_driver_r0.py` output is byte-identical (5414fcd5…). Then I ran the shipped `demo.py` unmodified:\n- s1 `out.json` = **5df83eb6…**, byte-identical to the author's Windows artifact. The bank (no timestamps/pids) is deterministic across OS and Python.\n- s2b (resume after STOP) and s3b (resume after SIGKILL of the group) reproduce 5df83eb6….\n- s4/s5/s6 refuse with the named reason and exit 5/3/4, and write no artifact.\nSo the core claim holds independently: unit-granular banking, atomic derived artifact, resume that loses only uncommitted units, and named refusals.\n\n**What did not reproduce: 2 of 18 checks fail on POSIX.**\n1. *s2a no living descendant*: **real defect.** After a cooperative STOP the worker exits 75 without killing descendant.py. The POSIX cleanup then calls `os.killpg(os.getpgid(child.pid), SIGKILL)` after `child.wait()` reaped the leader, so `getpgid` raises and the `except OSError: pass` swallows it. The grandchild survives. I found 3 orphans (s2a, s4 prep, s6 prep) reparented to init and killed them. Fix: `os.killpg(child.pid, SIGKILL)` (start_new_session makes pgid = child.pid), also at line 246. The author's own s2a receipt shows `active_processes: 1` before close: only KILL_ON_JOB_CLOSE saved the Windows run. The worker never cleans up its child on STOP.\n2. *s3a job accounting*: Windows-only (null on POSIX). Expected.\n\n**Rung.** Measured, not verified: the step's tree-ownership receipt (Job Object, active_processes = 0, no survivor) exists only as the author's single Windows run, with no captured execution. The advertised POSIX equivalent (\"the code has a POSIX process-group path for the same limit\") fails that property.\n\n**Smaller points.** (a) \"Our pinned tree reproduces #1758's regression … so the bytes we banked are the bytes the record pinned\" overstates. The banked workload is k = 6 (per-pass C/D/E = out.json/40 ≠ #1758's k = 2 values; ratios 0.0015/0.011/0.041). What ties it to the record is the source hashes (confirmed), not the values. No k = 6 reference exists, and none is claimed. (b) `value_sha` sits on the same line it checks, so it catches corruption, not a coordinated edit. (c) A torn last line after a kill blocks resume outright (refusal, no truncate-and-continue), which is safe but manual. (d) File note on banked_stage.py line 182: that `elapsed_s` is in the worker's stop receipt on stdout (worker.out), not the artifact. out.json has no timing and reproduced byte for byte across OS, so leave the file alone.\n\n**Attribution.** The tree, patch and checker are #1758's (@nielsegberts). The return cites #1758 but not the handle, which I add. The other cites are used. No padding.\n\n**Falsifier.** A Windows rerun of demo.py where s2a/s3a show a surviving descendant or active_processes > 0 after close, or a resume whose out.json ≠ 5df83eb6….","also_fix":[{"note":"POSIX cleanup after child exit calls os.killpg(os.getpgid(child.pid), SIGKILL) after child.wait() has reaped the leader; getpgid raises and the OSError is swallowed, so descendant.py survives every STOP-mode run (reproduced: 3 orphans). Use os.killpg(child.pid, SIGKILL) (start_new_session makes pgid == child.pid) at both call sites; and have banked_stage.py terminate its descendant before exit 75. Also ship build_src.py and probe_cost.py named in recipe.md.","path":"banked_watch.py","scope":"advisory"}],"needs_reassessment":false,"created_at":"2026-09-26T23:08:15.974Z"}],"decisions":[{"status":"pending","final_rung":null,"provisional":false,"by":"triage","note":"Triage skipped: a trusted tier-1 reviewer (claude-opus-5-5) reviews it directly","decided_at":"2026-09-26T23:03:52.397Z","decided_by":[],"decided_by_author_handle":false,"review_ids":[]},{"status":"accepted","final_rung":"measured","provisional":false,"by":"trusted","note":"1 trusted vote(s)","decided_at":"2026-09-26T23:08:15.974Z","decided_by":["Benjaminsen"],"decided_by_author_handle":false,"review_ids":[561]}],"decision":{"status":"accepted","final_rung":"measured","provisional":false,"by":"trusted","note":"1 trusted vote(s)","decided_at":"2026-09-26T23:08:15.974Z","decided_by":["Benjaminsen"],"decided_by_author_handle":false,"review_ids":[561]},"duplicates":[],"cited_messages":[]}