@urateam/core 0.1.33 → 0.1.34

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.
Files changed (44) hide show
  1. package/dist/__tests__/audit-immutability.test.js +43 -0
  2. package/dist/__tests__/audit-immutability.test.js.map +1 -1
  3. package/dist/__tests__/pm-scheduler.test.js +59 -0
  4. package/dist/__tests__/pm-scheduler.test.js.map +1 -1
  5. package/dist/__tests__/runner-retry-strategies.test.d.ts +23 -0
  6. package/dist/__tests__/runner-retry-strategies.test.d.ts.map +1 -0
  7. package/dist/__tests__/runner-retry-strategies.test.js +274 -0
  8. package/dist/__tests__/runner-retry-strategies.test.js.map +1 -0
  9. package/dist/__tests__/scratch-file-guard.test.d.ts +2 -0
  10. package/dist/__tests__/scratch-file-guard.test.d.ts.map +1 -0
  11. package/dist/__tests__/scratch-file-guard.test.js +144 -0
  12. package/dist/__tests__/scratch-file-guard.test.js.map +1 -0
  13. package/dist/__tests__/spec-vs-impl-gate.test.d.ts +2 -0
  14. package/dist/__tests__/spec-vs-impl-gate.test.d.ts.map +1 -0
  15. package/dist/__tests__/spec-vs-impl-gate.test.js +222 -0
  16. package/dist/__tests__/spec-vs-impl-gate.test.js.map +1 -0
  17. package/dist/__tests__/typecheck-gate.test.d.ts +2 -0
  18. package/dist/__tests__/typecheck-gate.test.d.ts.map +1 -0
  19. package/dist/__tests__/typecheck-gate.test.js +196 -0
  20. package/dist/__tests__/typecheck-gate.test.js.map +1 -0
  21. package/dist/audit/events.d.ts +39 -0
  22. package/dist/audit/events.d.ts.map +1 -1
  23. package/dist/audit/events.js +60 -0
  24. package/dist/audit/events.js.map +1 -1
  25. package/dist/pipeline/runner.d.ts.map +1 -1
  26. package/dist/pipeline/runner.js +145 -1
  27. package/dist/pipeline/runner.js.map +1 -1
  28. package/dist/pipeline/scratch-file-guard.d.ts +21 -0
  29. package/dist/pipeline/scratch-file-guard.d.ts.map +1 -0
  30. package/dist/pipeline/scratch-file-guard.js +155 -0
  31. package/dist/pipeline/scratch-file-guard.js.map +1 -0
  32. package/dist/pipeline/spec-vs-impl-gate.d.ts +49 -0
  33. package/dist/pipeline/spec-vs-impl-gate.d.ts.map +1 -0
  34. package/dist/pipeline/spec-vs-impl-gate.js +177 -0
  35. package/dist/pipeline/spec-vs-impl-gate.js.map +1 -0
  36. package/dist/pipeline/typecheck-gate.d.ts +34 -0
  37. package/dist/pipeline/typecheck-gate.d.ts.map +1 -0
  38. package/dist/pipeline/typecheck-gate.js +89 -0
  39. package/dist/pipeline/typecheck-gate.js.map +1 -0
  40. package/dist/types.d.ts +6 -0
  41. package/dist/types.d.ts.map +1 -1
  42. package/dist/types.js +13 -0
  43. package/dist/types.js.map +1 -1
  44. 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, "../../../..");
@@ -82,5 +84,46 @@ describe("audit_events immutability", () => {
82
84
  .filter((file) => !allowed.some((a) => file.endsWith(a) || file === a));
83
85
  expect(offenders, `Unauthorized logAuditEventUnchecked usage in:\n${offenders.join("\n")}`).toEqual([]);
84
86
  });
87
+ /**
88
+ * Tier 1d — keep CLAUDE.md's claimed audit-event count in sync with
89
+ * AuditEventTypeSchema. The autonomous pipeline has historically added new
90
+ * event types to the schema without updating the doc count (see Tier 1a's
91
+ * pre-existing 17→41 drift). This test fails CI when the regex match
92
+ * `(\d+) event types` in CLAUDE.md disagrees with `AuditEventTypeSchema`'s
93
+ * length.
94
+ *
95
+ * The pipeline's review-stage prompt will surface this as a blocking
96
+ * `audit-count-drift` finding via the convention checklist (Tier 2);
97
+ * the unit test is the deterministic backstop.
98
+ */
99
+ it("CLAUDE.md audit-event count matches AuditEventTypeSchema length", () => {
100
+ const repoRoot = path.resolve(__dirname, "../../../..");
101
+ const claudeMd = readFileSync(path.join(repoRoot, "CLAUDE.md"), "utf8");
102
+ const matches = [...claudeMd.matchAll(/(\d+)\s+event\s+types/g)];
103
+ expect(matches.length, "CLAUDE.md must contain exactly one `<N> event types` sentence so Tier 1d can lock it down").toBe(1);
104
+ const documented = Number(matches[0][1]);
105
+ const actual = AuditEventTypeSchema.options.length;
106
+ expect(documented, `CLAUDE.md says "${documented} event types" but AuditEventTypeSchema has ${actual}. Update CLAUDE.md or the schema; they must match.`).toBe(actual);
107
+ });
108
+ /**
109
+ * Tier 1d — mirror of the event-type count check for the actor-type enum.
110
+ * The actor-type list is shorter and changes less often, but the same drift
111
+ * pattern applies (e.g. BEC-207 added a new actor without updating any doc).
112
+ * CLAUDE.md doesn't currently cite a number for actor types, so this test
113
+ * is gated: it only runs if a `(\d+) actor types` sentence is present, and
114
+ * fails when present-but-stale. Removes the test gracefully when the doc
115
+ * doesn't enumerate.
116
+ */
117
+ it("CLAUDE.md actor-type count matches AuditActorTypeSchema length (when present)", () => {
118
+ const repoRoot = path.resolve(__dirname, "../../../..");
119
+ const claudeMd = readFileSync(path.join(repoRoot, "CLAUDE.md"), "utf8");
120
+ const matches = [...claudeMd.matchAll(/(\d+)\s+actor\s+types/g)];
121
+ if (matches.length === 0)
122
+ return; // not enumerated; nothing to validate
123
+ expect(matches.length, "CLAUDE.md must contain at most one `<N> actor types` sentence").toBe(1);
124
+ const documented = Number(matches[0][1]);
125
+ const actual = AuditActorTypeSchema.options.length;
126
+ expect(documented, `CLAUDE.md says "${documented} actor types" but AuditActorTypeSchema has ${actual}.`).toBe(actual);
127
+ });
85
128
  });
86
129
  //# 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":"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"}
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":"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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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-retry-strategies.test.js","sourceRoot":"","sources":["../../src/__tests__/runner-retry-strategies.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scratch-file-guard.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scratch-file-guard.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/scratch-file-guard.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Tier 1a — scratch-file denylist gate.
3
+ *
4
+ * `findScratchFiles` is wired into the pipeline runner just before push and
5
+ * forces draft + a `category: "scratch-files"` blocking finding when any of
6
+ * the agent's added files match the denylist (FINAL_CHECKLIST.md,
7
+ * commit-test-changes.sh, TESTING_COMPLETE.md, *.bak, untracked *.log, etc).
8
+ *
9
+ * The matcher is a pure function so it can be tested without git. The git
10
+ * layer (`enumerateAddedFiles`) is exercised by the runner integration.
11
+ */
12
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
13
+ import { matchScratchPatterns } from "../pipeline/scratch-file-guard.js";
14
+ describe("matchScratchPatterns — fires on bad cases", () => {
15
+ it("matches FINAL_CHECKLIST.md at repo root", () => {
16
+ expect(matchScratchPatterns(["FINAL_CHECKLIST.md"])).toEqual([
17
+ "FINAL_CHECKLIST.md",
18
+ ]);
19
+ });
20
+ it("matches TESTING_COMPLETE.md at repo root (TESTING_* pattern)", () => {
21
+ expect(matchScratchPatterns(["TESTING_COMPLETE.md"])).toEqual([
22
+ "TESTING_COMPLETE.md",
23
+ ]);
24
+ });
25
+ it("matches *_REPORT.md (case-insensitive)", () => {
26
+ expect(matchScratchPatterns(["VERIFICATION_REPORT.md"])).toEqual([
27
+ "VERIFICATION_REPORT.md",
28
+ ]);
29
+ expect(matchScratchPatterns(["test_report.md"])).toEqual(["test_report.md"]);
30
+ });
31
+ it("matches TEST_*.md at repo root", () => {
32
+ expect(matchScratchPatterns(["TEST_PLAN.md"])).toEqual(["TEST_PLAN.md"]);
33
+ });
34
+ it("matches FINAL_*.md at repo root", () => {
35
+ expect(matchScratchPatterns(["FINAL_NOTES.md"])).toEqual(["FINAL_NOTES.md"]);
36
+ });
37
+ it("matches *.bak and *.bak.* anywhere", () => {
38
+ expect(matchScratchPatterns(["foo.bak"])).toEqual(["foo.bak"]);
39
+ expect(matchScratchPatterns(["src/utils.ts.bak"])).toEqual(["src/utils.ts.bak"]);
40
+ expect(matchScratchPatterns(["config.bak.20260511"])).toEqual([
41
+ "config.bak.20260511",
42
+ ]);
43
+ });
44
+ it("matches root-level commit-*.sh and run-*.sh", () => {
45
+ expect(matchScratchPatterns(["commit-test-changes.sh"])).toEqual([
46
+ "commit-test-changes.sh",
47
+ ]);
48
+ expect(matchScratchPatterns(["run-verification.sh"])).toEqual([
49
+ "run-verification.sh",
50
+ ]);
51
+ });
52
+ it("matches *.tmp anywhere", () => {
53
+ expect(matchScratchPatterns(["scratch.tmp"])).toEqual(["scratch.tmp"]);
54
+ expect(matchScratchPatterns(["src/foo.tmp"])).toEqual(["src/foo.tmp"]);
55
+ });
56
+ it("matches untracked *.log anywhere", () => {
57
+ expect(matchScratchPatterns(["debug.log"])).toEqual(["debug.log"]);
58
+ expect(matchScratchPatterns(["logs/run.log"])).toEqual(["logs/run.log"]);
59
+ });
60
+ it("matches any new repo-root *.md NOT in the exemption set", () => {
61
+ expect(matchScratchPatterns(["NOTES.md"])).toEqual(["NOTES.md"]);
62
+ expect(matchScratchPatterns(["scratch.md"])).toEqual(["scratch.md"]);
63
+ expect(matchScratchPatterns(["SUMMARY.md"])).toEqual(["SUMMARY.md"]);
64
+ });
65
+ it("returns all matches in input order, deduped", () => {
66
+ const matches = matchScratchPatterns([
67
+ "FINAL_CHECKLIST.md",
68
+ "src/foo.ts",
69
+ "commit-test.sh",
70
+ "debug.log",
71
+ ]);
72
+ expect(matches).toEqual([
73
+ "FINAL_CHECKLIST.md",
74
+ "commit-test.sh",
75
+ "debug.log",
76
+ ]);
77
+ });
78
+ });
79
+ describe("matchScratchPatterns — does NOT fire on clean diffs", () => {
80
+ it("does not match repo-root README.md (tracked exemption)", () => {
81
+ expect(matchScratchPatterns(["README.md"])).toEqual([]);
82
+ });
83
+ it("does not match repo-root CLAUDE.md (tracked exemption)", () => {
84
+ expect(matchScratchPatterns(["CLAUDE.md"])).toEqual([]);
85
+ });
86
+ it("does not match repo-root CHANGELOG.md, CONTRIBUTING.md, SECURITY.md, CODE_OF_CONDUCT.md, LICENSE.md, AUTHORS.md", () => {
87
+ expect(matchScratchPatterns([
88
+ "CHANGELOG.md",
89
+ "CONTRIBUTING.md",
90
+ "SECURITY.md",
91
+ "CODE_OF_CONDUCT.md",
92
+ "LICENSE.md",
93
+ "AUTHORS.md",
94
+ ])).toEqual([]);
95
+ });
96
+ it("does not match exemptions case-insensitively (Readme.md, Changelog.md)", () => {
97
+ expect(matchScratchPatterns(["Readme.md", "Changelog.md"])).toEqual([]);
98
+ });
99
+ it("does not match docs in subdirectories (docs/foo.md, .github/PULL_REQUEST_TEMPLATE.md)", () => {
100
+ expect(matchScratchPatterns([
101
+ "docs/feature.md",
102
+ ".github/PULL_REQUEST_TEMPLATE.md",
103
+ "packages/core/README.md",
104
+ ])).toEqual([]);
105
+ });
106
+ it("does not match real source files (src/foo.ts, packages/core/src/runner.ts, scripts/sync.ts)", () => {
107
+ expect(matchScratchPatterns([
108
+ "src/foo.ts",
109
+ "packages/core/src/pipeline/runner.ts",
110
+ "scripts/gh-linear-sync.ts",
111
+ "tests/foo.test.ts",
112
+ ])).toEqual([]);
113
+ });
114
+ it("does not match nested .sh scripts (scripts/setup.sh) — only root commit-*.sh / run-*.sh", () => {
115
+ expect(matchScratchPatterns(["scripts/setup.sh", "deploy/restart.sh"])).toEqual([]);
116
+ });
117
+ it("returns empty array for an empty input", () => {
118
+ expect(matchScratchPatterns([])).toEqual([]);
119
+ });
120
+ });
121
+ describe("findScratchFiles env-var escape hatch", () => {
122
+ const ENV_KEY = "URATEAM_DISABLE_SCRATCH_GUARD";
123
+ beforeEach(() => {
124
+ delete process.env[ENV_KEY];
125
+ });
126
+ afterEach(() => {
127
+ delete process.env[ENV_KEY];
128
+ });
129
+ it("when URATEAM_DISABLE_SCRATCH_GUARD=true, returns skipped=true and empty files (no git work)", async () => {
130
+ process.env[ENV_KEY] = "true";
131
+ const { findScratchFiles } = await import("../pipeline/scratch-file-guard.js");
132
+ const result = await findScratchFiles("/nonexistent/path", "main");
133
+ expect(result).toEqual({ files: [], skipped: true });
134
+ });
135
+ it("when URATEAM_DISABLE_SCRATCH_GUARD is unset, gate is active (returns skipped=false)", async () => {
136
+ // We don't have a real worktree here, so we just confirm skipped is false.
137
+ // The git layer is exercised by the runner integration tests.
138
+ const { findScratchFiles } = await import("../pipeline/scratch-file-guard.js");
139
+ // Use a path that exists but is not a git repo so git commands return [].
140
+ const result = await findScratchFiles("/tmp", "main");
141
+ expect(result.skipped).toBe(false);
142
+ });
143
+ });
144
+ //# sourceMappingURL=scratch-file-guard.test.js.map