Files
reverse-engineering-anything/tests/boundary/process/processSettlementDeadline.test.ts
T
Saim Shafique 7724edbdd3 fix(process): report single empty settlement observation as unverifiable (#2232)
observeSettlement classified a group as alive_at_deadline when the settlement
budget expired after one empty observation, though no live member was ever
seen. Track observed liveness and return unverifiable when the deadline ends
observation with only empty rounds. The two-consecutive-empty rule for
quiesced is unchanged, and the cleanup_outcome projection for non-quiesced
settlements stays cleaned.

Fixes #2170.
2026-10-13 00:15:12 +08:00

74 lines
2.4 KiB
TypeScript

import { spawn } from "node:child_process";
import { describe, expect, it } from "vitest";
import { observeSettlement } from "../../../src/process/capture/ProcessCaptureLifecycle.js";
import { observeOwnedProcessGroups } from "../../../src/process/ProcessOwnershipObservation.js";
/** Process group id that cannot exist on any supported host. */
const ABSENT_GROUP_ID = 4_294_967_295;
const observeGroup = async (groupId: number) =>
observeOwnedProcessGroups("settlement-deadline-probe", [groupId]);
describe("settlement deadline classification", () => {
it("does not report a single empty observation as alive_at_deadline", async () => {
expect(
(await observeGroup(ABSENT_GROUP_ID)).get(ABSENT_GROUP_ID)?.state,
).toBe("empty");
const settlement = await observeSettlement(
"settlement-single-empty",
[ABSENT_GROUP_ID],
0,
() => undefined,
"linux",
);
expect(settlement.state).toBe("unverifiable");
});
it("still reports observed liveness as alive_at_deadline", async () => {
const runId = "settlement-live-group";
// A detached child leads its own process group and carries the run token,
// so the group observes as a genuinely owned live member.
const child = spawn("sleep", ["30"], {
detached: true,
stdio: "ignore",
env: { ...process.env, REA_PROCESS_RUN_ID: runId },
});
child.unref();
try {
// Wait until the child is actually listed before asserting on it.
const started = Date.now();
while (
(await observeOwnedProcessGroups(runId, [child.pid!])).get(child.pid!)
?.state !== "alive"
) {
if (Date.now() - started > 5_000)
throw new Error("live fixture group never observed as alive");
await new Promise((resolve) => setTimeout(resolve, 50));
}
const settlement = await observeSettlement(
runId,
[child.pid!],
0,
() => undefined,
"linux",
);
expect(settlement.state).toBe("alive_at_deadline");
} finally {
child.kill("SIGKILL");
}
});
it("still reports two consecutive empty observations as quiesced", async () => {
const settlement = await observeSettlement(
"settlement-two-empty",
[ABSENT_GROUP_ID],
1_000,
() => undefined,
"linux",
);
expect(settlement.state).toBe("quiesced");
});
});