feat: P2 operator, preprocessing state/service, and runtime config lease

This commit is contained in:
2026-08-11 18:40:11 +02:00
parent ca391ba59c
commit f7c2b69837
10 changed files with 2501 additions and 31 deletions
+16 -12
View File
@@ -10,18 +10,22 @@ import { ThtRunner } from "../src/tht/tht-runner.js";
// Spy on child_process.spawn so we can capture the resolved argv (incl. -c config)
// that ThtRunner.run() builds, without launching a real process.
vi.mock("node:child_process", () => ({
spawn: vi.fn(() => {
const ch: any = new EventEmitter();
ch.stdout = new EventEmitter();
ch.stderr = new EventEmitter();
queueMicrotask(() => {
ch.stdout.emit("data", Buffer.from('{"id":"x"}'));
ch.emit("close", 0);
});
return ch;
}),
}));
vi.mock("node:child_process", async (importOriginal) => {
const actual = await importOriginal<typeof import("node:child_process")>();
return {
...actual,
spawn: vi.fn(() => {
const ch: any = new EventEmitter();
ch.stdout = new EventEmitter();
ch.stderr = new EventEmitter();
queueMicrotask(() => {
ch.stdout.emit("data", Buffer.from('{"id":"x"}'));
ch.emit("close", 0);
});
return ch;
}),
};
});
import { spawn } from "node:child_process";
test("sessionNew parses id from JSON", async () => {
@@ -0,0 +1,85 @@
import { expect, test, vi } from "vitest";
import {
runWorkspaceMaintenanceCli,
type WorkspaceMaintenanceIo,
} from "../src/workspace-maintenance.js";
import type { WorkspaceOperationResult } from "../src/workspaces/preprocessing-service.js";
function io(stdin: string): WorkspaceMaintenanceIo & { stdout: string[]; stderr: string[] } {
const stdout: string[] = [];
const stderr: string[] = [];
return {
stdin,
stdout,
stderr,
writeStdout: (value) => void stdout.push(value),
writeStderr: (value) => void stderr.push(value),
};
}
function ok(operation: string): WorkspaceOperationResult {
return {
schemaVersion: 1,
status: "succeeded",
code: "ok",
workspaceId: "psd-clinical",
workspaceRevision: "a".repeat(40),
descriptorBlob: "b".repeat(40),
operation,
completedStages: [],
};
}
test("entrypoint emits exactly one pristine JSON document and maps success/block/failure exits", async () => {
const service = {
inspect: vi.fn(async () => ok("inspect")),
preprocessDwh: vi.fn(async () => ({ ...ok("preprocess dwh"), status: "blocked", code: "manual_review_required" as const })),
run: vi.fn(async () => ({ ...ok("preprocess run"), status: "failed", code: "semantic_index_incompatible" as const })),
} as any;
const inspectIo = io(JSON.stringify({ schemaVersion: 1, workspaceId: "psd-clinical" }));
expect(await runWorkspaceMaintenanceCli(["node", "workspace-maintenance", "inspect"], service, inspectIo)).toBe(0);
expect(JSON.parse(inspectIo.stdout.join(""))).toMatchObject({ operation: "inspect", code: "ok" });
expect(inspectIo.stderr.join("")).toBe("");
const blockedIo = io(JSON.stringify({ schemaVersion: 1, workspaceId: "psd-clinical" }));
expect(await runWorkspaceMaintenanceCli(["node", "workspace-maintenance", "preprocess-dwh"], service, blockedIo)).toBe(3);
expect(JSON.parse(blockedIo.stdout.join(""))).toMatchObject({ code: "manual_review_required" });
const failedIo = io(JSON.stringify({ schemaVersion: 1, workspaceId: "psd-clinical" }));
expect(await runWorkspaceMaintenanceCli(["node", "workspace-maintenance", "preprocess-run"], service, failedIo)).toBe(1);
expect(JSON.parse(failedIo.stdout.join(""))).toMatchObject({ code: "semantic_index_incompatible" });
});
test("malformed stdin, unknown commands, and extra fields fail with exit 2 but still return bounded JSON", async () => {
const service = {} as any;
const malformedIo = io("not-json");
expect(await runWorkspaceMaintenanceCli(["node", "workspace-maintenance", "inspect"], service, malformedIo)).toBe(2);
expect(JSON.parse(malformedIo.stdout.join(""))).toMatchObject({ status: "failed", operation: "inspect" });
const extraFieldIo = io(JSON.stringify({ schemaVersion: 1, workspaceId: "psd-clinical", unexpected: true }));
expect(await runWorkspaceMaintenanceCli(["node", "workspace-maintenance", "inspect"], service, extraFieldIo)).toBe(2);
expect(JSON.parse(extraFieldIo.stdout.join(""))).toMatchObject({ status: "failed", operation: "inspect" });
const unknownIo = io(JSON.stringify({ schemaVersion: 1, workspaceId: "psd-clinical" }));
expect(await runWorkspaceMaintenanceCli(["node", "workspace-maintenance", "explode"], service, unknownIo)).toBe(2);
expect(JSON.parse(unknownIo.stdout.join(""))).toMatchObject({ status: "failed", operation: "explode" });
});
test("raw exception text is redacted from stderr and stdout remains within the public result contract", async () => {
const service = {
inspect: vi.fn(async () => {
throw new Error("https://secret.example.invalid?q=token SELECT * FROM sensitive_table");
}),
} as any;
const captured = io(JSON.stringify({ schemaVersion: 1, workspaceId: "psd-clinical" }));
expect(await runWorkspaceMaintenanceCli(["node", "workspace-maintenance", "inspect"], service, captured)).toBe(1);
expect(JSON.parse(captured.stdout.join(""))).toMatchObject({
status: "failed",
operation: "inspect",
});
expect(captured.stderr.join("")).not.toContain("secret.example.invalid");
expect(captured.stderr.join("")).not.toContain("SELECT *");
});
@@ -0,0 +1,333 @@
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, expect, test, vi } from "vitest";
import { parseWorkspaceYaml } from "../src/workspaces/schema.js";
import { PreprocessingStateStore } from "../src/workspaces/preprocessing-state.js";
import {
WorkspacePreprocessingService,
type ChildProcessRequest,
} from "../src/workspaces/preprocessing-service.js";
const roots: string[] = [];
afterEach(() => {
roots.splice(0).forEach((root) => rmSync(root, { recursive: true, force: true }));
});
const semanticRuntime = {
internalQdrantUrl: "http://qdrant:6333",
internalEmbeddingUrl: "http://embedding:11434",
internalEmbeddingModel: "qwen3-embedding:0.6b",
internalEmbeddingDimensions: 1024,
};
const baseWorkspace = parseWorkspaceYaml(`workspace:
schema_version: 3
id: psd-clinical
name: Runtime Lease
language: en
dwh:
engine: postgres
database: analytics
schema: mart
supported_transports: [postgres_direct]
semantic_index:
vector_store:
engine: qdrant
collection: psd-clinical
dimensions: 1024
distance: cosine
embedding:
provider: ollama_internal
model: qwen3-embedding:0.6b
dimensions: 1024
llm_policy:
allowed: [zai/glm-5.2]
`);
const filesystemWorkspace = parseWorkspaceYaml(`${baseWorkspace ? '' : ''}workspace:
schema_version: 3
id: fs-workspace
name: Filesystem
language: en
dwh:
engine: postgres
database: analytics
schema: mart
supported_transports: [postgres_direct]
semantic_index:
vector_store:
engine: qdrant
collection: fs-workspace
dimensions: 1024
distance: cosine
embedding:
provider: ollama_internal
model: qwen3-embedding:0.6b
dimensions: 1024
llm_policy:
allowed: [zai/glm-5.2]
evidence:
source:
type: filesystem
uri: fs-workspace/evidence
`);
const privateHttpWorkspace = parseWorkspaceYaml(`workspace:
schema_version: 3
id: http-workspace
name: Http
language: en
dwh:
engine: postgres
database: analytics
schema: mart
supported_transports: [postgres_direct]
semantic_index:
vector_store:
engine: qdrant
collection: http-workspace
dimensions: 1024
distance: cosine
embedding:
provider: ollama_internal
model: qwen3-embedding:0.6b
dimensions: 1024
llm_policy:
allowed: [zai/glm-5.2]
evidence:
source:
type: http
uris: [http://127.0.0.1/private.md]
authentication: none
connect_timeout_ms: 1000
read_timeout_ms: 2000
max_bytes: 100
max_redirects: 0
allow_private_hosts: true
max_cache_bytes: 100
`);
function runtime(workspace = baseWorkspace, workspaceId = workspace.workspace.id) {
return {
workspace,
workspaceId,
workspaceRevision: "a".repeat(40),
descriptorBlob: "b".repeat(40),
catalogBlob: "c".repeat(40),
configLease: {
path: `/data/sessions/${workspaceId}/preprocessing/runtime-config/${"a".repeat(40)}.yaml`,
workspaceId,
workspaceRevision: "a".repeat(40),
descriptorBlob: "b".repeat(40),
catalogBlob: "c".repeat(40),
configDigest: "sha256:config",
bindingDigest: "sha256:bindings",
release: () => undefined,
},
};
}
function fixture(workspace = baseWorkspace) {
const dataRoot = mkdtempSync(join(tmpdir(), "tht-preprocessing-service-"));
roots.push(dataRoot);
const requests: ChildProcessRequest[] = [];
const runChild = vi.fn(async (request: ChildProcessRequest) => {
requests.push(request);
return { exitCode: 0, stdout: JSON.stringify({ status: "succeeded" }), stderr: "" };
});
const service = new WorkspacePreprocessingService({
dataRoot,
acquireActiveRuntime: async () => runtime(workspace),
runChild,
listSessions: async () => [],
semanticPreflight: async () => ({ ok: true }),
});
return { dataRoot, runChild, requests, service };
}
test("preprocess dwh uses fixed argv and resumes outer state without rerunning a completed stage", async () => {
const f = fixture();
f.runChild.mockResolvedValueOnce({
exitCode: 0,
stdout: JSON.stringify({ status: "succeeded", run_id: "d".repeat(32) }),
stderr: "",
});
const first = await f.service.preprocessDwh({ workspaceId: "psd-clinical" });
expect(first).toMatchObject({
status: "succeeded",
code: "ok",
operation: "preprocess dwh",
completedStages: ["dwh"],
childRuns: { dwh: "d".repeat(32) },
});
expect((f.runChild.mock.calls[0]![0] as ChildProcessRequest).argv).toEqual([
"preprocess", "dwh", "--steps", "introspect,lsh", "--json", "-c", "/dev/fd/3",
]);
const second = await f.service.preprocessDwh({
workspaceId: "psd-clinical",
resumeRunId: first.runId!,
});
expect(second.status).toBe("unchanged");
expect(f.runChild).toHaveBeenCalledTimes(1);
});
test("schema suggest-fks publishes a candidate artifact and blocks full runs for manual review", async () => {
const f = fixture();
f.runChild
.mockResolvedValueOnce({
exitCode: 0,
stdout: JSON.stringify({ status: "succeeded", run_id: "d".repeat(32) }),
stderr: "",
})
.mockResolvedValueOnce({
exitCode: 0,
stdout: JSON.stringify({
status: "succeeded",
candidate_count: 1,
candidate_digest: "sha256:" + "e".repeat(64),
candidate_yaml: "tables: []\n",
}),
stderr: "",
});
const result = await f.service.run({ workspaceId: "psd-clinical" });
expect(result).toMatchObject({
status: "blocked",
code: "manual_review_required",
completedStages: ["dwh", "fk_suggest"],
});
expect(f.runChild.mock.calls.map(([request]) => (request as ChildProcessRequest).argv[0])).toEqual(["preprocess", "schema"]);
});
test("schema check requires the exact candidate digest, stages annotations via temp file, and persists the review", async () => {
const f = fixture();
f.runChild.mockResolvedValueOnce({
exitCode: 0,
stdout: JSON.stringify({
status: "succeeded",
candidate_count: 1,
candidate_digest: "sha256:" + "e".repeat(64),
candidate_yaml: "tables: []\n",
}),
stderr: "",
});
const suggest = await f.service.suggestFks({ workspaceId: "psd-clinical" });
await expect(f.service.checkSchema({
workspaceId: "psd-clinical",
annotationsYaml: "tables: {}\n",
reviewedCandidatesDigest: "sha256:" + "f".repeat(64),
})).resolves.toMatchObject({ status: "failed", code: "annotation_invalid" });
const reviewedDigest = suggest.artifactIdentities![0]!.digest;
let stagedPath = "";
f.runChild.mockImplementationOnce(async (request: ChildProcessRequest) => {
stagedPath = request.argv[request.argv.indexOf("--annotations") + 1]!;
expect(readFileSync(stagedPath, "utf8")).toBe("tables: {}\n");
expect(request.argv).toEqual([
"schema", "check", "--annotations", stagedPath,
"--reviewed-candidates", reviewedDigest,
"--json", "-c", "/dev/fd/3",
]);
return {
exitCode: 0,
stdout: JSON.stringify({
status: "succeeded",
orphan_count: 0,
annotations_digest: "sha256:annotations",
reviewed_candidates_digest: reviewedDigest,
}),
stderr: "",
};
});
const checked = await f.service.checkSchema({
workspaceId: "psd-clinical",
annotationsYaml: "tables: {}\n",
reviewedCandidatesDigest: reviewedDigest,
});
expect(checked).toMatchObject({ status: "succeeded", code: "ok" });
expect(() => readFileSync(stagedPath, "utf8")).toThrow();
const state = new PreprocessingStateStore({ dataRoot: f.dataRoot, workspaceId: "psd-clinical" });
expect(state.readFkReview(suggest.runId!)?.reviewedCandidatesDigest).toBe(reviewedDigest);
});
test("index schema fails closed when semantic preflight refuses the collection", async () => {
const dataRoot = mkdtempSync(join(tmpdir(), "tht-preprocessing-service-"));
roots.push(dataRoot);
const runChild = vi.fn();
const service = new WorkspacePreprocessingService({
dataRoot,
acquireActiveRuntime: async () => runtime(baseWorkspace),
runChild,
listSessions: async () => [],
semanticPreflight: async () => ({ ok: false, code: "semantic_index_incompatible" }),
});
const result = await service.indexSchema({ workspaceId: "psd-clinical" });
expect(result).toMatchObject({ status: "failed", code: "semantic_index_incompatible" });
expect(runChild).not.toHaveBeenCalled();
});
test("evidence stops before child execution for filesystem sources and refuses private HTTP hosts outside the allowlist", async () => {
const filesystem = fixture(filesystemWorkspace);
const blocked = await filesystem.service.preprocessEvidence({ workspaceId: "fs-workspace" });
expect(blocked).toMatchObject({ status: "blocked", code: "evidence_materialization_required" });
expect(filesystem.runChild).not.toHaveBeenCalled();
const httpDataRoot = mkdtempSync(join(tmpdir(), "tht-preprocessing-service-"));
roots.push(httpDataRoot);
const httpService = new WorkspacePreprocessingService({
dataRoot: httpDataRoot,
acquireActiveRuntime: async () => runtime(privateHttpWorkspace, "http-workspace"),
runChild: vi.fn(),
listSessions: async () => [],
semanticPreflight: async () => ({ ok: true }),
httpPrivateHostAllowlist: ["metadata.internal"],
});
const refused = await httpService.preprocessEvidence({ workspaceId: "http-workspace" });
expect(refused).toMatchObject({ status: "failed", code: "egress_policy_refused" });
});
test("full runs follow the explicit order and finish unchanged when no Evidence source exists", async () => {
const f = fixture();
f.runChild
.mockResolvedValueOnce({
exitCode: 0,
stdout: JSON.stringify({ status: "succeeded", run_id: "d".repeat(32) }),
stderr: "",
})
.mockResolvedValueOnce({
exitCode: 0,
stdout: JSON.stringify({
status: "succeeded",
candidate_count: 0,
candidate_digest: "sha256:" + "0".repeat(64),
candidate_yaml: "tables: []\n",
}),
stderr: "",
})
.mockResolvedValueOnce({
exitCode: 0,
stdout: JSON.stringify({
status: "succeeded",
counts: { added: 1, updated: 0, deleted: 0, unchanged: 0 },
}),
stderr: "",
});
const result = await f.service.run({ workspaceId: "psd-clinical" });
expect(result).toMatchObject({
status: "succeeded",
code: "ok",
completedStages: ["dwh", "fk_suggest", "schema_index"],
warnings: ["workspace has no Evidence source"],
});
expect(f.runChild.mock.calls.map(([request]) => (request as ChildProcessRequest).argv.slice(0, 2).join(" "))).toEqual([
"preprocess dwh",
"schema suggest-fks",
"vector index-schema",
]);
});
@@ -0,0 +1,119 @@
import { existsSync, mkdtempSync, readFileSync, rmSync, statSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, expect, test } from "vitest";
import { PreprocessingStateStore } from "../src/workspaces/preprocessing-state.js";
const roots: string[] = [];
afterEach(() => {
roots.splice(0).forEach((root) => rmSync(root, { recursive: true, force: true }));
});
function fixture() {
const dataRoot = mkdtempSync(join(tmpdir(), "tht-preprocessing-state-"));
roots.push(dataRoot);
return {
dataRoot,
store: new PreprocessingStateStore({ dataRoot, workspaceId: "psd-clinical" }),
};
}
test("job state creates durable 0600 JSON and enforces same-revision resume", async () => {
const { store } = fixture();
const job = await store.beginJob({
operation: "preprocess dwh",
workspaceRevision: "a".repeat(40),
descriptorBlob: "b".repeat(40),
catalogBlob: "c".repeat(40),
configDigest: "sha256:config",
bindingDigest: "sha256:bindings",
});
const path = store.jobPath(job.runId);
expect(existsSync(path)).toBe(true);
expect(statSync(path).mode & 0o777).toBe(0o600);
expect(JSON.parse(readFileSync(path, "utf8"))).toMatchObject({
schemaVersion: 1,
operation: "preprocess dwh",
workspaceId: "psd-clinical",
workspaceRevision: "a".repeat(40),
descriptorBlob: "b".repeat(40),
catalogBlob: "c".repeat(40),
configDigest: "sha256:config",
bindingDigest: "sha256:bindings",
});
await expect(store.beginJob({
operation: "preprocess dwh",
runId: job.runId,
workspaceRevision: "d".repeat(40),
descriptorBlob: "b".repeat(40),
catalogBlob: "c".repeat(40),
configDigest: "sha256:config",
bindingDigest: "sha256:bindings",
})).rejects.toMatchObject({ code: "preprocessing_resume_mismatch" });
const resumed = await store.beginJob({
operation: "preprocess dwh",
runId: job.runId,
workspaceRevision: "a".repeat(40),
descriptorBlob: "b".repeat(40),
catalogBlob: "c".repeat(40),
configDigest: "sha256:config",
bindingDigest: "sha256:bindings",
});
expect(resumed.runId).toBe(job.runId);
});
test("writer lock rejects a concurrent contender and the kernel releases it after holder death", async () => {
const f = fixture();
const other = new PreprocessingStateStore({ dataRoot: f.dataRoot, workspaceId: "psd-clinical" });
const first = await f.store.acquireWriterLock();
await expect(other.acquireWriterLock()).rejects.toMatchObject({ code: "preprocessing_conflict" });
process.kill(first.holderPid, "SIGKILL");
const deadline = Date.now() + 5_000;
while (Date.now() < deadline) {
try {
const recovered = await other.acquireWriterLock();
await recovered.release();
return;
} catch (error) {
if ((error as { code?: string }).code !== "preprocessing_conflict") throw error;
await new Promise((resolve) => setTimeout(resolve, 50));
}
}
throw new Error("writer lock was not released after holder death");
});
test("session inventory guard blocks resumable sessions pinned to a different revision", async () => {
const { store } = fixture();
await expect(store.assertSessionInventoryCompatible("a".repeat(40), [
{ id: "open-other", status: "closed", archived: false, workspaceRevision: "b".repeat(40) },
])).rejects.toMatchObject({ code: "preprocessing_conflict" });
await expect(store.assertSessionInventoryCompatible("a".repeat(40), [
{ id: "current", status: "open", archived: false, workspaceRevision: "a".repeat(40) },
{ id: "finalized", status: "finalized", archived: false, workspaceRevision: "b".repeat(40) },
{ id: "archived", status: "closed", archived: true, workspaceRevision: "c".repeat(40) },
])).resolves.toBeUndefined();
});
test("candidate and review artifacts are digest-bound durable files", async () => {
const { store } = fixture();
const runId = "1".repeat(32);
const candidate = await store.writeFkCandidates(runId, `tables: []
`);
const review = await store.writeFkReview(runId, {
reviewedCandidatesDigest: candidate.digest,
annotationsDigest: "sha256:annotations",
workspaceRevision: "a".repeat(40),
});
expect(candidate.digest).toMatch(/^sha256:[0-9a-f]{64}$/);
expect(review.digest).toMatch(/^sha256:[0-9a-f]{64}$/);
expect(store.readFkCandidates(runId)?.digest).toBe(candidate.digest);
expect(store.readFkReview(runId)?.reviewedCandidatesDigest).toBe(candidate.digest);
});
@@ -0,0 +1,239 @@
import { execFile } from "node:child_process";
import {
chmodSync,
existsSync,
mkdtempSync,
mkdirSync,
readFileSync,
rmSync,
statSync,
symlinkSync,
writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { promisify } from "node:util";
import { afterEach, expect, test, vi } from "vitest";
import { WorkspaceRegistry } from "../src/workspaces/registry.js";
import type { WorkspaceRegistryConfig } from "../src/workspaces/types.js";
import {
publishDeterministicRuntimeConfigLease,
renderActiveWorkspaceRuntime,
renderWorkspaceRuntimeFromSnapshotPath,
} from "../src/workspaces/runtime-config-lease.js";
const runFile = promisify(execFile);
const roots: string[] = [];
afterEach(() => {
vi.unstubAllEnvs();
roots.splice(0).forEach((root) => rmSync(root, { recursive: true, force: true }));
});
async function git(cwd: string, args: string[]): Promise<string> {
return (await runFile("git", args, { cwd })).stdout.trim();
}
async function fixture() {
const root = mkdtempSync(join(tmpdir(), "tht-runtime-lease-"));
roots.push(root);
const remote = join(root, "remote.git");
const source = join(root, "source");
const registryRoot = join(root, "registry");
const secretRoot = join(root, "secrets");
const dataRoot = join(root, "data");
const harnessDir = join(root, "harness");
mkdirSync(harnessDir, { recursive: true });
mkdirSync(join(harnessDir, "config"), { recursive: true });
writeFileSync(join(harnessDir, "config", "tht.yaml"), `session_storage:
mode: local
profile: server
`);
await git(root, ["init", "--bare", "--initial-branch=main", remote]);
mkdirSync(source);
await git(source, ["init", "--initial-branch=main"]);
await git(source, ["config", "user.name", "Runtime Lease Test"]);
await git(source, ["config", "user.email", "runtime-lease@example.invalid"]);
writeFileSync(join(source, "thoth-workspaces.yaml"), `schema_version: 1
workspaces: [{id: psd-clinical, name: Runtime Lease}]
`);
mkdirSync(join(source, "psd-clinical", "evidence"), { recursive: true });
writeFileSync(join(source, "psd-clinical", "workspace.yaml"), `workspace:
schema_version: 3
id: psd-clinical
name: Runtime Lease
language: en
dwh:
engine: postgres
database: analytics
schema: mart
supported_transports: [postgres_direct]
semantic_index:
vector_store:
engine: qdrant
collection: psd-clinical
dimensions: 1024
distance: cosine
embedding:
provider: ollama_internal
model: qwen3-embedding:0.6b
dimensions: 1024
llm_policy:
allowed: [zai/glm-5.2]
evidence:
source:
type: filesystem
uri: psd-clinical/evidence
`);
writeFileSync(join(source, "psd-clinical", "evidence", "guide.md"), `# hello
`);
await git(source, ["add", "."]);
await git(source, ["commit", "-m", "Canonical workspace"]);
await git(source, ["remote", "add", "origin", remote]);
await git(source, ["push", "origin", "main"]);
mkdirSync(secretRoot);
const passwordFile = join(secretRoot, "dwh-password");
writeFileSync(passwordFile, "secret", { mode: 0o600 });
chmodSync(passwordFile, 0o600);
mkdirSync(dataRoot);
const registryConfig: WorkspaceRegistryConfig = {
root: registryRoot,
remoteUrl: remote,
branch: "main",
gitAuthorName: "Runtime Lease Test",
gitAuthorEmail: "runtime-lease@example.invalid",
installationId: "test",
secretRoots: [secretRoot],
maxImportBytes: 1024 * 1024,
maxImportEntries: 16,
};
const registry = new WorkspaceRegistry(registryConfig);
await registry.bootstrap();
const revision = (await registry.list())[0];
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_TRANSPORT", "postgres_direct");
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_HOST", "warehouse.internal");
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_PORT", "5432");
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_USER", "reader");
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_PASSWORD_FILE", passwordFile);
return {
dataRoot,
harnessDir,
registry,
registryConfig,
revision,
};
}
const semanticRuntime = {
internalQdrantUrl: "http://qdrant:6333",
internalEmbeddingUrl: "http://embedding:11434",
internalEmbeddingModel: "qwen3-embedding:0.6b",
internalEmbeddingDimensions: 1024,
};
test("active workspace rendering is byte-identical to direct snapshot rendering", async () => {
const f = await fixture();
const direct = renderWorkspaceRuntimeFromSnapshotPath({
snapshotPath: f.revision.snapshotPath,
harnessDir: f.harnessDir,
configPath: "config/tht.yaml",
dataRoot: f.dataRoot,
secretRoots: f.registryConfig.secretRoots,
semanticRuntime,
});
const active = await renderActiveWorkspaceRuntime({
workspaceId: "psd-clinical",
registry: f.registry,
registryConfig: f.registryConfig,
harnessDir: f.harnessDir,
configPath: "config/tht.yaml",
dataRoot: f.dataRoot,
secretRoots: f.registryConfig.secretRoots,
semanticRuntime,
});
expect(active.renderedConfig).toBe(direct.renderedConfig);
expect(active.workspaceRevision).toBe(f.revision.commit);
expect(active.descriptorBlob).toBe(f.revision.blob);
expect(active.catalogBlob).toMatch(/^[0-9a-f]{40}$/);
});
test("deterministic operator leases publish one revision-bound protected config and refuse changed same-revision bytes", async () => {
const f = await fixture();
const first = await publishDeterministicRuntimeConfigLease({
workspaceId: "psd-clinical",
registry: f.registry,
registryConfig: f.registryConfig,
harnessDir: f.harnessDir,
configPath: "config/tht.yaml",
dataRoot: f.dataRoot,
secretRoots: f.registryConfig.secretRoots,
semanticRuntime,
});
const second = await publishDeterministicRuntimeConfigLease({
workspaceId: "psd-clinical",
registry: f.registry,
registryConfig: f.registryConfig,
harnessDir: f.harnessDir,
configPath: "config/tht.yaml",
dataRoot: f.dataRoot,
secretRoots: f.registryConfig.secretRoots,
semanticRuntime,
});
expect(second.path).toBe(first.path);
expect(first.path).toBe(join(
f.dataRoot,
"sessions",
"psd-clinical",
"preprocessing",
"runtime-config",
`${f.revision.commit}.yaml`,
));
expect(statSync(first.path).mode & 0o777).toBe(0o400);
expect(statSync(first.manifestPath).mode & 0o777).toBe(0o600);
expect(readFileSync(first.path, "utf8")).toContain("collection_lifecycle: require_existing");
expect(existsSync(first.manifestPath)).toBe(true);
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_HOST", "warehouse-two.internal");
await expect(publishDeterministicRuntimeConfigLease({
workspaceId: "psd-clinical",
registry: f.registry,
registryConfig: f.registryConfig,
harnessDir: f.harnessDir,
configPath: "config/tht.yaml",
dataRoot: f.dataRoot,
secretRoots: f.registryConfig.secretRoots,
semanticRuntime,
})).rejects.toMatchObject({ code: "effective_config_mismatch" });
});
test("runtime rendering rejects untrusted snapshot paths and symlinks", async () => {
const f = await fixture();
const outside = join(f.dataRoot, "outside.yaml");
writeFileSync(outside, readFileSync(f.revision.snapshotPath, "utf8"));
const symlink = join(f.dataRoot, "alias.yaml");
symlinkSync(f.revision.snapshotPath, symlink);
expect(() => renderWorkspaceRuntimeFromSnapshotPath({
snapshotPath: outside,
harnessDir: f.harnessDir,
configPath: "config/tht.yaml",
dataRoot: f.dataRoot,
secretRoots: f.registryConfig.secretRoots,
semanticRuntime,
})).toThrow(/trusted runtime snapshot/i);
expect(() => renderWorkspaceRuntimeFromSnapshotPath({
snapshotPath: symlink,
harnessDir: f.harnessDir,
configPath: "config/tht.yaml",
dataRoot: f.dataRoot,
secretRoots: f.registryConfig.secretRoots,
semanticRuntime,
})).toThrow(/trusted runtime snapshot/i);
});