mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-29 04:25:52 +01:00
feat(workspaces): verify seeds and add managed repair
Replace binary readiness markers with an evidence-bearing seed manifest and enforce a shared validation contract for minimal and full clones. Add an exclusive audited database repair path with recoverable backup, bounded phase diagnostics, and healthy restart validation. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
4b968d8c05
commit
53a0aa3020
21 files changed
+1568
-154
No files matched your search
@@ -137,7 +137,10 @@ test("uses the base CLI when its import graph boots", () => {
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
const config = readWorktreeConfig(worktreeCwd);
|
||||
assert.equal(config.$meta.source, "fake-cli");
|
||||
assert.ok(fs.existsSync(path.join(worktreeCwd, ".paperclip", "seed-pending")));
|
||||
assert.equal(
|
||||
JSON.parse(fs.readFileSync(path.join(worktreeCwd, ".paperclip", "seed-manifest.json"), "utf8")).state,
|
||||
"pending",
|
||||
);
|
||||
const initInvocation = readCliInvocations(baseCwd).find(
|
||||
(args) => args[0] === "worktree" && args[1] === "init",
|
||||
);
|
||||
@@ -166,7 +169,10 @@ test("falls back to an isolated config when the base CLI cannot boot", () => {
|
||||
);
|
||||
const env = fs.readFileSync(path.join(worktreeCwd, ".paperclip", ".env"), "utf8");
|
||||
assert.match(env, /PAPERCLIP_IN_WORKTREE=true/);
|
||||
assert.ok(fs.existsSync(path.join(worktreeCwd, ".paperclip", "seed-pending")));
|
||||
assert.equal(
|
||||
JSON.parse(fs.readFileSync(path.join(worktreeCwd, ".paperclip", "seed-manifest.json"), "utf8")).state,
|
||||
"pending",
|
||||
);
|
||||
});
|
||||
|
||||
test("repairs an unhealthy base install under the lock and then uses the CLI", (t) => {
|
||||
@@ -271,7 +277,7 @@ test("runtime provisioning invokes ensure-seeded once and fast-exits after succe
|
||||
|
||||
const second = runRuntimeProvision(baseCwd, worktreeCwd);
|
||||
assert.equal(second.status, 0, second.stderr);
|
||||
assert.match(second.stderr, /already seeded; skipping/);
|
||||
assert.match(second.stderr, /already seeded.*skipping/);
|
||||
const ensureCallsAfterSecond = readCliInvocations(baseCwd)
|
||||
.filter((args) => args[0] === "worktree" && args[1] === "ensure-seeded");
|
||||
assert.equal(ensureCallsAfterSecond.length, 1);
|
||||
@@ -290,3 +296,22 @@ test("runtime provisioning leaves seed-pending in place when ensure-seeded fails
|
||||
assert.ok(fs.existsSync(path.join(worktreeCwd, ".paperclip", "seed-pending")));
|
||||
assert.ok(!fs.existsSync(path.join(worktreeCwd, ".paperclip", "seed-complete")));
|
||||
});
|
||||
|
||||
test("runtime provisioning does not trust a truncated verified manifest", () => {
|
||||
const baseCwd = makeBaseWorkspace({ helpExit: 0, initExit: 0, ensureExit: 4 });
|
||||
const worktreeCwd = makeTempDir("paperclip-provision-runtime-truncated-");
|
||||
fs.mkdirSync(path.join(worktreeCwd, ".paperclip"), { recursive: true });
|
||||
fs.writeFileSync(path.join(worktreeCwd, ".paperclip", "config.json"), "{}\n");
|
||||
fs.writeFileSync(
|
||||
path.join(worktreeCwd, ".paperclip", "seed-manifest.json"),
|
||||
JSON.stringify({ version: 2, state: "verified" }),
|
||||
);
|
||||
|
||||
const result = runRuntimeProvision(baseCwd, worktreeCwd);
|
||||
assert.equal(result.status, 4, result.stderr);
|
||||
assert.equal(
|
||||
readCliInvocations(baseCwd)
|
||||
.filter((args) => args[0] === "worktree" && args[1] === "ensure-seeded").length,
|
||||
1,
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user