mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-31 06:04:11 +01:00
Merge origin/master and preserve task workspace preparation
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
commit
3cfe5d58df
9 files changed
+1472
-928
No files matched your search
@@ -8501,12 +8501,10 @@ describeEmbeddedPostgres("heartbeat orphaned process recovery", () => {
|
||||
.set({ status: "paused" })
|
||||
.where(eq(agents.id, agentId));
|
||||
release();
|
||||
if (next!)
|
||||
await vi.waitFor(async () =>
|
||||
expect((await heartbeat.getRun(next!.id))?.status).not.toBe(
|
||||
"running",
|
||||
),
|
||||
);
|
||||
// Wait for the released executor and its cleanup, not the default
|
||||
// one-second polling window. The next case must not inherit live work.
|
||||
await heartbeat.drainActiveRunExecutions();
|
||||
if (next!) expect((await heartbeat.getRun(next!.id))?.status).not.toBe("running");
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -12146,7 +12144,9 @@ describeEmbeddedPostgres("heartbeat orphaned process recovery", () => {
|
||||
const legacyReviewBefore = withLegacyReview
|
||||
? await db.select().from(issues).where(eq(issues.id, legacyReviewId))
|
||||
: [];
|
||||
mockAdapterExecute.mockImplementationOnce(async () => {
|
||||
let planOnlyRunId = "";
|
||||
mockAdapterExecute.mockImplementationOnce(async (input?: unknown) => {
|
||||
planOnlyRunId = (input as { runId: string }).runId;
|
||||
if (withLegacyReview) {
|
||||
// These pre-dispatch cancellations used to satisfy both the no-comment
|
||||
// and churn thresholds and suppress an otherwise valid continuation.
|
||||
@@ -12170,17 +12170,23 @@ describeEmbeddedPostgres("heartbeat orphaned process recovery", () => {
|
||||
await heartbeat.reconcileStrandedAssignedIssues();
|
||||
await heartbeat.promoteDueScheduledRetries(new Date(Date.now() + 31_000));
|
||||
await heartbeat.resumeQueuedRuns();
|
||||
// The continuation is produced by completion; wait for that durable boundary.
|
||||
await heartbeat.drainActiveRunExecutions();
|
||||
|
||||
const livenessWake = await waitForValue(async () => {
|
||||
expect(planOnlyRunId).not.toBe("");
|
||||
const livenessWakes = await waitForValue(async () => {
|
||||
const rows = await db
|
||||
.select()
|
||||
.from(agentWakeupRequests)
|
||||
.where(eq(agentWakeupRequests.agentId, agentId));
|
||||
return (
|
||||
rows.find((row) => row.reason === "issue_disposition_repair") ?? null
|
||||
);
|
||||
// Follow-up repairs can already exist. Match this plan-only result,
|
||||
// rather than relying on the database's unordered row order.
|
||||
const matching = rows.filter((row) => row.reason === "issue_disposition_repair"
|
||||
&& row.payload?.retryOfRunId === planOnlyRunId);
|
||||
return matching.length > 0 ? matching : null;
|
||||
});
|
||||
expect(livenessWake).toBeTruthy();
|
||||
expect(livenessWakes).toHaveLength(1);
|
||||
const livenessWake = livenessWakes![0]!;
|
||||
expect(livenessWake?.payload).toMatchObject({
|
||||
issueId,
|
||||
dispositionRepairAttempt: 1,
|
||||
@@ -12189,7 +12195,7 @@ describeEmbeddedPostgres("heartbeat orphaned process recovery", () => {
|
||||
const sourceRunId = (
|
||||
livenessWake?.payload as Record<string, unknown> | null
|
||||
)?.retryOfRunId;
|
||||
expect(sourceRunId).toBeTruthy();
|
||||
expect(sourceRunId).toBe(planOnlyRunId);
|
||||
const sourceRun = await db
|
||||
.select()
|
||||
.from(heartbeatRuns)
|
||||
|
||||
Reference in new issue
Block a user