@urateam/core 0.1.33 → 0.1.35
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/__tests__/audit-immutability.test.js +50 -0
- package/dist/__tests__/audit-immutability.test.js.map +1 -1
- package/dist/__tests__/pm-scheduler.test.js +59 -0
- package/dist/__tests__/pm-scheduler.test.js.map +1 -1
- package/dist/__tests__/review-convention-prompt.test.d.ts +2 -0
- package/dist/__tests__/review-convention-prompt.test.d.ts.map +1 -0
- package/dist/__tests__/review-convention-prompt.test.js +142 -0
- package/dist/__tests__/review-convention-prompt.test.js.map +1 -0
- package/dist/__tests__/runner-retry-strategies.test.d.ts +23 -0
- package/dist/__tests__/runner-retry-strategies.test.d.ts.map +1 -0
- package/dist/__tests__/runner-retry-strategies.test.js +274 -0
- package/dist/__tests__/runner-retry-strategies.test.js.map +1 -0
- package/dist/__tests__/scratch-file-guard.test.d.ts +2 -0
- package/dist/__tests__/scratch-file-guard.test.d.ts.map +1 -0
- package/dist/__tests__/scratch-file-guard.test.js +144 -0
- package/dist/__tests__/scratch-file-guard.test.js.map +1 -0
- package/dist/__tests__/spec-vs-impl-gate.test.d.ts +2 -0
- package/dist/__tests__/spec-vs-impl-gate.test.d.ts.map +1 -0
- package/dist/__tests__/spec-vs-impl-gate.test.js +222 -0
- package/dist/__tests__/spec-vs-impl-gate.test.js.map +1 -0
- package/dist/__tests__/typecheck-gate.test.d.ts +2 -0
- package/dist/__tests__/typecheck-gate.test.d.ts.map +1 -0
- package/dist/__tests__/typecheck-gate.test.js +196 -0
- package/dist/__tests__/typecheck-gate.test.js.map +1 -0
- package/dist/audit/events.d.ts +39 -0
- package/dist/audit/events.d.ts.map +1 -1
- package/dist/audit/events.js +60 -0
- package/dist/audit/events.js.map +1 -1
- package/dist/executor/prompt/templates.d.ts.map +1 -1
- package/dist/executor/prompt/templates.js +6 -3
- package/dist/executor/prompt/templates.js.map +1 -1
- package/dist/executor/review/review-prompt.d.ts.map +1 -1
- package/dist/executor/review/review-prompt.js +8 -2
- package/dist/executor/review/review-prompt.js.map +1 -1
- package/dist/pipeline/runner.d.ts.map +1 -1
- package/dist/pipeline/runner.js +145 -1
- package/dist/pipeline/runner.js.map +1 -1
- package/dist/pipeline/scratch-file-guard.d.ts +21 -0
- package/dist/pipeline/scratch-file-guard.d.ts.map +1 -0
- package/dist/pipeline/scratch-file-guard.js +155 -0
- package/dist/pipeline/scratch-file-guard.js.map +1 -0
- package/dist/pipeline/spec-vs-impl-gate.d.ts +49 -0
- package/dist/pipeline/spec-vs-impl-gate.d.ts.map +1 -0
- package/dist/pipeline/spec-vs-impl-gate.js +177 -0
- package/dist/pipeline/spec-vs-impl-gate.js.map +1 -0
- package/dist/pipeline/typecheck-gate.d.ts +34 -0
- package/dist/pipeline/typecheck-gate.d.ts.map +1 -0
- package/dist/pipeline/typecheck-gate.js +89 -0
- package/dist/pipeline/typecheck-gate.js.map +1 -0
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/index.js.map +1 -1
- package/dist/security/review-checklist.d.ts +16 -1
- package/dist/security/review-checklist.d.ts.map +1 -1
- package/dist/security/review-checklist.js +85 -1
- package/dist/security/review-checklist.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { describe, it, expect } from "vitest";
|
|
11
11
|
import { execFileSync } from "node:child_process";
|
|
12
|
+
import { readFileSync } from "node:fs";
|
|
12
13
|
import path from "node:path";
|
|
14
|
+
import { AuditEventTypeSchema, AuditActorTypeSchema } from "../types.js";
|
|
13
15
|
describe("audit_events immutability", () => {
|
|
14
16
|
it("only audit/retention.ts may delete or update audit_events rows", () => {
|
|
15
17
|
const repoRoot = path.resolve(__dirname, "../../../..");
|
|
@@ -68,6 +70,13 @@ describe("audit_events immutability", () => {
|
|
|
68
70
|
"packages/core/src/qa/github.ts",
|
|
69
71
|
"packages/core/src/qa/gap.ts",
|
|
70
72
|
"packages/core/src/__tests__/audit-immutability.test.ts",
|
|
73
|
+
// Tier 2: the convention-checklist text documents the
|
|
74
|
+
// `audit-bypass-undocumented` category by name (`logAuditEventUnchecked`
|
|
75
|
+
// appears as a literal in the prompt fragment, not as a call site).
|
|
76
|
+
// The grep is intentionally loose so renames to similar identifiers
|
|
77
|
+
// still trip; the allow-list entry is the right surface for "this
|
|
78
|
+
// file mentions the name but does not invoke it" exceptions.
|
|
79
|
+
"packages/core/src/security/review-checklist.ts",
|
|
71
80
|
];
|
|
72
81
|
let matches = [];
|
|
73
82
|
try {
|
|
@@ -82,5 +91,46 @@ describe("audit_events immutability", () => {
|
|
|
82
91
|
.filter((file) => !allowed.some((a) => file.endsWith(a) || file === a));
|
|
83
92
|
expect(offenders, `Unauthorized logAuditEventUnchecked usage in:\n${offenders.join("\n")}`).toEqual([]);
|
|
84
93
|
});
|
|
94
|
+
/**
|
|
95
|
+
* Tier 1d — keep CLAUDE.md's claimed audit-event count in sync with
|
|
96
|
+
* AuditEventTypeSchema. The autonomous pipeline has historically added new
|
|
97
|
+
* event types to the schema without updating the doc count (see Tier 1a's
|
|
98
|
+
* pre-existing 17→41 drift). This test fails CI when the regex match
|
|
99
|
+
* `(\d+) event types` in CLAUDE.md disagrees with `AuditEventTypeSchema`'s
|
|
100
|
+
* length.
|
|
101
|
+
*
|
|
102
|
+
* The pipeline's review-stage prompt will surface this as a blocking
|
|
103
|
+
* `audit-count-drift` finding via the convention checklist (Tier 2);
|
|
104
|
+
* the unit test is the deterministic backstop.
|
|
105
|
+
*/
|
|
106
|
+
it("CLAUDE.md audit-event count matches AuditEventTypeSchema length", () => {
|
|
107
|
+
const repoRoot = path.resolve(__dirname, "../../../..");
|
|
108
|
+
const claudeMd = readFileSync(path.join(repoRoot, "CLAUDE.md"), "utf8");
|
|
109
|
+
const matches = [...claudeMd.matchAll(/(\d+)\s+event\s+types/g)];
|
|
110
|
+
expect(matches.length, "CLAUDE.md must contain exactly one `<N> event types` sentence so Tier 1d can lock it down").toBe(1);
|
|
111
|
+
const documented = Number(matches[0][1]);
|
|
112
|
+
const actual = AuditEventTypeSchema.options.length;
|
|
113
|
+
expect(documented, `CLAUDE.md says "${documented} event types" but AuditEventTypeSchema has ${actual}. Update CLAUDE.md or the schema; they must match.`).toBe(actual);
|
|
114
|
+
});
|
|
115
|
+
/**
|
|
116
|
+
* Tier 1d — mirror of the event-type count check for the actor-type enum.
|
|
117
|
+
* The actor-type list is shorter and changes less often, but the same drift
|
|
118
|
+
* pattern applies (e.g. BEC-207 added a new actor without updating any doc).
|
|
119
|
+
* CLAUDE.md doesn't currently cite a number for actor types, so this test
|
|
120
|
+
* is gated: it only runs if a `(\d+) actor types` sentence is present, and
|
|
121
|
+
* fails when present-but-stale. Removes the test gracefully when the doc
|
|
122
|
+
* doesn't enumerate.
|
|
123
|
+
*/
|
|
124
|
+
it("CLAUDE.md actor-type count matches AuditActorTypeSchema length (when present)", () => {
|
|
125
|
+
const repoRoot = path.resolve(__dirname, "../../../..");
|
|
126
|
+
const claudeMd = readFileSync(path.join(repoRoot, "CLAUDE.md"), "utf8");
|
|
127
|
+
const matches = [...claudeMd.matchAll(/(\d+)\s+actor\s+types/g)];
|
|
128
|
+
if (matches.length === 0)
|
|
129
|
+
return; // not enumerated; nothing to validate
|
|
130
|
+
expect(matches.length, "CLAUDE.md must contain at most one `<N> actor types` sentence").toBe(1);
|
|
131
|
+
const documented = Number(matches[0][1]);
|
|
132
|
+
const actual = AuditActorTypeSchema.options.length;
|
|
133
|
+
expect(documented, `CLAUDE.md says "${documented} actor types" but AuditActorTypeSchema has ${actual}.`).toBe(actual);
|
|
134
|
+
});
|
|
85
135
|
});
|
|
86
136
|
//# sourceMappingURL=audit-immutability.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-immutability.test.js","sourceRoot":"","sources":["../../src/__tests__/audit-immutability.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"audit-immutability.test.js","sourceRoot":"","sources":["../../src/__tests__/audit-immutability.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -137,5 +137,64 @@ describe("PmScheduler.tick", () => {
|
|
|
137
137
|
errors: expect.arrayContaining([expect.stringContaining("triage")]),
|
|
138
138
|
}), expect.any(Number));
|
|
139
139
|
});
|
|
140
|
+
describe("paused-tick (BEC-200) — PM_AGENT_PAUSED gates promote / recover-stuck / deprioritize / cancel", () => {
|
|
141
|
+
/**
|
|
142
|
+
* `isPmPaused()` returns true when `PM_AGENT_PAUSED === "true"` OR the
|
|
143
|
+
* in-memory flag is set (via Slack `/pm pause`). Per scheduler.ts the
|
|
144
|
+
* paused branch logs:
|
|
145
|
+
* "PM Agent is paused — skipping start-todo, recover-stuck, promote,
|
|
146
|
+
* deprioritize, and cancel"
|
|
147
|
+
*
|
|
148
|
+
* Triage and budget-eval are NOT gated by pause — they read state but
|
|
149
|
+
* don't mutate Linear. These tests assert each gated action skips and
|
|
150
|
+
* each non-gated action still runs.
|
|
151
|
+
*/
|
|
152
|
+
afterEach(() => {
|
|
153
|
+
// Restore env var so subsequent test files in the same suite don't see
|
|
154
|
+
// a paused PM Agent — this is the regression the prior #261 review
|
|
155
|
+
// flagged ("paused-tick tests leak `PM_AGENT_PAUSED` env var").
|
|
156
|
+
delete process.env.PM_AGENT_PAUSED;
|
|
157
|
+
});
|
|
158
|
+
it("paused via env var → promote, recoverStuck, deprioritize, cancel all skipped", async () => {
|
|
159
|
+
process.env.PM_AGENT_PAUSED = "true";
|
|
160
|
+
const scheduler = makeScheduler();
|
|
161
|
+
await scheduler.tick();
|
|
162
|
+
// Gated actions: must NOT run
|
|
163
|
+
expect(mockActions.recoverStuckInProgressIssues).not.toHaveBeenCalled();
|
|
164
|
+
expect(mockActions.promoteReadyIssues).not.toHaveBeenCalled();
|
|
165
|
+
expect(mockActions.deprioritizeStaleIssues).not.toHaveBeenCalled();
|
|
166
|
+
expect(mockActions.cancelAbandonedIssues).not.toHaveBeenCalled();
|
|
167
|
+
// Non-gated: still run (state-reading / informational)
|
|
168
|
+
expect(mockActions.evaluateBudget).toHaveBeenCalled();
|
|
169
|
+
expect(mockActions.triageNewIssues).toHaveBeenCalled();
|
|
170
|
+
expect(mockActions.resolveApprovals).toHaveBeenCalled();
|
|
171
|
+
expect(mockActions.postDigest).toHaveBeenCalledWith(expect.objectContaining({ paused: true }), expect.any(Number));
|
|
172
|
+
});
|
|
173
|
+
it("paused → recoverRetriableRuns still runs (decoupled from PM pause; transient-failure recovery is non-mutating)", async () => {
|
|
174
|
+
// BEC-170 / scheduler.ts: recoverRetriableRuns is invoked unconditionally
|
|
175
|
+
// before the pause check. The "paused" intent is to stop NEW autonomous
|
|
176
|
+
// assignment; recovering a run that already had a transient failure is
|
|
177
|
+
// resuming WORK ALREADY IN FLIGHT, not new assignment.
|
|
178
|
+
process.env.PM_AGENT_PAUSED = "true";
|
|
179
|
+
const scheduler = makeScheduler();
|
|
180
|
+
await scheduler.tick();
|
|
181
|
+
expect(mockActions.recoverRetriableRuns).toHaveBeenCalled();
|
|
182
|
+
});
|
|
183
|
+
it("unpaused tick after a paused one resumes all guarded actions", async () => {
|
|
184
|
+
// Pause → tick (gates fire) → unpause → tick (gates clear).
|
|
185
|
+
process.env.PM_AGENT_PAUSED = "true";
|
|
186
|
+
const scheduler = makeScheduler();
|
|
187
|
+
await scheduler.tick();
|
|
188
|
+
vi.clearAllMocks();
|
|
189
|
+
// Re-arm default behaviour for the second tick.
|
|
190
|
+
mockActions.evaluateBudget.mockResolvedValue(mockOkEvaluation());
|
|
191
|
+
delete process.env.PM_AGENT_PAUSED;
|
|
192
|
+
await scheduler.tick();
|
|
193
|
+
expect(mockActions.promoteReadyIssues).toHaveBeenCalled();
|
|
194
|
+
expect(mockActions.recoverStuckInProgressIssues).toHaveBeenCalled();
|
|
195
|
+
expect(mockActions.deprioritizeStaleIssues).toHaveBeenCalled();
|
|
196
|
+
expect(mockActions.cancelAbandonedIssues).toHaveBeenCalled();
|
|
197
|
+
});
|
|
198
|
+
});
|
|
140
199
|
});
|
|
141
200
|
//# sourceMappingURL=pm-scheduler.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pm-scheduler.test.js","sourceRoot":"","sources":["../../src/__tests__/pm-scheduler.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pm-scheduler.test.js","sourceRoot":"","sources":["../../src/__tests__/pm-scheduler.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG7E,SAAS,gBAAgB,CAAC,YAAuC,EAAE;IACjE,OAAO;QACL,MAAM,EAAE;YACN;gBACE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAiB,EAAE;gBAClC,UAAU,EAAE,QAAQ;gBACpB,KAAK,EAAE,SAAS;gBAChB,IAAI,EAAE,CAAC;gBACP,OAAO,EAAE,CAAC;gBACV,IAAI,EAAE,IAAa;aACpB;SACF;QACD,SAAS,EAAE,IAAI;QACf,cAAc,EAAE,KAAK;QACrB,WAAW,EAAE,CAAC;QACd,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB;IAC5B,OAAO;QACL,MAAM,EAAE;YACN;gBACE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAiB,EAAE;gBAClC,UAAU,EAAE,QAAQ;gBACpB,KAAK,EAAE,SAAS;gBAChB,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,GAAG;gBACZ,IAAI,EAAE,aAAsB;aAC7B;SACF;QACD,SAAS,EAAE,aAAa;QACxB,cAAc,EAAE,IAAI;QACpB,WAAW,EAAE,+CAA+C;QAC5D,WAAW,EAAE,CAAC;KACf,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,MAAM,WAAW,GAAG;QAClB,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,CAAC;QAC7D,oBAAoB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;QACjF,4BAA4B,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC3D,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC9C,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;QAC7E,kBAAkB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACjD,uBAAuB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACtD,qBAAqB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACpD,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;QAChD,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,GAAG,EAAE,CAAC;QACvD,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;KACpG,CAAC;IAEF,SAAS,aAAa;QACpB,OAAO,iBAAiB,CAAC;YACvB,MAAM,EAAE;gBACN,OAAO,EAAE,IAAI;gBACb,cAAc,EAAE,OAAO;gBACvB,eAAe,EAAE,CAAC;gBAClB,WAAW,EAAE,CAAC;gBACd,gBAAgB,EAAE,OAAO;gBACzB,cAAc,EAAE,MAAM;gBACtB,OAAO,EAAE,CAAC,QAAQ,CAAC;gBACnB,kBAAkB,EAAE,IAAI;gBACxB,qBAAqB,EAAE,MAAM;gBAC7B,oBAAoB,EAAE,CAAC;gBACvB,8BAA8B,EAAE,KAAK;gBACrC,sBAAsB,EAAE,CAAC;aAC1B;YACD,EAAE,EAAE,EAAS,EAAE,qCAAqC;YACpD,YAAY,EAAE,EAAE;YAChB,aAAa,EAAE,EAAE;YACjB,OAAO,EAAE,WAAW;SACrB,CAAC,CAAC;IACL,CAAC;IAED,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,qBAAqB,EAAE,CAAC;QAC9B,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,cAAc,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,WAAW,CAAC,cAAc,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE;YACvD,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzB,OAAO,gBAAgB,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QACH,WAAW,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACzI,WAAW,CAAC,4BAA4B,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACxH,WAAW,CAAC,eAAe,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACrG,WAAW,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9I,WAAW,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACzG,WAAW,CAAC,uBAAuB,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACnH,WAAW,CAAC,qBAAqB,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAE3G,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QAEvB,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC;YACxB,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,kBAAkB,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ;SACvG,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qFAAqF,EAAE,KAAK,IAAI,EAAE;QACnG,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QACvB,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QAEvB,oCAAoC;QACpC,MAAM,CAAC,WAAW,CAAC,4BAA4B,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAE1E,8EAA8E;QAC9E,MAAM,WAAW,GAAG,WAAW,CAAC,cAAc,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;QAC3E,MAAM,iBAAiB,GAAG,WAAW,CAAC,4BAA4B,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;QAC/F,MAAM,WAAW,GAAG,WAAW,CAAC,eAAe,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;QAC5E,MAAM,CAAC,iBAAiB,CAAC,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;QACvD,MAAM,CAAC,iBAAiB,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,WAAW,CAAC,cAAc,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,CAAC,CAAC;QAEtE,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QAEvB,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAC9D,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,gBAAgB,EAAE,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,WAAW,CAAC,eAAe,CAAC,iBAAiB,CAAC;YAC5C,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE;SAC3F,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QAEvB,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,oBAAoB,CACjD,MAAM,CAAC,gBAAgB,CAAC;YACtB,OAAO,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;SACjF,CAAC,EACF,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CACnB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,WAAW,CAAC,eAAe,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAE5E,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QAEvB,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,oBAAoB,CACjD,MAAM,CAAC,gBAAgB,CAAC;YACtB,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;SACpE,CAAC,EACF,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CACnB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,+FAA+F,EAAE,GAAG,EAAE;QAC7G;;;;;;;;;;WAUG;QACH,SAAS,CAAC,GAAG,EAAE;YACb,uEAAuE;YACvE,mEAAmE;YACnE,gEAAgE;YAChE,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8EAA8E,EAAE,KAAK,IAAI,EAAE;YAC5F,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,MAAM,CAAC;YAErC,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;YAClC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;YAEvB,8BAA8B;YAC9B,MAAM,CAAC,WAAW,CAAC,4BAA4B,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YACxE,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YAC9D,MAAM,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YACnE,MAAM,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YAEjE,uDAAuD;YACvD,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,gBAAgB,EAAE,CAAC;YACtD,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,gBAAgB,EAAE,CAAC;YACvD,MAAM,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC,gBAAgB,EAAE,CAAC;YACxD,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,oBAAoB,CACjD,MAAM,CAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EACzC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CACnB,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gHAAgH,EAAE,KAAK,IAAI,EAAE;YAC9H,0EAA0E;YAC1E,wEAAwE;YACxE,uEAAuE;YACvE,uDAAuD;YACvD,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,MAAM,CAAC;YAErC,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;YAClC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;YAEvB,MAAM,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,gBAAgB,EAAE,CAAC;QAC9D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;YAC5E,4DAA4D;YAC5D,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,MAAM,CAAC;YACrC,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;YAClC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;YAEvB,EAAE,CAAC,aAAa,EAAE,CAAC;YACnB,gDAAgD;YAChD,WAAW,CAAC,cAAc,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,CAAC,CAAC;YAEjE,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;YACnC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;YAEvB,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,gBAAgB,EAAE,CAAC;YAC1D,MAAM,CAAC,WAAW,CAAC,4BAA4B,CAAC,CAAC,gBAAgB,EAAE,CAAC;YACpE,MAAM,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC,gBAAgB,EAAE,CAAC;YAC/D,MAAM,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC,gBAAgB,EAAE,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-convention-prompt.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/review-convention-prompt.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier 2 — convention-checklist review prompt.
|
|
3
|
+
*
|
|
4
|
+
* The review-stage prompt is augmented with a 9-category project-convention
|
|
5
|
+
* checklist drawn from CLAUDE.md. The review agent uses these categories
|
|
6
|
+
* verbatim in its `ReviewFinding[]` output, so the existing draft-PR /
|
|
7
|
+
* review-fix loop machinery picks them up as blocking findings just like
|
|
8
|
+
* the security categories.
|
|
9
|
+
*
|
|
10
|
+
* This test verifies the prompt assembly contains every category by name,
|
|
11
|
+
* the categories list in REVIEW_OUTPUT_FORMAT is exhaustive, and the
|
|
12
|
+
* checklist text itself is non-empty.
|
|
13
|
+
*/
|
|
14
|
+
import { describe, it, expect } from "vitest";
|
|
15
|
+
import { reviewTemplate } from "../executor/prompt/templates.js";
|
|
16
|
+
import { PROJECT_CONVENTION_CHECKLIST, REVIEW_OUTPUT_FORMAT, } from "../security/review-checklist.js";
|
|
17
|
+
const TIER_2_CATEGORIES = [
|
|
18
|
+
"scratch-files",
|
|
19
|
+
"db-ddl-drift",
|
|
20
|
+
"audit-bypass-undocumented",
|
|
21
|
+
"credential-in-interface",
|
|
22
|
+
"spec-vs-impl",
|
|
23
|
+
"convention-execfile",
|
|
24
|
+
"convention-console",
|
|
25
|
+
"convention-throw",
|
|
26
|
+
"convention-as-any",
|
|
27
|
+
];
|
|
28
|
+
const stubIssue = {
|
|
29
|
+
id: "BEC-999",
|
|
30
|
+
slug: "test-issue",
|
|
31
|
+
title: "test issue",
|
|
32
|
+
description: "fixture",
|
|
33
|
+
acceptanceCriteria: [],
|
|
34
|
+
labels: ["auto-implement"],
|
|
35
|
+
priority: 0,
|
|
36
|
+
};
|
|
37
|
+
const stubRepo = {
|
|
38
|
+
url: "https://example.invalid/repo.git",
|
|
39
|
+
defaultBranch: "main",
|
|
40
|
+
testCommand: "pnpm test",
|
|
41
|
+
buildCommand: "pnpm build",
|
|
42
|
+
provider: "github",
|
|
43
|
+
};
|
|
44
|
+
describe("PROJECT_CONVENTION_CHECKLIST — exported and non-empty", () => {
|
|
45
|
+
it("is a non-empty string", () => {
|
|
46
|
+
expect(typeof PROJECT_CONVENTION_CHECKLIST).toBe("string");
|
|
47
|
+
expect(PROJECT_CONVENTION_CHECKLIST.length).toBeGreaterThan(200);
|
|
48
|
+
});
|
|
49
|
+
it("mentions all 9 Tier 2 categories by exact name", () => {
|
|
50
|
+
for (const cat of TIER_2_CATEGORIES) {
|
|
51
|
+
expect(PROJECT_CONVENTION_CHECKLIST, `category "${cat}" must be named verbatim in the checklist`).toContain(cat);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
it("names the failure modes the autonomous pipeline has actually shipped (PR #258 scratch files, PR #254 spec-vs-impl, etc.)", () => {
|
|
55
|
+
// These are contextual references the brief calls out — anchor the
|
|
56
|
+
// checklist to real incidents so the agent has explicit framing.
|
|
57
|
+
expect(PROJECT_CONVENTION_CHECKLIST).toMatch(/scratch|FINAL_|TESTING_|TEST_/);
|
|
58
|
+
expect(PROJECT_CONVENTION_CHECKLIST).toMatch(/execFile/);
|
|
59
|
+
expect(PROJECT_CONVENTION_CHECKLIST).toMatch(/createLogger|console\.log/);
|
|
60
|
+
expect(PROJECT_CONVENTION_CHECKLIST).toMatch(/failPipeline|throw/);
|
|
61
|
+
expect(PROJECT_CONVENTION_CHECKLIST).toMatch(/AnyDb|as any/);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe("REVIEW_OUTPUT_FORMAT — enumerates the new categories", () => {
|
|
65
|
+
it("lists every Tier 2 category in the allowed-values block", () => {
|
|
66
|
+
for (const cat of TIER_2_CATEGORIES) {
|
|
67
|
+
expect(REVIEW_OUTPUT_FORMAT, `category "${cat}" must be listed as a valid value in REVIEW_OUTPUT_FORMAT`).toContain(cat);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe("reviewTemplate — assembles the convention checklist into the prompt", () => {
|
|
72
|
+
it("includes PROJECT_CONVENTION_CHECKLIST verbatim", () => {
|
|
73
|
+
const prompt = reviewTemplate(stubIssue, stubRepo);
|
|
74
|
+
expect(prompt).toContain(PROJECT_CONVENTION_CHECKLIST);
|
|
75
|
+
});
|
|
76
|
+
it("includes every Tier 2 category name", () => {
|
|
77
|
+
const prompt = reviewTemplate(stubIssue, stubRepo);
|
|
78
|
+
for (const cat of TIER_2_CATEGORIES) {
|
|
79
|
+
expect(prompt, `category "${cat}" must appear in the assembled prompt`).toContain(cat);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
it("still includes SECURITY_REVIEW_CHECKLIST (additive, not replacement)", () => {
|
|
83
|
+
const prompt = reviewTemplate(stubIssue, stubRepo);
|
|
84
|
+
expect(prompt).toContain("SQL injection");
|
|
85
|
+
expect(prompt).toContain("XSS");
|
|
86
|
+
});
|
|
87
|
+
it("includes REVIEW_OUTPUT_FORMAT (anchor for the structured-output parser)", () => {
|
|
88
|
+
// The template uses `${REVIEW_OUTPUT_FORMAT}` then `.trim()` on the whole
|
|
89
|
+
// string, which strips the constant's trailing newline. Compare against
|
|
90
|
+
// the trimmed value so the assertion catches both missing-interpolation
|
|
91
|
+
// and accidental-removal but tolerates the .trim().
|
|
92
|
+
const prompt = reviewTemplate(stubIssue, stubRepo);
|
|
93
|
+
expect(prompt).toContain(REVIEW_OUTPUT_FORMAT.trim());
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe("OpenRouter fanout prompt — includes the convention checklist + enumerates Tier 2 categories", () => {
|
|
97
|
+
it("buildReviewPrompt's system message includes PROJECT_CONVENTION_CHECKLIST", async () => {
|
|
98
|
+
const { buildReviewPrompt } = await import("../executor/review/review-prompt.js");
|
|
99
|
+
const built = buildReviewPrompt({
|
|
100
|
+
handoff: {
|
|
101
|
+
runId: "r1",
|
|
102
|
+
issueId: "i1",
|
|
103
|
+
stage: "review",
|
|
104
|
+
timestamp: new Date().toISOString(),
|
|
105
|
+
summary: "stub",
|
|
106
|
+
filesChanged: [],
|
|
107
|
+
approach: "stub",
|
|
108
|
+
context: { issueIntent: "stub", constraints: [], assumptions: [] },
|
|
109
|
+
tokenBudget: { contextTokensUsed: 0, recommendedMaxTurns: 1 },
|
|
110
|
+
},
|
|
111
|
+
diff: "",
|
|
112
|
+
files: [],
|
|
113
|
+
maxInputTokens: 8000,
|
|
114
|
+
});
|
|
115
|
+
const system = built.messages.find((m) => m.role === "system");
|
|
116
|
+
expect(system?.content).toContain(PROJECT_CONVENTION_CHECKLIST);
|
|
117
|
+
});
|
|
118
|
+
it("buildReviewPrompt's system message enumerates every Tier 2 category", async () => {
|
|
119
|
+
const { buildReviewPrompt } = await import("../executor/review/review-prompt.js");
|
|
120
|
+
const built = buildReviewPrompt({
|
|
121
|
+
handoff: {
|
|
122
|
+
runId: "r1",
|
|
123
|
+
issueId: "i1",
|
|
124
|
+
stage: "review",
|
|
125
|
+
timestamp: new Date().toISOString(),
|
|
126
|
+
summary: "stub",
|
|
127
|
+
filesChanged: [],
|
|
128
|
+
approach: "stub",
|
|
129
|
+
context: { issueIntent: "stub", constraints: [], assumptions: [] },
|
|
130
|
+
tokenBudget: { contextTokensUsed: 0, recommendedMaxTurns: 1 },
|
|
131
|
+
},
|
|
132
|
+
diff: "",
|
|
133
|
+
files: [],
|
|
134
|
+
maxInputTokens: 8000,
|
|
135
|
+
});
|
|
136
|
+
const system = built.messages.find((m) => m.role === "system")?.content ?? "";
|
|
137
|
+
for (const cat of TIER_2_CATEGORIES) {
|
|
138
|
+
expect(system, `fanout system prompt must mention category "${cat}"`).toContain(cat);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=review-convention-prompt.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-convention-prompt.test.js","sourceRoot":"","sources":["../../src/__tests__/review-convention-prompt.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BEC-200 — runner retry-strategy tests
|
|
3
|
+
*
|
|
4
|
+
* Verifies the three documented retry strategies in `PipelineConfig.retry`:
|
|
5
|
+
*
|
|
6
|
+
* 1. `fix-and-retry` — on a failed stage, re-execute up to `maxAttempts`
|
|
7
|
+
* times. `stageRetries[stage]` increments on each retry. If a retry
|
|
8
|
+
* succeeds, the pipeline proceeds; if all retries fail, the run is
|
|
9
|
+
* marked retriable (per failPipeline's `retriable=true` branch).
|
|
10
|
+
*
|
|
11
|
+
* 2. `escalate` — on a failed stage, NO retries are attempted. The run
|
|
12
|
+
* fails immediately, marked retriable.
|
|
13
|
+
*
|
|
14
|
+
* 3. `fail-fast` — on a failed stage, NO retries. The run fails
|
|
15
|
+
* immediately, marked NON-retriable (no automatic recovery).
|
|
16
|
+
*
|
|
17
|
+
* Mock strategy: hijack `executeStage` to return failed/completed based on a
|
|
18
|
+
* per-test counter, then call `runner.start()` directly and inspect the DB.
|
|
19
|
+
* Avoids the webhook-driven scaffolding in ralph-gate.test.ts since retry
|
|
20
|
+
* logic doesn't depend on it.
|
|
21
|
+
*/
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=runner-retry-strategies.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-retry-strategies.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/runner-retry-strategies.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BEC-200 — runner retry-strategy tests
|
|
3
|
+
*
|
|
4
|
+
* Verifies the three documented retry strategies in `PipelineConfig.retry`:
|
|
5
|
+
*
|
|
6
|
+
* 1. `fix-and-retry` — on a failed stage, re-execute up to `maxAttempts`
|
|
7
|
+
* times. `stageRetries[stage]` increments on each retry. If a retry
|
|
8
|
+
* succeeds, the pipeline proceeds; if all retries fail, the run is
|
|
9
|
+
* marked retriable (per failPipeline's `retriable=true` branch).
|
|
10
|
+
*
|
|
11
|
+
* 2. `escalate` — on a failed stage, NO retries are attempted. The run
|
|
12
|
+
* fails immediately, marked retriable.
|
|
13
|
+
*
|
|
14
|
+
* 3. `fail-fast` — on a failed stage, NO retries. The run fails
|
|
15
|
+
* immediately, marked NON-retriable (no automatic recovery).
|
|
16
|
+
*
|
|
17
|
+
* Mock strategy: hijack `executeStage` to return failed/completed based on a
|
|
18
|
+
* per-test counter, then call `runner.start()` directly and inspect the DB.
|
|
19
|
+
* Avoids the webhook-driven scaffolding in ralph-gate.test.ts since retry
|
|
20
|
+
* logic doesn't depend on it.
|
|
21
|
+
*/
|
|
22
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
23
|
+
import { createDb } from "../db/client.js";
|
|
24
|
+
import { PipelineRunner } from "../pipeline/runner.js";
|
|
25
|
+
import { pipelineRuns } from "../db/schema.js";
|
|
26
|
+
import { eq } from "drizzle-orm";
|
|
27
|
+
import { installTestProLicense, restoreLicense } from "./helpers/license.js";
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Mock surface
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
const { mockCreatePRViaCli, mockExecFile } = vi.hoisted(() => ({
|
|
32
|
+
mockCreatePRViaCli: vi
|
|
33
|
+
.fn()
|
|
34
|
+
.mockResolvedValue("https://github.com/test/repo/pull/99"),
|
|
35
|
+
mockExecFile: vi.fn().mockImplementation((...args) => {
|
|
36
|
+
const cb = args.find((a) => typeof a === "function");
|
|
37
|
+
if (cb)
|
|
38
|
+
cb(null, "", "");
|
|
39
|
+
}),
|
|
40
|
+
}));
|
|
41
|
+
let stageResultsQueue = [];
|
|
42
|
+
let executeStageCalls = [];
|
|
43
|
+
function handoffFor(runId, issueId, stage) {
|
|
44
|
+
return {
|
|
45
|
+
runId,
|
|
46
|
+
issueId,
|
|
47
|
+
stage,
|
|
48
|
+
timestamp: new Date().toISOString(),
|
|
49
|
+
summary: `Stage ${stage} done`,
|
|
50
|
+
filesChanged: ["src/feature.ts"],
|
|
51
|
+
approach: `approach for ${stage}`,
|
|
52
|
+
context: {
|
|
53
|
+
issueIntent: "test retry strategies",
|
|
54
|
+
constraints: [],
|
|
55
|
+
assumptions: [],
|
|
56
|
+
},
|
|
57
|
+
tokenBudget: { contextTokensUsed: 100, recommendedMaxTurns: 3 },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
vi.mock("../executor/executor.js", () => ({
|
|
61
|
+
executeStage: vi.fn().mockImplementation(async ({ runId, issueId, stage, db }) => {
|
|
62
|
+
const { nanoid } = await import("nanoid");
|
|
63
|
+
const { stageRuns: stageRunsTable } = await import("../db/schema.js");
|
|
64
|
+
const { eq: drizzleEq } = await import("drizzle-orm");
|
|
65
|
+
const attempt = executeStageCalls.filter((c) => c.stage === stage).length;
|
|
66
|
+
executeStageCalls.push({ stage, attempt });
|
|
67
|
+
const verdict = stageResultsQueue.shift() ?? "completed";
|
|
68
|
+
const stageRunId = nanoid();
|
|
69
|
+
await db.insert(stageRunsTable).values({
|
|
70
|
+
id: stageRunId,
|
|
71
|
+
pipelineRunId: runId,
|
|
72
|
+
stage,
|
|
73
|
+
status: "running",
|
|
74
|
+
});
|
|
75
|
+
await db
|
|
76
|
+
.update(stageRunsTable)
|
|
77
|
+
.set({
|
|
78
|
+
status: verdict,
|
|
79
|
+
completedAt: new Date(),
|
|
80
|
+
inputTokens: 100,
|
|
81
|
+
outputTokens: 50,
|
|
82
|
+
turns: 1,
|
|
83
|
+
handoffArtifact: JSON.stringify(handoffFor(runId, issueId, stage)),
|
|
84
|
+
errorMessage: verdict === "failed" ? "simulated stage failure" : null,
|
|
85
|
+
})
|
|
86
|
+
.where(drizzleEq(stageRunsTable.id, stageRunId));
|
|
87
|
+
return {
|
|
88
|
+
status: verdict,
|
|
89
|
+
inputTokens: 100,
|
|
90
|
+
outputTokens: 50,
|
|
91
|
+
turns: 1,
|
|
92
|
+
...(verdict === "completed"
|
|
93
|
+
? {
|
|
94
|
+
handoffArtifact: handoffFor(runId, issueId, stage),
|
|
95
|
+
handoffIsStructured: true,
|
|
96
|
+
}
|
|
97
|
+
: { errorMessage: "simulated stage failure" }),
|
|
98
|
+
stageRunId,
|
|
99
|
+
};
|
|
100
|
+
}),
|
|
101
|
+
}));
|
|
102
|
+
vi.mock("../repo/git.js", () => ({
|
|
103
|
+
cloneRepo: vi.fn().mockResolvedValue(undefined),
|
|
104
|
+
createWorktree: vi.fn().mockResolvedValue("/tmp/retry-strategies-worktree"),
|
|
105
|
+
deleteWorktree: vi.fn().mockResolvedValue(undefined),
|
|
106
|
+
pushBranch: vi.fn().mockResolvedValue(undefined),
|
|
107
|
+
pushBranchForce: vi.fn().mockResolvedValue(undefined),
|
|
108
|
+
rebaseBranch: vi.fn().mockResolvedValue({ success: true, hasConflicts: false }),
|
|
109
|
+
abortRebase: vi.fn().mockResolvedValue(undefined),
|
|
110
|
+
autoCommitChanges: vi.fn().mockResolvedValue(false),
|
|
111
|
+
createPRViaCli: mockCreatePRViaCli,
|
|
112
|
+
mergePRViaCli: vi.fn().mockResolvedValue(true),
|
|
113
|
+
getDiffLineCount: vi.fn().mockResolvedValue(50),
|
|
114
|
+
getChangedFiles: vi.fn().mockResolvedValue(["src/feature.ts"]),
|
|
115
|
+
checkDuplicateBranch: vi.fn().mockResolvedValue(null),
|
|
116
|
+
cleanupWorktrees: vi.fn().mockResolvedValue([]),
|
|
117
|
+
branchName: vi.fn().mockImplementation((id, slug) => `agent/${id}-${slug}`),
|
|
118
|
+
gitExecSafe: vi.fn().mockResolvedValue(""),
|
|
119
|
+
gitExecRaw: vi.fn().mockResolvedValue(""),
|
|
120
|
+
gitExec: vi.fn().mockResolvedValue(""),
|
|
121
|
+
choosePushStrategy: vi.fn().mockReturnValue("standard"),
|
|
122
|
+
getAgentCommits: vi.fn().mockResolvedValue([]),
|
|
123
|
+
installPrePushHook: vi.fn().mockResolvedValue(undefined),
|
|
124
|
+
}));
|
|
125
|
+
vi.mock("../executor/test-quality.js", () => ({
|
|
126
|
+
checkTestQuality: vi.fn().mockResolvedValue({ violations: [] }),
|
|
127
|
+
}));
|
|
128
|
+
vi.mock("../repo/tech-stack.js", () => ({
|
|
129
|
+
detectTechStack: vi.fn().mockResolvedValue({
|
|
130
|
+
languages: ["typescript"],
|
|
131
|
+
frameworks: [],
|
|
132
|
+
buildSystems: ["pnpm"],
|
|
133
|
+
}),
|
|
134
|
+
}));
|
|
135
|
+
vi.mock("../repo/devcontainer.js", () => ({
|
|
136
|
+
shouldUseDevcontainer: vi.fn().mockResolvedValue(false),
|
|
137
|
+
devcontainerUp: vi.fn().mockResolvedValue(undefined),
|
|
138
|
+
devcontainerDown: vi.fn().mockResolvedValue(undefined),
|
|
139
|
+
}));
|
|
140
|
+
vi.mock("../pm/coordination.js", () => ({
|
|
141
|
+
upsertActiveWork: vi.fn().mockResolvedValue(undefined),
|
|
142
|
+
removeActiveWork: vi.fn().mockResolvedValue(undefined),
|
|
143
|
+
checkFileOverlap: vi.fn().mockResolvedValue({
|
|
144
|
+
hasOverlap: false,
|
|
145
|
+
overlappingFiles: [],
|
|
146
|
+
conflictingRunIds: [],
|
|
147
|
+
}),
|
|
148
|
+
getModifiedFiles: vi.fn().mockResolvedValue([]),
|
|
149
|
+
}));
|
|
150
|
+
vi.mock("node:child_process", () => ({
|
|
151
|
+
execFile: mockExecFile,
|
|
152
|
+
}));
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
// Fixtures
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
const REPO_CONFIG = {
|
|
157
|
+
url: "https://github.com/test/test-repo.git",
|
|
158
|
+
defaultBranch: "main",
|
|
159
|
+
testCommand: "pnpm test",
|
|
160
|
+
buildCommand: "pnpm build",
|
|
161
|
+
};
|
|
162
|
+
function makePipelineConfig(retry, stages = ["implement"]) {
|
|
163
|
+
return {
|
|
164
|
+
name: "Auto Implement",
|
|
165
|
+
stages,
|
|
166
|
+
retry,
|
|
167
|
+
review: { requiredApprovals: 0 },
|
|
168
|
+
prStrategy: "ready",
|
|
169
|
+
validateHandoffs: false,
|
|
170
|
+
ralphIterations: 0, // disable RALPH so the retry-loop is the only re-exec path
|
|
171
|
+
reviewFixIterations: 0,
|
|
172
|
+
deepReviewPasses: 0,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const ISSUE = {
|
|
176
|
+
id: "issue-rs-1",
|
|
177
|
+
identifier: "RS-1",
|
|
178
|
+
title: "retry-strategies test issue",
|
|
179
|
+
description: "Test retry strategies",
|
|
180
|
+
priority: 2,
|
|
181
|
+
};
|
|
182
|
+
async function waitForRunComplete(db, issueId, timeoutMs = 5_000) {
|
|
183
|
+
const deadline = Date.now() + timeoutMs;
|
|
184
|
+
while (Date.now() < deadline) {
|
|
185
|
+
const rows = await db.select().from(pipelineRuns).where(eq(pipelineRuns.issueId, issueId));
|
|
186
|
+
if (rows.length > 0) {
|
|
187
|
+
const run = rows[0];
|
|
188
|
+
if (["completed", "failed", "retriable", "aborted"].includes(run.status)) {
|
|
189
|
+
return run;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
await new Promise((r) => setTimeout(r, 25));
|
|
193
|
+
}
|
|
194
|
+
throw new Error(`Pipeline for ${issueId} did not finish within ${timeoutMs}ms`);
|
|
195
|
+
}
|
|
196
|
+
// ---------------------------------------------------------------------------
|
|
197
|
+
// Tests
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
describe("PipelineRunner retry strategies (BEC-200)", () => {
|
|
200
|
+
let db;
|
|
201
|
+
let notifier;
|
|
202
|
+
beforeEach(async () => {
|
|
203
|
+
await installTestProLicense();
|
|
204
|
+
stageResultsQueue = [];
|
|
205
|
+
executeStageCalls = [];
|
|
206
|
+
mockCreatePRViaCli.mockClear();
|
|
207
|
+
db = await createDb({ driver: "sqlite", connectionString: ":memory:" });
|
|
208
|
+
notifier = {
|
|
209
|
+
onPipelineStart: vi.fn(async () => { }),
|
|
210
|
+
onStageComplete: vi.fn(async () => { }),
|
|
211
|
+
onPipelineComplete: vi.fn(async () => { }),
|
|
212
|
+
onPipelineFailed: vi.fn(async () => { }),
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
afterEach(async () => {
|
|
216
|
+
await restoreLicense();
|
|
217
|
+
});
|
|
218
|
+
function makeRunner() {
|
|
219
|
+
return new PipelineRunner({
|
|
220
|
+
db,
|
|
221
|
+
notifier,
|
|
222
|
+
concurrency: 1,
|
|
223
|
+
agentRunDir: "/tmp/retry-strategies-runs",
|
|
224
|
+
repoCloneDir: "/tmp/retry-strategies-repos",
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
it("fix-and-retry: stage succeeds after one retry → stageRetries[stage] = 1, run completes", async () => {
|
|
228
|
+
// First implement call fails, second (retry attempt 1) succeeds.
|
|
229
|
+
stageResultsQueue = ["failed", "completed"];
|
|
230
|
+
const config = makePipelineConfig({ maxAttempts: 2, strategy: "fix-and-retry" });
|
|
231
|
+
const runner = makeRunner();
|
|
232
|
+
const issue = { ...ISSUE, identifier: "RS-1" };
|
|
233
|
+
await runner.start(issue, "auto-implement", config, REPO_CONFIG, issue);
|
|
234
|
+
const run = await waitForRunComplete(db, "RS-1");
|
|
235
|
+
expect(run.status).toBe("completed");
|
|
236
|
+
expect(executeStageCalls.filter((c) => c.stage === "implement")).toHaveLength(2);
|
|
237
|
+
});
|
|
238
|
+
it("fix-and-retry: exhausts maxAttempts → run marked retriable, stageRetries shows N retries", async () => {
|
|
239
|
+
// initial + 2 retries all fail
|
|
240
|
+
stageResultsQueue = ["failed", "failed", "failed"];
|
|
241
|
+
const config = makePipelineConfig({ maxAttempts: 2, strategy: "fix-and-retry" });
|
|
242
|
+
const runner = makeRunner();
|
|
243
|
+
const issue = { ...ISSUE, identifier: "RS-2" };
|
|
244
|
+
await runner.start(issue, "auto-implement", config, REPO_CONFIG, issue);
|
|
245
|
+
const run = await waitForRunComplete(db, "RS-2");
|
|
246
|
+
// failPipeline with retriable=true sets status="retriable" (auto-recovery candidate)
|
|
247
|
+
expect(["retriable", "failed"]).toContain(run.status);
|
|
248
|
+
// 1 initial + 2 retries
|
|
249
|
+
expect(executeStageCalls.filter((c) => c.stage === "implement")).toHaveLength(3);
|
|
250
|
+
});
|
|
251
|
+
it("escalate: NO retries on failure — fails immediately", async () => {
|
|
252
|
+
stageResultsQueue = ["failed"];
|
|
253
|
+
const config = makePipelineConfig({ maxAttempts: 5, strategy: "escalate" });
|
|
254
|
+
const runner = makeRunner();
|
|
255
|
+
const issue = { ...ISSUE, identifier: "RS-3" };
|
|
256
|
+
await runner.start(issue, "auto-implement", config, REPO_CONFIG, issue);
|
|
257
|
+
const run = await waitForRunComplete(db, "RS-3");
|
|
258
|
+
expect(["retriable", "failed"]).toContain(run.status);
|
|
259
|
+
// Strategy "escalate" enters the retry loop but breaks on the first
|
|
260
|
+
// iteration — so executeStage is called exactly once.
|
|
261
|
+
expect(executeStageCalls.filter((c) => c.stage === "implement")).toHaveLength(1);
|
|
262
|
+
});
|
|
263
|
+
it("fail-fast: NO retries, marks run as failed (non-retriable)", async () => {
|
|
264
|
+
stageResultsQueue = ["failed"];
|
|
265
|
+
const config = makePipelineConfig({ maxAttempts: 5, strategy: "fail-fast" });
|
|
266
|
+
const runner = makeRunner();
|
|
267
|
+
const issue = { ...ISSUE, identifier: "RS-4" };
|
|
268
|
+
await runner.start(issue, "auto-implement", config, REPO_CONFIG, issue);
|
|
269
|
+
const run = await waitForRunComplete(db, "RS-4");
|
|
270
|
+
expect(run.status).toBe("failed");
|
|
271
|
+
expect(executeStageCalls.filter((c) => c.stage === "implement")).toHaveLength(1);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
//# sourceMappingURL=runner-retry-strategies.test.js.map
|