mesh/delivery delivered
mesh/check checking 5a7076a6a25e on f836c021e14f
The runtime gives a watch's current values 10 s and waits for each to be taken; a forge write per key made ~200 keys outlast it at every attempt, so after node-tools restarted on novox at 23:25:58 the watch never held and no verdict reached mesh/check. Writes now run in the background, a few at a time, each key's in revision order.
178 lines
11 KiB
TypeScript
178 lines
11 KiB
TypeScript
// **mesh/check is written from the checker's owed state, read by a watch** (ADR 0521; R4e round 2 finding R2-1; finding K1
|
|
// before it). No tool writes mesh/check, since a tool is told no caller and node-tools invokes every tool. Nor does an event:
|
|
// nothing in the delivery plan orders this module before the forge bridge, and a durable consumer whose filters change keeps
|
|
// its deliver policy, so an event said before this module consumed it was lost. A watch of the checker's state hands over
|
|
// the latest value of every key when it starts, whenever that is.
|
|
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
|
|
const sha = "0123456789abcdef0123456789abcdef01234567";
|
|
const key = (s = sha, repo = "novox/mesh-sdk", n = 12) => `${repo}.${n}.${s}.status=mesh/check`;
|
|
const owed = (over: Record<string, unknown> = {}) => ({ v: 1, act: "status", context: "mesh/check", state: "success",
|
|
text: "pass 0123456789ab on aaaaaaaaaaaa", target: "https://view.example/checks/g.1", ...over });
|
|
const put = (k: string, value: unknown, revision: number, current = false) =>
|
|
({ state: "mesh-delivery-checker.owed", key: k, op: "put" as const, value, revision, current });
|
|
|
|
function forge() {
|
|
const sent: string[] = [];
|
|
let failing = 0;
|
|
return {
|
|
sent,
|
|
fail: (n: number) => { failing = n; },
|
|
setCommitStatus: async (o: string, r: string, s: string, st: any) => {
|
|
if (failing > 0) { failing--; throw new Error("Gitea API /repos/x/statuses: 502 bad gateway"); }
|
|
sent.push(`${o}/${r}@${s.slice(0, 8)} ${st.context} ${st.state} ${st.description}${st.target_url ? " " + st.target_url : ""}`);
|
|
},
|
|
};
|
|
}
|
|
const noSleep = async () => {};
|
|
|
|
test("the checker's owed is what this module reads, and it consumes no check.status", async () => {
|
|
const { CHECKER_OWED } = await import("../check.ts");
|
|
assert.equal(CHECKER_OWED, "mesh-delivery-checker.owed");
|
|
const manifest = JSON.parse(readFileSync(new URL("../module.json", import.meta.url), "utf8"));
|
|
assert.ok(manifest.reads.includes(CHECKER_OWED), "gitea's manifest reads the checker's owed");
|
|
assert.ok(!manifest.consumes.some((c: string) => c.includes("check.status")), "no check.status is consumed");
|
|
});
|
|
|
|
test("an owed mesh/check writes the status on its head: its state, its line cut and its link", async () => {
|
|
const { CheckStatuses } = await import("../check.ts");
|
|
const f = forge();
|
|
const checks = new CheckStatuses(f, () => {}, noSleep);
|
|
assert.equal(await checks.apply(put(key(), owed(), 7, true)), "written");
|
|
const other = sha.replace(/0/g, "f");
|
|
assert.equal(await checks.apply(put(key(other, "novox/my=2erepo"), owed({ state: "pending", text: "y".repeat(300), target: "javascript:x" }), 8)), "written");
|
|
assert.equal(f.sent[0], "novox/mesh-sdk@01234567 mesh/check success pass 0123456789ab on aaaaaaaaaaaa https://view.example/checks/g.1");
|
|
assert.ok(f.sent[1].startsWith("novox/my.repo@f1234567 mesh/check pending yyyy"), f.sent[1]);
|
|
assert.ok(f.sent[1].length < 200, "the line is cut as every status's is");
|
|
assert.ok(!f.sent[1].includes("javascript"), "a link that is no web page is not written");
|
|
});
|
|
|
|
test("a key or value that is no owed mesh/check, and a delete, write nothing", async () => {
|
|
const { CheckStatuses } = await import("../check.ts");
|
|
const f = forge();
|
|
const checks = new CheckStatuses(f, () => {}, noSleep);
|
|
const cases = [
|
|
put(key(sha.slice(0, 12)), owed(), 1), put(`novox/mesh-sdk.12.${sha}.status=mesh/merge-gate`, owed(), 1),
|
|
put(`novox/mesh-sdk.12.${sha}.view`, owed(), 1), put(`nokey`, owed(), 1), put(`../x/y.12.${sha}.status=mesh/check`, owed(), 1),
|
|
put(key(), owed({ context: "mesh/delivery" }), 1), put(key(), owed({ act: "view" }), 1), put(key(), owed({ state: "green" }), 1),
|
|
put(key(), owed({ v: 2 }), 1), put(key(), null, 1), put(key(), "text", 1), put(key(), owed(), -1),
|
|
{ state: "mesh-delivery-checker.owed", key: key(), op: "delete" as const, revision: 2, current: false },
|
|
];
|
|
for (const c of cases) assert.equal(await checks.apply(c as any), "dropped", JSON.stringify(c));
|
|
assert.deepEqual(f.sent, []);
|
|
});
|
|
|
|
test("a revision older than one written on the key is dropped; the same one is written again", async () => {
|
|
const { CheckStatuses } = await import("../check.ts");
|
|
const f = forge();
|
|
const checks = new CheckStatuses(f, () => {}, noSleep);
|
|
await checks.apply(put(key(), owed({ state: "success" }), 10));
|
|
assert.equal(await checks.apply(put(key(), owed({ state: "pending" }), 9)), "dropped", "a stale pending never hides the verdict");
|
|
assert.equal(await checks.apply(put(key(), owed({ state: "success" }), 10)), "written");
|
|
assert.equal(await checks.apply(put(key(sha.replace(/1/g, "2")), owed({ state: "pending" }), 3)), "written", "another key is its own");
|
|
assert.equal(await checks.apply(put(key(), owed({ state: "pending" }), 11)), "written");
|
|
assert.deepEqual(f.sent.map((s) => s.split(" ").slice(0, 3).join(" ")), ["novox/mesh-sdk@01234567 mesh/check success",
|
|
"novox/mesh-sdk@01234567 mesh/check success", "novox/mesh-sdk@02234567 mesh/check pending", "novox/mesh-sdk@01234567 mesh/check pending"]);
|
|
});
|
|
|
|
test("a forge that refuses is asked again until it writes, unless a newer revision of the key came meanwhile", async () => {
|
|
const { CheckStatuses } = await import("../check.ts");
|
|
const f = forge();
|
|
const said: string[] = [];
|
|
const waits: number[] = [];
|
|
const checks = new CheckStatuses(f, (l) => said.push(l), async (ms) => { waits.push(ms); });
|
|
f.fail(2);
|
|
await checks.take(put(key(), owed({ state: "success" }), 5));
|
|
await checks.settled();
|
|
assert.deepEqual(f.sent.map((s) => s.split(" ")[2]), ["success"], "written on the third ask");
|
|
assert.deepEqual(waits, [2_000, 5_000]);
|
|
assert.match(said[0], /502.*asked again/);
|
|
// A refusal whose key moved on meanwhile is not asked again: the newer revision is written, the older never after it.
|
|
const g = forge();
|
|
let release: () => void = () => {};
|
|
const gate = new Promise<void>((r) => { release = r; });
|
|
const later = new CheckStatuses(g, () => {}, () => gate);
|
|
g.fail(1);
|
|
await later.take(put(key(), owed({ state: "pending" }), 6));
|
|
await later.take(put(key(), owed({ state: "success" }), 7));
|
|
release();
|
|
await later.settled();
|
|
assert.deepEqual(g.sent.map((s) => s.split(" ")[2]), ["success"]);
|
|
});
|
|
|
|
test("a watch refused at first is asked again, said once, and once granted writes the latest revision of each key", async () => {
|
|
const { CheckStatuses, watchOwed } = await import("../check.ts");
|
|
const f = forge();
|
|
const said: string[] = [];
|
|
const checks = new CheckStatuses(f, () => {}, noSleep);
|
|
// The checker's bucket as the bus keeps it: two revisions of one key written while the read was refused.
|
|
const kept = new Map<string, { value: unknown; revision: number }>();
|
|
kept.set(key(), { value: owed({ state: "pending" }), revision: 3 });
|
|
kept.set(key(), { value: owed({ state: "success" }), revision: 4 });
|
|
let asked = 0;
|
|
const watch = async (handler: (c: any) => Promise<void>) => {
|
|
asked++;
|
|
if (asked < 3) throw new Error("gitea keeps and reads no state called \"mesh-delivery-checker.owed\"");
|
|
for (const [k, e] of kept) await handler(put(k, e.value, e.revision, true));
|
|
};
|
|
await watchOwed(watch, checks, noSleep, (l) => said.push(l));
|
|
await checks.settled();
|
|
assert.equal(asked, 3);
|
|
assert.deepEqual(f.sent.map((s) => s.split(" ")[2]), ["success"], "only the latest revision is written");
|
|
assert.equal(said.filter((l) => /could not be bound/.test(l)).length, 1, `said once: ${said.join(" | ")}`);
|
|
assert.ok(said.some((l) => /bound after 3 attempts/.test(l)), said.join(" | "));
|
|
});
|
|
|
|
test("no tool writes mesh/check: gitea_check_status is gone and gitea_commit_status refuses it", async () => {
|
|
const delivery = await import("../delivery.ts");
|
|
assert.equal((delivery as Record<string, unknown>).checkStatusTool, undefined, "delivery.ts serves no gitea_check_status");
|
|
assert.throws(() => delivery.deliveryStatus("mesh/check", "success", "x"), /mesh-delivery-checker\.owed/);
|
|
const index = readFileSync(new URL("../index.ts", import.meta.url), "utf8");
|
|
assert.ok(!/gitea_check_status|checkStatusTool/.test(index), "index.ts serves no gitea_check_status");
|
|
});
|
|
|
|
test("the watch's current values are taken without waiting on the forge, so a slow forge never times the watch out (issue 1726)", async () => {
|
|
// The tool runtime hands a watch's current values one at a time and waits for each to be taken; it gives the whole set
|
|
// 10 s (mesh-tools StateTimeout) and otherwise ends the watch. On 2026-10-23 the owed held ~200 keys, each written to the
|
|
// forge before the next was handed over: the set took longer than 10 s, the watch ended at every attempt, and no
|
|
// verdict reached the forge's mesh/check again.
|
|
const { CheckStatuses, watchOwed } = await import("../check.ts");
|
|
const sent: string[] = [];
|
|
let release: () => void = () => {};
|
|
const slow = new Promise<void>((r) => { release = r; });
|
|
const f = { setCommitStatus: async (_o: string, _r: string, s: string, st: any) => { await slow; sent.push(`${s.slice(0, 4)} ${st.state}`); } };
|
|
const checks = new CheckStatuses(f, () => {}, noSleep);
|
|
const keys = Array.from({ length: 200 }, (_, i) => key(i.toString(16).padStart(4, "0") + sha.slice(4), "novox/mesh-sdk", i + 1));
|
|
let handedOver = 0;
|
|
let attempts = 0;
|
|
const watch = async (handler: (c: any) => Promise<void>) => {
|
|
if (++attempts > 1) return; // a second attempt is not what this test waits for: the first must hold
|
|
// The runtime's bound on the current values: the forge has answered none of them yet.
|
|
const timedOut = new Promise<"timeout">((r) => setTimeout(() => r("timeout"), 200));
|
|
const delivered = (async () => { for (const [i, k] of keys.entries()) { await handler(put(k, owed(), i + 1, true)); handedOver++; } return "delivered" as const; })();
|
|
if (await Promise.race([delivered, timedOut]) === "timeout") throw new Error("the current values of mesh-delivery-checker.owed did not arrive in 10s");
|
|
};
|
|
const said: string[] = [];
|
|
await watchOwed(watch, checks, noSleep, (l) => said.push(l));
|
|
assert.equal(handedOver, 200, "every current value was taken before the forge answered");
|
|
assert.ok(!said.some((l) => /could not be bound/.test(l)), said.join(" | "));
|
|
assert.equal(sent.length, 0, "nothing is written before the forge answers");
|
|
release();
|
|
await checks.settled();
|
|
assert.equal(sent.length, 200, "every owed status is written once the forge answers");
|
|
});
|
|
|
|
test("the writes a watch's start hands over go to the forge a few at a time, never all at once (issue 1726)", async () => {
|
|
const { CheckStatuses, WRITES_AT_ONCE } = await import("../check.ts");
|
|
let running = 0, most = 0, done = 0;
|
|
const f = { setCommitStatus: async () => { running++; most = Math.max(most, running); await new Promise((r) => setTimeout(r, 1)); running--; done++; } };
|
|
const checks = new CheckStatuses(f, () => {}, noSleep);
|
|
for (let i = 0; i < 50; i++) await checks.take(put(key(i.toString(16).padStart(4, "0") + sha.slice(4), "novox/mesh-sdk", i + 1), owed(), i + 1, true));
|
|
await checks.settled();
|
|
assert.equal(done, 50);
|
|
assert.equal(most, WRITES_AT_ONCE);
|
|
});
|