fix(harness): expose trusted assistant coordinator context (#797)

This commit is contained in:
jason.woltje committed 2026-11-05 20:39:48 -06:00
1 parent 29a3cc6323
commit 2f1cef4c1d
8 files changed
+108 -4

No files matched your search

+6
View File
@@ -6201,3 +6201,9 @@ Before: isolated checkout at 05fdfef9ea1fdddf58c725c04f229ca8559fc054, branch fi
## 2026-11-05 — MVP 3 relay fixes (#797 / #1839), author phase completed
After: assistant addresses the configured chief instance; role-send receipts derive provenance from the stored message and existing reply-chain checks; PM and chief guidance describes the existing bound bootstrap decision and request-based staffing before task creation. No role JSON, schema, policy or alias change. F2 whole-file regression was red (7 pass, 1 fail: null relay receipt) then green (8 pass), with unlinked, wrong-recipient and caller-supplied-ID negatives; threaded reply file passed 20/20. Final whole-suite gates: bus on Node 24.22.1 1596/1596; harness 242/242; business 307/307; 37 additional broker-importer files 512/512; zero failures, cancellations or skips. Original Node 26 bus attempt was interrupted after project-files stalled in a socket send: 1593 pass, one cancelled; that whole file passed 8/8 on Node 24.22.1 and the complete bus suite was rerun. Scratch TMPDIR, exact commands and logs: /mnt/storage/scratch/mosaic-lead/mvp3/relay-fix-r1-report.md. Local commit authorized; independent review and all publication or live actions remain outside this author phase.
## 2026-11-05 — MVP 3 relay R2 trusted coordinator context (#797 / #1839)
Before: isolated branch fix/mvp3-relay-797-r2 from 29a3cc63238307d8644447c67a0364a6b03dfa36. Independent R1 review's sole CHANGES finding: owner-started assistants could not discover an arbitrary configured chief key, especially offline. Direct R2 charter authorizes trusted generated routing context, offline swapped-key integration evidence, required tests, append-only records and a local commit; no push or live action. Queue read refused linked worktree, then canonical read returned nothing; no queue mutation.
After: assistant-only resolved coordinator context comes from validated launch.by and the coordinator's optional configured identity.name. The generated prompt names the exact instance key and role guidance uses it explicitly; no-launch context reports a blocker. Broker source, messaging policy, recipient checks and role JSON are unchanged. Config-to-bundle-to-broker integration covers owner-launched assistant, offline chief, violet/opal definition swap, descriptive name, ignored session override, correct stored recipient/provenance, forbidden CIO and definition-alias refusals. Required whole-file gate 321/321 and additional content/path/bundle checks 124/124 on Node 24.22.1; final touched bundle file 24/24, all zero failures/cancellations/skips. Existing digest machinery covers assistant coordinator and prompt bytes; no literal changed-source hash pin required an update. Original reviewer probes 12/13 because their F1 deepEqual asserts the diagnosed defect; preserved original and a scratch copy changing only that assertion to notDeepEqual passed 13/13, including F1. Initial added fixture runs had two setup mistakes (missing store directory, thread claims absent from agents); corrected. Initial related run 79/124 had missing local dependencies and one Claude style-hook assertion; npm ci from the unchanged lockfile followed by the same whole-group rerun passed 124/124. Scratch evidence: /mnt/storage/scratch/tmp/0T6C89; exact commands and limits: /mnt/storage/scratch/mosaic-lead/mvp3/relay-fix-r2-report.md. Local commit only; independent exact-candidate review remains.
+2
View File
@@ -2066,3 +2066,5 @@ are never rewritten or removed; corrections are new entries.
2026-11-04 | Mos, skill integrator | #818 / Gitea #1845 | Integrated exact independently approved ms-ux-improvement candidate02 into source;3hashes/validator/whitespace pass and author histories preserved. Separate commit from MVP; its activation target staysbd8120318. No install, activation, publication or live action.
2026-11-05 | Codex implementation sub-agent | #797 / #1839 MVP 3 relay fixes | Isolated author work on fix/mvp3-relay-797 at 05fdfef9ea1fdddf58c725c04f229ca8559fc054; queue refused linked worktree; local commit only, no live or push authority. Evidence: /mnt/storage/scratch/mosaic-lead/mvp3/relay-fix-r1-report.md.
2026-11-05 | Codex implementation sub-agent | #797 / #1839 MVP 3 relay fixes author handoff | Four bounded fixes; F2 red/green retained; final bus, harness, business and direct-importer gates 2657/2657 with zero failures/cancellations/skips. Local commit only; independent review remains. Full evidence: /mnt/storage/scratch/mosaic-lead/mvp3/relay-fix-r1-report.md.
2026-11-05 | Codex implementation sub-agent | #797 / #1839 relay R2 trusted coordinator context | Chartered local branch fix/mvp3-relay-797-r2 from 29a3cc63238307d8644447c67a0364a6b03dfa36; isolated config-to-bundle-to-broker correction, no push or live authority. Queue refused linked worktree; canonical read returned nothing. Evidence: /mnt/storage/scratch/mosaic-lead/mvp3/relay-fix-r2-report.md.
2026-11-05 | Codex implementation sub-agent | #797 / #1839 relay R2 author handoff | Trusted configured-coordinator discovery with offline arbitrary-key integration; required 321/321, related 124/124, final touched bundle 24/24, corrected reviewer acceptance probes 13/13. Original probe preserved with obsolete equality assertion documented. Local commit only; independent review remains. Evidence: /mnt/storage/scratch/mosaic-lead/mvp3/relay-fix-r2-report.md.
+7
View File
@@ -335,6 +335,13 @@ outside the vocabulary. `launch` is set exactly when `classify(record,
`role.launch` for the launcher, `launch` is null. A launcher should
still ask `classify`, not read `launch` alone.
An assistant also receives `coordinator`: the validated business's `launch.by`
as `instance`, and that instance's configured `identity.name` as `name` (or
null). With no launch block, `coordinator` is null. This routing context is
included in the resolved digest and the generated session prompt; it does not
grant authority. The name is descriptive, not a broker display-name alias;
the assistant addresses messages to the exact instance key.
Errors are `BusinessError` with `exitCode` 2 (invalid) or 4 (a required
file missing). The CLI adds 3 for a system config problem and 4 for usage.
+7
View File
@@ -92,6 +92,13 @@ export function resolveInstance({ system, business, project = null, instance })
credentials: Object.fromEntries(Object.entries(entry.credentials).filter(([kind]) => !isHostKind(kind))),
tracker: entry.tracker,
launch,
// #797 relay R2: an owner-started assistant cannot infer its coordinator
// from launchedBy or running claims. Only the validated business chooses
// this address; it grants no launch authority or messaging exception.
...(definition.name === "assistant" ? { coordinator: business.launch ? {
instance: business.launch.by,
name: business.roles[business.launch.by].identity?.name ?? null,
} : null } : {}),
// REQ-HARN-2: the search-source plug-in the organization file switches on, by name.
webSource: business.plugins?.["search-source"] ?? null,
// The role file's skill names. The bundle resolves each against <dataRoot>/skills-enabled.
+2 -1
View File
@@ -153,7 +153,8 @@ test("the contract passes work to the chief of staff and directs no one", () =>
assert.match(text, /don't direct\s+other agents/);
assert.match(text, /create or assign\s+tasks/);
assert.match(text, /launch\s+sessions/);
assert.match(text, /business's configured chief of staff instance, using\s+its instance key or name/);
assert.match(text, /exact instance key in the generated `Configured coordinator`\s+line under `This session`/);
assert.match(text, /Use that key as send_message\.to for requests\s+and rulings/);
assert.doesNotMatch(text, /addressed to the `chief-of-staff` role/);
// Round 1 F1: rulings go to the chief of staff, never to the role they concern (REQ-ASSIST-1, REQ-ASSIST-2).
assert.match(text, /Relay each ruling the user gives verbatim to the chief\s+of\s+staff,\s+naming\s+whose\s+ruling\s+it\s+is\s+and\s+which\s+role\s+it\s+concerns/);
+3
View File
@@ -268,6 +268,9 @@ function prompt({ contract, resolved, session, tools, untyped, builtins, persona
"",
`- Business: ${resolved.business}. Role instance: ${resolved.instance} (definition ${resolved.definition}). Run: ${session.run}.`,
`- Launched by: ${session.launchedBy}. Harness: ${session.harness}, model ${session.model}.`,
...(resolved.definition === "assistant" ? [resolved.coordinator
? `- Configured coordinator: instance key ${JSON.stringify(resolved.coordinator.instance)}${resolved.coordinator.name ? ` (configured identity name: ${JSON.stringify(resolved.coordinator.name)})` : ""}. Use this exact instance key as send_message.to for business requests and rulings; the broker checks every send.`
: "- Configured coordinator: none. Report the missing business launcher configuration to the user; do not guess a recipient."] : []),
`- Workspace: ${session.workspace}. File tools work inside it only.`,
...checkoutLines(session.checkouts ?? []),
// Row 89 (#1583): the names the harness gives its built-ins, as the manifest lists them.
+76
View File
@@ -6,12 +6,88 @@ import { join } from "node:path";
import { BundleError, buildBundle, sessionModel, SOURCES } from "../src/bundle.mjs";
import { HARNESS, REPO_SKILLS, resolvedFor, scratch } from "./helpers.mjs";
import { decide } from "../src/gate.mjs";
import { resolveInstance, validateBusinessDocument } from "../../business/src/index.mjs";
import { businessDoc, REPO_ROLES, systemFor } from "../../business/tests/helpers.mjs";
import { Store } from "../../bus/src/store.mjs";
import { Broker } from "../../bus/src/broker.mjs";
const UNSLOP_DIR = new URL("../../../tools/unslop-hook/", import.meta.url).pathname;
const sha = (p) => createHash("sha256").update(readFileSync(p)).digest("hex");
const mode = (p) => statSync(p).mode & 0o777;
// #797 relay R2: no running chief or launchedBy hint is needed to discover
// an arbitrary coordinator key. Exercise config -> resolve -> bundle -> bus.
test("an owner-started assistant identifies and can address the configured offline coordinator", (t) => {
const root = scratch(t);
const doc = businessDoc(root);
delete doc.roles.chief;
doc.roles.assistant = { definition: "assistant", vars: { harness: "pi", model: "glm-5.3-flash", thinking: "high" } };
doc.roles.violet = { definition: "chief-of-staff", identity: { name: "Violet Dispatch", email: "[email protected]", gitea: { url: "https://git.example", user: "violet" } } };
doc.roles.opal = { definition: "chief-information-officer" };
const records = [], prompts = [];
for (const coordinator of ["violet", "opal"]) {
const other = coordinator === "violet" ? "opal" : "violet";
doc.roles[coordinator].definition = "chief-of-staff";
doc.roles[other].definition = "chief-information-officer";
doc.launch.by = coordinator;
const business = validateBusinessDocument(doc, join(root, "businesses", "acme.json"), { rolesDir: REPO_ROLES });
const resolve = (instance) => resolveInstance({ system: systemFor(root), business, instance });
const resolved = resolve("assistant");
const expectedName = coordinator === "violet" ? "Violet Dispatch" : null;
assert.deepEqual(resolved.coordinator, { instance: coordinator, name: expectedName });
assert.ok(Object.isFrozen(resolved.coordinator));
assert.equal(resolved.launch, null, "routing context grants no launch authority");
records.push(resolved);
const workspace = join(root, coordinator); mkdirSync(workspace);
const bundle = buildBundle({ dir: join(workspace, "bundle"), resolved,
contract: readFileSync(join(REPO_ROLES, "assistant.md"), "utf8"), harness: HARNESS.pi,
session: { run: "assistant-run", launchedBy: business.human, workspace,
toolSocket: join(workspace, "tools.sock"), turnMarker: join(workspace, "turn.done"),
coordinator: { instance: other } } }); // Untrusted/session input cannot override the config.
const prompt = readFileSync(bundle.files.prompt, "utf8");
prompts.push(prompt);
assert.match(prompt, /Launched by: jason\./);
assert.ok(prompt.includes(`Configured coordinator: instance key "${coordinator}"`));
assert.ok(!prompt.includes(`Configured coordinator: instance key "${other}"`));
if (expectedName) assert.ok(prompt.includes(`configured identity name: "${expectedName}"`));
assert.equal(bundle.manifest.resolvedDigest, resolved.digest);
assert.equal(bundle.manifest.files["prompt.md"], sha(bundle.files.prompt));
const storeDir = join(workspace, "store"); mkdirSync(storeDir, { mode: 0o700 });
const store = new Store(storeDir);
t.after(() => store.close());
const broker = new Broker({ store, businesses: { acme: { ...business,
roles: Object.fromEntries(Object.entries(business.roles).map(([key, entry]) =>
[key, { ...entry, authority: resolve(key).limits.authority }])) } } });
const owner = broker.bindHuman({ business: "acme", human: business.human, via: "cli", outsideAgent: true });
const call = (cap, verb, args = {}) => broker.request(cap, { verb, args });
const project = call(owner, "project.create", { name: "Work" }).id;
const thread = call(owner, "thread.create", { project, name: "Origin" }).id;
const assistant = broker.bindLaunch({ business: "acme", role: "assistant", run: "assistant-run", harness: "pi", thread });
call(assistant, "role.claim");
assert.deepEqual(call(assistant, "agents"), [], "no coordinator or other non-thread role is running");
assert.equal(store.get("SELECT count(*) n FROM role_claims WHERE role=?", coordinator).n, 0, "the coordinator has never claimed a run");
const source = call(owner, "thread.send", { thread, body: "Build a timer" });
const sent = call(assistant, "message.send", { to: resolved.coordinator.instance, body: "Build a timer", in_reply_to: source.id });
assert.equal(store.get("SELECT to_role FROM messages WHERE id=?", sent.id).to_role, coordinator);
assert.equal(sent.request, source.request);
assert.throws(() => call(assistant, "message.send", { to: other, body: "Bypass", in_reply_to: source.id }), { code: "message-recipient-refused" });
assert.throws(() => call(assistant, "message.send", { to: "chief-of-staff", body: "Guess" }), { code: "unknown-role" });
}
assert.notDeepEqual(records[0], records[1]);
assert.notEqual(records[0].digest, records[1].digest);
assert.notEqual(prompts[0], prompts[1]);
});
test("an assistant without a configured launcher reports missing coordinator context", (t) => {
const resolved = resolvedFor(t, "assistant", (doc) => { delete doc.launch; doc.roles.assistant = { definition: "assistant" }; });
assert.equal(resolved.coordinator, null);
const b = build(t, resolved);
assert.match(readFileSync(b.files.prompt, "utf8"), /Configured coordinator: none\. Report the missing business launcher configuration/);
});
function build(t, resolved, extra = {}) {
const dir = scratch(t);
const workspace = join(dir, "ws");
+5 -3
View File
@@ -18,9 +18,11 @@ sessions.
- Talk with the user. Answer what they ask, say plainly what you don't
know and keep their requests in their own words.
- Send each request for the business to the chief of staff as a message,
addressed to the business's configured chief of staff instance, using
its instance key or name. Keep the user's words as they gave them, and
name the request each message carries.
addressed to the exact instance key in the generated `Configured coordinator`
line under `This session`. Use that key as send_message.to for requests
and rulings, even when the chief is not running. If no coordinator is
configured, report that blocker to the user. Keep the user's words as they
gave them, and name the request each message carries.
- Relay each ruling the user gives verbatim to the chief of staff,
naming whose ruling it is and which role it concerns. Don't summarize
it, paraphrase it or add to it. Don't send it to that role yourself.