diff --git a/packages/cli/tests/launcher.test.mjs b/packages/cli/tests/launcher.test.mjs index 2202c7753..0a34fe27a 100644 --- a/packages/cli/tests/launcher.test.mjs +++ b/packages/cli/tests/launcher.test.mjs @@ -773,21 +773,28 @@ test("row 213 a creative instance's persona is read from /personas: o const dir = join(given.root, "config", "personas", "acme"); mkdirSync(dir, { recursive: true, mode: 0o700 }); writeFileSync(join(dir, "bean.md"), "Not the pinned text.\n", { mode: 0o600 }); - const { f, host, launcher } = await setup(t, undefined, given); - // The chief of staff holds role.launch; a test chief session bound to this process asks. - const chief = await host.bindLaunch({ business: "acme", role: "chief", run: "chief-test", harness: "pi", pid: process.pid, startTime: startTimeOf(process.pid) }); - 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. - assert.deepEqual(await launcher.fromSession(chief.cap, "bean"), { ok: false, error: "launch-failed" }); + // 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. + const thread = 'persona-thread'; + const { f, launcher } = await setup(t, undefined, given, { wrap: host => ({ + ...host, + op: message => message.op === 'threadsState' + ? Promise.resolve([{ thread, instance: 'bean', holder: null, pending: 1 }]) + : host.op(message), + }) }); + // The bundle's refusal remains launch-failed with the persona mismatch as its reason. + await launcher.tick(); const [e] = log(f); assert.deepEqual([e.event, e.code, log(f).length], ["refused", "launch-failed", 1]); + 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.ok(!JSON.stringify(log(f)).includes("PERSONA-MARKER-d2")); assert.deepEqual(readSessions(f.dataRoot), []); // 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.deepEqual(readdirSync(join(f.dataRoot, "launches", "acme", runs[0])), ["session"]); + assert.deepEqual(readdirSync(join(f.dataRoot, "launches", "acme", runs[0])), []); + assert.equal(existsSync(join(f.dataRoot, "threads", "acme", thread, "session")), true); }); test("row 64 on Claude Code a role skill that isn't enabled refuses the same way, before anything starts", { timeout: 30000 }, async (t) => {