Files
playbook/antigravity-awesome-skills/tools/scripts/tests/aas_v1_transaction.test.js
T
2026-07-20 00:03:02 +00:00

689 lines
34 KiB
JavaScript

"use strict";
const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");
const versions = require("../../lib/aas-v1/versions");
const { sha256, canonicalJson } = require("../../lib/aas-v1/canonical-json");
const { buildPlanEnvelope } = require("../../lib/aas-v1/stack");
const {
appendRecord,
acquireLock,
applyPlan,
buildRecoveryPlan,
buildManagedState,
createJournal,
digestManagedEntries,
doctor,
journalPath,
preflight,
readManagedState,
recover,
releaseLock,
recoveryIdFor,
treeDigest,
} = require("../../lib/aas-v1/transaction");
const {
cleanupMaterializedLayout,
inspectLayout,
materializeLayout,
remainingMaterializedLayoutPaths,
} = require("../../lib/aas-v1/transaction/safety");
const DIGEST = (letter) => `sha256-${letter.repeat(64)}`;
const CATALOG = { package: "agentic-awesome-skills", version: "15.0.0", integrity: DIGEST("a") };
const TARGET_ID = DIGEST("b");
function writeTree(directory, files) {
fs.mkdirSync(directory, { recursive: true });
for (const [relative, content] of Object.entries(files)) {
const destination = path.join(directory, relative);
fs.mkdirSync(path.dirname(destination), { recursive: true });
fs.writeFileSync(destination, content);
}
}
function fixture() {
const sandbox = fs.mkdtempSync(path.join(os.tmpdir(), "aas-v1-transaction-"));
const root = path.join(sandbox, "target");
const skillsDirectory = path.join(root, "skills");
const transactionDirectory = path.join(root, ".aas-transactions");
const stateFile = path.join(root, ".aas-managed-state.json");
const sources = path.join(sandbox, "sources");
fs.mkdirSync(skillsDirectory, { recursive: true });
fs.mkdirSync(transactionDirectory, { recursive: true });
fs.mkdirSync(sources, { recursive: true });
const adapter = {
resolveTransactionLayout() { return { root, skillsDirectory, stateFile, transactionDirectory }; },
computeTargetIdentity() { return TARGET_ID; },
resolveSourceTree({ skillId }) { return path.join(sources, skillId); },
validateSourceTree(source) { return source.endsWith(`${path.sep}sources${path.sep}${path.basename(source)}`); },
};
return { sandbox, root, skillsDirectory, transactionDirectory, stateFile, sources, adapter };
}
function buildInstallPlan(fx, skillId = "alpha", overrides = {}) {
const source = path.join(fx.sources, skillId);
if (!fs.existsSync(source)) writeTree(source, { "SKILL.md": "# Alpha\n", "nested/example.txt": "hello\n" });
const sourceDigest = treeDigest(source);
const emptyDigest = digestManagedEntries([]);
const nextDigest = digestManagedEntries([{ skillId, treeDigest: sourceDigest, catalogIntegrity: CATALOG.integrity }]);
return buildPlanEnvelope({
manifest: {
schemaVersion: 2,
name: "transaction-test",
catalog: CATALOG,
targets: [{ host: "codex", scope: "project" }],
profile: { goals: ["test"], languages: [], frameworks: [], constraints: [] },
skills: [{ id: skillId }],
},
handshake: versions,
catalog: CATALOG,
runtime: { package: "agentic-awesome-skills", version: "15.0.0", integrity: "sha512-runtime", closureDigest: DIGEST("c") },
target: { host: "codex", scope: "project", adapterVersion: "1.0.0", identityDigest: TARGET_ID },
installedState: { digest: emptyDigest, entries: [] },
operations: [{ kind: "install", skillId, sourceTreeDigest: sourceDigest, expectedTreeDigest: null, resultTreeDigest: sourceDigest, backupRequired: false }],
overrides: [],
stateCommit: { previousDigest: emptyDigest, nextDigest, position: "final" },
...overrides,
});
}
function buildReplacePlan(fx, { allowDrift }) {
const state = readManagedState(fx.stateFile);
const destination = path.join(fx.skillsDirectory, "alpha");
const currentDigest = treeDigest(destination);
const source = path.join(fx.sources, "alpha-next");
writeTree(source, { "SKILL.md": "# Alpha v2\n" });
const resultDigest = treeDigest(source);
const nextDigest = digestManagedEntries([{ skillId: "alpha", treeDigest: resultDigest, catalogIntegrity: CATALOG.integrity }]);
const adapter = { ...fx.adapter, resolveSourceTree() { return source; } };
const plan = buildPlanEnvelope({
manifest: {
schemaVersion: 2,
name: "transaction-test",
catalog: CATALOG,
targets: [{ host: "codex", scope: "project" }],
profile: { goals: ["test"], languages: [], frameworks: [], constraints: [] },
skills: [{ id: "alpha" }],
},
handshake: versions,
catalog: CATALOG,
runtime: { package: "agentic-awesome-skills", version: "15.0.0", integrity: "sha512-runtime", closureDigest: DIGEST("c") },
target: { host: "codex", scope: "project", adapterVersion: "1.0.0", identityDigest: TARGET_ID },
installedState: {
digest: state.stateDigest,
entries: state.entries.map(({ skillId, treeDigest: digest, catalogIntegrity }) => ({ skillId, treeDigest: digest, catalogIntegrity })),
},
operations: [{ kind: "replaceManaged", skillId: "alpha", sourceTreeDigest: resultDigest, expectedTreeDigest: currentDigest, resultTreeDigest: resultDigest, backupRequired: true }],
overrides: allowDrift ? [{ kind: "managedDrift", skillId: "alpha", reasonCodes: ["approved-local-backup"] }] : [],
stateCommit: { previousDigest: state.stateDigest, nextDigest, position: "final" },
});
return { adapter, plan, resultDigest };
}
function snapshot(root) {
const results = [];
function visit(directory, relative = "") {
for (const name of fs.readdirSync(directory).sort()) {
const absolute = path.join(directory, name);
const item = relative ? `${relative}/${name}` : name;
const stat = fs.lstatSync(absolute);
if (stat.isDirectory()) {
results.push(`d:${item}`);
visit(absolute, item);
} else results.push(`f:${item}:${sha256(fs.readFileSync(absolute))}`);
}
}
visit(root);
return results;
}
test("tree digest is deterministic and rejects symlinks", () => {
const fx = fixture();
const one = path.join(fx.sandbox, "one");
const two = path.join(fx.sandbox, "two");
writeTree(one, { "z.txt": "z", "a/x.txt": "x" });
writeTree(two, { "a/x.txt": "x", "z.txt": "z" });
assert.equal(treeDigest(one), treeDigest(two));
fs.symlinkSync(path.join(one, "z.txt"), path.join(one, "link"));
assert.throws(() => treeDigest(one), { code: "AAS_TRANSACTION_TREE_SYMLINK" });
fs.rmSync(fx.sandbox, { recursive: true });
});
test("apply commits managed state last, preserves unmanaged bytes, and is idempotent", () => {
const fx = fixture();
writeTree(path.join(fx.skillsDirectory, "unmanaged"), { "keep.txt": "do not change" });
const unmanagedBefore = treeDigest(path.join(fx.skillsDirectory, "unmanaged"));
const plan = buildInstallPlan(fx);
const boundaries = [];
const result = applyPlan({ plan, adapter: fx.adapter, approvalDigest: plan.digest, onBoundary: (name) => boundaries.push(name) });
assert.equal(result.status, "applied");
assert.equal(treeDigest(path.join(fx.skillsDirectory, "unmanaged")), unmanagedBefore);
assert.equal(treeDigest(path.join(fx.skillsDirectory, "alpha")), plan.payload.operations[0].resultTreeDigest);
const state = readManagedState(fx.stateFile);
assert.deepEqual(state.completedPlanDigests, [plan.digest]);
assert.equal(boundaries.at(-1), "committed");
const before = snapshot(fx.root);
let called = false;
const again = applyPlan({ plan, adapter: fx.adapter, approvalDigest: plan.digest, onBoundary: () => { called = true; } });
assert.equal(again.status, "alreadyApplied");
assert.equal(called, false);
assert.deepEqual(snapshot(fx.root), before);
fs.rmSync(fx.sandbox, { recursive: true });
});
test("a post-commit cleanup failure is surfaced and completed by approved recovery", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
assert.throws(() => applyPlan({
plan,
adapter: fx.adapter,
approvalDigest: plan.digest,
onBoundary(name) {
if (name === "committed") throw new Error("cleanup boundary fault");
},
}), { code: "AAS_TRANSACTION_RECOVERY_REQUIRED" });
assert.equal(treeDigest(path.join(fx.skillsDirectory, "alpha")), plan.payload.operations[0].resultTreeDigest);
const diagnosis = doctor({ target: plan.payload.target, adapter: fx.adapter });
assert.equal(diagnosis.status, "recoveryRequired");
const cleanup = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId: diagnosis.recoveries[0].recoveryId, action: "cleanup" });
assert.equal(recover({ recoveryPlan: cleanup, plan, adapter: fx.adapter, approvalDigest: cleanup.digest }).status, "cleaned");
assert.equal(applyPlan({ plan, adapter: fx.adapter, approvalDigest: plan.digest }).status, "alreadyApplied");
fs.rmSync(fx.sandbox, { recursive: true });
});
test("bootstrap publication failure preserves plan-bound recovery evidence", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
assert.throws(() => applyPlan({
plan,
adapter: fx.adapter,
approvalDigest: plan.digest,
onBoundary(name) {
if (name === "bootstrapPublished") throw new Error("fault after bootstrap rename");
},
}), { code: "AAS_TRANSACTION_RECOVERY_REQUIRED" });
const lockFile = path.join(fx.root, ".aas-transaction.lock");
assert.equal(fs.existsSync(lockFile), true);
let diagnosis = doctor({ target: plan.payload.target, adapter: fx.adapter });
assert.equal(diagnosis.status, "recoveryRequired");
assert.equal(diagnosis.recoveries[0].bootstrapOnly, true);
// Simulate the failed CLI process having exited before the separately
// approved recovery command starts.
const lock = JSON.parse(fs.readFileSync(lockFile, "utf8"));
lock.pid = 2147483647;
fs.writeFileSync(lockFile, `${canonicalJson(lock)}\n`);
const cleanup = buildRecoveryPlan({
plan,
adapter: fx.adapter,
recoveryId: diagnosis.recoveries[0].recoveryId,
action: "cleanup",
});
assert.equal(recover({ recoveryPlan: cleanup, plan, adapter: fx.adapter, approvalDigest: cleanup.digest }).status, "cleaned");
diagnosis = doctor({ target: plan.payload.target, adapter: fx.adapter });
assert.equal(diagnosis.status, "healthy");
fs.rmSync(fx.sandbox, { recursive: true });
});
test("cleanup recovery closes a WAL created before layout materialization", () => {
const fx = fixture();
fs.rmSync(fx.transactionDirectory, { recursive: true });
writeTree(path.join(fx.skillsDirectory, "unmanaged"), { "keep.txt": "untouched\n" });
const unmanagedBefore = treeDigest(path.join(fx.skillsDirectory, "unmanaged"));
const plan = buildInstallPlan(fx);
const inspected = inspectLayout(fx.adapter, plan.payload.target);
assert.equal(inspected.missingDirectories.length, 1);
assert.equal(path.basename(inspected.missingDirectories[0]), path.basename(fx.transactionDirectory));
const applyLock = acquireLock(inspected, plan);
const recoveryId = recoveryIdFor(plan.digest, TARGET_ID);
const markerName = `.aas-layout-${recoveryId}`;
const bootstrapBody = {
directories: inspected.missingDirectories
.map((directory) => path.relative(inspected.root, directory).split(path.sep).join("/")),
markerName,
markerToken: applyLock.token,
planDigest: plan.digest,
recoveryId,
schemaVersion: 1,
targetIdentityDigest: TARGET_ID,
};
fs.writeFileSync(path.join(fx.root, `.aas-bootstrap-${recoveryId}.json`), `${canonicalJson({
...bootstrapBody,
recordDigest: sha256(canonicalJson(bootstrapBody)),
})}\n`);
createJournal(fx.root, recoveryId, plan.digest, TARGET_ID);
fs.closeSync(applyLock.descriptor);
fs.writeFileSync(applyLock.path, `${canonicalJson({ ...applyLock.record, pid: 2147483647 })}\n`);
const diagnosis = doctor({ target: plan.payload.target, adapter: fx.adapter });
assert.equal(diagnosis.status, "recoveryRequired");
assert.equal(diagnosis.recoveries[0].bootstrapOnly, undefined);
const cleanup = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId, action: "cleanup" });
assert.equal(cleanup.payload.bootstrapOnly, false);
assert.equal(recover({ recoveryPlan: cleanup, plan, adapter: fx.adapter, approvalDigest: cleanup.digest }).status, "cleaned");
assert.equal(fs.existsSync(fx.transactionDirectory), false);
assert.equal(treeDigest(path.join(fx.skillsDirectory, "unmanaged")), unmanagedBefore);
assert.equal(doctor({ target: plan.payload.target, adapter: fx.adapter }).status, "healthy");
fs.rmSync(fx.sandbox, { recursive: true });
});
test("cleanup recovery stays fail-closed when a marker-owned stage is not empty", () => {
const fx = fixture();
fs.rmSync(fx.transactionDirectory, { recursive: true });
const plan = buildInstallPlan(fx);
const inspected = inspectLayout(fx.adapter, plan.payload.target);
const applyLock = acquireLock(inspected, plan);
const recoveryId = recoveryIdFor(plan.digest, TARGET_ID);
const markerName = `.aas-layout-${recoveryId}`;
const bootstrapBody = {
directories: inspected.missingDirectories
.map((directory) => path.relative(inspected.root, directory).split(path.sep).join("/")),
markerName,
markerToken: applyLock.token,
planDigest: plan.digest,
recoveryId,
schemaVersion: 1,
targetIdentityDigest: TARGET_ID,
};
fs.writeFileSync(path.join(fx.root, `.aas-bootstrap-${recoveryId}.json`), `${canonicalJson({
...bootstrapBody,
recordDigest: sha256(canonicalJson(bootstrapBody)),
})}\n`);
createJournal(fx.root, recoveryId, plan.digest, TARGET_ID);
const missing = inspected.missingDirectories[0];
const stage = path.join(path.dirname(missing), `.aas-layout-stage-${applyLock.token}-${path.basename(missing)}`);
fs.mkdirSync(stage, { mode: 0o700 });
fs.writeFileSync(path.join(stage, markerName), `${applyLock.token}\n`, { mode: 0o600 });
fs.writeFileSync(path.join(stage, "unexpected.txt"), "unmanaged\n", { mode: 0o600 });
fs.closeSync(applyLock.descriptor);
fs.writeFileSync(applyLock.path, `${canonicalJson({ ...applyLock.record, pid: 2147483647 })}\n`);
const cleanup = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId, action: "cleanup" });
assert.throws(() => recover({
recoveryPlan: cleanup,
plan,
adapter: fx.adapter,
approvalDigest: cleanup.digest,
}), { code: "AAS_TRANSACTION_LAYOUT_CLEANUP_INCOMPLETE" });
assert.equal(fs.existsSync(stage), true);
assert.equal(fs.readFileSync(path.join(stage, "unexpected.txt"), "utf8"), "unmanaged\n");
assert.equal(fs.existsSync(path.join(fx.root, `.aas-bootstrap-${recoveryId}.json`)), true);
assert.equal(doctor({ target: plan.payload.target, adapter: fx.adapter }).status, "recoveryRequired");
fs.unlinkSync(path.join(stage, "unexpected.txt"));
assert.equal(recover({
recoveryPlan: cleanup,
plan,
adapter: fx.adapter,
approvalDigest: cleanup.digest,
}).status, "cleaned");
assert.equal(fs.existsSync(stage), false);
assert.equal(doctor({ target: plan.payload.target, adapter: fx.adapter }).status, "healthy");
fs.rmSync(fx.sandbox, { recursive: true });
});
test("layout publication failure is tracked before fsync and leaves no partial artifact", () => {
const fx = fixture();
fs.rmSync(fx.skillsDirectory, { recursive: true });
fs.rmSync(fx.transactionDirectory, { recursive: true });
const plan = buildInstallPlan(fx);
assert.throws(() => applyPlan({
plan,
adapter: fx.adapter,
approvalDigest: plan.digest,
onBoundary(name) {
if (name === "layoutDirectoryPublished") throw new Error("fault after layout rename");
},
}), { code: "AAS_TRANSACTION_LAYOUT_CREATE_FAILED" });
assert.equal(fs.existsSync(fx.skillsDirectory), false);
assert.equal(fs.existsSync(fx.transactionDirectory), false);
assert.equal(fs.readdirSync(fx.root).some((name) => name.startsWith(".aas-")), false);
assert.equal(doctor({ target: plan.payload.target, adapter: fx.adapter }).status, "healthy");
fs.rmSync(fx.sandbox, { recursive: true });
});
test("layout tombstone cleanup resumes after its rename durability boundary", () => {
const fx = fixture();
fs.rmSync(fx.skillsDirectory, { recursive: true });
fs.rmSync(fx.transactionDirectory, { recursive: true });
const inspected = inspectLayout(fx.adapter, { host: "codex", scope: "project", identityDigest: TARGET_ID });
const markerToken = "c".repeat(48);
const markerName = `.aas-layout-recovery-${"d".repeat(32)}`;
const created = [];
materializeLayout(inspected, { markerName, markerToken, createdDirectories: created });
assert.throws(() => cleanupMaterializedLayout(inspected, created, {
markerName,
markerToken,
onBoundary(name) {
if (name === "layoutDirectoryTombstoned") throw new Error("fault after tombstone rename");
},
}), /fault after tombstone rename/);
assert.ok(fs.readdirSync(fx.root).some((name) => name.startsWith(`.aas-layout-remove-${markerToken}-`)));
cleanupMaterializedLayout(inspected, created, { markerName, markerToken });
assert.equal(fs.existsSync(fx.skillsDirectory), false);
assert.equal(fs.existsSync(fx.transactionDirectory), false);
assert.equal(fs.readdirSync(fx.root).some((name) => name.includes(markerToken)), false);
fs.rmSync(fx.sandbox, { recursive: true });
});
test("layout cleanup removes only exact marker-owned stages left before publication", () => {
const fx = fixture();
fs.writeFileSync(path.join(fx.root, "unmanaged.txt"), "mine\n");
fs.rmSync(fx.skillsDirectory, { recursive: true });
fs.rmSync(fx.transactionDirectory, { recursive: true });
const inspected = inspectLayout(fx.adapter, { host: "codex", scope: "project", identityDigest: TARGET_ID });
const markerToken = "e".repeat(48);
const markerName = `.aas-layout-recovery-${"f".repeat(32)}`;
for (const directory of inspected.missingDirectories) {
const stage = path.join(path.dirname(directory), `.aas-layout-stage-${markerToken}-${path.basename(directory)}`);
fs.mkdirSync(stage, { mode: 0o700 });
fs.writeFileSync(path.join(stage, markerName), `${markerToken}\n`, { mode: 0o600 });
}
assert.ok(remainingMaterializedLayoutPaths(inspected, inspected.missingDirectories, { markerName, markerToken }).length > 0);
cleanupMaterializedLayout(inspected, inspected.missingDirectories, { markerName, markerToken });
assert.deepEqual(remainingMaterializedLayoutPaths(inspected, inspected.missingDirectories, { markerName, markerToken }), []);
assert.equal(fs.readdirSync(fx.root).some((name) => name.includes(markerToken)), false);
assert.equal(fs.readFileSync(path.join(fx.root, "unmanaged.txt"), "utf8"), "mine\n");
assert.equal(fs.existsSync(fx.skillsDirectory), false);
assert.equal(fs.existsSync(fx.transactionDirectory), false);
fs.rmSync(fx.sandbox, { recursive: true });
});
test("layout cleanup postcondition detects a dangling symlink artifact", (t) => {
const fx = fixture();
fs.rmSync(fx.transactionDirectory, { recursive: true });
const inspected = inspectLayout(fx.adapter, { host: "codex", scope: "project", identityDigest: TARGET_ID });
const markerToken = "9".repeat(48);
const markerName = `.aas-layout-recovery-${"8".repeat(32)}`;
const directory = inspected.missingDirectories[0];
const stage = path.join(path.dirname(directory), `.aas-layout-stage-${markerToken}-${path.basename(directory)}`);
fs.mkdirSync(path.dirname(stage), { recursive: true });
try {
fs.symlinkSync(path.join(fx.root, "missing-target"), stage, "dir");
} catch (error) {
if (["EPERM", "EACCES", "ENOSYS"].includes(error.code)) {
fs.rmSync(fx.sandbox, { recursive: true });
t.skip(`symlink unavailable: ${error.code}`);
return;
}
throw error;
}
assert.deepEqual(remainingMaterializedLayoutPaths(inspected, [directory], { markerName, markerToken }), [
path.relative(inspected.root, stage).split(path.sep).join("/"),
]);
fs.unlinkSync(stage);
assert.deepEqual(remainingMaterializedLayoutPaths(inspected, [directory], { markerName, markerToken }), []);
fs.rmSync(fx.sandbox, { recursive: true });
});
test("alreadyApplied verifies final bytes and refuses a completed state with drift or recovery artifacts", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
applyPlan({ plan, adapter: fx.adapter, approvalDigest: plan.digest });
fs.writeFileSync(path.join(fx.skillsDirectory, "alpha", "SKILL.md"), "tampered\n");
assert.throws(() => applyPlan({ plan, adapter: fx.adapter, approvalDigest: plan.digest }), { code: "AAS_TRANSACTION_FINAL_STATE_DRIFT" });
fs.writeFileSync(path.join(fx.skillsDirectory, "alpha", "SKILL.md"), "# Alpha\n");
const recoveryId = recoveryIdFor(plan.digest, TARGET_ID);
createJournal(fx.root, recoveryId, plan.digest, TARGET_ID);
assert.throws(() => applyPlan({ plan, adapter: fx.adapter, approvalDigest: plan.digest }), { code: "AAS_TRANSACTION_RECOVERY_REQUIRED" });
fs.rmSync(fx.sandbox, { recursive: true });
});
test("unmanaged collision and target identity drift fail before writes", () => {
const fx = fixture();
writeTree(path.join(fx.skillsDirectory, "alpha"), { "personal.txt": "mine" });
const plan = buildInstallPlan(fx);
const before = snapshot(fx.root);
assert.throws(() => preflight({ plan, adapter: fx.adapter }), { code: "AAS_TRANSACTION_UNMANAGED_COLLISION" });
assert.deepEqual(snapshot(fx.root), before);
const drifting = { ...fx.adapter, computeTargetIdentity() { return DIGEST("f"); } };
assert.throws(() => preflight({ plan, adapter: drifting }), { code: "AAS_TRANSACTION_TARGET_DRIFT" });
fs.rmSync(fx.sandbox, { recursive: true });
});
test("target lock is held before materialization and preflight, preventing concurrent stale plans", () => {
const fx = fixture();
const first = buildInstallPlan(fx, "alpha");
const second = buildInstallPlan(fx, "beta");
let concurrentCode = null;
const result = applyPlan({
plan: first,
adapter: fx.adapter,
approvalDigest: first.digest,
onBoundary(name) {
if (name !== "lockAcquired" || concurrentCode) return;
try {
applyPlan({ plan: second, adapter: fx.adapter, approvalDigest: second.digest });
} catch (error) {
concurrentCode = error.code;
}
},
});
assert.equal(result.status, "applied");
assert.equal(concurrentCode, "AAS_TRANSACTION_LOCKED");
const state = readManagedState(fx.stateFile);
assert.deepEqual(state.entries.map((entry) => entry.skillId), ["alpha"]);
assert.equal(fs.existsSync(path.join(fx.skillsDirectory, "beta")), false);
fs.rmSync(fx.sandbox, { recursive: true });
});
test("managed local edits block unless the immutable plan carries an explicit backed-up override", () => {
const fx = fixture();
const initial = buildInstallPlan(fx);
applyPlan({ plan: initial, adapter: fx.adapter, approvalDigest: initial.digest });
fs.writeFileSync(path.join(fx.skillsDirectory, "alpha", "SKILL.md"), "# locally edited\n");
const blocked = buildReplacePlan(fx, { allowDrift: false });
assert.throws(() => preflight({ plan: blocked.plan, adapter: blocked.adapter }), { code: "AAS_TRANSACTION_MANAGED_DRIFT" });
const approved = buildReplacePlan(fx, { allowDrift: true });
assert.equal(applyPlan({ plan: approved.plan, adapter: approved.adapter, approvalDigest: approved.plan.digest }).status, "applied");
assert.equal(treeDigest(path.join(fx.skillsDirectory, "alpha")), approved.resultDigest);
fs.rmSync(fx.sandbox, { recursive: true });
});
test("fault after promotion rolls back bytes and requires approved cleanup before reuse", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
let injected = false;
assert.throws(() => applyPlan({
plan,
adapter: fx.adapter,
approvalDigest: plan.digest,
onBoundary(name) {
if (name === "destinationPromoted" && !injected) {
injected = true;
throw new Error("fault");
}
},
}), { code: "AAS_TRANSACTION_APPLY_ROLLED_BACK" });
assert.equal(fs.existsSync(path.join(fx.skillsDirectory, "alpha")), false);
assert.equal(fs.existsSync(fx.stateFile), false);
assert.throws(() => applyPlan({ plan, adapter: fx.adapter, approvalDigest: plan.digest }), { code: "AAS_TRANSACTION_RECOVERY_REQUIRED" });
const diagnosisBefore = snapshot(fx.root);
const diagnosis = doctor({ target: plan.payload.target, adapter: fx.adapter });
assert.equal(diagnosis.status, "recoveryRequired");
assert.deepEqual(snapshot(fx.root), diagnosisBefore, "doctor must be read-only");
const cleanup = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId: diagnosis.recoveries[0].recoveryId, action: "cleanup" });
assert.throws(() => recover({ recoveryPlan: cleanup, plan, adapter: fx.adapter, approvalDigest: DIGEST("0") }), { code: "AAS_RECOVERY_APPROVAL_MISMATCH" });
assert.equal(recover({ recoveryPlan: cleanup, plan, adapter: fx.adapter, approvalDigest: cleanup.digest }).status, "cleaned");
assert.equal(applyPlan({ plan, adapter: fx.adapter, approvalDigest: plan.digest }).status, "applied");
fs.rmSync(fx.sandbox, { recursive: true });
});
test("rollback restores a pre-existing empty managed-state file byte-for-byte", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
const emptyState = buildManagedState({
target: plan.payload.target,
catalog: CATALOG,
entries: [],
completedPlanDigests: [],
});
const previousBytes = `${canonicalJson(emptyState)}\n`;
fs.writeFileSync(fx.stateFile, previousBytes);
assert.throws(() => applyPlan({
plan,
adapter: fx.adapter,
approvalDigest: plan.digest,
onBoundary(name) {
if (name === "managedStateCommitted") throw new Error("fault after state promote");
},
}), { code: "AAS_TRANSACTION_APPLY_ROLLED_BACK" });
assert.equal(fs.readFileSync(fx.stateFile, "utf8"), previousBytes);
assert.equal(fs.existsSync(path.join(fx.skillsDirectory, "alpha")), false);
const diagnosis = doctor({ target: plan.payload.target, adapter: fx.adapter });
const cleanup = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId: diagnosis.recoveries[0].recoveryId, action: "cleanup" });
assert.equal(recover({ recoveryPlan: cleanup, plan, adapter: fx.adapter, approvalDigest: cleanup.digest }).status, "cleaned");
fs.rmSync(fx.sandbox, { recursive: true });
});
test("explicit rollback is digest-bound and refuses destination drift", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
const recoveryId = recoveryIdFor(plan.digest, TARGET_ID);
const root = path.join(fx.transactionDirectory, recoveryId);
fs.mkdirSync(root, { mode: 0o700 });
const journal = createJournal(fx.root, recoveryId, plan.digest, TARGET_ID);
fs.renameSync(path.join(fx.sources, "alpha"), path.join(fx.skillsDirectory, "alpha"));
appendRecord(journal, "destinationPromoted", { skillId: "alpha", treeDigest: plan.payload.operations[0].resultTreeDigest });
const recoveryPlan = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId, action: "rollback" });
const misleading = structuredClone(recoveryPlan);
misleading.payload.operations = [];
misleading.digest = sha256(canonicalJson(misleading.payload));
assert.throws(() => recover({ recoveryPlan: misleading, plan, adapter: fx.adapter, approvalDigest: misleading.digest }), { code: "AAS_RECOVERY_OPERATIONS_MISMATCH" });
fs.writeFileSync(path.join(fx.skillsDirectory, "alpha", "SKILL.md"), "tampered\n");
assert.throws(() => recover({ recoveryPlan, plan, adapter: fx.adapter, approvalDigest: recoveryPlan.digest }), { code: "AAS_RECOVERY_PRECONDITION_DRIFT" });
fs.writeFileSync(path.join(fx.skillsDirectory, "alpha", "SKILL.md"), "# Alpha\n");
assert.equal(recover({ recoveryPlan, plan, adapter: fx.adapter, approvalDigest: recoveryPlan.digest }).status, "rolledBack");
assert.equal(fs.existsSync(path.join(fx.skillsDirectory, "alpha")), false);
const cleanup = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId, action: "cleanup" });
assert.equal(recover({ recoveryPlan: cleanup, plan, adapter: fx.adapter, approvalDigest: cleanup.digest }).status, "cleaned");
fs.rmSync(fx.sandbox, { recursive: true });
});
test("recovery never retires an apply lock owned by a live process", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
const ready = preflight({ plan, adapter: fx.adapter });
const applyLock = acquireLock(ready.layout, plan);
const recoveryId = recoveryIdFor(plan.digest, TARGET_ID);
createJournal(fx.root, recoveryId, plan.digest, TARGET_ID);
const recoveryPlan = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId, action: "cleanup" });
assert.throws(() => recover({ recoveryPlan, plan, adapter: fx.adapter, approvalDigest: recoveryPlan.digest }), { code: "AAS_TRANSACTION_LOCK_LIVE_OR_UNKNOWN" });
assert.equal(fs.existsSync(applyLock.path), true);
releaseLock(applyLock);
fs.rmSync(fx.sandbox, { recursive: true });
});
test("doctor exposes and recovery retires a dead standalone recovery guard", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
const ready = preflight({ plan, adapter: fx.adapter });
const guard = acquireLock(ready.layout, plan, "recovery-guard");
fs.closeSync(guard.descriptor);
const record = { ...guard.record, pid: 2147483647 };
fs.writeFileSync(guard.path, `${canonicalJson(record)}\n`);
const diagnosis = doctor({ target: plan.payload.target, adapter: fx.adapter });
assert.equal(diagnosis.status, "recoveryRequired");
assert.equal(diagnosis.recoveries.length, 1);
const cleanup = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId: diagnosis.recoveries[0].recoveryId, action: "cleanup" });
assert.equal(recover({ recoveryPlan: cleanup, plan, adapter: fx.adapter, approvalDigest: cleanup.digest }).status, "cleaned");
assert.equal(fs.readdirSync(fx.root).some((name) => name.includes("transaction-recovery.lock")), false);
fs.rmSync(fx.sandbox, { recursive: true });
});
test("a partial bootstrap record is recoverable only before a root WAL exists", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
const ready = preflight({ plan, adapter: fx.adapter });
const applyLock = acquireLock(ready.layout, plan);
fs.closeSync(applyLock.descriptor);
fs.writeFileSync(applyLock.path, `${canonicalJson({ ...applyLock.record, pid: 2147483647 })}\n`);
const recoveryId = recoveryIdFor(plan.digest, TARGET_ID);
const bootstrap = path.join(fx.root, `.aas-bootstrap-${recoveryId}.json`);
fs.writeFileSync(bootstrap, '{"partial":');
const pendingWal = `${journalPath(fx.root, recoveryId)}.pending-${applyLock.token}`;
fs.writeFileSync(pendingWal, '{"partialWal":');
const diagnosis = doctor({ target: plan.payload.target, adapter: fx.adapter });
assert.equal(diagnosis.status, "recoveryRequired");
assert.equal(diagnosis.recoveries[0].recoveryId, recoveryId);
const cleanup = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId, action: "cleanup" });
assert.equal(recover({ recoveryPlan: cleanup, plan, adapter: fx.adapter, approvalDigest: cleanup.digest }).status, "cleaned");
assert.equal(fs.existsSync(bootstrap), false);
assert.equal(fs.existsSync(pendingWal), false);
fs.rmSync(fx.sandbox, { recursive: true });
});
test("recovery repairs only an approved torn WAL tail", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
assert.throws(() => applyPlan({
plan,
adapter: fx.adapter,
approvalDigest: plan.digest,
onBoundary(name) {
if (name === "destinationPromoted") throw new Error("fault");
},
}), { code: "AAS_TRANSACTION_APPLY_ROLLED_BACK" });
const recoveryId = recoveryIdFor(plan.digest, TARGET_ID);
const wal = journalPath(fx.root, recoveryId);
fs.appendFileSync(wal, '{"partial":');
const diagnosis = doctor({ target: plan.payload.target, adapter: fx.adapter });
assert.equal(diagnosis.status, "recoveryRequired");
const cleanup = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId, action: "cleanup" });
assert.match(cleanup.payload.checkpoint.tornTailDigest, /^sha256-[a-f0-9]{64}$/);
assert.equal(recover({ recoveryPlan: cleanup, plan, adapter: fx.adapter, approvalDigest: cleanup.digest }).status, "cleaned");
assert.equal(fs.existsSync(wal), false);
fs.rmSync(fx.sandbox, { recursive: true });
});
test("the same approved recovery plan resumes after a crash between mutation and WAL completion", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
const recoveryId = recoveryIdFor(plan.digest, TARGET_ID);
const root = path.join(fx.transactionDirectory, recoveryId);
fs.mkdirSync(root, { mode: 0o700 });
const journal = createJournal(fx.root, recoveryId, plan.digest, TARGET_ID);
fs.renameSync(path.join(fx.sources, "alpha"), path.join(fx.skillsDirectory, "alpha"));
appendRecord(journal, "mutationIntent", {
actionId: "apply:promote:alpha", phase: "apply", kind: "rename", logicalId: "alpha",
beforeDigest: null, afterDigest: plan.payload.operations[0].resultTreeDigest,
});
const recoveryPlan = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId, action: "rollback" });
let killed = false;
assert.throws(() => recover({
recoveryPlan,
plan,
adapter: fx.adapter,
approvalDigest: recoveryPlan.digest,
onBoundary(name) {
if (name === "rollback:discard-new:alpha:mutated" && !killed) {
killed = true;
throw new Error("simulated hard stop");
}
},
}), /simulated hard stop/);
assert.equal(fs.existsSync(path.join(fx.skillsDirectory, "alpha")), false);
fs.appendFileSync(journalPath(fx.root, recoveryId), '{"partialRecovery":');
assert.equal(recover({ recoveryPlan, plan, adapter: fx.adapter, approvalDigest: recoveryPlan.digest }).status, "rolledBack");
const cleanup = buildRecoveryPlan({ plan, adapter: fx.adapter, recoveryId, action: "cleanup" });
assert.equal(recover({ recoveryPlan: cleanup, plan, adapter: fx.adapter, approvalDigest: cleanup.digest }).status, "cleaned");
fs.rmSync(fx.sandbox, { recursive: true });
});
test("plan physical paths are ignored and adapter containment is enforced", () => {
const fx = fixture();
const plan = buildInstallPlan(fx);
assert.equal(canonicalJson(plan).includes(fx.root), false);
const escaping = {
...fx.adapter,
resolveTransactionLayout() {
return { root: fx.root, skillsDirectory: fx.skillsDirectory, stateFile: path.join(fx.sandbox, "outside.json"), transactionDirectory: fx.transactionDirectory };
},
};
assert.throws(() => preflight({ plan, adapter: escaping }), { code: "AAS_TRANSACTION_PATH_OUTSIDE_TARGET" });
fs.rmSync(fx.sandbox, { recursive: true });
});