From 3b5024216f45cb5519c6a0e32e10046967d92861 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Fri, 9 Oct 2026 23:06:17 -0500 Subject: [PATCH] docs(review): row 47 round 1 review packet, approve (darkwing) Co-Authored-By: Claude Opus 5.5 --- .../r1/candidate-manifest.sha256 | 6 + .../work/queue-47-review/r1/files.txt | 6 + .../darkwing/work/queue-47-review/r1/gate.sh | 17 ++ .../r1/mut/Mr-conversation.txt | 196 +++++++++++++++ .../queue-47-review/r1/mut/Mr-shims-left.txt | 1 + .../r1/mut/afterleak-conversation.txt | 228 ++++++++++++++++++ .../r1/mut/afterleak-shims-left.txt | 1 + .../r1/mut/h22noreap-conversation.txt | 205 ++++++++++++++++ .../r1/mut/h22noreap-shims-left.txt | 1 + .../r1/mut/h23noreap-conversation.txt | 173 +++++++++++++ .../r1/mut/h23noreap-shims-left.txt | 1 + .../r1/mut/k19leak-conversation.txt | 200 +++++++++++++++ .../r1/mut/k19leak-shims-left.txt | 1 + .../queue-47-review/r1/mut/manifest-after.txt | 6 + .../work/queue-47-review/r1/mut/mutate.py | 33 +++ .../r1/mut/noprobe-conversation.txt | 200 +++++++++++++++ .../r1/mut/noprobe-shims-left.txt | 1 + .../r1/mut/now13-conversation.txt | 200 +++++++++++++++ .../r1/mut/now13-shims-left.txt | 1 + .../r1/mut/reapnosweep-conversation.txt | 173 +++++++++++++ .../r1/mut/reapnosweep-shims-left.txt | 1 + .../work/queue-47-review/r1/mut/run.sh | 22 ++ .../work/queue-47-review/r1/mut/summary.txt | 13 + .../r1/mut/sweeponly-conversation.txt | 200 +++++++++++++++ .../r1/mut/sweeponly-shims-left.txt | 1 + .../r1/mut/sweeppid-conversation.txt | 200 +++++++++++++++ .../r1/mut/sweeppid-shims-left.txt | 1 + .../r1/out/node-conversation.txt | 173 +++++++++++++ .../queue-47-review/r1/out/node-webui.txt | 31 +++ .../work/queue-47-review/r1/out/summary.txt | 13 + .../work/queue-47-review/r1/out/test-auth.txt | 17 ++ .../queue-47-review/r1/out/test-conductor.txt | 55 +++++ .../queue-47-review/r1/out/test-config.txt | 26 ++ .../queue-47-review/r1/out/test-discord.txt | 70 ++++++ .../r1/out/test-extension-package.txt | 21 ++ .../r1/out/test-foundation.txt | 53 ++++ .../queue-47-review/r1/out/test-queue.txt | 35 +++ .../r1/out/test-release-docker.txt | 16 ++ .../queue-47-review/r1/out/test-release.txt | 7 + .../work/queue-47-review/r1/out/test-task.txt | 33 +++ .../work/queue-47-review/review-r1.md | 158 ++++++++++++ 41 files changed, 2796 insertions(+) create mode 100644 agents/darkwing/work/queue-47-review/r1/candidate-manifest.sha256 create mode 100644 agents/darkwing/work/queue-47-review/r1/files.txt create mode 100755 agents/darkwing/work/queue-47-review/r1/gate.sh create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/Mr-conversation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/Mr-shims-left.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/afterleak-conversation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/afterleak-shims-left.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/h22noreap-conversation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/h22noreap-shims-left.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/h23noreap-conversation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/h23noreap-shims-left.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/k19leak-conversation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/k19leak-shims-left.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/manifest-after.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/mutate.py create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/noprobe-conversation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/noprobe-shims-left.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/now13-conversation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/now13-shims-left.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/reapnosweep-conversation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/reapnosweep-shims-left.txt create mode 100755 agents/darkwing/work/queue-47-review/r1/mut/run.sh create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/summary.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/sweeponly-conversation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/sweeponly-shims-left.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/sweeppid-conversation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/mut/sweeppid-shims-left.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/node-conversation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/node-webui.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/summary.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/test-auth.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/test-conductor.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/test-config.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/test-discord.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/test-extension-package.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/test-foundation.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/test-queue.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/test-release-docker.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/test-release.txt create mode 100644 agents/darkwing/work/queue-47-review/r1/out/test-task.txt create mode 100644 agents/darkwing/work/queue-47-review/review-r1.md diff --git a/agents/darkwing/work/queue-47-review/r1/candidate-manifest.sha256 b/agents/darkwing/work/queue-47-review/r1/candidate-manifest.sha256 new file mode 100644 index 00000000..2721c6e8 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/candidate-manifest.sha256 @@ -0,0 +1,6 @@ +dfd9be08c4a31ee536bbcd9bfd8e73cd8baa4114086b55845627ea0c97023e2a agents/dewey/work/queue-47/evidence.md +061ca09644d03690c92b2d09f3b13d407f194fe0b590125692c359d10bace395 packages/conversation/tests/claim.test.mjs +9bb32c730e6fd1d6648ff623cd6ded71cda300ede2d618e28ee6b682626d4d01 packages/conversation/tests/cohort.test.mjs +896f09586916ffdb399b2b5bd04770473a6dd62938d1e9cc0a7e0239f32a36ef packages/conversation/tests/flows.test.mjs +ca003075749dec9368c91f282c8218d602eeb8c6290282a884876be5af2d87e6 packages/conversation/tests/harness.mjs +2ae5d7b8119f29654e1672d1948992be79e973049a50da99250de7ade26b2071 packages/conversation/tests/races.test.mjs diff --git a/agents/darkwing/work/queue-47-review/r1/files.txt b/agents/darkwing/work/queue-47-review/r1/files.txt new file mode 100644 index 00000000..ecc535a9 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/files.txt @@ -0,0 +1,6 @@ +agents/dewey/work/queue-47/evidence.md +packages/conversation/tests/claim.test.mjs +packages/conversation/tests/cohort.test.mjs +packages/conversation/tests/flows.test.mjs +packages/conversation/tests/harness.mjs +packages/conversation/tests/races.test.mjs diff --git a/agents/darkwing/work/queue-47-review/r1/gate.sh b/agents/darkwing/work/queue-47-review/r1/gate.sh new file mode 100755 index 00000000..e2265c05 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/gate.sh @@ -0,0 +1,17 @@ +#!/bin/bash +export TMPDIR=~/darkwing-scratch/r47a/tmp DOCKER_HOST=unix:///nonexistent.sock +cd ~/darkwing-scratch/r47a/wt +O=~/darkwing-scratch/r47a/out +: > $O/summary.txt +shims() { ps -eo pid,args | grep -F "$TMPDIR" | grep -F shim.mjs | grep -v grep | wc -l; } +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)" >> $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 "shims-left-end=$(shims)" >> $O/summary.txt +echo DONE >> $O/summary.txt diff --git a/agents/darkwing/work/queue-47-review/r1/mut/Mr-conversation.txt b/agents/darkwing/work/queue-47-review/r1/mut/Mr-conversation.txt new file mode 100644 index 00000000..f9d335d3 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/Mr-conversation.txt @@ -0,0 +1,196 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (230.761469ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (35.283345ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (19.246256ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (666.451415ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (419.502539ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (259.427764ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (243.237404ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (216.032408ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.493472ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12101.571707ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (35852.52336ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (364.603499ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (157.89886ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (696.888506ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (353.745861ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (432.046961ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (176.123441ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (237.115041ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (443.951742ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (1335.729283ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (399.160544ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (128.725923ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (69.244187ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.523388ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.102658ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.859532ms) +✔ no shim from this file's tests is left running for the after hook (25.021175ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (2907.900269ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (662.084573ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (2648.481561ms) +✔ K4: two engines; force stop one; the other survives by independent observation (4971.590724ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (2671.091036ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (2543.899927ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (2497.760482ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5061.043083ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (944.475903ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (579.802852ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (510.816848ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (853.259964ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (570.67324ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (748.384126ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3374.04811ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (27.290911ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (633.85929ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (650.888402ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (103.278418ms) +✔ no shim from this file's tests is left running for the after hook (26.447839ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (219.066131ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (486.569612ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (237.738849ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (344.619515ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (230.932458ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.452415ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (242.54138ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (326.810099ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (250.642243ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (222.955355ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (302.713109ms) +✔ 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 (343.538094ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.0646ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (302.801926ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (249.456734ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (315.374632ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (225.411308ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.373986ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.257853ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.32094ms) +✔ 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.481082ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.859499ms) +✖ 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) (1.169348ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (6.289639ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.414834ms) +✔ 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.419486ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.101127ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (224.439992ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (265.687996ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (602.750029ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (980.633425ms) +✔ H4: self-takeover is refused (211.637746ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (506.871423ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1488.148474ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (257.919317ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (807.188663ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (345.183361ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (230.52151ms) +✔ H13: a retry with the same request ID and different text is refused (187.355213ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (695.840348ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (392.932221ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (219.444268ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (986.019029ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (368.285501ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (809.335038ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (217.250935ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (337.785107ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.629978ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (681.233021ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (588.806469ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (712.524709ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2943.496164ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (678.292339ms) +✔ no shim from this file's tests is left running for the after hook (26.16412ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (8.500467ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (2.946212ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (3.038266ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (3.460723ms) +✔ F1: an unreadable fork is never merged into another branch's history (2.377455ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (3.037382ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (1.323094ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (2.118799ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (5.420763ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (6.4095ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (5.711012ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (6.202576ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (8.351461ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.80748ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.879545ms) +✔ F9: registrations never add or redirect a root (1.819782ms) +✔ F10: a header cwd naming another project is refused (4.267714ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.734978ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.160641ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.942174ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.400315ms) +✔ F13: compaction is a marker in place, then the retained content (0.72091ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (541.577382ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.290547ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.426317ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.189166ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.018126ms) +✔ a seat directory without search permission refuses that root, not the catalogue (1.785298ms) +✔ every page and cursor is a valid CHAT-01 record (734.907993ms) +✔ the engine pin holds for the installed package (3.14919ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (289.737014ms) +✔ 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) (607.426468ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (240.104396ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (819.982387ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (520.700411ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (292.365153ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (20.764736ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (410.320626ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (234.058416ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (327.369494ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (752.757501ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1969.460632ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (228.669663ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (312.846973ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (221.554358ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (269.807001ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (554.763895ms) +✔ N10: fake conformance (32.742057ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (465.53822ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (311.07635ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (366.274019ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (379.816865ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (381.8195ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (380.794236ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (215.48326ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (368.478508ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (764.711894ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (601.979351ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (519.115829ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (210.54534ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (191.338939ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (189.870649ms) +✔ 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 (237.835355ms) +✔ 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 (157.620797ms) +ℹ tests 165 +ℹ suites 0 +ℹ pass 164 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 58028.081921 + +✖ failing tests: + +test at packages/conversation/tests/flows.test.mjs:714:1 +✖ 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) (1.169348ms) + AssertionError [ERR_ASSERTION]: ["\u0014","\u000f","hi\r"] + + actual - expected + + + [] + - [ + - 'hi' + - ] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/flows.test.mjs:726:12) + 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: [], + expected: [ 'hi' ], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-47-review/r1/mut/Mr-shims-left.txt b/agents/darkwing/work/queue-47-review/r1/mut/Mr-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/Mr-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-47-review/r1/mut/afterleak-conversation.txt b/agents/darkwing/work/queue-47-review/r1/mut/afterleak-conversation.txt new file mode 100644 index 00000000..22188977 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/afterleak-conversation.txt @@ -0,0 +1,228 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (253.899662ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (33.284113ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (19.860532ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (734.363814ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (524.38725ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (252.799759ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (222.741713ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (234.15361ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.493404ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12258.436675ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (32349.669618ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (272.642236ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (147.477768ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (480.56355ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (338.33334ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (399.586115ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (149.751919ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (236.949804ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (387.390616ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (1038.478309ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (237.992787ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (119.660597ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (80.974265ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.444071ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.109812ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.86441ms) +✖ no shim from this file's tests is left running for the after hook (5035.26209ms) +✖ /home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/claim.test.mjs (5043.339958ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (3302.420094ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (472.970914ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (2796.728057ms) +✔ K4: two engines; force stop one; the other survives by independent observation (5105.353597ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (2543.819351ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (2510.616024ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (2475.701534ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5063.223619ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (771.359208ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (645.101545ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (506.62451ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (829.124385ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (420.127538ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (685.425895ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3650.969116ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (50.323904ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (469.843386ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (401.628845ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (83.176682ms) +✔ no shim from this file's tests is left running for the after hook (28.57982ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (249.951436ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (230.734553ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (529.84075ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (468.686749ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (237.030606ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.410276ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (217.020169ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (315.308644ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (240.266481ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (216.341803ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (277.942621ms) +✔ 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 (211.881183ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.956364ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (209.424433ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (233.942839ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (240.21204ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (202.309814ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.473741ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.344905ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.345713ms) +✔ 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.509785ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (31.230161ms) +✔ 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.535526ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.767751ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.427819ms) +✔ 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.374154ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.124458ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (253.515467ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (294.243499ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (643.849856ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (1035.077009ms) +✔ H4: self-takeover is refused (220.514251ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (513.050569ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1044.31887ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (200.880629ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (646.165518ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (299.259321ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (204.891687ms) +✔ H13: a retry with the same request ID and different text is refused (210.61934ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (608.700028ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (293.875373ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (207.822911ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (907.20909ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (383.22996ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (780.261155ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (314.578713ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (492.689541ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.638149ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (745.520193ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (614.542673ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (775.55878ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2983.804441ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (663.639159ms) +✔ no shim from this file's tests is left running for the after hook (29.149662ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.901379ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (2.757561ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (3.006657ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (4.500776ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.961886ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.558189ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (1.380572ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (2.109752ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.787822ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.931861ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (5.60544ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (5.016363ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (7.376863ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (9.418495ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (2.608935ms) +✔ F9: registrations never add or redirect a root (2.387521ms) +✔ F10: a header cwd naming another project is refused (4.782722ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.704275ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.158477ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.217859ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.398999ms) +✔ F13: compaction is a marker in place, then the retained content (0.772587ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (562.681896ms) +✔ fragments never cut a surrogate pair and keep an empty string (5.139319ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.62126ms) +✔ unknown conversations, empty files and non-Pi files refuse (3.23556ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.209457ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.226314ms) +✔ every page and cursor is a valid CHAT-01 record (787.451304ms) +✔ the engine pin holds for the installed package (2.048735ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (285.366263ms) +✔ 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) (579.211254ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (272.40564ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (577.591802ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (946.761723ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (282.830757ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.001149ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (399.29855ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (230.660155ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (301.688325ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (545.551867ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1879.973217ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (206.93602ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (301.335987ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (216.121148ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (246.935251ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (338.923698ms) +✔ N10: fake conformance (32.84403ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (463.157846ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (304.192068ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (300.327975ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (383.033758ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (376.977901ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (372.577696ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (279.493416ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (661.735582ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (826.188509ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (576.149478ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (487.44522ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (249.137762ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (216.081275ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (213.406251ms) +✔ 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 (229.431708ms) +✔ 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 (235.869084ms) +ℹ tests 166 +ℹ suites 0 +ℹ pass 164 +ℹ fail 2 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 60982.361112 + +✖ failing tests: + +test at packages/conversation/tests/claim.test.mjs:714:1 +✖ no shim from this file's tests is left running for the after hook (5035.26209ms) + AssertionError [ERR_ASSERTION]: a test left its shim running + + actual - expected + + + [ + + { + + pid: 3459119, + + socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-afterleak/chat03-lQNQDH/f55/sock/shim-cede1ee324e5.sock', + + unit: 'mosaic-chat-cede1ee324e5b263ef2671152' + + } + + ] + - [] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/claim.test.mjs:715:10) + 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: [ { pid: 3459119, socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-afterleak/chat03-lQNQDH/f55/sock/shim-cede1ee324e5.sock', unit: 'mosaic-chat-cede1ee324e5b263ef2671152' } ], + expected: [], + operator: 'deepStrictEqual', + diff: 'simple' + } + +test at packages/conversation/tests/claim.test.mjs:28:1 +✖ /home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/claim.test.mjs (5043.339958ms) + AssertionError [ERR_ASSERTION]: no shim outlives this file (#1533) + + actual - expected + + + [ + + { + + pid: 3459119, + + socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-afterleak/chat03-lQNQDH/f55/sock/shim-cede1ee324e5.sock', + + unit: 'mosaic-chat-cede1ee324e5b263ef2671152' + + } + + ] + - [] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/claim.test.mjs:32:10) + at async TestHook.run (node:internal/test_runner/test:1409:7) + at async Test.runHook (node:internal/test_runner/test:1289:9) + at async after (node:internal/test_runner/test:1342:9) + at async Test.run (node:internal/test_runner/test:1428:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: [ { pid: 3459119, socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-afterleak/chat03-lQNQDH/f55/sock/shim-cede1ee324e5.sock', unit: 'mosaic-chat-cede1ee324e5b263ef2671152' } ], + expected: [], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-47-review/r1/mut/afterleak-shims-left.txt b/agents/darkwing/work/queue-47-review/r1/mut/afterleak-shims-left.txt new file mode 100644 index 00000000..1ab4cf4d --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/afterleak-shims-left.txt @@ -0,0 +1 @@ +3459119 /usr/bin/node /home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/src/shim.mjs --socket /home/jwoltje/darkwing-scratch/r47a/tmp/mut-afterleak/chat03-lQNQDH/f55/sock/shim-cede1ee324e5.sock -- /usr/bin/node /home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/fake-pi.mjs --mode rpc --no-extensions --no-prompt-templates --no-themes --no-approve --session /home/jwoltje/darkwing-scratch/r47a/tmp/mut-afterleak/chat03-lQNQDH/f55/proj/.pi/state/fixture-seat/sessions/s1.jsonl diff --git a/agents/darkwing/work/queue-47-review/r1/mut/h22noreap-conversation.txt b/agents/darkwing/work/queue-47-review/r1/mut/h22noreap-conversation.txt new file mode 100644 index 00000000..203fb5ac --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/h22noreap-conversation.txt @@ -0,0 +1,205 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (197.049296ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (30.2567ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (17.869101ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (345.31181ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (422.999536ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (331.462139ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (269.896862ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (226.565456ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.459269ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (11410.993529ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (33468.852499ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (278.035112ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (156.636284ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (648.670807ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (282.454964ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (359.105989ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (98.174892ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (200.317068ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (257.96069ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (719.726591ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (173.907622ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (88.540111ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (69.986196ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.40838ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.037676ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.732583ms) +✔ no shim from this file's tests is left running for the after hook (25.039017ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (2950.569631ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (451.497915ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (2781.966793ms) +✔ K4: two engines; force stop one; the other survives by independent observation (4839.738336ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (2514.094444ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (2517.229628ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (2437.649908ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5021.280751ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (959.412745ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (554.748075ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (598.302911ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (646.325558ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (328.297709ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (524.693662ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3271.735696ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (33.382515ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (360.808345ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (361.996968ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (82.528117ms) +✔ no shim from this file's tests is left running for the after hook (28.074449ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (194.578162ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (188.929563ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (186.630794ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (310.239901ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (250.607896ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.453839ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (325.324105ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (366.090081ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (225.087215ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (192.31515ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (209.298056ms) +✔ 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 (218.342388ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.97722ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (207.199358ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (226.432261ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (251.463208ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (201.15355ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.426921ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.272057ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.326321ms) +✔ 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.493318ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.929698ms) +✔ 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.489135ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.824779ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.428027ms) +✔ 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.351569ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.110321ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (237.286641ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (230.878494ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (277.834974ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (1060.632333ms) +✔ H4: self-takeover is refused (224.791538ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (446.212191ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1052.06213ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (231.205097ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (660.604274ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (278.293002ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (207.032141ms) +✔ H13: a retry with the same request ID and different text is refused (196.251993ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (727.62471ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (370.396901ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (192.209941ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (876.947035ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (321.051889ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (758.666111ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (360.368072ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (335.060909ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.612822ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (661.027296ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (566.594343ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (708.560077ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2938.033537ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (655.993875ms) +✖ no shim from this file's tests is left running for the after hook (5056.941433ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (9.45792ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (2.653489ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (2.771711ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (3.721783ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.744085ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.950975ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (1.033733ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.299469ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (4.631965ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.083972ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.777326ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.450746ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (7.504334ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (11.504271ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (2.590604ms) +✔ F9: registrations never add or redirect a root (2.60161ms) +✔ F10: a header cwd naming another project is refused (5.312424ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.833801ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.576443ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.031185ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.540383ms) +✔ F13: compaction is a marker in place, then the retained content (1.055277ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (495.761506ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.530977ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.508889ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.332009ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.215739ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.130551ms) +✔ every page and cursor is a valid CHAT-01 record (791.701227ms) +✔ the engine pin holds for the installed package (2.128908ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (263.839834ms) +✔ 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) (503.901361ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (264.144541ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (460.491405ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (459.366987ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (331.634788ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (20.888495ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (490.102814ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (213.93758ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (293.015714ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (477.191806ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1888.727614ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (203.998308ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (316.971117ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (282.097455ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (256.140276ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (477.083588ms) +✔ N10: fake conformance (32.934542ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (450.496013ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (281.090048ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (298.332038ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (355.356665ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (358.037348ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (524.641792ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (195.587322ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (285.42895ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (632.572932ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (497.638133ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (464.937522ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (222.460525ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (153.565035ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (166.396372ms) +✔ 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.677414ms) +✔ 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 (248.72541ms) +ℹ tests 165 +ℹ suites 0 +ℹ pass 164 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 53159.579855 + +✖ failing tests: + +test at packages/conversation/tests/races.test.mjs:902:1 +✖ no shim from this file's tests is left running for the after hook (5056.941433ms) + AssertionError [ERR_ASSERTION]: a test left its shim running + + actual - expected + + + [ + + { + + pid: 3568275, + + socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-h22noreap/chat03-9zq6wq/f33/sock/shim-cfdfa3433345.sock', + + unit: 'mosaic-chat-cfdfa3433345b9db00c5d3051' + + }, + + { + + pid: 3568508, + + socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-h22noreap/chat03-9zq6wq/f33/sock/shim-cd552eea1f4f.sock', + + unit: 'mosaic-chat-cd552eea1f4f3842f83cdde65' + + } + + ] + - [] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/races.test.mjs:903:10) + 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: [ { pid: 3568275, socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-h22noreap/chat03-9zq6wq/f33/sock/shim-cfdfa3433345.sock', unit: 'mosaic-chat-cfdfa3433345b9db00c5d3051' }, { pid: 3568508, socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-h22noreap/chat03-9zq6wq/f33/sock/shim-cd552eea1f4f.sock', unit: 'mosaic-chat-cd552eea1f4f3842f83cdde65' } ], + expected: [], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-47-review/r1/mut/h22noreap-shims-left.txt b/agents/darkwing/work/queue-47-review/r1/mut/h22noreap-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/h22noreap-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-47-review/r1/mut/h23noreap-conversation.txt b/agents/darkwing/work/queue-47-review/r1/mut/h23noreap-conversation.txt new file mode 100644 index 00000000..082336e6 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/h23noreap-conversation.txt @@ -0,0 +1,173 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (210.899084ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (29.31549ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (17.448014ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (343.333366ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (402.030356ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (229.874766ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (225.367275ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (235.538338ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.510001ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (11107.098528ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (34234.25014ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (257.480277ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (143.029294ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (640.332526ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (280.540927ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (344.303521ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (100.06914ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (193.668152ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (260.464092ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (719.818824ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (176.592675ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (84.681532ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (68.297527ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.391231ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.076531ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.691738ms) +✔ no shim from this file's tests is left running for the after hook (24.993244ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (2926.997693ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (457.071569ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (2764.632052ms) +✔ K4: two engines; force stop one; the other survives by independent observation (4847.049015ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (2624.498105ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (2504.544818ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (2404.966985ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5364.683799ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (760.038648ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (786.324974ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (488.827654ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (648.931098ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (535.972437ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (721.376017ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3325.570656ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (21.89574ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (369.227467ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (361.962609ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (85.614309ms) +✔ no shim from this file's tests is left running for the after hook (26.492113ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (200.045294ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (185.609228ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (183.997293ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (339.6938ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (186.03016ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.412374ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (172.208693ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (328.732036ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (228.009808ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (195.782075ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (215.719368ms) +✔ 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 (212.909605ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.147188ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (201.279039ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (220.788048ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (250.112806ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (194.326465ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.405847ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.253462ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.309444ms) +✔ 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.464404ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (31.10644ms) +✔ 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.456697ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.716844ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.439276ms) +✔ 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.339054ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.102817ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (219.772943ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (247.163097ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (270.012137ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (771.823938ms) +✔ H4: self-takeover is refused (243.410382ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (456.213319ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1034.647794ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (233.37577ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (707.537006ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (265.35379ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (194.180998ms) +✔ H13: a retry with the same request ID and different text is refused (182.89918ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (540.720156ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (289.805567ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (188.196907ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (876.45361ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (364.162773ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (740.85462ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (196.962746ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (339.055104ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.612248ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (682.735127ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (554.789216ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (707.976793ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2900.763338ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (558.159465ms) +✔ no shim from this file's tests is left running for the after hook (26.551198ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (5.823937ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.618154ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (2.043225ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.654588ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.853218ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.892136ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (1.156663ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.916826ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (4.844588ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (6.50136ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (5.149952ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.701323ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.772768ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.21024ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.860667ms) +✔ F9: registrations never add or redirect a root (1.777036ms) +✔ F10: a header cwd naming another project is refused (7.824365ms) +✔ F11: parentSession renders with a marker and the parent is never opened (1.222698ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (6.650439ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.648522ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.562117ms) +✔ F13: compaction is a marker in place, then the retained content (0.796403ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (535.261071ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.446942ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.359388ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.192692ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.017901ms) +✔ a seat directory without search permission refuses that root, not the catalogue (1.868379ms) +✔ every page and cursor is a valid CHAT-01 record (732.019885ms) +✔ the engine pin holds for the installed package (2.291951ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (273.447098ms) +✔ 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) (580.641872ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (246.192927ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (450.247343ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (488.211935ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (216.62409ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (19.979108ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (376.258015ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (224.504275ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (299.424625ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (480.041118ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1885.455756ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (186.703798ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (270.4736ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (187.391958ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (156.128647ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (401.559088ms) +✔ N10: fake conformance (32.345984ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (444.806874ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (270.811479ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (301.230822ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (369.074885ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (346.504687ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (343.343183ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (199.261583ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (316.774796ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (626.019436ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (483.717534ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (433.204563ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (199.668666ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (166.130174ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (200.872925ms) +✔ 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.757521ms) +✔ 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 (199.990162ms) +ℹ tests 165 +ℹ suites 0 +ℹ pass 165 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 53439.906087 diff --git a/agents/darkwing/work/queue-47-review/r1/mut/h23noreap-shims-left.txt b/agents/darkwing/work/queue-47-review/r1/mut/h23noreap-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/h23noreap-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-47-review/r1/mut/k19leak-conversation.txt b/agents/darkwing/work/queue-47-review/r1/mut/k19leak-conversation.txt new file mode 100644 index 00000000..99bbe6d7 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/k19leak-conversation.txt @@ -0,0 +1,200 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (202.054486ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (29.094903ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (20.521371ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (380.265738ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (383.77194ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (235.297995ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (178.708428ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (191.616901ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.488977ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (11459.462545ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (32312.775307ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (262.995988ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (145.295044ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (620.604825ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (277.742463ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (357.582737ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (135.674806ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (194.274656ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (300.792706ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (1028.727876ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (213.849293ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (92.99746ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (67.615031ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.586644ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.081281ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (2.22829ms) +✔ no shim from this file's tests is left running for the after hook (24.991113ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (2945.629077ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (455.109288ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (2781.203996ms) +✔ K4: two engines; force stop one; the other survives by independent observation (4882.741961ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (2545.016691ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (2654.869004ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (2370.187002ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5552.934552ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (788.269939ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (712.605732ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (806.214727ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (692.985289ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (332.069099ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (463.128132ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3254.545765ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (21.722265ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (278.326856ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (292.170135ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (69.124067ms) +✖ no shim from this file's tests is left running for the after hook (5042.966648ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (194.790194ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (190.066625ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (182.2687ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (315.705683ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (182.793024ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.416493ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (186.923301ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (282.324841ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (210.171112ms) +✔ 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.893319ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (224.590288ms) +✔ 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 (220.473361ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.02041ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (204.112998ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (214.878204ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (252.623854ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (199.609442ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.42963ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.296061ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.320954ms) +✔ 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.481725ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.849683ms) +✔ 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.444594ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.71464ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.328147ms) +✔ 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.329988ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.104019ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (224.528016ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (243.085787ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (269.197312ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (816.20328ms) +✔ H4: self-takeover is refused (178.587331ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (438.883667ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1060.31653ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (223.711706ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (662.952093ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (293.495194ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (193.47591ms) +✔ H13: a retry with the same request ID and different text is refused (197.665643ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (592.405485ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (295.824203ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (250.953389ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (978.022423ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (370.058061ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (768.589881ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (202.773991ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (346.678335ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.658992ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (671.389147ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (587.714656ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (707.767483ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2964.584779ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (590.347364ms) +✔ no shim from this file's tests is left running for the after hook (25.878234ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.168172ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.700461ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.581868ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.428857ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.316679ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.848228ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (1.202433ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.615224ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (4.181542ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.451603ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.915774ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.416033ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (7.368711ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.044047ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.730808ms) +✔ F9: registrations never add or redirect a root (1.692061ms) +✔ F10: a header cwd naming another project is refused (4.311864ms) +✔ F11: parentSession renders with a marker and the parent is never opened (1.06521ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.958754ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.190111ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.705023ms) +✔ F13: compaction is a marker in place, then the retained content (0.921494ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (503.65243ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.346234ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.423213ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.18304ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.023734ms) +✔ a seat directory without search permission refuses that root, not the catalogue (1.835462ms) +✔ every page and cursor is a valid CHAT-01 record (744.075418ms) +✔ the engine pin holds for the installed package (1.714045ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (266.329572ms) +✔ 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) (514.394265ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (240.931026ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (452.163235ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (457.981922ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (220.293101ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (20.779992ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (324.014318ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (193.956062ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (293.795022ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (512.045177ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1880.726547ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (195.495573ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (276.81879ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (227.736397ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (235.102568ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (436.369737ms) +✔ N10: fake conformance (32.547618ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (478.496775ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (300.483864ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (342.840723ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (364.51853ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (375.392696ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (354.980863ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (202.914908ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (290.893238ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (727.756146ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (508.176217ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (487.479705ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (192.908547ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (172.475922ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (181.295263ms) +✔ 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 (214.730578ms) +✔ 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 (212.086389ms) +ℹ tests 165 +ℹ suites 0 +ℹ pass 164 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 52233.099536 + +✖ failing tests: + +test at packages/conversation/tests/cohort.test.mjs:748:1 +✖ no shim from this file's tests is left running for the after hook (5042.966648ms) + AssertionError [ERR_ASSERTION]: a test left its shim running + + actual - expected + + + [ + + { + + pid: 3538170, + + socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-k19leak/chat03-GfMOSY/f24/sock/k19.sock', + + unit: 'mosaic-chat-ccf3b9f715753becf8b551870' + + } + + ] + - [] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/cohort.test.mjs:749:10) + 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: [ { pid: 3538170, socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-k19leak/chat03-GfMOSY/f24/sock/k19.sock', unit: 'mosaic-chat-ccf3b9f715753becf8b551870' } ], + expected: [], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-47-review/r1/mut/k19leak-shims-left.txt b/agents/darkwing/work/queue-47-review/r1/mut/k19leak-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/k19leak-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-47-review/r1/mut/manifest-after.txt b/agents/darkwing/work/queue-47-review/r1/mut/manifest-after.txt new file mode 100644 index 00000000..9b84b815 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/manifest-after.txt @@ -0,0 +1,6 @@ +agents/dewey/work/queue-47/evidence.md: OK +packages/conversation/tests/claim.test.mjs: OK +packages/conversation/tests/cohort.test.mjs: OK +packages/conversation/tests/flows.test.mjs: OK +packages/conversation/tests/harness.mjs: OK +packages/conversation/tests/races.test.mjs: OK diff --git a/agents/darkwing/work/queue-47-review/r1/mut/mutate.py b/agents/darkwing/work/queue-47-review/r1/mut/mutate.py new file mode 100644 index 00000000..1111b438 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/mutate.py @@ -0,0 +1,33 @@ +# mutate.py : apply one named mutant (each edit exact text, must match once). Run from the tree root. +import sys +C = "packages/conversation/" +NOPROBE = (C + "tests/claim.test.mjs", " // The force stop leaves the probe's shim running: nothing sends `release`.\n reap(probe);\n", "") +M = { + "Mr": [(C + "src/terminal.mjs", " holds = this.held !== null;\n", " holds = false;\n")], + "noprobe": [NOPROBE], + "now13": [(C + "tests/claim.test.mjs", " // The force stop leaves the shim running: nothing sends `release`.\n reap(fx);\n", "")], + "afterleak": [NOPROBE, (C + "tests/claim.test.mjs", " for (const fx of reaped) reap(fx);\n killShims();\n const left", " const left")], + # The sweep alone, with no records: noprobe, and after doesn't reap the fixtures. + "sweeponly": [NOPROBE, (C + "tests/claim.test.mjs", " for (const fx of reaped) reap(fx);\n killShims();\n const left", " killShims();\n const left")], + # The sweep kills by PID only, no scope kill: noprobe and after without reap. + "sweeppid": [NOPROBE, (C + "tests/claim.test.mjs", " for (const fx of reaped) reap(fx);\n killShims();\n const left", " killShims();\n const left"), + (C + "tests/harness.mjs", " if (s.unit) spawnSync(\"systemctl\", [\"--user\", \"kill\", \"--signal=SIGKILL\", `${s.unit}.scope`], { stdio: \"ignore\", timeout: 5000 });\n", "")], + # K19 leaves its scope: no kill, no release. + "k19leak": [(C + "tests/cohort.test.mjs", + " const killed = await shimRequest(socketPath, \"kill\", { timeoutMs: 5000 }, 8000);\n const released = killed.ok ? await shimRequest(socketPath, \"release\") : killed;\n if (!released.ok) spawnSync(\"systemctl\", [\"--user\", \"kill\", \"--signal=SIGKILL\", `${unitName}.scope`], { stdio: \"ignore\", timeout: 5000 });\n await proc.exited;\n assert.equal(killed.ok, true, JSON.stringify(killed));\n assert.equal(released.ok, true, JSON.stringify(released));\n", + " void proc;\n")], + # H23 doesn't reap its fixture. + "h23noreap": [(C + "tests/races.test.mjs", " await b.exited;\n reap(fx);\n});\n\n// Last in the file.", " await b.exited;\n});\n\n// Last in the file.")], + # H22 (a scope, force-stopped, then relaunched) doesn't reap its fixture. + "h22noreap": [(C + "tests/races.test.mjs", " await b.exited;\n reap(fx);\n});\n\ntest(\"H23", " await b.exited;\n});\n\ntest(\"H23")], + # reap() without the sweep: the backstop alone. + "reapnosweep": [(C + "tests/harness.mjs", " // calls above didn't reach: neither result is checked.\n killShims(fx.base);\n", " // calls above didn't reach: neither result is checked.\n")], +} +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-47-review/r1/mut/noprobe-conversation.txt b/agents/darkwing/work/queue-47-review/r1/mut/noprobe-conversation.txt new file mode 100644 index 00000000..2bb4f99b --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/noprobe-conversation.txt @@ -0,0 +1,200 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (282.937597ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (50.093746ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (19.74016ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (520.780811ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (443.539556ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (249.091677ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (215.670313ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (234.14316ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.617411ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (13219.243338ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (35043.20244ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (373.142977ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (475.241878ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (622.145753ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (445.37713ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (519.884557ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (125.014355ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (212.933884ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (326.08032ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (906.246954ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (213.52989ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (119.253093ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (78.067386ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.440182ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.111808ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (2.13747ms) +✖ no shim from this file's tests is left running for the after hook (5046.252437ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (3104.602351ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (697.532535ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (3047.740898ms) +✔ K4: two engines; force stop one; the other survives by independent observation (5198.390202ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (2519.122514ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (2573.295712ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (2493.738315ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5195.842609ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (859.9822ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (742.744435ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (561.834231ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (901.421249ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (463.846568ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (715.309839ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3391.404111ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (26.042965ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (523.024463ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (330.55586ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (82.540287ms) +✔ no shim from this file's tests is left running for the after hook (26.566716ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (286.168512ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (377.747436ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (215.200155ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (326.602654ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (230.455005ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.440313ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (215.740333ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (330.41535ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (245.354601ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (225.812654ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (246.631562ms) +✔ 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 (252.64731ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.067682ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (451.425124ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (316.454708ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (311.885054ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (292.804535ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.420948ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.255838ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.327912ms) +✔ 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.481876ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (31.289223ms) +✔ 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.486287ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.783371ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.39157ms) +✔ 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.34537ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.0984ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (272.955772ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (340.814472ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (451.028642ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (908.055698ms) +✔ H4: self-takeover is refused (227.773618ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (506.331615ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1553.972775ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (374.170056ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (1281.70912ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (388.891311ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (215.368506ms) +✔ H13: a retry with the same request ID and different text is refused (236.172724ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (690.882483ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (337.15436ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (229.432724ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (1197.075582ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (505.809962ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (1003.411377ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (186.620806ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (304.074651ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.660476ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (689.760131ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (579.201376ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (711.583219ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2954.117441ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (676.012514ms) +✔ no shim from this file's tests is left running for the after hook (25.886638ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.588771ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.703565ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.787985ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.64103ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.443367ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.991457ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.794714ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.278564ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.372104ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.185505ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (5.862704ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.223447ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.438179ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.015533ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.968255ms) +✔ F9: registrations never add or redirect a root (2.093746ms) +✔ F10: a header cwd naming another project is refused (4.510677ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.728622ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (5.254575ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.091962ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.374193ms) +✔ F13: compaction is a marker in place, then the retained content (0.933001ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (509.469711ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.303588ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (4.26981ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.105312ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.036966ms) +✔ a seat directory without search permission refuses that root, not the catalogue (1.788252ms) +✔ every page and cursor is a valid CHAT-01 record (811.987754ms) +✔ the engine pin holds for the installed package (1.836325ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (267.238939ms) +✔ 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) (598.801528ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (276.924431ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (749.402112ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (498.688556ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (266.07953ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.947376ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (394.118829ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (232.943051ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (324.480381ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (655.833704ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (2170.238581ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (305.14733ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (342.485459ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (180.111325ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (290.142357ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (428.925667ms) +✔ N10: fake conformance (34.033601ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (529.657483ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (313.788867ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (391.601448ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (484.338398ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (489.422664ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (497.122206ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (296.008524ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (467.081721ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (734.233914ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (533.918507ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (502.012851ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (205.405617ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (193.442972ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (185.960475ms) +✔ 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 (195.282092ms) +✔ 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.424206ms) +ℹ tests 165 +ℹ suites 0 +ℹ pass 164 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 63077.020588 + +✖ failing tests: + +test at packages/conversation/tests/claim.test.mjs:716:1 +✖ no shim from this file's tests is left running for the after hook (5046.252437ms) + AssertionError [ERR_ASSERTION]: a test left its shim running + + actual - expected + + + [ + + { + + pid: 3407906, + + socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-noprobe/chat03-Q8oINH/f55/sock/shim-c32a2893a970.sock', + + unit: 'mosaic-chat-c32a2893a9706deb3bec82ca0' + + } + + ] + - [] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/claim.test.mjs:717:10) + 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: [ { pid: 3407906, socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-noprobe/chat03-Q8oINH/f55/sock/shim-c32a2893a970.sock', unit: 'mosaic-chat-c32a2893a9706deb3bec82ca0' } ], + expected: [], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-47-review/r1/mut/noprobe-shims-left.txt b/agents/darkwing/work/queue-47-review/r1/mut/noprobe-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/noprobe-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-47-review/r1/mut/now13-conversation.txt b/agents/darkwing/work/queue-47-review/r1/mut/now13-conversation.txt new file mode 100644 index 00000000..9a3c168a --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/now13-conversation.txt @@ -0,0 +1,200 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (198.698815ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (32.862657ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (17.889047ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (485.604813ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (365.231889ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (232.065585ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (181.538597ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (183.821556ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.610861ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (11633.757353ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (38168.11999ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (367.150641ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (145.663175ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (456.48183ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (316.350227ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (392.363184ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (115.172256ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (242.361847ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (305.279805ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (867.981978ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (411.049411ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (107.290437ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (79.610014ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (5.001315ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.182592ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (2.108134ms) +✖ no shim from this file's tests is left running for the after hook (5069.458005ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (3088.297138ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (471.125148ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (2756.987349ms) +✔ K4: two engines; force stop one; the other survives by independent observation (5023.712968ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (2554.275667ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (2735.958459ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (2522.163222ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5637.374272ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (825.150571ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (925.855507ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (799.307491ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (1542.680606ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (552.967583ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (546.085838ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3285.771371ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (24.867ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (376.020519ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (349.317488ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (61.467027ms) +✔ no shim from this file's tests is left running for the after hook (26.090499ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (199.663758ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (304.621318ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (209.329704ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (270.026975ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (189.943314ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.423509ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (188.105029ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (284.880872ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (192.41889ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (153.892727ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (189.945342ms) +✔ 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 (194.689916ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.931016ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (196.780721ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (213.861585ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (237.075778ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (208.338445ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.442794ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.300169ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.32973ms) +✔ 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.511474ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.938535ms) +✔ 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.47667ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (4.817998ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.431762ms) +✔ 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.365261ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.121626ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (229.95575ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (244.144747ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (419.408382ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (768.597537ms) +✔ H4: self-takeover is refused (178.373354ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (389.61586ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (975.461449ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (248.747123ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (665.043422ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (310.63687ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (194.775379ms) +✔ H13: a retry with the same request ID and different text is refused (191.465442ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (547.019679ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (290.665609ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (189.887032ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (933.090386ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (523.920195ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (981.477342ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (218.106746ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (351.898454ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.598431ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (694.089088ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (514.270031ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (939.240048ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3072.076081ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (653.420449ms) +✔ no shim from this file's tests is left running for the after hook (26.494042ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (5.54234ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.548775ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.498421ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.194536ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.447354ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.786317ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.744188ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.141692ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.091082ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (3.959532ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.701716ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.696632ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.324616ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.794386ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.567147ms) +✔ F9: registrations never add or redirect a root (1.458632ms) +✔ F10: a header cwd naming another project is refused (3.704001ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.647529ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (3.690779ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.971159ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.435078ms) +✔ F13: compaction is a marker in place, then the retained content (0.776037ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (509.154104ms) +✔ fragments never cut a surrogate pair and keep an empty string (5.140956ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.694451ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.573043ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.247235ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.171709ms) +✔ every page and cursor is a valid CHAT-01 record (758.079284ms) +✔ the engine pin holds for the installed package (1.62462ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (247.368358ms) +✔ 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) (542.398677ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (238.906024ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (592.557974ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (408.954193ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (218.537145ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.789466ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (327.144677ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (187.305082ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (277.516328ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (443.666689ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1846.380562ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (194.887956ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (280.229511ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (184.022735ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (176.418657ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (397.733238ms) +✔ N10: fake conformance (31.9138ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (473.51531ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (281.37194ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (327.373894ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (519.646809ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (519.289096ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (413.910759ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (216.468282ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (319.436286ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (673.393295ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (486.237526ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (671.744395ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (313.768091ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (182.117391ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (259.568701ms) +✔ 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 (270.08494ms) +✔ 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 (254.988226ms) +ℹ tests 165 +ℹ suites 0 +ℹ pass 164 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 63864.593514 + +✖ failing tests: + +test at packages/conversation/tests/claim.test.mjs:716:1 +✖ no shim from this file's tests is left running for the after hook (5069.458005ms) + AssertionError [ERR_ASSERTION]: a test left its shim running + + actual - expected + + + [ + + { + + pid: 3447135, + + socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-now13/chat03-49mRK9/f97/sock/shim-caf8d6f42417.sock', + + unit: 'mosaic-chat-caf8d6f4241771cc4dd83db5c' + + } + + ] + - [] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/claim.test.mjs:717:10) + 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: [ { pid: 3447135, socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-now13/chat03-49mRK9/f97/sock/shim-caf8d6f42417.sock', unit: 'mosaic-chat-caf8d6f4241771cc4dd83db5c' } ], + expected: [], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-47-review/r1/mut/now13-shims-left.txt b/agents/darkwing/work/queue-47-review/r1/mut/now13-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/now13-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-47-review/r1/mut/reapnosweep-conversation.txt b/agents/darkwing/work/queue-47-review/r1/mut/reapnosweep-conversation.txt new file mode 100644 index 00000000..020f87c3 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/reapnosweep-conversation.txt @@ -0,0 +1,173 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (207.271804ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (27.378503ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (17.734201ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (401.463097ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (424.149463ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (260.321182ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (216.303228ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (198.475187ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.530333ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (9580.246552ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (32490.502812ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (265.204197ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (146.055374ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (608.687771ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (283.134728ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (348.792391ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (110.258855ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (168.831108ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (293.044336ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (1011.928942ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (192.216459ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (95.914112ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (70.729115ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.126228ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.074734ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.743051ms) +✔ no shim from this file's tests is left running for the after hook (26.734544ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (2951.343801ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (430.822757ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (2740.61561ms) +✔ K4: two engines; force stop one; the other survives by independent observation (4802.817192ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (2465.610533ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (2710.911294ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (2365.599726ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5208.374708ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (705.036427ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (556.452572ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (678.820054ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (675.592705ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (324.575793ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (516.070431ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3248.044103ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (22.751721ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (316.43844ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (283.795513ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (83.41128ms) +✔ no shim from this file's tests is left running for the after hook (27.163484ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (197.270317ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (196.984698ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (242.28257ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (264.905841ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (251.57943ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.428407ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (263.885551ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (305.700471ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (223.918645ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (195.860354ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (214.150476ms) +✔ 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 (204.109833ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.909702ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (204.12687ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (225.290366ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (250.520935ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (206.142267ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.41733ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.27429ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.37043ms) +✔ 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.502339ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.943287ms) +✔ 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.504745ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.717556ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.483407ms) +✔ 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.329417ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.099683ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (245.471689ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (246.021579ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (335.482637ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (923.349311ms) +✔ H4: self-takeover is refused (191.466141ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (456.147402ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1017.207863ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (236.676987ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (661.959995ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (296.013005ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (265.514914ms) +✔ H13: a retry with the same request ID and different text is refused (216.459394ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (771.292898ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (367.682417ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (228.139489ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (891.312509ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (307.782218ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (778.911906ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (198.565122ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (341.100834ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.610067ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (633.054053ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (535.933625ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (661.804814ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2929.74862ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (669.043564ms) +✔ no shim from this file's tests is left running for the after hook (27.421304ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (5.900029ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.636176ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.750661ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.40655ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.804873ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.858031ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.844388ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.246411ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.458235ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.565903ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.341684ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.313517ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.109439ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.687318ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (2.005059ms) +✔ F9: registrations never add or redirect a root (1.84741ms) +✔ F10: a header cwd naming another project is refused (4.18711ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.831652ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.297263ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.129671ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.696325ms) +✔ F13: compaction is a marker in place, then the retained content (0.866729ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (519.860154ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.62088ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.530826ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.372473ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.106265ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.06523ms) +✔ every page and cursor is a valid CHAT-01 record (774.932604ms) +✔ the engine pin holds for the installed package (1.897167ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (278.377573ms) +✔ 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.405456ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (242.204143ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (519.439509ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (414.693165ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (312.944285ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.937563ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (401.944364ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (205.60076ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (303.758094ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (463.80476ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1950.729013ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (232.903168ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (363.906033ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (282.17414ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (265.639301ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (474.858611ms) +✔ N10: fake conformance (32.677774ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (447.029703ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (286.460188ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (290.431139ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (366.969251ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (380.832064ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (354.439631ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (199.111062ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (272.807596ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (676.108776ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (541.840477ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (492.00608ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (229.057693ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (175.273367ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (193.822882ms) +✔ 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 (216.01477ms) +✔ 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.571295ms) +ℹ tests 165 +ℹ suites 0 +ℹ pass 165 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 49363.024117 diff --git a/agents/darkwing/work/queue-47-review/r1/mut/reapnosweep-shims-left.txt b/agents/darkwing/work/queue-47-review/r1/mut/reapnosweep-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/reapnosweep-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-47-review/r1/mut/run.sh b/agents/darkwing/work/queue-47-review/r1/mut/run.sh new file mode 100755 index 00000000..7a8ac19e --- /dev/null +++ b/agents/darkwing/work/queue-47-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/r47a/tmp/mut-$m DOCKER_HOST=unix:///nonexistent.sock +mkdir -p $TMPDIR +M=~/darkwing-scratch/r47a/mut; cd ~/darkwing-scratch/r47a/wt +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-47-review/r1/mut/summary.txt b/agents/darkwing/work/queue-47-review/r1/mut/summary.txt new file mode 100644 index 00000000..ec815200 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/summary.txt @@ -0,0 +1,13 @@ +Mr rc 1 ℹ pass 164 ℹ fail 1 shims-left 0 +noprobe rc 1 ℹ pass 164 ℹ fail 1 shims-left 0 +now13 rc 1 ℹ pass 164 ℹ fail 1 shims-left 0 +afterleak rc 1 ℹ pass 164 ℹ fail 2 shims-left 1 +sweeponly rc 1 ℹ pass 164 ℹ fail 1 shims-left 0 +sweeppid rc 1 ℹ pass 164 ℹ fail 1 shims-left 0 +k19leak rc 1 ℹ pass 164 ℹ fail 1 shims-left 0 +h23noreap rc 0 ℹ pass 165 ℹ fail 0 shims-left 0 +reapnosweep rc 0 ℹ pass 165 ℹ fail 0 shims-left 0 +DONE +manifest rc=0 +h22noreap rc 1 ℹ pass 164 ℹ fail 1 shims-left 0 +manifest rc=0 after h22noreap (run after DONE) diff --git a/agents/darkwing/work/queue-47-review/r1/mut/sweeponly-conversation.txt b/agents/darkwing/work/queue-47-review/r1/mut/sweeponly-conversation.txt new file mode 100644 index 00000000..e0cb4056 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/sweeponly-conversation.txt @@ -0,0 +1,200 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (219.22162ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (23.765285ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (19.835106ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (677.055327ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (565.256821ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (257.310579ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (239.136175ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (218.373694ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.590114ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12029.61787ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (30878.301788ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (287.664713ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (155.736773ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (452.81341ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (315.312236ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (379.01671ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (118.606186ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (211.612835ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (279.515244ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (785.941592ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (199.611313ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (95.335199ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (77.381194ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.361384ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.142543ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.938508ms) +✖ no shim from this file's tests is left running for the after hook (5019.603223ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (3200.252717ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (529.274581ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (2868.634419ms) +✔ K4: two engines; force stop one; the other survives by independent observation (5110.98429ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (2541.203565ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (2475.547415ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (2361.050725ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (6461.358245ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (713.270412ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (564.741213ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (483.075851ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (794.671937ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (426.842821ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (569.619555ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3261.74847ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (27.269794ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (531.307009ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (465.646205ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (82.674166ms) +✔ no shim from this file's tests is left running for the after hook (25.397912ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (229.034341ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (502.781612ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (216.97478ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (451.470365ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (222.111955ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.397399ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (227.363437ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (339.547516ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (242.128975ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (210.685516ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (242.777703ms) +✔ 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 (344.665889ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (9.896061ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (252.050993ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (254.617339ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (277.942168ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (235.804509ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.412249ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.261896ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.323508ms) +✔ 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.476089ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.706168ms) +✔ 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.384241ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (4.691081ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.356412ms) +✔ 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.323979ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.096363ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (225.795171ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (269.285437ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (611.712432ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (1040.161233ms) +✔ H4: self-takeover is refused (223.766709ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (483.992838ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1331.586166ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (281.034529ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (721.030469ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (365.24181ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (232.315138ms) +✔ H13: a retry with the same request ID and different text is refused (218.980022ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (686.025613ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (307.533843ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (232.615491ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (923.383092ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (539.323132ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (838.31859ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (229.489054ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (396.824559ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.653646ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (678.692377ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (625.288367ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (722.611686ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2839.482157ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (610.170391ms) +✔ no shim from this file's tests is left running for the after hook (24.228875ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.463565ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.693891ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.733322ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.531828ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.344865ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.071245ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (0.803497ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.251514ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.411618ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.329635ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.675201ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (6.025147ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.7227ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.835583ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.728641ms) +✔ F9: registrations never add or redirect a root (1.742691ms) +✔ F10: a header cwd naming another project is refused (3.9573ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.759548ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.09653ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.228863ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.408581ms) +✔ F13: compaction is a marker in place, then the retained content (0.897507ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (534.197443ms) +✔ fragments never cut a surrogate pair and keep an empty string (4.583271ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.532858ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.342871ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.15181ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.03718ms) +✔ every page and cursor is a valid CHAT-01 record (779.363124ms) +✔ the engine pin holds for the installed package (1.849074ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (279.715201ms) +✔ 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) (547.522098ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (242.72555ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (812.948913ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (615.318151ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (266.66633ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.877037ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (412.712916ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (226.935176ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (332.816958ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (652.278512ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1943.118139ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (222.075483ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (324.648835ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (237.783638ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (264.056599ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (389.449033ms) +✔ N10: fake conformance (32.857365ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (413.601451ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (310.062237ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (294.630345ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (484.253844ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (496.213776ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (381.020463ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (207.059927ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (440.374037ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (649.883294ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (651.981202ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (489.606583ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (139.447168ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (173.130328ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (184.996545ms) +✔ 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 (207.728707ms) +✔ 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 (239.825509ms) +ℹ tests 165 +ℹ suites 0 +ℹ pass 164 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 53766.897467 + +✖ failing tests: + +test at packages/conversation/tests/claim.test.mjs:715:1 +✖ no shim from this file's tests is left running for the after hook (5019.603223ms) + AssertionError [ERR_ASSERTION]: a test left its shim running + + actual - expected + + + [ + + { + + pid: 3491796, + + socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-sweeponly/chat03-NvSlTB/f55/sock/shim-c57cf2b7dc43.sock', + + unit: 'mosaic-chat-c57cf2b7dc4384ee284c7c8ca' + + } + + ] + - [] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/claim.test.mjs:716:10) + 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: [ { pid: 3491796, socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-sweeponly/chat03-NvSlTB/f55/sock/shim-c57cf2b7dc43.sock', unit: 'mosaic-chat-c57cf2b7dc4384ee284c7c8ca' } ], + expected: [], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-47-review/r1/mut/sweeponly-shims-left.txt b/agents/darkwing/work/queue-47-review/r1/mut/sweeponly-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/sweeponly-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-47-review/r1/mut/sweeppid-conversation.txt b/agents/darkwing/work/queue-47-review/r1/mut/sweeppid-conversation.txt new file mode 100644 index 00000000..85f2affc --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/sweeppid-conversation.txt @@ -0,0 +1,200 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (212.307304ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (33.241548ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (19.690237ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (365.735842ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (476.656649ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (252.219246ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (203.752506ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (218.059827ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.827711ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12986.540113ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (29667.327918ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (263.096526ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (153.684222ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (438.623192ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (292.216779ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (354.209654ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (99.843498ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (199.922328ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (270.3889ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (785.105243ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (197.740901ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (88.807427ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (69.375455ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.533954ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.057677ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.755071ms) +✖ no shim from this file's tests is left running for the after hook (5015.591033ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (3012.37604ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (456.752613ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (2853.357608ms) +✔ K4: two engines; force stop one; the other survives by independent observation (5101.754986ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (2510.116268ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (2507.829556ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (2385.107361ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5096.425544ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (748.270129ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (698.688142ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (461.090943ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (764.265641ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (368.273775ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (585.010913ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3303.227292ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (44.55575ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (340.095364ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (407.45662ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (65.922828ms) +✔ no shim from this file's tests is left running for the after hook (26.780264ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (203.806154ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (198.186853ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (199.091556ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (346.518529ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (190.366735ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.478363ms) +✔ 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.877259ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (303.887167ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (250.230797ms) +✔ 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.267876ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (202.246951ms) +✔ 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 (204.796413ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.997429ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (206.23248ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (215.165122ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (232.091292ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (197.742321ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.433064ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.264916ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.33873ms) +✔ 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.482271ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.503364ms) +✔ 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.508488ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.194845ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.502874ms) +✔ 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.374229ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.141727ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (244.73443ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (251.027442ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (295.533573ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (874.357109ms) +✔ H4: self-takeover is refused (230.948664ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (432.850202ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1003.554755ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (203.401943ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (713.216897ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (327.609666ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (187.90498ms) +✔ H13: a retry with the same request ID and different text is refused (180.014369ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (617.363478ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (269.250448ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (200.985765ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (893.863913ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (361.590816ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (772.788917ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (191.089022ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (339.528421ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.617666ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (662.309994ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (1578.967408ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (841.811267ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2893.408865ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (609.408041ms) +✔ no shim from this file's tests is left running for the after hook (24.887141ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.826388ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.874992ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (2.088607ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (3.046621ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.89486ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (3.832698ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (2.351568ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (2.059196ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (5.549088ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.912965ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (6.192415ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (5.499ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (7.619517ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (12.775709ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (2.547278ms) +✔ F9: registrations never add or redirect a root (2.661461ms) +✔ F10: a header cwd naming another project is refused (5.443268ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.748576ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.475394ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.950489ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.66476ms) +✔ F13: compaction is a marker in place, then the retained content (0.810283ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (568.348502ms) +✔ fragments never cut a surrogate pair and keep an empty string (5.675357ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.769068ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.773876ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.250822ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.338683ms) +✔ every page and cursor is a valid CHAT-01 record (878.978932ms) +✔ the engine pin holds for the installed package (1.990805ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (299.382164ms) +✔ 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) (600.196612ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (293.379255ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (478.752914ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (496.518825ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (229.675189ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (22.369485ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (345.76914ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (209.867289ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (310.103199ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (449.582349ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1873.348979ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (145.516554ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (281.565014ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (202.855278ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (238.854877ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (366.704339ms) +✔ N10: fake conformance (31.268588ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (387.555351ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (254.221566ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (318.654843ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (392.533184ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (375.602357ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (370.59127ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (197.627792ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (353.031336ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (687.713946ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (406.944589ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (1522.272602ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (237.477898ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (209.176383ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (176.405994ms) +✔ 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 (146.513631ms) +✔ 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.956939ms) +ℹ tests 165 +ℹ suites 0 +ℹ pass 164 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 52878.90005 + +✖ failing tests: + +test at packages/conversation/tests/claim.test.mjs:715:1 +✖ no shim from this file's tests is left running for the after hook (5015.591033ms) + AssertionError [ERR_ASSERTION]: a test left its shim running + + actual - expected + + + [ + + { + + pid: 3524005, + + socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-sweeppid/chat03-LcZocr/f55/sock/shim-c0dce842c2ea.sock', + + unit: 'mosaic-chat-c0dce842c2ea498500eca8f92' + + } + + ] + - [] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r47a/wt/packages/conversation/tests/claim.test.mjs:716:10) + 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: [ { pid: 3524005, socket: '/home/jwoltje/darkwing-scratch/r47a/tmp/mut-sweeppid/chat03-LcZocr/f55/sock/shim-c0dce842c2ea.sock', unit: 'mosaic-chat-c0dce842c2ea498500eca8f92' } ], + expected: [], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-47-review/r1/mut/sweeppid-shims-left.txt b/agents/darkwing/work/queue-47-review/r1/mut/sweeppid-shims-left.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/mut/sweeppid-shims-left.txt @@ -0,0 +1 @@ + diff --git a/agents/darkwing/work/queue-47-review/r1/out/node-conversation.txt b/agents/darkwing/work/queue-47-review/r1/out/node-conversation.txt new file mode 100644 index 00000000..549ff67c --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/out/node-conversation.txt @@ -0,0 +1,173 @@ +✔ W1: two processes acquire the same pair at once; exactly one claim (748.083419ms) +✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (48.776016ms) +✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (27.06872ms) +✔ W2: acquire while a claim is reserved or active refuses already-active (421.457932ms) +✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (402.390693ms) +✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (254.045709ms) +✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (244.400915ms) +✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (239.716607ms) +✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.325186ms) +✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (13356.104987ms) +✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (36068.863466ms) +✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (252.623185ms) +✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (148.149392ms) +✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (630.377836ms) +✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (286.783672ms) +✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (347.24802ms) +✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (102.897217ms) +✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (220.305866ms) +✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (418.974636ms) +✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (932.402989ms) +✔ W11: the controller writes no session file; only the fake engine's own appends appear (204.140858ms) +✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (92.498337ms) +✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (78.471097ms) +✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.439765ms) +✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.197349ms) +✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.813056ms) +✔ no shim from this file's tests is left running for the after hook (25.234145ms) +✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (3507.986737ms) +✔ K2: K1 on the process-group fallback ends uncertain, never stopped (488.26111ms) +✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (2807.697949ms) +✔ K4: two engines; force stop one; the other survives by independent observation (5077.47375ms) +✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (2577.773206ms) +✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (2709.866313ms) +✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (2448.965499ms) +✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5820.759171ms) +✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (729.781747ms) +✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (645.129116ms) +✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (652.019615ms) +✔ K6: recover without proof, without confirmation, or with changed pins is refused (789.185088ms) +✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (367.180176ms) +✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (806.040921ms) +✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3273.574724ms) +✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (24.586649ms) +✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (299.433157ms) +✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (299.231036ms) +✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (81.16899ms) +✔ no shim from this file's tests is left running for the after hook (25.931375ms) +✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (203.436663ms) +✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (773.840378ms) +✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (268.793695ms) +✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (331.406567ms) +✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (220.921848ms) +✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.427235ms) +✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (205.441943ms) +✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (310.116384ms) +✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (271.294599ms) +✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (201.090126ms) +✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (231.32039ms) +✔ 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 (218.02235ms) +✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.602383ms) +✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (224.057707ms) +✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (236.338343ms) +✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (281.785722ms) +✔ terminal: engine control characters are made visible; a lost connection refuses submit (228.267016ms) +✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.418138ms) +✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.280314ms) +✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.306187ms) +✔ 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.48246ms) +✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.948332ms) +✔ 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.436041ms) +✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.664433ms) +✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.323378ms) +✔ 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.399489ms) +✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.102825ms) +✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (221.258318ms) +✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (836.995174ms) +✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (345.379527ms) +✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (912.356131ms) +✔ H4: self-takeover is refused (234.984573ms) +✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (468.136324ms) +✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1141.024711ms) +✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (236.737014ms) +✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (1160.793929ms) +✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (317.507653ms) +✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (222.364545ms) +✔ H13: a retry with the same request ID and different text is refused (215.785684ms) +✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (633.428602ms) +✔ H15: a revoked connection's command is refused; the revocation fence holds (290.244169ms) +✔ H16: a second controller for the same session refuses already-active; the first is untouched (221.311078ms) +✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (920.773309ms) +✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (667.241115ms) +✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (1249.039812ms) +✔ H18: two prompts before any native output: the second refuses busy; one engine write (331.549187ms) +✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (461.162549ms) +✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.655085ms) +✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (753.02375ms) +✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (619.748198ms) +✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (791.966316ms) +✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2953.46659ms) +✔ H23: requests pending at a restart are not resent; each shows outcome unknown (821.845284ms) +✔ no shim from this file's tests is left running for the after hook (25.659792ms) +✔ a plain conversation: catalogue row, one page, CHAT-01 records (8.997065ms) +✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.836337ms) +✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.869323ms) +✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.785801ms) +✔ F1: an unreadable fork is never merged into another branch's history (1.514939ms) +✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.08467ms) +✔ F1: a file whose entries are all unreadable shows a notice per line (1.109708ms) +✔ F2: a truncated trailing line marks the view incomplete, not an error (1.43512ms) +✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.918335ms) +✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.373201ms) +✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (5.010585ms) +✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (5.206126ms) +✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (7.340925ms) +✔ F7: a symlinked file and a symlinked directory component are refused, never opened (9.045792ms) +✔ F8: a file swapped for a symlink after the catalogue is refused (1.879664ms) +✔ F9: registrations never add or redirect a root (1.864646ms) +✔ F10: a header cwd naming another project is refused (4.700498ms) +✔ F11: parentSession renders with a marker and the parent is never opened (0.909364ms) +✔ F12: two leaves: the default leaf is shown and the other branch reads alone (6.844885ms) +✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.439724ms) +✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.604906ms) +✔ F13: compaction is a marker in place, then the retained content (0.802607ms) +✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (522.527587ms) +✔ fragments never cut a surrogate pair and keep an empty string (5.380359ms) +✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.847291ms) +✔ unknown conversations, empty files and non-Pi files refuse (2.816787ms) +✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.358511ms) +✔ a seat directory without search permission refuses that root, not the catalogue (2.385576ms) +✔ every page and cursor is a valid CHAT-01 record (863.558219ms) +✔ the engine pin holds for the installed package (2.284265ms) +✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (262.803824ms) +✔ 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) (537.60608ms) +✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (331.695583ms) +✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (1083.153523ms) +✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (535.341366ms) +✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (248.458287ms) +✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.767648ms) +✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (386.548344ms) +✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (250.152615ms) +✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (324.635181ms) +✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (507.783689ms) +✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1931.729518ms) +✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (221.397946ms) +✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (324.497019ms) +✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (148.971188ms) +✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (261.283024ms) +✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (441.385924ms) +✔ N10: fake conformance (32.218012ms) +✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (429.582597ms) +✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (273.423146ms) +✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (303.722538ms) +✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (395.259681ms) +✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (417.929598ms) +✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (669.815407ms) +✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (341.540953ms) +✔ N17: the run fails on its own during the exchange: failed, Failed on its own (551.736315ms) +✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (1329.575149ms) +✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (456.102377ms) +✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (595.331647ms) +✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (285.686961ms) +✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (232.628891ms) +✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (187.264585ms) +✔ 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.475028ms) +✔ 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 (229.935301ms) +ℹ tests 165 +ℹ suites 0 +ℹ pass 165 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 59084.73944 diff --git a/agents/darkwing/work/queue-47-review/r1/out/node-webui.txt b/agents/darkwing/work/queue-47-review/r1/out/node-webui.txt new file mode 100644 index 00000000..9cf6410c --- /dev/null +++ b/agents/darkwing/work/queue-47-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 (3737.296989ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (3966.21881ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (4260.503082ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (273.228743ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (234.452668ms) +✔ bus refusals map to statuses and never carry a path or a stack (76.516425ms) +✔ humanCall speaks the human transport protocol without blocking the server (2784.361067ms) +✔ busReader takes --business, else the live bus host, else refuses (149.074355ms) +✔ humanCall kills a transport that runs past its timeout (528.127044ms) +✔ serve refuses a --business value that is not a business id (203.925382ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3486.138769ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (1870.194644ms) +✔ conversation view: a newer session with no readable history keeps the marker (1117.230752ms) +✔ conversation view: seats without history say so and offer no reply (870.280067ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (3625.064473ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53317.26966ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3752.067649ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22335.011066ms) +✔ loopback host and board origin fail closed (6.498143ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (102.695568ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (94.391046ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1768.953308ms) +ℹ tests 22 +ℹ suites 0 +ℹ pass 22 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 53693.094645 diff --git a/agents/darkwing/work/queue-47-review/r1/out/summary.txt b/agents/darkwing/work/queue-47-review/r1/out/summary.txt new file mode 100644 index 00000000..7909dac8 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/out/summary.txt @@ -0,0 +1,13 @@ +node-conversation exit=0 ℹ pass 165 ℹ fail 0 shims-left=0 +node-webui exit=0 ℹ pass 22 ℹ fail 0 shims-left=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 +shims-left-end=0 +DONE diff --git a/agents/darkwing/work/queue-47-review/r1/out/test-auth.txt b/agents/darkwing/work/queue-47-review/r1/out/test-auth.txt new file mode 100644 index 00000000..ac228760 --- /dev/null +++ b/agents/darkwing/work/queue-47-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-47-review/r1/out/test-conductor.txt b/agents/darkwing/work/queue-47-review/r1/out/test-conductor.txt new file mode 100644 index 00000000..9d495a7c --- /dev/null +++ b/agents/darkwing/work/queue-47-review/r1/out/test-conductor.txt @@ -0,0 +1,55 @@ +Note: switching to '21e0f1a31c559dfe4031e6de635ffb11d1a34606'. + +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 '21e0f1a31c559dfe4031e6de635ffb11d1a34606'. + +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-47-review/r1/out/test-config.txt b/agents/darkwing/work/queue-47-review/r1/out/test-config.txt new file mode 100644 index 00000000..76c05ef7 --- /dev/null +++ b/agents/darkwing/work/queue-47-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-47-review/r1/out/test-discord.txt b/agents/darkwing/work/queue-47-review/r1/out/test-discord.txt new file mode 100644 index 00000000..b013f9ff --- /dev/null +++ b/agents/darkwing/work/queue-47-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-47-review/r1/out/test-extension-package.txt b/agents/darkwing/work/queue-47-review/r1/out/test-extension-package.txt new file mode 100644 index 00000000..4aea83ad --- /dev/null +++ b/agents/darkwing/work/queue-47-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: 3331064 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-47-review/r1/out/test-foundation.txt b/agents/darkwing/work/queue-47-review/r1/out/test-foundation.txt new file mode 100644 index 00000000..6338e1e6 --- /dev/null +++ b/agents/darkwing/work/queue-47-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-47-review/r1/out/test-queue.txt b/agents/darkwing/work/queue-47-review/r1/out/test-queue.txt new file mode 100644 index 00000000..51c1601e --- /dev/null +++ b/agents/darkwing/work/queue-47-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/r47a/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-47-review/r1/out/test-release-docker.txt b/agents/darkwing/work/queue-47-review/r1/out/test-release-docker.txt new file mode 100644 index 00000000..7202b85d --- /dev/null +++ b/agents/darkwing/work/queue-47-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-47-review/r1/out/test-release.txt b/agents/darkwing/work/queue-47-review/r1/out/test-release.txt new file mode 100644 index 00000000..1d6ed050 --- /dev/null +++ b/agents/darkwing/work/queue-47-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-47-review/r1/out/test-task.txt b/agents/darkwing/work/queue-47-review/r1/out/test-task.txt new file mode 100644 index 00000000..85aa46f0 --- /dev/null +++ b/agents/darkwing/work/queue-47-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-47-review/review-r1.md b/agents/darkwing/work/queue-47-review/review-r1.md new file mode 100644 index 00000000..1d2ad788 --- /dev/null +++ b/agents/darkwing/work/queue-47-review/review-r1.md @@ -0,0 +1,158 @@ +# Row 47, S5 follow-up (Mr flows test and the shim leak), round 1 review (Darkwing) + +Issue #1533, request comment 27036, notes comment 27037, queue revs 277 +and 278 (`10351f6a`). Brief: `docs/plans/2026-10-10_s5-follow-up-and-hygiene.md` +(blob `24ceb88c`), section "S5 follow-up". Base `21e0f1a3`. Candidate +manifest sha256 +`0587e393746e5cc6bb31e06b94461661fc7679f6f5fa6a72835c60b286a6055f`, +6 files: five test files in `packages/conversation/tests/` and Dewey's +`evidence.md`. No `src/` change. + +Verdict: **approve**, comment 27043. The new flows test is the shape of my row 40 note 1 +probe in both chunkings, and it's the only test Mr fails. The leak +diagnosis checks out against the code: the shim ignores SIGTERM, nothing in +`src/` sends `release`, and two claim tests left a force-stopped scope for +an `after` hook whose kill results nobody checked. Each test now reaps its own +scope, every scope-launching file ends with a check that names a leak, and +the `after` hook fails the file if a shim survives the sweep. Every leak +mutant I tried in claim, cohort and races is killed, and `afterleak` +reproduces the round 2 leak with the hook catching it. Two notes below, +neither blocking. + +## Method + +- A detached worktree at `21e0f1a3` with the six files copied from a + snapshot of the canonical tree, then `sha256sum -c`: 6 OK. Checked again + after the mutants: 6 OK (`r1/mut/manifest-after.txt`). +- I read the diff in full, `src/shim.mjs`, `ScopeLauncher` and + `forceStopCohort` in `src/cohort.mjs`, `#run` in `src/terminal.mjs`, and + W5, W13, K19, H22 and H23. +- 10 mutants (`r1/mut/mutate.py`, `run.sh`), each run on the whole + conversation suite with its own TMPDIR. After each run the runner lists any + shim left under that TMPDIR, SIGKILLs its `mosaic-chat-*` scope and the PID, + and restores the files from backup copies. +- No shim was running before the gate, after it, or after any mutant other + than `afterleak` (killed by the runner, see below). After all runs + `systemctl --user list-units --all 'mosaic-chat-*'` lists nothing. + +Node is v26.8.1, `TMPDIR=~/darkwing-scratch/r47a/tmp`. `gate.sh` set +`DOCKER_HOST=unix:///nonexistent.sock`. + +## Suites + +| Suite | Result | +|---|---| +| conversation | 165/0 | +| webui | 22/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. They +fail the same way in my row 41 gates. Dewey's run reports 98/0, so it ran +the Docker cases; I didn't. + +## Mr + +The test types Ctrl-T, Ctrl-O inside the text held behind it, `hi` Enter, +then `yo` Enter and Ctrl-C, once as three chunks and once as one. It +asserts `sent` is `["hi"]`, then `held` is null, then `yo` goes through and +Ctrl-C quits. That's my `probe/stacked-later.mjs` from row 40, plus the +single-chunk case, where the hold and the stacked hold come from one +`#parse`. Under Mr (`holds = false;` at `terminal.mjs:158`) the suite is +164/1 and the one failure is this test (`r1/mut/Mr-conversation.txt`). + +## The leak + +Dewey's reading matches the code: + +- `shim.mjs` ignores SIGTERM and SIGHUP and exits only on `release` once the + engine cgroup is empty. +- The only shim ops `src/` sends are `hello`, `term`, `events`, `freeze`, + `members` and `kill` (`cohort.mjs:115-192`). So a force-stopped scope + stays up with its shim until something SIGKILLs the unit. +- W5's probe and W13 force-stop a scope and left it to the `after` hook, + whose `systemctl --user kill` and `stop` results were never checked. + +The evidence names f55, the W5 probe fixture, as Filbert's leaked shim. My +`afterleak` run leaked the same fixture (`f55/sock/shim-cede1ee324e5.sock`). +Dewey says what the journal can't show, which is why the `after` +kill missed in Filbert's run. The fix doesn't depend on knowing: the tests +reap right away, and the sweep kills by PID whatever `systemctl` does. + +The new helpers read `/proc//cmdline` for `node <...>/shim.mjs --socket +`, which is exactly `ScopeLauncher`'s argv +(`cohort.mjs:105`). `tmp` is per test process, so each file sees only its +own shims, and a parallel gate from another seat isn't touched. `noprobe` +failing proves the detector finds a real shim. + +K19's `finally` used to assert on `kill` before sending `release`, so a +failed kill left the scope. It now sends `release` only after a good kill, +SIGKILLs the scope if either fails, and asserts afterwards. + +## Mutants + +| Mutant | Change | Conversation | Result | +|---|---|---|---| +| Mr | `holds = false;` after re-parsing held text | 164/1 | killed by the new flows test | +| noprobe | W5 doesn't reap its probe | 164/1 | killed: claim's "no shim ... left running" | +| now13 | W13 doesn't reap its fixture | 164/1 | killed, same test | +| afterleak | noprobe, and `after` doesn't reap or sweep | 164/2 | killed: the same test and claim's `after` hook; 1 shim left, killed by the runner | +| sweeponly | noprobe, and `after` sweeps but doesn't reap | 164/1 | killed by the last test; the sweep alone cleans up, no shim left | +| sweeppid | sweeponly, and `killShims` skips the scope kill | 164/1 | same; the PID kill alone is enough | +| k19leak | K19's `finally` sends no kill and no release | 164/1 | killed: cohort's "no shim ... left running" | +| h22noreap | H22 (force stop, then relaunch in a scope) doesn't reap | 164/1 | killed: races' "no shim ... left running" | +| h23noreap | H23 doesn't reap | 165/0 | equivalent: H23 runs on `pgroup`, no shim | +| reapnosweep | `reap()` without its `killShims(fx.base)` | 165/0 | survives, expected: it's a backstop for a missed `systemctl` | + +`afterleak` is the round 2 leak on purpose. Its hook failure names the shim +(`r1/mut/afterleak-conversation.txt:205`), and node:test marks the file +failed: + +``` +AssertionError [ERR_ASSERTION]: no shim outlives this file (#1533) ++ pid: 3459119, ++ socket: '.../tmp/mut-afterleak/chat03-lQNQDH/f55/sock/shim-cede1ee324e5.sock', ++ unit: 'mosaic-chat-cede1ee324e5b263ef2671152' +``` + +So all three scope-launching files have their final check killed by a leak +mutant, which Dewey's table showed only for claim. + +## Notes (not blocking) + +1. `liveShims` takes the first cgroup segment ending in `.scope` as the + shim's unit, and `killShims` SIGKILLs that whole unit. Today every shim + comes from `ScopeLauncher`, so that's the `mosaic-chat-*` scope. A future + test that spawned `shim.mjs` directly from a shell inside a terminal's + `app-*.scope` would get that terminal's scope killed. Matching + `/^mosaic-chat-.*\.scope$/`, which is what my runner does, costs one + regex. Worth folding into the next change to `harness.mjs`. +2. The brief asks for the Mr output in the packet. `evidence.md` has the + table and the `afterleak` excerpt; the outputs stay in + `~/dewey-scratch`. Mine are in `r1/mut/` if Sage wants them on file. + +## Finding for Sage + +I agree with Dewey's out-of-scope finding and the recommended follow-up. In +a running controller every force stop leaves a `mosaic-chat-*.scope` with +an idle node shim, until the unit is killed by hand or the user manager +restarts. The fix is `release` after a proven force stop (and on close of a +stopped binding), with a test that the unit is gone. That's `cohort.mjs` or +`controller.mjs` work, outside this brief. + +## Files + +- `r1/candidate-manifest.sha256`, `r1/files.txt`: copies of Dewey's. +- `r1/gate.sh`, `r1/out/`: suite runs, `summary.txt` with a shim count + after each node suite and at the end. +- `r1/mut/`: mutant definitions, runner, per-mutant output and shims-left + lists, `summary.txt`, and the manifest check after the runs. `h22noreap` + ran after the first batch, so its line follows `DONE`.