414 lines
20 KiB
TypeScript
414 lines
20 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "node:test";
|
|
import { createHash } from "node:crypto";
|
|
import { loadReaderWorkspace } from "./reader-fixture.js";
|
|
import {
|
|
compileExecutionPlan,
|
|
checkExecutionWorld,
|
|
checkedWorldDigest,
|
|
implementationDigest,
|
|
hexDigest,
|
|
parsePackageArtifacts,
|
|
artifactPath,
|
|
type PackageArtifacts,
|
|
type ExecutionPlan,
|
|
type ArtifactImplementation,
|
|
} from "../src/execution-world/index.js";
|
|
|
|
import { buildArtifactFixture as buildFixture } from "./artifact-fixture.js";
|
|
import { compileKernelProgram } from "../src/execution-world/kernel.js";
|
|
import { loadCompositeWorkspace } from "./composite-fixture.js";
|
|
import { standardNativeBackends } from "../src/execution-world/native-backends.js";
|
|
|
|
test("optional targets close over calls into another package", async () => {
|
|
const workspace = await loadCompositeWorkspace();
|
|
const before = compileExecutionPlan(workspace).definition.operations.find(
|
|
(op) => op.operationId === "document:annotate:call",
|
|
)!;
|
|
assert.ok(before, "fixture exposes the composed add-highlight operation");
|
|
assert.equal(before.availableTargets.length, 2);
|
|
workspace.packageImports.find((pkg) => pkg.revisionId === "package:comment-runtime@1")!.exports[0]!.execution = {
|
|
kind: "transaction",
|
|
targets: ["server"],
|
|
};
|
|
const after = compileExecutionPlan(workspace).definition.operations.find((op) => op.key === before.key)!;
|
|
assert.deepEqual(after.availableTargets, ["server"]);
|
|
assert.deepEqual(after.execution, before.execution);
|
|
});
|
|
|
|
test("native support can be supplied for a nominal device target without platform syntax", async () => {
|
|
const workspace = await loadReaderWorkspace();
|
|
const target = "interface:example.esp32@1";
|
|
for (const pkg of workspace.packageImports)
|
|
for (const entry of pkg.exports) {
|
|
if (entry.execution && entry.execution.kind !== "remote") entry.execution.targets.push(target);
|
|
}
|
|
const plan = compileExecutionPlan(workspace, [
|
|
...standardNativeBackends,
|
|
{ target, supports: (binding) => binding.kind === "state" || binding.kind === "edge" },
|
|
]);
|
|
assert.ok(
|
|
plan.definition.operations
|
|
.filter((op) => op.binding.kind === "state")
|
|
.every((op) => op.availableTargets.includes(target)),
|
|
);
|
|
assert.ok(
|
|
plan.definition.operations.some((op) => op.binding.kind === "package" && op.availableTargets.includes(target)),
|
|
);
|
|
});
|
|
const resign = (implementation: ArtifactImplementation) => {
|
|
const { contentDigest, ...body } = implementation;
|
|
implementation.contentDigest = implementationDigest(body);
|
|
};
|
|
|
|
test("installed targets are implementation properties; authoritative fallback preserves the interface", async () => {
|
|
const workspace = await loadReaderWorkspace();
|
|
const plan = compileExecutionPlan(workspace);
|
|
const factory = plan.definition.operations.find(
|
|
(op) => op.binding.kind === "package" && op.binding.exportId === "reader:create-document",
|
|
)!;
|
|
assert.deepEqual(factory.execution, { kind: "transaction", targets: ["server"] });
|
|
assert.deepEqual(factory.availableTargets, ["server", "target:org.quixos.execution.javascript@1"]);
|
|
const kernel = compileKernelProgram(plan) as { operations: { key: string; targets: string[] }[] };
|
|
assert.deepEqual(kernel.operations.find((op) => op.key === factory.key)!.targets, [
|
|
"server",
|
|
"target:org.quixos.execution.javascript@1",
|
|
]);
|
|
|
|
const provider = workspace.packageImports
|
|
.flatMap((pkg) => pkg.exports)
|
|
.find((entry) => entry.id === "reader:create-document")!;
|
|
provider.execution = { kind: "transaction", targets: ["server"] };
|
|
const authoritative = compileExecutionPlan(workspace).definition.operations.find((op) => op.key === factory.key)!;
|
|
assert.deepEqual(authoritative.availableTargets, ["server"]);
|
|
assert.deepEqual(authoritative.execution, factory.execution);
|
|
});
|
|
|
|
test("reader execution plan closes selector storage and traversed interface dependencies", async () => {
|
|
const workspace = await loadReaderWorkspace();
|
|
const plan = compileExecutionPlan(workspace);
|
|
assert.equal(plan.digest, compileExecutionPlan(structuredClone(workspace)).digest);
|
|
assert.equal(plan.definition.owners.length, 5);
|
|
const excerpt =
|
|
plan.definition.operations.find((o) => o.operationId === "highlight:excerpt:get") ??
|
|
plan.definition.operations.find((o) => o.binding.kind === "package" && o.binding.exportId === "reader:excerpt")!;
|
|
assert.ok(excerpt.dependencies.some((d) => d.kind === "state" && d.slot === "slot:highlight:range"));
|
|
assert.ok(
|
|
excerpt.dependencies.some(
|
|
(d) => d.kind === "edge" && d.edge === "edge:document-highlights" && d.projection === "projection:document",
|
|
),
|
|
);
|
|
const calls = excerpt.dependencies.filter((d) => d.kind === "operation");
|
|
assert.equal(calls.length, 2);
|
|
for (const call of calls) {
|
|
assert.equal(call.via?.projectionId, "projection:document");
|
|
const target = plan.definition.operations.find((o) => o.key === call.operation)!;
|
|
assert.ok(target.dependencies.some((d) => d.kind === "state" && d.slot.startsWith("slot:document:")));
|
|
}
|
|
const admission = plan.definition.queries.find((q) => q.query.checked.declaration.displayName === "ReplicaInputs")!;
|
|
assert.ok(admission.admittedOperations.includes(excerpt.key));
|
|
assert.equal(plan.definition.profiles[0]!.profile, "camino-automerge-3.4.1-structured-v1");
|
|
const factory = plan.definition.operations.find(
|
|
(o) => o.binding.kind === "package" && o.binding.exportId === "reader:create-document",
|
|
)!;
|
|
assert.equal(factory.scope, "class");
|
|
assert.ok(
|
|
factory.binding.kind === "package" && factory.binding.dependencies.some((d) => d.binding.kind === "creation"),
|
|
);
|
|
assert.ok(plan.definition.owners.some((o) => Array.isArray(o.initialization) && o.initialization.length > 0));
|
|
});
|
|
|
|
test("artifact closure checks bytes, exact source/schema, ABI, exports and target coverage", async () => {
|
|
const plan = compileExecutionPlan(await loadReaderWorkspace());
|
|
const fixture = buildFixture(plan);
|
|
const world = await checkExecutionWorld(plan, [fixture.manifest], fixture.read);
|
|
assert.equal(world.artifacts.length, 3);
|
|
assert.equal(
|
|
checkedWorldDigest(world),
|
|
checkedWorldDigest(await checkExecutionWorld(plan, [structuredClone(fixture.manifest)], fixture.read)),
|
|
);
|
|
const negative = async (change: (manifest: PackageArtifacts) => void, pattern: RegExp) => {
|
|
const manifest = structuredClone(fixture.manifest);
|
|
change(manifest);
|
|
await assert.rejects(checkExecutionWorld(plan, [manifest], fixture.read), pattern);
|
|
};
|
|
await negative((m) => {
|
|
m.bindingDigest = "0".repeat(64);
|
|
}, /Substituted binding schema/);
|
|
await negative((m) => {
|
|
m.sourceDigest = "0".repeat(64);
|
|
}, /source revision/);
|
|
await negative((m) => {
|
|
(m.versions as unknown as Record<string, string>).value = "v2";
|
|
}, /Incompatible runtime codecs/);
|
|
await negative((m) => {
|
|
m.implementations = m.implementations.filter((i) => i.target !== "target:org.quixos.execution.javascript@1");
|
|
}, /Missing target:org.quixos.execution.javascript@1 implementation/);
|
|
await negative((m) => {
|
|
m.implementations = m.implementations.filter((i) => i.compatibility !== "quixos-service-v1");
|
|
}, /Missing service fallback/);
|
|
await negative((m) => {
|
|
m.implementations[0]!.exports.push("wrong-export");
|
|
resign(m.implementations[0]!);
|
|
}, /Unknown export/);
|
|
await negative((m) => {
|
|
m.implementations[0]!.files[0]!.digest = "0".repeat(64);
|
|
resign(m.implementations[0]!);
|
|
}, /Artifact bytes/);
|
|
await negative((m) => {
|
|
m.implementations[0]!.exports.pop();
|
|
}, /metadata digest mismatch/);
|
|
await assert.rejects(
|
|
checkExecutionWorld(plan, [fixture.manifest], async () => new Uint8Array([1])),
|
|
/Artifact bytes/,
|
|
);
|
|
for (const path of ["/tmp/code", "../code", "a/../b", "a//b", "a\\b", "a%2fb", "a?query"])
|
|
assert.throws(() => artifactPath(path), /normalized relative/);
|
|
const changed = structuredClone(plan);
|
|
changed.definition.versions.value = "wrong" as typeof changed.definition.versions.value;
|
|
await assert.rejects(
|
|
checkExecutionWorld(changed, [fixture.manifest], fixture.read),
|
|
/Unsupported plan codec versions/,
|
|
);
|
|
});
|
|
|
|
test("artifact identity changes when code or registry changes without hashing its own digest", async () => {
|
|
const plan = compileExecutionPlan(await loadReaderWorkspace()),
|
|
fixture = buildFixture(plan);
|
|
const before = checkedWorldDigest(await checkExecutionWorld(plan, [fixture.manifest], fixture.read));
|
|
const manifest = structuredClone(fixture.manifest);
|
|
manifest.implementations[2]!.registryExport = "anotherRegistry";
|
|
resign(manifest.implementations[2]!);
|
|
const after = checkedWorldDigest(await checkExecutionWorld(plan, [manifest], fixture.read));
|
|
assert.notEqual(before, after);
|
|
assert.equal(parsePackageArtifacts(manifest).implementations[2]!.registryExport, "anotherRegistry");
|
|
assert.equal(hexDigest(plan.definition), plan.digest);
|
|
});
|
|
|
|
test("transactions cannot derive their membership from an admitted presentation query", async () => {
|
|
const workspace = await loadReaderWorkspace(),
|
|
pkg = workspace.packageImports[0]!;
|
|
const query = pkg.queries!.find((q) => q.placement?.kind === "local")!;
|
|
const entry = pkg.exports.find((e) => e.id === "reader:add-highlight")!;
|
|
const portId = "test:query-port" as (typeof entry.dependencyPorts)[number]["id"];
|
|
entry.dependencyPorts.push({
|
|
id: portId,
|
|
displayName: "visible",
|
|
requirement: { kind: "query", packageRevisionId: pkg.revisionId, queryId: query.id },
|
|
});
|
|
const bound = workspace.conformances
|
|
.flatMap((c) => c.operationBindings)
|
|
.find((o) => o.binding.kind === "package" && o.binding.exportId === entry.id)!.binding;
|
|
assert.equal(bound.kind, "package");
|
|
if (bound.kind !== "package") return;
|
|
bound.dependencies.push({
|
|
portId,
|
|
binding: { kind: "query", packageRevisionId: pkg.revisionId, queryId: query.id, scope: "object" },
|
|
});
|
|
assert.throws(() => compileExecutionPlan(workspace), /QUERY_IN_TRANSACTION.*test:query-port/);
|
|
});
|
|
|
|
test("port ABI carries only declared port actions, never caller-selected storage IDs", async () => {
|
|
const { checkPortInvocation } = await import("../src/execution-world/index.js");
|
|
const frame = {
|
|
abi: "quixos-transaction-ports-v1",
|
|
frame: "frame1",
|
|
invocation: "invoke1",
|
|
sequence: 1,
|
|
portId: "content",
|
|
action: { kind: "state", primitive: "read" },
|
|
input: { codec: "camino-value-v1", usage: "argument", value: null },
|
|
};
|
|
assert.deepEqual(checkPortInvocation(frame), frame);
|
|
assert.throws(() => checkPortInvocation({ ...frame, slotId: "private" }), /fields or ABI/);
|
|
assert.throws(
|
|
() => checkPortInvocation({ ...frame, action: { kind: "state", primitive: "read", slotId: "private" } }),
|
|
/Invalid port action/,
|
|
);
|
|
assert.throws(() => checkPortInvocation({ ...frame, sequence: NaN }), /sequence/);
|
|
assert.throws(() => checkPortInvocation({ ...frame, action: { kind: "creation", key: "" } }), /Invalid port action/);
|
|
});
|
|
|
|
test("local queries cannot silently expand the replica relationship traversal", async () => {
|
|
const workspace = await loadReaderWorkspace((name, text) =>
|
|
name === "queries/replica-inputs.graphql" ? "query ReplicaInputs { root { sourceRevision content } }" : text,
|
|
);
|
|
assert.throws(() => compileExecutionPlan(workspace), /REPLICA_TRAVERSAL_MISSING/);
|
|
});
|
|
|
|
test("local relationships require complete source candidates even when a filter initially matches", async () => {
|
|
for (const selection of ["highlights(first: 10)", 'highlights(all: 1000, where: {color: {eq: "yellow"}})']) {
|
|
const workspace = await loadReaderWorkspace((name, text) =>
|
|
name === "queries/replica-inputs.graphql" ? text.replace("highlights(all: 1000)", selection) : text,
|
|
);
|
|
assert.throws(() => compileExecutionPlan(workspace), /REPLICA_RELATION_INCOMPLETE/);
|
|
}
|
|
});
|
|
|
|
test("closed generic applications retain distinct identities and codec shapes", async () => {
|
|
const { compileCapabilityResourceSource, compileCapabilitySource } =
|
|
await import("../src/capability-language/index.js");
|
|
const source = { repository: "https://example.test/generic.git", commit: "a".repeat(40) };
|
|
const definition = compileCapabilityResourceSource(
|
|
`interface Cell<value V : storable> id "cell" revision "cell@1" {
|
|
value content id "value" : V { get id "get" execution snapshot; }
|
|
}`,
|
|
{ source },
|
|
);
|
|
assert.ok(definition.ok && definition.resource.kind === "interface", JSON.stringify(definition.diagnostics));
|
|
const compiled = compileCapabilitySource(
|
|
`workspace Demo id "ws" revision "ws@1" commit "${source.commit}" {
|
|
import interface Cell; atom Item id "item";
|
|
conform Item as Cell<string> id "text-owner" { private state Text id "text-slot" on Item : string policy register; bind content.get to state Text.read; }
|
|
conform Item as Cell<int64> id "number-owner" { private state Number id "number-slot" on Item : int64 policy register; bind content.get to state Number.read; }
|
|
}`,
|
|
"workspace.qx",
|
|
{ interfaces: new Map([["Cell", definition.resource.revision]]) },
|
|
);
|
|
assert.ok(compiled.ok, JSON.stringify(compiled.diagnostics));
|
|
const plan = compileExecutionPlan(compiled.workspace);
|
|
assert.equal(plan.definition.operations.length, 2);
|
|
assert.notEqual(
|
|
plan.definition.operations[0]!.interfaceRevisionId,
|
|
plan.definition.operations[1]!.interfaceRevisionId,
|
|
);
|
|
assert.deepEqual(
|
|
new Set(plan.definition.operations.map((o) => (o.output.kind === "scalar" ? o.output.name : null))),
|
|
new Set(["string", "int64"]),
|
|
);
|
|
assert.ok(plan.definition.bindingSchema.interfaces.every((i) => i.application));
|
|
});
|
|
|
|
test("unbound portable exports cannot claim an unsupported transport codec", async () => {
|
|
const workspace = await loadReaderWorkspace();
|
|
workspace.packageImports[0]!.exports.find((e) => e.id === "reader:validate-range")!.outputType = {
|
|
kind: "message",
|
|
descriptorId: "opaque-message",
|
|
};
|
|
assert.throws(() => compileExecutionPlan(workspace), /UNSUPPORTED_PORTABLE_CODEC.*reader:validate-range/);
|
|
});
|
|
|
|
test("query dependencies propagate target requirements through selected getters", async () => {
|
|
const workspace = await loadReaderWorkspace(),
|
|
pkg = workspace.packageImports[0]!;
|
|
const query = pkg.queries!.find((q) => q.displayName === "HighlightList")!;
|
|
const entry = pkg.exports.find((e) => e.id === "reader:excerpt")!;
|
|
const portId = "test:selector-query" as (typeof entry.dependencyPorts)[number]["id"];
|
|
entry.dependencyPorts.push({
|
|
id: portId,
|
|
displayName: "visible",
|
|
requirement: { kind: "query", packageRevisionId: pkg.revisionId, queryId: query.id },
|
|
});
|
|
const bound = workspace.conformances
|
|
.flatMap((c) => c.operationBindings)
|
|
.find((o) => o.binding.kind === "package" && o.binding.exportId === entry.id)!.binding;
|
|
assert.equal(bound.kind, "package");
|
|
if (bound.kind !== "package") return;
|
|
bound.dependencies.push({
|
|
portId,
|
|
binding: { kind: "query", packageRevisionId: pkg.revisionId, queryId: query.id, scope: "workspace" },
|
|
});
|
|
compileExecutionPlan(workspace);
|
|
// Package artifact support is checked over the composed graph; an interface
|
|
// declaration cannot manufacture an authoritative implementation.
|
|
entry.execution = { kind: "snapshot", targets: ["target:org.quixos.execution.javascript@1"] };
|
|
assert.throws(() => compileExecutionPlan(workspace), /MISSING_SERVER_IMPLEMENTATION/);
|
|
});
|
|
|
|
test("implementation selection is explicit, target checked and independent of manifest order", async () => {
|
|
const { selectArtifactImplementation } = await import("../src/execution-world/index.js");
|
|
const plan = compileExecutionPlan(await loadReaderWorkspace());
|
|
const { manifest, read } = buildFixture(plan);
|
|
const selection = {
|
|
target: "target:org.quixos.execution.javascript@1",
|
|
compatibility: "quixos-js-module-v1" as const,
|
|
exports: [manifest.implementations[0]!.exports[0]!],
|
|
};
|
|
assert.equal(selectArtifactImplementation(manifest, selection).id, "browser");
|
|
const alternative = structuredClone(manifest.implementations.find((i) => i.id === "browser")!);
|
|
alternative.id = "browser-alternative";
|
|
resign(alternative);
|
|
manifest.implementations.unshift(alternative);
|
|
await checkExecutionWorld(plan, [manifest], read);
|
|
assert.throws(() => selectArtifactImplementation(manifest, selection), /AMBIGUOUS_IMPLEMENTATION/);
|
|
assert.equal(selectArtifactImplementation(manifest, { ...selection, id: alternative.id }).id, alternative.id);
|
|
manifest.implementations.reverse();
|
|
assert.equal(selectArtifactImplementation(manifest, { ...selection, id: alternative.id }).id, alternative.id);
|
|
for (const invalid of [
|
|
{ ...selection, id: "missing" },
|
|
{ ...selection, id: "service" },
|
|
{ ...selection, id: alternative.id, target: "arduino" },
|
|
{ ...selection, id: alternative.id, exports: ["not-exported"] },
|
|
])
|
|
assert.throws(() => selectArtifactImplementation(manifest, invalid), /IMPLEMENTATION_UNAVAILABLE/);
|
|
assert.equal(
|
|
selectArtifactImplementation(manifest, { ...selection, target: "server", compatibility: "quixos-service-v1" }).id,
|
|
"service",
|
|
);
|
|
});
|
|
|
|
test("execution planning rejects unsupported grouping before installing the query", async () => {
|
|
const workspace = await loadReaderWorkspace((name, text) =>
|
|
name === "queries/reader-screen.graphql"
|
|
? text.replace("aggregate { count }", "groups(by: {color: true}, first: 10) { entries { aggregate { count } } }")
|
|
: text,
|
|
);
|
|
assert.throws(() => compileExecutionPlan(workspace), /QUERY_OPERATOR_UNSUPPORTED.*grouping/);
|
|
});
|
|
|
|
test("a count-only local query still requires complete relationship admission", async () => {
|
|
for (const source of [
|
|
"query ReplicaInputs { root { sourceRevision } }",
|
|
"query ReplicaInputs { root { highlights(first: 1) { entries { node { color } } } } }",
|
|
]) {
|
|
const workspace = await loadReaderWorkspace((name, text) => {
|
|
if (name === "queries/replica-inputs.graphql") return source;
|
|
if (name === "queries/reader-screen.graphql")
|
|
return "query ReaderScreen { root { _camino { relations { highlights { aggregate { count } } } } } }";
|
|
return text;
|
|
});
|
|
assert.throws(() => compileExecutionPlan(workspace), /REPLICA_TRAVERSAL_MISSING|REPLICA_RELATION_INCOMPLETE/);
|
|
}
|
|
});
|
|
|
|
test("public reflection contains nominal contracts and callable descriptors without private bindings", async () => {
|
|
const { publicDefinitionSnapshot } = await import("../src/execution-world/public-reflection.js");
|
|
const plan = compileExecutionPlan(await loadReaderWorkspace());
|
|
const installation = {
|
|
codec: "camino-execution-installation-v1" as const,
|
|
plan: plan.digest,
|
|
world: "test",
|
|
packages: plan.definition.workspace.packageImports.map((pkg) => ({
|
|
revision: pkg.revisionId,
|
|
root: "private-installation-root",
|
|
})),
|
|
components: [],
|
|
routes: {},
|
|
};
|
|
const kernel = compileKernelProgram(plan) as import("../src/execution-world/inspection.js").InspectionKernel;
|
|
const snapshot = publicDefinitionSnapshot(plan, installation, kernel);
|
|
assert.ok(snapshot.rows.interfaces.length);
|
|
assert.ok(snapshot.rows.queries.length);
|
|
assert.ok(snapshot.rows.conformances.length);
|
|
const publicText = JSON.stringify(snapshot);
|
|
for (const privateKey of [
|
|
"privateAttachments",
|
|
"operationBindings",
|
|
"relationshipMaterializations",
|
|
"storagePolicy",
|
|
"ports",
|
|
])
|
|
assert.ok(!publicText.includes('"' + privateKey + '"'), privateKey);
|
|
assert.ok(publicText.includes('"descriptor"'));
|
|
assert.ok(publicText.includes('"scope":"class"'));
|
|
assert.equal(snapshot.id, publicDefinitionSnapshot(plan, installation, kernel).id);
|
|
// Historical checked availability must survive a newer host compiler. If
|
|
// reflection silently regenerates the Kernel, this evidence disappears.
|
|
const historical = structuredClone(kernel);
|
|
const installed = historical.operations.find((operation) => !operation.unsupported)!;
|
|
assert.ok(installed);
|
|
installed.unsupported = "CHECKED_HISTORICAL_UNSUPPORTED";
|
|
const historicalSnapshot = publicDefinitionSnapshot(plan, installation, historical);
|
|
assert.match(JSON.stringify(historicalSnapshot.rows.conformances), /CHECKED_HISTORICAL_UNSUPPORTED/);
|
|
});
|