Qualify collection compare-and-swap and explicit ensure mutations

This commit is contained in:
Timothy J. Aveni
2026-09-20 22:57:27 -07:00
parent 115976cacd
commit 33f674321b
5 changed files with 101 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/parser.js";
import { compileExecutionPlan } from "../src/execution-world/plan.js";
import type { InterfaceRevision } from "../src/capability-model/types.js";
export async function collectionsPlan() {
const read = (name: string) => readFile(`test/fixtures/collections/${name}.qx`, "utf8");
const source = { repository: "https://example.test/collections.git", commit: "a".repeat(40) };
const interfaces = new Map<string, InterfaceRevision>();
for (const name of ["NodeData"]) {
const result = compileCapabilityResourceSource(await read(name), { source, environment: { interfaces } });
assert.ok(result.ok && result.resource.kind === "interface", JSON.stringify(result.diagnostics));
interfaces.set(name, result.resource.revision);
}
const pkg = compileCapabilityResourceSource(await read("CollectionRuntime"), { source, environment: { interfaces } });
assert.ok(pkg.ok && pkg.resource.kind === "package", JSON.stringify(pkg.diagnostics));
const result = compileCapabilitySource(await read("workspace"), "workspace.qx", {
interfaces,
packages: new Map([["CollectionRuntime", pkg.resource.revision]]),
});
assert.ok(result.ok, JSON.stringify(result.diagnostics));
return compileExecutionPlan(result.workspace);
}
+6
View File
@@ -119,3 +119,9 @@ for (const [name, revision] of [
`dist/portable-reader/async/${name}.ts`,
generateRemoteTypeScriptBindings(asyncPlan.definition.bindingSchema, revision),
);
const { collectionsPlan } = await import("./collections-fixture.js");
const collections = await collectionsPlan();
await mkdir("dist/portable-reader/collections", { recursive: true });
await writeFile("dist/portable-reader/collections/plan.json", JSON.stringify(collections));
await writeFile("dist/portable-reader/collections/kernel.json", JSON.stringify(compileKernelProgram(collections)));
+18
View File
@@ -0,0 +1,18 @@
type Replacement = record { expected: list<string>; targets: list<atom-ref<Node>>; };
type Seed = record { label: string; };
external atom Node id "collection:node";
package CollectionRuntime id "collection:runtime" revision "collection:runtime@1" {
operation version id "collection:runtime:version" : unit -> list<string>
mode call execution snapshot targets [browser, server] receiver atom Node requires {
edge items id "collection:version:items" : many atom Node [resolve];
};
operation replace id "collection:runtime:replace" : Replacement -> unit
mode call execution transaction targets [browser, server] receiver atom Node requires {
edge items id "collection:replace:items" : many atom Node [resolve, connect, disconnect];
};
operation ensure id "collection:runtime:ensure" : unit -> atom-ref<Node>
mode call execution transaction targets [browser, server] receiver atom Node requires {
edge detail id "collection:ensure:detail" : optional-one atom Node [resolve, connect];
creation node id "collection:ensure:node" : Node input Seed;
};
}
+26
View File
@@ -0,0 +1,26 @@
type Replacement = record { expected: list<string>; targets: list<atom-ref<Node>>; };
external atom Node id "collection:node";
interface NodeData id "collection:data" revision "collection:data@1" {
queryable portable value version id "collection:version" : list<string> {
get id "collection:version:get" execution snapshot targets [browser, server];
}
operation replace id "collection:replace" : Replacement -> unit {
call id "collection:replace:call" execution transaction targets [browser, server];
}
operation ensure id "collection:ensure" : unit -> atom-ref<Node> {
call id "collection:ensure:call" execution transaction targets [browser, server];
}
queryable value label id "collection:label" : string {
get id "collection:label:get" execution snapshot targets [browser, server];
set id "collection:label:set" execution transaction targets [browser, server];
}
queryable relation items id "collection:items" : many atom Node {
resolve id "collection:items:resolve" execution snapshot targets [browser, server];
}
queryable relation containers id "collection:containers" : many atom Node {
resolve id "collection:containers:resolve" execution snapshot targets [browser, server];
}
queryable relation detail id "collection:detail" : optional-one atom Node {
resolve id "collection:detail:resolve" execution snapshot targets [browser, server];
}
}
+28
View File
@@ -0,0 +1,28 @@
workspace Collections id "workspace:collections" revision "workspace:collections@1" commit "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" {
import interface NodeData;
import package CollectionRuntime;
atom Node id "collection:node";
conform Node as NodeData id "collection:node:data" {
private state Label id "collection:label-slot" on Node : string policy register;
private edge Items id "collection:items-edge" {
atom Node projection items id "collection:items-projection" many;
atom Node projection containers id "collection:containers-projection" many;
}
private edge Detail id "collection:detail-edge" {
atom Node projection detail id "collection:detail-projection" optional-one;
atom Node projection owner id "collection:owner-projection" optional-one;
}
initialize { label to state Label; };
bind label.get to state Label.read;
bind label.set to state Label.write;
bind items.resolve to edge Items.items.resolve;
bind containers.resolve to edge Items.containers.resolve;
bind detail.resolve to edge Detail.detail.resolve;
bind version.get to package CollectionRuntime.version with { items to edge Items.items; };
bind replace.call to package CollectionRuntime.replace with { items to edge Items.items; };
bind ensure.call to package CollectionRuntime.ensure with {
detail to edge Detail.detail;
node to creation Node with { NodeData from input; };
};
}
}