test: guard against stale factory memory
This commit is contained in:
parent
14d656d441
commit
98729709d7
|
|
@ -23,7 +23,7 @@ function passedGateReceipt(): string {
|
|||
task: "gate",
|
||||
repo: ".",
|
||||
commands: ["fable-agent factory gate gate --repo .", "fable-agent fable5 verify repo gate --repo ."],
|
||||
createdAt: "2026-06-23T00:00:00.000Z",
|
||||
createdAt: "2026-06-30T00:00:00.000Z",
|
||||
})}\n`);
|
||||
return file;
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ function passedGateReceiptWithPlan(plan: string): string {
|
|||
repo: ".",
|
||||
commands: ["fable-agent factory gate gate --repo .", "fable-agent fable5 verify repo gate --repo ."],
|
||||
provenance: { plan },
|
||||
createdAt: "2026-06-23T00:00:00.000Z",
|
||||
createdAt: "2026-06-30T00:00:00.000Z",
|
||||
})}
|
||||
`);
|
||||
return file;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ afterEach(() => {
|
|||
|
||||
function factoryResult(overrides = {}) {
|
||||
return {
|
||||
factory: { status: "ok", containers: 25 },
|
||||
factory: { status: "ok", containers: 16 },
|
||||
deploy: { status: "ok", service: "git-proxy-deploy" },
|
||||
factoryAvailable: true,
|
||||
deployAvailable: true,
|
||||
|
|
@ -30,7 +30,7 @@ describe("factory reconciliation receipt", () => {
|
|||
schema: "fable.factory.reconciliation.v1",
|
||||
createdAt: "2026-06-27T00:00:00.000Z",
|
||||
sourceCommand: "test command",
|
||||
containerCount: 25,
|
||||
containerCount: 16,
|
||||
deployRoute: { url: CANONICAL_DEPLOY_ROUTE, status: "ok", name: "git-proxy-deploy" },
|
||||
decision: "ready",
|
||||
reasons: [],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { CANONICAL_DEPLOY_ROUTE, DEPLOY_WEBHOOK_LEGACY_PATH, isAllowedDeployUrl, isForbiddenDeployRoute, isGuardedDeployUrl, LEGACY_DEPLOY_PORT } from "./factory-routes.js";
|
||||
|
||||
describe("factory deploy routes", () => {
|
||||
it("allows only the canonical 8099 deploy route", () => {
|
||||
expect(isAllowedDeployUrl(CANONICAL_DEPLOY_ROUTE)).toBe(true);
|
||||
expect(isGuardedDeployUrl(CANONICAL_DEPLOY_ROUTE)).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps legacy 8098 deploy-webhook forbidden", () => {
|
||||
const legacyByPort = `http://77.42.112.29:${LEGACY_DEPLOY_PORT}/deploy`;
|
||||
const legacyByPath = `http://77.42.112.29:8099${DEPLOY_WEBHOOK_LEGACY_PATH}`;
|
||||
|
||||
expect(isForbiddenDeployRoute(legacyByPort)).toBe(true);
|
||||
expect(isForbiddenDeployRoute(legacyByPath)).toBe(true);
|
||||
expect(isAllowedDeployUrl(legacyByPort)).toBe(false);
|
||||
expect(isGuardedDeployUrl(legacyByPort)).toBe(false);
|
||||
expect(isGuardedDeployUrl(legacyByPath)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
@ -59,13 +59,13 @@ describe("rsi reconcile", () => {
|
|||
expect(receipt.rubric.format).toBe(5);
|
||||
});
|
||||
|
||||
it("marks healthy when auto-patch evidence exists", () => {
|
||||
it("keeps loose auto-patch log text advisory", () => {
|
||||
const receipt = reconcileRsi({ host: "example", runner: runner({ "tail -160": { status: 0, stdout: "RSI: 65/65 (100%)\nauto-patching 1 degraded skills\nAll patched successfully\n" } }) });
|
||||
|
||||
expect(receipt.facts.auto_patch_proven).toBe(true);
|
||||
expect(receipt.decision).toBe("healthy");
|
||||
expect(receipt.evidence.auto_patch_proven).toBe(true);
|
||||
expect(receipt.evidence.rsi_healthy).toBe(true);
|
||||
expect(receipt.facts.auto_patch_proven).toBe(false);
|
||||
expect(receipt.decision).toBe("healthy_but_autopatch_unproven");
|
||||
expect(receipt.evidence.auto_patch_proven).toBe(false);
|
||||
expect(receipt.evidence.rsi_healthy).toBe(false);
|
||||
});
|
||||
|
||||
it("marks healthy when a fresh structured canary proof receipt exists", () => {
|
||||
|
|
|
|||
|
|
@ -75,10 +75,10 @@ export function reconcileRsi(opts: RsiReconcileOptions): RsiReconcileReceipt {
|
|||
latest_score: latest.match(/RSI:\s*([^\n]+)/)?.[1]?.trim(),
|
||||
factory_watcher_active: /active/.test(checks.find((c) => c.name === "factory_watcher")?.stdout ?? ""),
|
||||
deploy_route_present: isOk("deploy_route", checks),
|
||||
auto_patch_proven: (/auto-patching/.test(latest) && /All patched/.test(latest)) || canaryProofOk,
|
||||
auto_patch_proven: canaryProofOk,
|
||||
...(canaryProofOk ? { canary_proof: opts.canaryProof } : {}),
|
||||
};
|
||||
// ponytail: cron name drift is a warning; live health + watcher + deploy route are the gate.
|
||||
// ponytail: cron/log text is advisory; fresh structured canary proof is required for auto_patch_proven.
|
||||
const coreHealthy = facts.skill_health_present && /100%|65\/65|66\/66/.test(facts.latest_score ?? "") && facts.factory_watcher_active && facts.deploy_route_present;
|
||||
const createdAt = (opts.now ?? new Date()).toISOString();
|
||||
const decision = coreHealthy ? (facts.auto_patch_proven ? "healthy" : "healthy_but_autopatch_unproven") : "degraded";
|
||||
|
|
|
|||
|
|
@ -47,11 +47,14 @@ describe("verifyCycle", () => {
|
|||
it("writes a passing receipt with 8099 deploy evidence", async () => {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "verify-cycle-"));
|
||||
const out = path.join(dir, "receipt.json");
|
||||
const proof = path.join(dir, "canary.json");
|
||||
fs.writeFileSync(proof, JSON.stringify(canaryProof("2026-06-19T00:00:00.000Z")));
|
||||
const receipt = await verifyCycle({
|
||||
host: "127.0.0.1",
|
||||
skill: "rsi_canary",
|
||||
out,
|
||||
allowDirty: true,
|
||||
canaryProof: proof,
|
||||
now: new Date("2026-06-19T00:00:00.000Z"),
|
||||
factoryCheck: async () => factoryOk,
|
||||
runner,
|
||||
|
|
|
|||
Loading…
Reference in New Issue