feat: add render graph driven renderer architecture

Amp-Thread-ID: https://ampcode.com/threads/T-019f9d91-77c1-7206-a60f-ed6554ce92ab

Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
Amp
2026-07-27 02:53:44 +00:00
co-authored by heaust
parent 8a8369706b
commit d4e8634f67
290 changed files with 48804 additions and 1995 deletions
+327
View File
@@ -0,0 +1,327 @@
import assert from "node:assert/strict";
import test from "node:test";
import { validCommand, validFxNodeReplayCommand } from "@lib/commands/validate.js";
import { commandId, linkId, nodeId, socketId } from "@lib/core/types.js";
import { saveCompositionCompatibility } from "@lib/composition/save-compatibility.js";
import { createFxNodeHeadless } from "@lib/headless-runtime.js";
import { APPLICATION_COMPILED, APPLICATION_HEADLESS } from "./application.js";
import type { FxNodeCompositionData } from "@lib/composition/index.js";
const composition = {
...APPLICATION_COMPILED.source,
id: "command-log-test",
version: 7,
nodes: { value: APPLICATION_COMPILED.source.nodes["fxnode.shader.value"]! },
};
const runtime = createFxNodeHeadless(composition);
const save = (commands: readonly unknown[], baseline: unknown = runtime.save(runtime.emptyDocument())) => ({
kind: "fxnode.command-log",
schemaVersion: 2,
composition,
baseline,
commands,
});
test("command validators are total and replay is forward-only", () => {
const hostile = new Proxy(
{},
{
ownKeys() {
throw new Error("hostile");
},
},
);
assert.doesNotThrow(() => validCommand(hostile));
assert.equal(validCommand(hostile), false);
assert.equal(validCommand({ type: "undo" }), true);
assert.equal(validFxNodeReplayCommand({ type: "undo" }), false);
assert.equal(
validFxNodeReplayCommand({ type: "batch", commands: [{ type: "node.move", id: "n", position: { x: 1, y: 2 } }] }),
true,
);
});
test("replay commits atomically once, preserves bounded staged history, and accepts empty logs", () => {
const original = runtime.createEngine(runtime.emptyDocument(), 1),
commands = [
{ type: "node.add", nodeId: nodeId("n"), nodeType: "value", position: { x: 0, y: 0 } } as const,
{ type: "node.move", id: nodeId("n"), position: { x: 2, y: 3 } } as const,
];
const result = runtime.replaySaveData(original, save(commands), 0, commandId("restore"));
assert.equal(result.ok, true);
if (!result.ok) return;
assert.equal(result.status, "committed");
if (result.status !== "committed") return;
assert.equal(Object.isFrozen(result.saveData), true);
assert.notEqual(result.saveData, save(commands));
assert.equal(result.state.version, 1);
assert.deepEqual(result.state.document.nodes.n!.position, { x: 2, y: 3 });
assert.equal(result.state.undo.length, 1);
assert.equal(result.state.redo.length, 0);
assert.equal(result.mutationEnvelope.cause, "load");
assert.equal(result.mutationEnvelope.mutations.length, 1);
assert.equal(result.mutationEnvelope.mutations[0]?.kind, "document.replaced");
const empty = runtime.replaySaveData(result.state, save([]));
assert.equal(empty.ok, true);
if (empty.ok) {
assert.equal(empty.state.version, 2);
assert.equal(empty.state.undo.length, 0);
}
});
test("replay rejection, noop, composition mismatch, and stale source inspection are atomic", () => {
const state = runtime.createEngine(runtime.emptyDocument());
for (const data of [
save([{ type: "node.remove", id: "missing" }]),
save([{ type: "batch", commands: [] }]),
{ ...save([]), composition: { ...composition, id: "other" } },
]) {
const result = runtime.replaySaveData(state, data);
assert.equal(result.ok, false);
if (!result.ok) assert.equal(result.state, state);
}
const noop = runtime.replaySaveData(state, save([{ type: "batch", commands: [] }]));
assert.equal(noop.ok, false);
if (!noop.ok) {
assert.equal(noop.issues[0]?.code, "replay.noop");
assert.equal(noop.issues[0]?.path, "/commands/0");
}
let inspected = false;
const hostile = new Proxy(
{},
{
ownKeys() {
inspected = true;
throw new Error("inspected");
},
},
);
const stale = runtime.replaySaveData(state, hostile, 1);
assert.equal(stale.ok, false);
assert.equal(inspected, false);
if (!stale.ok) {
assert.equal(stale.state, state);
assert.equal(stale.issues[0]?.code, "version.stale");
}
const unchanged = runtime.replaySaveData(state, save([]));
assert.equal(unchanged.ok, true);
if (unchanged.ok) {
assert.equal(unchanged.status, "noop");
assert.equal(unchanged.state.version, state.version);
assert.equal(unchanged.state.document, state.document);
}
});
test("persisted commands reject malformed durable values and links atomically", () => {
const state = runtime.createEngine(runtime.emptyDocument());
const link = {
id: "l",
fromNodeId: "a",
fromSocketId: "a:o",
toNodeId: "b",
toSocketId: "b:i",
muted: false,
extensions: {},
};
const malformed = [
{ type: "link.add", link: { ...link, muted: 0 } },
{ type: "link.add", link: { ...link, extensions: { bad: undefined } } },
{ type: "node.parameter", id: "n", key: "value", value: { kind: "number", value: "1" } },
{ type: "node.socket-default", id: "n", socketId: "n:o", value: { kind: "vector", value: [1, 2] } },
{ type: "node.add", nodeId: "n", nodeType: "not-bound", position: { x: 0, y: 0 } },
];
for (const command of malformed) {
const result = runtime.replaySaveData(state, save([command]));
assert.equal(result.ok, false);
if (!result.ok) {
assert.equal(result.state, state);
assert.match(result.issues[0]?.path ?? "", /^\/commands\/0/);
}
}
});
test("command and baseline admissions have independent budgets and require V2", () => {
const state = runtime.createEngine(runtime.emptyDocument()),
baseline = runtime.save(runtime.emptyDocument());
const large = { ...baseline, metadata: { values: Array.from({ length: 100_001 }, () => 0) } };
assert.equal(runtime.replaySaveData(state, save([], large)).ok, true);
const commands = Array.from({ length: 1_001 }, () => ({ type: "node.remove", id: "n" }));
const over = runtime.replaySaveData(state, save(commands, baseline));
assert.equal(over.ok, false);
if (!over.ok) assert.equal(over.state, state);
const v1 = runtime.replaySaveData(state, save([], { ...baseline, schemaVersion: 1 }));
assert.equal(v1.ok, false);
if (!v1.ok) {
assert.equal(v1.state, state);
assert.equal(v1.issues[0]?.code, "baseline.schema");
}
});
test("save schema v1 and future versions have distinct structured errors", () => {
const state = runtime.createEngine(runtime.emptyDocument());
for (const [schemaVersion, code] of [
[1, "save.schema.unsupported"],
[3, "save.schema.future"],
] as const) {
const result = runtime.replaySaveData(state, { ...save([]), schemaVersion });
assert.equal(result.ok, false);
if (!result.ok) {
assert.equal(result.issues[0]?.code, code);
assert.equal(result.issues[0]?.path, "/schemaVersion");
assert.equal(result.state, state);
}
}
});
test("save decode alone normalizes embedded schema-1 composition menus", () => {
const state = runtime.createEngine(runtime.emptyDocument());
const legacyComposition = {
...composition,
schemaVersion: 1,
menuGroups: { legacy: { title: "Legacy", order: 0 } },
nodes: Object.fromEntries(
Object.entries(composition.nodes).map(([id, node]) => [
id,
{ ...node, menu: { kind: "entry", group: "legacy", order: 0, keywords: [] } },
]),
),
};
const result = runtime.replaySaveData(state, { ...save([]), composition: legacyComposition });
assert.equal(result.ok, true);
if (!result.ok) return;
assert.equal(result.saveData.composition.schemaVersion, 2);
assert.equal("menuGroups" in result.saveData.composition, false);
assert.equal("menu" in result.saveData.composition.nodes.value!, false);
assert.equal(validateLegacyRaw(legacyComposition), false);
for (const invalid of [
{ ...legacyComposition, menuGroups: undefined },
{ ...legacyComposition, nodes: { ...legacyComposition.nodes, value: composition.nodes.value } },
{
...legacyComposition,
nodes: {
...legacyComposition.nodes,
value: { ...legacyComposition.nodes.value, menu: { kind: "entry", group: "missing", order: 0, keywords: [] } },
},
},
{ ...legacyComposition, unexpected: true },
]) {
const rejected = runtime.replaySaveData(state, { ...save([]), composition: invalid });
assert.equal(rejected.ok, false);
}
});
const validateLegacyRaw = (value: unknown) => {
try {
createFxNodeHeadless(value as FxNodeCompositionData);
return true;
} catch {
return false;
}
};
test("composition compatibility accepts true supersets and rejects changed replay semantics", () => {
const extra = APPLICATION_COMPILED.source.nodes["fxnode.shader.color"]!,
presentation = {
...composition,
version: 8,
theme: { ...composition.theme, background: "#123456" as const },
nodes: { ...composition.nodes, extra },
};
const reordered = {
...presentation,
nodes: {
...presentation.nodes,
value: { ...presentation.nodes.value!, ui: [...presentation.nodes.value!.ui].reverse() },
},
};
const baseline = runtime.save(runtime.emptyDocument());
assert.deepEqual(saveCompositionCompatibility(composition, reordered, baseline), []);
const supersetRuntime = createFxNodeHeadless(reordered),
accepted = supersetRuntime.replaySaveData(supersetRuntime.createEngine(supersetRuntime.emptyDocument()), save([]));
assert.equal(accepted.ok, true);
const changed = {
...presentation,
nodes: {
...presentation.nodes,
value: {
...presentation.nodes.value!,
parameters: {
value: { ...presentation.nodes.value!.parameters.value!, default: { kind: "number" as const, value: 42 } },
},
},
},
};
const semantic = saveCompositionCompatibility(composition, changed as FxNodeCompositionData, baseline);
assert.equal(semantic[0]?.code, "composition.incompatible");
assert.equal(semantic[1]?.code, "composition.node-semantic");
assert.equal(semantic[1]?.path, "/composition/nodes/value");
const missing = { ...presentation, nodes: { extra } };
const absent = saveCompositionCompatibility(composition, missing, baseline);
assert.equal(absent[0]?.code, "composition.incompatible");
assert.equal(absent[1]?.code, "composition.definition-missing");
const forged = {
...save([{ type: "node.add", nodeId: "x", nodeType: "extra", position: { x: 0, y: 0 } }]),
composition,
};
const rejected = supersetRuntime.replaySaveData(
supersetRuntime.createEngine(supersetRuntime.emptyDocument()),
forged,
);
assert.equal(rejected.ok, false);
if (!rejected.ok) assert.equal(rejected.issues[0]?.code, "command.invalid");
});
test("compatibility guards opaque promotion and caps structured issues", () => {
const extra = APPLICATION_COMPILED.source.nodes["fxnode.shader.color"]!,
current = { ...composition, nodes: { ...composition.nodes, opaque: extra } };
const opaque = { ...runtime.save(runtime.emptyDocument()), nodes: [{ id: "o", typeId: "opaque" }] as never };
const promoted = saveCompositionCompatibility(composition, current, opaque);
assert.equal(promoted[0]?.code, "composition.incompatible");
assert.equal(promoted[1]?.code, "composition.opaque-promotion");
assert.equal(promoted[1]?.path, "/baseline/nodes/0/typeId");
const many = Object.fromEntries(
Array.from({ length: 150 }, (_, i) => [`style-${i}`, { header: "#000000" }]),
) as unknown as typeof composition.nodeStyles,
withMany = { ...composition, nodeStyles: many };
const capped = saveCompositionCompatibility(
withMany,
{ ...composition, nodeStyles: {} },
runtime.save(runtime.emptyDocument()),
);
assert.equal(capped.length, 100);
});
test("trusted journal validation rejects executable commands outside the durable schema", () => {
const full = createFxNodeHeadless(APPLICATION_COMPILED.source),
from = full.materializeNode("from", "fxnode.shader.value"),
to = full.materializeNode("to", "fxnode.shader.math"),
baseline = full.save({ ...full.emptyDocument(), nodes: { from, to } }),
link = {
id: linkId("l"),
fromNodeId: nodeId("from"),
fromSocketId: socketId("from:value"),
toNodeId: nodeId("to"),
toSocketId: socketId("to:a"),
muted: false,
extensions: {},
};
assert.equal(full.validateReplayJournal(baseline, [{ type: "link.add", link }]), true);
assert.equal(
full.validateReplayJournal(baseline, [{ type: "link.add", link: { ...link, transient: "not durable" } as never }]),
false,
);
});
test("replay rejects a command whose resulting aggregate exceeds persistence closure", () => {
const node = runtime.materializeNode("n", "value"),
baseline = runtime.save({ ...runtime.emptyDocument(), nodes: { n: node } });
const baselineText = "b".repeat(8_388_350),
commandText = "c".repeat(1_048_554);
const result = runtime.replaySaveData(
runtime.createEngine(runtime.emptyDocument()),
save([{ type: "node.label", id: "n", label: commandText }], { ...baseline, metadata: { text: baselineText } }),
);
assert.equal(result.ok, false);
if (!result.ok) assert.equal(result.state.document.nodes.n, undefined);
});