add lgtm evidence history and artifact metadata

This commit is contained in:
wassname
2026-06-07 19:03:01 +08:00
parent 023a2c2263
commit 25116e399a
8 changed files with 443 additions and 45 deletions
+15 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { getDisplayStatus, getGateStatus, getReviewBadges } from "../src/review-badges.js";
import { getCompletionMode, getDisplayStatus, getGateStatus, getReviewBadges, getReviewState } from "../src/review-badges.js";
import type { Task } from "../src/types.js";
function makeTask(overrides: Partial<Task> = {}): Task {
@@ -60,6 +60,20 @@ describe("getReviewBadges", () => {
});
});
describe("review state helpers", () => {
it("reports completion mode as direct before any lgtm evidence", () => {
expect(getCompletionMode(makeTask())).toBe("direct");
});
it("reports completion mode as lgtm after evidence history exists", () => {
expect(getCompletionMode(makeTask({ metadata: { lgtm_history: [{ iteration: 1 }] } }))).toBe("lgtm");
});
it("reports superseded when only history remains", () => {
expect(getReviewState(makeTask({ metadata: { lgtm_history: [{ iteration: 1 }] } }))).toBe("superseded");
});
});
describe("getGateStatus", () => {
it("reports ready when human sign-off is open", () => {
expect(getGateStatus(makeTask({
+36
View File
@@ -1,4 +1,8 @@
import { mkdtempSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { archiveCurrentEvidence, buildArtifactRecords, getCurrentEvidenceIteration, getEvidenceHistory } from "../src/index.js";
import { appendRobotReviewMetadata, getLatestRobotReview, getRobotReviews, shouldOpenHumanSignoffGate } from "../src/robot-review.js";
import type { Task } from "../src/types.js";
@@ -45,6 +49,38 @@ describe("robot review helpers", () => {
expect(reviews[0].accepted).toBe(true);
});
it("builds artifact records with absolute path and sha256", () => {
const dir = mkdtempSync(join(tmpdir(), "pi-lgtm-"));
const path = join(dir, "evidence.log");
writeFileSync(path, "hello\n");
const [artifact] = buildArtifactRecords([path]);
expect(artifact.path).toBe(path);
expect(artifact.bytes).toBe(6);
expect(artifact.sha256).toHaveLength(64);
});
it("archives current evidence with reason", () => {
const task = makeTask({
metadata: {
lgtm_evidence: "literal output",
lgtm_failure_likely: "wrong seed",
lgtm_failure_sneaky: "wrong threshold",
lgtm_falsification_test: "pytest -k check",
lgtm_verification_hints: ["see line 5"],
lgtm_remaining_uncertainty: "not load tested",
lgtm_submitted_at: "2026-06-07T00:00:00.000Z",
lgtm_commands: [{ cmd: "pytest", exit_code: 0 }],
},
});
const archived = archiveCurrentEvidence(task, "threshold changed");
const taskWithHistory = makeTask({ metadata: archived });
expect(getCurrentEvidenceIteration(task)?.iteration).toBe(1);
expect(getEvidenceHistory(taskWithHistory)).toHaveLength(1);
expect(getEvidenceHistory(taskWithHistory)[0].supersede_reason).toBe("threshold changed");
});
it("appends robot reviews as iterations", () => {
const task = makeTask();
const metadata1 = appendRobotReviewMetadata(task, {
+11
View File
@@ -189,6 +189,17 @@ describe("TaskStore (in-memory)", () => {
expect(() => store.update("1", { status: "completed" })).toThrow("/lgtm");
});
it("blocks TaskUpdate(status=completed) after evidence was superseded into history", () => {
store.create("Superseded", "Desc", "done");
store.update("1", {
metadata: {
lgtm_history: [{ iteration: 1, supersede_reason: "threshold changed" }],
},
pending_approval: false,
});
expect(() => store.update("1", { status: "completed" })).toThrow("completion_mode=lgtm");
});
it("returns not found for update on non-existent task", () => {
const { task, changedFields } = store.update("999", { status: "in_progress" });
expect(task).toBeUndefined();