review(queue-51): round 2, approve, recover release after the confirmation (darkwing)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
d7ae740247a7dbd26bdcadfe97e1acf70121911d6fed69f4fc2408f483279ef8 agents/dewey/work/queue-51/evidence.md
|
||||
aaefe3cd02ea25dc00c31d0f94ef4c74544b9929614618511be294aa314de9ce packages/conversation/README.md
|
||||
ae9cd6f800d57412ff04da7673bff6b62d506ec4ac46a15d351a45a5087a8953 packages/conversation/src/controller.mjs
|
||||
6fada028358fbfe79f2a7dbda7fee8028142a833caed5bd3c2d4f00e861a19ec packages/conversation/tests/cohort.test.mjs
|
||||
3409fcce6ebb0281b5e018983a005b0c23b8641ba69cd25ea8aec6c161870d3b packages/conversation/tests/ctrl-child.mjs
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
export TMPDIR=~/darkwing-scratch/r51b/tmp DOCKER_HOST=unix:///nonexistent.sock
|
||||
cd ~/darkwing-scratch/r51b/wt
|
||||
O=~/darkwing-scratch/r51b/out
|
||||
: > $O/summary.txt
|
||||
shims() { ps -eo pid,args | grep -F "$TMPDIR" | grep -F shim.mjs | grep -v grep | wc -l; }
|
||||
units() { systemctl --user list-units --all 'mosaic-chat-*' --no-legend | wc -l; }
|
||||
echo "start $(date -u +%FT%TZ) shims=$(shims) units=$(units)" >> $O/summary.txt
|
||||
for p in conversation webui; do
|
||||
node --test "packages/$p/tests/*.test.mjs" > $O/node-$p.txt 2>&1; e=$?
|
||||
echo "node-$p exit=$e $(grep -E '^ℹ (pass|fail)' $O/node-$p.txt | tr '\n' ' ') shims-left=$(shims) units=$(units)" >> $O/summary.txt
|
||||
done
|
||||
for f in scripts/test-*.sh; do
|
||||
s=$(basename $f .sh)
|
||||
$f > $O/$s.txt 2>&1; e=$?
|
||||
echo "$s exit=$e $(grep -E 'passed, [0-9]+ failed' $O/$s.txt | tail -1)" >> $O/summary.txt
|
||||
done
|
||||
echo "end $(date -u +%FT%TZ) shims-left=$(shims) units=$(units)" >> $O/summary.txt
|
||||
echo DONE >> $O/summary.txt
|
||||
for p in control-board queue; do
|
||||
node --test "packages/$p/tests/*.test.mjs" > $O/node-$p.txt 2>&1; e=$?
|
||||
echo "node-$p exit=$e $(grep -E '^ℹ (pass|fail)' $O/node-$p.txt | tr '\n' ' ')" >> $O/summary.txt
|
||||
done
|
||||
echo DONE2 >> $O/summary.txt
|
||||
@@ -0,0 +1,235 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (223.985151ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (32.620561ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (19.611922ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (378.285629ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (401.810846ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (232.363299ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (272.76975ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (213.831123ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.419176ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12111.695607ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (36888.868126ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (259.356201ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (151.467197ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (595.309814ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (282.201511ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (352.673758ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (106.123934ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (198.776097ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (277.897509ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (753.009748ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (187.941264ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (88.620161ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (76.730342ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.133234ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.076716ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.924155ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.047876ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1009.243932ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (466.569338ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (899.293837ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (3003.173196ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (702.044369ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (813.442609ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (747.13105ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (6145.885984ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (948.334601ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (874.886798ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (607.817287ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (667.463841ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (319.923818ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (499.742365ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3217.777369ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (29.809023ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (355.017562ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (258.587156ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (83.332891ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (561.952407ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (482.894582ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1124.966495ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (645.829402ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (465.587129ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (152.348181ms)
|
||||
✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2776.636806ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (514.17354ms)
|
||||
✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (474.682607ms)
|
||||
✖ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (2382.158392ms)
|
||||
✖ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2616.321746ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (298.833085ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (23.52216ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (211.450717ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (217.2113ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (209.306043ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (290.875104ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (203.603086ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.449595ms)
|
||||
✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (201.610268ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (378.238162ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (288.579559ms)
|
||||
✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (208.957535ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (205.907514ms)
|
||||
✔ 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.057457ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.334455ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (205.403399ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (224.647774ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (242.201059ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (266.435397ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.384767ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.247695ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.339252ms)
|
||||
✔ 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.481711ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.032327ms)
|
||||
✔ 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.600962ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.71951ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.361179ms)
|
||||
✔ 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.32064ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.116364ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (229.520948ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (259.705961ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (308.605307ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (857.137594ms)
|
||||
✔ H4: self-takeover is refused (260.685225ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (515.268057ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1042.342631ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (300.993764ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (537.300747ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (254.811001ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (142.498836ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (183.191576ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (554.415807ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (286.5008ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (195.883889ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (812.374021ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (341.901969ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (750.549857ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (256.124108ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (406.460934ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.658818ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (783.285315ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (588.026148ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (721.265872ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3179.697061ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (602.727506ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (23.131317ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.580767ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.698714ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (2.601182ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (3.152393ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.608096ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.391492ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (1.089866ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.373901ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (4.194578ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.601703ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (5.150193ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.950429ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.73455ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.494877ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (1.670162ms)
|
||||
✔ F9: registrations never add or redirect a root (1.536725ms)
|
||||
✔ F10: a header cwd naming another project is refused (3.728479ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (0.699051ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.113165ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.894503ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.326266ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (0.836781ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (491.224916ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (4.766004ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.536594ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (2.423983ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.093858ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (2.182606ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (752.026434ms)
|
||||
✔ the engine pin holds for the installed package (1.936177ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (258.89728ms)
|
||||
✔ 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) (510.669015ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (252.423303ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (524.98724ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (452.564003ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (246.867638ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (20.968745ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (431.254543ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (254.757881ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (336.268659ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (471.822751ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1880.34387ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (190.558905ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (279.717161ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (148.516544ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (216.086324ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (356.438655ms)
|
||||
✔ N10: fake conformance (32.083433ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (400.421485ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (269.090395ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (283.314204ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (382.874514ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (339.723918ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (412.28814ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (250.56939ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (444.092197ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (919.349629ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (470.70348ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (480.686403ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (194.348212ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (200.131924ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (187.287538ms)
|
||||
✔ 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 (150.490115ms)
|
||||
✔ 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 (184.831315ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 175
|
||||
ℹ fail 2
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 57236.688204
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/conversation/tests/cohort.test.mjs:1049:1
|
||||
✖ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (2382.158392ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
+ [
|
||||
+ [
|
||||
+ 2483563,
|
||||
+ 'SIGKILL'
|
||||
+ ]
|
||||
+ ]
|
||||
- []
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r51b/wt2/packages/conversation/tests/cohort.test.mjs:1065:12)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ [ 2483563, 'SIGKILL' ] ],
|
||||
expected: [],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/conversation/tests/cohort.test.mjs:1081:1
|
||||
✖ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2616.321746ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
+ [
|
||||
+ [
|
||||
+ 2484011,
|
||||
+ 'SIGKILL'
|
||||
+ ]
|
||||
+ ]
|
||||
- []
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r51b/wt2/packages/conversation/tests/cohort.test.mjs:1105:10)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ [ 2484011, 'SIGKILL' ] ],
|
||||
expected: [],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (212.615731ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (32.954294ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (18.172829ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (375.941814ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (399.276752ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (258.418955ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (327.362714ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (350.509686ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.708729ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12212.045852ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (38082.591861ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (260.985979ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (143.524135ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (633.509338ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (268.965183ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (345.28464ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (114.490507ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (196.416052ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (271.662288ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (858.457464ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (288.898611ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (102.578258ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (68.340129ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.502359ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.08239ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.79788ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (25.157925ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (950.026134ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (456.763097ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (1018.61259ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (3045.193125ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (749.608773ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (788.435946ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (711.377048ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5481.467648ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (981.028413ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (1027.723225ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (547.138591ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (649.637945ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (300.307963ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (459.679536ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3269.640619ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (41.334565ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (290.835409ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (335.082012ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (92.413809ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (411.927967ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (659.419553ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1559.002039ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (812.38225ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (465.632314ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (329.796416ms)
|
||||
✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2807.774302ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (566.731504ms)
|
||||
✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (604.989126ms)
|
||||
✖ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (2542.372443ms)
|
||||
✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2568.711852ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (280.507215ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (26.4886ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (209.488238ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (202.927672ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (200.23979ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (256.85389ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (197.146957ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.751775ms)
|
||||
✔ 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.9848ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (344.230194ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (380.320119ms)
|
||||
✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (241.803609ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (271.365464ms)
|
||||
✔ 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 (226.561464ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.142369ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (219.351216ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (221.08819ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (253.313493ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (205.011234ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.443345ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.271284ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.342211ms)
|
||||
✔ 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.470868ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (31.35788ms)
|
||||
✔ 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.532051ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (4.766349ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.428898ms)
|
||||
✔ 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.356401ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.104975ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (244.665777ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (253.55239ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (291.595553ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (776.71445ms)
|
||||
✔ H4: self-takeover is refused (326.945905ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (651.319089ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1081.309342ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (234.532032ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (549.6886ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (264.904697ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (182.954717ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (241.729284ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (730.243349ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (297.716439ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (196.415793ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (848.242939ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (318.528706ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (732.465149ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (192.488473ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (339.805324ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.658929ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (677.30021ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (565.875447ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (740.833321ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3052.013796ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (633.102526ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (25.75198ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.875927ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (2.133952ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.96991ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.749885ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.53229ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.205763ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (0.947565ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.357601ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.501526ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.260406ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.696449ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.836895ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.693931ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.863366ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (2.15975ms)
|
||||
✔ F9: registrations never add or redirect a root (1.678725ms)
|
||||
✔ F10: a header cwd naming another project is refused (4.338571ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (0.880941ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (5.50669ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.085123ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.471323ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (0.985429ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (543.976097ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (5.302138ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.706787ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (2.642896ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.358674ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (2.653337ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (832.484232ms)
|
||||
✔ the engine pin holds for the installed package (1.999531ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (276.297631ms)
|
||||
✔ 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) (574.652583ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (269.138997ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (480.46456ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (408.407851ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (231.048426ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.130964ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (417.115509ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (403.354604ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (343.135342ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (544.160761ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1930.930805ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (200.844189ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (292.509154ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (305.910763ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (219.720988ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (381.512159ms)
|
||||
✔ N10: fake conformance (30.857024ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (439.945628ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (286.871771ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (289.672433ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (356.781258ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (353.983378ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (340.074145ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (191.814421ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (365.451159ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (644.923613ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (468.295227ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (565.849602ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (233.962533ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (235.330515ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (230.600881ms)
|
||||
✔ 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.840992ms)
|
||||
✔ 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 (210.222027ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 176
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 58995.641837
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/conversation/tests/cohort.test.mjs:1049:1
|
||||
✖ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (2542.372443ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
+ [
|
||||
+ [
|
||||
+ 2472191,
|
||||
+ 'SIGKILL'
|
||||
+ ]
|
||||
+ ]
|
||||
- []
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r51b/wt2/packages/conversation/tests/cohort.test.mjs:1065:12)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ [ 2472191, 'SIGKILL' ] ],
|
||||
expected: [],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
agents/dewey/work/queue-51/evidence.md: OK
|
||||
packages/conversation/README.md: OK
|
||||
packages/conversation/src/controller.mjs: OK
|
||||
packages/conversation/tests/cohort.test.mjs: OK
|
||||
packages/conversation/tests/ctrl-child.mjs: OK
|
||||
@@ -0,0 +1,35 @@
|
||||
# mutate.py <id>: apply one named mutant (each edit exact text, must match once). Run from the tree root.
|
||||
import sys
|
||||
CT = "packages/conversation/src/controller.mjs"
|
||||
PROOF = " if (b.state !== \"stopped\" || b.admission !== \"closed\" || !this.#stopped(s)) return refused(\"stop-proof\");\n"
|
||||
RECREL = " // After every check, so a refused recover changes nothing (K6).\n await this.#releaseListed(\"recover\", this.claim);\n"
|
||||
REL = " await this.#releaseListed(\"recover\", this.claim);\n"
|
||||
CONF = " if (!this.#checkConfirmation(r, c, \"recover\")) return refused(\"confirmation\");\n"
|
||||
TARGET = " if (session.leaf !== this.claim.record.leafAtProof || session.branch !== this.claim.record.branchAtProof) return refused(\"target\");\n"
|
||||
KILL = " const kill = killEngine && this.b?.state !== \"stopped\";\n"
|
||||
M = {
|
||||
# Round 1's order: the release right after the stop-proof check.
|
||||
"recconf": [(CT, CONF + RECREL, CONF), (CT, PROOF, PROOF + REL)],
|
||||
# The release above the stop-proof check.
|
||||
"recbefore": [(CT, CONF + RECREL, CONF), (CT, PROOF, REL + PROOF)],
|
||||
# The release after the pins and target checks, before the confirmation.
|
||||
"recpreconf": [(CT, CONF + RECREL, CONF), (CT, TARGET, TARGET + REL)],
|
||||
# The release after the acquire.
|
||||
"recafteracq": [(CT, CONF + RECREL, CONF), (CT, " const e = { id: newId(\"eligibility\")", REL + " const e = { id: newId(\"eligibility\")")],
|
||||
"norecover": [(CT, CONF + RECREL, CONF)],
|
||||
# The free-path release isn't awaited.
|
||||
"startnoawait": [(CT, " await this.#releaseListed(\"start\", { claimId: h.record.claimId, record: h.record });\n", " void this.#releaseListed(\"start\", { claimId: h.record.claimId, record: h.record });\n")],
|
||||
"noseat": [(CT, " for (const h of [prior, seatHead]) {\n", " for (const h of [prior]) {\n")],
|
||||
"nolookup": [(CT, " if ((await this.units.lookup(claim.record)).state === \"absent\") return null;\n", "")],
|
||||
"nodelete": [(CT, " if (this.scopeReleases.get(claim.claimId) === earlier) this.scopeReleases.delete(claim.claimId);\n", "")],
|
||||
"closeproof": [(CT, KILL, " const kill = killEngine && !(this.b?.state === \"stopped\" && this.#stopped(this.stops.get(this.b.stop)));\n")],
|
||||
"closekill": [(CT, KILL, " const kill = killEngine;\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)
|
||||
@@ -0,0 +1,217 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (226.896607ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (28.167646ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (19.533473ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (533.661328ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (573.639837ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (291.883319ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (297.703451ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (240.281394ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.639861ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12439.411312ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (38250.348807ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (587.732298ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (142.627862ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (609.479298ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (278.793036ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (338.000199ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (107.101786ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (198.122106ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (260.187021ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (735.704419ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (183.858666ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (87.005575ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (66.908967ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.10703ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.080602ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.890131ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.462797ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1144.202948ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (623.245162ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (866.471947ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (3157.241432ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (921.012814ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (866.497033ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (737.657858ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5680.305159ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (952.552614ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (899.213326ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (671.936336ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (656.353945ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (365.791973ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (463.193596ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3260.143648ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (23.751259ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (322.919993ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (260.296742ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (186.884461ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (567.983481ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (476.454332ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1111.571723ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (609.684895ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (469.888528ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (130.838241ms)
|
||||
✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2959.690252ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (510.899033ms)
|
||||
✖ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (574.777454ms)
|
||||
✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (608.135217ms)
|
||||
✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2659.780102ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (297.423221ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (25.344182ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (207.208821ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (201.624311ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (312.677902ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (470.195358ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (275.342539ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.48336ms)
|
||||
✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (295.018121ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (410.414633ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (222.041395ms)
|
||||
✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (204.167426ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (202.253322ms)
|
||||
✔ 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 (243.466736ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.007282ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (275.01146ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (235.870356ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (285.048607ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (301.444604ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.402355ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.249265ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.294525ms)
|
||||
✔ 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.501275ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (29.99981ms)
|
||||
✔ 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.441533ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.745967ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.386907ms)
|
||||
✔ 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.337994ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.09934ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (226.63829ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (252.986371ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (322.748226ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (1242.792072ms)
|
||||
✔ H4: self-takeover is refused (278.57893ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (463.271877ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1152.415204ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (307.928665ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (862.829488ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (382.599142ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (328.329235ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (279.84945ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (920.304786ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (329.976404ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (197.961154ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (886.344803ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (346.300989ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (758.068719ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (196.489896ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (346.946876ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.646656ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (675.938599ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (532.404586ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (695.185473ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2945.789989ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (594.199638ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (25.672329ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.312514ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.717305ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.839754ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.548523ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.684725ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.027635ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (0.790368ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.428343ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (4.656609ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (3.990091ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.217317ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.156329ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.236428ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.871729ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (2.025644ms)
|
||||
✔ F9: registrations never add or redirect a root (1.8747ms)
|
||||
✔ F10: a header cwd naming another project is refused (3.909609ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (0.747161ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.683048ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (3.279355ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.805471ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (0.830317ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (586.20837ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (5.247409ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.810645ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (2.498546ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.32926ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (2.189072ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (828.456167ms)
|
||||
✔ the engine pin holds for the installed package (1.881383ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (272.485936ms)
|
||||
✔ 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) (611.46647ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (279.112616ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (501.209635ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (762.731897ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (327.419075ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.787925ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (520.917686ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (212.454075ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (299.890058ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (549.693022ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1946.173288ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (234.998239ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (461.304762ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (333.84256ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (360.655293ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (545.493017ms)
|
||||
✔ N10: fake conformance (32.993837ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (417.593929ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (280.644408ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (302.592573ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (351.530989ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (350.226112ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (363.036491ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (202.782065ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (369.617713ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (656.570315ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (525.142557ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (498.476743ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (150.534811ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (192.210776ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (203.655826ms)
|
||||
✔ 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.867312ms)
|
||||
✔ 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 (195.969388ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 176
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 59728.388899
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/conversation/tests/cohort.test.mjs:1004:1
|
||||
✖ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (574.777454ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
[
|
||||
[
|
||||
'force-stop',
|
||||
'unavailable',
|
||||
null
|
||||
],
|
||||
- [
|
||||
- 'recover',
|
||||
- 'released',
|
||||
- 'absent'
|
||||
- ]
|
||||
]
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r51b/wt2/packages/conversation/tests/cohort.test.mjs:1030:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ [ 'force-stop', 'unavailable', null ] ],
|
||||
expected: [ [ 'force-stop', 'unavailable', null ], [ 'recover', 'released', 'absent' ] ],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (209.812305ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (31.596713ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (16.865413ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (409.009847ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (382.734026ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (234.151608ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (198.261514ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (190.708869ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.948471ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (11976.054483ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (39366.094305ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (262.918616ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (143.497175ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (616.11398ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (279.842443ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (359.418164ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (112.281746ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (215.496192ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (270.262984ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (754.103211ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (259.694804ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (91.528696ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (72.767099ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.52146ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.098365ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.791037ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (29.227788ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1035.074876ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (444.063051ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (747.970793ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (2975.7536ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (679.355826ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (830.856437ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (833.005125ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5756.682073ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (768.039865ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (585.80089ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (659.24289ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (613.572007ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (315.870588ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (452.34197ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3285.257435ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (120.380693ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (381.635805ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (375.473852ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (86.767929ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (478.110743ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (656.340734ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1585.899954ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (847.578589ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (448.219879ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (318.640551ms)
|
||||
✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (3026.507972ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (552.965142ms)
|
||||
✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (704.598562ms)
|
||||
✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (657.20104ms)
|
||||
✖ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2541.711065ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (273.218951ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.675367ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (203.278494ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (190.159429ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (284.165594ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (276.216987ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (192.580108ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.427424ms)
|
||||
✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (198.125481ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (306.1816ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (205.357906ms)
|
||||
✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (171.935943ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (203.4889ms)
|
||||
✔ 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 (190.720463ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.07304ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (193.427393ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (213.752328ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (234.238319ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (189.47783ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.396529ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.287241ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.317257ms)
|
||||
✔ 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.471462ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.840346ms)
|
||||
✔ 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.421114ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.788254ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.355126ms)
|
||||
✔ 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.30335ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.100639ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (217.928978ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (244.055458ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (362.856651ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (800.119886ms)
|
||||
✔ H4: self-takeover is refused (196.524786ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (411.032099ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (975.505451ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (212.751537ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (522.6803ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (259.129737ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (120.968325ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (167.479335ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (602.934601ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (272.219954ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (200.97538ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (846.808199ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (445.990408ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (908.374606ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (197.114166ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (337.362618ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.675388ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (661.274751ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (567.551798ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (684.46252ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3069.254786ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (591.446983ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (25.600964ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.094545ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.67267ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.800012ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.399652ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.511162ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.792705ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (0.820786ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.175867ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.065015ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.002963ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.205844ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.321985ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (7.553294ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.248563ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (1.899766ms)
|
||||
✔ F9: registrations never add or redirect a root (1.936515ms)
|
||||
✔ F10: a header cwd naming another project is refused (4.081673ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (0.783219ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.2913ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.10679ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.463133ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (0.784714ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (533.074989ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (4.832583ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.651953ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (2.36422ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.027547ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (1.904937ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (755.259232ms)
|
||||
✔ the engine pin holds for the installed package (1.789637ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (276.96992ms)
|
||||
✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (519.896012ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (253.034583ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (542.506214ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (441.081989ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (229.238773ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.793548ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (351.907095ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (194.730682ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (277.342536ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (446.459741ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1861.831437ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (195.66958ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (280.564421ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (158.344467ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (174.885146ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (382.451067ms)
|
||||
✔ N10: fake conformance (32.692746ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (412.148167ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (330.487566ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (334.684261ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (533.167021ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (344.461037ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (354.541594ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (160.860968ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (260.88606ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (699.367313ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (483.641113ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (444.86105ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (229.607426ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (174.032052ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (178.164937ms)
|
||||
✔ 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 (188.268429ms)
|
||||
✔ 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 (130.040069ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 176
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 60228.738662
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/conversation/tests/cohort.test.mjs:1081:1
|
||||
✖ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2541.711065ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
+ [
|
||||
+ {
|
||||
+ at: '2026-10-10T06:55:17.157Z',
|
||||
+ claim: 'c28dd8cd48878438e098ae625',
|
||||
+ kind: 'release',
|
||||
+ outcome: 'unavailable',
|
||||
+ reason: 'the shim socket is gone',
|
||||
+ unitName: 'mosaic-chat-c28dd8cd48878438e098ae625',
|
||||
+ why: 'start'
|
||||
+ }
|
||||
+ ]
|
||||
- []
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r51b/wt2/packages/conversation/tests/cohort.test.mjs:1097:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ { kind: 'release', claim: 'c28dd8cd48878438e098ae625', unitName: 'mosaic-chat-c28dd8cd48878438e098ae625', why: 'start', outcome: 'unavailable', reason: 'the shim socket is gone', at: '2026-10-10T06:55:17.157Z' } ],
|
||||
expected: [],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (215.170552ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (33.477186ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (21.006625ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (364.840205ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (389.6812ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (239.41792ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (196.408249ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (197.043518ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.547323ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (11891.313298ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (40420.670333ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (252.681062ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (139.685421ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (590.062676ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (291.664023ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (354.584775ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (117.772268ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (198.709689ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (293.169015ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (850.525028ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (320.677285ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (114.315183ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (69.629722ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.285896ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.114413ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.78544ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (25.527073ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1012.077119ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (443.019159ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (773.426661ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (2973.269052ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (792.091835ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (832.297729ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (680.570445ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5644.26973ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (795.416915ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (688.579434ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (749.657801ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (771.86662ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (378.105552ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (491.332555ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3376.794173ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (25.283336ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (350.14358ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (316.621789ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (82.812787ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (408.532703ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (723.683599ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1450.673821ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (863.428173ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (447.272796ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (319.898071ms)
|
||||
✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2690.627541ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (497.20001ms)
|
||||
✖ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (445.507538ms)
|
||||
✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (612.67698ms)
|
||||
✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2746.456872ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (329.589344ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (29.296328ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (222.109682ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (209.503651ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (204.993231ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (270.92844ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (194.457793ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.459826ms)
|
||||
✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (189.203179ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (292.403718ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (215.073906ms)
|
||||
✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (194.307285ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (198.545471ms)
|
||||
✔ 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 (183.928173ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.948964ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (192.864984ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (208.927278ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (234.138913ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (194.908463ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.443642ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.271509ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.317933ms)
|
||||
✔ 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.500376ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (31.007031ms)
|
||||
✔ 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.499771ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (4.715733ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.366764ms)
|
||||
✔ 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.334405ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.098534ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (218.196132ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (258.894123ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (291.911283ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (798.265657ms)
|
||||
✔ H4: self-takeover is refused (195.719803ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (448.51721ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (973.316036ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (230.471509ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (523.538541ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (252.88333ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (121.08094ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (203.838287ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (610.900181ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (284.492614ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (232.67284ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (1109.159981ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (324.238266ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (831.653949ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (257.554531ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (511.50483ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.652272ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (655.745909ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (644.505046ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (700.44632ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2973.56528ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (667.673025ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (29.595585ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (8.87445ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (2.545328ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (2.780402ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (3.475793ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.503766ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.981315ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (0.782809ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.177764ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.107129ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (6.682489ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.769212ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (5.67859ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.648663ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.134571ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (1.815001ms)
|
||||
✔ F9: registrations never add or redirect a root (1.740743ms)
|
||||
✔ F10: a header cwd naming another project is refused (3.898653ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (0.646724ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (3.829802ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.81509ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.380724ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (0.688858ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (499.657127ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (4.561411ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.426883ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (2.12751ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.013351ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (1.8574ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (801.496918ms)
|
||||
✔ the engine pin holds for the installed package (1.646285ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (250.79459ms)
|
||||
✔ 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) (521.688109ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (259.23397ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (504.737175ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (440.160182ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (221.91143ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (22.00951ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (351.9517ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (200.143859ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (297.338052ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (437.712847ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1880.007298ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (200.582058ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (291.272496ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (123.457006ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (222.823816ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (441.836439ms)
|
||||
✔ N10: fake conformance (31.753601ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (558.888182ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (336.669293ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (293.04274ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (375.361684ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (406.465183ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (518.646315ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (265.696333ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (360.435017ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (694.070417ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (461.696881ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (526.185925ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (231.714244ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (199.196276ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (201.727211ms)
|
||||
✔ 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 (206.304146ms)
|
||||
✔ 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 (181.693035ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 176
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 60796.862557
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/conversation/tests/cohort.test.mjs:1004:1
|
||||
✖ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (445.507538ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
[
|
||||
[
|
||||
'force-stop',
|
||||
'unavailable',
|
||||
null
|
||||
],
|
||||
- [
|
||||
- 'recover',
|
||||
- 'released',
|
||||
- 'absent'
|
||||
- ]
|
||||
]
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r51b/wt2/packages/conversation/tests/cohort.test.mjs:1030:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ [ 'force-stop', 'unavailable', null ] ],
|
||||
expected: [ [ 'force-stop', 'unavailable', null ], [ 'recover', 'released', 'absent' ] ],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (208.335245ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (30.804067ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (18.141178ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (449.2095ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (395.702205ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (314.793962ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (369.614912ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (282.170495ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.440145ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12139.771894ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (38045.925585ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (271.299767ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (148.267221ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (707.182078ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (289.313634ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (356.117155ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (105.689856ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (199.658778ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (277.672583ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (854.170473ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (287.05972ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (133.594921ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (67.196345ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.108285ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.043674ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.720508ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.640047ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1048.808795ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (628.747876ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (865.840818ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (3034.499324ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (744.83389ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (805.557532ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (687.314358ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5779.74429ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (804.639537ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (640.450825ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (659.791383ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (641.232446ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (305.297427ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (463.253744ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3247.804413ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (23.28651ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (493.243577ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (288.065011ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (61.270123ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (563.119537ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (496.541418ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1143.283558ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (676.033841ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (470.863571ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (149.113176ms)
|
||||
✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2933.869625ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (600.549563ms)
|
||||
✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (630.189503ms)
|
||||
✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (434.438333ms)
|
||||
✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2561.276153ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (293.926632ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.505904ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (198.925211ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (289.980101ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (199.771152ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (279.289306ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (187.287453ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.44446ms)
|
||||
✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (332.782377ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (437.935405ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (277.693113ms)
|
||||
✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (193.019713ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (230.4527ms)
|
||||
✔ 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 (217.647024ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.870431ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (213.643309ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (219.64474ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (266.061614ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (203.893232ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.41743ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.253165ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.356142ms)
|
||||
✔ 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.451286ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.787587ms)
|
||||
✔ 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.436354ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.695302ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.393155ms)
|
||||
✔ 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.341205ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.100036ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (219.226677ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (243.735089ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (381.377634ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (1000.852196ms)
|
||||
✔ H4: self-takeover is refused (311.157753ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (501.709605ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1091.831676ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (234.353692ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (532.66838ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (257.643221ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (248.448234ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (257.956489ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (731.367457ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (277.171107ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (189.966526ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (861.355521ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (353.98858ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (741.917678ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (201.23048ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (324.71843ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.629585ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (783.649792ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (604.820208ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (721.411188ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3142.900143ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (613.31105ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (25.735249ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (5.506033ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.568698ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.771072ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.64893ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.582295ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.866454ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (0.778575ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.170755ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (2.964273ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (3.764444ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.073864ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.061467ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.089697ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.494513ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (1.838199ms)
|
||||
✔ F9: registrations never add or redirect a root (1.734545ms)
|
||||
✔ F10: a header cwd naming another project is refused (4.020293ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (0.91808ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.13723ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.987223ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.469848ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (0.823311ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (513.288597ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (4.76624ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.563216ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (2.36197ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.091818ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (2.026722ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (806.487462ms)
|
||||
✔ the engine pin holds for the installed package (1.612443ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (280.251566ms)
|
||||
✔ 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) (516.292775ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (260.530626ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (557.019846ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (432.800671ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (228.799031ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.159821ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (647.110096ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (277.128403ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (297.290958ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (512.775306ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1950.550684ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (318.848428ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (363.353454ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (180.594145ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (209.599186ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (380.233193ms)
|
||||
✔ N10: fake conformance (32.898433ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (430.218948ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (275.519677ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (296.148196ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (354.434361ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (347.797905ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (355.902735ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (185.30156ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (520.539816ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (824.293104ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (531.747838ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (452.349178ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (190.09251ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (222.999335ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (237.821861ms)
|
||||
✔ 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 (215.32801ms)
|
||||
✔ 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 (176.575088ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 177
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 59122.611429
|
||||
@@ -0,0 +1,185 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (224.276041ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (34.245092ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (22.236075ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (580.596071ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (405.237972ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (252.194002ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (239.508739ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (212.686409ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.473714ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (11899.291831ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (37048.584383ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (257.187704ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (142.610484ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (629.479348ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (278.736789ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (344.772895ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (107.630612ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (198.095481ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (272.512172ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (722.993264ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (176.47258ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (84.673881ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (72.809741ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.197943ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.083562ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.813762ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (23.921731ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1148.142792ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (514.348128ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (635.841017ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (2853.131257ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (528.072967ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (603.463883ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (560.347123ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5403.131079ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (849.098362ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (708.729863ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (545.872657ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (803.989196ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (448.335724ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (689.38692ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3310.752385ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (41.265728ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (448.247413ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (400.737811ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (83.411625ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (405.951543ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (581.650142ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1208.977412ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (745.07535ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (469.029856ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (128.249475ms)
|
||||
✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2713.997118ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (879.864057ms)
|
||||
✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (835.068065ms)
|
||||
✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (550.007806ms)
|
||||
✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (3104.39794ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (358.699967ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (33.368854ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (217.756576ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (345.390643ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (240.212003ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (308.736158ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (220.848815ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.432648ms)
|
||||
✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (218.376943ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (340.680597ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (239.172097ms)
|
||||
✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (214.522511ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (203.844477ms)
|
||||
✔ 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 (226.859903ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (9.922895ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (230.877469ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (256.914076ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (470.691858ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (200.849178ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.401129ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.253758ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.30143ms)
|
||||
✔ 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.51301ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (29.97913ms)
|
||||
✔ 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.450825ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (4.695976ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.363883ms)
|
||||
✔ 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.32382ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.100439ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (224.245948ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (259.126547ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (440.230376ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (954.678392ms)
|
||||
✔ H4: self-takeover is refused (223.363243ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (481.276316ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1371.800544ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (210.261459ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (544.597895ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (339.477899ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (195.753394ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (238.363702ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (602.7895ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (287.773078ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (210.064333ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (916.804377ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (341.950362ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (779.012529ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (288.631243ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (323.266ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.667803ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (681.134503ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (569.855993ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (790.489911ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3066.603452ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (676.840062ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (26.684167ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.029149ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.857382ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.803048ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.418186ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.439927ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.064654ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (0.84148ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.220585ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.930635ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (3.960169ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.334059ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.43036ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.423236ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.761852ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (1.739403ms)
|
||||
✔ F9: registrations never add or redirect a root (1.680381ms)
|
||||
✔ F10: a header cwd naming another project is refused (4.749424ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (0.835039ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.786641ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.360068ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.45859ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (0.878861ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (509.534207ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (4.51014ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.431615ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (2.226766ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.039357ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (1.855545ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (750.776831ms)
|
||||
✔ the engine pin holds for the installed package (1.781262ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (268.468798ms)
|
||||
✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (563.474712ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (242.011791ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (641.21541ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (507.011541ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (255.049849ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.836272ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (410.713002ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (226.21061ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (318.216617ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (501.077015ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1900.513065ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (194.941654ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (339.17847ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (193.058971ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (237.298597ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (366.033663ms)
|
||||
✔ N10: fake conformance (33.065318ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (426.501011ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (312.073069ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (303.988614ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (357.840398ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (348.838366ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (369.560143ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (210.512832ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (458.452105ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (757.178809ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (570.315461ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (472.512345ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (334.656683ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (208.14998ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (252.247066ms)
|
||||
✔ 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 (238.775426ms)
|
||||
✔ 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 (237.999996ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 177
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 57450.555787
|
||||
@@ -0,0 +1,215 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (211.958885ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (29.960168ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (16.341998ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (470.503578ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (421.52755ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (250.22264ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (202.939545ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (343.035588ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.520463ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (11604.979262ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (36539.259777ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (292.776851ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (145.958948ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (627.886066ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (271.42409ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (409.861616ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (107.011865ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (229.246448ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (264.111111ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (742.655551ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (188.388325ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (98.982846ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (74.824269ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.416892ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.099809ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.689025ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.265662ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (897.511956ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (501.187702ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (721.7731ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (2792.24843ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (516.101412ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (696.405054ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (790.540644ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5551.786173ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (737.124835ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (573.621717ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (570.405763ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (864.599047ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (511.116161ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (446.215128ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3284.684864ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (23.776247ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (383.89008ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (400.14541ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (82.911807ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (441.131681ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (512.330227ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1208.484694ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (1018.165239ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (468.130204ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (170.978572ms)
|
||||
✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2834.549352ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (480.819663ms)
|
||||
✖ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (412.719114ms)
|
||||
✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (437.657747ms)
|
||||
✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2852.054048ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (395.673441ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.189207ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (202.660235ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (215.367686ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (304.704976ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (299.338767ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (221.245526ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.427986ms)
|
||||
✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (216.895719ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (314.71448ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (325.086317ms)
|
||||
✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (279.66165ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (207.524721ms)
|
||||
✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (201.015013ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.927189ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (207.551642ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (215.322145ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (244.593291ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (194.363396ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.42249ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.262042ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.324137ms)
|
||||
✔ 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.464316ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.948215ms)
|
||||
✔ 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.780661ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.694361ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.326778ms)
|
||||
✔ 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.334249ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.113653ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (224.501774ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (256.275432ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (411.124909ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (869.944763ms)
|
||||
✔ H4: self-takeover is refused (309.229816ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (479.055933ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1011.289537ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (165.178179ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (502.134199ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (277.805647ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (197.013505ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (211.094725ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (596.697907ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (344.232562ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (246.027616ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (975.38381ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (345.29645ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (792.007861ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (206.897442ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (339.479585ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.594249ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (658.635923ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (740.560857ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (832.500122ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3001.000123ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (614.966714ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.70864ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.958501ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.918143ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.98309ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.683498ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.48295ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.166673ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (0.877164ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.564766ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.713257ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.522341ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.579185ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (5.494397ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (8.042311ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.207736ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (1.849865ms)
|
||||
✔ F9: registrations never add or redirect a root (1.732921ms)
|
||||
✔ F10: a header cwd naming another project is refused (3.971515ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (0.782576ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.241832ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.06562ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.435508ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (0.786967ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (513.773782ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (4.408661ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.419166ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (3.027247ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.123539ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (1.914753ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (815.714898ms)
|
||||
✔ the engine pin holds for the installed package (2.064865ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (256.205333ms)
|
||||
✔ 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) (513.054807ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (283.652637ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (491.970658ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (567.539955ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (256.650578ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (22.036306ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (378.333597ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (263.207522ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (391.436359ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (484.878691ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1897.078987ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (212.246785ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (293.029579ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (179.734968ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (272.894268ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (502.516027ms)
|
||||
✔ N10: fake conformance (33.851012ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (537.830687ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (269.882505ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (286.309944ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (373.573718ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (370.244517ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (375.875036ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (206.884823ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (327.887838ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (756.308683ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (597.225894ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (666.165563ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (296.347293ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (206.398192ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (211.325724ms)
|
||||
✔ 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 (208.867155ms)
|
||||
✔ 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 (150.939072ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 176
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 57236.029796
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/conversation/tests/cohort.test.mjs:1004:1
|
||||
✖ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (412.719114ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
[
|
||||
[
|
||||
'force-stop',
|
||||
'unavailable'
|
||||
],
|
||||
+ [
|
||||
+ 'recover',
|
||||
+ 'released'
|
||||
+ ]
|
||||
]
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r51b/wt2/packages/conversation/tests/cohort.test.mjs:1026:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ [ 'force-stop', 'unavailable' ], [ 'recover', 'released' ] ],
|
||||
expected: [ [ 'force-stop', 'unavailable' ] ],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (264.947409ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (35.35371ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (24.6948ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (418.158589ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (454.532882ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (277.08111ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (230.285948ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (226.476336ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.720464ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12714.970145ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (38014.603994ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (272.431381ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (175.601545ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (808.081182ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (277.717109ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (348.822811ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (118.390096ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (202.342613ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (366.330975ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (1113.061177ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (266.746299ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (107.785347ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (70.992438ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.411726ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.057437ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.743979ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (25.713161ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1041.793627ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (551.298708ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (881.161215ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (3149.961144ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (744.198249ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (917.869588ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (777.111469ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (6136.868929ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (812.234851ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (666.648443ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (721.783192ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (556.028097ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (335.361745ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (482.20854ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3236.675895ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (35.492232ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (350.775572ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (269.293855ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (112.425861ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (348.228132ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (562.240019ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1435.712925ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (684.958149ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (469.333903ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (150.983736ms)
|
||||
✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2684.697769ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (548.809239ms)
|
||||
✖ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (553.41641ms)
|
||||
✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (450.879837ms)
|
||||
✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2622.681766ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (278.78895ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (22.792533ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (267.902207ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (237.561224ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (237.375866ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (339.023306ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (264.345834ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.435006ms)
|
||||
✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (229.201308ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (332.507301ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (259.31901ms)
|
||||
✔ 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.06733ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (238.820482ms)
|
||||
✔ 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 (296.641394ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (10.659768ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (237.880281ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (241.43922ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (290.242591ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (255.615096ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.395397ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.257531ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.314626ms)
|
||||
✔ 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.520481ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (31.052516ms)
|
||||
✔ 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.4807ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.753935ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.377655ms)
|
||||
✔ 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.843527ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.100207ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (235.442879ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (316.40165ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (335.777717ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (980.59686ms)
|
||||
✔ H4: self-takeover is refused (229.517161ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (525.007908ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1266.035771ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (297.19431ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (753.362826ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (402.345554ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (226.688158ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (195.250413ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (672.578267ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (414.313965ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (226.399649ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (976.839815ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (396.142538ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (1121.577209ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (215.215483ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (354.865079ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.645369ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (680.410159ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (553.444648ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (728.306273ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2969.173218ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (631.503385ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (30.099439ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (7.510772ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.978582ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (2.178874ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.864086ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.940529ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.491035ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (0.953011ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.435892ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.888682ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (5.368458ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (7.052692ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (6.587632ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (8.242846ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (9.782678ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (3.040379ms)
|
||||
✔ F9: registrations never add or redirect a root (2.773731ms)
|
||||
✔ F10: a header cwd naming another project is refused (7.045157ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (1.223336ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (7.496866ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.338215ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.69831ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (0.874033ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (543.549405ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (5.240004ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.800149ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (2.790933ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.40637ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (2.364965ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (803.379266ms)
|
||||
✔ the engine pin holds for the installed package (2.023074ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (310.42466ms)
|
||||
✔ 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) (564.403331ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (263.283747ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (600.671629ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (516.818756ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (307.571899ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (23.03312ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (405.282364ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (240.433892ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (326.502964ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (592.499206ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1959.275569ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (207.731374ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (313.18067ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (219.051601ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (266.042742ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (454.039531ms)
|
||||
✔ N10: fake conformance (31.7504ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (552.99864ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (325.882114ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (309.906978ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (404.305145ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (404.087587ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (415.562475ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (481.404826ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (389.779315ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (721.199238ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (576.637358ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (494.071685ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (263.068864ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (222.416903ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (221.813038ms)
|
||||
✔ 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 (220.529956ms)
|
||||
✔ 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 (211.268215ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 176
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 60509.784615
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/conversation/tests/cohort.test.mjs:1004:1
|
||||
✖ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (553.41641ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
[
|
||||
[
|
||||
'force-stop',
|
||||
'unavailable'
|
||||
],
|
||||
+ [
|
||||
+ 'recover',
|
||||
+ 'released'
|
||||
+ ]
|
||||
]
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r51b/wt2/packages/conversation/tests/cohort.test.mjs:1026:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ [ 'force-stop', 'unavailable' ], [ 'recover', 'released' ] ],
|
||||
expected: [ [ 'force-stop', 'unavailable' ] ],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (297.104214ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (42.102492ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (42.849545ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (459.503427ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (438.278885ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (254.053586ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (207.844531ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (197.620933ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.513686ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12197.524399ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (36892.685455ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (320.262508ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (164.961047ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (771.896626ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (357.562692ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (504.788946ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (176.59688ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (265.915761ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (480.422974ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (969.567699ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (189.539013ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (96.900449ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (71.45642ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (3.530222ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.135087ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.836776ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.268599ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (874.141267ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (548.94794ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (598.428892ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (2874.287719ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (861.71016ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (860.557523ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (662.361482ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5618.249577ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (855.192038ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (601.999032ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (426.255576ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (660.089301ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (471.07349ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (483.127129ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3263.341924ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (24.771603ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (393.351266ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (505.087401ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (245.589835ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (686.297616ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (1201.843304ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1562.067891ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (853.617944ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (479.186502ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (376.594148ms)
|
||||
✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (3215.254254ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (653.440932ms)
|
||||
✖ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (551.848702ms)
|
||||
✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (717.541607ms)
|
||||
✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2647.777733ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (405.287027ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (25.577974ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (336.247858ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (316.700648ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (269.660953ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (327.897507ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (226.42036ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.426849ms)
|
||||
✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (210.654385ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (292.018923ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (247.549412ms)
|
||||
✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (240.605619ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (214.271049ms)
|
||||
✔ 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 (217.38884ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.007639ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (202.01105ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (228.551614ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (237.401404ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (193.087323ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.428087ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.28537ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.312901ms)
|
||||
✔ 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.500472ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (31.133186ms)
|
||||
✔ 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.478062ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.869248ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.450064ms)
|
||||
✔ 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.341713ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.094632ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (233.00939ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (403.707857ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (388.165837ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (919.399543ms)
|
||||
✔ H4: self-takeover is refused (186.257973ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (525.822379ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1036.147439ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (216.662448ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (538.949552ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (264.12417ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (131.303734ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (193.985449ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (552.645989ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (289.004961ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (206.418067ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (873.560085ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (348.61363ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (754.390638ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (175.417089ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (340.575023ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.626584ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (656.489649ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (554.33542ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (718.596812ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (2972.129836ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (674.785368ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (25.914158ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (5.572048ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.530231ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.773932ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.459041ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.331129ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.889302ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (0.772245ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.233077ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.518698ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.333228ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.404933ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.30556ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.172086ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (7.237802ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (1.640178ms)
|
||||
✔ F9: registrations never add or redirect a root (1.526778ms)
|
||||
✔ F10: a header cwd naming another project is refused (3.447216ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (0.650893ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (3.707053ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (1.770173ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.2625ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (0.680814ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (498.497901ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (5.047347ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (1.55498ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (2.51719ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.169498ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (2.069809ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (770.127883ms)
|
||||
✔ the engine pin holds for the installed package (1.662621ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (254.928902ms)
|
||||
✔ 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) (500.49113ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (258.38522ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (735.777761ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (540.606826ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (263.539491ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.875909ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (353.51312ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (236.952565ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (330.649176ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (485.81671ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1878.032569ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (191.195644ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (281.821233ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (193.489813ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (195.979094ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (409.762782ms)
|
||||
✔ N10: fake conformance (33.397479ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (438.783154ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (258.729852ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (289.817062ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (364.018275ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (359.301475ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (330.080207ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (198.06304ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (320.467282ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (650.492454ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (419.824533ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (505.604124ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (216.791965ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (202.548113ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (200.322565ms)
|
||||
✔ 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 (194.158269ms)
|
||||
✔ 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 (178.497429ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 176
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 58795.353516
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/conversation/tests/cohort.test.mjs:1004:1
|
||||
✖ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (551.848702ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
[
|
||||
[
|
||||
'force-stop',
|
||||
'unavailable'
|
||||
],
|
||||
+ [
|
||||
+ 'recover',
|
||||
+ 'released'
|
||||
+ ]
|
||||
]
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r51b/wt2/packages/conversation/tests/cohort.test.mjs:1026:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ [ 'force-stop', 'unavailable' ], [ 'recover', 'released' ] ],
|
||||
expected: [ [ 'force-stop', 'unavailable' ] ],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
# run.sh <mutant>: mutate, run the conversation suite, list and kill shims left under TMPDIR, restore from backups.
|
||||
m=$1
|
||||
export TMPDIR=~/darkwing-scratch/r51b/muttmp/mut-$m DOCKER_HOST=unix:///nonexistent.sock
|
||||
mkdir -p $TMPDIR
|
||||
M=~/darkwing-scratch/r51b/mut; cd ~/darkwing-scratch/r51b/wt2
|
||||
files=$(python3 -I $M/mutate.py $m --files)
|
||||
for f in $files; do cp -p $f $f.mutbak; done
|
||||
if python3 -I $M/mutate.py $m > /dev/null; then
|
||||
node --test "packages/conversation/tests/*.test.mjs" > $M/$m-conversation.txt 2>&1; e=$?
|
||||
else e=mutate-failed; fi
|
||||
left=$(ps -eo pid=,args= | grep -F "$TMPDIR/" | grep -F /shim.mjs | grep -v grep)
|
||||
n=$(printf '%s' "$left" | grep -c .)
|
||||
echo "$left" > $M/$m-shims-left.txt
|
||||
printf '%s\n' "$left" | while read pid rest; do
|
||||
[ -n "$pid" ] || continue
|
||||
u=$(tr '/' '\n' < /proc/$pid/cgroup | grep '^mosaic-chat-.*\.scope$')
|
||||
[ -n "$u" ] && systemctl --user kill --signal=SIGKILL "$u"
|
||||
kill -9 $pid 2>/dev/null
|
||||
done
|
||||
for f in $files; do mv $f.mutbak $f; done
|
||||
echo "$m rc $e $(grep -E '^ℹ (pass|fail)' $M/$m-conversation.txt | tr '\n' ' ') shims-left $n" >> $M/summary.txt
|
||||
@@ -0,0 +1,205 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (232.354988ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (32.278803ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (21.181463ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (561.49758ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (494.807754ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (311.283881ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (311.925349ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (221.512723ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.366163ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (12013.651124ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (38464.652826ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (259.940021ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (139.408344ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (643.731884ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (275.778957ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (332.632966ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (105.719633ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (190.270568ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (257.564243ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (720.413493ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (188.23406ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (97.032994ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (69.066726ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.081063ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.099107ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.752774ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.100311ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1124.004421ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (650.104063ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (827.067014ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (3019.167282ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (691.240889ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (811.093133ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (711.138089ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (5664.000003ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (993.803345ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (826.174909ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (654.418889ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (652.963495ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (317.754726ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (501.733936ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3258.053308ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (25.786224ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (323.312577ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (296.236361ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (82.806022ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (480.646861ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (725.283719ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1161.667499ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (655.227568ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (446.094989ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (374.913543ms)
|
||||
✖ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2633.661737ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (799.858285ms)
|
||||
✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (592.086319ms)
|
||||
✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (398.216694ms)
|
||||
✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2775.957761ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (397.616211ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.618707ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (223.113072ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (402.385907ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (200.91629ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (352.545712ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (386.193275ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.524483ms)
|
||||
✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (204.459707ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (434.790765ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (208.628416ms)
|
||||
✔ 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.207965ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (209.525324ms)
|
||||
✔ E4: a page read after message_end but before its entry is persisted: marker at the seam, re-read after run-settled, each message once (214.791001ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.257555ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (207.785389ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (222.93139ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (246.012191ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (217.850966ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.378358ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.255604ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.315044ms)
|
||||
✔ 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.482176ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.79974ms)
|
||||
✔ 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.456685ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (5.694544ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.358734ms)
|
||||
✔ 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.31609ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.100786ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (227.856584ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (277.283003ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (495.610302ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (1136.441089ms)
|
||||
✔ H4: self-takeover is refused (266.830013ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (420.918645ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1028.026142ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (229.392447ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (640.957893ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (295.422428ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (244.62704ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (212.181907ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (601.446306ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (308.514796ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (210.690231ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (866.919372ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (351.68384ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (721.987863ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (185.048847ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (327.914413ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.684845ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (671.906917ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (557.834039ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (673.114767ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3121.386021ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (715.134803ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (27.256085ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (9.312309ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (2.719201ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (3.197326ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (4.243174ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.602719ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (2.064589ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (0.856939ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.297126ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.816202ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (4.470416ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.99739ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.641481ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.965942ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (8.361429ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (1.888174ms)
|
||||
✔ F9: registrations never add or redirect a root (1.790481ms)
|
||||
✔ F10: a header cwd naming another project is refused (4.222416ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (0.766335ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (4.392649ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (2.122902ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (1.57253ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (0.802449ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (522.209998ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (4.524039ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (16.690237ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (2.052498ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (0.988824ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (4.230078ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (793.552903ms)
|
||||
✔ the engine pin holds for the installed package (1.805911ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (287.764811ms)
|
||||
✔ 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) (608.252102ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (259.958004ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (714.851606ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (516.228968ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (424.768279ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.946522ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (492.321296ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (196.243286ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (274.687332ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (479.450814ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (1930.182747ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (219.832833ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (303.065429ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (208.542039ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (196.17292ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (390.615086ms)
|
||||
✔ N10: fake conformance (31.997685ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (439.054261ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (273.274049ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (281.710039ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (361.013334ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (338.674289ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (329.743881ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (185.670772ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (303.936609ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (654.783311ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (484.74142ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (397.040995ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (175.364992ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (140.122467ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (133.075267ms)
|
||||
✔ 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 (132.032987ms)
|
||||
✔ 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 (166.035429ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 176
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 59120.208858
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/conversation/tests/cohort.test.mjs:965:3
|
||||
✖ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2633.661737ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
|
||||
0 !== 1
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r51b/wt2/packages/conversation/tests/cohort.test.mjs:991:28)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 0,
|
||||
expected: 1,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
start 2026-10-10T06:47:51Z
|
||||
recconf rc 1 ℹ pass 176 ℹ fail 1 shims-left 0
|
||||
recbefore rc 1 ℹ pass 176 ℹ fail 1 shims-left 0
|
||||
recpreconf rc 1 ℹ pass 176 ℹ fail 1 shims-left 0
|
||||
recafteracq rc 0 ℹ pass 177 ℹ fail 0 shims-left 0
|
||||
norecover rc 1 ℹ pass 176 ℹ fail 1 shims-left 0
|
||||
startnoawait rc 1 ℹ pass 176 ℹ fail 1 shims-left 0
|
||||
noseat rc 0 ℹ pass 177 ℹ fail 0 shims-left 0
|
||||
nolookup rc 1 ℹ pass 176 ℹ fail 1 shims-left 0
|
||||
nodelete rc 1 ℹ pass 176 ℹ fail 1 shims-left 0
|
||||
closeproof rc 1 ℹ pass 176 ℹ fail 1 shims-left 0
|
||||
closekill rc 1 ℹ pass 175 ℹ fail 2 shims-left 0
|
||||
end 2026-10-10T06:58:43Z
|
||||
@@ -0,0 +1,132 @@
|
||||
✔ explicit request, Seen, ordinary completion and a new request have distinct attention states (3.720805ms)
|
||||
✔ attention convention ignores reasoning/quoted examples and permits leading blank lines (0.231591ms)
|
||||
✔ completed smoke replies and ordinary questions are idle, not human blockers (0.756859ms)
|
||||
✔ only an explicit first-line input request makes a finished reply waiting (0.155247ms)
|
||||
✔ tool activity, user text, errors and unfinished turns override attention text (0.129266ms)
|
||||
✔ STOP access failure is unknown, not absence, under a non-root identity (34.957147ms)
|
||||
✔ connector Task never inherits Discord routing envelopes; ordinary Task still uses user text (2.850481ms)
|
||||
✔ connector discovery keeps only safe identity; rejects modes, mismatches, links and traversal (1.437301ms)
|
||||
✔ canonical owner identity and STOP are independent; no tmux fallback or forged registration (5.718902ms)
|
||||
✔ connector reply refusal precedes forged live tmux registration; ordinary agent still sends (0.55417ms)
|
||||
✔ server rescans connector discovery and refuses HTTP reply without transport (34.831061ms)
|
||||
✔ connector session links and linked directories are not read (1.140204ms)
|
||||
✔ newer live matching launch marks old activity, preserves history/attention/attribution, then clears on new activity (2.284298ms)
|
||||
✔ CLI print uses the relaunch notice instead of old current preview (56.579498ms)
|
||||
✔ connector owner and fixed task never inherit a native relaunch notice (2.132768ms)
|
||||
✔ equality, stale/unknown/offline, mismatched registration and unknown activity do not assert relaunch (1.211392ms)
|
||||
✔ loadConfig: missing file throws ConfigError (1.409816ms)
|
||||
✔ loadConfig: invalid JSON throws ConfigError (0.340941ms)
|
||||
✔ loadConfig: missing dataRoot throws ConfigError (0.210714ms)
|
||||
✔ loadConfig: relative dataRoot throws ConfigError (0.216754ms)
|
||||
✔ loadConfig: valid config returns dataRoot (0.595039ms)
|
||||
✔ findNewestSession: picks the newest by mtime among two files (0.418702ms)
|
||||
✔ findNewestSession: finds files in nested subdirectories (0.302951ms)
|
||||
✔ findNewestSession: returns null for a missing dir (0.150042ms)
|
||||
✔ readSession: extracts fields, collapses/truncates text, counts a truncated final line (0.595572ms)
|
||||
✔ readSession: model and provider follow the latest model_change entry or assistant turn; null when the log names neither; scanAgent carries them (1.154061ms)
|
||||
✔ readSession: lastError carries the assistant errorMessage only when the last assistant turn errored (0.437752ms)
|
||||
✔ findNewestSession/scan: never read sibling auth or secrets next to a sessions dir (1.037412ms)
|
||||
✔ deriveState: full state table (0.166197ms)
|
||||
✔ rule: newest entry is an assistant message with a tool call, after a question-looking text, is working (0.286196ms)
|
||||
✔ rule: newest entry is a tool result with no assistant text after it is working (0.252317ms)
|
||||
✔ rule: a finished ordinary turn is idle, even if it says your move (0.243231ms)
|
||||
✔ task: the first user message of the session, from text blocks (0.236427ms)
|
||||
✔ task: a plain-string user content is accepted, whitespace collapsed and long text capped (0.248753ms)
|
||||
✔ task: no user message in the log means null (shown as unknown), never a guess (0.2404ms)
|
||||
✔ workspace: the live tmux pane path wins; the session cwd is the fallback; neither means null (0.340106ms)
|
||||
✔ activeProject: basename of the nearest .git directory or .git file above the workspace; none means null (0.516621ms)
|
||||
✔ scan: the written record carries task, workspace and activeProject (0.451829ms)
|
||||
✔ registration: overrides task, project and workspace; every source says registration; registered carries the launch fields; the grouping column is untouched (0.527779ms)
|
||||
✔ registration: empty task and null project/workspace leave the derived values in place; registered is still non-null (0.350807ms)
|
||||
✔ registration: a record whose pid is gone is stale; derived values win, sources say derived, registered stays with alive false; a pid the probe cannot decide is not stale; pidAlive itself (0.895535ms)
|
||||
✔ registration: no registration leaves the Gate A fields exactly as before, and registered is null (0.381734ms)
|
||||
✔ loadRegistrations: a missing seatsDir gives empty lists (0.127087ms)
|
||||
✔ loadRegistrations: one good record, one malformed JSON, one with an unknown field; a stray file under seatsDir is ignored (0.666671ms)
|
||||
✔ matchRegistration: matches by sessionsDir, and by realpath through a symlink; sessionsDir null never matches; same seat name with a different sessionsDir does not match (fleet vs repo darkwing) (0.296397ms)
|
||||
✔ scan: writes the registration override to disk; index.json carries registered and registrationErrors (1.083156ms)
|
||||
✔ scan: a relative seatsDir throws ConfigError; an omitted seatsDir behaves as before (0.214634ms)
|
||||
✔ scanAgent: waitingOnYou is true for waiting/error and false otherwise (0.430318ms)
|
||||
✔ scanAgent: ageSeconds is computed from the injected now (0.225173ms)
|
||||
✔ scanAgent: sessionFile null and state idle when sessions dir is empty but alive (0.1349ms)
|
||||
✔ discoverRepoAgents: finds agents with a sessions dir, skips those without, sorted by name (0.303093ms)
|
||||
✔ discoverFleetAgents: finds agents with a sessions dir, sorted by name, fleet tmux fields (0.343605ms)
|
||||
✔ scan: writes per-agent files and index.json, rerun overwrites, no leftover tmp files (0.800285ms)
|
||||
✔ scan: relative boardDir throws ConfigError (0.082516ms)
|
||||
✔ CLI: scan with assume-alive liveness exits 0, prints board summary, writes board files (55.91655ms)
|
||||
✔ CLI: missing config exits 2 with a refused: message (54.578639ms)
|
||||
✔ CLI: unknown command exits 2 (50.636832ms)
|
||||
✔ CLI: unknown --liveness value exits 2 (55.990862ms)
|
||||
✔ panesRunPi: true when any trimmed line equals 'pi' (0.242325ms)
|
||||
✔ panesRunPi: false for bash-only, claude, empty, or node-pi-style lines (0.092365ms)
|
||||
✔ tmuxIsAlive: a pane running pi is alive (0.217599ms)
|
||||
✔ tmuxIsAlive: session exists but pi has exited is not alive (0.078076ms)
|
||||
✔ tmuxIsAlive: no such tmux session is not alive (0.069604ms)
|
||||
✔ tmuxIsAlive: tmux could not be run at all is unknown (null), never assumed alive (0.069513ms)
|
||||
✔ tmuxIsAlive: passes -L <socket> only when a socket is given (0.105914ms)
|
||||
✔ parsePanes: one pane per line, command and optional tab-separated path (0.087208ms)
|
||||
✔ tmuxInspect: reports the path of the pane running pi, not of a shell pane (0.085758ms)
|
||||
✔ tmuxInspect: no pi pane, no session, or no tmux gives no workspace and the matching liveness (0.105291ms)
|
||||
✔ loadSeen: missing file returns {} (0.168507ms)
|
||||
✔ loadSeen: invalid JSON throws ConfigError (0.215272ms)
|
||||
✔ loadSeen: a JSON array throws ConfigError (0.170824ms)
|
||||
✔ loadSeen: a non-string value throws ConfigError (0.189685ms)
|
||||
✔ markSeen: seen true adds the key and writes seen.json mode 0600, no leftover tmp files (0.379032ms)
|
||||
✔ markSeen: seen false deletes the key (0.31735ms)
|
||||
✔ markSeen: missing, empty, or non-string fields throw ConfigError (0.238033ms)
|
||||
✔ markSeen: project containing '/' throws ConfigError (0.204025ms)
|
||||
✔ markSeen: non-boolean seen throws ConfigError (0.1952ms)
|
||||
✔ scanAgent: a seen mark matching the waiting session's lastTimestamp clears waitingOnYou (0.343328ms)
|
||||
✔ scanAgent: a stale mark (agent wrote something newer) is not seen and waitingOnYou is true (0.335678ms)
|
||||
✔ scanAgent: a working session with a matching mark is not seen (marks only apply to waiting/error) (0.277196ms)
|
||||
✔ scanAgent: an error-state session with a matching mark is seen (0.256877ms)
|
||||
✔ scan: index.seen and waitingOnYou reflect seen.json, which scan never rewrites or deletes (0.570268ms)
|
||||
✔ scan: a corrupt seen.json makes scan throw ConfigError (fail closed) (0.22088ms)
|
||||
✔ taskSetBy: a registered task carries the record's setter; a record without the field (pre-#1511) reads unknown; the value is not copied into registered (0.766968ms)
|
||||
✔ taskSetBy: null whenever the task shown is not the registered one: no registration, an empty registered task, a stale registration; the field is always present (0.651403ms)
|
||||
✔ taskSetBy: scan() reads the field from disk through the seat package (bounded there), writes it to the per-agent record and index, and an invalid on-disk value is a registrationError, never a row value (1.027169ms)
|
||||
✔ isLoopbackHost: recognizes loopback hosts (1.165522ms)
|
||||
✔ isLoopbackHost: rejects non-loopback hosts (4.169004ms)
|
||||
✔ startServer: refuses a non-loopback host with ConfigError, never opens a socket (3.335733ms)
|
||||
✔ startServer: serves page, healthz, and a rescanning /api/board (35.492884ms)
|
||||
✔ startServer: a seatsDir registration overrides the row and index.registered reflects it (6.456487ms)
|
||||
✔ startServer: /api/board returns 500 JSON with an error field when scan throws (2.594768ms)
|
||||
✔ CLI: serve refuses a non-loopback host with exit 2 and a refused: message (56.167392ms)
|
||||
✔ CLI: serve rejects a non-numeric --port with exit 2 (50.78742ms)
|
||||
✔ CLI: scan still works after the async cli refactor (50.803175ms)
|
||||
✔ CLI: live serve prints its URL and answers /healthz (63.281177ms)
|
||||
✔ page.html: esc() escapes every HTML-significant character (0.602624ms)
|
||||
✔ POST /api/seen marks a row; GET /api/board still shows it seen; seen:false clears it (9.008453ms)
|
||||
✔ POST /api/seen without a JSON content-type returns 400 and does not write a mark (1.987018ms)
|
||||
✔ POST /api/seen with invalid JSON returns 400 (2.800995ms)
|
||||
✔ POST /api/seen with a body over 4096 bytes returns 400 (or resets the connection) and writes no mark (2.083993ms)
|
||||
✔ POST /api/seen with a missing agent returns 400 (1.315879ms)
|
||||
✔ POST /api/board returns 405; PUT /api/seen returns 405 (1.79913ms)
|
||||
✔ CLI: scan --print marks a seen row with 's' and the summary line ends with 'N seen)' (51.939432ms)
|
||||
✔ page.html: seenControl() escapes rec.project/agent/lastActivity, and the POST uses a JSON content-type (0.311658ms)
|
||||
✔ page.html: has a collapsed Seen section that lists seen rows with the shared row builder (0.268297ms)
|
||||
✔ page.html: each project has a Hide seen checkbox (default on) beside Hide offline, with a hidden-count note (0.15774ms)
|
||||
✔ page.html: a project header reads "N of N" only while a checkbox hides rows (0.129566ms)
|
||||
✔ page.html: every row shows Task and Active project, derived or the word unknown, with the workspace in the detail (0.697448ms)
|
||||
✔ page.html: task and active project cells show their source via sourceTag(); the detail has a Registered row via registeredText(); SOURCE_LABEL maps registration to registered; every dynamic value in sourceTag/fromSource/registeredText is escaped (0.562308ms)
|
||||
✔ POST /api/reply: runs agent-send.sh with -s from the registration, -S <host>:control-board, -m text plus the fixed trailer, no -L on the default socket, MOSAIC_TMUX_SOCKET stripped; answers delivered with the exit code and both streams (26.714185ms)
|
||||
✔ POST /api/reply: a registration with a tmux socket adds -L <socket> (27.055093ms)
|
||||
✔ POST /api/reply: a non-zero tool exit is a 200 with delivered false, the exit code and the stderr verbatim (36.335961ms)
|
||||
✔ POST /api/reply: refusals before the tool runs: empty or blank or long text 400, unknown row 404, no registration 409, stale registration 409, no tmux session 409, bad JSON 400; the tool is never called (14.905579ms)
|
||||
✔ POST /api/reply: a missing agent-send.sh is a 500 with the path in the error, not a crash (4.72918ms)
|
||||
✔ replyToRow: DEFAULT_AGENT_SEND is the repository's tools/tmux/agent-send.sh and it is executable (0.16806ms)
|
||||
✔ page.html: the reply box appears only where canReply() holds (live registration with a tmux session), the detail has a Reply row, the submit posts JSON to /api/reply, receipts and drafts survive a refresh, and every receipt value is escaped (0.579465ms)
|
||||
✔ startServer: /api/board carries taskSetBy from a live registration and null for the derived rows (2.486587ms)
|
||||
✔ page.html: the task cell and detail show who set a registered task via setByTag()/setByText(), both escaped, only from rec.taskSetBy; the reply gate does not read it (0.300772ms)
|
||||
✔ Host/Origin guard: GET /api/board and POST /api/reply refuse a foreign Host, a wrong port and a cross-origin Origin with 403 JSON, before any scan or send, and never send CORS headers (8.147614ms)
|
||||
✔ Host/Origin guard: loopback names on this port are accepted, with or without a same-origin Origin (34.258693ms)
|
||||
✔ conversation routes (F16): a foreign Host, a wrong port and a cross-origin Origin get 403 before the reader runs, with no CORS headers (5.36354ms)
|
||||
✔ every refusal code the reader can raise has an HTTP status (0.914577ms)
|
||||
✔ conversation routes: catalogue, first page, next page and follow over HTTP; refusals map to 4xx with their code; nothing is written (46.117604ms)
|
||||
ℹ tests 124
|
||||
ℹ suites 0
|
||||
ℹ pass 124
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 642.951021
|
||||
@@ -0,0 +1,185 @@
|
||||
✔ W1: two processes acquire the same pair at once; exactly one claim (597.429003ms)
|
||||
✔ W1: two writers publish the same revision at once: one wins, the other gets null, the winner's record stays (40.954663ms)
|
||||
✔ W1: a revision name appears only after its bytes are synced; before that, only a temp file exists (22.786834ms)
|
||||
✔ W2: acquire while a claim is reserved or active refuses already-active (436.808045ms)
|
||||
✔ W3: acquire while stopping, uncertain, or stopped without proof refuses unsafe-replacement (454.299254ms)
|
||||
✔ W4: same session with another seat tuple, and the reverse, both refuse; a loser on the seat key closes it no-unit (263.424205ms)
|
||||
✔ W4: a hard link of one session under another seat is the same session: the second controller refuses already-active and launches nothing (272.125077ms)
|
||||
✔ W4: a copy of one session under another seat is the same session: the second controller refuses already-active and launches nothing (280.860876ms)
|
||||
✔ W4: a session header ID that changes after construction refuses target; nothing is claimed or launched (2.321896ms)
|
||||
✔ W5: SIGKILL between every publication barrier of acquire and transition; restart never finds two holders or a lost claim (15442.268306ms)
|
||||
✔ W5: SIGKILL between every publication barrier of release; restart finishes or holds the release (38878.226775ms)
|
||||
✔ W6: controller killed mid-turn while the engine lives; restart is uncertain, no launch, prompts refuse (308.230077ms)
|
||||
✔ W12: a live owner paused with SIGSTOP; a second controller refuses already-active and changes nothing (179.569827ms)
|
||||
✔ W13: crash after the engine spawns, before active; restart finds the live unit: uncertain, no second spawn, force stop only (789.45693ms)
|
||||
✔ W14: crash after reservation, before the spawn marker: stopped with a no-unit observation; the pair is free (306.446157ms)
|
||||
✔ W20: crash after the spawn marker, scope collected; uncertain in both runs, the marker is copied, no launch until a boot proof (359.243563ms)
|
||||
✔ W15: crash between the two keys during release; restart finishes it under the same claim ID (143.555489ms)
|
||||
✔ W7: recorded boot ID differs on the same machine: stopped with a boot proof; open tool calls become uncertain (216.770471ms)
|
||||
✔ W8: resume after a proven stop with the same pins: new claim ID, generation +1, same conversation, branch and leaf (261.528248ms)
|
||||
✔ W9: resume with a changed binary, argv digest, branch or leaf is refused and the claim is unchanged (732.424205ms)
|
||||
✔ W11: the controller writes no session file; only the fake engine's own appends appear (184.306631ms)
|
||||
✔ W16: a highest revision that won't parse holds the pair uncertain; the older stopped revision is not reused (92.396695ms)
|
||||
✔ W17: a claim root copied from another host refuses foreign-host and promotes nothing (71.719283ms)
|
||||
✔ G1: a session path or claim root under .pi/state, ~/.claude, the data root or a registration refuses at construction (4.188625ms)
|
||||
✔ G2: a symlink inside the fixture root to a live session file is refused by the real-path check (1.050245ms)
|
||||
✔ G3: a fixture path swapped for a live path after construction is refused at bind (1.766601ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.382928ms)
|
||||
✔ K1: force stop kills a tool child that called setsid; stopped with a verified proof (1258.500505ms)
|
||||
✔ K2: K1 on the process-group fallback ends uncertain, never stopped (574.76375ms)
|
||||
✔ K3: SIGTERM acknowledged while a member lives: stopping until the kill phase, never stopped from TERM (1089.622732ms)
|
||||
✔ K4: two engines; force stop one; the other survives by independent observation (3335.415607ms)
|
||||
✔ K5: a stop during a tool call leaves the effect uncertain, and it is shown (898.301693ms)
|
||||
✔ K12: a member forking in a loop: the freeze stops it, enumeration is complete, populated 0 after cgroup.kill (933.17654ms)
|
||||
✔ K13: a member writing its pid into another cgroup is refused by the namespace; the kill is complete (744.388173ms)
|
||||
✔ K15: the shim gone, engine/cgroup.events unreadable, or the engine cgroup missing: evidence unavailable, not empty; uncertain (6012.188982ms)
|
||||
✔ K10: controller killed between the TERM and kill phases: restart checks the invocation ID and re-runs from TERM for the same stop (1094.887185ms)
|
||||
✔ K11: controller killed after the confirmation is recorded, before TERM: restart checks the invocation ID and re-runs from TERM for the same stop (928.160229ms)
|
||||
✔ K14: a unit with the recorded name but another invocation ID: evidence unavailable, no signals, uncertain (907.561325ms)
|
||||
✔ K6: recover without proof, without confirmation, or with changed pins is refused (1844.132732ms)
|
||||
✔ K7: recover after proof, then launch: new claim and execution, generation +1, same leaf; the cancelled prompt is not replayed (800.065323ms)
|
||||
✔ K8: an engine that loads another leaf on resume is refused before admission; it stays claimed until a proven stop (970.579212ms)
|
||||
✔ K9: an interrupt that never settles stays uncertain; force stop stays available; takeover is refused while fenced (3511.266329ms)
|
||||
✔ K16: a claim from another machine ID refuses foreign-host; no boot proof is issued (47.870479ms)
|
||||
✔ K17: two launcher calls with one eligibility record: one launch, the other refuses, no second engine (612.731605ms)
|
||||
✔ K18: the leaf changes after eligibility: launch refused; the reservation stays until released with proof (565.51884ms)
|
||||
✔ K19: a scope launched with only the engine environment still reaches the user manager; the engine sees no other names (83.890468ms)
|
||||
✔ R1: after a proven force stop the controller releases the scope; the shim and the unit are gone (614.675809ms)
|
||||
✔ R2: close releases the scope of a binding proven stopped, once, when the stop's own release hasn't run (772.72612ms)
|
||||
✔ R3: no release after an unavailable stop or an unverified proof: the scope and its shim stay as evidence (1771.565041ms)
|
||||
✔ R4: after a normal engine exit the scope stays until a proven force stop releases it (905.141171ms)
|
||||
✔ R5: the harness finds a running shim and reaps it, and never signals a shim outside a mosaic-chat- scope (Filbert N1 and N2 on #1533) (488.1033ms)
|
||||
✔ R6: releaseCohort releases nothing while the engine runs, for another invocation ID, or for a cohort without a scope (169.830008ms)
|
||||
✔ R7: controller killed after the claim is stopped, before the release: the restart releases the scope (2940.654947ms)
|
||||
✔ R8: controller killed between the two keys' stopped revisions: the restart releases the scope (653.83933ms)
|
||||
✔ R9: a release that ended unavailable is tried again on a confirmed recover, not a refused one (741.044451ms)
|
||||
✔ R10: close releases and signals nothing for a stopped binding whose proof no longer verifies (Filbert N3 on #1536) (494.799094ms)
|
||||
✔ R11: close({ killEngine: true }) after a proven stop sends no signal to the recorded engine PID; a restart releases nothing more (2707.140013ms)
|
||||
✔ R12: a restart onto a claim stopped on a boot proof releases nothing, though its scope is listed (290.262258ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (24.778786ms)
|
||||
✔ S1: `/goal x`, with leading spaces or a tab, refuses text-policy at admission; zero engine bytes (622.128704ms)
|
||||
✔ S2: every prefix pinned Pi interprets is refused, from the list the code uses; the rest reach the engine exactly (300.825282ms)
|
||||
✔ S3: `/goal` on the second line is pinned from the source: Pi checks only index 0, so it is admitted and sent exactly (240.561873ms)
|
||||
✔ S4: a `/` left in the composer is cleared when control transfers and returns; the next submit sends only the new text (372.93656ms)
|
||||
✔ S5: an observer terminal gets a paste then Enter, as send-message.sh does: not admitted: controller, nothing sent (252.201002ms)
|
||||
✔ S6: a mediated-shaped registration (no tmux) passed to the board's replyToRow: 409 no tmux session; exec never runs (0.711935ms)
|
||||
✔ S7: ESC, bracketed-paste markers and U+2028/U+2029 travel as one JSON string; the engine receives the exact text in one record (271.788979ms)
|
||||
✔ P3: a Pi confirm, select, input or editor dialog is shown disabled with a reason and never answered (376.507665ms)
|
||||
✔ E1: send, ack, user, toolCall, toolResult, final answer: shown once, no refresh, draft and reading position kept (600.067881ms)
|
||||
✔ E2: U+2028, U+2029 inside JSON strings and CRLF line ends each parse as one record, on the splitter and through the controller (380.539687ms)
|
||||
✔ E3: a multipart final, two blocks, null request correlation and duplicate delivery (270.431244ms)
|
||||
✔ 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 (306.027417ms)
|
||||
✔ E4: a gap or a new epoch also reconciles; nothing is concatenated across a gap (11.561473ms)
|
||||
✔ E5: an unknown native event gives no client event; evidence records its type and bytes; the terminal count goes up (265.91842ms)
|
||||
✔ E6: a tool result delayed across a pause and a reconnect is reconciled without a manual refresh (287.513903ms)
|
||||
✔ E7: the terminal renders the same stream as the library client, as observer and then as controller, and submits only as controller (315.357808ms)
|
||||
✔ terminal: engine control characters are made visible; a lost connection refuses submit (262.980595ms)
|
||||
✔ terminal: outcome unknown is shown as such, with no resend offer, and nothing is resent (0.397905ms)
|
||||
✔ terminal: text after Enter in the same input chunk starts the next message; it never joins the one submitted (0.260694ms)
|
||||
✔ terminal: a paste-start marker split right after its ESC still opens the paste; the Enter inside it never submits (0.335573ms)
|
||||
✔ 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.495242ms)
|
||||
✔ terminal: input held behind Ctrl-T waits for that takeover while an earlier action is still pending (Darkwing T1 on #1522) (30.973599ms)
|
||||
✔ 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.421448ms)
|
||||
✔ terminal: an action that throws still releases the input held behind it, in order, then rethrows (4.660811ms)
|
||||
✔ terminal: after an action throws, later input still runs; input() puts the error in the status line (Filbert N1 on #1522) (0.338748ms)
|
||||
✔ 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.32873ms)
|
||||
✔ terminal: invisible and bidi characters are made visible; head, status and notice lines stay one line (0.10422ms)
|
||||
✔ every record these fixtures produced is a valid CHAT-01 record (E5: no record fails the schema) (230.400298ms)
|
||||
✔ H1: two takeovers with the same expected generation: one wins, +1; the other refuses generation (653.150176ms)
|
||||
✔ H2: the old controller's prompt after a takeover commits is refused with zero engine bytes (403.187068ms)
|
||||
✔ H3: a takeover while a prompt holds the dispatch lock: written under the old actor, or refused; never both (1062.773413ms)
|
||||
✔ H4: self-takeover is refused (323.883638ms)
|
||||
✔ H9: Interrupt racing a prompt's dispatch: before the write, dispatch-refused and no-turn; after, §3 rules (1001.823003ms)
|
||||
✔ H10: Interrupt and force stop together: one stop chain, force stop supersedes (1397.568741ms)
|
||||
✔ H10: an overlap during the pause before the abort: no abort, the stop ends uncertain (301.405362ms)
|
||||
✔ H10: a no-turn Interrupt lifts only its own fence; admission stays closed under force stop, overlap or revocation (1003.344709ms)
|
||||
✔ H11: the controller disconnects mid-turn: work continues, the claim is unchanged, control stays put (500.407872ms)
|
||||
✔ H12: an exact retry after reconnecting to the same incarnation returns the same receipt; one dispatch (219.149076ms)
|
||||
✔ H13: a retry with the same request ID and different text is refused (212.761321ms)
|
||||
✔ H14: late stdout from the old engine after a replacement is dropped by incarnation, counted, never rendered (685.726227ms)
|
||||
✔ H15: a revoked connection's command is refused; the revocation fence holds (311.346956ms)
|
||||
✔ H16: a second controller for the same session refuses already-active; the first is untouched (219.885369ms)
|
||||
✔ H10: a second force stop while the first escalation runs refuses fenced; one escalation, and the claim records only the first stop's phases (979.029191ms)
|
||||
✔ a force stop whose fence throws leaves no escalation flag behind, so the next force stop runs (Darkwing F2, #1507) (420.895881ms)
|
||||
✔ H17: a confirmation reused, answered from another connection, or used after the stop changed is refused (1575.278781ms)
|
||||
✔ H18: two prompts before any native output: the second refuses busy; one engine write (267.216566ms)
|
||||
✔ H19: the pipe fails mid-line under a large prompt: delivery-unknown transport-unknown, poisoned, no later write (503.892121ms)
|
||||
✔ H19: the link itself never writes again after an unknown outcome, whoever calls it (0.672585ms)
|
||||
✔ H19: the controller dies mid-write of a large line: after restart the outcome is unknown and nothing is resent (809.520784ms)
|
||||
✔ H20: the line is written but the ack is lost when the controller dies: orphan, outcome unknown, nothing resent (710.867603ms)
|
||||
✔ H21: a retry of the exact request with the old token after a crash is stale-incarnation; no second write (1046.420902ms)
|
||||
✔ H22: after H21 and a valid recovery, a new request with the new token is admitted (3203.72305ms)
|
||||
✔ H23: requests pending at a restart are not resent; each shows outcome unknown (774.698692ms)
|
||||
✔ no shim from this file's tests is left running for the after hook (25.168567ms)
|
||||
✔ a plain conversation: catalogue row, one page, CHAT-01 records (6.277121ms)
|
||||
✔ native entries map to blocks: tools, thinking, bash, notices, ids that do not fit (1.76589ms)
|
||||
✔ F1: a malformed line is an unavailable part at its position, and reading continues (1.710685ms)
|
||||
✔ F1: a missing parent stops the history with a notice that names the unreadable lines (2.405706ms)
|
||||
✔ F1: an unreadable fork is never merged into another branch's history (1.369735ms)
|
||||
✔ F1: a follow stays on its branch when the next entry's parent is unreadable (1.998627ms)
|
||||
✔ F1: a file whose entries are all unreadable shows a notice per line (0.849718ms)
|
||||
✔ F2: a truncated trailing line marks the view incomplete, not an error (1.462077ms)
|
||||
✔ pagination: 100 parts, then the rest; parts concatenate to the whole branch (3.875461ms)
|
||||
✔ F3: a replaced file (new inode) refuses old cursors with reconcile (3.946285ms)
|
||||
✔ F4: a same-inode rewrite of the prefix refuses old cursors with reconcile (4.219958ms)
|
||||
✔ F5: growth between pages keeps the epoch and the page stops at the pinned length (4.330458ms)
|
||||
✔ F6: unknown, foreign and expired cursors refuse and leave the cursor usable (6.497358ms)
|
||||
✔ F7: a symlinked file and a symlinked directory component are refused, never opened (10.539458ms)
|
||||
✔ F8: a file swapped for a symlink after the catalogue is refused (2.849015ms)
|
||||
✔ F9: registrations never add or redirect a root (2.003292ms)
|
||||
✔ F10: a header cwd naming another project is refused (5.719428ms)
|
||||
✔ F11: parentSession renders with a marker and the parent is never opened (1.161772ms)
|
||||
✔ F12: two leaves: the default leaf is shown and the other branch reads alone (7.044442ms)
|
||||
✔ F12: a follow refuses when an appended duplicate id changes the branch's earlier parts (3.383635ms)
|
||||
✔ F12: a second root (Pi's resetLeaf) starts its own branch (2.382306ms)
|
||||
✔ F13: compaction is a marker in place, then the retained content (1.223236ms)
|
||||
✔ F14: long strings split into fragments and parts, reassemble exactly, and pages respect the byte cap (556.637487ms)
|
||||
✔ fragments never cut a surrogate pair and keep an empty string (7.107353ms)
|
||||
✔ F15: a Claude seat is an unsupported-harness placeholder whose directory is never read (2.317922ms)
|
||||
✔ unknown conversations, empty files and non-Pi files refuse (3.784049ms)
|
||||
✔ an unreadable file or root inside the roots is refused per row, not a failed catalogue (1.191234ms)
|
||||
✔ a seat directory without search permission refuses that root, not the catalogue (2.16053ms)
|
||||
✔ every page and cursor is a valid CHAT-01 record (826.794516ms)
|
||||
✔ the engine pin holds for the installed package (2.204289ms)
|
||||
✔ pinned Pi, sealed and without credentials, answers the controller's commands with the shapes the fake models (275.749316ms)
|
||||
✔ sealed, pinned Pi ignores a trusted project's .pi resources; --approve past the seal would load them, and checkSeal refuses it (Filbert F2 on #1522) (592.272344ms)
|
||||
✔ pinned Pi appends thinking_level_change at start when the branch lacks one, so the leaf moves (K8 then fails closed) (267.154931ms)
|
||||
✔ N25: ordinary Interrupt reconciles; a non-empty queue_update in the window is O5 (1007.851326ms)
|
||||
✔ N1: an extension's follow-up queued after the fence is cleared before any abort; O5, Unknown (570.541339ms)
|
||||
✔ N1: a follow-up queued before the fence is O5 at once; the Interrupt refuses fenced (299.49222ms)
|
||||
✔ N2: with abort first, the fake runs the external item (the ordering guard has teeth) (21.98398ms)
|
||||
✔ N3: the fence lands in preflight, preflight errors, no run: failed, No run, uncertain (496.710918ms)
|
||||
✔ N4: the ack arrives after the first abort and a run starts: clear and abort again; Interrupted (600.387309ms)
|
||||
✔ N5: an input handler takes the prompt: ack, no run, delivery-unknown handled-without-run (465.448988ms)
|
||||
✔ N6: an extension queues between clear_queue and abort: O5 and O6, Unknown (659.831336ms)
|
||||
✔ N7: clear_queue times out: no abort, nativeQueue unknown, force stop still ends it (2041.813279ms)
|
||||
✔ N7: clear_queue answers an error: no abort, nativeQueue unknown, the link not poisoned (363.61738ms)
|
||||
✔ N8: an extension prompt starts a run during Mosaic preflight; the losing settle is O3 (286.892274ms)
|
||||
✔ N9: a run that started before the fence and ends aborted: failed interrupted, Interrupted (214.649233ms)
|
||||
✔ N9: decision 34: a run that ends aborted with no stop in progress: aborted-without-stop, uncertain, outcome unknown (266.662438ms)
|
||||
✔ N9: an aborted that lands after the fence but before any abort is written: aborted-without-stop, Unknown (510.244859ms)
|
||||
✔ N10: fake conformance (34.05928ms)
|
||||
✔ N11: the run fails before any user message_start: delivery-unknown ack-without-start, never failed (420.27127ms)
|
||||
✔ N12: input that starts a run after the final empty clear is O1 and not part of the stop's proof (288.353793ms)
|
||||
✔ N13: agent_start with no slot held is O1; a later prompt refuses with zero engine bytes (343.93325ms)
|
||||
✔ N14: the run completes while clear_queue is in flight: finished, Completed first, uncertain (429.948175ms)
|
||||
✔ N14: the run completes after the abort is written, before Pi applies it: finished, never relabelled (431.01797ms)
|
||||
✔ N15: the fence lands in preflight, then an input handler takes it: handled-without-run, No run (739.636959ms)
|
||||
✔ N16: Interrupt with no slot and no run refuses no-turn: no stop, no bytes, admission open (540.57363ms)
|
||||
✔ N17: the run fails on its own during the exchange: failed, Failed on its own (479.358507ms)
|
||||
✔ N18: no final assistant message_end, or a lost line: working stays working; before working, transport-unknown (1180.289784ms)
|
||||
✔ N19: a losing extension prompt settles inside the Mosaic run before its user message: O3, run-overlap (806.745071ms)
|
||||
✔ N20: an extension triggerTurn during Mosaic preflight starts first; while streaming it queues with no signal (959.642257ms)
|
||||
✔ N21: a losing settle after the receipt settled finished is O2; the receipt stays finished (301.877165ms)
|
||||
✔ N22: an agent-level custom message is dropped by the clear with no signal; evidence names the seal (262.131945ms)
|
||||
✔ N23: a nextTurn message survives clear and abort and attaches to the next prompt, with no signal (272.31997ms)
|
||||
✔ 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 (312.121732ms)
|
||||
✔ 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 (307.878355ms)
|
||||
ℹ tests 177
|
||||
ℹ suites 0
|
||||
ℹ pass 177
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 63911.226669
|
||||
@@ -0,0 +1,158 @@
|
||||
✔ F1: an ordinary commit after update-ref is refused until step 8; then it commits and the queue stays at C (1405.027247ms)
|
||||
✔ F1: a plain `commit -e` whose guard ran before update-ref fails at its own HEAD update (1256.223427ms)
|
||||
ℹ git commit -e: index.lock free during the editor
|
||||
✔ F1: a `commit -e -- path` whose guard ran before update-ref fails at its own HEAD update (1364.988847ms)
|
||||
ℹ git commit -e -- src.txt: index.lock held during the editor
|
||||
✔ F1: step 8 with index.lock held exits 3, and ordinary commits stay refused until the printed command runs (1253.192262ms)
|
||||
✔ F1: HEAD moving after the step-7 guard check and before update-ref: refused, nothing published (1140.688659ms)
|
||||
✔ F1: H is recorded before the canary, so HEAD moving during the step-1 canary is refused at step 7 (1179.218113ms)
|
||||
✔ F1: a queue commit landing after H is recorded: step 1 says HEAD moved, not the guard (1520.834607ms)
|
||||
✔ F1: a queue commit landing between the HEAD check and the canary: the failed clean run is reported as HEAD moved (1208.393201ms)
|
||||
✔ F1: a shared-index change during the procedure is not committed (1349.817188ms)
|
||||
✔ F1: a queue path staged after update-ref: step 8 stops and touches nothing (1233.269115ms)
|
||||
✔ F1: a missing or a different hook refuses (893.363806ms)
|
||||
✔ F1: same bytes without the exec bit, a symlinked hook, and core.hooksPath in the local or global scope each refuse before update-ref (1512.378613ms)
|
||||
✔ F1: the canary refuses a hook that git would not run (846.626261ms)
|
||||
✔ F1: the guard deactivated after step 1 is refused at the step-7 recheck (1271.772154ms)
|
||||
✔ bootstrap: implementation-only HEAD, the guard, genesis, the --genesis commit, then an extending commit (1154.763397ms)
|
||||
✔ bootstrap: --genesis with a base present, no base without --genesis, an op before the first commit, a changed map, another branch (935.746574ms)
|
||||
✔ bootstrap: the archived tests and validator run outside any repository (1052.392278ms)
|
||||
✔ general: an unrelated staged file stays staged, and the committed blobs are the snapshot bytes (973.871615ms)
|
||||
✔ general: a queue write after the snapshot is not committed (1344.426355ms)
|
||||
✔ general: a snapshot whose log does not extend the base refuses (1036.874077ms)
|
||||
✔ general: install-hook privilege, repair of a same-bytes hook, and its refusals (163.692047ms)
|
||||
✔ general: environment overrides, a linked worktree and usage (677.029562ms)
|
||||
✔ general: a queue path staged before the run refuses at step 1 (703.413217ms)
|
||||
✔ general: HEAD's queue tests failing in the archive refuse (929.321661ms)
|
||||
✔ genesis document serializes deterministically and replays (5.038082ms)
|
||||
✔ a hand edit that stays valid JSON fails replay; a formatting-only edit fails re-serialization (2.578519ms)
|
||||
✔ a tampered result, receipt or viewSha fails replay (2.754672ms)
|
||||
✔ op ids: 8 to 72 characters for callers, 80 in the log for .outcome entries (0.220275ms)
|
||||
✔ add: defaults for an ordinary seat, privileged extras, refusals (4.423892ms)
|
||||
✔ matrix: queued→briefed privileged; briefed→in-progress owner with after satisfied (5.388769ms)
|
||||
✔ matrix: release, review round, changes requested and waiting-on-jason (14.263772ms)
|
||||
✔ matrix J5: in-review→done by the gate owner with evidence naming the current round (9.505118ms)
|
||||
✔ review issue, lead decision 23: none refuses, one is used, several need --issue, later rounds keep it (20.972625ms)
|
||||
✔ the row schema refuses a round with a null issue, and the A1 review shape (P2) (2.303536ms)
|
||||
✔ matrix R1: every state × target × actor class matches 8.7, gate owner jason or not, required or not (1363.105355ms)
|
||||
✔ matrix: blocked keeps the claim and returns only to previousState (4.447554ms)
|
||||
✔ matrix J4: parking is Jason's, refused while required; unpark returns to queued (2.614957ms)
|
||||
✔ field edits: who may change what (5.165574ms)
|
||||
✔ set issues keeps a logged narrowing of closes (N10) (2.942552ms)
|
||||
✔ text the table shows refuses \ and <, everywhere it enters (N8) (1.85875ms)
|
||||
✔ every accepted text renders to nine cells on every row (N8) (20.914489ms)
|
||||
✔ genesis: the map refuses an owner among its row's reviewers; replay doesn't (2026-10-04) (0.512522ms)
|
||||
✔ times and dates must be calendar values, not just the shape (2026-10-04) (1.581623ms)
|
||||
✔ replay holds every op id to the caller's rule (N11) (5.167698ms)
|
||||
✔ note: owner, listed reviewer or privileged; empty clears (1.162734ms)
|
||||
✔ assign moves the claim with the owner; done clears it (3.197846ms)
|
||||
✔ render is byte-stable and escapes pipes (0.807018ms)
|
||||
✔ view classification: current, genuine stale, edited stale marker, changed current body, markers (0.995364ms)
|
||||
✔ next: resume, then review, then start, then wait, then nothing; lowest id first (19.195788ms)
|
||||
✔ canonical args make a retry's identity independent of list order (0.309044ms)
|
||||
✔ manifests, headings and blob ids (0.427786ms)
|
||||
✔ the migration map: one queue-map block, exact keys (0.572247ms)
|
||||
✔ every call but `queue` reaches the seat CLI exactly as before A2 (607.731736ms)
|
||||
✔ `queue` reaches the queue CLI with the rest of the arguments (195.574222ms)
|
||||
✔ the pre-A2 fixture is the script A2 changed (0.356401ms)
|
||||
✔ acquire publishes the record by link; release removes only its own lock (13.389715ms)
|
||||
✔ a kill between the temp write and the link leaves no lock (63.38172ms)
|
||||
✔ a short or failed temp write refuses and leaves no lock and no temp (12.392891ms)
|
||||
✔ a link error other than EEXIST refuses (9.631904ms)
|
||||
✔ an error after the link releases the lock: unreadable gate, failing temp stat (25.868635ms)
|
||||
✔ a release that fails on a gate path is reported, never a stack trace (P1) (48.706483ms)
|
||||
✔ a paused holder: another writer waits 10 s, then refuses naming it live (10163.747837ms)
|
||||
✔ two concurrent unlockers: the second refuses on the gate (39.197091ms)
|
||||
✔ a writer publishing during an unlock, lock first: unlock sees it live and refuses (21.147628ms)
|
||||
✔ a writer publishing during an unlock, gate first: the writer releases and refuses (19.956698ms)
|
||||
✔ a gate swapped while held is left in place and reported, on success and on refusal (N1) (25.205621ms)
|
||||
✔ a reused pid within one boot is mismatch; unlock removes the lock and never signals the process (19.540586ms)
|
||||
✔ the same pid and start on a different boot is mismatch (0.454593ms)
|
||||
✔ a foreign host is unknown whatever the local pid says; unlock refuses (80.038503ms)
|
||||
✔ unreadable /proc: classification is unknown and acquire refuses (0.714459ms)
|
||||
✔ invalid records: empty, unparsable, wrong keys, bad start or boot (0.193384ms)
|
||||
✔ a stale gate blocks writers; --check-gate says mismatch for a reused pid (27.989621ms)
|
||||
✔ a delayed release by a dead owner, after unlock and a new owner: the inode check keeps the new lock (37.885324ms)
|
||||
✔ release checks the inode too: a byte-identical lock file with a new inode is left in place (7.559526ms)
|
||||
✔ unlock refuses a live, unknown or invalid lock, and does nothing without one (33.37987ms)
|
||||
✔ the migration map validates and renders the golden genesis table (4.544617ms)
|
||||
✔ the marked QUEUE.md holds every row and parked item between its markers (1.521251ms)
|
||||
✔ map-check reports each kind of drift (4.063935ms)
|
||||
✔ a request posts once as the requester; a retry sends nothing (907.567474ms)
|
||||
✔ each transport answer maps to posted, failed or uncertain (8.9 step 3) (5634.985493ms)
|
||||
✔ the pre-send checks: GET user must name the requester, under the deadline (2024.877288ms)
|
||||
✔ the lead's request refuses a token for login sage (1338.651634ms)
|
||||
✔ the credential file: the seat's own, 0600, no symlink, never the shared default (1228.486095ms)
|
||||
✔ an unresolved request blocks a new request, a new round, waiting-on-jason and done (2754.692489ms)
|
||||
✔ a same-op retry after a kill sends nothing, even with a stale view (3950.371161ms)
|
||||
✔ a held lock at the outcome exits 3 and names what the transport said (929.89329ms)
|
||||
✔ late outcomes: after an abandon, and after a resolve with the same or another id (2694.821705ms)
|
||||
✔ resolve checks the comment: issue, markers, round, candidate and author (1837.280602ms)
|
||||
✔ the lead resolves a seat's request: the comment's author is the requester, fetched with the lead's token (748.902483ms)
|
||||
✔ validateRow checks a request round's shape, which every replayed entry must keep (596.650199ms)
|
||||
✔ request, changes, a new candidate, approval: every round pinned; no review files (1989.692934ms)
|
||||
✔ a row with no reviewers opens a round that posts nothing (1237.326447ms)
|
||||
✔ verify-commit: a prospective tree must hold exactly the candidate's paths (1426.649569ms)
|
||||
✔ semantics: v1 entries replay as before; review entries need v2 (521.341911ms)
|
||||
✔ set reviewers refuses the row's owner (2026-09-28) (344.323927ms)
|
||||
✔ the owner records no verdict, even as a listed reviewer (517.176466ms)
|
||||
✔ a request comment over the length limit is not sent (588.836789ms)
|
||||
✔ a late POST on a closed row leaves a conflict nothing can resolve, and resolve asks nothing (694.41838ms)
|
||||
✔ a Jason-gated row reaches waiting-on-jason only on every reviewer's approval (2666.764879ms)
|
||||
✔ genesis: refusals before anything is written (441.184559ms)
|
||||
✔ genesis: the map must be committed, well formed, with committed briefs and seats (638.17522ms)
|
||||
✔ genesis: markers, a stray witness, once only; a retry returns the receipt (542.713935ms)
|
||||
✔ genesis: a file holding genesis alone with no witness is confirmed by sync or a retry (519.374038ms)
|
||||
✔ canonical checks: worktree, second clone, detached HEAD, wrong branch, GIT_DIR, foreign code; a symlink works (742.390057ms)
|
||||
✔ --by that differs from MOSAIC_AGENT_NAME warns on stderr and logs nothing more (N12) (1175.319818ms)
|
||||
✔ op ids: missing, too long, reserved; a retry answers; another payload refuses (836.173892ms)
|
||||
✔ a retried add returns the id it first allocated, after reassignment and after done (1235.189137ms)
|
||||
✔ Rocko's S4 schedule: a lost result, another writer, then the retry opens no second round (796.685316ms)
|
||||
✔ the review issue and the evidence round through the CLI (lead decision 23, 8.7) (1562.587561ms)
|
||||
✔ claims and add defaults through the CLI; candidates are manifests or reachable commits (951.858105ms)
|
||||
✔ add, set reviewers and assign refuse the row's owner as a reviewer (712.267751ms)
|
||||
✔ the working-brief check: a changed working copy refuses the start and flags next (829.028797ms)
|
||||
✔ next: resume first, then nothing for an idle seat; needs a seat (390.962001ms)
|
||||
✔ view stale: new ops and verify refuse naming the unshown op; retries answer; reads warn; render fixes (869.719553ms)
|
||||
✔ view unknown: a hand edit, an old marker over an edited body, missing or duplicate markers (1381.457848ms)
|
||||
✔ a hand edit to queue.json refuses every verb, reads included (798.612258ms)
|
||||
✔ verify and render --check leave bytes and mtimes unchanged (559.180177ms)
|
||||
✔ render is byte-stable across runs and repositories (379.44948ms)
|
||||
✔ snapshot and verify --snapshot (949.105612ms)
|
||||
✔ usage errors exit 4 (672.356981ms)
|
||||
✔ a short write, ENOSPC or a file fsync failure: nothing visible, temp removed (392.348745ms)
|
||||
✔ a rename failure: nothing visible, temp removed (197.725628ms)
|
||||
✔ a directory fsync failure: uncertain, exit 3, no receipt; the tail refuses new ops; a retry confirms (325.656857ms)
|
||||
✔ a directory fsync failure, then sync names the op (421.964441ms)
|
||||
✔ a witness write failure: uncertain, durable, exit 3; the view is untouched (251.660287ms)
|
||||
✔ the .git fsync after the witness rename fails: uncertain, exit 3, the witness says so (212.645687ms)
|
||||
✔ confirming a tail fsyncs queue.json and docs/plans before the witness; either failure changes nothing (294.551614ms)
|
||||
✔ the docs/plans fsync after the view rename fails: the op stands, the view is written, a warning says so (247.644967ms)
|
||||
✔ a lock swapped while held is left in place and reported, on a receipt and on a refusal (270.768187ms)
|
||||
✔ a lock that cannot be released after an op is reported, on a receipt and on a refusal (343.766488ms)
|
||||
✔ unlock prints a swapped gate's warning on stderr, the result on stdout (173.697367ms)
|
||||
✔ a view write that fails keeps the op and reports a stale view (435.79884ms)
|
||||
✔ SIGKILL before the rename: nothing recorded; the retry removes the leftover temp (724.765935ms)
|
||||
✔ SIGKILL after the rename, before the witness: the tail refuses new ops and sync names the op (742.710009ms)
|
||||
✔ SIGKILL after the witness, before the view: the stale refusal names the op (861.558187ms)
|
||||
✔ SIGKILL after the view, before the receipt: the retry returns the receipt (712.43739ms)
|
||||
✔ git checkout between steps 1 and 7: step 7 refuses and nothing is written (291.706896ms)
|
||||
✔ git stash restoring an older valid pair: history lost; accept-history needs privilege, a reason and --yes (1340.212527ms)
|
||||
✔ a deleted witness: refused after the locked recheck; accept-history records it absent (438.89869ms)
|
||||
✔ a header edit during a write: the op stands, the view write is skipped with a warning (253.809717ms)
|
||||
✔ a reader paused between the witness and the file while a writer finishes: no lost-history report (259.923983ms)
|
||||
✔ file-then-witness order forced by a hook: the locked recheck prevents a false report (309.231838ms)
|
||||
✔ a writer paused before and after the witness rename: readers see a tail, then a match (379.415949ms)
|
||||
✔ a true rollback is reported only after the locked recheck; a held lock names its holder instead (702.75824ms)
|
||||
✔ an accept-history in progress: an unlocked reader waits on the lock and never reports lost history (716.014685ms)
|
||||
✔ the platform check refuses other filesystems (172.883969ms)
|
||||
✔ tmpfs passes only a test layer that allows it (N5) (267.737966ms)
|
||||
✔ unlock keeps a multi-line lock record on stdout (P3) (245.081358ms)
|
||||
ℹ tests 148
|
||||
ℹ suites 0
|
||||
ℹ pass 148
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 34710.608382
|
||||
@@ -0,0 +1,31 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3472.217224ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (3656.128933ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (4070.705241ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (246.660525ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (71.125718ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (31.337264ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2067.223133ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (120.163476ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (527.949051ms)
|
||||
✔ serve refuses a --business value that is not a business id (171.747344ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3449.547014ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (1645.808442ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1186.148336ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (994.798861ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (3399.383957ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53317.153671ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3351.849099ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22166.043857ms)
|
||||
✔ loopback host and board origin fail closed (8.758778ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (111.560154ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (86.007953ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (823.950155ms)
|
||||
ℹ tests 22
|
||||
ℹ suites 0
|
||||
ℹ pass 22
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 53688.255416
|
||||
@@ -0,0 +1,17 @@
|
||||
start 2026-10-10T06:43:17Z shims=0 units=0
|
||||
node-conversation exit=0 ℹ pass 177 ℹ fail 0 shims-left=0 units=1
|
||||
node-webui exit=0 ℹ pass 22 ℹ fail 0 shims-left=0 units=0
|
||||
test-auth exit=0 selftest: 15 passed, 0 failed
|
||||
test-conductor exit=0 selftest: 17 passed, 0 failed
|
||||
test-config exit=0 selftest: 24 passed, 0 failed
|
||||
test-discord exit=0 discord suite: 66 passed, 0 failed
|
||||
test-extension-package exit=0 extension package selftest: 18 passed, 0 failed
|
||||
test-foundation exit=0 selftest: 44 passed, 0 failed
|
||||
test-queue exit=0 queue suite: 27 passed, 0 failed
|
||||
test-release exit=0 selftest: 4 passed, 0 failed
|
||||
test-task exit=1 selftest: 26 passed, 2 failed
|
||||
end 2026-10-10T06:46:47Z shims-left=0 units=0
|
||||
DONE
|
||||
node-control-board exit=0 ℹ pass 124 ℹ fail 0
|
||||
node-queue exit=0 ℹ pass 148 ℹ fail 0
|
||||
DONE2
|
||||
@@ -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
|
||||
@@ -0,0 +1,23 @@
|
||||
On branch refactor
|
||||
Your branch is up to date with 'origin/refactor'.
|
||||
|
||||
nothing to commit, working tree clean
|
||||
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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: 2230130 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
|
||||
@@ -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
|
||||
@@ -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/r51b/wt) is not the queue's canonical root (/mnt/storage/src/mosaic-stack)
|
||||
|
||||
queue suite: 27 passed, 0 failed
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,131 @@
|
||||
# Row 51, cohort release follow-ups, round 2 review (Darkwing)
|
||||
|
||||
Issue #1537, request comment 27072, notes comment 27073, queue revs
|
||||
304-306. My round 1 was comment 27071 (changes); Sage ruled to move the
|
||||
call and keep the text. Base `b7e9efb7`, which changes nothing under
|
||||
`packages/` or `scripts/` since round 1's `bbb2167f`. Candidate manifest
|
||||
sha256
|
||||
`c34039dc0d52b965bd73cc9f079ae7b253140d77713a3323abc4743f359f0c02`,
|
||||
the same 5 files as round 1. `ctrl-child.mjs` is unchanged from round 1.
|
||||
|
||||
Verdict: **approve**. `#recover` now retries the release after the
|
||||
confirmation check and before the acquire, so a refused `recover` has no
|
||||
side effect. The packet's K6 line and the README now match the code. R9
|
||||
pins the order: every placement of the release above the confirmation
|
||||
check that I tried (round 1's, above the stop-proof check, and between
|
||||
the target and confirmation checks) fails R9. The three notes Dewey took
|
||||
from round 1 each kill the mutant they were aimed at. `noseat` still
|
||||
survives and the packet lists it as a follow-up, which I accept.
|
||||
|
||||
## Method
|
||||
|
||||
- Detached worktree at `b7e9efb7`, the five candidate files copied from a
|
||||
snapshot of the canonical tree, then `sha256sum -c`: 5 OK. A second
|
||||
worktree for the mutants; its five files check OK after all runs
|
||||
(`r2/mut/manifest-after.txt`).
|
||||
- I read the round 1 to round 2 diff in full, `#recover` again from top to
|
||||
bottom, R7 and R9-R11, the README bullet, the packet's "Round 2"
|
||||
section, and the `recover` command in
|
||||
`docs/plans/chat-01/contracts.schema.json`.
|
||||
- 11 mutants (`r2/mut/mutate.py`, `run.sh`), the whole conversation suite
|
||||
each, own TMPDIR each, run after the gate finished. After each run the
|
||||
runner lists any shim left under that TMPDIR. No mutant left one.
|
||||
|
||||
Node v26.8.1, `TMPDIR=~/darkwing-scratch/r51b/tmp`, `gate.sh` with
|
||||
`DOCKER_HOST=unix:///nonexistent.sock`, 06:43:17Z to 06:46:47Z, then
|
||||
control-board and queue (node).
|
||||
|
||||
## Suites
|
||||
|
||||
| Suite | Result |
|
||||
|---|---|
|
||||
| conversation | 177/0 |
|
||||
| webui | 22/0 |
|
||||
| control-board | 124/0 |
|
||||
| queue (node) | 148/0 |
|
||||
| test-auth | 15/0 |
|
||||
| test-conductor | 17/0 |
|
||||
| test-config | 24/0 |
|
||||
| test-discord | 66/0 |
|
||||
| test-extension-package | 18/0 |
|
||||
| test-foundation | 44/0 |
|
||||
| test-queue | 27/0 |
|
||||
| test-release | 4/0 without Docker, 14/0 with it (`test-release-docker.txt`) |
|
||||
| test-task | 26/2 |
|
||||
|
||||
The two `test-task` failures are "user recall run succeeds" and "recalled
|
||||
user name", the live worker check that needs Docker and a model call, as in
|
||||
round 1. Dewey's 98/0 ran them. The one `mosaic-chat-*` unit counted right
|
||||
after the conversation suite was gone at the gate's end, and none was
|
||||
listed after the mutants.
|
||||
|
||||
## The recover order
|
||||
|
||||
```
|
||||
if (... !this.#stopped(s)) return refused("stop-proof");
|
||||
... pins, refused(ENGINE_PIN_MISMATCH) ...
|
||||
... session leaf and branch, refused("target") ...
|
||||
if (!this.#checkConfirmation(r, c, "recover")) return refused("confirmation");
|
||||
// After every check, so a refused recover changes nothing (K6).
|
||||
await this.#releaseListed("recover", this.claim);
|
||||
... acquire ...
|
||||
```
|
||||
|
||||
That's option 1 from my round 1 review. R9 now sends two recovers with the
|
||||
socket back before the confirmed one: one with a confirmation ID that was
|
||||
never issued, and one with a confirmation confirmed for `force-stop`. Both
|
||||
come back `confirmation`, `evidence.releases` is still the one `unavailable`
|
||||
entry, and the unit is still active. The packet says a recover with no
|
||||
`confirmation` field is refused `malformed` before `#recover`. I checked:
|
||||
the schema's `recover` command lists `stop` and `confirmation` as required,
|
||||
and the controller's `malformedRequest` runs before dispatch and refuses a
|
||||
`recover` whose fields don't match `SHAPES.recover` (`stop` and
|
||||
`confirmation`, both IDs).
|
||||
|
||||
The `await` between the confirmation check and the acquire lets another
|
||||
command run in between. That isn't new: the acquire was already awaited,
|
||||
so two recovers could interleave before this row.
|
||||
|
||||
## Mutants
|
||||
|
||||
| Mutant | Change | Conversation | Result |
|
||||
|---|---|---|---|
|
||||
| recconf | the release right after the stop-proof check (round 1's order) | 176/1 | killed: R9 |
|
||||
| recbefore | the release above the stop-proof check | 176/1 | killed: R9 |
|
||||
| recpreconf | the release after the target check, before the confirmation | 176/1 | killed: R9 |
|
||||
| norecover | recover releases nothing | 176/1 | killed: R9 |
|
||||
| nodelete | `#releaseListed` never drops an earlier result | 176/1 | killed: R9 |
|
||||
| startnoawait | the free-path release isn't awaited | 176/1 | killed: R7 |
|
||||
| nolookup | `#releaseListed` sends a request for a unit already absent | 176/1 | killed: R11 |
|
||||
| closeproof | close skips the signal only while `#stopped()` still accepts the stop | 176/1 | killed: R10 |
|
||||
| closekill | close signals after a proven stop | 175/2 | killed: R10, R11 |
|
||||
| recafteracq | the release moves to just after the acquire | 177/0 | survives: see note 1 |
|
||||
| noseat | the free path checks only the session head | 177/0 | survives: the packet's follow-up |
|
||||
|
||||
`recpreconf` is the one placement Dewey's table doesn't have. It's the
|
||||
closest wrong order, past every check except the confirmation, and R9
|
||||
catches it like the others.
|
||||
|
||||
## Notes (not blocking)
|
||||
|
||||
1. `recafteracq` survives. The packet's K17 line says the recover release
|
||||
runs "after them and before the acquire". After the acquire it still
|
||||
acts on `this.claim`, the stopped record the acquire doesn't replace, so
|
||||
no test can tell the two apart from outside. I see no safety difference
|
||||
either: both orders release only a proven-stopped cohort, and both run
|
||||
only on a recover that passed every check. The one difference is a
|
||||
recover whose acquire throws: before the acquire, the release has
|
||||
already happened. That's fine for a recover that passed its
|
||||
confirmation. R7's trick (the launcher reads `evidence.releases.length`)
|
||||
would pin the order if anyone wants it. I don't need it.
|
||||
2. `noseat` survives, as the packet says. It needs a second session on the
|
||||
same seat. I agree it's a follow-up and not this row.
|
||||
3. Dewey's other follow-ups stand as in round 1. The `uncertain` binding
|
||||
whose engine exited on its own is row 52's.
|
||||
|
||||
## Files
|
||||
|
||||
- `r2/candidate-manifest.sha256`: copy of Dewey's.
|
||||
- `r2/gate.sh`, `r2/out/`: suite runs and `summary.txt`.
|
||||
- `r2/mut/`: mutant definitions, runner, per-mutant output and
|
||||
shims-left lists, `summary.txt`, and the manifest check after the runs.
|
||||
Reference in New Issue
Block a user