import assert from "node:assert/strict"; import { test } from "node:test"; import { ViewFollower, findingKey, unansweredFinding, viewTools, type ViewAnswer, type ViewChange, type ViewEvent } from "../views.ts"; // ADR 0615: the module asks the indexer's read tool once, then keeps its picture of `modules` from the indexer's views // events; a gap asks once more; an owner that is down is asked again and never read instead. const made = "2026-11-04T12:00:00Z"; const answer = (revision: number, values: Record): ViewAnswer => ({ v: 1, owner: "o", state: "modules", revision, created: made, values }); const ev = (revision: number, key: string, value?: unknown, extra: Partial = {}): ViewEvent => ({ v: 1, owner: "o", state: "modules", key, revision, created: made, value, deleted: value === undefined, ...extra }); test("a follower takes the first view, then the events, and asks again only on a gap", async () => { const changes: ViewChange[] = []; const said: string[] = []; let asks = 0; let down = 2; const raised: string[][] = []; const f = new ViewFollower({ owner: "o", state: "modules", tool: "o.read", ask: async () => { if (down-- > 0) throw new Error("no responders"); asks++; return answer(9, { a: { repository: "novox/a" }, b: { repository: "novox/b" } }); }, take: (c) => { changes.push(c); }, raise: (_a, e) => { raised.push(["raised", e]); }, clear: () => { raised.push(["cleared", ""]); }, say: (l) => said.push(l), sleep: async () => {}, now: (() => { let t = 0; return () => (t += 200_000); })() }); await f.start(); assert.equal(f.ready, true); assert.equal(f.values.size, 2); assert.deepEqual(raised.map((r) => r.slice(0, 2)), [["raised", "no responders"], ["cleared", ""]]); assert.ok(said.some((l) => l.includes("no first view of o's modules") && l.includes("o.read")), said.join("|")); await f.hear(ev(8, "a", { repository: "old" })); // already in the picture await f.hear(ev(10, "c", { repository: "novox/c" })); await f.hear(ev(11, "a")); // deleted assert.deepEqual([f.revision, f.values.has("a"), f.values.has("c"), asks], [11, false, true, 1]); assert.deepEqual(changes.slice(-2).map((c) => [c.key, c.op]), [["c", "put"], ["a", "delete"]]); await f.hear(ev(13, "d", { repository: "x" })); // revision 12 missed: a gap assert.equal(asks, 2); await f.hear(ev(1, "e", { repository: "x" }, { created: "2026-11-04T13:00:00Z" })); // the state made again: a gap assert.equal(asks, 3); await f.hear(ev(10, "f", undefined, { gap: true })); // the next revision, too large to carry: a gap assert.equal(asks, 4); await f.hear({ ...ev(10, "g", { repository: "x" }), state: "other" }); // another state assert.equal(f.values.has("g"), false); }); test("the reader's two tools say where the first view stands and ask it again by hand", async () => { let asks = 0; const acts: Record[] = []; const follower = new ViewFollower({ owner: "o", state: "modules", tool: "o.read", ask: async () => { asks++; return answer(5, { a: 1 }); }, take: () => {}, sleep: async () => {} }); const [first, again] = viewTools(() => ({ follower, owner: "o", tool: "o.read", state: "modules" }), async (act) => { acts.push(act); }); assert.deepEqual(await first.run({}), { views: [{ owner: "o", tool: "o.read", state: "modules", revision: 0, created: "", keys: 0, answered: false, asks: 0, "by-hand": 0 }] }); const after = (await again.run({})) as { views: { revision: number; "by-hand": number; asks: number }[] }; assert.deepEqual([after.views[0].revision, after.views[0]["by-hand"], asks, acts.length], [5, 1, 1, 1]); await assert.rejects(viewTools(() => ({ follower, owner: "o", tool: "o.read", state: "modules" }), async () => { throw new Error("no holder"); })[1].run({}), /not recorded/); assert.deepEqual(await viewTools(() => undefined, async () => {})[0].run({}), { views: [] }); }); test("the finding of a first view unanswered is the one mesh-sdk writes: key, kind, subject and the words", () => { const f = unansweredFinding("gitea", "mesh-delivery-indexer", "modules", "mesh-delivery-indexer.indexer_read_modules", new Date("2026-11-04T12:00:00Z"), "no responders", new Date("2026-11-04T12:03:00Z")); assert.equal(f.key, "module.gitea.mesh-delivery-indexer.modules.first-view-unanswered"); assert.equal(findingKey("module", "a.b", "k"), "module.a.b.k"); assert.equal(f.value.severity, "warning"); assert.match(String(f.value.summary), /gitea has no first view of mesh-delivery-indexer's modules: .* \(no responders\)/); });