mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-16 10:50:38 +09:00
[codex] Add runtime lifecycle recovery and live issue visibility (#4419)
This commit is contained in:
parent
9a8d219949
commit
5a0c1979cf
121 changed files with 9625 additions and 2044 deletions
146
server/src/__tests__/recovery-classifiers.test.ts
Normal file
146
server/src/__tests__/recovery-classifiers.test.ts
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { classifyIssueGraphLiveness as classifyIssueGraphLivenessCompat } from "../services/issue-liveness.ts";
|
||||
import { decideRunLivenessContinuation as decideRunLivenessContinuationCompat } from "../services/run-continuations.ts";
|
||||
import {
|
||||
RECOVERY_KEY_PREFIXES,
|
||||
RECOVERY_ORIGIN_KINDS,
|
||||
RECOVERY_REASON_KINDS,
|
||||
buildIssueGraphLivenessIncidentKey,
|
||||
buildIssueGraphLivenessLeafKey,
|
||||
buildRunLivenessContinuationIdempotencyKey,
|
||||
classifyIssueGraphLiveness,
|
||||
decideRunLivenessContinuation,
|
||||
parseIssueGraphLivenessIncidentKey,
|
||||
} from "../services/recovery/index.ts";
|
||||
|
||||
const companyId = "company-1";
|
||||
const agentId = "agent-1";
|
||||
const managerId = "manager-1";
|
||||
const issueId = "issue-1";
|
||||
const blockerId = "blocker-1";
|
||||
const runId = "run-1";
|
||||
|
||||
describe("recovery classifier boundary", () => {
|
||||
it("keeps issue graph liveness classifier parity with the compatibility export", () => {
|
||||
const input = {
|
||||
issues: [
|
||||
{
|
||||
id: issueId,
|
||||
companyId,
|
||||
identifier: "PAP-2073",
|
||||
title: "Centralize recovery classifiers",
|
||||
status: "blocked",
|
||||
assigneeAgentId: agentId,
|
||||
assigneeUserId: null,
|
||||
createdByAgentId: null,
|
||||
createdByUserId: null,
|
||||
executionState: null,
|
||||
},
|
||||
{
|
||||
id: blockerId,
|
||||
companyId,
|
||||
identifier: "PAP-2074",
|
||||
title: "Move recovery side effects",
|
||||
status: "todo",
|
||||
assigneeAgentId: null,
|
||||
assigneeUserId: null,
|
||||
createdByAgentId: null,
|
||||
createdByUserId: null,
|
||||
executionState: null,
|
||||
},
|
||||
],
|
||||
relations: [{ companyId, blockerIssueId: blockerId, blockedIssueId: issueId }],
|
||||
agents: [
|
||||
{
|
||||
id: agentId,
|
||||
companyId,
|
||||
name: "Coder",
|
||||
role: "engineer",
|
||||
status: "idle",
|
||||
reportsTo: managerId,
|
||||
},
|
||||
{
|
||||
id: managerId,
|
||||
companyId,
|
||||
name: "CTO",
|
||||
role: "cto",
|
||||
status: "idle",
|
||||
reportsTo: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(classifyIssueGraphLiveness(input)).toEqual(classifyIssueGraphLivenessCompat(input));
|
||||
});
|
||||
|
||||
it("keeps run liveness continuation decision parity with the compatibility export", () => {
|
||||
const input = {
|
||||
run: {
|
||||
id: runId,
|
||||
companyId,
|
||||
agentId,
|
||||
continuationAttempt: 0,
|
||||
} as never,
|
||||
issue: {
|
||||
id: issueId,
|
||||
companyId,
|
||||
identifier: "PAP-2073",
|
||||
title: "Centralize recovery classifiers",
|
||||
status: "in_progress",
|
||||
assigneeAgentId: agentId,
|
||||
executionState: null,
|
||||
projectId: null,
|
||||
} as never,
|
||||
agent: {
|
||||
id: agentId,
|
||||
companyId,
|
||||
status: "idle",
|
||||
} as never,
|
||||
livenessState: "plan_only" as const,
|
||||
livenessReason: "Planned without acting",
|
||||
nextAction: "Take the first concrete action.",
|
||||
budgetBlocked: false,
|
||||
idempotentWakeExists: false,
|
||||
};
|
||||
|
||||
expect(decideRunLivenessContinuation(input)).toEqual(decideRunLivenessContinuationCompat(input));
|
||||
});
|
||||
|
||||
it("keeps recovery origin and idempotency keys stable", () => {
|
||||
expect(RECOVERY_ORIGIN_KINDS).toMatchObject({
|
||||
issueGraphLivenessEscalation: "harness_liveness_escalation",
|
||||
strandedIssueRecovery: "stranded_issue_recovery",
|
||||
staleActiveRunEvaluation: "stale_active_run_evaluation",
|
||||
});
|
||||
expect(RECOVERY_REASON_KINDS.runLivenessContinuation).toBe("run_liveness_continuation");
|
||||
expect(RECOVERY_KEY_PREFIXES.issueGraphLivenessIncident).toBe("harness_liveness");
|
||||
expect(RECOVERY_KEY_PREFIXES.issueGraphLivenessLeaf).toBe("harness_liveness_leaf");
|
||||
|
||||
const incidentKey = buildIssueGraphLivenessIncidentKey({
|
||||
companyId,
|
||||
issueId,
|
||||
state: "blocked_by_unassigned_issue",
|
||||
blockerIssueId: blockerId,
|
||||
});
|
||||
expect(incidentKey).toBe(
|
||||
"harness_liveness:company-1:issue-1:blocked_by_unassigned_issue:blocker-1",
|
||||
);
|
||||
expect(parseIssueGraphLivenessIncidentKey(incidentKey)).toEqual({
|
||||
companyId,
|
||||
issueId,
|
||||
state: "blocked_by_unassigned_issue",
|
||||
leafIssueId: blockerId,
|
||||
});
|
||||
expect(buildIssueGraphLivenessLeafKey({
|
||||
companyId,
|
||||
state: "blocked_by_unassigned_issue",
|
||||
leafIssueId: blockerId,
|
||||
})).toBe("harness_liveness_leaf:company-1:blocked_by_unassigned_issue:blocker-1");
|
||||
expect(buildRunLivenessContinuationIdempotencyKey({
|
||||
issueId,
|
||||
sourceRunId: runId,
|
||||
livenessState: "plan_only",
|
||||
nextAttempt: 1,
|
||||
})).toBe("run_liveness_continuation:issue-1:run-1:plan_only:1");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue