fix: inherit run scope for scheduled retries

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-08-01 22:54:01 +00:00
1 parent 67044f91a6
commit 75ac8b4dbb
3 files changed
+38 -2

No files matched your search

@@ -142,10 +142,21 @@ describeEmbeddedPostgres("activity service", () => {
permissions: {},
});
await db.insert(issues).values({
id: issueId,
companyId,
title: "Summarize a completed run",
status: "done",
priority: "medium",
assigneeAgentId: agentId,
});
await db.insert(heartbeatRuns).values({
id: runId,
companyId,
agentId,
scopeKind: "issue",
issueId,
invocationSource: "assignment",
status: "succeeded",
contextSnapshot: { issueId },
@@ -256,6 +267,8 @@ describeEmbeddedPostgres("activity service", () => {
id: runId,
companyId,
agentId,
scopeKind: "issue",
issueId,
invocationSource: "assignment",
status: "succeeded",
startedAt: new Date("2026-04-18T20:00:00.000Z"),
@@ -350,6 +363,8 @@ describeEmbeddedPostgres("activity service", () => {
id: runId,
companyId,
agentId,
scopeKind: "issue",
issueId,
invocationSource: "assignment",
status: "succeeded",
startedAt: new Date("2026-04-18T20:00:00.000Z"),
@@ -365,6 +380,8 @@ describeEmbeddedPostgres("activity service", () => {
id: otherRunId,
companyId,
agentId,
scopeKind: "issue",
issueId,
invocationSource: "assignment",
status: "succeeded",
startedAt: new Date("2026-04-18T20:05:00.000Z"),
@@ -472,6 +489,8 @@ describeEmbeddedPostgres("activity service", () => {
id: runId,
companyId,
agentId,
scopeKind: "issue",
issueId,
invocationSource: "assignment",
status: "succeeded",
startedAt: new Date("2026-04-18T20:10:00.000Z"),
@@ -380,6 +380,11 @@ describeEmbeddedPostgres("heartbeat bounded retry scheduling", () => {
identifier: `${issuePrefix}-1`,
});
// Complete the circular issue/run fixture after both FK targets exist.
await db.update(heartbeatRuns)
.set({ scopeKind: "issue", issueId })
.where(eq(heartbeatRuns.id, runId));
return { companyId, agentId, issueId, runId, now };
}
@@ -1755,6 +1760,9 @@ describeEmbeddedPostgres("heartbeat bounded retry scheduling", () => {
issueNumber: 1,
identifier: `T${companyId.replace(/-/g, "").slice(0, 6).toUpperCase()}-2`,
});
await db.update(heartbeatRuns)
.set({ scopeKind: "issue", issueId })
.where(eq(heartbeatRuns.id, sourceRunId));
const scheduled = await heartbeat.scheduleBoundedRetry(sourceRunId, {
now,
@@ -1856,6 +1864,9 @@ describeEmbeddedPostgres("heartbeat bounded retry scheduling", () => {
issueNumber: 1,
identifier: `T${companyId.replace(/-/g, "").slice(0, 6).toUpperCase()}-3`,
});
await db.update(heartbeatRuns)
.set({ scopeKind: "issue", issueId })
.where(eq(heartbeatRuns.id, sourceRunId));
const scheduled = await heartbeat.scheduleBoundedRetry(sourceRunId, {
now,
@@ -1966,6 +1977,9 @@ describeEmbeddedPostgres("heartbeat bounded retry scheduling", () => {
issueNumber: 1,
identifier: `T${companyId.replace(/-/g, "").slice(0, 6).toUpperCase()}-3`,
});
await db.update(heartbeatRuns)
.set({ scopeKind: "issue", issueId })
.where(eq(heartbeatRuns.id, sourceRunId));
const scheduled = await heartbeat.scheduleBoundedRetry(sourceRunId, {
now,
+5 -2
View File
@@ -10511,7 +10511,10 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {})
: null;
const transientRetryNotBefore = transientRecovery?.retryNotBefore ?? null;
const contextSnapshot = parseObject(run.contextSnapshot);
const issueId = readNonEmptyString(contextSnapshot.issueId);
// A retry inherits the durable authorization scope of its source run. Do
// not promote an untrusted or legacy contextSnapshot.issueId into a new
// issue binding: that could either violate the FK or misclassify history.
const issueId = run.scopeKind === "issue" ? run.issueId : null;
if (!baseSchedule) {
await appendRunEvent(run, await nextRunEventSeq(run.id), {
@@ -10901,7 +10904,7 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {})
.values({
companyId: run.companyId,
agentId: run.agentId,
scopeKind: issueId ? "issue" : "company",
scopeKind: run.scopeKind,
issueId,
invocationSource: "automation",
triggerDetail: "system",