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