feat: P3 effective configuration, memory root, and revision-scoped records
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { expect, test } from "vitest";
|
||||
import {
|
||||
buildCanonicalEffectiveConfig,
|
||||
canonicalEffectiveConfigJson,
|
||||
configFingerprint,
|
||||
effectiveConfigIdentity,
|
||||
inputFingerprint,
|
||||
} from "../src/workspaces/effective-config.js";
|
||||
|
||||
const semanticRuntime = {
|
||||
internalQdrantUrl: "http://qdrant:6333",
|
||||
internalEmbeddingUrl: "http://embedding:11434",
|
||||
internalEmbeddingModel: "qwen3-embedding:0.6b",
|
||||
internalEmbeddingDimensions: 1024,
|
||||
};
|
||||
|
||||
function directRendered(): Record<string, unknown> {
|
||||
return {
|
||||
runtime_identity: {
|
||||
workspace_id: "psd-clinical",
|
||||
workspace_revision: "a".repeat(40),
|
||||
source_identity: "workspace://psd-clinical",
|
||||
},
|
||||
session_storage: { mode: "local" },
|
||||
profile: "server",
|
||||
language: "it",
|
||||
database: {
|
||||
host: "dwh.internal",
|
||||
port: 5432,
|
||||
database: "postgres",
|
||||
schema: "datawarehouse",
|
||||
user: "thoth_reader",
|
||||
password_file: "/run/secrets/dwh-password",
|
||||
ssl_ca_file: "/run/secrets/dwh-ca.pem",
|
||||
transport: "direct",
|
||||
},
|
||||
dwh: { type: "postgres_direct" },
|
||||
resources: {
|
||||
vector: {
|
||||
engine: "qdrant",
|
||||
base_url: "http://qdrant:6333",
|
||||
collection: "psd-clinical",
|
||||
dimensions: 1024,
|
||||
distance: "cosine",
|
||||
collection_lifecycle: "require_existing",
|
||||
},
|
||||
embeddings: {
|
||||
provider: "ollama_internal",
|
||||
base_url: "http://embedding:11434",
|
||||
model: "qwen3-embedding:0.6b",
|
||||
dimensions: 1024,
|
||||
},
|
||||
},
|
||||
roots: {
|
||||
sessions: "/data/sessions/psd-clinical/sessions",
|
||||
artifacts: "/data/sessions/psd-clinical/artifacts",
|
||||
indexes: "/data/sessions/psd-clinical/indexes",
|
||||
},
|
||||
paths: {
|
||||
sessions: "/data/sessions/psd-clinical/sessions",
|
||||
artifacts: "/data/sessions/psd-clinical/artifacts",
|
||||
indexes: "/data/sessions/psd-clinical/indexes",
|
||||
memory: "/data/sessions/psd-clinical/memory",
|
||||
},
|
||||
evidence: {
|
||||
sources: [{
|
||||
type: "filesystem",
|
||||
root: "/srv/registry/snapshots/rev/psd-clinical/evidence",
|
||||
patterns: ["**/*.md"],
|
||||
max_bytes: 10_485_760,
|
||||
}],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function restRendered(): Record<string, unknown> {
|
||||
return {
|
||||
...directRendered(),
|
||||
database: {
|
||||
host: "localhost",
|
||||
port: 5432,
|
||||
database: "postgres",
|
||||
schema: "datawarehouse",
|
||||
user: "rest",
|
||||
password: "",
|
||||
transport: "rest",
|
||||
},
|
||||
dwh: {
|
||||
type: "thoth_rest",
|
||||
database: { database: "postgres", schema: "datawarehouse" },
|
||||
endpoint: {
|
||||
base_url: "https://dwh.example.test",
|
||||
api_key_file: "/run/secrets/dwh-api-key",
|
||||
},
|
||||
},
|
||||
rest: {
|
||||
base_url: "https://dwh.example.test",
|
||||
api_key_file: "/run/secrets/dwh-api-key",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const directCanonical =
|
||||
`{"schemaVersion":1,"dwh":{` +
|
||||
`"engine":"postgres","database":"postgres","schema":"datawarehouse",` +
|
||||
`"transport":"postgres_direct","host":"dwh.internal","port":5432,"user":"thoth_reader"},` +
|
||||
`"vector":{"collection":"psd-clinical","dimensions":1024,"distance":"cosine"},` +
|
||||
`"embedding":{"model":"qwen3-embedding:0.6b","dimensions":1024},` +
|
||||
`"roots":{"artifacts":"/data/sessions/psd-clinical/artifacts",` +
|
||||
`"indexes":"/data/sessions/psd-clinical/indexes"}}`;
|
||||
|
||||
test("canonical effective config is deterministic and contains the expected key order", () => {
|
||||
const rendered = directRendered();
|
||||
const canonical = buildCanonicalEffectiveConfig(rendered);
|
||||
expect(canonicalEffectiveConfigJson(canonical)).toBe(directCanonical);
|
||||
expect(buildCanonicalEffectiveConfig(rendered)).toEqual(canonical);
|
||||
});
|
||||
|
||||
test("canonical effective config excludes secrets, evidence, session storage, and runtime identity", () => {
|
||||
const json = canonicalEffectiveConfigJson(buildCanonicalEffectiveConfig(directRendered()));
|
||||
expect(json).not.toContain("password_file");
|
||||
expect(json).not.toContain("ssl_ca_file");
|
||||
expect(json).not.toContain("session_storage");
|
||||
expect(json).not.toContain("runtime_identity");
|
||||
expect(json).not.toContain("evidence");
|
||||
expect(json).not.toContain("sources");
|
||||
expect(json).not.toContain("collection_lifecycle");
|
||||
expect(json).not.toContain("base_url"); // vector/embedding service URLs are not identity
|
||||
expect(json).not.toContain("memory");
|
||||
expect(json).not.toContain('"sessions"');
|
||||
});
|
||||
|
||||
test("REST transport canonicalizes to transport rest_api with baseUrl and no host/port", () => {
|
||||
const canonical = buildCanonicalEffectiveConfig(restRendered());
|
||||
const json = canonicalEffectiveConfigJson(canonical);
|
||||
expect(json).toContain(`"transport":"rest_api"`);
|
||||
expect(json).toContain(`"baseUrl":"https://dwh.example.test"`);
|
||||
expect(json).not.toContain(`"host":`);
|
||||
expect(json).not.toContain(`"port":`);
|
||||
expect(json).not.toContain("api_key_file");
|
||||
});
|
||||
|
||||
test("identity and fingerprint helpers produce stable prefixed hex values", () => {
|
||||
const rendered = directRendered();
|
||||
const identity = effectiveConfigIdentity("psd-clinical", rendered);
|
||||
const cfg = configFingerprint(rendered);
|
||||
const input = inputFingerprint("psd-clinical", rendered);
|
||||
|
||||
expect(identity).toMatch(/^workspace:\/\/psd-clinical@v1:[0-9a-f]{64}$/);
|
||||
expect(cfg).toBe("sha256:" + createHash("sha256").update(directCanonical).digest("hex"));
|
||||
expect(input).toBe("sha256:" + createHash("sha256").update(identity).digest("hex"));
|
||||
expect(input).not.toBe(cfg);
|
||||
});
|
||||
|
||||
test("content-only or session_storage changes keep the same effective config identity", () => {
|
||||
const base = directRendered();
|
||||
const identityBefore = effectiveConfigIdentity("psd-clinical", base);
|
||||
const fingerprintBefore = configFingerprint(base);
|
||||
|
||||
const contentOnly = {
|
||||
...base,
|
||||
runtime_identity: {
|
||||
...base.runtime_identity,
|
||||
workspace_revision: "b".repeat(40),
|
||||
},
|
||||
session_storage: { mode: "remote", url: "http://example.test" },
|
||||
evidence: {
|
||||
sources: [{
|
||||
type: "filesystem",
|
||||
root: "/srv/registry/snapshots/other/psd-clinical/evidence",
|
||||
patterns: ["**/*.txt"],
|
||||
max_bytes: 999,
|
||||
}],
|
||||
},
|
||||
};
|
||||
|
||||
expect(effectiveConfigIdentity("psd-clinical", contentOnly)).toBe(identityBefore);
|
||||
expect(configFingerprint(contentOnly)).toBe(fingerprintBefore);
|
||||
});
|
||||
|
||||
test("DWH-affecting changes alter the effective config identity", () => {
|
||||
const base = directRendered();
|
||||
const identityBefore = effectiveConfigIdentity("psd-clinical", base);
|
||||
|
||||
const changedHost = { ...base, database: { ...(base.database as object), host: "dwh-two.internal" } };
|
||||
expect(effectiveConfigIdentity("psd-clinical", changedHost)).not.toBe(identityBefore);
|
||||
|
||||
const changedDatabase = { ...base, database: { ...(base.database as object), database: "analytics" } };
|
||||
expect(effectiveConfigIdentity("psd-clinical", changedDatabase)).not.toBe(identityBefore);
|
||||
|
||||
const changedCollection = { ...base, resources: { ...base.resources, vector: { ...(base.resources as Record<string, any>).vector, collection: "other" } } };
|
||||
expect(effectiveConfigIdentity("psd-clinical", changedCollection)).not.toBe(identityBefore);
|
||||
|
||||
const changedTransport = restRendered();
|
||||
expect(effectiveConfigIdentity("psd-clinical", changedTransport)).not.toBe(identityBefore);
|
||||
});
|
||||
@@ -115,13 +115,31 @@ function runtime(workspace = baseWorkspace, workspaceId = workspace.workspace.id
|
||||
descriptorBlob: "b".repeat(40),
|
||||
catalogBlob: "c".repeat(40),
|
||||
configLease: {
|
||||
path: `/data/sessions/${workspaceId}/preprocessing/runtime-config/${"a".repeat(40)}.yaml`,
|
||||
path: `/data/sessions/${workspaceId}/preprocessing/runtime-config/${"a".repeat(40)}-identitysuffix.yaml`,
|
||||
workspaceId,
|
||||
workspaceRevision: "a".repeat(40),
|
||||
descriptorBlob: "b".repeat(40),
|
||||
catalogBlob: "c".repeat(40),
|
||||
configDigest: "sha256:config",
|
||||
bindingDigest: "sha256:bindings",
|
||||
effectiveConfig: {
|
||||
schemaVersion: 1,
|
||||
dwh: {
|
||||
engine: "postgres",
|
||||
database: "analytics",
|
||||
schema: "mart",
|
||||
transport: "postgres_direct",
|
||||
host: "dwh.internal",
|
||||
port: 5432,
|
||||
user: "reader",
|
||||
},
|
||||
vector: { collection: workspaceId, dimensions: 1024, distance: "cosine" },
|
||||
embedding: { model: "qwen3-embedding:0.6b", dimensions: 1024 },
|
||||
roots: { artifacts: "/data/artifacts", indexes: "/data/indexes" },
|
||||
},
|
||||
effectiveConfigIdentity: "workspace://psd-clinical@v1:" + "d".repeat(64),
|
||||
configFingerprint: "sha256:" + "e".repeat(64),
|
||||
inputFingerprint: "sha256:" + "f".repeat(64),
|
||||
release: () => undefined,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -14,7 +14,13 @@ import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import { afterEach, expect, test, vi } from "vitest";
|
||||
import { parse } from "yaml";
|
||||
import { WorkspaceRegistry } from "../src/workspaces/registry.js";
|
||||
import {
|
||||
buildCanonicalEffectiveConfig,
|
||||
canonicalEffectiveConfigJson,
|
||||
effectiveConfigIdentity,
|
||||
} from "../src/workspaces/effective-config.js";
|
||||
import type { WorkspaceRegistryConfig } from "../src/workspaces/types.js";
|
||||
import {
|
||||
publishDeterministicRuntimeConfigLease,
|
||||
@@ -123,6 +129,7 @@ evidence:
|
||||
return {
|
||||
dataRoot,
|
||||
harnessDir,
|
||||
source,
|
||||
registry,
|
||||
registryConfig,
|
||||
revision,
|
||||
@@ -163,7 +170,7 @@ test("active workspace rendering is byte-identical to direct snapshot rendering"
|
||||
expect(active.catalogBlob).toMatch(/^sha256:[0-9a-f]{64}$/);
|
||||
});
|
||||
|
||||
test("deterministic operator leases publish one revision-bound protected config and refuse changed same-revision bytes", async () => {
|
||||
test("deterministic operator leases are keyed by logical identity and stable across calls", async () => {
|
||||
const f = await fixture();
|
||||
const first = await publishDeterministicRuntimeConfigLease({
|
||||
workspaceId: "psd-clinical",
|
||||
@@ -186,6 +193,7 @@ test("deterministic operator leases publish one revision-bound protected config
|
||||
semanticRuntime,
|
||||
});
|
||||
|
||||
const suffix = first.inputFingerprint.slice(7, 23);
|
||||
expect(second.path).toBe(first.path);
|
||||
expect(first.path).toBe(join(
|
||||
f.dataRoot,
|
||||
@@ -193,15 +201,34 @@ test("deterministic operator leases publish one revision-bound protected config
|
||||
"psd-clinical",
|
||||
"preprocessing",
|
||||
"runtime-config",
|
||||
`${f.revision.commit}.yaml`,
|
||||
`${f.revision.commit}-${suffix}.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(readFileSync(first.path, "utf8")).toContain("memory:");
|
||||
expect(existsSync(first.manifestPath)).toBe(true);
|
||||
expect(first.effectiveConfigIdentity).toMatch(/^workspace:\/\/psd-clinical@v1:[0-9a-f]{64}$/);
|
||||
expect(first.configFingerprint).toMatch(/^sha256:[0-9a-f]{64}$/);
|
||||
expect(first.inputFingerprint).toMatch(/^sha256:[0-9a-f]{64}$/);
|
||||
expect(first.inputFingerprint).not.toBe(first.configFingerprint);
|
||||
const manifest = JSON.parse(readFileSync(first.manifestPath, "utf8"));
|
||||
expect(manifest).toMatchObject({
|
||||
schemaVersion: 1,
|
||||
workspaceId: "psd-clinical",
|
||||
workspaceRevision: f.revision.commit,
|
||||
descriptorBlob: first.descriptorBlob,
|
||||
catalogBlob: first.catalogBlob,
|
||||
configDigest: first.configDigest,
|
||||
bindingDigest: first.bindingDigest,
|
||||
effectiveConfigIdentity: first.effectiveConfigIdentity,
|
||||
configFingerprint: first.configFingerprint,
|
||||
inputFingerprint: first.inputFingerprint,
|
||||
path: first.path,
|
||||
});
|
||||
|
||||
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_HOST", "warehouse-two.internal");
|
||||
await expect(publishDeterministicRuntimeConfigLease({
|
||||
const changed = await publishDeterministicRuntimeConfigLease({
|
||||
workspaceId: "psd-clinical",
|
||||
registry: f.registry,
|
||||
registryConfig: f.registryConfig,
|
||||
@@ -210,7 +237,11 @@ test("deterministic operator leases publish one revision-bound protected config
|
||||
dataRoot: f.dataRoot,
|
||||
secretRoots: f.registryConfig.secretRoots,
|
||||
semanticRuntime,
|
||||
})).rejects.toMatchObject({ code: "effective_config_mismatch" });
|
||||
});
|
||||
expect(changed.path).not.toBe(first.path);
|
||||
expect(changed.inputFingerprint).not.toBe(first.inputFingerprint);
|
||||
expect(changed.configFingerprint).not.toBe(first.configFingerprint);
|
||||
expect(readFileSync(changed.path, "utf8")).toContain("warehouse-two.internal");
|
||||
});
|
||||
|
||||
test("runtime rendering rejects untrusted snapshot paths and symlinks", async () => {
|
||||
@@ -237,3 +268,74 @@ test("runtime rendering rejects untrusted snapshot paths and symlinks", async ()
|
||||
semanticRuntime,
|
||||
})).toThrow(/trusted runtime snapshot/i);
|
||||
});
|
||||
|
||||
|
||||
test("operator lease and session snapshot produce byte-identical effective DWH bindings", async () => {
|
||||
const f = await fixture();
|
||||
const session = renderWorkspaceRuntimeFromSnapshotPath({
|
||||
snapshotPath: f.revision.snapshotPath,
|
||||
harnessDir: f.harnessDir,
|
||||
configPath: "config/tht.yaml",
|
||||
dataRoot: f.dataRoot,
|
||||
secretRoots: f.registryConfig.secretRoots,
|
||||
semanticRuntime,
|
||||
});
|
||||
const lease = 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 sessionCanonical = canonicalEffectiveConfigJson(buildCanonicalEffectiveConfig(parse(session.renderedConfig)));
|
||||
const operatorCanonical = canonicalEffectiveConfigJson(lease.effectiveConfig);
|
||||
expect(operatorCanonical).toBe(sessionCanonical);
|
||||
expect(lease.effectiveConfigIdentity).toBe(
|
||||
effectiveConfigIdentity("psd-clinical", parse(session.renderedConfig)),
|
||||
);
|
||||
});
|
||||
|
||||
test("a content-only Evidence commit keeps the same effective config identity with a new revision lease", async () => {
|
||||
const f = await fixture();
|
||||
const firstLease = 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 firstIdentity = firstLease.effectiveConfigIdentity;
|
||||
|
||||
writeFileSync(
|
||||
join(f.source, "psd-clinical", "evidence", "guide.md"),
|
||||
"# updated content only\n",
|
||||
);
|
||||
await git(f.source, ["add", "psd-clinical/evidence/guide.md"]);
|
||||
await git(f.source, ["commit", "-m", "Evidence content only"]);
|
||||
await git(f.source, ["push", "origin", "main"]);
|
||||
await f.registry.pull();
|
||||
const current = (await f.registry.list())[0];
|
||||
|
||||
const secondLease = 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(secondLease.workspaceRevision).toBe(current.commit);
|
||||
expect(secondLease.workspaceRevision).not.toBe(firstLease.workspaceRevision);
|
||||
expect(secondLease.effectiveConfigIdentity).toBe(firstIdentity);
|
||||
expect(secondLease.path).not.toBe(firstLease.path);
|
||||
});
|
||||
|
||||
@@ -40,6 +40,7 @@ const paths: RuntimePaths = {
|
||||
sessions: "/data/workspaces/psd-clinical/sessions",
|
||||
artifacts: "/data/workspaces/psd-clinical/artifacts",
|
||||
indexes: "/data/workspaces/psd-clinical/indexes",
|
||||
memory: "/data/workspaces/psd-clinical/memory",
|
||||
};
|
||||
const semanticRuntime: SemanticRuntimeConfig = {
|
||||
internalQdrantUrl: "http://qdrant:6333",
|
||||
|
||||
Reference in New Issue
Block a user