patchrelay 0.36.3 → 0.36.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-info.json +3 -3
- package/dist/db.js +7 -0
- package/dist/idle-reconciliation.js +19 -0
- package/dist/issue-session.js +4 -1
- package/dist/run-orchestrator.js +52 -24
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
package/dist/db.js
CHANGED
|
@@ -357,6 +357,7 @@ export class PatchRelayDatabase {
|
|
|
357
357
|
last_github_ci_snapshot_head_sha, last_github_ci_snapshot_gate_check_name, last_github_ci_snapshot_gate_check_status, last_github_ci_snapshot_json, last_github_ci_snapshot_settled_at,
|
|
358
358
|
last_queue_signal_at, last_queue_incident_json,
|
|
359
359
|
last_attempted_failure_head_sha, last_attempted_failure_signature,
|
|
360
|
+
ci_repair_attempts, queue_repair_attempts, review_fix_attempts, zombie_recovery_attempts, last_zombie_recovery_at,
|
|
360
361
|
updated_at
|
|
361
362
|
) VALUES (
|
|
362
363
|
@projectId, @linearIssueId, @issueKey, @title, @description, @url,
|
|
@@ -369,6 +370,7 @@ export class PatchRelayDatabase {
|
|
|
369
370
|
@lastGitHubCiSnapshotHeadSha, @lastGitHubCiSnapshotGateCheckName, @lastGitHubCiSnapshotGateCheckStatus, @lastGitHubCiSnapshotJson, @lastGitHubCiSnapshotSettledAt,
|
|
370
371
|
@lastQueueSignalAt, @lastQueueIncidentJson,
|
|
371
372
|
@lastAttemptedFailureHeadSha, @lastAttemptedFailureSignature,
|
|
373
|
+
@ciRepairAttempts, @queueRepairAttempts, @reviewFixAttempts, @zombieRecoveryAttempts, @lastZombieRecoveryAt,
|
|
372
374
|
@now
|
|
373
375
|
)
|
|
374
376
|
`).run({
|
|
@@ -415,6 +417,11 @@ export class PatchRelayDatabase {
|
|
|
415
417
|
lastQueueIncidentJson: params.lastQueueIncidentJson ?? null,
|
|
416
418
|
lastAttemptedFailureHeadSha: params.lastAttemptedFailureHeadSha ?? null,
|
|
417
419
|
lastAttemptedFailureSignature: params.lastAttemptedFailureSignature ?? null,
|
|
420
|
+
ciRepairAttempts: params.ciRepairAttempts ?? 0,
|
|
421
|
+
queueRepairAttempts: params.queueRepairAttempts ?? 0,
|
|
422
|
+
reviewFixAttempts: params.reviewFixAttempts ?? 0,
|
|
423
|
+
zombieRecoveryAttempts: params.zombieRecoveryAttempts ?? 0,
|
|
424
|
+
lastZombieRecoveryAt: params.lastZombieRecoveryAt ?? null,
|
|
418
425
|
now,
|
|
419
426
|
});
|
|
420
427
|
}
|
|
@@ -491,6 +491,25 @@ export class IdleIssueReconciler {
|
|
|
491
491
|
mergeConflictDetected,
|
|
492
492
|
downstreamOwned,
|
|
493
493
|
});
|
|
494
|
+
if ((issue.factoryState === "escalated" || issue.factoryState === "failed")
|
|
495
|
+
&& (reactiveIntent?.runType === "review_fix" || reactiveIntent?.runType === "branch_upkeep")) {
|
|
496
|
+
const pendingRunContext = reactiveIntent.runType === "branch_upkeep"
|
|
497
|
+
? buildBranchUpkeepContext(issue.prNumber, project.github?.baseBranch ?? "main", pr.mergeStateStatus, pr.headRefOid)
|
|
498
|
+
: undefined;
|
|
499
|
+
this.logger.info({
|
|
500
|
+
issueKey: issue.issueKey,
|
|
501
|
+
prNumber: issue.prNumber,
|
|
502
|
+
from: issue.factoryState,
|
|
503
|
+
runType: reactiveIntent.runType,
|
|
504
|
+
mergeStateStatus: pr.mergeStateStatus,
|
|
505
|
+
}, "Reconciliation: recovered terminal requested-changes issue from GitHub truth");
|
|
506
|
+
this.advanceIdleIssue(issue, reactiveIntent.compatibilityFactoryState, {
|
|
507
|
+
pendingRunType: reactiveIntent.runType,
|
|
508
|
+
...(pendingRunContext ? { pendingRunContext } : {}),
|
|
509
|
+
clearFailureProvenance: true,
|
|
510
|
+
});
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
494
513
|
if (reactiveIntent?.runType === "branch_upkeep" && mergeConflictDetected) {
|
|
495
514
|
this.logger.info({ issueKey: issue.issueKey, prNumber: issue.prNumber, mergeable: pr.mergeable, mergeStateStatus: pr.mergeStateStatus }, "Reconciliation: PR still needs branch upkeep after requested changes");
|
|
496
515
|
this.advanceIdleIssue(issue, reactiveIntent.compatibilityFactoryState, {
|
package/dist/issue-session.js
CHANGED
|
@@ -79,12 +79,15 @@ export function isIssueSessionReadyForExecution(params) {
|
|
|
79
79
|
return false;
|
|
80
80
|
if (params.blockedByCount > 0)
|
|
81
81
|
return false;
|
|
82
|
-
if (params.sessionState === "done" || params.sessionState === "
|
|
82
|
+
if (params.sessionState === "done" || params.sessionState === "waiting_input") {
|
|
83
83
|
return false;
|
|
84
84
|
}
|
|
85
85
|
if (params.hasPendingWake) {
|
|
86
86
|
return true;
|
|
87
87
|
}
|
|
88
|
+
if (params.sessionState === "failed") {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
88
91
|
if (!params.hasLegacyPendingRun) {
|
|
89
92
|
return false;
|
|
90
93
|
}
|
package/dist/run-orchestrator.js
CHANGED
|
@@ -12,7 +12,7 @@ import { getThreadTurns } from "./codex-thread-utils.js";
|
|
|
12
12
|
import { deriveIssueSessionReactiveIntent } from "./issue-session.js";
|
|
13
13
|
const DEFAULT_CI_REPAIR_BUDGET = 3;
|
|
14
14
|
const DEFAULT_QUEUE_REPAIR_BUDGET = 3;
|
|
15
|
-
const DEFAULT_REVIEW_FIX_BUDGET =
|
|
15
|
+
const DEFAULT_REVIEW_FIX_BUDGET = 6;
|
|
16
16
|
const DEFAULT_ZOMBIE_RECOVERY_BUDGET = 5;
|
|
17
17
|
const ZOMBIE_RECOVERY_BASE_DELAY_MS = 15_000; // 15s, 30s, 60s, 120s, 240s
|
|
18
18
|
const ISSUE_SESSION_LEASE_MS = 10 * 60_000;
|
|
@@ -636,8 +636,8 @@ export class RunOrchestrator {
|
|
|
636
636
|
this.escalate(issue, runType, `Queue repair budget exhausted (${DEFAULT_QUEUE_REPAIR_BUDGET} attempts)`);
|
|
637
637
|
return;
|
|
638
638
|
}
|
|
639
|
-
if (runType
|
|
640
|
-
this.escalate(issue, runType, `
|
|
639
|
+
if (isRequestedChangesRunType(runType) && issue.reviewFixAttempts >= DEFAULT_REVIEW_FIX_BUDGET) {
|
|
640
|
+
this.escalate(issue, runType, `Requested-changes budget exhausted (${DEFAULT_REVIEW_FIX_BUDGET} attempts)`);
|
|
641
641
|
return;
|
|
642
642
|
}
|
|
643
643
|
// Increment repair counters
|
|
@@ -655,7 +655,7 @@ export class RunOrchestrator {
|
|
|
655
655
|
return;
|
|
656
656
|
}
|
|
657
657
|
}
|
|
658
|
-
if (runType
|
|
658
|
+
if (isRequestedChangesRunType(runType)) {
|
|
659
659
|
const updated = this.db.upsertIssueWithLease({ projectId: issue.projectId, linearIssueId: issue.linearIssueId, leaseId }, { projectId: issue.projectId, linearIssueId: issue.linearIssueId, reviewFixAttempts: issue.reviewFixAttempts + 1 });
|
|
660
660
|
if (!updated) {
|
|
661
661
|
this.releaseIssueSessionLease(item.projectId, item.issueId);
|
|
@@ -1467,13 +1467,6 @@ export class RunOrchestrator {
|
|
|
1467
1467
|
queueRepairAttempts: issue.queueRepairAttempts - 1,
|
|
1468
1468
|
});
|
|
1469
1469
|
}
|
|
1470
|
-
else if (run.runType === "review_fix" && issue.reviewFixAttempts > 0) {
|
|
1471
|
-
this.db.upsertIssueWithLease(lease, {
|
|
1472
|
-
projectId: issue.projectId,
|
|
1473
|
-
linearIssueId: issue.linearIssueId,
|
|
1474
|
-
reviewFixAttempts: issue.reviewFixAttempts - 1,
|
|
1475
|
-
});
|
|
1476
|
-
}
|
|
1477
1470
|
if (run.runType === "ci_repair" || run.runType === "queue_repair") {
|
|
1478
1471
|
this.db.upsertIssueWithLease(lease, {
|
|
1479
1472
|
projectId: issue.projectId,
|
|
@@ -1490,21 +1483,56 @@ export class RunOrchestrator {
|
|
|
1490
1483
|
return;
|
|
1491
1484
|
}
|
|
1492
1485
|
if (isRequestedChangesRunType(run.runType)) {
|
|
1486
|
+
const refreshedIssue = await this.refreshIssueAfterReactivePublish(run, this.db.getIssue(run.projectId, run.linearIssueId) ?? issue);
|
|
1487
|
+
const project = this.config.projects.find((entry) => entry.id === run.projectId);
|
|
1488
|
+
const retryContext = project
|
|
1489
|
+
? await this.resolveRequestedChangesWakeContext(refreshedIssue, run.runType, run.runType === "branch_upkeep"
|
|
1490
|
+
? {
|
|
1491
|
+
branchUpkeepRequired: true,
|
|
1492
|
+
reviewFixMode: "branch_upkeep",
|
|
1493
|
+
wakeReason: "branch_upkeep",
|
|
1494
|
+
}
|
|
1495
|
+
: undefined, project)
|
|
1496
|
+
: undefined;
|
|
1497
|
+
const retryRunType = resolveRequestedChangesMode(run.runType, retryContext) === "branch_upkeep"
|
|
1498
|
+
? "branch_upkeep"
|
|
1499
|
+
: "review_fix";
|
|
1500
|
+
const recoveredState = resolveRecoverablePostRunState(refreshedIssue) ?? "failed";
|
|
1493
1501
|
const interruptedMessage = "Requested-changes run was interrupted before PatchRelay could verify that a new PR head was published";
|
|
1494
|
-
this.failRunAndClear(run, interruptedMessage,
|
|
1502
|
+
this.failRunAndClear(run, interruptedMessage, recoveredState);
|
|
1495
1503
|
await this.restoreIdleWorktree(issue);
|
|
1496
|
-
const
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1504
|
+
const recoveredIssue = this.db.getIssue(run.projectId, run.linearIssueId) ?? refreshedIssue;
|
|
1505
|
+
if (recoveredState === "changes_requested") {
|
|
1506
|
+
this.db.upsertIssue({
|
|
1507
|
+
projectId: run.projectId,
|
|
1508
|
+
linearIssueId: run.linearIssueId,
|
|
1509
|
+
pendingRunType: retryRunType,
|
|
1510
|
+
pendingRunContextJson: retryContext ? JSON.stringify(retryContext) : null,
|
|
1511
|
+
});
|
|
1512
|
+
this.feed?.publish({
|
|
1513
|
+
level: "warn",
|
|
1514
|
+
kind: "workflow",
|
|
1515
|
+
issueKey: issue.issueKey,
|
|
1516
|
+
projectId: run.projectId,
|
|
1517
|
+
stage: run.runType,
|
|
1518
|
+
status: "retry_queued",
|
|
1519
|
+
summary: "Requested-changes run was interrupted; PatchRelay will retry from fresh GitHub truth",
|
|
1520
|
+
});
|
|
1521
|
+
this.enqueueIssue(run.projectId, run.linearIssueId);
|
|
1522
|
+
}
|
|
1523
|
+
else {
|
|
1524
|
+
this.feed?.publish({
|
|
1525
|
+
level: "error",
|
|
1526
|
+
kind: "workflow",
|
|
1527
|
+
issueKey: issue.issueKey,
|
|
1528
|
+
projectId: run.projectId,
|
|
1529
|
+
stage: run.runType,
|
|
1530
|
+
status: "escalated",
|
|
1531
|
+
summary: interruptedMessage,
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
void this.linearSync.emitActivity(recoveredIssue, buildRunFailureActivity(run.runType, interruptedMessage));
|
|
1535
|
+
void this.linearSync.syncSession(recoveredIssue, { activeRunType: run.runType });
|
|
1508
1536
|
this.releaseIssueSessionLease(run.projectId, run.linearIssueId);
|
|
1509
1537
|
return;
|
|
1510
1538
|
}
|