mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-07 06:16:06 -10:00
test(recovery): align retained allocation fixture with readiness (#18984)
## Thinking Path > - Paperclip manages AI agents and their work. > - Restart recovery must preserve the original remote allocation and its files. > - #18934 readies that same retained allocation before preparation. > - The older #18936 failure fixture rejects every readiness call. > - It stops before the intended preparation-failure boundary. > - This change updates only that fixture and checks the original allocation identity. ## Linked Issues or Issue Description **What happened?** The three remote preparation retention cases fail after #18934. Their driver stub throws `Reattachment must not resume the allocation`. The production code now calls readiness on the same validated lease before preparation, so the test never reaches its intended execution failure. **Expected behavior** The fixture should allow readiness of the original allocation. It must reject replacement acquisition and retain its preparation-error, ownership, saved-file and retention checks. **Steps to reproduce** Run `src/__tests__/heartbeat-native-remote-failure-retention.test.ts` on master `86814c6550`. All three cases stop at the stale readiness stub. Refs #18934 and #18936. This one-file baseline correction is split from #18970 so it can unblock the shared failure also observed on #18977. It carries no core API change or evaluation source pin. ## What Changed - Return the original lease from the fixture readiness stub. - Assert exactly one readiness call for the original company, environment, run, workspace, provider allocation and remote path. - Assert that no new allocation is acquired. Keep all existing preparation failure, ownership and retained-work assertions. ## Verification - Before #18934, the three existing cases passed locally. On the actual merged #18934 contract, they reproduced the three CI failures in 18.06 seconds. - With this fixture correction, all three passed in 11.83 seconds. Production runtime code and the original 60-second case deadline are unchanged. - The corrected test blob and its relevant production/helper blobs match the already-tested merged-source proof. Current master still has the same stale test blob; this isolated PR applies only the identical fixture correction. - Command from `server/`: `node ../node_modules/vitest/vitest.mjs run --config vitest.config.ts src/__tests__/heartbeat-native-remote-failure-retention.test.ts`. - `git diff --check` passes. Full repository typecheck/build were not rerun for this one-file fixture split; fresh normal CI and review are pending. - [Original failing CI job](https://github.com/paperclipai/paperclip/actions/runs/41855440307/job/126665077718). It remains failed; no remote retry was used as proof. ## Risks - Low scope: test fixture only. A readiness call for a replacement or wrong allocation fails the identity assertions. - This does not alter production recovery, permissions, cleanup policy, evaluation deadlines or grading. ## Model Used OpenAI `gpt-6.1-sol`, with reasoning, repository inspection, code editing and tool execution. The host did not expose the model context-window limit. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <[email protected]>
This commit is contained in:
1 parent
86814c6550
commit
04a24f4e06
1 file changed
+13
-3
@@ -11,7 +11,7 @@ import { appendHeartbeatRunEvent } from "../services/heartbeat-run-events.js";
|
||||
import { issueRecoveryActionService } from "../services/issue-recovery-actions.js";
|
||||
import { pinFailedObservedWorkspace } from "../services/native-runtime/native-observed-workspace-preservation.js";
|
||||
import { heartbeatService } from "../services/heartbeat.js";
|
||||
import { environmentRuntimeService, classifyEnvironmentCapabilities } from "../services/environment-runtime.js";
|
||||
import { environmentRuntimeService, classifyEnvironmentCapabilities, type EnvironmentDriverResumeInput } from "../services/environment-runtime.js";
|
||||
import { instanceSettingsService } from "../services/instance-settings.js";
|
||||
import { buildNativeExecutionInput } from "../services/native-runtime/native-execution-input.js";
|
||||
import { nativeRuntimeContextFixture } from "../services/native-runtime/runtime-context.test-fixture.js";
|
||||
@@ -107,9 +107,11 @@ describeEmbeddedPostgres("heartbeat native remote preparation failure retention"
|
||||
expect(await pinFailedObservedWorkspace(db, companyId, f.runId)).toBe(false);
|
||||
throw preparationFailure;
|
||||
});
|
||||
const acquireAllocation = vi.fn(async () => { throw new Error("Unexpected new allocation"); });
|
||||
const readyAllocation = vi.fn(async ({ lease }: EnvironmentDriverResumeInput) => lease);
|
||||
const runtime = environmentRuntimeService(db, { drivers: [{ driver: "sandbox",
|
||||
acquireRunLease: async () => { throw new Error("Unexpected new allocation"); },
|
||||
resumeRunLease: async () => { throw new Error("Reattachment must not resume the allocation"); },
|
||||
acquireRunLease: acquireAllocation,
|
||||
resumeRunLease: readyAllocation,
|
||||
releaseRunLease: async () => { throw new Error("Unexpected destructive cleanup"); },
|
||||
retryPendingSandboxTeardown: async () => { throw new Error("Stop must remain separately verified"); },
|
||||
realizeWorkspace: async () => { throw new Error("Unexpected workspace realization"); },
|
||||
@@ -124,6 +126,14 @@ describeEmbeddedPostgres("heartbeat native remote preparation failure retention"
|
||||
nativeSessionBackendFactory: () => { throw new Error("No provider backend may be created"); } });
|
||||
await heartbeat.recoverNativeRunsAfterRestart(new Date(), [f.runId]);
|
||||
await heartbeat.drainActiveRunExecutions();
|
||||
expect(readyAllocation).toHaveBeenCalledExactlyOnceWith({
|
||||
environment: expect.objectContaining({ id: environmentId }),
|
||||
lease: expect.objectContaining({ id: leaseId, companyId, environmentId,
|
||||
executionWorkspaceId: workspaceId, heartbeatRunId: f.runId, providerLeaseId,
|
||||
status: "active", leasePolicy: "ephemeral" }),
|
||||
requestedCwd: remoteCwd,
|
||||
});
|
||||
expect(acquireAllocation).not.toHaveBeenCalled();
|
||||
expect(resumed).toHaveBeenCalledOnce();
|
||||
const [run] = await db.select().from(heartbeatRuns).where(eq(heartbeatRuns.id, f.runId));
|
||||
expect(run.error).toBe(preparationFailure.message);
|
||||
|
||||
Reference in new issue
Block a user