mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-04 19:28:46 +01:00
Unblock closed liveness recovery issues in graph reconciliation
This commit is contained in:
1 parent
986df210a3
commit
53493eb3e9
2 files changed
+63
No files matched your search
@@ -724,4 +724,43 @@ describeEmbeddedPostgres("heartbeat issue graph liveness escalation", () => {
|
||||
expect(blockers.some((row) => row.blockerIssueId === closedEscalationId)).toBe(false);
|
||||
expect(blockers.some((row) => row.blockerIssueId === freshEscalation?.id)).toBe(true);
|
||||
});
|
||||
|
||||
it("removes closed liveness escalations from blocker relations during reconciliation", async () => {
|
||||
await enableAutoRecovery();
|
||||
const { companyId, blockedIssueId, blockerIssueId } = await seedBlockedChain();
|
||||
const heartbeat = heartbeatService(db);
|
||||
|
||||
const first = await heartbeat.reconcileIssueGraphLiveness();
|
||||
expect(first.escalationsCreated).toBe(1);
|
||||
|
||||
const escalations = await db
|
||||
.select()
|
||||
.from(issues)
|
||||
.where(
|
||||
and(
|
||||
eq(issues.companyId, companyId),
|
||||
eq(issues.originKind, "harness_liveness_escalation"),
|
||||
),
|
||||
);
|
||||
expect(escalations).toHaveLength(1);
|
||||
|
||||
await db
|
||||
.update(issues)
|
||||
.set({ status: "done", blockedByIssueIds: [] })
|
||||
.where(eq(issues.id, escalations[0]!.id));
|
||||
await db
|
||||
.update(issues)
|
||||
.set({ status: "done", blockedByIssueIds: [] })
|
||||
.where(eq(issues.id, blockerIssueId));
|
||||
|
||||
const second = await heartbeat.reconcileIssueGraphLiveness();
|
||||
expect(second.obsoleteRecoveryBlockerRelationsRemoved).toBe(0);
|
||||
expect(second.doneRecoveryBlockerRelationsRemoved).toBe(1);
|
||||
|
||||
const blockers = await db
|
||||
.select({ blockerIssueId: issueRelations.issueId })
|
||||
.from(issueRelations)
|
||||
.where(eq(issueRelations.relatedIssueId, blockedIssueId));
|
||||
expect(blockers.some((row) => row.blockerIssueId === escalations[0]!.id)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -2590,6 +2590,28 @@ export function recoveryService(db: Db, deps: { enqueueWakeup: RecoveryWakeup })
|
||||
return result;
|
||||
}
|
||||
|
||||
async function retireDoneLivenessRecoveryBlockers() {
|
||||
const closedRecoveries = await db
|
||||
.select()
|
||||
.from(issues)
|
||||
.where(
|
||||
and(
|
||||
eq(issues.originKind, RECOVERY_ORIGIN_KINDS.issueGraphLivenessEscalation),
|
||||
isNull(issues.hiddenAt),
|
||||
inArray(issues.status, ["done", "cancelled"]),
|
||||
),
|
||||
);
|
||||
|
||||
let blockerRelationsRemoved = 0;
|
||||
for (const recovery of closedRecoveries) {
|
||||
if (await removeRecoveryBlockerFromSource(recovery)) {
|
||||
blockerRelationsRemoved += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return { blockerRelationsRemoved };
|
||||
}
|
||||
|
||||
function normalizeIssueGraphLivenessAutoRecoveryLookbackHours(raw: unknown) {
|
||||
const numeric = Math.floor(asNumber(raw, DEFAULT_ISSUE_GRAPH_LIVENESS_AUTO_RECOVERY_LOOKBACK_HOURS));
|
||||
return Math.min(
|
||||
@@ -2985,6 +3007,7 @@ export function recoveryService(db: Db, deps: { enqueueWakeup: RecoveryWakeup })
|
||||
const now = new Date();
|
||||
const cutoff = new Date(now.getTime() - lookbackHours * 60 * 60 * 1000);
|
||||
const obsoleteRecoveryCleanup = await retireObsoleteLivenessRecoveryIssues(findings);
|
||||
const doneRecoveryBlockerCleanup = await retireDoneLivenessRecoveryBlockers();
|
||||
const updatedAtByIssueKey = await loadLivenessDependencyUpdatedAtByIssue(findings);
|
||||
const result = {
|
||||
findings: findings.length,
|
||||
@@ -2999,6 +3022,7 @@ export function recoveryService(db: Db, deps: { enqueueWakeup: RecoveryWakeup })
|
||||
obsoleteRecoveriesRetired: obsoleteRecoveryCleanup.retired,
|
||||
obsoleteRecoveriesActiveSkipped: obsoleteRecoveryCleanup.activeSkipped,
|
||||
obsoleteRecoveryBlockerRelationsRemoved: obsoleteRecoveryCleanup.blockerRelationsRemoved,
|
||||
doneRecoveryBlockerRelationsRemoved: doneRecoveryBlockerCleanup.blockerRelationsRemoved,
|
||||
issueIds: [] as string[],
|
||||
escalationIssueIds: [] as string[],
|
||||
retiredRecoveryIssueIds: obsoleteRecoveryCleanup.retiredIssueIds,
|
||||
|
||||
Reference in new issue
Block a user