test: pin the compaction audit before the persona refusal

Apply the exact two-row fixture assertion approved by mos-1418 and sage-3232. Preserve earlier red logs; no product change and no rerun before review.
This commit is contained in:
Rocko committed 2026-10-23 00:56:43 -05:00
1 parent b97a3ff975
commit 7cbd839d03
14 files changed
+630 -11

No files matched your search

+31
View File
@@ -229,3 +229,34 @@ The next CLEAR reruns from the beginning: whole files, suites, shells, all
Sage-3179: commit/push during the current gap; hold re-claim until our own Sage-3179: commit/push during the current gap; hold re-claim until our own
slot, after 292 then 294. No tests or queue writes under another seat's slot. slot, after 292 then 294. No tests or queue writes under another seat's slot.
## Restart scope: sage-3224
Run HEAD b97a3ff97, source/test manifest a973912f, unchanged. Start every
stage from the beginning; no prior passing test carry. Sage-3224 explicitly
requires timeout -k 10 per stage, so the packet driver now wraps each Node
stage in that command too (shell stages already had it); the existing process
group timeout/cleanup remains a second bound. No source or test edit.
Singles 300s, suites 1800s, shells 7200s, mutants 180s, TERM-to-KILL 10s.
Fresh short stage TMPDIR. Explicit TAP. Separate run-4a9c-mos1408 output.
## Second old-test edit: mos-1418 / sage-3232 (no restart yet)
The b97a restart at 05:48:57.418-05:49:26.296Z stopped at row213 again:
creative4/0/0, threads19/0/0, user-principal23/0/0, launcher33/1/0.
Original TAP is run-4a9c-mos1408/single-cli-launcher.test.tap. Row270 now
records compactions before the persona refusal: captured tuple was
['compactions',undefined,2], not the full compactions object. Static inference
of count0/known true/reason null was explicitly identified as inference.
No edit or rerun occurred before Mos's approval; slot returned after empty
cwd sweep and 14-hash check. Remaining stages unrun.
Mos-1418 permits this exact second edit: move run-directory lookup above the
pin, require exactly two rows, deepEqual row0 minus at to event compactions,
instance bean, thread, SESSION, run runs[0], count0, known true, reason null;
then take e from row1 and require refused/launch-failed. Later e.thread,
e.why, content nonleak, no sessions, one run, empty run directory and native/
legacy store assertions stay unchanged. Only the specified comment changes.
No product bytes change. If inference is wrong, report red, no third edit.
Dewey must inspect this test diff before the next full restart. Local commit
only while294 holds; push waits for Sage's named gap. No runs after this edit.
+13 -6
View File
@@ -265,10 +265,10 @@ index bfe55b61e..d8248284c 100644
(!threaded && s.instance === r.instance && (spawnedAt.get(s.run) ?? Date.parse(s.startedAt)) <= at))); (!threaded && s.instance === r.instance && (spawnedAt.get(s.run) ?? Date.parse(s.startedAt)) <= at)));
} }
diff --git a/packages/cli/tests/launcher.test.mjs b/packages/cli/tests/launcher.test.mjs diff --git a/packages/cli/tests/launcher.test.mjs b/packages/cli/tests/launcher.test.mjs
index 2202c7753..a9a7d2d40 100644 index 2202c7753..baabd843e 100644
--- a/packages/cli/tests/launcher.test.mjs --- a/packages/cli/tests/launcher.test.mjs
+++ b/packages/cli/tests/launcher.test.mjs +++ b/packages/cli/tests/launcher.test.mjs
@@ -773,21 +773,30 @@ test("row 213 a creative instance's persona is read from <configDir>/personas: o @@ -773,21 +773,34 @@ test("row 213 a creative instance's persona is read from <configDir>/personas: o
const dir = join(given.root, "config", "personas", "acme"); const dir = join(given.root, "config", "personas", "acme");
mkdirSync(dir, { recursive: true, mode: 0o700 }); mkdirSync(dir, { recursive: true, mode: 0o700 });
writeFileSync(join(dir, "bean.md"), "Not the pinned text.\n", { mode: 0o600 }); writeFileSync(join(dir, "bean.md"), "Not the pinned text.\n", { mode: 0o600 });
@@ -278,6 +278,8 @@ index 2202c7753..a9a7d2d40 100644
- await new Client({ path: host.path, cap: chief.cap }).call("role.claim"); - await new Client({ path: host.path, cap: chief.cap }).call("role.claim");
- // The bundle's refusal comes back as launch-failed, as webPlan's does, with its reason in the log. - // The bundle's refusal comes back as launch-failed, as webPlan's does, with its reason in the log.
- assert.deepEqual(await launcher.fromSession(chief.cap, "bean"), { ok: false, error: "launch-failed" }); - assert.deepEqual(await launcher.fromSession(chief.cap, "bean"), { ok: false, error: "launch-failed" });
- const [e] = log(f);
- assert.deepEqual([e.event, e.code, log(f).length], ["refused", "launch-failed", 1]);
+ // Row 219: creative instances launch from their thread, not from a chief's standalone request. + // Row 219: creative instances launch from their thread, not from a chief's standalone request.
+ // The mismatch occurs before bindLaunch, so only the host's thread-state snapshot is a fixture. + // The mismatch occurs before bindLaunch, so only the host's thread-state snapshot is a fixture.
+ const thread = 'persona-thread'; + const thread = 'persona-thread';
@@ -288,16 +290,21 @@ index 2202c7753..a9a7d2d40 100644
+ ? Promise.resolve([{ thread, session: SESSION, instance: 'bean', holder: null, pending: 1 }]) + ? Promise.resolve([{ thread, session: SESSION, instance: 'bean', holder: null, pending: 1 }])
+ : host.op(message), + : host.op(message),
+ }) }); + }) });
+ // The bundle's refusal remains launch-failed with the persona mismatch as its reason. + // The thread path records row 270's run-start count before the bundle's persona refusal.
+ await launcher.tick(); + await launcher.tick();
const [e] = log(f); + const runs = readdirSync(join(f.dataRoot, "launches", "acme"));
assert.deepEqual([e.event, e.code, log(f).length], ["refused", "launch-failed", 1]); + const entries = log(f);
+ assert.equal(entries.length, 2);
+ const { at, ...compactions } = entries[0];
+ assert.deepEqual(compactions, { event: 'compactions', instance: 'bean', thread, session: SESSION, run: runs[0], count: 0, known: true, reason: null });
+ const e = entries[1];
+ assert.deepEqual([e.event, e.code], ["refused", "launch-failed"]);
+ assert.equal(e.thread, thread); + assert.equal(e.thread, thread);
assert.equal(e.why, `instance bean: persona file ${join(dir, "bean.md")} isn't the file persona.sha256 names`); assert.equal(e.why, `instance bean: persona file ${join(dir, "bean.md")} isn't the file persona.sha256 names`);
assert.ok(!JSON.stringify(log(f)).includes("PERSONA-MARKER-d2")); assert.ok(!JSON.stringify(log(f)).includes("PERSONA-MARKER-d2"));
assert.deepEqual(readSessions(f.dataRoot), []); assert.deepEqual(readSessions(f.dataRoot), []);
// The run directory exists by then (BUILD.md residual); the persona is read before any bundle file. // The run directory exists by then (BUILD.md residual); the persona is read before any bundle file.
const runs = readdirSync(join(f.dataRoot, "launches", "acme")); - const runs = readdirSync(join(f.dataRoot, "launches", "acme"));
assert.equal(runs.length, 1); assert.equal(runs.length, 1);
- assert.deepEqual(readdirSync(join(f.dataRoot, "launches", "acme", runs[0])), ["session"]); - assert.deepEqual(readdirSync(join(f.dataRoot, "launches", "acme", runs[0])), ["session"]);
+ assert.deepEqual(readdirSync(join(f.dataRoot, "launches", "acme", runs[0])), []); + assert.deepEqual(readdirSync(join(f.dataRoot, "launches", "acme", runs[0])), []);
@@ -3,7 +3,7 @@ b0c66c8999b567896923f6c876911dba936c6eca1ccc7aaeada51369fd613594 packages/bus/t
de4913f50801a11fd172e3f2c2b3cb41ab04e84d32a6650d1c8662b5e227ea3d packages/bus/tests/threads.test.mjs de4913f50801a11fd172e3f2c2b3cb41ab04e84d32a6650d1c8662b5e227ea3d packages/bus/tests/threads.test.mjs
8f7d6745fffb2a0898ac80c012084ac48964748da6439a8c56facc6529ffb19b packages/bus/tests/user-principal.test.mjs 8f7d6745fffb2a0898ac80c012084ac48964748da6439a8c56facc6529ffb19b packages/bus/tests/user-principal.test.mjs
b74275ce43249bafc97edc87a6a3aa0431c62fe1a28cd9fa265246e6d6da219b packages/cli/src/launcher.mjs b74275ce43249bafc97edc87a6a3aa0431c62fe1a28cd9fa265246e6d6da219b packages/cli/src/launcher.mjs
6e5446030f4bbec714598cc64bf096e9b2a0bd3da1d77817b848fcd67e0d2db9 packages/cli/tests/launcher.test.mjs 2c3f120dfdc0b52bf8ab38a88e86251be75d4b0d218e23df489dcaf815d6bc15 packages/cli/tests/launcher.test.mjs
a219036737419870e0aa9d0da20843759a66be5bafff44d3292593833f8fcb9a packages/cli/tests/thread-launch.test.mjs a219036737419870e0aa9d0da20843759a66be5bafff44d3292593833f8fcb9a packages/cli/tests/thread-launch.test.mjs
cbfd54e6b375561d1e4679ee8d78a3285f970d9a7198cec9d22a06510a36afba packages/webui/src/chat-http.mjs cbfd54e6b375561d1e4679ee8d78a3285f970d9a7198cec9d22a06510a36afba packages/webui/src/chat-http.mjs
f49a49c6ec69783190d3f5eaf34316cb4d2c44d10d2ee9336fe1383207afefff packages/webui/src/chat.mjs f49a49c6ec69783190d3f5eaf34316cb4d2c44d10d2ee9336fe1383207afefff packages/webui/src/chat.mjs
+1
View File
@@ -21,6 +21,7 @@ def sweep():
return found return found
def execute(label,args,cwd=ROOT,deadline=300,docker=False): def execute(label,args,cwd=ROOT,deadline=300,docker=False):
if args[0]=='node' and '--test' in args and '--test-reporter=tap' not in args:args=[args[0],'--test-reporter=tap',*args[1:]] if args[0]=='node' and '--test' in args and '--test-reporter=tap' not in args:args=[args[0],'--test-reporter=tap',*args[1:]]
if args[0]!='timeout':args=['timeout','-k','10',str(deadline),*args]
verify();short=tempfile.mkdtemp(prefix='r',dir='/mnt/storage/scratch/tmp') verify();short=tempfile.mkdtemp(prefix='r',dir='/mnt/storage/scratch/tmp')
env=os.environ.copy();env.update(TMPDIR=short,NO_COLOR='1',COMPOSE_PROJECT_NAME='rocko-r219-gate') env=os.environ.copy();env.update(TMPDIR=short,NO_COLOR='1',COMPOSE_PROJECT_NAME='rocko-r219-gate')
env.pop('MOSAIC_GITEA_CREDENTIAL_FILE',None);env.pop('MOSAIC_LIVE_PROVIDER',None) env.pop('MOSAIC_GITEA_CREDENTIAL_FILE',None);env.pop('MOSAIC_LIVE_PROVIDER',None)
@@ -0,0 +1 @@
[]
@@ -0,0 +1 @@
[]
@@ -0,0 +1 @@
{"head": "b97a3ff9757ec2ac39d9ab4cebb9769e471df932", "manifest": "a973912fe2fb9c64606cd99a385305b8f51498a096511b3a980bca6b0a5b98aa", "start": "2026-10-23T05:48:57.416807+00:00"}
@@ -0,0 +1,2 @@
Error response from daemon: network rocko-r219-gate_default not found
exit status 1
@@ -0,0 +1,4 @@
{"label": "single-bus-creative.test", "args": ["timeout", "-k", "10", "300", "node", "--test-reporter=tap", "--test", "packages/bus/tests/creative.test.mjs"], "start": "2026-10-23T05:48:57.418927+00:00", "end": "2026-10-23T05:48:57.834246+00:00", "seconds": 0.415, "exit": 0, "timeout": false, "counts": {"tests": 4, "pass": 4, "fail": 0, "cancelled": 0, "skipped": 0}, "skips": ["# skipped 0"], "log": "agents/rocko/work/queue-219/run-4a9c-mos1408/single-bus-creative.test.tap", "tmpdir": "/mnt/storage/scratch/tmp/rs156uowe"}
{"label": "single-bus-threads.test", "args": ["timeout", "-k", "10", "300", "node", "--test-reporter=tap", "--test", "packages/bus/tests/threads.test.mjs"], "start": "2026-10-23T05:48:57.835837+00:00", "end": "2026-10-23T05:48:59.152912+00:00", "seconds": 1.317, "exit": 0, "timeout": false, "counts": {"tests": 19, "pass": 19, "fail": 0, "cancelled": 0, "skipped": 0}, "skips": ["# skipped 0"], "log": "agents/rocko/work/queue-219/run-4a9c-mos1408/single-bus-threads.test.tap", "tmpdir": "/mnt/storage/scratch/tmp/rbqz65jtz"}
{"label": "single-bus-user-principal.test", "args": ["timeout", "-k", "10", "300", "node", "--test-reporter=tap", "--test", "packages/bus/tests/user-principal.test.mjs"], "start": "2026-10-23T05:48:59.154288+00:00", "end": "2026-10-23T05:48:59.719646+00:00", "seconds": 0.565, "exit": 0, "timeout": false, "counts": {"tests": 23, "pass": 23, "fail": 0, "cancelled": 0, "skipped": 0}, "skips": ["# skipped 0"], "log": "agents/rocko/work/queue-219/run-4a9c-mos1408/single-bus-user-principal.test.tap", "tmpdir": "/mnt/storage/scratch/tmp/rztf343rx"}
{"label": "single-cli-launcher.test", "args": ["timeout", "-k", "10", "300", "node", "--test-reporter=tap", "--test", "packages/cli/tests/launcher.test.mjs"], "start": "2026-10-23T05:48:59.721051+00:00", "end": "2026-10-23T05:49:26.296570+00:00", "seconds": 26.576, "exit": 1, "timeout": false, "counts": {"tests": 34, "pass": 33, "fail": 1, "cancelled": 0, "skipped": 0}, "skips": ["# skipped 0"], "log": "agents/rocko/work/queue-219/run-4a9c-mos1408/single-cli-launcher.test.tap", "tmpdir": "/mnt/storage/scratch/tmp/r8xucbjgl"}
@@ -0,0 +1,36 @@
TAP version 13
# organization: {"event":"reload-needs-restart","business":"demo"}
# organization: {"event":"reload-needs-restart","business":"demo"}
# Subtest: M6: a creative raise refuses decision-not-allowed, cited or not, and no decision row appears; the assistant still raises
ok 1 - M6: a creative raise refuses decision-not-allowed, cited or not, and no decision row appears; the assistant still raises
---
duration_ms: 37.235384
type: 'test'
...
# Subtest: a creative instance sends only to the user and hears only from the user
ok 2 - a creative instance sends only to the user and hears only from the user
---
duration_ms: 44.266739
type: 'test'
...
# Subtest: M10 through the broker: the chief and the tester are refused on bean, the human's limits.set of its models key works
ok 3 - M10 through the broker: the chief and the tester are refused on bean, the human's limits.set of its models key works
---
duration_ms: 83.079495
type: 'test'
...
# Subtest: row 256 T6 the human deletes a creative instance through the broker; the chief and the tester are refused at the verb
ok 4 - row 256 T6 the human deletes a creative instance through the broker; the chief and the tester are refused at the verb
---
duration_ms: 63.576082
type: 'test'
...
1..4
# tests 4
# suites 0
# pass 4
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 356.82109
@@ -0,0 +1,124 @@
TAP version 13
# Subtest: REQ-ROLE-2 REQ-THREAD-1: one holder per thread, through the broker and the trigger
ok 1 - REQ-ROLE-2 REQ-THREAD-1: one holder per thread, through the broker and the trigger
---
duration_ms: 37.957781
type: 'test'
...
# Subtest: REQ-ROLE-2 REQ-THREAD-1: the 3e triggers refuse writes that skip the broker
ok 2 - REQ-ROLE-2 REQ-THREAD-1: the 3e triggers refuse writes that skip the broker
---
duration_ms: 68.301373
type: 'test'
...
# Subtest: REQ-MSG-1: a message to or from the assistant names its thread, or is refused
ok 3 - REQ-MSG-1: a message to or from the assistant names its thread, or is refused
---
duration_ms: 31.316512
type: 'test'
...
# Subtest: REQ-MSG-1: the chief of staff's reply comes back to the thread that sent the work
ok 4 - REQ-MSG-1: the chief of staff's reply comes back to the thread that sent the work
---
duration_ms: 593.922455
type: 'test'
...
# Subtest: REQ-MSG-1: a reply can't carry one thread instance's thread to another thread instance
ok 5 - REQ-MSG-1: a reply can't carry one thread instance's thread to another thread instance
---
duration_ms: 24.857971
type: 'test'
...
# Subtest: REQ-THREAD-1 REQ-USER-2: one thread's messages never reach another thread's holder
ok 6 - REQ-THREAD-1 REQ-USER-2: one thread's messages never reach another thread's holder
---
duration_ms: 27.519976
type: 'test'
...
# Subtest: REQ-LAUNCH-1: a message to a thread with no holder waits, and the next holder gets it
ok 7 - REQ-LAUNCH-1: a message to a thread with no holder waits, and the next holder gets it
---
duration_ms: 30.716822
type: 'test'
...
# Subtest: REQ-THREAD-2 REQ-LAUNCH-1: threadIdle releases only a thread with nothing waiting, and only for its holder
ok 8 - REQ-THREAD-2 REQ-LAUNCH-1: threadIdle releases only a thread with nothing waiting, and only for its holder
---
duration_ms: 33.754906
type: 'test'
...
# Subtest: REQ-THREAD-2 REQ-LAUNCH-1: a message delivered to a run that ended unread doesn't hold up the next holder
ok 9 - REQ-THREAD-2 REQ-LAUNCH-1: a message delivered to a run that ended unread doesn't hold up the next holder
---
duration_ms: 29.046481
type: 'test'
...
# Subtest: REQ-ROLE-2 REQ-THREAD-1 Q169: a role.revoke the human approved ends every thread run of the assistant
ok 10 - REQ-ROLE-2 REQ-THREAD-1 Q169: a role.revoke the human approved ends every thread run of the assistant
---
duration_ms: 26.449042
type: 'test'
...
# Subtest: Q169 REQ-USER-2: assistant.stop ends the human's own assistant thread runs, and only the human's
ok 11 - Q169 REQ-USER-2: assistant.stop ends the human's own assistant thread runs, and only the human's
---
duration_ms: 38.524966
type: 'test'
...
# Subtest: REQ-USER-2: the human verbs refuse another owner's thread
ok 12 - REQ-USER-2: the human verbs refuse another owner's thread
---
duration_ms: 28.558392
type: 'test'
...
# Subtest: REQ-THREAD-1: thread.create refuses when the business has no thread instance or more than one
ok 13 - REQ-THREAD-1: thread.create refuses when the business has no thread instance or more than one
---
duration_ms: 23.166467
type: 'test'
...
# Subtest: REQ-ORG-2: projects and threads are named once, and the repo names a business project
ok 14 - REQ-ORG-2: projects and threads are named once, and the repo names a business project
---
duration_ms: 28.154835
type: 'test'
...
# Subtest: REQ-THREAD-2: thread.messages returns the thread's history in pages and writes nothing
ok 15 - REQ-THREAD-2: thread.messages returns the thread's history in pages and writes nothing
---
duration_ms: 86.802213
type: 'test'
...
# Subtest: project.create refuses a repository name without its matching repo before any write
ok 16 - project.create refuses a repository name without its matching repo before any write
---
duration_ms: 15.244016
type: 'test'
...
# Subtest: project.create keeps unrelated names with and without a repository
ok 17 - project.create keeps unrelated names with and without a repository
---
duration_ms: 11.57841
type: 'test'
...
# Subtest: C2-09a: explicit creative instances bind independent threads, default sessions and holders
ok 18 - C2-09a: explicit creative instances bind independent threads, default sessions and holders
---
duration_ms: 46.82113
type: 'test'
...
# Subtest: C2-09a: explicit missing, non-thread and malformed selectors create no thread or session
ok 19 - C2-09a: explicit missing, non-thread and malformed selectors create no thread or session
---
duration_ms: 20.263528
type: 'test'
...
1..19
# tests 19
# suites 0
# pass 19
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 1283.575562
@@ -0,0 +1,148 @@
TAP version 13
# Subtest: R3: bindUser binds a granted user and refuses one with no live grant
ok 1 - R3: bindUser binds a granted user and refuses one with no live grant
---
duration_ms: 15.216913
type: 'test'
...
# Subtest: R3: a user named like the business human, the tester or a principal word is refused, whatever the grants say
ok 2 - R3: a user named like the business human, the tester or a principal word is refused, whatever the grants say
---
duration_ms: 10.127905
type: 'test'
...
# Subtest: R3: each collaborator verb is allowed to a granted user
ok 3 - R3: each collaborator verb is allowed to a granted user
---
duration_ms: 18.491408
type: 'test'
...
# Subtest: R3: every verb off the collaborator list refuses a user access-refused before its own checks
ok 4 - R3: every verb off the collaborator list refuses a user access-refused before its own checks
---
duration_ms: 95.840429
type: 'test'
...
# Subtest: R3: task, web and host verbs refuse a user access-refused
ok 5 - R3: task, web and host verbs refuse a user access-refused
---
duration_ms: 22.333602
type: 'test'
...
# Subtest: R3 leak: project.list shows granted projects only
ok 6 - R3 leak: project.list shows granted projects only
---
duration_ms: 12.494935
type: 'test'
...
# Subtest: R3 leak: thread.create needs the project and the thread instance granted, and an ungranted id reads as one that does not exist
ok 7 - R3 leak: thread.create needs the project and the thread instance granted, and an ungranted id reads as one that does not exist
---
duration_ms: 15.195921
type: 'test'
...
# Subtest: R3 leak: thread.list shows the user its own threads that are still granted, never others
ok 8 - R3 leak: thread.list shows the user its own threads that are still granted, never others
---
duration_ms: 33.037437
type: 'test'
...
# Subtest: R3 leak: names shows granted instances only
ok 9 - R3 leak: names shows granted instances only
---
duration_ms: 14.891286
type: 'test'
...
# Subtest: R3: thread.send is from user:<id> and writes no human.input
ok 10 - R3: thread.send is from user:<id> and writes no human.input
---
duration_ms: 13.366772
type: 'test'
...
# Subtest: R3: a reply-chain message.send into another user thread is refused
ok 11 - R3: a reply-chain message.send into another user thread is refused
---
duration_ms: 15.523733
type: 'test'
...
# Subtest: R3: the run reply to a user message reaches that user thread.messages, with no waiting and no notice
ok 12 - R3: the run reply to a user message reaches that user thread.messages, with no waiting and no notice
---
duration_ms: 18.163702
type: 'test'
...
# Subtest: R3: a reply to: user without a matching in_reply_to is refused user-reply-required
ok 13 - R3: a reply to: user without a matching in_reply_to is refused user-reply-required
---
duration_ms: 26.445744
type: 'test'
...
# Subtest: R3: a non-thread run, the human and the tester cannot send to: user
ok 14 - R3: a non-thread run, the human and the tester cannot send to: user
---
duration_ms: 17.29104
type: 'test'
...
# Subtest: R3: a user thread run cannot message the owner, while its uncited gated raise reaches only the owner inbox, B9
ok 15 - R3: a user thread run cannot message the owner, while its uncited gated raise reaches only the owner inbox, B9
---
duration_ms: 19.258704
type: 'test'
...
# Subtest: R3: a removed or expired grant refuses the next request access-revoked, and the file is read per request
ok 16 - R3: a removed or expired grant refuses the next request access-revoked, and the file is read per request
---
duration_ms: 18.231409
type: 'test'
...
# Subtest: R3: a user refusal is recorded as action.refused by user:<id>
ok 17 - R3: a user refusal is recorded as action.refused by user:<id>
---
duration_ms: 13.797301
type: 'test'
...
# Subtest: R3: a business with a role keyed user refuses invalid-business
ok 18 - R3: a business with a role keyed user refuses invalid-business
---
duration_ms: 9.468564
type: 'test'
...
# Subtest: R3: name.set refuses the name user
ok 19 - R3: name.set refuses the name user
---
duration_ms: 9.752458
type: 'test'
...
# Subtest: R3 r4: while halted, a granted user's thread.send refuses processing-halted and thread.messages still answers
ok 20 - R3 r4: while halted, a granted user's thread.send refuses processing-halted and thread.messages still answers
---
duration_ms: 13.617784
type: 'test'
...
# Subtest: R3 r4: the chief's hire refuses an instance named user with the code it gives human and tester
ok 21 - R3 r4: the chief's hire refuses an instance named user with the code it gives human and tester
---
duration_ms: 14.726171
type: 'test'
...
# Subtest: R3 r4: a non-function access throws before the store is read
ok 22 - R3 r4: a non-function access throws before the store is read
---
duration_ms: 0.105564
type: 'test'
...
# Subtest: C2-09a: naming an instance cannot bypass its collaborator grant or disclose an ungranted project
ok 23 - C2-09a: naming an instance cannot bypass its collaborator grant or disclose an ungranted project
---
duration_ms: 15.883063
type: 'test'
...
1..23
# tests 23
# suites 0
# pass 23
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 523.149354
@@ -0,0 +1,259 @@
TAP version 13
# Subtest: C2-04: launcher workspace clones code but never the library
ok 1 - C2-04: launcher workspace clones code but never the library
---
duration_ms: 1444.885132
type: 'test'
...
# Subtest: bus start --pm: the launcher instance (the chief of staff) runs under its own PID namespace, registered, with a manifest
ok 2 - bus start --pm: the launcher instance (the chief of staff) runs under its own PID namespace, registered, with a manifest
---
duration_ms: 1312.408111
type: 'test'
...
# usage: {"event":"usage-unknown","business":"acme","run":"r910aab09c0d6","instance":"chief","turn":"368e3045-8783-47d3-8ae1-e429b321d9b1","source":"@none","code":"baseline-unknown"}
# usage: {"event":"usage-unknown","business":"acme","run":"r5bb5f0657d94","instance":"coder","turn":"3432d01f-ca94-4a5e-88d3-19588a40a81d","source":"@none","code":"baseline-unknown"}
# Subtest: the chief of staff launches a coder through its launch tool; the coder answers; refusals name their code
ok 3 - the chief of staff launches a coder through its launch tool; the coder answers; refusals name their code
---
duration_ms: 745.868459
type: 'test'
...
# usage: {"event":"usage-unknown","business":"acme","run":"r0f3692812967","instance":"chief","turn":"3bd3e4d7-3af4-4a1c-99f1-a8f25b7ab1dd","source":"@none","code":"baseline-unknown"}
# usage: {"event":"usage-unknown","business":"acme","run":"re94397bc3680","instance":"pm","turn":"b2db478d-2905-49fd-a81a-0800643bed6a","source":"@none","code":"baseline-unknown"}
# usage: {"event":"usage-unknown","business":"acme","run":"r0f3692812967","instance":"chief","turn":"ac2aa380-f3a0-40d4-960f-a543acb8c431","source":"@none","code":"baseline-unknown"}
# usage: {"event":"usage-unknown","business":"acme","run":"re94397bc3680","instance":"pm","turn":"e8b5124b-591b-4d5b-829c-e944bb3e24bb","source":"@none","code":"baseline-unknown"}
# usage: {"event":"usage-unknown","business":"acme","run":"re94397bc3680","instance":"pm","turn":"6a6e1fa4-5182-42dc-bbc2-26f136eedee3","source":"@none","code":"baseline-unknown"}
# usage: {"event":"usage-unknown","business":"acme","run":"r0f3692812967","instance":"chief","turn":"54eb77b5-3880-4afb-9772-0b9d590eb328","source":"@none","code":"baseline-unknown"}
# usage: {"event":"usage-unknown","business":"acme","run":"re94397bc3680","instance":"pm","turn":"11fe8b92-1dae-416a-838b-ae305db74bc6","source":"@none","code":"baseline-unknown"}
# usage: {"event":"usage-unknown","business":"acme","run":"r0f3692812967","instance":"chief","turn":"68266357-b477-433c-99ed-f1af37143d91","source":"@none","code":"baseline-unknown"}
# Subtest: a launched pm's request_staff reaches the chief of staff; no other session has the tool and the launch limits still hold
ok 4 - a launched pm's request_staff reaches the chief of staff; no other session has the tool and the launch limits still hold
---
duration_ms: 1245.265675
type: 'test'
...
# Subtest: each launch makes sure the workspace has a clone of the project: cloned, fast-forwarded, or fetched and logged
ok 5 - each launch makes sure the workspace has a clone of the project: cloned, fast-forwarded, or fetched and logged
---
duration_ms: 4072.119958
type: 'test'
...
# Subtest: a role the broker says holds a merge decision gets land_work, its prompt line, its landing and the git socket; without it, none
ok 6 - a role the broker says holds a merge decision gets land_work, its prompt line, its landing and the git socket; without it, none
---
duration_ms: 621.888037
type: 'test'
...
# Subtest: REQ-LAUNCH-1 the tick starts a listed merge decision holder once, with land_work, the Landing line and its landing turn; an unlisted holder starts nothing
ok 7 - REQ-LAUNCH-1 the tick starts a listed merge decision holder once, with land_work, the Landing line and its landing turn; an unlisted holder starts nothing
---
duration_ms: 417.133166
type: 'test'
...
# usage: {"event":"usage-unknown","business":"acme","run":"r8e91dd37dc4b","instance":"coder","turn":"a7b24e30-ac5e-47cf-a951-90cf0d948b4d","source":"@none","code":"baseline-unknown"}
# Subtest: a holder running since before the resolution is stopped once the broker releases it, land-relaunch, and the next tick starts it: landing turn first, then the message that waited
ok 8 - a holder running since before the resolution is stopped once the broker releases it, land-relaunch, and the next tick starts it: landing turn first, then the message that waited
---
duration_ms: 730.904044
type: 'test'
...
# Subtest: a landing run that ended isn't started again for its decision, a spent decision starts nothing, and a new decision starts the holder
ok 9 - a landing run that ended isn't started again for its decision, a spent decision starts nothing, and a new decision starts the holder
---
duration_ms: 698.470719
type: 'test'
...
# Subtest: after a restart, the new host's first tick starts a holder whose decision is still held
ok 10 - after a restart, the new host's first tick starts a holder whose decision is still held
---
duration_ms: 920.432738
type: 'test'
...
# Subtest: a refused landing start is logged once per code with its decision, isn't a start, and the next tick with room starts the holder
ok 11 - a refused landing start is logged once per code with its decision, isn't a start, and the next tick with room starts the holder
---
duration_ms: 641.309798
type: 'test'
...
# Subtest: a project clone that can't be made refuses checkout-failed, from --chief and from a session, with no run and no clone left
ok 12 - a project clone that can't be made refuses checkout-failed, from --chief and from a session, with no run and no clone left
---
duration_ms: 267.647539
type: 'test'
...
# Subtest: a runner that stops at once ends its launch with the runner's reason
ok 13 - a runner that stops at once ends its launch with the runner's reason
---
duration_ms: 332.423482
type: 'test'
...
# Subtest: a Claude Code launch with no session credential refuses before it starts
ok 14 - a Claude Code launch with no session credential refuses before it starts
---
duration_ms: 181.931254
type: 'test'
...
# Subtest: a pi launch needs no session credential: pi logs in through its own ENV_ALLOW variables
ok 15 - a pi launch needs no session credential: pi logs in through its own ENV_ALLOW variables
---
duration_ms: 315.27683
type: 'test'
...
# usage: {"event":"plugin-refused","kind":"harness","name":"down","code":"missing","message":"/mnt/storage/scratch/rocko-r219/packages/plugins/harness/down is missing","kept":[]}
# plugins: {"event":"plugin-refused","kind":"harness","name":"down","code":"missing","message":"/mnt/storage/scratch/rocko-r219/packages/plugins/harness/down is missing","kept":[]}
# Subtest: row 65 a failed primary preflight launches the fallback on a fixture harness module, recording the route and the reason
ok 16 - row 65 a failed primary preflight launches the fallback on a fixture harness module, recording the route and the reason
---
duration_ms: 353.028786
type: 'test'
...
# Subtest: a runner killed from the host ends its launch as killed, not failed
ok 17 - a runner killed from the host ends its launch as killed, not failed
---
duration_ms: 375.548364
type: 'test'
...
# Subtest: a missing or failing bwrap refuses sandbox-unavailable before anything starts; there is no unconfined fallback
ok 18 - a missing or failing bwrap refuses sandbox-unavailable before anything starts; there is no unconfined fallback
---
duration_ms: 187.871873
type: 'test'
...
# Subtest: row 64 a role skill that isn't enabled refuses skill-not-enabled, and one that isn't a plain directory skill-refused, before anything starts
ok 19 - row 64 a role skill that isn't enabled refuses skill-not-enabled, and one that isn't a plain directory skill-refused, before anything starts
---
duration_ms: 187.807189
type: 'test'
...
# Subtest: row 213 a creative instance's persona is read from <configDir>/personas: off its digest the launch fails with the mismatch as its reason
not ok 20 - row 213 a creative instance's persona is read from <configDir>/personas: off its digest the launch fails with the mismatch as its reason
---
duration_ms: 255.698016
type: 'test'
location: '/mnt/storage/scratch/rocko-r219/packages/cli/tests/launcher.test.mjs:766:1'
failureType: 'testCodeFailure'
error: |-
Expected values to be strictly deep-equal:
+ actual - expected
[
+ 'compactions',
+ undefined,
+ 2
- 'refused',
- 'launch-failed',
- 1
]
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected:
0: 'refused'
1: 'launch-failed'
2: 1
actual:
0: 'compactions'
2: 2
operator: 'deepStrictEqual'
stack: |-
TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r219/packages/cli/tests/launcher.test.mjs:789:10)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async Test.run (node:internal/test_runner/test:1409:7)
async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
...
# Subtest: row 64 on Claude Code a role skill that isn't enabled refuses the same way, before anything starts
ok 21 - row 64 on Claude Code a role skill that isn't enabled refuses the same way, before anything starts
---
duration_ms: 194.030218
type: 'test'
...
# usage: {"event":"usage-unknown","business":"acme","run":"r3715d40bd7fb","instance":"chief","turn":"4c85d22f-fdab-4ab7-ad8a-6b4c4d1fbf72","source":"@none","code":"baseline-unknown"}
# usage: {"event":"usage-unknown","business":"acme","run":"r16ae936abadf","instance":"coder","turn":"2c6b06f1-8f36-4261-81b7-2689b9bb7ff4","source":"@none","code":"baseline-unknown"}
# Subtest: a real Claude Code coder's shell can't read a stand-in secret or anything else its sandbox doesn't hold
ok 22 - a real Claude Code coder's shell can't read a stand-in secret or anything else its sandbox doesn't hold
---
duration_ms: 1456.773218
type: 'test'
...
# Subtest: a host that died hard leaves its sessions to the next host, which kills them and ends their runs so the role can be launched again
ok 23 - a host that died hard leaves its sessions to the next host, which kills them and ends their runs so the role can be launched again
---
duration_ms: 1063.59923
type: 'test'
...
# Subtest: a host that died hard leaves its sessions to the next host, which finds one already exited (23) and ends their runs so the role can be launched again
ok 24 - a host that died hard leaves its sessions to the next host, which finds one already exited (23) and ends their runs so the role can be launched again
---
duration_ms: 4016.888246
type: 'test'
...
# Subtest: bus start --no-launch leaves an earlier host's live session alone: no signal, no end, sessions.json as it was
ok 25 - bus start --no-launch leaves an earlier host's live session alone: no signal, no end, sessions.json as it was
---
duration_ms: 237.364574
type: 'test'
...
# Subtest: bus start --no-launch refuses every launch: the PM launch and a session's request, each logged, nothing spawned
ok 26 - bus start --no-launch refuses every launch: the PM launch and a session's request, each logged, nothing spawned
---
duration_ms: 197.775267
type: 'test'
...
# Subtest: bus start --no-launch starts no thread tick; the same host with launches runs it
ok 27 - bus start --no-launch starts no thread tick; the same host with launches runs it
---
duration_ms: 1181.987654
type: 'test'
...
# Subtest: a malformed sessions.json refuses the host start with exit 3 and stays as it was
ok 28 - a malformed sessions.json refuses the host start with exit 3 and stays as it was
---
duration_ms: 177.111363
type: 'test'
...
# Subtest: an over-long launch request is refused at once, not at the 10 s idle timeout
ok 29 - an over-long launch request is refused at once, not at the 10 s idle timeout
---
duration_ms: 183.364128
type: 'test'
...
# Subtest: a launch client that never closes its side doesn't hold the host's close
ok 30 - a launch client that never closes its side doesn't hold the host's close
---
duration_ms: 179.49662
type: 'test'
...
# Subtest: a runner that ignores SIGTERM is killed when the host closes
ok 31 - a runner that ignores SIGTERM is killed when the host closes
---
duration_ms: 1352.083242
type: 'test'
...
# Subtest: kill switch refuses chief and hire before launch work and a clear permits a later request
ok 32 - kill switch refuses chief and hire before launch work and a clear permits a later request
---
duration_ms: 319.505559
type: 'test'
...
# Subtest: kill switch stops an actual managed namespace and records the halt reason without rewriting its bundle
ok 33 - kill switch stops an actual managed namespace and records the halt reason without rewriting its bundle
---
duration_ms: 334.076309
type: 'test'
...
# Subtest: a launch waiting across halt and resume cannot use its stale admission
ok 34 - a launch waiting across halt and resume cannot use its stale admission
---
duration_ms: 201.932098
type: 'test'
...
1..34
# tests 34
# suites 0
# pass 33
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 26522.233904
+8 -4
View File
@@ -783,16 +783,20 @@ test("row 213 a creative instance's persona is read from <configDir>/personas: o
? Promise.resolve([{ thread, session: SESSION, instance: 'bean', holder: null, pending: 1 }]) ? Promise.resolve([{ thread, session: SESSION, instance: 'bean', holder: null, pending: 1 }])
: host.op(message), : host.op(message),
}) }); }) });
// The bundle's refusal remains launch-failed with the persona mismatch as its reason. // The thread path records row 270's run-start count before the bundle's persona refusal.
await launcher.tick(); await launcher.tick();
const [e] = log(f); const runs = readdirSync(join(f.dataRoot, "launches", "acme"));
assert.deepEqual([e.event, e.code, log(f).length], ["refused", "launch-failed", 1]); const entries = log(f);
assert.equal(entries.length, 2);
const { at, ...compactions } = entries[0];
assert.deepEqual(compactions, { event: 'compactions', instance: 'bean', thread, session: SESSION, run: runs[0], count: 0, known: true, reason: null });
const e = entries[1];
assert.deepEqual([e.event, e.code], ["refused", "launch-failed"]);
assert.equal(e.thread, thread); assert.equal(e.thread, thread);
assert.equal(e.why, `instance bean: persona file ${join(dir, "bean.md")} isn't the file persona.sha256 names`); assert.equal(e.why, `instance bean: persona file ${join(dir, "bean.md")} isn't the file persona.sha256 names`);
assert.ok(!JSON.stringify(log(f)).includes("PERSONA-MARKER-d2")); assert.ok(!JSON.stringify(log(f)).includes("PERSONA-MARKER-d2"));
assert.deepEqual(readSessions(f.dataRoot), []); assert.deepEqual(readSessions(f.dataRoot), []);
// The run directory exists by then (BUILD.md residual); the persona is read before any bundle file. // The run directory exists by then (BUILD.md residual); the persona is read before any bundle file.
const runs = readdirSync(join(f.dataRoot, "launches", "acme"));
assert.equal(runs.length, 1); assert.equal(runs.length, 1);
assert.deepEqual(readdirSync(join(f.dataRoot, "launches", "acme", runs[0])), []); assert.deepEqual(readdirSync(join(f.dataRoot, "launches", "acme", runs[0])), []);
assert.equal(existsSync(join(f.dataRoot, "threads", "acme", thread, "sessions", SESSION, "session")), true); assert.equal(existsSync(join(f.dataRoot, "threads", "acme", thread, "sessions", SESSION, "session")), true);