fix(adapters): preserve issue reports through delivery

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-07-12 16:46:34 +00:00
1 parent b996985902
commit 27dd2d5cc7
3 files changed
+83 -2

No files matched your search

@@ -821,6 +821,36 @@ describe("renderPaperclipWakePrompt", () => {
);
});
it("preserves cross-issue reports in adapter payloads and prompts", () => {
const payload = {
reports: [
{
id: "report-1",
targetIssueId: "issue-target",
originIssueId: "issue-origin",
originRunId: "run-origin",
originAgentId: "agent-origin",
fingerprint: "audit-result",
payload: {
type: "audit.result",
summary: "Audit passed",
data: { checks: 9 },
},
wakeRequested: true,
createdAt: "2026-07-12T16:00:00.000Z",
},
],
};
const serialized = stringifyPaperclipWakePayload(payload);
expect(JSON.parse(serialized ?? "{}")).toMatchObject(payload);
const prompt = renderPaperclipWakePrompt(payload);
expect(prompt).toContain("Cross-issue reports in delivery order:");
expect(prompt).toContain("report report-1 from issue issue-origin run run-origin");
expect(prompt).toContain('"summary":"Audit passed"');
});
it("escapes backticks and strips control characters in the branch guard", () => {
const prompt = renderPaperclipWakePrompt({
reason: "issue_assigned",
+53 -1
View File
@@ -615,6 +615,18 @@ type PaperclipWakeExecutionWorkspace = {
branchName: string | null;
};
type PaperclipWakeReport = {
id: string;
targetIssueId: string;
originIssueId: string;
originRunId: string;
originAgentId: string;
fingerprint: string;
payload: Record<string, unknown>;
wakeRequested: boolean;
createdAt: string | null;
};
type PaperclipWakePayload = {
reason: string | null;
issue: PaperclipWakeIssue | null;
@@ -639,6 +651,7 @@ type PaperclipWakePayload = {
commentIds: string[];
latestCommentId: string | null;
comments: PaperclipWakeComment[];
reports: PaperclipWakeReport[];
requestedCount: number;
includedCount: number;
missingCount: number;
@@ -681,6 +694,28 @@ function normalizePaperclipWakeComment(value: unknown): PaperclipWakeComment | n
};
}
function normalizePaperclipWakeReport(value: unknown): PaperclipWakeReport | null {
const report = parseObject(value);
const id = asString(report.id, "").trim();
const targetIssueId = asString(report.targetIssueId, "").trim();
const originIssueId = asString(report.originIssueId, "").trim();
const originRunId = asString(report.originRunId, "").trim();
const originAgentId = asString(report.originAgentId, "").trim();
const fingerprint = asString(report.fingerprint, "").trim();
if (!id || !targetIssueId || !originIssueId || !originRunId || !originAgentId || !fingerprint) return null;
return {
id,
targetIssueId,
originIssueId,
originRunId,
originAgentId,
fingerprint,
payload: parseObject(report.payload),
wakeRequested: asBoolean(report.wakeRequested, false),
createdAt: asString(report.createdAt, "").trim() || null,
};
}
function normalizePaperclipWakePlanReviewAuthor(value: unknown): PaperclipWakePlanReviewAuthor | null {
const author = parseObject(value);
const type = asString(author.type, "").trim() || null;
@@ -1175,6 +1210,11 @@ export function normalizePaperclipWakePayload(value: unknown): PaperclipWakePayl
.map((entry) => normalizePaperclipWakeComment(entry))
.filter((entry): entry is PaperclipWakeComment => Boolean(entry))
: [];
const reports = Array.isArray(payload.reports)
? payload.reports
.map((entry) => normalizePaperclipWakeReport(entry))
.filter((entry): entry is PaperclipWakeReport => Boolean(entry))
: [];
const commentWindow = parseObject(payload.commentWindow);
const commentIds = Array.isArray(payload.commentIds)
? payload.commentIds
@@ -1210,7 +1250,7 @@ export function normalizePaperclipWakePayload(value: unknown): PaperclipWakePayl
const activeTreeHold = normalizePaperclipWakeTreeHoldSummary(payload.activeTreeHold);
const checkboxSelection = normalizePaperclipWakeCheckboxSelection(payload.checkboxSelection);
const executionWorkspace = normalizePaperclipWakeExecutionWorkspace(payload.executionWorkspace);
if (comments.length === 0 && commentIds.length === 0 && annotationDeltas.length === 0 && childIssueSummaries.length === 0 && unresolvedBlockerIssueIds.length === 0 && unresolvedBlockerSummaries.length === 0 && !activeTreeHold && !executionStage && !continuationSummary && !planReviewContext && !livenessContinuation && !taskWatchdog && !checkboxSelection && !executionWorkspace && !normalizePaperclipWakeIssue(payload.issue)) {
if (comments.length === 0 && reports.length === 0 && commentIds.length === 0 && annotationDeltas.length === 0 && childIssueSummaries.length === 0 && unresolvedBlockerIssueIds.length === 0 && unresolvedBlockerSummaries.length === 0 && !activeTreeHold && !executionStage && !continuationSummary && !planReviewContext && !livenessContinuation && !taskWatchdog && !checkboxSelection && !executionWorkspace && !normalizePaperclipWakeIssue(payload.issue)) {
return null;
}
@@ -1238,6 +1278,7 @@ export function normalizePaperclipWakePayload(value: unknown): PaperclipWakePayl
commentIds,
latestCommentId: asString(payload.latestCommentId, "").trim() || null,
comments,
reports,
requestedCount: asNumber(commentWindow.requestedCount, comments.length || commentIds.length),
includedCount: asNumber(commentWindow.includedCount, comments.length),
missingCount: asNumber(commentWindow.missingCount, 0),
@@ -1667,6 +1708,17 @@ export function renderPaperclipWakePrompt(
lines.push("");
}
if (normalized.reports.length > 0) {
lines.push("Cross-issue reports in delivery order:");
for (const [index, report] of normalized.reports.entries()) {
lines.push(
`${index + 1}. report ${report.id} from issue ${report.originIssueId} run ${report.originRunId}`,
JSON.stringify(report.payload),
"",
);
}
}
return lines.join("\n").trim();
}
-1
View File
@@ -12830,7 +12830,6 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {})
: null,
startedAt: meta.startedAt,
});
await acknowledgePendingReports();
},
authToken: authToken ?? undefined,
});