Move bootstrap and instruction acceptance coverage to stacked PR

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-10 11:08:49 -05:00
1 parent ab5bb8552a
commit 26d404cbfe
2 files changed
+4 -77

No files matched your search

@@ -326,7 +326,7 @@ describe("executeNativeSession recovery", () => {
const completeRun = vi.fn(async () => {});
try {
const execution = executeNativeSession({
input, turnTimeoutMs, bootstrapTimeoutMs: 5,
input, turnTimeoutMs,
backend: {
async descriptor() { return { kind: "mock", name: "long-lived", version: "1", capabilities }; },
async openSession() { return session; },
@@ -2256,18 +2256,15 @@ describe("executeNativeSession recovery", () => {
runnerInstanceId: "runner-recovery",
controlPlaneInstanceId: "control-recovery",
timeoutMs: 5,
bootstrapTimeoutMs: 10,
});
const execution = execute();
const rejection = expect(execution).rejects.toThrow(
"native session bootstrap timed out after 10ms",
"native session bootstrap timed out after 5ms",
);
await bootstrapStarted;
expect(bootstrapSignal?.aborted).toBe(false);
await vi.advanceTimersByTimeAsync(5);
expect(bootstrapSignal?.aborted).toBe(false);
await vi.advanceTimersByTimeAsync(5);
await rejection;
expect(bootstrapSignal?.aborted).toBe(true);
expect(openRun).not.toHaveBeenCalled();
@@ -2662,7 +2659,6 @@ describe("executeNativeSession recovery", () => {
runnerInstanceId: "runner-recovery",
controlPlaneInstanceId: "control-recovery",
timeoutMs: 10,
bootstrapTimeoutMs: 100,
keepSessionOpen: true,
onSession: (current) => retainedSessions.push(current),
});
@@ -5517,7 +5513,6 @@ describe("executeNativeSession recovery", () => {
controlPlaneInstanceId: "control-recovery",
persistedSession: structuredClone(checkpoint),
timeoutMs: 5,
bootstrapTimeoutMs: 100,
onSession,
});
const rejection = expect(execution).rejects.toThrow(
@@ -5653,18 +5648,15 @@ describe("executeNativeSession recovery", () => {
controlPlaneInstanceId: "control-recovery",
persistedSession: structuredClone(checkpoint),
timeoutMs: 5,
bootstrapTimeoutMs: 10,
onSession,
});
const rejection = expect(execution).rejects.toThrow(
"native session replacement bootstrap timed out after 10ms",
"native session replacement bootstrap timed out after 5ms",
);
await replacementStarted;
expect(replacementSignal?.aborted).toBe(false);
await vi.advanceTimersByTimeAsync(5);
expect(replacementSignal?.aborted).toBe(false);
await vi.advanceTimersByTimeAsync(5);
await rejection;
expect(replacementSignal?.aborted).toBe(true);
expect(openRun).not.toHaveBeenCalled();
@@ -1,9 +1,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import * as fileStore from "../services/agent-file-store.js";
import * as persistentFiles from "../services/persistent-agent-files.js";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { agentInstructionsService } from "../services/agent-instructions.js";
type TestAgent = {
@@ -39,7 +37,6 @@ describe("agent instructions service", () => {
});
afterEach(async () => {
vi.restoreAllMocks();
if (originalPaperclipHome === undefined) delete process.env.PAPERCLIP_HOME;
else process.env.PAPERCLIP_HOME = originalPaperclipHome;
if (originalPaperclipInstanceId === undefined) delete process.env.PAPERCLIP_INSTANCE_ID;
@@ -62,68 +59,6 @@ describe("agent instructions service", () => {
if (entry === "../invalid") expect(bundle.warnings.length).toBeGreaterThan(0);
});
it.each(["explicit", "legacy"])("keeps %s external instructions on their configured root after selecting Boat", async (configuration) => {
const root = await makeTempDir("boat-external-instructions-"); cleanupDirs.add(root);
await fs.writeFile(path.join(root, "AGENTS.md"), "external authority");
await fs.writeFile(path.join(root, "NEXT.md"), "next external entry");
const agent = { ...makeAgent(configuration === "explicit"
? { instructionsBundleMode: "external", instructionsRootPath: root, instructionsEntryFile: "AGENTS.md" }
: { instructionsFilePath: path.join(root, "AGENTS.md") }), defaultEnvironmentId: "boat-environment" };
const remote = vi.spyOn(persistentFiles, "persistentAgentFiles").mockResolvedValue({ root: "/remote/personal" } as never);
const db = { transaction: vi.fn(async () => { throw new Error("Must not adopt external instructions"); }) };
const svc = agentInstructionsService(db as never);
expect((await svc.getBundle(agent)).rootPath).toBe(root);
expect((await svc.readFile(agent, "AGENTS.md")).content).toBe("external authority");
expect((await svc.exportFiles(agent)).files["AGENTS.md"]).toBe("external authority");
const updated = await svc.updateBundle(agent, { entryFile: "NEXT.md" });
expect(updated.bundle.mode).toBe("external");
expect(updated.bundle.rootPath).toBe(root);
expect(updated.bundle.entryFile).toBe("NEXT.md");
expect(remote).not.toHaveBeenCalled();
expect(db.transaction).not.toHaveBeenCalled();
});
it("excludes only home-level runtime files from remote listing and export", async () => {
const agent = makeAgent({ instructionsBundleMode: "managed" });
const list = vi.fn(async (relative = "") => {
if (relative === ".paperclip-runtime") throw new Error("Must not enumerate provider packs or session state");
if (!relative) return [{ name: "AGENTS.md", kind: "file", size: 12 }, { name: ".paperclip-runtime", kind: "directory", size: 0 }, { name: "notes", kind: "directory", size: 0 }];
if (relative === "notes") return [{ name: ".paperclip-runtime", kind: "directory", size: 0 }];
return [{ name: "user.md", kind: "file", size: 12 }];
});
const readBytes = vi.fn(async () => ({ bytes: Buffer.from("instructions"), sha256: "hash" }));
vi.spyOn(persistentFiles, "persistentAgentFiles").mockResolvedValue({ root: "/remote/home", list, readBytes } as never);
vi.spyOn(persistentFiles, "seedPersistentAgentHome").mockResolvedValue(undefined);
vi.spyOn(fileStore, "adoptAgentFiles").mockResolvedValue("/controller/home");
const db = { transaction: async (fn: (tx: unknown) => Promise<unknown>) => fn({ select: () => ({ from: () => ({ where: async () => [agent] }) }) }) };
const svc = agentInstructionsService(db as never);
expect((await svc.getBundle(agent)).files.map(file => file.path)).toEqual(["AGENTS.md", "notes/.paperclip-runtime/user.md"]);
expect((await svc.exportFiles(agent)).files).toEqual({ "AGENTS.md": "instructions", "notes/.paperclip-runtime/user.md": "instructions" });
expect(list).not.toHaveBeenCalledWith(".paperclip-runtime");
expect(readBytes).not.toHaveBeenCalledWith(expect.stringMatching(/^\.paperclip-runtime\//));
});
it("previews an explicit external-to-managed migration before adopting remote personal files", async () => {
const root = await makeTempDir("boat-instructions-migration-"); cleanupDirs.add(root);
await fs.writeFile(path.join(root, "AGENTS.md"), "external migration source");
const agent = makeAgent({ instructionsBundleMode: "external", instructionsRootPath: root, instructionsEntryFile: "AGENTS.md" });
const seedBytes = vi.fn();
vi.spyOn(persistentFiles, "persistentAgentFiles").mockResolvedValue({ root: "/remote/personal", seedBytes } as never);
const db = {
select: () => ({ from: () => ({ where: async () => [] }) }),
transaction: async (fn: (tx: unknown) => Promise<unknown>) => fn({
select: () => ({ from: () => ({ where: async () => [agent] }) }),
}),
};
const svc = agentInstructionsService(db as never);
const updated = await svc.updateBundle(agent, { mode: "managed" });
expect(updated.bundle.mode).toBe("managed");
expect(updated.bundle.rootPath).toBe(updated.bundle.managedRootPath);
expect(await fs.readFile(path.join(updated.bundle.managedRootPath, "AGENTS.md"), "utf8")).toBe("external migration source");
expect(seedBytes).not.toHaveBeenCalled();
expect(await fs.readFile(path.join(root, "AGENTS.md"), "utf8")).toBe("external migration source");
});
it("lists external bundles containing large binary assets", async () => {
const root = await makeTempDir("external-large-assets-"); cleanupDirs.add(root);
await fs.writeFile(path.join(root, "AGENTS.md"), "external instructions");