mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-10 03:31:40 -10:00
fix(slice-05): deterministic per-branch audit-write tests (guard B1 repair on 63ee7dd7) (OPR.0.3.2.5)
Repairs guard BLOCKING-CONCERN B1 on qitem-20260518211733-7ae5a53e /63ee7dd7: the prior apply-mode audit-write test was loose (asserted outcome IN {success, failed, partial} without controlling which branch the bootstrap actually took). Guard discriminator showed that disabling the completed+partial call sites only still passed the suite — the catch-path audit-write filled in with outcome=failed which the loose assertion accepted. The completed+partial branches could silently lose their audit records while close-out tests remained green. That is the stated Item 4 failure class. Fix applied (mirrors guard's fix recipe): - packages/daemon/test/bundle-routes.test.ts: replaces the single loose apply-mode test with 4 deterministic per-branch tests, each stubbing setup.bootstrapOrchestrator.bootstrap via vi.fn() to force a specific outcome: - apply / completed → mockResolvedValue({status: 'completed', rigId, runId, stages}); assert outcome=success + exact targetRigId - apply / partial → mockResolvedValue({status: 'partial', rigId, ...}); assert outcome=partial + exact targetRigId - apply / failed-result → mockResolvedValue({status: 'failed', stages, errors}); assert outcome=failed - apply / thrown-error → mockRejectedValue(new Error(...)); assert outcome=failed - Shared runApplyAuditTest helper composes the seedPackage + /create + bootstrap-stub + /install + /history flow with original-bootstrap restoration in finally - The plan-mode no-audit test is preserved unchanged Verified: - 35/35 daemon bundle-routes green (was 32; +3 net: -1 loose +4 deterministic) - vi import added to test file (vitest already provides it) - Daemon bundle-audit suite unchanged (10/10) - Function-rename discriminator (renaming writeInstallAudit to writeInstallAudit_BROKEN at the definition): 5/35 fail (the 4 new apply-branch tests + one pre-existing apply-path test); restoring returns 35/35 - Per-branch discriminator implicit in test design: each branch's audit-write call is the only path producing the asserted outcome (catch path can only contribute the 'failed' outcome, not 'success' or 'partial'). Disabling success path → success test fails. Same for partial. Failed-result test could in principle share with thrown-error but they exercise different code paths (return vs catch); disabling either's call site fails the corresponding test uniquely - Coherence + audit-every-layer grep clean Pre-commit discipline applied (banked): git diff --cached --stat verified +135/-33 on the one test file BEFORE commit. No accidental scope inclusions. Diff: 1 file, +135 / -33 lines. No source files modified. Branch chain since main (unchanged at HEAD): ... ->0af652dc(CLEAR) ->b0ae54ad(CLEAR) ->63ee7dd7(Item 4 close-out, guard B1) -> THIS COMMIT (B1 repair, test-only). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
1 parent
63ee7dd793
commit
f7c5a477fa
1 file changed
+133
-31
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import os from "node:os";
|
||||
@@ -1069,41 +1069,143 @@ describe("Bundle API routes", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("POST /api/bundles/install apply mode writes an audit record visible via /history (any outcome)", async () => {
|
||||
/**
|
||||
* Item 4 Checkpoint 5.3 B1 repair: deterministic per-branch audit-write tests.
|
||||
* Each test stubs setup.bootstrapOrchestrator.bootstrap with vi.fn() to force
|
||||
* a specific outcome, then asserts the exact outcome ends up in
|
||||
* /api/bundles/history. Discriminator: disabling each branch's
|
||||
* writeInstallAudit call must fail its paired test specifically.
|
||||
*/
|
||||
async function runApplyAuditTest(opts: {
|
||||
bundleName: string;
|
||||
bootstrapResult?: unknown;
|
||||
bootstrapThrows?: Error;
|
||||
expectedOutcome: "success" | "failed" | "partial";
|
||||
expectedRigId?: string;
|
||||
}): Promise<{ records: Array<Record<string, unknown>>; total: number }> {
|
||||
const { specPath } = seedPackage();
|
||||
const bundlePath = path.join(tmpDir, `${opts.bundleName}.rigbundle`);
|
||||
const targetRoot = fs.mkdtempSync(path.join(os.tmpdir(), `${opts.bundleName}-target-`));
|
||||
const origBootstrap = setup.bootstrapOrchestrator.bootstrap.bind(setup.bootstrapOrchestrator);
|
||||
try {
|
||||
await app.request("/api/bundles/create", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ specPath, bundleName: opts.bundleName, bundleVersion: "0.1.0", outputPath: bundlePath }),
|
||||
});
|
||||
|
||||
const stub = opts.bootstrapThrows
|
||||
? vi.fn().mockRejectedValue(opts.bootstrapThrows)
|
||||
: vi.fn().mockResolvedValue(opts.bootstrapResult);
|
||||
(setup.bootstrapOrchestrator as unknown as { bootstrap: typeof stub }).bootstrap = stub;
|
||||
|
||||
await app.request("/api/bundles/install", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ bundlePath, targetRoot, autoApprove: true }),
|
||||
});
|
||||
|
||||
const history = await app.request("/api/bundles/history");
|
||||
const body = await history.json();
|
||||
return body;
|
||||
} finally {
|
||||
(setup.bootstrapOrchestrator as unknown as { bootstrap: typeof origBootstrap }).bootstrap = origBootstrap;
|
||||
fs.rmSync(targetRoot, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
it("POST /api/bundles/install apply / completed branch writes audit record with outcome=success", async () => {
|
||||
const origHome = process.env.OPENRIG_HOME;
|
||||
const auditHome = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-audit-apply-"));
|
||||
const auditHome = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-audit-completed-"));
|
||||
process.env.OPENRIG_HOME = auditHome;
|
||||
try {
|
||||
const { specPath } = seedPackage();
|
||||
const bundlePath = path.join(tmpDir, "apply-mode.rigbundle");
|
||||
const targetRoot = fs.mkdtempSync(path.join(os.tmpdir(), "apply-target-"));
|
||||
try {
|
||||
await app.request("/api/bundles/create", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ specPath, bundleName: "apply-mode", bundleVersion: "0.1.0", outputPath: bundlePath }),
|
||||
});
|
||||
const body = await runApplyAuditTest({
|
||||
bundleName: "completed-test",
|
||||
bootstrapResult: {
|
||||
status: "completed",
|
||||
runId: "test-run-completed",
|
||||
rigId: "01H000000000000000COMPL01",
|
||||
stages: [{ stage: "resolve_spec", status: "ok" }],
|
||||
errors: [],
|
||||
},
|
||||
expectedOutcome: "success",
|
||||
});
|
||||
expect(body.total).toBe(1);
|
||||
expect(body.records[0].outcome).toBe("success");
|
||||
expect(body.records[0].targetRigId).toBe("01H000000000000000COMPL01");
|
||||
expect(typeof body.records[0].daemonVersion).toBe("string");
|
||||
} finally {
|
||||
if (origHome === undefined) delete process.env.OPENRIG_HOME;
|
||||
else process.env.OPENRIG_HOME = origHome;
|
||||
fs.rmSync(auditHome, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
// Apply mode triggers the audit-write at one of the completion branches
|
||||
// (completed / partial / failed / caught-error). Outcome may vary in
|
||||
// the test bootstrap, but the record MUST be written.
|
||||
await app.request("/api/bundles/install", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ bundlePath, targetRoot, autoApprove: true }),
|
||||
});
|
||||
it("POST /api/bundles/install apply / partial branch writes audit record with outcome=partial", async () => {
|
||||
const origHome = process.env.OPENRIG_HOME;
|
||||
const auditHome = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-audit-partial-"));
|
||||
process.env.OPENRIG_HOME = auditHome;
|
||||
try {
|
||||
const body = await runApplyAuditTest({
|
||||
bundleName: "partial-test",
|
||||
bootstrapResult: {
|
||||
status: "partial",
|
||||
runId: "test-run-partial",
|
||||
rigId: "01H000000000000000PARTI01",
|
||||
stages: [
|
||||
{ stage: "resolve_spec", status: "ok" },
|
||||
{ stage: "instantiate_rig", status: "failed" },
|
||||
],
|
||||
errors: ["partial fail"],
|
||||
},
|
||||
expectedOutcome: "partial",
|
||||
});
|
||||
expect(body.total).toBe(1);
|
||||
expect(body.records[0].outcome).toBe("partial");
|
||||
expect(body.records[0].targetRigId).toBe("01H000000000000000PARTI01");
|
||||
} finally {
|
||||
if (origHome === undefined) delete process.env.OPENRIG_HOME;
|
||||
else process.env.OPENRIG_HOME = origHome;
|
||||
fs.rmSync(auditHome, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
const history = await app.request("/api/bundles/history");
|
||||
const body = await history.json();
|
||||
expect(body.total).toBe(1);
|
||||
const rec = body.records[0];
|
||||
expect(typeof rec.installedAt).toBe("string");
|
||||
expect(rec.bundlePath).toBe(bundlePath);
|
||||
expect(["success", "failed", "partial"]).toContain(rec.outcome);
|
||||
expect(typeof rec.daemonVersion).toBe("string");
|
||||
} finally {
|
||||
fs.rmSync(targetRoot, { recursive: true, force: true });
|
||||
}
|
||||
it("POST /api/bundles/install apply / failed-result branch writes audit record with outcome=failed", async () => {
|
||||
const origHome = process.env.OPENRIG_HOME;
|
||||
const auditHome = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-audit-failed-"));
|
||||
process.env.OPENRIG_HOME = auditHome;
|
||||
try {
|
||||
const body = await runApplyAuditTest({
|
||||
bundleName: "failed-result-test",
|
||||
bootstrapResult: {
|
||||
status: "failed",
|
||||
runId: "test-run-failed",
|
||||
stages: [{ stage: "resolve_spec", status: "failed" }],
|
||||
errors: ["resolve failed"],
|
||||
},
|
||||
expectedOutcome: "failed",
|
||||
});
|
||||
expect(body.total).toBe(1);
|
||||
expect(body.records[0].outcome).toBe("failed");
|
||||
} finally {
|
||||
if (origHome === undefined) delete process.env.OPENRIG_HOME;
|
||||
else process.env.OPENRIG_HOME = origHome;
|
||||
fs.rmSync(auditHome, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("POST /api/bundles/install apply / thrown-error branch writes audit record with outcome=failed", async () => {
|
||||
const origHome = process.env.OPENRIG_HOME;
|
||||
const auditHome = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-audit-thrown-"));
|
||||
process.env.OPENRIG_HOME = auditHome;
|
||||
try {
|
||||
const body = await runApplyAuditTest({
|
||||
bundleName: "thrown-test",
|
||||
bootstrapThrows: new Error("simulated bootstrap explosion"),
|
||||
expectedOutcome: "failed",
|
||||
});
|
||||
expect(body.total).toBe(1);
|
||||
expect(body.records[0].outcome).toBe("failed");
|
||||
} finally {
|
||||
if (origHome === undefined) delete process.env.OPENRIG_HOME;
|
||||
else process.env.OPENRIG_HOME = origHome;
|
||||
|
||||
Reference in new issue
Block a user