feat(bus): the bus and the broker core (row 37, S2, rocko)

Rocko's round 2 candidate, approved by Darkwing (#1519 comment 26757).
build.patch 40d7e838, manifest 61519059, 24 files under packages/bus,
schema v3b (179ffe35, lead decision 60). Integration gate in a git
worktree of 942dca9e (S1 in the tree) plus the patch: bus 43/43 and
business 60/60 on Node 24 and 26, every package test and every
scripts/test-*.sh green, test-task 98/98 with the live-provider cases.
Rulings from lead decisions 62 and 63: the human proof is cooperative in
slice 1, and a self-raised cross-role decision routes to the human.
Single-use gated approvals follow in row 43.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-05 17:15:53 -05:00
co-authored by Claude Opus 5.5
parent 942dca9ea8
commit 38828a2cb3
24 changed files with 3646 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { Store } from './store.mjs';
import { Broker, BusError } from './broker.mjs';
import { Credentials } from './credentials.mjs';
import { serve } from './server.mjs';
import { verifyHuman } from './human.mjs';
// Trusted host API. S1 supplies resolved definitions, S6 supplies launch records.
// Neither a business-file writer nor a socket-accessible configuration endpoint.
export async function startBroker({ dataRoot, businesses, launches = [], readers = [], repoRoots = [] }) {
let store, credentials, server;
try {
const references = {};
for (const [business, b] of Object.entries(businesses)) {
for (const [role, r] of Object.entries(b.roles))
if (r.credentials) references[business + '/' + role] = r.credentials;
if (b.tracker?.sync?.credentials) references[business + '/@sync'] = b.tracker.sync.credentials;
}
const protectedRoots = [
fileURLToPath(new URL('../../../', import.meta.url)),
...repoRoots,
...Object.values(businesses).flatMap((b) => Object.values(b.projects ?? {}).map((p) => p.root)),
];
credentials = new Credentials({ references, repoRoots: protectedRoots, dataRoot });
store = new Store(dataRoot);
const broker = new Broker({ store, businesses, secretCheck: (value) => credentials.assertClean(value) });
// Process identities must be supplied for every managed run when using the human transport.
const launchRecords = [];
function bindLaunch(r) {
if (
!Number.isSafeInteger(r.pid) ||
r.pid < 2 ||
typeof r.startTime !== 'string' ||
!/^\d+$/.test(r.startTime)
)
throw new BusError('invalid-launch-process');
const cap = broker.bindLaunch(r);
launchRecords.push({ ...r });
return { business: r.business, run: r.run, cap };
}
const bound = launches.map(bindLaunch);
const readCaps = readers.map((business) => ({ business, cap: broker.bindReader({ business }) }));
const path = join(store.directory, 'broker.sock');
server = await serve({
broker,
path,
authenticateHuman: (proof) => {
const { business } = verifyHuman(proof, {
cliPath: fileURLToPath(new URL('./human-cli.mjs', import.meta.url)),
launches: launchRecords,
});
const human = businesses[business]?.human;
if (!human) throw new BusError('unknown-business');
return broker.bindHuman({ business, human, via: 'cli', outsideAgent: true });
},
});
return {
broker,
credentials,
path,
bindLaunch,
launches: bound,
readers: readCaps,
async close() {
await server.close();
store.close();
credentials.close();
},
};
} catch (e) {
await server?.close();
store?.close();
credentials?.close();
throw e;
}
}