From aeab166edbb9984c029f5d0946526da481878d23 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Sat, 10 Oct 2026 03:25:24 -0500 Subject: [PATCH] docs(queue-52): darkwing round 1 review, approve Co-Authored-By: Claude Opus 5.5 --- .../r1/candidate-manifest.sha256 | 6 + .../darkwing/work/queue-52-review/r1/gate.sh | 25 ++ .../work/queue-52-review/r1/model/second.diff | 11 + .../work/queue-52-review/r1/model/second.txt | 44 ++++ .../queue-52-review/r1/model/working.diff | 11 + .../work/queue-52-review/r1/model/working.txt | 46 ++++ .../r1/mut/base-conversation.txt | 190 +++++++++++++++ .../r1/mut/base-shims-left.txt | 1 + .../r1/mut/bindadvance-conversation.txt | 190 +++++++++++++++ .../r1/mut/bindadvance-shims-left.txt | 1 + .../r1/mut/bindboth-conversation.txt | 230 ++++++++++++++++++ .../r1/mut/bindboth-shims-left.txt | 1 + .../r1/mut/emptyguard-conversation.txt | 190 +++++++++++++++ .../r1/mut/emptyguard-shims-left.txt | 1 + .../queue-52-review/r1/mut/manifest-after.txt | 6 + .../work/queue-52-review/r1/mut/mutate.py | 40 +++ .../r1/mut/noadvance-conversation.txt | 190 +++++++++++++++ .../r1/mut/noadvance-shims-left.txt | 1 + .../r1/mut/noboot-conversation.txt | 190 +++++++++++++++ .../r1/mut/noboot-shims-left.txt | 1 + .../r1/mut/noinv-conversation.txt | 190 +++++++++++++++ .../r1/mut/noinv-shims-left.txt | 1 + .../r1/mut/nomembers-conversation.txt | 190 +++++++++++++++ .../r1/mut/nomembers-shims-left.txt | 1 + .../r1/mut/nopidcmp-conversation.txt | 216 ++++++++++++++++ .../r1/mut/nopidcmp-shims-left.txt | 1 + .../r1/mut/nopopulated-conversation.txt | 190 +++++++++++++++ .../r1/mut/nopopulated-shims-left.txt | 1 + .../r1/mut/noscope-conversation.txt | 190 +++++++++++++++ .../r1/mut/noscope-shims-left.txt | 1 + .../r1/mut/noslotcheck-conversation.txt | 190 +++++++++++++++ .../r1/mut/noslotcheck-shims-left.txt | 1 + .../r1/mut/nostartcmp-conversation.txt | 216 ++++++++++++++++ .../r1/mut/nostartcmp-shims-left.txt | 1 + .../work/queue-52-review/r1/mut/run.sh | 22 ++ .../work/queue-52-review/r1/mut/summary.txt | 15 ++ .../queue-52-review/r1/out/chat01-check.txt | 26 ++ .../r1/out/node-control-board.txt | 132 ++++++++++ .../r1/out/node-conversation.txt | 190 +++++++++++++++ .../queue-52-review/r1/out/node-queue.txt | 158 ++++++++++++ .../queue-52-review/r1/out/node-webui.txt | 31 +++ .../work/queue-52-review/r1/out/summary.txt | 18 ++ .../work/queue-52-review/r1/out/test-auth.txt | 17 ++ .../queue-52-review/r1/out/test-conductor.txt | 55 +++++ .../queue-52-review/r1/out/test-config.txt | 26 ++ .../queue-52-review/r1/out/test-discord.txt | 70 ++++++ .../r1/out/test-extension-package.txt | 21 ++ .../r1/out/test-foundation.txt | 53 ++++ .../queue-52-review/r1/out/test-queue.txt | 35 +++ .../r1/out/test-release-docker.txt | 16 ++ .../queue-52-review/r1/out/test-release.txt | 7 + .../work/queue-52-review/r1/out/test-task.txt | 33 +++ .../work/queue-52-review/review-r1.md | 200 +++++++++++++++ 53 files changed, 3889 insertions(+) create mode 100644 agents/darkwing/work/queue-52-review/r1/candidate-manifest.sha256 create mode 100755 agents/darkwing/work/queue-52-review/r1/gate.sh create mode 100644 agents/darkwing/work/queue-52-review/r1/model/second.diff create mode 100644 agents/darkwing/work/queue-52-review/r1/model/second.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/model/working.diff create mode 100644 agents/darkwing/work/queue-52-review/r1/model/working.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/base-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/base-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/bindadvance-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/bindadvance-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/bindboth-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/bindboth-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/emptyguard-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/emptyguard-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/manifest-after.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/mutate.py create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/noadvance-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/noadvance-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/noboot-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/noboot-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/noinv-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/noinv-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/nomembers-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/nomembers-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/nopidcmp-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/nopidcmp-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/nopopulated-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/nopopulated-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/noscope-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/noscope-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/noslotcheck-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/noslotcheck-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/nostartcmp-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/nostartcmp-shims-left.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/run.sh create mode 100644 agents/darkwing/work/queue-52-review/r1/mut/summary.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/chat01-check.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/node-control-board.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/node-conversation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/node-queue.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/node-webui.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/summary.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/test-auth.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/test-conductor.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/test-config.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/test-discord.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/test-extension-package.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/test-foundation.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/test-queue.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/test-release-docker.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/test-release.txt create mode 100644 agents/darkwing/work/queue-52-review/r1/out/test-task.txt create mode 100644 agents/darkwing/work/queue-52-review/review-r1.md diff --git a/agents/darkwing/work/queue-52-review/r1/candidate-manifest.sha256 b/agents/darkwing/work/queue-52-review/r1/candidate-manifest.sha256 new file mode 100644 index 00000000..79a4a085 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/candidate-manifest.sha256 @@ -0,0 +1,6 @@ +774224cf6a105ff80d3e71637bd84bf68cb2da447b3a4f0fec25e021b7401f46 agents/dewey/work/queue-52/evidence.md +35dff8a20c6f8afd1aa03fb237354bf6a4c34a796a11b9025acb20041c437d36 packages/conversation/README.md +4db71af0774022332808afc39ce37248305bf45e3a14811921fc589083a19289 packages/conversation/src/cohort.mjs +42a85b2ba2fc8f7137652df35ac61c8fc77bccd7697c8190129ffa8ba025d9fd packages/conversation/src/controller.mjs +b62421aec1f67ae293d2b5c2e7abda14ea945fb4e4a3abf0d1afeb9b61216eed packages/conversation/src/shim.mjs +1bcb0633698ac0f82b5626a1ed17b25724e393ea8fd61c956a0735721c397802 packages/conversation/tests/cohort.test.mjs diff --git a/agents/darkwing/work/queue-52-review/r1/gate.sh b/agents/darkwing/work/queue-52-review/r1/gate.sh new file mode 100755 index 00000000..43e779b5 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/gate.sh @@ -0,0 +1,25 @@ +#!/bin/bash +export TMPDIR=~/darkwing-scratch/r52a/tmp DOCKER_HOST=unix:///nonexistent.sock +cd ~/darkwing-scratch/r52a/wt +O=~/darkwing-scratch/r52a/out +: > $O/summary.txt +shims() { ps -eo pid,args | grep -F "$TMPDIR" | grep -F shim.mjs | grep -v grep | wc -l; } +units() { systemctl --user list-units --all 'mosaic-chat-*' --no-legend | wc -l; } +echo "start $(date -u +%FT%TZ) shims=$(shims) units=$(units)" >> $O/summary.txt +for p in conversation webui; do + node --test "packages/$p/tests/*.test.mjs" > $O/node-$p.txt 2>&1; e=$? + echo "node-$p exit=$e $(grep -E '^ℹ (pass|fail)' $O/node-$p.txt | tr '\n' ' ') shims-left=$(shims) units=$(units)" >> $O/summary.txt +done +for f in scripts/test-*.sh; do + s=$(basename $f .sh) + $f > $O/$s.txt 2>&1; e=$? + echo "$s exit=$e $(grep -E 'passed, [0-9]+ failed' $O/$s.txt | tail -1)" >> $O/summary.txt +done +echo "end $(date -u +%FT%TZ) shims-left=$(shims) units=$(units)" >> $O/summary.txt +echo DONE >> $O/summary.txt +for p in control-board queue; do + node --test "packages/$p/tests/*.test.mjs" > $O/node-$p.txt 2>&1; e=$? + echo "node-$p exit=$e $(grep -E '^ℹ (pass|fail)' $O/node-$p.txt | tr '\n' ' ')" >> $O/summary.txt +done +(node docs/plans/chat-01/check.mjs > $O/chat01-check.txt 2>&1; echo "chat01-check exit=$? $(tail -1 $O/chat01-check.txt)" >> $O/summary.txt) +echo DONE2 >> $O/summary.txt diff --git a/agents/darkwing/work/queue-52-review/r1/model/second.diff b/agents/darkwing/work/queue-52-review/r1/model/second.diff new file mode 100644 index 00000000..19d6efb0 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/model/second.diff @@ -0,0 +1,11 @@ +--- docs/plans/chat-01/check.mjs 2026-10-10 02:12:15.889001792 -0500 ++++ model/second/check.mjs 2026-10-10 03:08:54.562481270 -0500 +@@ -335,7 +335,7 @@ + // ends output, so an engine exit never supersedes a force stop, finished + // or not, nor a second engine exit. + const current = w.stops.find(s => s.id === w.binding.stop); +- if (ending(current?.mode)) return bad('stop-owned'); ++ if (current?.mode === 'force-stop') return bad('stop-owned'); + const outcome = startStop(w, { id: null, connection: null, target: targetOf(w) }, 'engine-exit'); + // Dispatched input has no engine left to report it: unknown, not failed. + // Working input was delivered; it keeps its state and no outcome is inferred. diff --git a/agents/darkwing/work/queue-52-review/r1/model/second.txt b/agents/darkwing/work/queue-52-review/r1/model/second.txt new file mode 100644 index 00000000..1c99d186 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/model/second.txt @@ -0,0 +1,44 @@ +Schema {"schemaCases": 100, "omissions": 322, "validator": "4.26.0", "failures": []} +Reference cases 76 pass +PASS sequence interrupt-reconcile-prompt +PASS sequence interrupt-confirmed-force-stop +PASS sequence controller-revoked-recovery-control-recover +PASS sequence takeover-old-controller-new-approval +PASS sequence observer-draft-upload-send +PASS sequence duplicate-native-decision +PASS sequence second-launch-active-uncertain-stopping +PASS sequence stop-lifecycle-queue-draft-links +PASS sequence confirmation-reconnect-reconfirm +PASS sequence corrupt-payload-control-and-cancel +PASS sequence revocation-nondestructive-reconciliation +PASS sequence admitted-disconnect-dispatch-receipt +PASS sequence retry-after-transfer-current-disposition +PASS sequence native-resolution-requires-evidence +PASS sequence confirmation-predecessor-and-supersession +PASS sequence different-actor-draft-privacy +PASS sequence empty-history-new-user-assistant-roles +node:internal/modules/run_main:107 + triggerUncaughtException( + ^ + +AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: ++ actual - expected + ++ 'engine-exit-fenced' +- 'refused:stop-owned' + + at file:///home/jwoltje/darkwing-scratch/r52a/model/second/check.mjs:671:10 + at sequence (file:///home/jwoltje/darkwing-scratch/r52a/model/second/check.mjs:388:31) + at file:///home/jwoltje/darkwing-scratch/r52a/model/second/check.mjs:660:1 + at ModuleJob.run (node:internal/modules/esm/module_job:569:25) + at async node:internal/modules/esm/loader:650:26 + at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'engine-exit-fenced', + expected: 'refused:stop-owned', + operator: 'strictEqual', + diff: 'simple' +} + +Node.js v26.8.1 diff --git a/agents/darkwing/work/queue-52-review/r1/model/working.diff b/agents/darkwing/work/queue-52-review/r1/model/working.diff new file mode 100644 index 00000000..1a10f1e3 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/model/working.diff @@ -0,0 +1,11 @@ +--- docs/plans/chat-01/check.mjs 2026-10-10 02:12:15.889001792 -0500 ++++ model/working/check.mjs 2026-10-10 03:08:54.562733718 -0500 +@@ -339,7 +339,7 @@ + const outcome = startStop(w, { id: null, connection: null, target: targetOf(w) }, 'engine-exit'); + // Dispatched input has no engine left to report it: unknown, not failed. + // Working input was delivered; it keeps its state and no outcome is inferred. +- const unknown = w.queue.filter(q => ['dispatched', 'acknowledged'].includes(q.state)); ++ const unknown = w.queue.filter(q => ['dispatched', 'acknowledged', 'working'].includes(q.state)); + for (const q of unknown) q.state = 'delivery-unknown'; + if (unknown.length) emit(w, 'queue-changed'); + return outcome; diff --git a/agents/darkwing/work/queue-52-review/r1/model/working.txt b/agents/darkwing/work/queue-52-review/r1/model/working.txt new file mode 100644 index 00000000..f05b84d4 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/model/working.txt @@ -0,0 +1,46 @@ +Schema {"schemaCases": 100, "omissions": 322, "validator": "4.26.0", "failures": []} +Reference cases 76 pass +PASS sequence interrupt-reconcile-prompt +PASS sequence interrupt-confirmed-force-stop +PASS sequence controller-revoked-recovery-control-recover +PASS sequence takeover-old-controller-new-approval +PASS sequence observer-draft-upload-send +PASS sequence duplicate-native-decision +PASS sequence second-launch-active-uncertain-stopping +PASS sequence stop-lifecycle-queue-draft-links +PASS sequence confirmation-reconnect-reconfirm +PASS sequence corrupt-payload-control-and-cancel +PASS sequence revocation-nondestructive-reconciliation +PASS sequence admitted-disconnect-dispatch-receipt +PASS sequence retry-after-transfer-current-disposition +PASS sequence native-resolution-requires-evidence +PASS sequence confirmation-predecessor-and-supersession +PASS sequence different-actor-draft-privacy +PASS sequence empty-history-new-user-assistant-roles +PASS sequence engine-exit-empty-cohort-stopped +PASS sequence engine-exit-live-unreadable-or-empty-cohort-uncertain +node:internal/modules/run_main:107 + triggerUncaughtException( + ^ + +AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: ++ actual - expected + ++ 'delivery-unknown' +- 'working' + + at file:///home/jwoltje/darkwing-scratch/r52a/model/working/check.mjs:698:53 + at sequence (file:///home/jwoltje/darkwing-scratch/r52a/model/working/check.mjs:388:31) + at file:///home/jwoltje/darkwing-scratch/r52a/model/working/check.mjs:693:1 + at ModuleJob.run (node:internal/modules/esm/module_job:569:25) + at async node:internal/modules/esm/loader:650:26 + at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'delivery-unknown', + expected: 'working', + operator: 'strictEqual', + diff: 'simple' +} + +Node.js v26.8.1 diff --git a/agents/darkwing/work/queue-52-review/r1/mut/base-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/base-conversation.txt new file mode 100644 index 00000000..657f82dc --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/base-conversation.txt @@ -0,0 +1,190 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (232.813861ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (36.380483ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (21.419677ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (550.313912ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (420.168522ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (277.899592ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (232.851425ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (221.510624ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.438717ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (13853.907746ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (44058.5945ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (322.225334ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (206.513206ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (773.855297ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (309.408854ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (362.245846ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (156.153447ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (208.209314ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (535.671773ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (1835.931653ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (429.913502ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (235.229088ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (93.896473ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.10379ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.044383ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.755566ms) +✔ no shim from this file's tests is left running for the after hook (25.332221ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1238.373496ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (514.173179ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (848.029213ms) +✔ K4: two engines; force stop one; the other survives by independent observation (3141.206419ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (876.937041ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (998.905385ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (844.97759ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5954.992107ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (1097.873649ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (877.142873ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (908.082163ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (1007.048567ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (743.67859ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (971.290956ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3383.787548ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (26.513706ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (384.023952ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (314.698284ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (86.984598ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (632.131664ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (678.946013ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1849.743838ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (657.274389ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2907.64551ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1940.355511ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (1024.558627ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2911.007005ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (441.155565ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (481.128068ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (133.908862ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (3468.955466ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (633.579698ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (868.875107ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (659.654781ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (3181.184197ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (327.023723ms) +✔ no shim from this file's tests is left running for the after hook (26.754331ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (225.910308ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (395.568904ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (230.145671ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (327.516982ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (228.16552ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.458ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (245.727109ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (333.75338ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (228.865393ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (237.636975ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (244.817821ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (224.040237ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.085165ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (232.426463ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (230.930534ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (264.331139ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (218.167662ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.494737ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.257218ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.332453ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.696021ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (31.335211ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.62314ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (4.941772ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.530727ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.380123ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.119828ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (238.331113ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (447.63826ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (332.477784ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (933.46825ms) +✔ H4: self-takeover is refused (218.09882ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (508.235365ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1139.471028ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (249.760243ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (861.037575ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (369.798394ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (206.644369ms) +✔ H13: a retry with the same request ID and different text is refused (217.72461ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (818.854075ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (381.970627ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (309.154497ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (1079.166046ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (418.109799ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (966.133975ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (258.518069ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (362.718374ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.679352ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (703.320801ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (798.577891ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (899.383725ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3216.888203ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (736.964693ms) +✔ no shim from this file's tests is left running for the after hook (24.9695ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.578413ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.922612ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.819544ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.656012ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.560996ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.939095ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.783071ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.357228ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.680882ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.588235ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.622739ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.747987ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (7.246066ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.744787ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (3.834994ms) +✔ F9: registrations never add or redirect a root (1.864455ms) +✔ F10: a header cwd naming another project is refused (4.175131ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.723797ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.180823ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.13367ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.636774ms) +✔ F13: compaction is a marker in place, then the retained content (0.778193ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (536.783665ms) +✔ fragments never cut a surrogate pair and keep an empty string (5.082053ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.59302ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.519492ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.119869ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.038875ms) +✔ every page and cursor is a valid CHAT-01 record (816.691278ms) +✔ the engine pin holds for the installed package (3.636252ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (298.731593ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (524.692362ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (280.979535ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (716.79434ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (515.730819ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (272.884122ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (20.894122ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (420.386704ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (219.874036ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (329.925194ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (531.185669ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1952.274552ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (218.098146ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (302.294977ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (206.764067ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (272.917198ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (591.533227ms) +✔ N10: fake conformance (32.112528ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (629.610838ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (310.802354ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (357.053072ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (458.681085ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (408.191906ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (393.224501ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (242.147072ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (534.94023ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (876.458948ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (671.336818ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (792.764183ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (324.628068ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (255.900386ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (228.072775ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (263.943412ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (382.129749ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 182 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 70617.999427 diff --git a/agents/darkwing/work/queue-52-review/r1/mut/base-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/base-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/base-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/bindadvance-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/bindadvance-conversation.txt new file mode 100644 index 00000000..0def5768 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/bindadvance-conversation.txt @@ -0,0 +1,190 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (290.513248ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (43.953229ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (22.976194ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (478.097168ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (465.016372ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (363.21621ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (274.714255ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (356.3799ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.925197ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (14350.673095ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (39201.220192ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (406.685798ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (191.778893ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (578.291249ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (334.125736ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (455.407699ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (157.980337ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (474.993254ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (585.013077ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (1215.414982ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (251.954782ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (122.773922ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (97.088816ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.224329ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.106905ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.796968ms) +✔ no shim from this file's tests is left running for the after hook (25.885957ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1037.719669ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (706.053438ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (1145.3882ms) +✔ K4: two engines; force stop one; the other survives by independent observation (3276.243126ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (852.472552ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (687.882447ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (751.678349ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5941.698591ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (946.218354ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (708.499325ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (586.959383ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (938.146711ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (530.392448ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (770.192857ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3498.15693ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (75.293536ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (780.465165ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (625.066749ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (84.895626ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (637.245042ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (581.575874ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1304.178178ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (468.221936ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2836.191814ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1669.876144ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (1080.002698ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2603.64442ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (611.935026ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (486.188706ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (160.13235ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2677.220658ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (518.150162ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (594.410398ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (572.008703ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2912.631139ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (363.463803ms) +✔ no shim from this file's tests is left running for the after hook (27.576822ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (258.837682ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (262.493255ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (266.725334ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (299.165227ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (233.36686ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.533913ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (374.525884ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (383.702031ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (407.146492ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (323.231537ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (330.37461ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (320.369803ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.677706ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (478.813308ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (332.277828ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (315.61516ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (227.300745ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.520014ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.296953ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.37304ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.517371ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.442661ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.739943ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.94891ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.533914ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.417365ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.131403ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (280.686094ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (325.065145ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (353.045008ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (1149.205565ms) +✔ H4: self-takeover is refused (397.177379ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (694.88751ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1624.527339ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (205.200489ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (891.47915ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (396.083436ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (245.316545ms) +✔ H13: a retry with the same request ID and different text is refused (502.234015ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (715.773191ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (351.814679ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (336.892538ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (1358.320239ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (386.087242ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (948.421558ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (213.038129ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (486.352139ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.659424ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (800.275322ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (863.887625ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (949.740223ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3043.831336ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (732.768037ms) +✔ no shim from this file's tests is left running for the after hook (29.708328ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (8.810958ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (2.566893ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (2.301198ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (3.203977ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.884574ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.666597ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (1.22323ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.539167ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (4.193886ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (6.512307ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (7.445314ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (6.248096ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (9.161325ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (13.008979ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (3.000005ms) +✔ F9: registrations never add or redirect a root (1.931944ms) +✔ F10: a header cwd naming another project is refused (6.598104ms) +✔ F11: parentSession renders with a marker and the parent is never opened (1.246609ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (7.799364ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (3.67721ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (3.157613ms) +✔ F13: compaction is a marker in place, then the retained content (1.382728ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (703.962005ms) +✔ fragments never cut a surrogate pair and keep an empty string (7.98342ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.983519ms) +✔ unknown conversations, empty files and non-Pi files refuse (3.173453ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.29687ms) +✔ a seat directory without search permission refuses that root, not the catalogue (3.186006ms) +✔ every page and cursor is a valid CHAT-01 record (1066.882033ms) +✔ the engine pin holds for the installed package (2.916563ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (382.141977ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (673.954204ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (328.817764ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (625.387371ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (501.31889ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (341.878571ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.038024ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (536.150226ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (362.696775ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (440.634714ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (865.524734ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (2024.472979ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (224.775691ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (338.906809ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (247.465631ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (555.791824ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (494.45879ms) +✔ N10: fake conformance (31.788414ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (518.917142ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (474.982765ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (378.239448ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (652.868516ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (414.093289ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (428.744628ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (222.956544ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (453.28746ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (1047.779655ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (1051.203199ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (808.895119ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (170.374157ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (221.3496ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (177.980946ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (224.454633ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (221.13787ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 182 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 65072.462742 diff --git a/agents/darkwing/work/queue-52-review/r1/mut/bindadvance-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/bindadvance-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/bindadvance-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/bindboth-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/bindboth-conversation.txt new file mode 100644 index 00000000..e222e2e4 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/bindboth-conversation.txt @@ -0,0 +1,230 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (196.170749ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (30.037091ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (17.489619ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (415.680048ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (395.677434ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (248.870551ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (195.209883ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (193.671305ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.610788ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (11961.670711ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (36086.213554ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (358.145099ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (205.029958ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (779.221551ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (373.261653ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (356.192698ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (113.828329ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (198.417562ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (285.094616ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (759.291436ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (186.224763ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (95.622507ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (70.581245ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.096237ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.384139ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.812638ms) +✔ no shim from this file's tests is left running for the after hook (25.372382ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1062.686968ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (585.062191ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (816.415513ms) +✔ K4: two engines; force stop one; the other survives by independent observation (3053.072615ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (537.064247ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (623.976244ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (531.65547ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5498.82166ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (818.000449ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (680.567149ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (889.291656ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (856.128537ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (617.24239ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (581.596089ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3398.922878ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (35.241ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (366.49244ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (323.474757ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (82.690272ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (416.811381ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (532.953706ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1506.766822ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (718.508608ms) +✖ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (4403.382344ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1238.803266ms) +✖ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (2847.749701ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2716.465641ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (596.27959ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (469.451931ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (153.539136ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2799.632468ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (510.030803ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (504.884658ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (403.429078ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2623.015231ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (287.659276ms) +✔ no shim from this file's tests is left running for the after hook (25.468541ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (189.123854ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (188.774509ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (255.723413ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (262.684843ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (192.1084ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.758751ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (194.632943ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (297.73068ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (212.96319ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (186.607387ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (214.778313ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (203.710893ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.966601ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (208.752801ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (226.637443ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (251.977283ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (342.602016ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.415187ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.251043ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.294817ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.508606ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.99466ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.416965ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.71769ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.383601ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.343733ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.093667ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (218.061991ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (234.931687ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (272.153504ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (848.635915ms) +✔ H4: self-takeover is refused (191.003911ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (432.660663ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1030.784374ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (370.473999ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (659.16206ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (298.356323ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (275.523763ms) +✔ H13: a retry with the same request ID and different text is refused (318.489117ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (783.134346ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (299.590057ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (202.66608ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (883.912644ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (371.756546ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (799.148254ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (199.826503ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (341.865197ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.630474ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (668.798099ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (564.529756ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (723.74984ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2941.291295ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (819.69928ms) +✔ no shim from this file's tests is left running for the after hook (25.974977ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.089486ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.602548ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.70469ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.319393ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.508277ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.913677ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.941354ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.285145ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.346763ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.516553ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (5.137631ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.412666ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.204287ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.4954ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (2.232374ms) +✔ F9: registrations never add or redirect a root (2.548698ms) +✔ F10: a header cwd naming another project is refused (5.062692ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.856699ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.256447ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.105944ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.374182ms) +✔ F13: compaction is a marker in place, then the retained content (0.774293ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (510.301149ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.466787ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.540088ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.178609ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (0.981092ms) +✔ a seat directory without search permission refuses that root, not the catalogue (14.82873ms) +✔ every page and cursor is a valid CHAT-01 record (788.820214ms) +✔ the engine pin holds for the installed package (1.762582ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (263.128546ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (515.185218ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (276.189237ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (453.265573ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (477.427287ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (230.856866ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (19.825036ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (350.117588ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (195.503297ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (290.867771ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (466.100954ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1840.897538ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (205.706589ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (455.93846ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (344.595501ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (272.07845ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (419.263938ms) +✔ N10: fake conformance (32.804393ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (442.566968ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (282.988712ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (297.703663ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (385.316727ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (390.364465ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (354.284159ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (197.025692ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (368.752939ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (726.527317ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (528.183046ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (510.934154ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (257.252812ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (195.435834ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (196.631154ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (222.24386ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (203.753251ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 180 +ℹ fail 2 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 57474.77352 + +✖ failing tests: + +test at packages/conversation/tests/cohort.test.mjs:906:1 +✖ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (4403.382344ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + actual - expected + + + 'stopping' + - 'uncertain' + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r52a/wt2/packages/conversation/tests/cohort.test.mjs:914:12) + at async Test.run (node:internal/test_runner/test:1409:7) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'stopping', + expected: 'uncertain', + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/conversation/tests/cohort.test.mjs:978:1 +✖ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (2847.749701ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + actual - expected + + + 'stopping' + - 'uncertain' + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r52a/wt2/packages/conversation/tests/cohort.test.mjs:986:12) + at async Test.run (node:internal/test_runner/test:1409:7) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'stopping', + expected: 'uncertain', + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-52-review/r1/mut/bindboth-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/bindboth-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/bindboth-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/emptyguard-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/emptyguard-conversation.txt new file mode 100644 index 00000000..a44433ca --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/emptyguard-conversation.txt @@ -0,0 +1,190 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (487.874836ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (36.293615ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (47.309217ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (644.117449ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (422.89616ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (254.476232ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (210.911329ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (224.691584ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (5.395174ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12226.705971ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (37559.470864ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (271.123577ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (172.036319ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (479.569451ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (296.025679ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (385.730506ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (104.099589ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (213.208514ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (371.667511ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (733.895364ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (191.851581ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (91.144594ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (72.209635ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.432142ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.053942ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.764457ms) +✔ no shim from this file's tests is left running for the after hook (25.61828ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1482.626777ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (620.049821ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (640.765209ms) +✔ K4: two engines; force stop one; the other survives by independent observation (3226.475032ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (633.500698ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (853.440363ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (549.01959ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5267.031869ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (808.909726ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (714.86821ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (471.844083ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (724.681297ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (483.180735ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (663.277796ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3313.103551ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (27.045452ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (826.620741ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (539.622487ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (285.871879ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (700.597742ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (801.603018ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1232.858857ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (702.466226ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2577.636482ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1168.499929ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (1124.022147ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2669.754831ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (441.193439ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (476.805605ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (151.345339ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (3104.645254ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (634.182673ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (521.257011ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (427.474874ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2648.109813ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (338.55868ms) +✔ no shim from this file's tests is left running for the after hook (25.279882ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (573.847537ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (434.007136ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (285.80762ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (324.393715ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (205.620756ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.60261ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (202.69126ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (313.477478ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (237.223769ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (230.400162ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (261.429394ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (284.107744ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.157ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (293.615427ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (280.251694ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (247.819315ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (211.511481ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.434464ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.248627ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.307125ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.493785ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.060822ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.454379ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.720999ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.37987ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.316197ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.096144ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (232.435806ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (601.81088ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (541.651232ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (866.911696ms) +✔ H4: self-takeover is refused (215.5574ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (494.300176ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1328.026689ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (236.53051ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (742.20742ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (294.439083ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (207.10811ms) +✔ H13: a retry with the same request ID and different text is refused (203.404996ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (639.707919ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (314.714461ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (265.551144ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (913.577305ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (354.642229ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (765.350971ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (200.703895ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (334.806368ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.599732ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (683.794293ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (578.990349ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (744.544682ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3040.306019ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (638.75862ms) +✔ no shim from this file's tests is left running for the after hook (29.988321ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.747896ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.930519ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.9916ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.721901ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.887168ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.328781ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.907895ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.34333ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.726085ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.653865ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (5.699918ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (5.224358ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (7.413277ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.708254ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.865261ms) +✔ F9: registrations never add or redirect a root (1.788112ms) +✔ F10: a header cwd naming another project is refused (4.143645ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.791899ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.493869ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.197848ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.529379ms) +✔ F13: compaction is a marker in place, then the retained content (0.781684ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (586.693002ms) +✔ fragments never cut a surrogate pair and keep an empty string (5.047911ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.71051ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.784622ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.195496ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.195588ms) +✔ every page and cursor is a valid CHAT-01 record (832.666985ms) +✔ the engine pin holds for the installed package (2.316933ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (291.370929ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (592.078319ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (339.143722ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (1104.903907ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (550.352111ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (246.253742ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (20.056724ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (378.683086ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (225.621647ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (316.471443ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (654.580932ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1904.91005ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (169.16267ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (300.850979ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (194.434217ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (247.60102ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (490.33698ms) +✔ N10: fake conformance (32.929102ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (519.241894ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (295.830916ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (298.621603ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (368.854747ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (366.147363ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (363.562036ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (191.079774ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (354.438927ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (706.385934ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (489.067429ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (491.993768ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (254.65858ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (177.816107ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (178.274142ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (236.784899ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (215.980751ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 182 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 59053.389276 diff --git a/agents/darkwing/work/queue-52-review/r1/mut/emptyguard-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/emptyguard-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/emptyguard-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/manifest-after.txt b/agents/darkwing/work/queue-52-review/r1/mut/manifest-after.txt new file mode 100644 index 00000000..c422fb0e --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/manifest-after.txt @@ -0,0 +1,6 @@ +agents/dewey/work/queue-52/evidence.md: OK +packages/conversation/README.md: OK +packages/conversation/src/cohort.mjs: OK +packages/conversation/src/controller.mjs: OK +packages/conversation/src/shim.mjs: OK +packages/conversation/tests/cohort.test.mjs: OK diff --git a/agents/darkwing/work/queue-52-review/r1/mut/mutate.py b/agents/darkwing/work/queue-52-review/r1/mut/mutate.py new file mode 100644 index 00000000..91006750 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/mutate.py @@ -0,0 +1,40 @@ +# mutate.py : apply one named mutant (each edit exact text, must match once). Run from the tree root. +import sys +CT = "packages/conversation/src/controller.mjs" +CO = "packages/conversation/src/cohort.mjs" +GUARD = " if (exec !== this.exec || !b || !this.claim?.record.engine || this.escalating || ending(this.stops.get(b.stop)?.mode)) return undefined;\n" +BINDADV = " if (ending(stop.mode)) this.b.state = state === \"uncertain\" ? \"uncertain\" : \"stopping\";\n" +ENDUNC = " if (stop.state !== \"superseded\") this.#advanceStop(stop, \"uncertain\");\n this.b.state = \"uncertain\";\n" +HEAD = "export async function engineExitCohort({ kind, unitName, invocationId, shimSocket, pid, start, settleMs = 2000 }) {\n if (kind !== \"scope\") return { outcome: \"unavailable\", reason: `a ${kind} cohort can't be enumerated completely` };\n const show = systemctlShow(unitName);\n" +INV = " if (!show || !invocationId || show.invocationId !== invocationId) {\n" +IDENT = " if (exit.pid !== pid || !Number.isInteger(exit.startTicks) || exit.startTicks < 1 || String(exit.startTicks) !== String(start) || exit.boot !== hello.boot) {\n" +M = { + "base": [], + # Dewey's five survivors, rewritten here from the packet's descriptions. + "noslotcheck": [(CT, GUARD, GUARD.replace("this.escalating || ", ""))], + "bindadvance": [(CT, BINDADV, BINDADV.replace("ending(stop.mode)", "stop.mode === \"force-stop\""))], + "emptyguard": [(CT, " if (s.mode === \"engine-exit\" && p.proof.members.length === 0) return false;\n", "")], + "nopopulated": [(CO, " if (e.populated === 0) {\n", " if (true) {\n")], + "nomembers": [(CO, " if (listed.members.length === 0) {\n", " if (true) {\n")], + # Mine. bindadvance plus #endStopUncertain not setting the binding: does + # any test see the binding follow an engine-exit stop to `uncertain`? + "bindboth": [(CT, BINDADV, BINDADV.replace("ending(stop.mode)", "stop.mode === \"force-stop\"")), (CT, ENDUNC, ENDUNC.replace(" this.b.state = \"uncertain\";\n", ""))], + # The engine-exit observation without the invocation ID check. + "noinv": [(CO, HEAD + INV, HEAD + " if (!show) {\n")], + # Without the hello's scope check. + "noscope": [(CO, " if (hello.invocationId !== invocationId || hello.scope !== show.controlGroup) return", " if (hello.invocationId !== invocationId) return")], + # Each half of the identity check alone, and the boot comparison. + "nopidcmp": [(CO, IDENT, IDENT.replace("exit.pid !== pid || ", ""))], + "nostartcmp": [(CO, IDENT, IDENT.replace(" || String(exit.startTicks) !== String(start)", ""))], + "noboot": [(CO, IDENT, IDENT.replace(" || exit.boot !== hello.boot", ""))], + # The engine-exit stop never moves from `fenced` to `stopping`. + "noadvance": [(CT, " this.#advanceStop(stop, \"stopping\");\n if (result.outcome !== \"proven\") return await fail(", " if (result.outcome !== \"proven\") return await fail(")], +} +if "--files" in sys.argv: + print(" ".join(sorted({f for f, _, _ in M[sys.argv[1]]}))); sys.exit(0) +for f, old, new in M[sys.argv[1]]: + s = open(f).read() + n = s.count(old) + if n != 1: sys.exit(f"{sys.argv[1]}: {n} matches in {f}") + open(f, "w").write(s.replace(old, new)) + print(f) diff --git a/agents/darkwing/work/queue-52-review/r1/mut/noadvance-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/noadvance-conversation.txt new file mode 100644 index 00000000..e216dbf4 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/noadvance-conversation.txt @@ -0,0 +1,190 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (202.745609ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (28.445371ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (21.018543ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (406.544455ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (386.204793ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (237.321226ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (193.903399ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (183.103068ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.825177ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12134.828332ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (37096.601255ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (246.006381ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (148.639254ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (678.59695ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (271.104863ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (348.041744ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (115.722338ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (200.224934ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (275.261944ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (731.525736ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (177.514233ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (87.196047ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (71.13828ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.322355ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.117682ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.766069ms) +✔ no shim from this file's tests is left running for the after hook (25.104588ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (987.113438ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (442.205563ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (786.114544ms) +✔ K4: two engines; force stop one; the other survives by independent observation (3016.379261ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (697.53255ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (929.708799ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (770.937421ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5519.344055ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (930.856317ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (702.259672ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (634.420676ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (735.273075ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (535.262631ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (486.430215ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3312.324759ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (26.299116ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (357.506951ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (297.58545ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (61.675532ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (632.350349ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (683.622219ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1635.242054ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (426.119184ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2830.740939ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1039.677157ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (1168.685018ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2565.363254ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (581.773847ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (492.890106ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (319.188391ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2610.44301ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (422.190919ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (642.360719ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (575.646908ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2728.790203ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (300.299656ms) +✔ no shim from this file's tests is left running for the after hook (27.580704ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (210.488428ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (193.87939ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (253.265247ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (257.29025ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (196.738899ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.484695ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (194.880985ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (296.103041ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (197.348236ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (202.752011ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (222.569381ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (244.595604ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.975419ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (221.046445ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (225.065378ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (246.706953ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (191.606467ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.44905ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.285968ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.311765ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.501121ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (31.110112ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.49833ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (4.723202ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.366828ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.33504ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.102692ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (219.189498ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (251.988971ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (348.841631ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (777.160998ms) +✔ H4: self-takeover is refused (190.774117ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (428.225519ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1122.174898ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (218.120034ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (507.563913ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (253.598973ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (128.144922ms) +✔ H13: a retry with the same request ID and different text is refused (194.989721ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (567.167341ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (290.213349ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (193.537852ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (957.581898ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (384.117605ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (865.878075ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (215.923602ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (410.740881ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.608254ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (676.154257ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (553.829975ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (671.881845ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3211.121274ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (676.601591ms) +✔ no shim from this file's tests is left running for the after hook (24.858944ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (5.885251ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.640912ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.788391ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.35937ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.446198ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.87338ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.820789ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.29414ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.359852ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (5.053661ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (5.962674ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.851412ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.615403ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.342461ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (2.022436ms) +✔ F9: registrations never add or redirect a root (2.589114ms) +✔ F10: a header cwd naming another project is refused (7.261783ms) +✔ F11: parentSession renders with a marker and the parent is never opened (1.127187ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.579431ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.056976ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.722498ms) +✔ F13: compaction is a marker in place, then the retained content (0.798852ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (509.019665ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.300197ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.484878ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.182445ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.014113ms) +✔ a seat directory without search permission refuses that root, not the catalogue (1.860972ms) +✔ every page and cursor is a valid CHAT-01 record (770.383116ms) +✔ the engine pin holds for the installed package (1.752395ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (281.697192ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (535.992065ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (272.46814ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (543.926425ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (402.012465ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (231.227225ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.87766ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (344.057315ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (186.851294ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (303.966245ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (536.273075ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1900.41057ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (194.227099ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (280.281345ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (149.15796ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (228.816042ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (385.645983ms) +✔ N10: fake conformance (31.824121ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (446.094636ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (366.994173ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (325.236771ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (411.788118ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (426.785759ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (390.33057ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (222.463535ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (361.38701ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (660.324778ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (503.513908ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (422.158566ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (206.971048ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (156.685004ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (197.148755ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (218.782713ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (194.681626ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 182 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 57405.803746 diff --git a/agents/darkwing/work/queue-52-review/r1/mut/noadvance-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/noadvance-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/noadvance-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/noboot-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/noboot-conversation.txt new file mode 100644 index 00000000..8d094827 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/noboot-conversation.txt @@ -0,0 +1,190 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (195.970749ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (25.067932ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (17.45155ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (407.806605ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (404.060015ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (242.444919ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (190.580574ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (192.793591ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.552208ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (11967.010724ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (38308.96985ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (257.605519ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (148.876047ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (701.978227ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (278.02487ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (354.549637ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (109.028088ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (198.60309ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (265.105109ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (755.645531ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (188.486031ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (92.38384ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (74.423786ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.141423ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.131391ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.812094ms) +✔ no shim from this file's tests is left running for the after hook (29.69979ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1025.395932ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (446.66764ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (783.995493ms) +✔ K4: two engines; force stop one; the other survives by independent observation (3015.970399ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (707.602279ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (800.671357ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (719.413082ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5604.556463ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (738.08681ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (616.02466ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (608.824908ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (591.155245ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (316.987225ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (473.77385ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3250.474727ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (42.231723ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (500.435969ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (291.21159ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (234.742193ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (555.971712ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (526.38748ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1166.140755ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (536.110445ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2678.064952ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (2116.338496ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (930.141396ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2607.378711ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (386.431343ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (467.276882ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (373.1395ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2908.4071ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (890.103287ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (785.490304ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (836.239038ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2672.42922ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (495.962271ms) +✔ no shim from this file's tests is left running for the after hook (25.110956ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (193.830912ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (192.441283ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (255.057761ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (264.000779ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (193.441553ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.461321ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (190.349263ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (293.093196ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (214.199486ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (184.713672ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (205.455273ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (208.038692ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.055783ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (207.527883ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (218.263384ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (241.860398ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (249.190794ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.398289ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.258933ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.313463ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.475973ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (29.713536ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.381898ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.668713ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.341615ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.330845ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.0975ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (221.425979ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (247.074772ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (348.652368ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (778.714598ms) +✔ H4: self-takeover is refused (188.524723ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (437.118038ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1029.664894ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (286.603951ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (795.120416ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (394.193934ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (220.993553ms) +✔ H13: a retry with the same request ID and different text is refused (191.432646ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (629.171904ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (287.371844ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (206.034013ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (905.408227ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (354.996965ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (749.255858ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (210.47991ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (325.492338ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.671176ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (662.216782ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (543.890307ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (671.42773ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2975.546571ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (599.091078ms) +✔ no shim from this file's tests is left running for the after hook (25.229093ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.42245ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.585655ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.618297ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.527252ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.379222ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.887705ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.74047ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.208791ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.224432ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.821791ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (6.232636ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.395452ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.483293ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (11.609706ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (3.218775ms) +✔ F9: registrations never add or redirect a root (2.557461ms) +✔ F10: a header cwd naming another project is refused (4.572432ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.704752ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (3.810319ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.905388ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.236779ms) +✔ F13: compaction is a marker in place, then the retained content (0.698595ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (521.558819ms) +✔ fragments never cut a surrogate pair and keep an empty string (5.037513ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.540848ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.534895ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.15797ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.182159ms) +✔ every page and cursor is a valid CHAT-01 record (787.836945ms) +✔ the engine pin holds for the installed package (1.754866ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (274.270131ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (543.992493ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (261.099688ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (535.231236ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (394.610312ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (231.780354ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (20.90624ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (339.446883ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (194.707232ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (297.782374ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (481.829225ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1918.771705ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (211.792435ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (331.298053ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (189.239647ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (248.084799ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (405.226481ms) +✔ N10: fake conformance (33.086642ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (420.258206ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (289.297848ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (317.014818ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (347.783992ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (366.81375ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (351.264791ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (197.156902ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (363.359629ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (639.571863ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (464.029859ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (405.628673ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (184.225923ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (177.618179ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (137.178834ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (172.873412ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (115.752491ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 182 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 58749.590622 diff --git a/agents/darkwing/work/queue-52-review/r1/mut/noboot-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/noboot-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/noboot-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/noinv-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/noinv-conversation.txt new file mode 100644 index 00000000..7fd53fdf --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/noinv-conversation.txt @@ -0,0 +1,190 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (205.100684ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (32.443494ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (20.625988ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (347.422106ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (455.558888ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (231.206176ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (187.599289ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (190.361539ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.497051ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (11808.512198ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (37234.669944ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (259.354ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (142.897417ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (640.762057ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (284.01395ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (340.126742ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (105.934529ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (189.147216ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (269.099446ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (790.765821ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (194.666604ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (91.799676ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (78.010558ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.407373ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.058736ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.730549ms) +✔ no shim from this file's tests is left running for the after hook (25.591ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1142.818808ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (426.634998ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (577.397773ms) +✔ K4: two engines; force stop one; the other survives by independent observation (3038.594483ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (545.450454ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (869.970089ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (544.6629ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5268.978171ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (775.502613ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (751.326615ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (770.793332ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (690.561219ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (428.650174ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (506.24752ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3361.587211ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (28.467526ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (362.311277ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (301.648834ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (82.825888ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (420.715869ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (738.312166ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1208.951154ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (704.207906ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2978.725184ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1096.088105ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (1131.728723ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2590.204805ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (468.877369ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (700.995178ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (151.853423ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (3058.806313ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (476.996663ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (701.962209ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (842.824832ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2805.041299ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (303.536156ms) +✔ no shim from this file's tests is left running for the after hook (26.163535ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (198.710386ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (195.491287ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (184.87269ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (344.919128ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (182.177261ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.43079ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (184.801122ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (289.210934ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (202.553368ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (190.747164ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (213.358942ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (207.318082ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.965056ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (215.586557ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (238.261228ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (274.688731ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (218.183289ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.388298ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.283906ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.308042ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.495873ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.778541ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.496533ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.720355ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.384067ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.322209ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.106419ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (226.386487ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (243.042967ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (279.808361ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (820.968064ms) +✔ H4: self-takeover is refused (184.679742ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (435.219281ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1085.193274ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (235.884964ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (677.083083ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (320.058791ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (203.246382ms) +✔ H13: a retry with the same request ID and different text is refused (215.061868ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (616.64458ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (291.753847ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (205.929943ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (1034.470569ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (357.366339ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (760.093715ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (332.780549ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (374.05598ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.63494ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (693.066755ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (559.839267ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (735.886906ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2952.671074ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (849.435284ms) +✔ no shim from this file's tests is left running for the after hook (27.280294ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (5.762453ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.56745ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.663008ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.415165ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.380573ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.839189ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.843785ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.251014ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.63245ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (5.124636ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (5.957687ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (5.053162ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (7.033273ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.348499ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.563247ms) +✔ F9: registrations never add or redirect a root (1.494525ms) +✔ F10: a header cwd naming another project is refused (3.621931ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.660114ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (3.790591ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.83218ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.277719ms) +✔ F13: compaction is a marker in place, then the retained content (0.691698ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (514.55472ms) +✔ fragments never cut a surrogate pair and keep an empty string (5.205078ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.662931ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.536551ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.173433ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.075037ms) +✔ every page and cursor is a valid CHAT-01 record (752.440167ms) +✔ the engine pin holds for the installed package (1.957107ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (260.838934ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (536.931019ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (242.243735ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (458.558201ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (497.531688ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (213.906412ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.780744ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (331.495827ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (192.636764ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (289.604552ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (476.712309ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1877.300406ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (210.018191ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (295.912136ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (195.828676ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (237.255778ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (376.068735ms) +✔ N10: fake conformance (32.758899ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (489.755558ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (372.150561ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (313.84609ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (374.699348ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (351.502262ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (364.249065ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (333.899946ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (372.516674ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (724.890471ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (544.384299ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (567.303149ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (213.265245ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (220.024959ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (194.361504ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (212.765111ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (204.926225ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 182 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 57392.844158 diff --git a/agents/darkwing/work/queue-52-review/r1/mut/noinv-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/noinv-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/noinv-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/nomembers-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/nomembers-conversation.txt new file mode 100644 index 00000000..b4c96a6b --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/nomembers-conversation.txt @@ -0,0 +1,190 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (210.406684ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (33.293698ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (18.827371ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (408.222281ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (374.15515ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (223.646873ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (188.791906ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (193.858267ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.576815ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12233.014342ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (35658.869267ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (262.897668ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (145.905652ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (725.433478ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (275.699594ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (348.307296ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (110.036428ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (196.689406ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (273.408213ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (823.699608ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (194.822848ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (90.360521ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (87.213828ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.485119ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.099602ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.776477ms) +✔ no shim from this file's tests is left running for the after hook (25.35681ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (603.647159ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (581.962651ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (820.959489ms) +✔ K4: two engines; force stop one; the other survives by independent observation (2823.081974ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (690.312012ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (780.377805ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (729.527964ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5640.266923ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (1092.300676ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (768.822103ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (597.376047ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (695.030978ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (486.505457ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (480.037198ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3316.339574ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (28.001374ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (466.982852ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (285.858346ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (92.513115ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (440.315801ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (611.441572ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1220.562723ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (406.734018ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2520.664795ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1341.554901ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (1059.110878ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2582.843125ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (476.994204ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (649.584263ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (152.042363ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2846.667852ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (470.726951ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (501.823884ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (540.089374ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2912.784965ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (311.246361ms) +✔ no shim from this file's tests is left running for the after hook (21.85192ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (212.354963ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (199.587922ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (248.054801ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (270.917947ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (184.085805ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.426865ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (182.431766ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (293.272165ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (206.958945ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (194.447808ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (213.835656ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (181.853627ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.930372ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (250.340909ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (267.713356ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (281.311824ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (212.207375ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.410516ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.261016ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.318071ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.498575ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (31.245696ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.487761ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.77362ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.364216ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.340024ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.096986ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (224.663977ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (251.021096ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (291.222149ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (845.257502ms) +✔ H4: self-takeover is refused (190.276259ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (446.559556ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1126.68503ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (244.261449ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (524.372802ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (247.473941ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (154.103224ms) +✔ H13: a retry with the same request ID and different text is refused (184.608988ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (587.856066ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (288.366123ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (194.562961ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (858.02698ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (363.57305ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (757.866845ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (248.311703ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (478.715948ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.67478ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (713.387174ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (565.627659ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (666.381887ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3061.178397ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (677.75233ms) +✔ no shim from this file's tests is left running for the after hook (28.290739ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.492816ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.74335ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.807878ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.395768ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.487782ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.945476ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.940272ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.343731ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.539987ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.73824ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (7.166447ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (7.544731ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (7.331421ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.384056ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.767286ms) +✔ F9: registrations never add or redirect a root (1.803166ms) +✔ F10: a header cwd naming another project is refused (4.06113ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.74276ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.234138ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.943667ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.396206ms) +✔ F13: compaction is a marker in place, then the retained content (0.785073ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (506.296953ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.979503ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.640856ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.411741ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.122496ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.165723ms) +✔ every page and cursor is a valid CHAT-01 record (759.246519ms) +✔ the engine pin holds for the installed package (1.904063ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (261.528703ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (502.640726ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (258.491731ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (489.639274ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (476.952716ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (216.035087ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (20.865236ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (327.712992ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (201.480946ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (295.403625ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (463.979926ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1935.191182ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (185.455585ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (275.229003ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (193.396577ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (233.810249ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (351.205916ms) +✔ N10: fake conformance (32.986384ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (426.310167ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (278.715304ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (302.252084ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (380.355092ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (343.852305ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (402.024776ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (306.666046ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (464.946914ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (632.007832ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (493.06126ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (475.214707ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (237.95955ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (203.532546ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (237.692238ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (276.427004ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (216.553491ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 182 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 56474.610172 diff --git a/agents/darkwing/work/queue-52-review/r1/mut/nomembers-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/nomembers-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/nomembers-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/nopidcmp-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/nopidcmp-conversation.txt new file mode 100644 index 00000000..66c49952 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/nopidcmp-conversation.txt @@ -0,0 +1,216 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (198.891146ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (31.341098ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (17.536361ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (338.008114ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (382.400149ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (241.59916ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (193.155758ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (192.517258ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.893475ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12130.100407ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (37272.072739ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (258.305578ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (145.11324ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (595.647083ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (277.984683ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (350.3281ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (106.14199ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (193.811105ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (265.090122ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (761.012583ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (184.668023ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (93.612883ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (74.595114ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.156272ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.107967ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.844235ms) +✔ no shim from this file's tests is left running for the after hook (25.545581ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (972.48042ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (451.966293ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (753.102206ms) +✔ K4: two engines; force stop one; the other survives by independent observation (3073.928339ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (1017.899867ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (907.914759ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (724.446794ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5833.992574ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (929.567768ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (627.132891ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (517.701737ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (701.266887ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (337.624552ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (478.917104ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3227.528802ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (24.222242ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (397.905753ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (293.142488ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (83.71205ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (606.136653ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (567.956835ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1231.156406ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (610.856352ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2592.547198ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1363.059996ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (997.555751ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2629.476888ms) +✖ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (499.04135ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (469.088209ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (355.140795ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2883.605891ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (656.928613ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (479.530908ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (596.582393ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2751.046388ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (503.867617ms) +✔ no shim from this file's tests is left running for the after hook (25.385274ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (201.041166ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (185.309128ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (182.701746ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (254.63298ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (182.722555ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.461045ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (189.019792ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (297.45239ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (209.936062ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (193.112491ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (208.622929ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (201.514737ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.960342ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (208.577251ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (235.877471ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (253.783886ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (217.916111ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.53036ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.432062ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.335633ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.503356ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.231874ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.556494ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.80802ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.396729ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.337191ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.099019ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (240.636853ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (231.889589ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (267.293865ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (771.605461ms) +✔ H4: self-takeover is refused (185.04692ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (436.028016ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1084.373666ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (138.255928ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (517.321679ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (258.20719ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (192.569888ms) +✔ H13: a retry with the same request ID and different text is refused (196.211576ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (603.142155ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (325.103656ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (299.181ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (1154.702366ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (363.213358ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (775.446046ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (269.132526ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (352.301751ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.693698ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (704.379395ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (567.47106ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (687.842855ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3114.336315ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (622.182956ms) +✔ no shim from this file's tests is left running for the after hook (25.907248ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (10.15444ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (2.96479ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (3.231669ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (3.972987ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.872289ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.106122ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (1.102634ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.394208ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.444977ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.57197ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (5.375026ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.937818ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (7.83889ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.888313ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.676049ms) +✔ F9: registrations never add or redirect a root (1.636257ms) +✔ F10: a header cwd naming another project is refused (4.056152ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.76478ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.522654ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.236325ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.488526ms) +✔ F13: compaction is a marker in place, then the retained content (0.847372ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (495.006035ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.417213ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.350939ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.17748ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.113457ms) +✔ a seat directory without search permission refuses that root, not the catalogue (1.79152ms) +✔ every page and cursor is a valid CHAT-01 record (777.922618ms) +✔ the engine pin holds for the installed package (1.91497ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (265.948475ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (519.746435ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (271.000743ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (460.746988ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (395.406374ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (224.112722ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.809551ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (339.999918ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (188.781717ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (293.901858ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (469.082308ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1857.457011ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (201.770398ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (290.213988ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (195.721471ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (200.312719ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (443.090034ms) +✔ N10: fake conformance (31.984329ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (705.599071ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (330.906039ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (304.680019ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (380.069573ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (371.993376ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (359.934992ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (270.268499ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (323.450325ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (663.909058ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (512.067169ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (425.789138ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (195.682218ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (172.070924ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (144.028917ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (204.786258ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (205.313727ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 181 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 57550.119195 + +✖ failing tests: + +test at packages/conversation/tests/cohort.test.mjs:1037:1 +✖ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (499.04135ms) + AssertionError [ERR_ASSERTION]: {"pid":4045044} + + actual - expected + + [ + + 'proven', + + undefined + - 'unavailable', + - "the shim reaped a process that isn't the recorded engine" + ] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r52a/wt2/packages/conversation/tests/cohort.test.mjs:1048:14) + at process.processTicksAndRejections (node:internal/process/task_queues:104:5) + at async Test.run (node:internal/test_runner/test:1409:7) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: [ 'proven', undefined ], + expected: [ 'unavailable', "the shim reaped a process that isn't the recorded engine" ], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-52-review/r1/mut/nopidcmp-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/nopidcmp-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/nopidcmp-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/nopopulated-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/nopopulated-conversation.txt new file mode 100644 index 00000000..af44106c --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/nopopulated-conversation.txt @@ -0,0 +1,190 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (207.830893ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (33.040979ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (18.79846ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (570.221459ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (410.545264ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (242.134635ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (261.89141ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (231.991716ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.48363ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12836.817961ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (36626.123156ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (250.518325ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (152.596315ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (773.298122ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (292.700715ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (344.732708ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (109.231617ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (199.409836ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (293.270218ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (942.914398ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (299.766598ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (98.701163ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (78.346914ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.313846ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.095057ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.779466ms) +✔ no shim from this file's tests is left running for the after hook (25.910647ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (802.300926ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (456.071295ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (907.427072ms) +✔ K4: two engines; force stop one; the other survives by independent observation (3084.456196ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (800.806847ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (1091.800094ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (798.369598ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5536.05762ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (796.345554ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (679.370291ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (838.665261ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (737.402653ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (394.707338ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (551.063593ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3269.87109ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (36.58353ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (455.304498ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (497.522053ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (83.523256ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (645.672294ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (726.315469ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1237.355522ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (402.395912ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2715.746625ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1122.47332ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (1245.535925ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2580.699345ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (639.099805ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (457.991168ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (152.816271ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2650.709819ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (730.957787ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (592.576857ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (467.823818ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2593.07762ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (414.729701ms) +✔ no shim from this file's tests is left running for the after hook (24.899254ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (214.312818ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (192.432582ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (412.689703ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (301.380902ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (209.235448ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.443555ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (192.242568ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (366.109993ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (262.602485ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (215.797728ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (226.242023ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (223.715881ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.167876ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (211.966166ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (217.846242ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (252.467082ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (202.148546ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.419463ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.282557ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.329352ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.502742ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.934817ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.48446ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.732052ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.370155ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.336731ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.134409ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (225.969311ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (358.729229ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (404.74986ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (899.711298ms) +✔ H4: self-takeover is refused (253.481907ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (482.962555ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1048.781956ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (235.203795ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (845.161868ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (362.81136ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (203.430661ms) +✔ H13: a retry with the same request ID and different text is refused (209.237033ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (652.588271ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (309.403881ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (206.534848ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (1124.361798ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (361.38215ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (799.902535ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (206.981039ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (347.411033ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.702985ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (659.32326ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (567.179714ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (743.231552ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3105.631577ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (666.621984ms) +✔ no shim from this file's tests is left running for the after hook (25.398952ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (5.633021ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.587721ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.6623ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.217453ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.251366ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.848975ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.785412ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.265809ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.294786ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (3.966559ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.383345ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.533454ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.695317ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.911437ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.766653ms) +✔ F9: registrations never add or redirect a root (1.686269ms) +✔ F10: a header cwd naming another project is refused (4.23105ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.828431ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.192371ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.92171ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.407985ms) +✔ F13: compaction is a marker in place, then the retained content (0.743022ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (529.269621ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.396114ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.389198ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.188509ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.008283ms) +✔ a seat directory without search permission refuses that root, not the catalogue (1.786804ms) +✔ every page and cursor is a valid CHAT-01 record (731.751053ms) +✔ the engine pin holds for the installed package (1.6432ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (277.684421ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (563.417621ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (239.857632ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (604.64304ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (551.870724ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (230.254279ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.757993ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (428.086837ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (223.706001ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (347.847635ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (519.04331ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1899.792825ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (213.988864ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (296.213247ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (198.363447ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (253.971211ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (406.823261ms) +✔ N10: fake conformance (33.072972ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (424.095253ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (281.15089ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (530.644398ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (393.270422ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (372.869981ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (359.563707ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (213.4221ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (399.279823ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (751.464632ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (567.061528ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (513.152875ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (251.949348ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (184.582147ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (204.895109ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (290.355077ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (236.01909ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 182 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 59063.519065 diff --git a/agents/darkwing/work/queue-52-review/r1/mut/nopopulated-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/nopopulated-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/nopopulated-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/noscope-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/noscope-conversation.txt new file mode 100644 index 00000000..7920d867 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/noscope-conversation.txt @@ -0,0 +1,190 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (219.569986ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (32.816877ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (19.43028ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (360.12678ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (401.428363ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (248.548229ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (237.935165ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (215.32409ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.658737ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12108.599279ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (39107.07406ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (252.355908ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (138.102674ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (697.965904ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (283.418799ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (363.373383ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (116.943692ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (207.192245ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (284.631727ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (707.210717ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (183.267413ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (98.478811ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (76.339015ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.81599ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.220127ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.996437ms) +✔ no shim from this file's tests is left running for the after hook (27.811349ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (928.963151ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (476.628369ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (813.762389ms) +✔ K4: two engines; force stop one; the other survives by independent observation (2992.353979ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (700.988125ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (833.387208ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (717.296549ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5565.240905ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (1077.131916ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (799.209994ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (655.764465ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (653.536429ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (356.944356ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (476.99566ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3555.545061ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (27.732253ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (703.833415ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (417.431711ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (83.769167ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (702.053782ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (603.104794ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1519.187552ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (378.327253ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2703.741241ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1055.22558ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (969.263853ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2582.243955ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (358.181186ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (649.620897ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (150.743011ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2810.474753ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (762.304093ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (608.296979ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (658.596576ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2870.852757ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (314.440807ms) +✔ no shim from this file's tests is left running for the after hook (29.707409ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (217.894774ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (201.678856ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (205.181445ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (303.224554ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (193.846021ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.436969ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (221.648231ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (325.994727ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (216.212224ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (188.323197ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (207.920336ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (205.919299ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.896703ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (200.900243ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (220.749526ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (245.903221ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (201.005313ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.433787ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.255055ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.311095ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.478391ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.009169ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.465136ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.76644ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.410112ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.330767ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.104967ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (224.50345ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (260.79027ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (276.359364ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (860.908654ms) +✔ H4: self-takeover is refused (213.728657ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (447.130558ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1024.519393ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (214.20468ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (530.909569ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (255.252838ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (119.229255ms) +✔ H13: a retry with the same request ID and different text is refused (180.821939ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (659.145916ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (283.024924ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (203.662811ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (864.76426ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (352.908073ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (735.862289ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (277.529004ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (445.927515ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.662787ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (695.472361ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (581.972954ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (712.642289ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2990.246833ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (672.92516ms) +✔ no shim from this file's tests is left running for the after hook (28.770361ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (5.74194ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.630423ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.811014ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (3.603316ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.3197ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.741442ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.73169ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.114906ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (2.967324ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.049135ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.165068ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.771223ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (8.131907ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (9.287359ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.896737ms) +✔ F9: registrations never add or redirect a root (1.763115ms) +✔ F10: a header cwd naming another project is refused (4.071594ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.865948ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.54953ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.171396ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.786412ms) +✔ F13: compaction is a marker in place, then the retained content (0.832411ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (531.262384ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.696041ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.46806ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.295544ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.085463ms) +✔ a seat directory without search permission refuses that root, not the catalogue (1.955184ms) +✔ every page and cursor is a valid CHAT-01 record (755.502818ms) +✔ the engine pin holds for the installed package (1.65912ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (286.338149ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (523.809442ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (252.071373ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (477.587276ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (474.431529ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (228.489737ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.881601ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (408.685797ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (215.926116ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (295.667487ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (460.151696ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1891.086975ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (202.724074ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (339.790781ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (147.756044ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (204.232551ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (405.503747ms) +✔ N10: fake conformance (33.042439ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (452.551603ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (288.020304ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (283.561353ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (355.532893ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (348.281736ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (497.11827ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (272.668514ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (339.915627ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (808.923056ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (483.635137ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (422.421525ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (202.454209ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (183.762346ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (197.505772ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (211.882145ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (182.453412ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 182 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 59646.873064 diff --git a/agents/darkwing/work/queue-52-review/r1/mut/noscope-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/noscope-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/noscope-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/noslotcheck-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/noslotcheck-conversation.txt new file mode 100644 index 00000000..96a51c7c --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/noslotcheck-conversation.txt @@ -0,0 +1,190 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (961.908465ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (84.787135ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (67.362858ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (863.496058ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (418.556075ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (300.968316ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (234.279343ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (223.337651ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (3.839908ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (15851.020358ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (40333.882516ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (339.418855ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (259.725931ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (551.161762ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (297.821623ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (386.405463ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (205.824153ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (223.108324ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (314.507771ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (1002.790836ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (236.695534ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (107.6844ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (74.132077ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.299146ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.069041ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.999686ms) +✔ no shim from this file's tests is left running for the after hook (25.786989ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1946.750267ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (533.341566ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (899.730229ms) +✔ K4: two engines; force stop one; the other survives by independent observation (3298.225359ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (870.699274ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (874.702741ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (977.65043ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (6973.362671ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (1059.703915ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (815.08443ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (752.509829ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (992.962656ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (637.974959ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (681.618502ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3372.04269ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (51.125882ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (452.489866ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (454.774135ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (81.897527ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (672.568954ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (1076.078004ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1266.021637ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (475.052923ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2814.210356ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1130.567872ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (1171.308449ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2568.771336ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (409.758372ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (612.793997ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (130.842422ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2850.909426ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (785.42667ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (561.852518ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (366.559177ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2790.604995ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (409.461331ms) +✔ no shim from this file's tests is left running for the after hook (25.972309ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (1068.713455ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (794.111141ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (219.159404ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (341.526971ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (232.851266ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.571456ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (249.907105ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (331.170537ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (291.394683ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (236.898552ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (273.153764ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (247.698312ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.131602ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (341.11368ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (277.39901ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (270.697516ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (223.921481ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.409455ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.267931ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.327048ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.49137ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.778843ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.489015ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.679349ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.356126ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.35892ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.096402ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (228.956835ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (1185.943834ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (577.511775ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (951.513058ms) +✔ H4: self-takeover is refused (284.652969ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (547.717009ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1353.579808ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (243.370527ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (645.681502ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (293.043389ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (226.053849ms) +✔ H13: a retry with the same request ID and different text is refused (264.626782ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (796.858159ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (332.056892ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (203.478953ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (1340.330774ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (397.071684ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (2209.647883ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (275.993132ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (434.102151ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.982554ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (710.325955ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (668.672617ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (881.909473ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3722.574683ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (596.64366ms) +✔ no shim from this file's tests is left running for the after hook (25.367059ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (11.49996ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (3.097991ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (3.47768ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (4.805339ms) +✔ F1: an unreadable fork is never merged into another branch's history (2.215886ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (3.126475ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (1.068367ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.379659ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (10.301137ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (53.244308ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (20.146348ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.762079ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.817926ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.099047ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (2.093162ms) +✔ F9: registrations never add or redirect a root (2.439405ms) +✔ F10: a header cwd naming another project is refused (4.337316ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.73476ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (7.832493ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (3.227117ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (2.257977ms) +✔ F13: compaction is a marker in place, then the retained content (1.020679ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (715.776207ms) +✔ fragments never cut a surrogate pair and keep an empty string (6.155504ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (2.116713ms) +✔ unknown conversations, empty files and non-Pi files refuse (3.25378ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.302002ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.283337ms) +✔ every page and cursor is a valid CHAT-01 record (967.160456ms) +✔ the engine pin holds for the installed package (3.48913ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (374.596899ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (702.242049ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (343.00876ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (1956.809414ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (504.046619ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (289.288269ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (23.150593ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (413.512248ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (289.394298ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (339.648271ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (589.704189ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (2017.363718ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (226.39562ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (362.8377ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (332.738036ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (279.055304ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (426.054531ms) +✔ N10: fake conformance (31.607904ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (535.920141ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (584.701637ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (355.664822ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (409.85617ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (1673.690889ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (443.430645ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (318.346076ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (436.515459ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (859.215529ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (642.349279ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (754.632895ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (413.630087ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (616.940993ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (303.66275ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (351.089152ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (238.800162ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 182 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 68057.547411 diff --git a/agents/darkwing/work/queue-52-review/r1/mut/noslotcheck-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/noslotcheck-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/noslotcheck-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/nostartcmp-conversation.txt b/agents/darkwing/work/queue-52-review/r1/mut/nostartcmp-conversation.txt new file mode 100644 index 00000000..6c4f56d5 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/nostartcmp-conversation.txt @@ -0,0 +1,216 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (207.546579ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (34.048708ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (15.815741ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (526.913261ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (402.880184ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (241.365255ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (193.931318ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (184.631105ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.68713ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12402.441237ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (37895.735718ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (263.446372ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (139.562071ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (626.615386ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (292.222834ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (351.699141ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (109.325451ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (193.569017ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (264.181748ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (942.360216ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (222.383811ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (94.152304ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (71.201849ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.634156ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.055946ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.746349ms) +✔ no shim from this file's tests is left running for the after hook (25.219966ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1143.722418ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (459.959557ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (779.139076ms) +✔ K4: two engines; force stop one; the other survives by independent observation (2973.611764ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (742.313865ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (827.638263ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (822.120986ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5799.433879ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (864.78359ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (678.694077ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (566.68676ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (676.475466ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (408.947932ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (430.354325ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3312.900694ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (47.324942ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (448.335146ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (281.357018ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (143.769448ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (574.478352ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (504.232595ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1466.621317ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (650.407666ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2527.552103ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1487.875713ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (956.394609ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2648.401762ms) +✖ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (483.40404ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (475.823917ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (339.187736ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2868.557067ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (675.705105ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (545.393078ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (408.971398ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2855.046824ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (392.07004ms) +✔ no shim from this file's tests is left running for the after hook (25.236571ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (207.209401ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (225.355435ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (345.490749ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (285.362576ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (210.35797ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.622515ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (196.577431ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (296.301008ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (202.435682ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (198.994819ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (203.965837ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (214.503623ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (9.975739ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (200.493733ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (216.872554ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (231.286641ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (200.433435ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.409219ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.25836ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.302291ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.483347ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (31.331832ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.419867ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.692354ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.357192ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.305535ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.094816ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (220.732142ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (250.980526ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (460.376463ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (833.585665ms) +✔ H4: self-takeover is refused (183.608008ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (434.505305ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1015.113145ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (236.041477ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (529.717707ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (260.702885ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (157.845011ms) +✔ H13: a retry with the same request ID and different text is refused (200.380307ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (652.362907ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (300.022294ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (222.703971ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (940.963356ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (408.996271ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (917.106945ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (215.152925ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (351.800768ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.622612ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (684.259741ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (592.696536ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (749.393867ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3292.301488ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (677.375969ms) +✔ no shim from this file's tests is left running for the after hook (25.101069ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.229525ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.597629ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.848175ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.365364ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.358887ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.623223ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.836978ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.220841ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.344834ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.171108ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.96196ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.572258ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.834288ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.012798ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.896532ms) +✔ F9: registrations never add or redirect a root (1.906633ms) +✔ F10: a header cwd naming another project is refused (4.240669ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.74669ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.308402ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (3.276074ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.5301ms) +✔ F13: compaction is a marker in place, then the retained content (0.778383ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (507.602233ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.568953ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (11.104382ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.170108ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.014957ms) +✔ a seat directory without search permission refuses that root, not the catalogue (1.858512ms) +✔ every page and cursor is a valid CHAT-01 record (782.235307ms) +✔ the engine pin holds for the installed package (1.691402ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (263.440441ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (619.396982ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (262.481491ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (645.944686ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (441.25168ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (240.336015ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (20.747943ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (351.625094ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (188.857257ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (291.536128ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (471.46499ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1889.033228ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (200.792686ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (304.396928ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (208.99262ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (240.265143ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (364.307692ms) +✔ N10: fake conformance (30.675002ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (477.61694ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (309.724547ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (332.948747ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (472.583785ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (393.105928ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (394.071421ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (205.892021ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (358.988271ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (630.769077ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (500.122237ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (527.225297ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (200.681975ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (474.290972ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (211.944854ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (226.783125ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (187.946813ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 181 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 58816.617524 + +✖ failing tests: + +test at packages/conversation/tests/cohort.test.mjs:1037:1 +✖ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (483.40404ms) + AssertionError [ERR_ASSERTION]: {"start":"295524322"} + + actual - expected + + [ + + 'proven', + + undefined + - 'unavailable', + - "the shim reaped a process that isn't the recorded engine" + ] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r52a/wt2/packages/conversation/tests/cohort.test.mjs:1048:14) + at process.processTicksAndRejections (node:internal/process/task_queues:104:5) + at async Test.run (node:internal/test_runner/test:1409:7) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: [ 'proven', undefined ], + expected: [ 'unavailable', "the shim reaped a process that isn't the recorded engine" ], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-52-review/r1/mut/nostartcmp-shims-left.txt b/agents/darkwing/work/queue-52-review/r1/mut/nostartcmp-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/nostartcmp-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-52-review/r1/mut/run.sh b/agents/darkwing/work/queue-52-review/r1/mut/run.sh new file mode 100644 index 00000000..b0988783 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/run.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# run.sh : mutate, run the conversation suite, list and kill shims left under TMPDIR, restore from backups. +m=$1 +export TMPDIR=~/darkwing-scratch/r52a/muttmp/mut-$m DOCKER_HOST=unix:///nonexistent.sock +mkdir -p $TMPDIR +M=~/darkwing-scratch/r52a/mut; cd ~/darkwing-scratch/r52a/wt2 +files=$(python3 -I $M/mutate.py $m --files) +for f in $files; do cp -p $f $f.mutbak; done +if python3 -I $M/mutate.py $m > /dev/null; then + node --test "packages/conversation/tests/*.test.mjs" > $M/$m-conversation.txt 2>&1; e=$? +else e=mutate-failed; fi +left=$(ps -eo pid=,args= | grep -F "$TMPDIR/" | grep -F /shim.mjs | grep -v grep) +n=$(printf '%s' "$left" | grep -c .) +echo "$left" > $M/$m-shims-left.txt +printf '%s\n' "$left" | while read pid rest; do + [ -n "$pid" ] || continue + u=$(tr '/' '\n' < /proc/$pid/cgroup | grep '^mosaic-chat-.*\.scope$') + [ -n "$u" ] && systemctl --user kill --signal=SIGKILL "$u" + kill -9 $pid 2>/dev/null +done +for f in $files; do mv $f.mutbak $f; done +echo "$m rc $e $(grep -E '^ℹ (pass|fail)' $M/$m-conversation.txt | tr '\n' ' ') shims-left $n" >> $M/summary.txt diff --git a/agents/darkwing/work/queue-52-review/r1/mut/summary.txt b/agents/darkwing/work/queue-52-review/r1/mut/summary.txt new file mode 100644 index 00000000..982df43d --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/mut/summary.txt @@ -0,0 +1,15 @@ +mut start 2026-10-10T08:08:23Z +base rc 0 ℹ pass 182 ℹ fail 0 shims-left 0 +noslotcheck rc 0 ℹ pass 182 ℹ fail 0 shims-left 0 +bindadvance rc 0 ℹ pass 182 ℹ fail 0 shims-left 0 +emptyguard rc 0 ℹ pass 182 ℹ fail 0 shims-left 0 +nopopulated rc 0 ℹ pass 182 ℹ fail 0 shims-left 0 +nomembers rc 0 ℹ pass 182 ℹ fail 0 shims-left 0 +bindboth rc 1 ℹ pass 180 ℹ fail 2 shims-left 0 +noinv rc 0 ℹ pass 182 ℹ fail 0 shims-left 0 +noscope rc 0 ℹ pass 182 ℹ fail 0 shims-left 0 +nopidcmp rc 1 ℹ pass 181 ℹ fail 1 shims-left 0 +nostartcmp rc 1 ℹ pass 181 ℹ fail 1 shims-left 0 +noboot rc 0 ℹ pass 182 ℹ fail 0 shims-left 0 +noadvance rc 0 ℹ pass 182 ℹ fail 0 shims-left 0 +mut end 2026-10-10T08:21:31Z units=0 diff --git a/agents/darkwing/work/queue-52-review/r1/out/chat01-check.txt b/agents/darkwing/work/queue-52-review/r1/out/chat01-check.txt new file mode 100644 index 00000000..c3456f72 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/chat01-check.txt @@ -0,0 +1,26 @@ +Schema {"schemaCases": 100, "omissions": 322, "validator": "4.26.0", "failures": []} +Reference cases 76 pass +PASS sequence interrupt-reconcile-prompt +PASS sequence interrupt-confirmed-force-stop +PASS sequence controller-revoked-recovery-control-recover +PASS sequence takeover-old-controller-new-approval +PASS sequence observer-draft-upload-send +PASS sequence duplicate-native-decision +PASS sequence second-launch-active-uncertain-stopping +PASS sequence stop-lifecycle-queue-draft-links +PASS sequence confirmation-reconnect-reconfirm +PASS sequence corrupt-payload-control-and-cancel +PASS sequence revocation-nondestructive-reconciliation +PASS sequence admitted-disconnect-dispatch-receipt +PASS sequence retry-after-transfer-current-disposition +PASS sequence native-resolution-requires-evidence +PASS sequence confirmation-predecessor-and-supersession +PASS sequence different-actor-draft-privacy +PASS sequence empty-history-new-user-assistant-roles +PASS sequence engine-exit-empty-cohort-stopped +PASS sequence engine-exit-live-unreadable-or-empty-cohort-uncertain +PASS sequence engine-exit-stale-confirmation-dispatched-receipt +PASS sequence engine-exit-refused-during-force-stop +PASS sequence engine-exit-binding-follows-stop +Additional regressions PASS: queue recovery, immutable queue edit, safe bootstrap and multipart snapshot/event reconstruction +CHAT-01 R3 PASS: 100 shape cases, 76 reference cases, 22 lifecycle sequences. All synthetic; runtime/authentication/protocol/cohort evidence producers NOT VERIFIED. diff --git a/agents/darkwing/work/queue-52-review/r1/out/node-control-board.txt b/agents/darkwing/work/queue-52-review/r1/out/node-control-board.txt new file mode 100644 index 00000000..2ac65fd9 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/node-control-board.txt @@ -0,0 +1,132 @@ +✔ explicit request, Seen, ordinary completion and a new request have distinct attention states (3.684126ms) +✔ attention convention ignores reasoning/quoted examples and permits leading blank lines (0.218812ms) +✔ completed smoke replies and ordinary questions are idle, not human blockers (0.736482ms) +✔ only an explicit first-line input request makes a finished reply waiting (0.146403ms) +✔ tool activity, user text, errors and unfinished turns override attention text (0.124267ms) +✔ STOP access failure is unknown, not absence, under a non-root identity (33.000011ms) +✔ connector Task never inherits Discord routing envelopes; ordinary Task still uses user text (2.991349ms) +✔ connector discovery keeps only safe identity; rejects modes, mismatches, links and traversal (1.354719ms) +✔ canonical owner identity and STOP are independent; no tmux fallback or forged registration (6.037376ms) +✔ connector reply refusal precedes forged live tmux registration; ordinary agent still sends (0.598616ms) +✔ server rescans connector discovery and refuses HTTP reply without transport (33.233967ms) +✔ connector session links and linked directories are not read (1.014457ms) +✔ newer live matching launch marks old activity, preserves history/attention/attribution, then clears on new activity (2.29252ms) +✔ CLI print uses the relaunch notice instead of old current preview (57.294829ms) +✔ connector owner and fixed task never inherit a native relaunch notice (2.679652ms) +✔ equality, stale/unknown/offline, mismatched registration and unknown activity do not assert relaunch (1.793099ms) +✔ loadConfig: missing file throws ConfigError (1.403833ms) +✔ loadConfig: invalid JSON throws ConfigError (0.279773ms) +✔ loadConfig: missing dataRoot throws ConfigError (0.217949ms) +✔ loadConfig: relative dataRoot throws ConfigError (0.220396ms) +✔ loadConfig: valid config returns dataRoot (0.653222ms) +✔ findNewestSession: picks the newest by mtime among two files (0.446181ms) +✔ findNewestSession: finds files in nested subdirectories (0.278596ms) +✔ findNewestSession: returns null for a missing dir (0.116345ms) +✔ readSession: extracts fields, collapses/truncates text, counts a truncated final line (0.60989ms) +✔ readSession: model and provider follow the latest model_change entry or assistant turn; null when the log names neither; scanAgent carries them (1.20474ms) +✔ readSession: lastError carries the assistant errorMessage only when the last assistant turn errored (0.441313ms) +✔ findNewestSession/scan: never read sibling auth or secrets next to a sessions dir (1.071845ms) +✔ deriveState: full state table (0.170555ms) +✔ rule: newest entry is an assistant message with a tool call, after a question-looking text, is working (0.311314ms) +✔ rule: newest entry is a tool result with no assistant text after it is working (0.296313ms) +✔ rule: a finished ordinary turn is idle, even if it says your move (0.297119ms) +✔ task: the first user message of the session, from text blocks (0.339137ms) +✔ task: a plain-string user content is accepted, whitespace collapsed and long text capped (0.27358ms) +✔ task: no user message in the log means null (shown as unknown), never a guess (0.27412ms) +✔ workspace: the live tmux pane path wins; the session cwd is the fallback; neither means null (0.372777ms) +✔ activeProject: basename of the nearest .git directory or .git file above the workspace; none means null (0.56442ms) +✔ scan: the written record carries task, workspace and activeProject (0.501075ms) +✔ registration: overrides task, project and workspace; every source says registration; registered carries the launch fields; the grouping column is untouched (0.574951ms) +✔ registration: empty task and null project/workspace leave the derived values in place; registered is still non-null (0.391649ms) +✔ registration: a record whose pid is gone is stale; derived values win, sources say derived, registered stays with alive false; a pid the probe cannot decide is not stale; pidAlive itself (1.031005ms) +✔ registration: no registration leaves the Gate A fields exactly as before, and registered is null (0.448407ms) +✔ loadRegistrations: a missing seatsDir gives empty lists (0.198561ms) +✔ loadRegistrations: one good record, one malformed JSON, one with an unknown field; a stray file under seatsDir is ignored (0.753137ms) +✔ matchRegistration: matches by sessionsDir, and by realpath through a symlink; sessionsDir null never matches; same seat name with a different sessionsDir does not match (fleet vs repo darkwing) (0.312822ms) +✔ scan: writes the registration override to disk; index.json carries registered and registrationErrors (1.772544ms) +✔ scan: a relative seatsDir throws ConfigError; an omitted seatsDir behaves as before (0.261395ms) +✔ scanAgent: waitingOnYou is true for waiting/error and false otherwise (0.494709ms) +✔ scanAgent: ageSeconds is computed from the injected now (0.263071ms) +✔ scanAgent: sessionFile null and state idle when sessions dir is empty but alive (0.161511ms) +✔ discoverRepoAgents: finds agents with a sessions dir, skips those without, sorted by name (0.395066ms) +✔ discoverFleetAgents: finds agents with a sessions dir, sorted by name, fleet tmux fields (0.379872ms) +✔ scan: writes per-agent files and index.json, rerun overwrites, no leftover tmp files (0.884316ms) +✔ scan: relative boardDir throws ConfigError (0.099616ms) +✔ CLI: scan with assume-alive liveness exits 0, prints board summary, writes board files (58.73943ms) +✔ CLI: missing config exits 2 with a refused: message (51.652707ms) +✔ CLI: unknown command exits 2 (48.203798ms) +✔ CLI: unknown --liveness value exits 2 (49.727483ms) +✔ panesRunPi: true when any trimmed line equals 'pi' (0.235794ms) +✔ panesRunPi: false for bash-only, claude, empty, or node-pi-style lines (0.074273ms) +✔ tmuxIsAlive: a pane running pi is alive (0.214179ms) +✔ tmuxIsAlive: session exists but pi has exited is not alive (0.084066ms) +✔ tmuxIsAlive: no such tmux session is not alive (0.053181ms) +✔ tmuxIsAlive: tmux could not be run at all is unknown (null), never assumed alive (0.063947ms) +✔ tmuxIsAlive: passes -L only when a socket is given (0.093626ms) +✔ parsePanes: one pane per line, command and optional tab-separated path (0.081066ms) +✔ tmuxInspect: reports the path of the pane running pi, not of a shell pane (0.081491ms) +✔ tmuxInspect: no pi pane, no session, or no tmux gives no workspace and the matching liveness (0.095921ms) +✔ loadSeen: missing file returns {} (0.126983ms) +✔ loadSeen: invalid JSON throws ConfigError (0.186682ms) +✔ loadSeen: a JSON array throws ConfigError (0.173194ms) +✔ loadSeen: a non-string value throws ConfigError (0.176856ms) +✔ markSeen: seen true adds the key and writes seen.json mode 0600, no leftover tmp files (0.34015ms) +✔ markSeen: seen false deletes the key (0.263336ms) +✔ markSeen: missing, empty, or non-string fields throw ConfigError (0.232673ms) +✔ markSeen: project containing '/' throws ConfigError (0.116685ms) +✔ markSeen: non-boolean seen throws ConfigError (0.107345ms) +✔ scanAgent: a seen mark matching the waiting session's lastTimestamp clears waitingOnYou (0.273692ms) +✔ scanAgent: a stale mark (agent wrote something newer) is not seen and waitingOnYou is true (0.24723ms) +✔ scanAgent: a working session with a matching mark is not seen (marks only apply to waiting/error) (0.21717ms) +✔ scanAgent: an error-state session with a matching mark is seen (0.225117ms) +✔ scan: index.seen and waitingOnYou reflect seen.json, which scan never rewrites or deletes (0.505347ms) +✔ scan: a corrupt seen.json makes scan throw ConfigError (fail closed) (0.1795ms) +✔ taskSetBy: a registered task carries the record's setter; a record without the field (pre-#1511) reads unknown; the value is not copied into registered (0.605846ms) +✔ taskSetBy: null whenever the task shown is not the registered one: no registration, an empty registered task, a stale registration; the field is always present (0.755359ms) +✔ taskSetBy: scan() reads the field from disk through the seat package (bounded there), writes it to the per-agent record and index, and an invalid on-disk value is a registrationError, never a row value (0.956388ms) +✔ isLoopbackHost: recognizes loopback hosts (1.30311ms) +✔ isLoopbackHost: rejects non-loopback hosts (4.416482ms) +✔ startServer: refuses a non-loopback host with ConfigError, never opens a socket (3.256677ms) +✔ startServer: serves page, healthz, and a rescanning /api/board (35.113345ms) +✔ startServer: a seatsDir registration overrides the row and index.registered reflects it (5.524457ms) +✔ startServer: /api/board returns 500 JSON with an error field when scan throws (2.180864ms) +✔ CLI: serve refuses a non-loopback host with exit 2 and a refused: message (54.955034ms) +✔ CLI: serve rejects a non-numeric --port with exit 2 (48.125029ms) +✔ CLI: scan still works after the async cli refactor (49.493087ms) +✔ CLI: live serve prints its URL and answers /healthz (61.334746ms) +✔ page.html: esc() escapes every HTML-significant character (0.664651ms) +✔ POST /api/seen marks a row; GET /api/board still shows it seen; seen:false clears it (8.375265ms) +✔ POST /api/seen without a JSON content-type returns 400 and does not write a mark (1.926518ms) +✔ POST /api/seen with invalid JSON returns 400 (2.774494ms) +✔ POST /api/seen with a body over 4096 bytes returns 400 (or resets the connection) and writes no mark (2.048784ms) +✔ POST /api/seen with a missing agent returns 400 (1.271562ms) +✔ POST /api/board returns 405; PUT /api/seen returns 405 (1.637048ms) +✔ CLI: scan --print marks a seen row with 's' and the summary line ends with 'N seen)' (55.544425ms) +✔ page.html: seenControl() escapes rec.project/agent/lastActivity, and the POST uses a JSON content-type (0.295879ms) +✔ page.html: has a collapsed Seen section that lists seen rows with the shared row builder (0.251814ms) +✔ page.html: each project has a Hide seen checkbox (default on) beside Hide offline, with a hidden-count note (0.158429ms) +✔ page.html: a project header reads "N of N" only while a checkbox hides rows (0.122255ms) +✔ page.html: every row shows Task and Active project, derived or the word unknown, with the workspace in the detail (0.314437ms) +✔ page.html: task and active project cells show their source via sourceTag(); the detail has a Registered row via registeredText(); SOURCE_LABEL maps registration to registered; every dynamic value in sourceTag/fromSource/registeredText is escaped (0.5284ms) +✔ POST /api/reply: runs agent-send.sh with -s from the registration, -S :control-board, -m text plus the fixed trailer, no -L on the default socket, MOSAIC_TMUX_SOCKET stripped; answers delivered with the exit code and both streams (25.905781ms) +✔ POST /api/reply: a registration with a tmux socket adds -L (24.859892ms) +✔ POST /api/reply: a non-zero tool exit is a 200 with delivered false, the exit code and the stderr verbatim (26.981272ms) +✔ POST /api/reply: refusals before the tool runs: empty or blank or long text 400, unknown row 404, no registration 409, stale registration 409, no tmux session 409, bad JSON 400; the tool is never called (14.150812ms) +✔ POST /api/reply: a missing agent-send.sh is a 500 with the path in the error, not a crash (4.377685ms) +✔ replyToRow: DEFAULT_AGENT_SEND is the repository's tools/tmux/agent-send.sh and it is executable (0.151316ms) +✔ page.html: the reply box appears only where canReply() holds (live registration with a tmux session), the detail has a Reply row, the submit posts JSON to /api/reply, receipts and drafts survive a refresh, and every receipt value is escaped (0.564515ms) +✔ startServer: /api/board carries taskSetBy from a live registration and null for the derived rows (2.713687ms) +✔ page.html: the task cell and detail show who set a registered task via setByTag()/setByText(), both escaped, only from rec.taskSetBy; the reply gate does not read it (0.302854ms) +✔ Host/Origin guard: GET /api/board and POST /api/reply refuse a foreign Host, a wrong port and a cross-origin Origin with 403 JSON, before any scan or send, and never send CORS headers (7.644147ms) +✔ Host/Origin guard: loopback names on this port are accepted, with or without a same-origin Origin (31.341119ms) +✔ conversation routes (F16): a foreign Host, a wrong port and a cross-origin Origin get 403 before the reader runs, with no CORS headers (5.575046ms) +✔ every refusal code the reader can raise has an HTTP status (3.620419ms) +✔ conversation routes: catalogue, first page, next page and follow over HTTP; refusals map to 4xx with their code; nothing is written (46.884311ms) +ℹ tests 124 +ℹ suites 0 +ℹ pass 124 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 623.980008 diff --git a/agents/darkwing/work/queue-52-review/r1/out/node-conversation.txt b/agents/darkwing/work/queue-52-review/r1/out/node-conversation.txt new file mode 100644 index 00000000..d503d630 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/node-conversation.txt @@ -0,0 +1,190 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (245.598663ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (37.542039ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (24.277957ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (845.471305ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (503.787827ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (247.34576ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (244.54038ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (213.396502ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.287394ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (13688.507156ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (38655.645397ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (278.804761ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (143.726774ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (638.496007ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (278.397419ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (346.122879ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (101.269132ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (196.291025ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (265.938168ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (727.119626ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (181.053647ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (89.69572ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (72.428427ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.356252ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.125574ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.74933ms) +✔ no shim from this file's tests is left running for the after hook (25.548837ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1455.687055ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (551.162865ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (829.420716ms) +✔ K4: two engines; force stop one; the other survives by independent observation (3161.267036ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (755.493865ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (1017.904845ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (1093.095119ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (6068.587021ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (859.177113ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (853.270286ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (1002.346221ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (851.600541ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (568.004432ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (717.383078ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3302.952038ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (30.476607ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (487.523167ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (379.86713ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (184.193377ms) +✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (603.457332ms) +✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (705.013162ms) +✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1274.277853ms) +✔ E1: a natural engine exit with no member left: an engine-exit stop, stopped on a proof naming the engine, and the scope released (618.947166ms) +✔ E2: an engine exit with a tool child alive: the stop ends uncertain and nothing is released; a force stop then ends it (2658.248325ms) +✔ E3: an engine exit and a force stop take one escalation slot, in either order (1186.509072ms) +✔ E4: a shim that doesn't answer: the engine-exit stop misses its deadline, ends uncertain and frees the slot (1324.102491ms) +✔ E5: an engine exit after a force stop ended uncertain starts no engine-exit stop; the force stop stays current (2663.0461ms) +✔ E6: the engine-exit observation refuses a reaped process that isn't the recorded engine: another PID or start ticks (606.004216ms) +✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (451.683259ms) +✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (313.71765ms) +✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2615.016897ms) +✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (474.425792ms) +✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (747.402309ms) +✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (553.430113ms) +✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2661.779498ms) +✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (244.468541ms) +✔ no shim from this file's tests is left running for the after hook (24.566568ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (243.851623ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (644.10377ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (241.016351ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (395.08229ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (252.521514ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.41911ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (243.333646ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (340.175865ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (231.02602ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (226.862281ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (254.280278ms) +✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (248.169829ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.013414ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (238.962072ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (317.008043ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (317.13635ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (192.899544ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.413531ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.271928ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.305125ms) +✔ terminal: Ctrl-T then Enter in one chunk is judged after the takeover, as if typed one key at a time (Filbert F2, #1507) (0.494819ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.936325ms) +✔ terminal: a hold inside held input holds again, and once it is drained later input and Ctrl-C still reach the terminal (Darkwing note 1 on #1522) (0.38582ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.655331ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.348419ms) +✔ terminal: input() reports an error when it happens, so it never overwrites a later status; held input's promise doesn't carry the holder's error (Filbert N4 on #1522) (0.378157ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.102792ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (219.813104ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (314.01186ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (718.688805ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (1048.114051ms) +✔ H4: self-takeover is refused (221.688551ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (482.548948ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1342.295512ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (227.665786ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (516.128659ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (271.623742ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (197.27492ms) +✔ H13: a retry with the same request ID and different text is refused (193.247514ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (542.497808ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (317.130918ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (208.705219ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (1441.344931ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (626.808565ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (876.493665ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (230.470069ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (380.745103ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.707475ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (722.811053ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (636.358411ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (1111.246685ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3468.449676ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (859.789675ms) +✔ no shim from this file's tests is left running for the after hook (25.237233ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.875783ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.712434ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.791411ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.592398ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.557023ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.080284ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.888392ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.351229ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.629098ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.57672ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.46566ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.446896ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.318441ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.258637ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.882021ms) +✔ F9: registrations never add or redirect a root (2.56865ms) +✔ F10: a header cwd naming another project is refused (5.926746ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.993945ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (7.729599ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.922057ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.356036ms) +✔ F13: compaction is a marker in place, then the retained content (0.81633ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (523.3244ms) +✔ fragments never cut a surrogate pair and keep an empty string (5.156506ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (2.47873ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.486641ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.131435ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.104494ms) +✔ every page and cursor is a valid CHAT-01 record (1033.874741ms) +✔ the engine pin holds for the installed package (1.873982ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (260.263744ms) +✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (575.02502ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (350.630556ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (970.861927ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (569.443358ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (314.457345ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.781504ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (414.640422ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (214.642586ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (315.790385ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (562.570071ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1896.232702ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (196.067539ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (282.827063ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (182.267151ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (221.698121ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (448.629281ms) +✔ N10: fake conformance (32.773822ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (566.43898ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (565.054925ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (467.263058ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (590.202636ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (417.601376ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (399.036761ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (231.365565ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (361.794489ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (828.283827ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (932.635926ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (704.353632ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (461.654218ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (356.440137ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (336.232844ms) +✔ N24: the seal is an allow-list: --extension, a missing --no-* flag, a second --mode or --session, a session or output flag, or a stray word refuses unsealed-engine; no engine starts (284.008839ms) +✔ N24b: the seal covers the engine command and environment: config can't name either, the env is built from names, and a mutated command is refused at bind (234.577483ms) +ℹ tests 182 +ℹ suites 0 +ℹ pass 182 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 61527.634243 diff --git a/agents/darkwing/work/queue-52-review/r1/out/node-queue.txt b/agents/darkwing/work/queue-52-review/r1/out/node-queue.txt new file mode 100644 index 00000000..621dbaa5 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/node-queue.txt @@ -0,0 +1,158 @@ +✔ F1: an ordinary commit after update-ref is refused until step 8; then it commits and the queue stays at C (1297.926202ms) +✔ F1: a plain `commit -e` whose guard ran before update-ref fails at its own HEAD update (1078.206663ms) +ℹ git commit -e: index.lock free during the editor +✔ F1: a `commit -e -- path` whose guard ran before update-ref fails at its own HEAD update (1095.2359ms) +ℹ git commit -e -- src.txt: index.lock held during the editor +✔ F1: step 8 with index.lock held exits 3, and ordinary commits stay refused until the printed command runs (1123.52289ms) +✔ F1: HEAD moving after the step-7 guard check and before update-ref: refused, nothing published (1080.293295ms) +✔ F1: H is recorded before the canary, so HEAD moving during the step-1 canary is refused at step 7 (1272.504519ms) +✔ F1: a queue commit landing after H is recorded: step 1 says HEAD moved, not the guard (1487.358499ms) +✔ F1: a queue commit landing between the HEAD check and the canary: the failed clean run is reported as HEAD moved (1060.96582ms) +✔ F1: a shared-index change during the procedure is not committed (1182.169241ms) +✔ F1: a queue path staged after update-ref: step 8 stops and touches nothing (1095.171779ms) +✔ F1: a missing or a different hook refuses (710.828984ms) +✔ F1: same bytes without the exec bit, a symlinked hook, and core.hooksPath in the local or global scope each refuse before update-ref (1276.53739ms) +✔ F1: the canary refuses a hook that git would not run (699.58617ms) +✔ F1: the guard deactivated after step 1 is refused at the step-7 recheck (1027.79386ms) +✔ bootstrap: implementation-only HEAD, the guard, genesis, the --genesis commit, then an extending commit (866.310238ms) +✔ bootstrap: --genesis with a base present, no base without --genesis, an op before the first commit, a changed map, another branch (923.873583ms) +✔ bootstrap: the archived tests and validator run outside any repository (1029.80026ms) +✔ general: an unrelated staged file stays staged, and the committed blobs are the snapshot bytes (940.019879ms) +✔ general: a queue write after the snapshot is not committed (1248.889648ms) +✔ general: a snapshot whose log does not extend the base refuses (1099.081908ms) +✔ general: install-hook privilege, repair of a same-bytes hook, and its refusals (162.464212ms) +✔ general: environment overrides, a linked worktree and usage (641.634702ms) +✔ general: a queue path staged before the run refuses at step 1 (715.64098ms) +✔ general: HEAD's queue tests failing in the archive refuse (940.14617ms) +✔ genesis document serializes deterministically and replays (5.940484ms) +✔ a hand edit that stays valid JSON fails replay; a formatting-only edit fails re-serialization (3.641442ms) +✔ a tampered result, receipt or viewSha fails replay (3.469013ms) +✔ op ids: 8 to 72 characters for callers, 80 in the log for .outcome entries (0.263999ms) +✔ add: defaults for an ordinary seat, privileged extras, refusals (5.909515ms) +✔ matrix: queued→briefed privileged; briefed→in-progress owner with after satisfied (6.389515ms) +✔ matrix: release, review round, changes requested and waiting-on-jason (13.576083ms) +✔ matrix J5: in-review→done by the gate owner with evidence naming the current round (7.916756ms) +✔ review issue, lead decision 23: none refuses, one is used, several need --issue, later rounds keep it (17.676615ms) +✔ the row schema refuses a round with a null issue, and the A1 review shape (P2) (2.11945ms) +✔ matrix R1: every state × target × actor class matches 8.7, gate owner jason or not, required or not (1333.619384ms) +✔ matrix: blocked keeps the claim and returns only to previousState (4.170338ms) +✔ matrix J4: parking is Jason's, refused while required; unpark returns to queued (2.951516ms) +✔ field edits: who may change what (5.473956ms) +✔ set issues keeps a logged narrowing of closes (N10) (3.247455ms) +✔ text the table shows refuses \ and <, everywhere it enters (N8) (2.108155ms) +✔ every accepted text renders to nine cells on every row (N8) (24.69893ms) +✔ genesis: the map refuses an owner among its row's reviewers; replay doesn't (2026-10-04) (0.521161ms) +✔ times and dates must be calendar values, not just the shape (2026-10-04) (1.691779ms) +✔ replay holds every op id to the caller's rule (N11) (5.601232ms) +✔ note: owner, listed reviewer or privileged; empty clears (1.236459ms) +✔ assign moves the claim with the owner; done clears it (2.541282ms) +✔ render is byte-stable and escapes pipes (0.529404ms) +✔ view classification: current, genuine stale, edited stale marker, changed current body, markers (0.572265ms) +✔ next: resume, then review, then start, then wait, then nothing; lowest id first (18.508424ms) +✔ canonical args make a retry's identity independent of list order (0.346717ms) +✔ manifests, headings and blob ids (0.423163ms) +✔ the migration map: one queue-map block, exact keys (0.55849ms) +✔ every call but `queue` reaches the seat CLI exactly as before A2 (598.740577ms) +✔ `queue` reaches the queue CLI with the rest of the arguments (218.535104ms) +✔ the pre-A2 fixture is the script A2 changed (0.332706ms) +✔ acquire publishes the record by link; release removes only its own lock (11.035557ms) +✔ a kill between the temp write and the link leaves no lock (52.647479ms) +✔ a short or failed temp write refuses and leaves no lock and no temp (11.909793ms) +✔ a link error other than EEXIST refuses (5.875643ms) +✔ an error after the link releases the lock: unreadable gate, failing temp stat (21.485982ms) +✔ a release that fails on a gate path is reported, never a stack trace (P1) (37.883057ms) +✔ a paused holder: another writer waits 10 s, then refuses naming it live (10102.738287ms) +✔ two concurrent unlockers: the second refuses on the gate (46.880426ms) +✔ a writer publishing during an unlock, lock first: unlock sees it live and refuses (21.666683ms) +✔ a writer publishing during an unlock, gate first: the writer releases and refuses (19.715978ms) +✔ a gate swapped while held is left in place and reported, on success and on refusal (N1) (23.208139ms) +✔ a reused pid within one boot is mismatch; unlock removes the lock and never signals the process (12.674972ms) +✔ the same pid and start on a different boot is mismatch (0.499813ms) +✔ a foreign host is unknown whatever the local pid says; unlock refuses (69.409168ms) +✔ unreadable /proc: classification is unknown and acquire refuses (0.709514ms) +✔ invalid records: empty, unparsable, wrong keys, bad start or boot (0.180227ms) +✔ a stale gate blocks writers; --check-gate says mismatch for a reused pid (21.639971ms) +✔ a delayed release by a dead owner, after unlock and a new owner: the inode check keeps the new lock (30.725911ms) +✔ release checks the inode too: a byte-identical lock file with a new inode is left in place (13.320379ms) +✔ unlock refuses a live, unknown or invalid lock, and does nothing without one (49.571274ms) +✔ the migration map validates and renders the golden genesis table (5.215354ms) +✔ the marked QUEUE.md holds every row and parked item between its markers (1.987613ms) +✔ map-check reports each kind of drift (5.043527ms) +✔ a request posts once as the requester; a retry sends nothing (901.277657ms) +✔ each transport answer maps to posted, failed or uncertain (8.9 step 3) (5117.983211ms) +✔ the pre-send checks: GET user must name the requester, under the deadline (1999.938959ms) +✔ the lead's request refuses a token for login sage (1105.886229ms) +✔ the credential file: the seat's own, 0600, no symlink, never the shared default (877.161859ms) +✔ an unresolved request blocks a new request, a new round, waiting-on-jason and done (2308.993585ms) +✔ a same-op retry after a kill sends nothing, even with a stale view (3288.994539ms) +✔ a held lock at the outcome exits 3 and names what the transport said (645.789079ms) +✔ late outcomes: after an abandon, and after a resolve with the same or another id (2435.89931ms) +✔ resolve checks the comment: issue, markers, round, candidate and author (1647.577978ms) +✔ the lead resolves a seat's request: the comment's author is the requester, fetched with the lead's token (770.35505ms) +✔ validateRow checks a request round's shape, which every replayed entry must keep (575.776837ms) +✔ request, changes, a new candidate, approval: every round pinned; no review files (1864.656731ms) +✔ a row with no reviewers opens a round that posts nothing (1531.164768ms) +✔ verify-commit: a prospective tree must hold exactly the candidate's paths (1507.616592ms) +✔ semantics: v1 entries replay as before; review entries need v2 (519.565419ms) +✔ set reviewers refuses the row's owner (2026-09-28) (359.531717ms) +✔ the owner records no verdict, even as a listed reviewer (478.085764ms) +✔ a request comment over the length limit is not sent (546.993689ms) +✔ a late POST on a closed row leaves a conflict nothing can resolve, and resolve asks nothing (792.643564ms) +✔ a Jason-gated row reaches waiting-on-jason only on every reviewer's approval (2557.086645ms) +✔ genesis: refusals before anything is written (406.715325ms) +✔ genesis: the map must be committed, well formed, with committed briefs and seats (663.485658ms) +✔ genesis: markers, a stray witness, once only; a retry returns the receipt (584.072263ms) +✔ genesis: a file holding genesis alone with no witness is confirmed by sync or a retry (425.788643ms) +✔ canonical checks: worktree, second clone, detached HEAD, wrong branch, GIT_DIR, foreign code; a symlink works (656.621928ms) +✔ --by that differs from MOSAIC_AGENT_NAME warns on stderr and logs nothing more (N12) (935.513416ms) +✔ op ids: missing, too long, reserved; a retry answers; another payload refuses (809.537348ms) +✔ a retried add returns the id it first allocated, after reassignment and after done (1129.480007ms) +✔ Rocko's S4 schedule: a lost result, another writer, then the retry opens no second round (1138.430587ms) +✔ the review issue and the evidence round through the CLI (lead decision 23, 8.7) (1435.162831ms) +✔ claims and add defaults through the CLI; candidates are manifests or reachable commits (935.949236ms) +✔ add, set reviewers and assign refuse the row's owner as a reviewer (544.971984ms) +✔ the working-brief check: a changed working copy refuses the start and flags next (685.882412ms) +✔ next: resume first, then nothing for an idle seat; needs a seat (335.647251ms) +✔ view stale: new ops and verify refuse naming the unshown op; retries answer; reads warn; render fixes (698.578437ms) +✔ view unknown: a hand edit, an old marker over an edited body, missing or duplicate markers (1185.528588ms) +✔ a hand edit to queue.json refuses every verb, reads included (608.003889ms) +✔ verify and render --check leave bytes and mtimes unchanged (460.974009ms) +✔ render is byte-stable across runs and repositories (315.585134ms) +✔ snapshot and verify --snapshot (872.741861ms) +✔ usage errors exit 4 (556.259554ms) +✔ a short write, ENOSPC or a file fsync failure: nothing visible, temp removed (316.943678ms) +✔ a rename failure: nothing visible, temp removed (232.902451ms) +✔ a directory fsync failure: uncertain, exit 3, no receipt; the tail refuses new ops; a retry confirms (275.434107ms) +✔ a directory fsync failure, then sync names the op (410.821707ms) +✔ a witness write failure: uncertain, durable, exit 3; the view is untouched (260.776857ms) +✔ the .git fsync after the witness rename fails: uncertain, exit 3, the witness says so (223.790987ms) +✔ confirming a tail fsyncs queue.json and docs/plans before the witness; either failure changes nothing (248.215453ms) +✔ the docs/plans fsync after the view rename fails: the op stands, the view is written, a warning says so (218.141378ms) +✔ a lock swapped while held is left in place and reported, on a receipt and on a refusal (246.422282ms) +✔ a lock that cannot be released after an op is reported, on a receipt and on a refusal (223.593961ms) +✔ unlock prints a swapped gate's warning on stderr, the result on stdout (183.029349ms) +✔ a view write that fails keeps the op and reports a stale view (222.454896ms) +✔ SIGKILL before the rename: nothing recorded; the retry removes the leftover temp (694.664044ms) +✔ SIGKILL after the rename, before the witness: the tail refuses new ops and sync names the op (713.057385ms) +✔ SIGKILL after the witness, before the view: the stale refusal names the op (684.764134ms) +✔ SIGKILL after the view, before the receipt: the retry returns the receipt (779.819264ms) +✔ git checkout between steps 1 and 7: step 7 refuses and nothing is written (490.159703ms) +✔ git stash restoring an older valid pair: history lost; accept-history needs privilege, a reason and --yes (1250.259282ms) +✔ a deleted witness: refused after the locked recheck; accept-history records it absent (414.77974ms) +✔ a header edit during a write: the op stands, the view write is skipped with a warning (256.841736ms) +✔ a reader paused between the witness and the file while a writer finishes: no lost-history report (289.179628ms) +✔ file-then-witness order forced by a hook: the locked recheck prevents a false report (249.200094ms) +✔ a writer paused before and after the witness rename: readers see a tail, then a match (239.189011ms) +✔ a true rollback is reported only after the locked recheck; a held lock names its holder instead (598.983025ms) +✔ an accept-history in progress: an unlocked reader waits on the lock and never reports lost history (606.87954ms) +✔ the platform check refuses other filesystems (161.406303ms) +✔ tmpfs passes only a test layer that allows it (N5) (250.993318ms) +✔ unlock keeps a multi-line lock record on stdout (P3) (224.753838ms) +ℹ tests 148 +ℹ suites 0 +ℹ pass 148 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 31907.89883 diff --git a/agents/darkwing/work/queue-52-review/r1/out/node-webui.txt b/agents/darkwing/work/queue-52-review/r1/out/node-webui.txt new file mode 100644 index 00000000..3fc1a67c --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/node-webui.txt @@ -0,0 +1,31 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3859.716121ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4578.851942ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5476.126857ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (250.443187ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (114.028741ms) +✔ bus refusals map to statuses and never carry a path or a stack (183.631886ms) +✔ humanCall speaks the human transport protocol without blocking the server (2505.953212ms) +✔ busReader takes --business, else the live bus host, else refuses (257.752776ms) +✔ humanCall kills a transport that runs past its timeout (535.155031ms) +✔ serve refuses a --business value that is not a business id (209.465156ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3844.081867ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2140.616313ms) +✔ conversation view: a newer session with no readable history keeps the marker (1061.542359ms) +✔ conversation view: seats without history say so and offer no reply (958.259221ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4602.555007ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (54385.273614ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4529.230891ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (21762.701465ms) +✔ loopback host and board origin fail closed (8.915595ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (92.077095ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (79.877866ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1650.572067ms) +ℹ tests 22 +ℹ suites 0 +ℹ pass 22 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 54709.673654 diff --git a/agents/darkwing/work/queue-52-review/r1/out/summary.txt b/agents/darkwing/work/queue-52-review/r1/out/summary.txt new file mode 100644 index 00000000..4b0cb020 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/summary.txt @@ -0,0 +1,18 @@ +start 2026-10-10T08:04:09Z shims=0 units=0 +node-conversation exit=0 ℹ pass 182 ℹ fail 0 shims-left=0 units=0 +node-webui exit=0 ℹ pass 22 ℹ fail 0 shims-left=0 units=0 +test-auth exit=0 selftest: 15 passed, 0 failed +test-conductor exit=0 selftest: 17 passed, 0 failed +test-config exit=0 selftest: 24 passed, 0 failed +test-discord exit=0 discord suite: 66 passed, 0 failed +test-extension-package exit=0 extension package selftest: 18 passed, 0 failed +test-foundation exit=0 selftest: 44 passed, 0 failed +test-queue exit=0 queue suite: 27 passed, 0 failed +test-release exit=0 selftest: 4 passed, 0 failed +test-task exit=1 selftest: 26 passed, 2 failed +end 2026-10-10T08:07:47Z shims-left=0 units=2 +DONE +node-control-board exit=0 ℹ pass 124 ℹ fail 0 +node-queue exit=0 ℹ pass 148 ℹ fail 0 +chat01-check exit=0 CHAT-01 R3 PASS: 100 shape cases, 76 reference cases, 22 lifecycle sequences. All synthetic; runtime/authentication/protocol/cohort evidence producers NOT VERIFIED. +DONE2 diff --git a/agents/darkwing/work/queue-52-review/r1/out/test-auth.txt b/agents/darkwing/work/queue-52-review/r1/out/test-auth.txt new file mode 100644 index 00000000..ac228760 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/test-auth.txt @@ -0,0 +1,17 @@ +OK status with missing harness credential exits 3 and still lists accounts +OK status reports harness credential (read-only) + mosaic accounts +OK api key material never reaches output +OK oauth token material never reaches output +OK unparseable credential file exits 2 +OK symlinked credential file exits 4 +OK env-side credential names reported +OK env var values never reach output +OK accounts without an accounts dir reports none and creates nothing +OK accounts lists files and marks the active one +OK loose account perms flagged in listing +OK agent --auth with missing account file refuses (exit 4) +OK agent --auth with non-0600 account file refuses +OK agent --auth with invalid account name refuses +OK auth.sh without valid config refuses + +selftest: 15 passed, 0 failed diff --git a/agents/darkwing/work/queue-52-review/r1/out/test-conductor.txt b/agents/darkwing/work/queue-52-review/r1/out/test-conductor.txt new file mode 100644 index 00000000..155eec33 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/test-conductor.txt @@ -0,0 +1,55 @@ +Note: switching to 'cc83ee4f6a458151a7d49ee4159387d03517d0bb'. + +You are in 'detached HEAD' state. You can look around, make experimental +changes and commit them, and you can discard any commits you make in this +state without impacting any branches by switching back to a branch. + +If you want to create a new branch to retain commits you create, you may +do so (now or later) by using -c with the switch command. Example: + + git switch -c + +Or undo this operation with: + + git switch - + +Turn off this advice by setting config variable advice.detachedHead to false + +Not currently on any branch. +nothing to commit, working tree clean +Note: switching to 'cc83ee4f6a458151a7d49ee4159387d03517d0bb'. + +You are in 'detached HEAD' state. You can look around, make experimental +changes and commit them, and you can discard any commits you make in this +state without impacting any branches by switching back to a branch. + +If you want to create a new branch to retain commits you create, you may +do so (now or later) by using -c with the switch command. Example: + + git switch -c + +Or undo this operation with: + + git switch - + +Turn off this advice by setting config variable advice.detachedHead to false + +OK dry-run: allowed change, exit 0, nothing committed (exit 0) +OK dry-run committed nothing +OK apply: allowed change exits 0 (exit 0) +OK apply: attribution in commit subject +OK apply: target tree clean after commit +OK disallowed path refused (exit 1) +OK disallowed path: target untouched +OK syntax gate refused broken .mjs (exit 1) +OK syntax gate: target untouched +OK suite failure refused (exit 1) +OK suite failure: target reverted to clean +OK disabled policy refused (exit 2) +OK disabled policy: target untouched +OK failed run refused (exit 1) +OK failed run: target untouched +OK missing run exits 4 (exit 4) +OK invalid policy exits 2 (exit 2) + +selftest: 17 passed, 0 failed diff --git a/agents/darkwing/work/queue-52-review/r1/out/test-config.txt b/agents/darkwing/work/queue-52-review/r1/out/test-config.txt new file mode 100644 index 00000000..76c05ef7 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/test-config.txt @@ -0,0 +1,26 @@ +OK absent adapter defaults to pi +OK adapter mock validates (exit 0) +OK unsupported adapter exits 2 (exit 2) +OK env exports adapter +OK bootstrap creates default when absent (exit 0) +OK bootstrap wrote config file +OK bootstrap is idempotent on existing config (exit 0) +OK bootstrap did not rewrite existing config +OK validate missing config exits 3 (exit 3) +OK malformed JSON exits 2 (exit 2) +OK unsupported configVersion exits 2 (exit 2) +OK unknown top-level key exits 2 (exit 2) +OK unknown execution key exits 2 (exit 2) +OK unsupported backend exits 2 (exit 2) +OK unsupported environment exits 2 (exit 2) +OK relative dataRoot exits 2 (exit 2) +OK non-canonical dataRoot exits 2 (exit 2) +OK filesystem root dataRoot exits 2 (exit 2) +OK home directory dataRoot exits 2 (exit 2) +OK dataRoot containing config dir exits 2 (exit 2) +OK control character in provider exits 2 (exit 2) +OK symlinked config file exits 2 (exit 2) +OK env exports resolve correctly +OK failed validation modified nothing + +selftest: 24 passed, 0 failed diff --git a/agents/darkwing/work/queue-52-review/r1/out/test-discord.txt b/agents/darkwing/work/queue-52-review/r1/out/test-discord.txt new file mode 100644 index 00000000..b013f9ff --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/test-discord.txt @@ -0,0 +1,70 @@ +toolchain: node v26.8.1 + +OK syntax: packages/discord/src/approvals.mjs +OK syntax: packages/discord/src/authorize.mjs +OK syntax: packages/discord/src/binding.mjs +OK syntax: packages/discord/src/cli.mjs +OK syntax: packages/discord/src/connector.mjs +OK syntax: packages/discord/src/context.mjs +OK syntax: packages/discord/src/engine-pi.mjs +OK syntax: packages/discord/src/errors.mjs +OK syntax: packages/discord/src/gateway.mjs +OK syntax: packages/discord/src/git.mjs +OK syntax: packages/discord/src/journal.mjs +OK syntax: packages/discord/src/notify.mjs +OK syntax: packages/discord/src/rest.mjs +OK syntax: packages/discord/src/setspark.mjs +OK syntax: packages/discord/src/tools.mjs +OK syntax: packages/discord/src/web.mjs +OK syntax: packages/discord/bin/git-credential.mjs +OK syntax: packages/discord/extension/tools.mjs +OK syntax: packages/discord/tests/approvals.test.mjs +OK syntax: packages/discord/tests/authorize.test.mjs +OK syntax: packages/discord/tests/binding.test.mjs +OK syntax: packages/discord/tests/connector.test.mjs +OK syntax: packages/discord/tests/context.test.mjs +OK syntax: packages/discord/tests/engine.test.mjs +OK syntax: packages/discord/tests/fake-pi.mjs +OK syntax: packages/discord/tests/gateway.test.mjs +OK syntax: packages/discord/tests/git.test.mjs +OK syntax: packages/discord/tests/helpers.mjs +OK syntax: packages/discord/tests/journal.test.mjs +OK syntax: packages/discord/tests/notify.test.mjs +OK syntax: packages/discord/tests/recover.test.mjs +OK syntax: packages/discord/tests/rest.test.mjs +OK syntax: packages/discord/tests/setspark.test.mjs +OK syntax: packages/discord/tests/tools.test.mjs +OK syntax: packages/discord/tests/web.test.mjs +OK syntax: packages/discord/fixtures/claim-worker.mjs +OK syntax: packages/discord/fixtures/legacy-owner-worker.mjs +OK syntax: scripts/discord.sh +OK syntax: scripts/discord-service.sh +OK packages/discord declares no dependencies +OK no bot-token-shaped string in packages/discord +OK fixture binding uses placeholder ids only +OK fixture binding validates +OK real pi with the extension exposes exactly list_dir, read_file, search and no built-in tool +OK real pi with a writable root exposes exactly the three reads plus write_file and edit_file, and writes nothing at start +OK real pi with a web key exposes the three reads plus web_fetch and web_search, and no write tool without a writable root +OK real pi with a git root exposes the reads, writes and the four git verbs, commits nothing at start, and never shows the token +OK real pi with protocol vault adds reserve_id to the git verbs +OK real pi with a setspark key exposes the reads and the eight record verbs, no counters, and never shows the key +OK real pi refuses a git key on a read-only root (fail closed) +OK real pi with the pilot flags (--no-tools) exposes no tool at all +OK real pi exits non-zero without MOSAIC_DISCORD_TOOLS: no session, no tools (fail closed) +OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT +OK node --test packages/discord/tests/ (ℹ pass 178) +OK scripts/discord.sh --help exits 0 +OK scripts/discord.sh check without a binding exits 4 +OK scripts/discord.sh recover without a binding exits 4 +OK scripts/discord.sh reload without a binding exits 4 +OK scripts/discord-service.sh without a command exits 4 +OK service unit renders with the repository path, a supervised run as the main process, exit 3 never retried, and reload as SIGHUP +OK service install writes the rendered unit (0644) and leaves no temp file +OK service install a second time reports unchanged +OK systemd-analyze verify accepts the rendered unit +OK service uninstall removes the unit file +OK service install with an unknown flag exits 4 +OK service install with USER unset finishes and names the account for lingering + +discord suite: 66 passed, 0 failed diff --git a/agents/darkwing/work/queue-52-review/r1/out/test-extension-package.txt b/agents/darkwing/work/queue-52-review/r1/out/test-extension-package.txt new file mode 100644 index 00000000..9cbbd9bc --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/test-extension-package.txt @@ -0,0 +1,21 @@ +OK initial ordinary-file install +OK installed tree matches canonical source +OK installed tree has no symlinks +OK check detects installation drift +OK sync refuses to overwrite installation drift +OK check detects an extra destination file +OK check detects an extra destination directory +OK check rejects a destination symlink +OK sync accepts a canonical source update +OK updated installation matches canonical source +scripts/test-extension-package.sh: line 14: 3765482 Killed "$@" > /dev/null 2>&1 +OK forced interruption kills the replacing process +OK next invocation recovers old consistent installation +OK interrupted replacement rolled back +OK sync succeeds after interruption recovery +OK unlocked stale lock file does not block +OK active lock refuses a concurrent sync +OK source symlink fails closed +OK nested second entrypoint fails closed + +extension package selftest: 18 passed, 0 failed diff --git a/agents/darkwing/work/queue-52-review/r1/out/test-foundation.txt b/agents/darkwing/work/queue-52-review/r1/out/test-foundation.txt new file mode 100644 index 00000000..6338e1e6 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/test-foundation.txt @@ -0,0 +1,53 @@ +toolchain: node v26.8.1, python 3.12.8, jsonschema 4.26.0 + +OK syntax: scripts/foundation-inspect.mjs +OK syntax: scripts/foundation/strict-json.mjs +OK syntax: scripts/foundation/canonical.mjs +OK syntax: scripts/foundation/resolve.mjs +OK syntax: scripts/foundation/validate-record.mjs +OK syntax: scripts/foundation/fixtures/build-fixtures.mjs +OK syntax: scripts/foundation/canonical.test.mjs +OK syntax: scripts/foundation/cli.test.mjs +OK syntax: scripts/foundation/fixtures.test.mjs +OK syntax: scripts/foundation/resolve.test.mjs +OK syntax: scripts/foundation/strict-json.test.mjs +OK syntax: scripts/foundation/verify-schema.py (ast only; no bytecode written) +OK fixture generator runs +OK checked-in fixtures/bundles equal a fresh generation +OK checked-in fixtures/raw equal a fresh generation +OK checked-in fixtures/index.json equal a fresh generation +OK checked-in demo bundles equal a fresh generation +OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT +OK node --test scripts/foundation/ (ℹ pass 80) +OK differential schema oracle: PASS: differential schema oracle (finite corpus; compatibility evidence, not equivalence proof) + platform witness: strftime('%Y') for year 999 -> '999' (pinned checker refuses years 0001..0999) + node v26.8.1; corpus 1568 records (38 pinned fixtures, 478 unique bundle records, 1052 typeCase/mutation/lexical cases) + schema column: agree-valid 540, agree-invalid 991, DISAGREEMENTS 0; strict-only (parser-bound) cases: 27; unsupported-kind records not schema-assessed by the inspector: 10 + profile column (schema-valid records only): profile-valid 510, profile-invalid 30 + profile refusals asserted: 30 schema-agreed-valid records refused only by the strict typed-string profile (rule profile-pattern-mismatch), 12 declared by name; 73 named probes verified against declared schema/profile columns +OK oracle: zero schema-column disagreements with the pinned checker +OK oracle: strict-only profile refusals are counted and asserted +OK demo: permitted read preview exits 0 (exit 0) +OK demo: permitted file.change preview exits 0 (exit 0) +OK demo: assignment.change proposal is unresolved (exit 3) (exit 3) +OK demo: revoked registration is refused (exit 3) (exit 3) +OK demo: message is not authority (exit 3) (exit 3) +OK usage: no arguments exits 2 (exit 2) +OK io: missing file exits 4 (exit 4) +OK io: directory exits 4 (exit 4) +OK io: symlink exits 4 (O_NOFOLLOW) (exit 4) +OK bound: oversize fixture exits 2 (exit 2) +OK profile: one final LF in a typed selection id is refused before admission (exit 2) (exit 2) +OK profile: two final LFs fail the schema pattern itself (exit 2) (exit 2) +OK profile: escaped newlines in free-form text stay allowed (exit 0) (exit 0) +OK profile refusal is invalid-request/profile-pattern-mismatch with selection and operation withheld, value not echoed +OK text output starts with the disclaimer +OK json output is valid JSON with result allowed and exactly the charter §7 fields +OK json golden matches byte-for-byte +OK sandboxed bundle run (env -i, PATH=/nonexistent) produced the unresolved proposal +OK sandbox inventory (path/type/size/mode/uid/gid/inode/mtime/sha256) unchanged by runs +OK canary never printed (bundle run and credential-file run) +OK a non-bundle JSON file is refused at the shape gate, not read into output +OK no field of the non-bundle file is echoed + +selftest: 44 passed, 0 failed diff --git a/agents/darkwing/work/queue-52-review/r1/out/test-queue.txt b/agents/darkwing/work/queue-52-review/r1/out/test-queue.txt new file mode 100644 index 00000000..92fcf9dd --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/test-queue.txt @@ -0,0 +1,35 @@ +toolchain: node v26.8.1, git version 2.55.0 + +OK syntax: packages/queue/src/cli.mjs +OK syntax: packages/queue/src/errors.mjs +OK syntax: packages/queue/src/io.mjs +OK syntax: packages/queue/src/lock.mjs +OK syntax: packages/queue/src/queue.mjs +OK syntax: packages/queue/src/review.mjs +OK syntax: packages/queue/src/store.mjs +OK syntax: packages/queue/tests/commit.test.mjs +OK syntax: packages/queue/tests/data.test.mjs +OK syntax: packages/queue/tests/dispatch.test.mjs +OK syntax: packages/queue/tests/helpers.mjs +OK syntax: packages/queue/tests/lock.test.mjs +OK syntax: packages/queue/tests/migration.test.mjs +OK syntax: packages/queue/tests/review.test.mjs +OK syntax: packages/queue/tests/store.test.mjs +OK syntax: packages/queue/tests/write.test.mjs +OK syntax: packages/queue/tests/fixtures/fake-gitea.mjs +OK syntax: packages/queue/tests/fixtures/kill-at.mjs +OK syntax: packages/queue/tests/fixtures/lock-child.mjs +OK syntax: packages/queue/tests/fixtures/mosaic-pre-a2.sh +OK syntax: scripts/queue-commit.sh +OK syntax: scripts/git-hooks/pre-commit +OK syntax: scripts/mosaic +OK queue-commit.sh, the guard and scripts/mosaic are executable +OK packages/queue declares no dependencies +ℹ tests 148 +ℹ pass 148 +ℹ fail 0 +OK node --test packages/queue/tests/ +OK scripts/mosaic queue help +skip queue verify and render --check: this checkout (/home/jwoltje/darkwing-scratch/r52a/wt) is not the queue's canonical root (/mnt/storage/src/mosaic-stack) + +queue suite: 27 passed, 0 failed diff --git a/agents/darkwing/work/queue-52-review/r1/out/test-release-docker.txt b/agents/darkwing/work/queue-52-review/r1/out/test-release-docker.txt new file mode 100644 index 00000000..7202b85d --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/test-release-docker.txt @@ -0,0 +1,16 @@ +OK valid RELEASE resolves (exit 0) +OK invalid RELEASE exits 1 (exit 1) +OK missing RELEASE exits 1 (exit 1) +OK valid RELEASE leaves image tag consistent with version +OK status safe on empty state (exit 0) +OK status created no pointer +OK fault-injected activation refuses (exit 1) +OK refused activation wrote no pointer +OK refusal logged exactly once with valid fields +OK healthy activation succeeds (exit 0) +OK pointer written with valid fields +OK repeat activation succeeds (log grows) (exit 0) +OK log is append-only across activations +OK rollback without previous refuses (exit 1) + +selftest: 14 passed, 0 failed diff --git a/agents/darkwing/work/queue-52-review/r1/out/test-release.txt b/agents/darkwing/work/queue-52-review/r1/out/test-release.txt new file mode 100644 index 00000000..1d6ed050 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/test-release.txt @@ -0,0 +1,7 @@ +OK valid RELEASE resolves (exit 0) +OK invalid RELEASE exits 1 (exit 1) +OK missing RELEASE exits 1 (exit 1) +OK valid RELEASE leaves image tag consistent with version +skip state-machine cases (docker daemon unavailable) + +selftest: 4 passed, 0 failed diff --git a/agents/darkwing/work/queue-52-review/r1/out/test-task.txt b/agents/darkwing/work/queue-52-review/r1/out/test-task.txt new file mode 100644 index 00000000..85aa46f0 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/r1/out/test-task.txt @@ -0,0 +1,33 @@ +OK valid task validates (exit 0) +OK unknown task key exits 2 (exit 2) +OK unsupported taskVersion exits 2 (exit 2) +OK invalid task id exits 2 (exit 2) +OK empty prompt exits 2 (exit 2) +OK NUL in expectExact exits 2 (exit 2) +OK out-of-range timeout exits 2 (exit 2) +OK missing mission file exits 4 (exit 4) +OK task with valid mission validates (exit 0) +OK invalid mission exits 2 (exit 2) +OK validate missing task exits 4 (exit 4) +OK validation does not modify the task file +OK prune dry-run exits 0 (exit 0) +OK dry-run deleted nothing +OK prune --keep=2 --yes removes oldest (exit 0) +OK kept exactly 2 newest runs +OK newest run kept, oldest pruned +OK append-only receipt written (3 entries) +OK sessions/workspaces untouched by prune +OK prune with invalid keep exits 4 (exit 4) +skip adapter seam cases (docker daemon unavailable) +skip workspace/capability cases (docker daemon unavailable) +skip live task cases (docker unavailable) +OK onboard without name exits 4 (non-interactive) (exit 4) +OK onboard --name renders profile (exit 0) +OK profile written +OK canon structure: required filled, optional placeholdered +OK canon sections present +FAIL user recall run succeeds (exit 1) +FAIL recalled user name (response: ) +OK no agent identity on headless run + +selftest: 26 passed, 2 failed diff --git a/agents/darkwing/work/queue-52-review/review-r1.md b/agents/darkwing/work/queue-52-review/review-r1.md new file mode 100644 index 00000000..2cc8e0e9 --- /dev/null +++ b/agents/darkwing/work/queue-52-review/review-r1.md @@ -0,0 +1,200 @@ +# Row 52, CHAT-01 engine-exit stop, round 1 review (Darkwing) + +Issue #1538, request comment 27085, notes comment 27086, queue revs +310-312. Base `cc83ee4f` (CHAT-01, local, not pushed). Candidate manifest +sha256 +`deac74341448e8e4560b2cc6418b55fbdcf3e68aa6963211ac7040af49d33d73`, +6 files. Filbert reviewed in parallel (27087, rev 313); I wrote this +before reading theirs. + +Verdict: **approve**, on these four CHAT-01 files at `cc83ee4f`: + +``` +a41fc4e2edb11371c275e3167774c162254e1457fd737121630dedd665431889 docs/plans/chat-01/README.md +ccceaf2653b279f5890748b40d16fae7493f199a33cecee035f82b92e80243af docs/plans/chat-01/check.mjs +941675de949c52c7fe7c4b7bcce3aff48bb26ccc1120e090574c5d25f9d9e22e docs/plans/chat-01/contracts.schema.json +c75c2b9f731bb70d0e033e8aa56f2c28accfa09384ec964fd3ecbd45974b2a7d docs/plans/chat-01/fixtures.json +``` + +All four points from my brief hold in the model and in the controller, and +a test fails when each one is taken away. Two of Dewey's five "equivalent" +survivors I'd call untested guards rather than equivalents, and I found +three more guards no test reaches. None of that blocks the row. Notes +below. + +## Method + +- I checked the four CHAT-01 hashes in the canonical tree against Dewey's + list (all match) and read the `cc83ee4f` diff in full. +- Detached worktree at `cc83ee4f`, the six candidate files copied from a + snapshot of the canonical tree, then `sha256sum -c`: 6 OK. A second + worktree for the mutants; its files still check OK after all runs + (`r1/mut/manifest-after.txt`). +- I read the candidate diff in full (`cohort.mjs`, `controller.mjs`, + `shim.mjs`, E1-E6, the README), plus the parts of the controller it + touches: `#transport`, `#uncertain`, the force-stop branch and its + `escalating` slot, `#serveOrphan`, and the claim chain. +- 13 conversation mutants (`r1/mut/mutate.py`, `run.sh`): a base run, + Dewey's five survivors rewritten from the packet's descriptions, and seven + of mine. Whole conversation suite each, own TMPDIR each, one at a time + after the gate. No mutant left a shim, and no `mosaic-chat-*` unit was + listed at the end. +- Two model mutants of my own on scratch copies of `check.mjs`. + +Node v26.8.1, `TMPDIR=~/darkwing-scratch/r52a/tmp`, `gate.sh` with +`DOCKER_HOST=unix:///nonexistent.sock`, 08:04:09Z to 08:07:47Z, then +control-board, queue (node) and the CHAT-01 check. Mutants 08:08:23Z to +08:21:31Z. `test-release` with Docker after that. + +## Suites + +| Suite | Result | +|---|---| +| `node docs/plans/chat-01/check.mjs` | PASS: 100 shape, 76 reference, 22 lifecycle | +| conversation | 182/0 | +| webui | 22/0 | +| control-board | 124/0 | +| queue (node) | 148/0 | +| test-auth | 15/0 | +| test-conductor | 17/0 | +| test-config | 24/0 | +| test-discord | 66/0 | +| test-extension-package | 18/0 | +| test-foundation | 44/0 | +| test-queue | 27/0 | +| test-release | 4/0 without Docker, 14/0 with it (`test-release-docker.txt`) | +| test-task | 26/2 | + +The two `test-task` failures are "user recall run succeeds" and "recalled +user name", the live worker check that needs Docker and a model call, as in +row 51. Dewey's 98/0 ran them. The gate's last line counts two +`mosaic-chat-*` units at 08:07:47Z. Both counts right after the +conversation and webui suites were zero, so they weren't from those runs; I +think they were another seat's test run, but I can't show that. None was +listed at 08:21:31Z. Filbert saw two scopes from my run directory at about +08:15Z: that's the `noinv` mutant's suite, which ran 08:15:40Z to 08:16:38Z +and left no shim. + +## The four points + +1. **Never supersede an unfinished force stop.** Model: `engine-exit` + refuses `stop-owned` when the current stop's mode is `force-stop` or + `engine-exit`, in any state, and the + `engine-exit-refused-during-force-stop` sequence walks the four + force-stop states. Controller: `#engineExit` (`controller.mjs:1550`) + returns before `#startStop` while `escalating` is held or the current + stop is ending. E3's second half (a force stop held at + `force-stop-recorded`) and E5 (a force stop that ended `uncertain` + before it closed the execution) pin it; Dewey's `noowncheck` and + `nostopcheck` die there. My model mutant `second` (refuse only under a + force stop, so a second engine exit goes through) dies in + `engine-exit-empty-cohort-stopped`, which sends a second engine exit + after the first is proven. +2. **The binding follows the stop.** The model uses `ending` at + `startStop`, `advance-stop` and `confirm-stopped`, and + `engine-exit-binding-follows-stop` checks each. The controller uses the + same `ending` in `#startStop` and `#advanceStop`, and + `#endStopUncertain` and `#stopProven` set the binding themselves. That + double path is why `bindadvance` survives alone. My `bindboth` + (`bindadvance` plus `#endStopUncertain` not setting the binding) dies on + E2 and E4, so the `uncertain` half is pinned. E3 pins `stopping` at the + fence. +3. **The proof names the engine.** The shim reads the engine's start ticks + right after spawn and records `{ code, signal, at, pid, startTicks, + boot }` in its exit handler (`shim.mjs:77`). `engineExitCohort` + (`cohort.mjs:219`) refuses a reaped process whose PID, start ticks or + boot differ, then proves with one member: the engine, with the reap time + as `terminatedAt`. E1 compares the member list exactly. The model's + `stopped()` and the controller's `#stopped` both refuse an `engine-exit` + proof with no member. `nopidcmp` and `nostartcmp` each die on E6, so + both halves of the identity check are pinned, not just the pair. +4. **A deadline that frees the slot.** The observation runs under + `within(..., this.T.exitProof)` and `finally` frees `escalating` + (`controller.mjs:1567`). E4 SIGSTOPs the shim, sees the stop end + `uncertain` with the deadline's reason and `escalating` null, then + proves a force stop after SIGCONT. Note 1 is about what E4 can and + can't tell apart. + +The claim: an engine exit writes no `stopping` claim, so a restart finds an +`uncertain` orphan and `#serveOrphan` resumes no stop (`resumeStop` needs +claim state `stopping`). `#transport`'s `uncertain` claim write and +`#stopProven`'s `stopped` write both go through `claimChain`, so the +`stopped` write can't land first. + +## Mutants + +| Mutant | Change | Conversation | Result | +|---|---|---|---| +| base | none | 182/0 | | +| noslotcheck | EOF ignores a held slot | 182/0 | survives: equivalent, agreed | +| bindadvance | `#advanceStop` moves the binding only for a force stop | 182/0 | survives: equivalent, agreed | +| emptyguard | `#stopped` accepts an engine-exit proof with no member | 182/0 | survives: equivalent alone, agreed | +| nopopulated | a populated `engine` cgroup proves | 182/0 | survives: see note 2 | +| nomembers | a listed member proves | 182/0 | survives: see note 2 | +| bindboth | `bindadvance` plus `#endStopUncertain` not setting the binding | 180/2 | killed: E2, E4 | +| noinv | the engine-exit observation skips the invocation ID check | 182/0 | survives: note 3 | +| noscope | it skips the hello's scope check | 182/0 | survives: note 3 | +| nopidcmp | the identity check skips the PID | 181/1 | killed: E6 | +| nostartcmp | it skips the start ticks | 181/1 | killed: E6 | +| noboot | it skips the boot (Dewey's follow-up) | 182/0 | survives: note 3 | +| noadvance | the engine-exit stop never moves `fenced` to `stopping` | 182/0 | survives: note 4 | + +Model mutants (`r1/model/`): `second` (an engine exit refused only under a +force stop) fails `engine-exit-empty-cohort-stopped`; `working` +(`working` input moved to `delivery-unknown` too) fails +`engine-exit-stale-confirmation-dispatched-receipt`. Both killed. + +On the three equivalents I agree with: `escalating` is set only for the +current force stop (`controller.mjs:726`, `#forceStop`) or the engine-exit +stop itself, and the resumed force stop in `#serveOrphan` has no engine +pipe, so `#onEnd` can't run beside it. The binding is `stopping` from the +fence on, and interrupt (`controller.mjs:742`) and revocation +(`controller.mjs:1758`) need it `active`. `emptyguard` is +reachable only through a second fault. + +## Notes (not blocking) + +1. E4 tells the deadline apart from `shimRequest`'s own 3000 ms timeout + only by the reason text. A SIGSTOPped shim also fails `hello` after 3 s + without `within`, so the slot would still come free; `nodeadline` dies on + E4's `/deadline/` match, not on a held slot. That's fine: the match + shows the deadline fired first. `within` is what caps the loop. One pass + can spend three 3 s requests, and the settle check runs only between + passes. `systemctlShow` is a `spawnSync` with a 5 s timeout that the + deadline can't preempt. `forceStopCohort` does the same, so this isn't + new. +2. `nopopulated` and `nomembers`: I accept the race argument as far as it + goes. The shim's `members` walks the `engine` cgroup that `populated` + reports on, so the two reads disagree only if a process starts or exits + between them. I'd call them untested guards rather than equivalents, + though: `nolive` shows a test needs both gone. A fake `members` answer + (the K15 shapes, Dewey's second follow-up) would pin each one. +3. Three checks in `engineExitCohort` that no test reaches: the + invocation ID against `systemctl show`, the hello's `scope` against the + unit's control group, and the boot (Dewey already lists the boot). All + three fail closed when they fire. The first two guard against a scope of + the same name from another invocation. `forceStopCohort` has the same + checks; I didn't look at whether its tests reach them. I'd fold these + into Dewey's K15 follow-up. +4. `noadvance` survives. Without the advance, an engine-exit stop goes + `fenced` to `stopped` or `fenced` to `uncertain`. The model's + `confirm-stopped` and `advance-stop` allow both, so it isn't a model + violation; a client just never sees the stop in `stopping`. The force + stop makes the same advance, and keeping the two paths alike is reason + enough to keep it. No test needed. +5. At EOF the binding goes `uncertain` first (`#transport`), then + `stopping` when `#startStop` runs. Clients see an `uncertain` event, then + `stopping`. The model has no EOF step before `engine-exit`, so there's + nothing to compare it to. I'd mention the order in the README if it ever + confuses a client. +6. Dewey's follow-ups (the pgroup fallback's untested natural exit, the + K15 shapes on this path) stand. I'd file them with notes 2 and 3 as one + issue. + +## Files + +- `r1/candidate-manifest.sha256`: copy of Dewey's. +- `r1/gate.sh`, `r1/out/`: suite runs, the CHAT-01 check and `summary.txt`. +- `r1/mut/`: mutant definitions, runner, per-mutant output and shims-left + lists, `summary.txt`, and the manifest check after the runs. +- `r1/model/`: the two model mutants' outputs.