test: read full run context and compare exact warm file bytes

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-09-08 23:59:55 -05:00
1 parent fb7914651b
commit 1d6ee1a642
4 files changed
+158 -35

No files matched your search

+12
View File
@@ -357,3 +357,15 @@ binary. An older binary is replaced with the app’s compatible artifact through
a temporary file and atomic rename, preserving image symlink targets and the
previous launcher on interrupted uploads. The durable checkpoint contract stays
at version 2 so existing native session backups remain restorable.
Warm continuity qualification reads the full run record before selecting the
persistence contract; company run listings omit the scoped-folder manifest.
Each completed scoped turn must have its own successful final save before the
harness reads cached bytes. Legacy host-workspace fallback is used only when
the full run record has no scoped manifest.
The three-turn fixture supplies a shell script that compares exact bytes before
appending and after writing. Missing or changed prior content fails without
repair; repeating the first turn cannot truncate existing work. This avoids
model-generated byte-count arithmetic while retaining independent per-turn
persistence checks and the same-sandbox, same-provider continuity requirements.
+27 -3
View File
@@ -776,6 +776,26 @@ function warmWorkspaceLine(turn: 1 | 2 | 3, nonce: string) {
return `T${turn}-${nonce}`;
}
function warmWorkspaceScript(turn: 1 | 2 | 3, nonce: string) {
if (!/^[a-zA-Z0-9-]+$/.test(nonce)) {
throw new Error("Invalid warm fixture nonce");
}
const lines = Array.from({ length: turn }, (_, index) =>
warmWorkspaceLine((index + 1) as 1 | 2 | 3, nonce),
);
const expected = (values: string[]) =>
`printf '%s\\n' ${values.map((line) => `'${line}'`).join(" ")}`;
return [
"set -eu",
`target="\${PAPERCLIP_TASK_DIR:-$PWD}/daytona-warm-${nonce}.txt"`,
turn === 1
? '[ ! -e "$target" ]'
: `${expected(lines.slice(0, -1))} | cmp - "$target"`,
`${expected([lines.at(-1)!])} >> "$target"`,
`${expected(lines)} | cmp - "$target"`,
].join("\n");
}
function warmTurnInstructions(turn: 1 | 2 | 3, nonce: string) {
const file = `"\${PAPERCLIP_TASK_DIR:-$PWD}/daytona-warm-${nonce}.txt"`;
const lines = Array.from({ length: turn }, (_, index) =>
@@ -789,9 +809,13 @@ function warmTurnInstructions(turn: 1 | 2 | 3, nonce: string) {
return [
`This is warm Daytona continuity turn ${turn} of 3. Use ${file} for every read and write. Expand this shell path inside each tool invocation; do not rely on a directory change in a previous shell call. The host-supplied task folder takes precedence over the current directory.`,
turn === 1
? `Create ${file} with exactly this one line followed by a newline: ${lines[0]}`
: `Before changing anything, read ${file} and verify its content is exactly ${lines.slice(0, -1).join("\\n")} followed by a newline. Then append exactly ${lines.at(-1)} followed by a newline.`,
`After the write, verify ${file} contains exactly these lines, once each and in order: ${lines.join(" | ")}.`,
? `The script below creates ${file} with exactly this one line followed by a newline: ${lines[0]}`
: `The script below first checks ${file} contains exactly ${lines.slice(0, -1).join("\\n")} followed by a newline, then appends exactly ${lines.at(-1)} followed by a newline.`,
`The final comparison requires ${file} to contain exactly these lines, once each and in order: ${lines.join(" | ")}.`,
"Execute this exact shell script once for the file operation and verification. It compares every byte, including the final newline; do not add guessed byte counts. If it fails, report the failure and do not repair the file or claim success. Only after it succeeds perform the runner-specific completion below.",
"```sh",
warmWorkspaceScript(turn, nonce),
"```",
`In a native runner, call paperclip_finish exactly once with {reportedWorkDisposition:"${finalTurn ? "done" : "needs_review"}",summary:"${marker}",completionClaim:{contractRevision:"1",objectiveSatisfied:true,criteria:[{criterionId:"objective",status:"satisfied",evidenceRefs:[]}],remainingWork:[]},evidence:[],verification:[{commandOrCheck:${JSON.stringify(`read ${file}`)},status:"passed"}]}. Wait for that tool call to succeed, then emit exactly ${marker} once as the complete user-facing final response.`,
legacyCompletion,
`In a legacy runner, the PATCH comment is the complete visible response. After its 2xx response, finish silently: do not print, echo, or emit ${marker} again as assistant text.`,
+98 -30
View File
@@ -40,23 +40,33 @@ async function fixture() {
status: () => 200,
text: async () => "T1-nonce\n",
};
const fullRun = {
id: "run",
companyId: "company",
agentId: "agent",
contextSnapshot: { paperclipWorkFolders: binding } as Record<
string,
unknown
> | null,
};
const api = {
get: vi.fn().mockResolvedValue([saved]),
get: vi
.fn()
.mockImplementation(async (url: string) =>
url === "/api/heartbeat-runs/run" ? fullRun : [saved],
),
request: { get: vi.fn().mockResolvedValue(response) },
};
return {
input: {
api,
run: {
id: "run",
companyId: "company",
agentId: "agent",
contextSnapshot: { paperclipWorkFolders: binding },
},
run: { id: "run", companyId: "company", agentId: "agent" },
issueId: "task",
workspacePath,
filename: "daytona-warm-nonce.txt",
},
fullRun,
binding,
saved,
};
}
@@ -75,16 +85,13 @@ describe("warm workspace persistence observation", () => {
daytonaWarmContinuityTask.buildPrompt("nonce"),
...daytonaWarmContinuityTask.buildFollowupMessages!("nonce"),
];
for (const [index, prompt] of prompts.entries()) {
const shellPath = prompt.match(
/Use ("[^"\n]+") for every read and write\./,
)?.[1];
expect(shellPath).toBeTruthy();
await promisify(execFile)(
"sh",
["-c", `printf 'T${index + 1}-nonce\\n' >> ${shellPath}`],
{ cwd: input.workspacePath, env },
);
for (const prompt of prompts) {
const script = prompt.match(/```sh\n([\s\S]*?)\n```/)?.[1];
expect(script).toBeTruthy();
await promisify(execFile)("sh", ["-c", script!], {
cwd: input.workspacePath,
env,
});
}
expect(
await readFile(
@@ -102,7 +109,48 @@ describe("warm workspace persistence observation", () => {
},
);
it("reads the saved scoped file without requiring a mirrored host file", async () => {
it.each([undefined, "wrong\n", "T1-nonce", "T1-nonce\n\n"])(
"rejects missing or changed prior content without repairing it: %j",
async (prior) => {
const { input } = await fixture();
const filename = path.join(input.workspacePath, input.filename);
if (prior !== undefined) await writeFile(filename, prior);
const prompt =
daytonaWarmContinuityTask.buildFollowupMessages!("nonce")[0]!;
const script = prompt.match(/```sh\n([\s\S]*?)\n```/)![1]!;
await expect(
promisify(execFile)("sh", ["-c", script], {
cwd: input.workspacePath,
env: { ...process.env, PAPERCLIP_TASK_DIR: input.workspacePath },
}),
).rejects.toThrow();
if (prior === undefined) {
await expect(readFile(filename)).rejects.toMatchObject({
code: "ENOENT",
});
} else {
expect(await readFile(filename, "utf8")).toBe(prior);
}
},
);
it("rejects repeating the initial write without truncating saved work", async () => {
const { input } = await fixture();
const filename = path.join(input.workspacePath, input.filename);
await writeFile(filename, "T1-nonce\n");
const script = daytonaWarmContinuityTask
.buildPrompt("nonce")
.match(/```sh\n([\s\S]*?)\n```/)![1]!;
await expect(
promisify(execFile)("sh", ["-c", script], {
cwd: input.workspacePath,
env: { ...process.env, PAPERCLIP_TASK_DIR: input.workspacePath },
}),
).rejects.toThrow();
expect(await readFile(filename, "utf8")).toBe("T1-nonce\n");
});
it("hydrates an abbreviated run before reading scoped bytes without a host mirror", async () => {
const { input } = await fixture();
expect(await readWarmWorkspaceFile(input)).toEqual({
source: "task-cache",
@@ -131,6 +179,27 @@ describe("warm workspace persistence observation", () => {
);
});
it("does not infer an unscoped run from another abbreviated API response", async () => {
const { input } = await fixture();
input.api.get.mockResolvedValue(input.run);
await writeFile(
path.join(input.workspacePath, input.filename),
"stale host copy",
);
await expect(readWarmWorkspaceFile(input)).rejects.toThrow(
"Full run context is required",
);
expect(input.api.request.get).not.toHaveBeenCalled();
});
it("rejects a full response for a different run", async () => {
const { input, fullRun } = await fixture();
fullRun.id = "different-run";
await expect(readWarmWorkspaceFile(input)).rejects.toThrow();
expect(input.api.get).toHaveBeenCalledTimes(1);
expect(input.api.request.get).not.toHaveBeenCalled();
});
it.each([
{ runId: "older-run" },
{ state: "failed" },
@@ -141,7 +210,7 @@ describe("warm workspace persistence observation", () => {
"rejects incomplete or unrelated checkpoint evidence: %j",
async (override) => {
const { input, saved } = await fixture();
input.api.get.mockResolvedValue([{ ...saved, ...override }]);
Object.assign(saved, override);
await expect(readWarmWorkspaceFile(input)).rejects.toThrow(
"successful final file save",
);
@@ -152,26 +221,25 @@ describe("warm workspace persistence observation", () => {
it.each(["runId", "companyId", "agentId", "taskId"] as const)(
"rejects a manifest with a different %s",
async (field) => {
const { input } = await fixture();
input.run.contextSnapshot.paperclipWorkFolders[field] = "other";
const { input, binding } = await fixture();
binding[field] = "other";
await expect(readWarmWorkspaceFile(input)).rejects.toThrow();
expect(input.api.get).not.toHaveBeenCalled();
expect(input.api.get).toHaveBeenCalledTimes(1);
},
);
it("keeps the host workspace contract when the run has no scoped manifest", async () => {
const { input } = await fixture();
const { input, fullRun } = await fixture();
fullRun.contextSnapshot = null;
await writeFile(
path.join(input.workspacePath, input.filename),
"T1-local\n",
);
expect(
await readWarmWorkspaceFile({
...input,
run: { ...input.run, contextSnapshot: null },
}),
).toEqual({ source: "host-workspace", content: "T1-local\n" });
expect(input.api.get).not.toHaveBeenCalled();
expect(await readWarmWorkspaceFile(input)).toEqual({
source: "host-workspace",
content: "T1-local\n",
});
expect(input.api.get).toHaveBeenCalledTimes(1);
expect(input.api.request.get).not.toHaveBeenCalled();
});
});
+21 -2
View File
@@ -16,7 +16,6 @@ export async function readWarmWorkspaceFile(input: {
id: string;
companyId: string;
agentId: string;
contextSnapshot?: Record<string, unknown> | null;
};
issueId: string;
workspacePath: string;
@@ -27,7 +26,27 @@ export async function readWarmWorkspaceFile(input: {
/^[a-zA-Z0-9-]+\.txt$/.test(filename),
"Invalid warm fixture filename",
);
const manifest = run.contextSnapshot?.paperclipWorkFolders;
// Company run listings summarize context. Absence there cannot establish
// that the run uses the legacy host-workspace contract.
const fullRun = await api.get<
typeof run & {
contextSnapshot: Record<string, unknown> | null;
}
>(`/api/heartbeat-runs/${encodeURIComponent(run.id)}`);
assert.equal(fullRun.id, run.id);
assert.equal(fullRun.companyId, run.companyId);
assert.equal(fullRun.agentId, run.agentId);
assert(
Object.hasOwn(fullRun, "contextSnapshot"),
"Full run context is required",
);
assert(
fullRun.contextSnapshot === null ||
(typeof fullRun.contextSnapshot === "object" &&
!Array.isArray(fullRun.contextSnapshot)),
"Invalid full run context",
);
const manifest = fullRun.contextSnapshot?.paperclipWorkFolders;
if (manifest === undefined || manifest === null) {
return {
source: "host-workspace",