docs: lead decision 72, the S4 follow-up and cohort briefs, and the trackers boot test

Decision 72 rules on F2 (five definite refusals stop a DM; unknown
outcomes keep retrying) and J4 (type-check confirmed journal lines),
and opens two rows: the S4 follow-up for Rocko and the K1, K3 and K10
cohort failures for Darkwing. The trackers boot test from the row 39
gate is kept under agents/sage/work/s4-follow-up/ until the follow-up
moves it into packages/cli/tests/.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-09 07:54:52 -05:00
co-authored by Claude Opus 5.5
parent e580ee2239
commit ec2a2c6773
3 changed files with 309 additions and 0 deletions
@@ -0,0 +1,66 @@
// Sage's row 39 gate check, not part of the candidate: the S4 host boots the
// S3 adapter through the real process.mjs when bootConfig emits trackers.
import { test } from "node:test";
import assert from "node:assert/strict";
import { chmodSync, mkdirSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { Client } from "../../bus/src/client.mjs";
import { bootConfig, loadSystem } from "../src/config.mjs";
import { startHost, startTimeOf } from "../src/host.mjs";
import { writeJson } from "../../business/tests/helpers.mjs";
import { FakeVikunja } from "../../tasks/src/fake.mjs";
import { SCOPES } from "../../tasks/tests/world.mjs";
import { fixture, tmp } from "./helpers.mjs";
test("bootConfig trackers reach the S3 adapter in the real broker child, which goes ready against a fake Vikunja", async (t) => {
const root = tmp(t);
const fake = new FakeVikunja();
const srv = await fake.listen();
t.after(() => srv.close());
const owner = fake.user("svc-acme");
const bots = {};
for (const r of ["sync", "pm", "cto", "coder", "reviewer"]) bots[r] = fake.user(`bot-acme-${r}`, { owner });
const project = fake.project("Acme", owner);
for (const r of ["pm", "cto", "coder", "reviewer"]) fake.share(project, bots[r], 1);
fake.share(project, bots.sync, 0);
fake.install(project);
const f = fixture(root, "acme", (doc) => {
doc.vars["tracker.baseUrl"] = srv.url;
doc.tracker.sync.botId = bots.sync;
for (const r of Object.keys(doc.roles)) doc.roles[r].tracker.botId = bots[r];
return doc;
});
const put = (file, token) => {
writeFileSync(file, token + "\n");
chmodSync(file, 0o600);
};
put(f.doc.tracker.sync.credentials.vikunja.file, fake.token(bots.sync, SCOPES.sync));
for (const r of Object.keys(f.doc.roles)) put(f.doc.roles[r].credentials.vikunja.file, fake.token(bots[r], r === "pm" ? SCOPES.pm : SCOPES.worker));
writeJson(join(root, "project", ".mosaic", "project.json"), { projectVersion: 1, id: "stack", vars: { "tracker.project": project } });
mkdirSync(f.dataRoot, { recursive: true, mode: 0o700 });
const boot = bootConfig({ system: loadSystem({ env: f.env }), businessId: "acme", env: f.env });
assert.deepEqual(boot.trackers, { acme: { baseUrl: srv.url, project, pollSeconds: 60, reconcileMinutes: 60 } });
const host = await startHost({ boot, business: "acme", log: () => {} });
t.after(() => host.close(0));
const launch = await host.bindLaunch({ business: "acme", role: "pm", run: "pm-run", harness: "pi", pid: process.pid, startTime: startTimeOf(process.pid) });
const pm = new Client({ path: host.path, cap: launch.cap });
await pm.call("role.claim");
let code;
const end = Date.now() + 15000;
do {
code = await pm.call("task.close", {}).then(() => "ok", (e) => e.code);
if (code !== "tracker-starting") break;
await new Promise((r) => setTimeout(r, 100));
} while (Date.now() < end);
console.log(`task.close {} answered: ${code}; fake saw ${fake.requests.length} requests, first ${fake.requests.slice(0, 3).map((r) => `${r.method} ${r.path} ${r.status}`).join(", ")}`);
assert.ok(fake.requests.some((r) => r.path === "/info"), "the adapter called the fake");
assert.doesNotMatch(code, /^(tracker-|credential-|scope-too-broad)/, "the adapter is ready, so the verb fails on its own arguments");
const before = fake.requests.length;
const missing = await pm.call("task.close", { task_ref: `vikunja:${project}/999`, verdict: "gate check" }).then(() => "ok", (e) => e.code);
console.log(`task.close on a missing task answered: ${missing}; it made ${fake.requests.slice(before).map((r) => `${r.method} ${r.path} ${r.status}`).join(", ")}`);
assert.ok(fake.requests.length > before, "a well-formed verb reached Vikunja through the adapter");
assert.equal(await host.close(0), 0);
});