From 0a31d30c6c5d3272509840adee6cc6dd661d531b Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Mon, 20 Jul 2026 09:56:18 +0000 Subject: [PATCH] test: recover review harness vault fixture --- .../ReviewHarness/reviewHarnessTypes.ts | 14 +++ .../reviewHarnessVaultFixture.ts | 75 +++++++++++ .../reviewHarnessVaultFixture.unit.spec.ts | 119 ++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 src/features/ReviewHarness/reviewHarnessTypes.ts create mode 100644 src/features/ReviewHarness/reviewHarnessVaultFixture.ts create mode 100644 src/features/ReviewHarness/reviewHarnessVaultFixture.unit.spec.ts diff --git a/src/features/ReviewHarness/reviewHarnessTypes.ts b/src/features/ReviewHarness/reviewHarnessTypes.ts new file mode 100644 index 00000000..0d43a07b --- /dev/null +++ b/src/features/ReviewHarness/reviewHarnessTypes.ts @@ -0,0 +1,14 @@ +export type ReviewHarnessScenarioStatus = + | "idle" + | "queued" + | "running" + | "waiting-for-user" + | "passed" + | "failed" + | "cancelled"; + +export interface ReviewHarnessScenarioResult { + readonly status: ReviewHarnessScenarioStatus; + readonly detail: string; + readonly observations: readonly string[]; +} diff --git a/src/features/ReviewHarness/reviewHarnessVaultFixture.ts b/src/features/ReviewHarness/reviewHarnessVaultFixture.ts new file mode 100644 index 00000000..5fcb3720 --- /dev/null +++ b/src/features/ReviewHarness/reviewHarnessVaultFixture.ts @@ -0,0 +1,75 @@ +import type { ReviewHarnessScenarioResult } from "./reviewHarnessTypes"; + +export const REVIEW_HARNESS_FIXTURE_ROOT = "__self-hosted-livesync-review-harness__"; +export const REVIEW_HARNESS_SOURCE_FILE = `${REVIEW_HARNESS_FIXTURE_ROOT}/round-trip.md`; +export const REVIEW_HARNESS_RENAMED_FILE = `${REVIEW_HARNESS_FIXTURE_ROOT}/round-trip-renamed.md`; + +const CREATED_CONTENT = "review-harness:created\n"; +const MODIFIED_CONTENT = "review-harness:modified\n"; + +export interface ReviewHarnessVaultFixtureRuntime { + confirmFixtureAccess(): Promise; + fixtureRootExists(): boolean; + createFixtureRoot(): Promise; + createFile(path: string, content: string): Promise; + readFile(file: TFile): Promise; + modifyFile(file: TFile, content: string): Promise; + renameFile(file: TFile, path: string): Promise; + filePath(file: TFile): string; + removeFixtureRoot(): Promise; +} + +/** + * Exercises a single, fixed fixture tree in a dedicated Vault. + * + * The runtime owns the platform adapter. This function owns the safety boundary: + * it refuses a pre-existing fixture root, tracks whether it created the root, and + * removes only that owned root in a `finally` block. + */ +export async function runReviewHarnessVaultRoundTrip( + runtime: ReviewHarnessVaultFixtureRuntime +): Promise { + if (!(await runtime.confirmFixtureAccess())) { + return { + status: "cancelled", + detail: "Vault fixture access was not approved.", + observations: [], + }; + } + + if (runtime.fixtureRootExists()) { + return { + status: "failed", + detail: "The owned fixture root already exists. It was left untouched.", + observations: [], + }; + } + + let fixtureOwned = false; + try { + await runtime.createFixtureRoot(); + fixtureOwned = true; + const file = await runtime.createFile(REVIEW_HARNESS_SOURCE_FILE, CREATED_CONTENT); + const created = await runtime.readFile(file); + if (created !== CREATED_CONTENT) throw new Error("Created fixture content did not round-trip."); + + await runtime.modifyFile(file, MODIFIED_CONTENT); + const modified = await runtime.readFile(file); + if (modified !== MODIFIED_CONTENT) throw new Error("Modified fixture content did not round-trip."); + + await runtime.renameFile(file, REVIEW_HARNESS_RENAMED_FILE); + if (runtime.filePath(file) !== REVIEW_HARNESS_RENAMED_FILE) { + throw new Error("The fixture rename did not update its path."); + } + const renamed = await runtime.readFile(file); + if (renamed !== MODIFIED_CONTENT) throw new Error("Renamed fixture content was not preserved."); + + return { + status: "passed", + detail: "The owned fixture tree completed its round trip and was removed.", + observations: ["create", "read", "modify", "rename", "read-after-rename", "cleanup"], + }; + } finally { + if (fixtureOwned) await runtime.removeFixtureRoot(); + } +} diff --git a/src/features/ReviewHarness/reviewHarnessVaultFixture.unit.spec.ts b/src/features/ReviewHarness/reviewHarnessVaultFixture.unit.spec.ts new file mode 100644 index 00000000..e76ff7f3 --- /dev/null +++ b/src/features/ReviewHarness/reviewHarnessVaultFixture.unit.spec.ts @@ -0,0 +1,119 @@ +import { describe, expect, it, vi } from "vitest"; +import { + REVIEW_HARNESS_RENAMED_FILE, + REVIEW_HARNESS_SOURCE_FILE, + runReviewHarnessVaultRoundTrip, + type ReviewHarnessVaultFixtureRuntime, +} from "./reviewHarnessVaultFixture"; + +interface FixtureFile { + path: string; + content: string; +} + +function createRuntime(): ReviewHarnessVaultFixtureRuntime & { + events: string[]; + rootExists: boolean; +} { + const runtime: ReviewHarnessVaultFixtureRuntime & { + events: string[]; + rootExists: boolean; + } = { + events: [], + rootExists: false, + confirmFixtureAccess: vi.fn(async () => true), + fixtureRootExists() { + return this.rootExists; + }, + async createFixtureRoot() { + this.events.push("create-root"); + this.rootExists = true; + }, + async createFile(path, content) { + this.events.push(`create-file:${path}`); + return { path, content }; + }, + async readFile(file) { + this.events.push(`read:${file.path}`); + return file.content; + }, + async modifyFile(file, content) { + this.events.push(`modify:${file.path}`); + file.content = content; + }, + async renameFile(file, path) { + this.events.push(`rename:${file.path}->${path}`); + file.path = path; + }, + filePath: (file) => file.path, + async removeFixtureRoot() { + this.events.push("remove-root"); + this.rootExists = false; + }, + }; + return runtime; +} + +describe("runReviewHarnessVaultRoundTrip", () => { + it("does not inspect or mutate the Vault when access is declined", async () => { + const runtime = createRuntime(); + vi.mocked(runtime.confirmFixtureAccess).mockResolvedValue(false); + const exists = vi.spyOn(runtime, "fixtureRootExists"); + + await expect(runReviewHarnessVaultRoundTrip(runtime)).resolves.toMatchObject({ status: "cancelled" }); + + expect(exists).not.toHaveBeenCalled(); + expect(runtime.events).toEqual([]); + }); + + it("leaves a pre-existing fixture root untouched", async () => { + const runtime = createRuntime(); + runtime.rootExists = true; + + await expect(runReviewHarnessVaultRoundTrip(runtime)).resolves.toMatchObject({ status: "failed" }); + + expect(runtime.events).toEqual([]); + expect(runtime.rootExists).toBe(true); + }); + + it("completes the round trip and removes its owned fixture root", async () => { + const runtime = createRuntime(); + + await expect(runReviewHarnessVaultRoundTrip(runtime)).resolves.toMatchObject({ status: "passed" }); + + expect(runtime.events).toEqual([ + "create-root", + `create-file:${REVIEW_HARNESS_SOURCE_FILE}`, + `read:${REVIEW_HARNESS_SOURCE_FILE}`, + `modify:${REVIEW_HARNESS_SOURCE_FILE}`, + `read:${REVIEW_HARNESS_SOURCE_FILE}`, + `rename:${REVIEW_HARNESS_SOURCE_FILE}->${REVIEW_HARNESS_RENAMED_FILE}`, + `read:${REVIEW_HARNESS_RENAMED_FILE}`, + "remove-root", + ]); + expect(runtime.rootExists).toBe(false); + }); + + it("removes an owned fixture root when an operation fails", async () => { + const runtime = createRuntime(); + runtime.modifyFile = vi.fn(async () => { + throw new Error("fixture write failed"); + }); + + await expect(runReviewHarnessVaultRoundTrip(runtime)).rejects.toThrow("fixture write failed"); + + expect(runtime.events[runtime.events.length - 1]).toBe("remove-root"); + expect(runtime.rootExists).toBe(false); + }); + + it("does not remove a root when creating it fails", async () => { + const runtime = createRuntime(); + runtime.createFixtureRoot = vi.fn(async () => { + throw new Error("root creation failed"); + }); + + await expect(runReviewHarnessVaultRoundTrip(runtime)).rejects.toThrow("root creation failed"); + + expect(runtime.events).toEqual([]); + }); +});