@urateam/core 0.1.25 → 0.1.26
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__/agent-stream-cache-tokens.test.d.ts +2 -0
- package/dist/__tests__/agent-stream-cache-tokens.test.d.ts.map +1 -0
- package/dist/__tests__/agent-stream-cache-tokens.test.js +25 -0
- package/dist/__tests__/agent-stream-cache-tokens.test.js.map +1 -0
- package/dist/__tests__/audit/pm-skipped-circuit-breaker-event.test.d.ts +2 -0
- package/dist/__tests__/audit/pm-skipped-circuit-breaker-event.test.d.ts.map +1 -0
- package/dist/__tests__/audit/pm-skipped-circuit-breaker-event.test.js +32 -0
- package/dist/__tests__/audit/pm-skipped-circuit-breaker-event.test.js.map +1 -0
- package/dist/__tests__/audit/review-model-low-output-ratio-event.test.d.ts +2 -0
- package/dist/__tests__/audit/review-model-low-output-ratio-event.test.d.ts.map +1 -0
- package/dist/__tests__/audit/review-model-low-output-ratio-event.test.js +23 -0
- package/dist/__tests__/audit/review-model-low-output-ratio-event.test.js.map +1 -0
- package/dist/__tests__/audit-immutability.test.js +2 -0
- package/dist/__tests__/audit-immutability.test.js.map +1 -1
- package/dist/__tests__/bec-181-circuit-breaker-audit-gap.test.d.ts +24 -0
- package/dist/__tests__/bec-181-circuit-breaker-audit-gap.test.d.ts.map +1 -0
- package/dist/__tests__/bec-181-circuit-breaker-audit-gap.test.js +253 -0
- package/dist/__tests__/bec-181-circuit-breaker-audit-gap.test.js.map +1 -0
- package/dist/__tests__/executor/review-feedback-profile-override.test.d.ts +2 -0
- package/dist/__tests__/executor/review-feedback-profile-override.test.d.ts.map +1 -0
- package/dist/__tests__/executor/review-feedback-profile-override.test.js +32 -0
- package/dist/__tests__/executor/review-feedback-profile-override.test.js.map +1 -0
- package/dist/__tests__/executor/review-feedback-prompt.test.d.ts +2 -0
- package/dist/__tests__/executor/review-feedback-prompt.test.d.ts.map +1 -0
- package/dist/__tests__/executor/review-feedback-prompt.test.js +29 -0
- package/dist/__tests__/executor/review-feedback-prompt.test.js.map +1 -0
- package/dist/__tests__/pipeline/pr-cost-summary.test.js +23 -0
- package/dist/__tests__/pipeline/pr-cost-summary.test.js.map +1 -1
- package/dist/__tests__/pm-circuit-breaker.test.js +86 -15
- package/dist/__tests__/pm-circuit-breaker.test.js.map +1 -1
- package/dist/__tests__/prune-worktrees-in-repo-dirs.test.d.ts +2 -0
- package/dist/__tests__/prune-worktrees-in-repo-dirs.test.d.ts.map +1 -0
- package/dist/__tests__/prune-worktrees-in-repo-dirs.test.js +64 -0
- package/dist/__tests__/prune-worktrees-in-repo-dirs.test.js.map +1 -0
- package/dist/__tests__/review/model-health.test.d.ts +2 -0
- package/dist/__tests__/review/model-health.test.d.ts.map +1 -0
- package/dist/__tests__/review/model-health.test.js +122 -0
- package/dist/__tests__/review/model-health.test.js.map +1 -0
- package/dist/__tests__/review-feedback.test.js +3 -2
- package/dist/__tests__/review-feedback.test.js.map +1 -1
- package/dist/__tests__/runner-ralph-feedback-skip.test.d.ts +2 -0
- package/dist/__tests__/runner-ralph-feedback-skip.test.d.ts.map +1 -0
- package/dist/__tests__/runner-ralph-feedback-skip.test.js +23 -0
- package/dist/__tests__/runner-ralph-feedback-skip.test.js.map +1 -0
- package/dist/__tests__/templates.test.js +4 -2
- package/dist/__tests__/templates.test.js.map +1 -1
- package/dist/__tests__/worktree-stale-recovery.test.js +11 -1
- package/dist/__tests__/worktree-stale-recovery.test.js.map +1 -1
- package/dist/audit/events.d.ts +12 -0
- package/dist/audit/events.d.ts.map +1 -1
- package/dist/audit/events.js +26 -0
- package/dist/audit/events.js.map +1 -1
- package/dist/db/migrations/postgres/013_stage_runs_cache_tokens.sql +6 -0
- package/dist/db/migrations/sqlite/012_stage_runs_cache_tokens.sql +6 -0
- package/dist/db/schema.d.ts +34 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +2 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/executor/agent-stream.d.ts +4 -0
- package/dist/executor/agent-stream.d.ts.map +1 -1
- package/dist/executor/agent-stream.js +5 -1
- package/dist/executor/agent-stream.js.map +1 -1
- package/dist/executor/executor.d.ts +9 -1
- package/dist/executor/executor.d.ts.map +1 -1
- package/dist/executor/executor.js +26 -4
- package/dist/executor/executor.js.map +1 -1
- package/dist/executor/prompt/templates.js +8 -8
- package/dist/executor/prompt/templates.js.map +1 -1
- package/dist/executor/review/model-health.d.ts +28 -0
- package/dist/executor/review/model-health.d.ts.map +1 -0
- package/dist/executor/review/model-health.js +64 -0
- package/dist/executor/review/model-health.js.map +1 -0
- package/dist/pipeline/cost-summary.d.ts +2 -0
- package/dist/pipeline/cost-summary.d.ts.map +1 -1
- package/dist/pipeline/cost-summary.js +18 -7
- package/dist/pipeline/cost-summary.js.map +1 -1
- package/dist/pipeline/review-providers-runner.d.ts.map +1 -1
- package/dist/pipeline/review-providers-runner.js +49 -0
- package/dist/pipeline/review-providers-runner.js.map +1 -1
- package/dist/pipeline/runner-ralph-helpers.d.ts +8 -0
- package/dist/pipeline/runner-ralph-helpers.d.ts.map +1 -0
- package/dist/pipeline/runner-ralph-helpers.js +15 -0
- package/dist/pipeline/runner-ralph-helpers.js.map +1 -0
- package/dist/pipeline/runner.d.ts +2 -2
- package/dist/pipeline/runner.d.ts.map +1 -1
- package/dist/pipeline/runner.js +10 -18
- package/dist/pipeline/runner.js.map +1 -1
- package/dist/pm/actions/db-queries.d.ts +11 -0
- package/dist/pm/actions/db-queries.d.ts.map +1 -1
- package/dist/pm/actions/db-queries.js +46 -0
- package/dist/pm/actions/db-queries.js.map +1 -1
- package/dist/pm/actions/promote.d.ts +5 -4
- package/dist/pm/actions/promote.d.ts.map +1 -1
- package/dist/pm/actions/promote.js +24 -4
- package/dist/pm/actions/promote.js.map +1 -1
- package/dist/pm/actions/start-todo.d.ts +4 -3
- package/dist/pm/actions/start-todo.d.ts.map +1 -1
- package/dist/pm/actions/start-todo.js +29 -8
- package/dist/pm/actions/start-todo.js.map +1 -1
- package/dist/pm/scheduler.d.ts.map +1 -1
- package/dist/pm/scheduler.js +6 -3
- package/dist/pm/scheduler.js.map +1 -1
- package/dist/repo/git.d.ts +27 -2
- package/dist/repo/git.d.ts.map +1 -1
- package/dist/repo/git.js +67 -8
- package/dist/repo/git.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-stream-cache-tokens.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/agent-stream-cache-tokens.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { consumeAgentStream } from "../executor/agent-stream.js";
|
|
3
|
+
describe("consumeAgentStream — cache tokens (BEC: cache telemetry)", () => {
|
|
4
|
+
it("accumulates cache_creation_input_tokens and cache_read_input_tokens from message.usage", async () => {
|
|
5
|
+
async function* fakeStream() {
|
|
6
|
+
yield { type: "assistant", usage: { input_tokens: 100, cache_creation_input_tokens: 5000, cache_read_input_tokens: 0, output_tokens: 200 }, content: [{ type: "text", text: "" }] };
|
|
7
|
+
yield { type: "assistant", usage: { input_tokens: 50, cache_creation_input_tokens: 0, cache_read_input_tokens: 5000, output_tokens: 300 }, content: [{ type: "text", text: "" }] };
|
|
8
|
+
yield { type: "assistant", usage: { input_tokens: 50, cache_creation_input_tokens: 0, cache_read_input_tokens: 5000, output_tokens: 250 }, content: [{ type: "text", text: "done" }] };
|
|
9
|
+
}
|
|
10
|
+
const result = await consumeAgentStream(fakeStream());
|
|
11
|
+
expect(result.inputTokens).toBe(200);
|
|
12
|
+
expect(result.outputTokens).toBe(750);
|
|
13
|
+
expect(result.cacheCreationInputTokens).toBe(5000);
|
|
14
|
+
expect(result.cacheReadInputTokens).toBe(10000);
|
|
15
|
+
});
|
|
16
|
+
it("treats missing cache fields as 0 (backward compat with non-cache responses)", async () => {
|
|
17
|
+
async function* fakeStream() {
|
|
18
|
+
yield { type: "assistant", usage: { input_tokens: 100, output_tokens: 200 }, content: [{ type: "text", text: "" }] };
|
|
19
|
+
}
|
|
20
|
+
const result = await consumeAgentStream(fakeStream());
|
|
21
|
+
expect(result.cacheCreationInputTokens).toBe(0);
|
|
22
|
+
expect(result.cacheReadInputTokens).toBe(0);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=agent-stream-cache-tokens.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-stream-cache-tokens.test.js","sourceRoot":"","sources":["../../src/__tests__/agent-stream-cache-tokens.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEjE,QAAQ,CAAC,0DAA0D,EAAE,GAAG,EAAE;IACxE,EAAE,CAAC,wFAAwF,EAAE,KAAK,IAAI,EAAE;QACtG,KAAK,SAAS,CAAC,CAAC,UAAU;YACxB,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,2BAA2B,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;YACpL,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,2BAA2B,EAAE,CAAC,EAAE,uBAAuB,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;YACnL,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,2BAA2B,EAAE,CAAC,EAAE,uBAAuB,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACzL,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,UAAU,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;QAC3F,KAAK,SAAS,CAAC,CAAC,UAAU;YACxB,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;QACvH,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,UAAU,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pm-skipped-circuit-breaker-event.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/audit/pm-skipped-circuit-breaker-event.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { pmSkippedCircuitBreakerEvent } from "../../audit/events.js";
|
|
3
|
+
describe("pmSkippedCircuitBreakerEvent (BEC-181)", () => {
|
|
4
|
+
it("returns an audit event with the documented shape", () => {
|
|
5
|
+
const event = pmSkippedCircuitBreakerEvent({
|
|
6
|
+
issueId: "BEC-157",
|
|
7
|
+
failureCount: 4,
|
|
8
|
+
threshold: 3,
|
|
9
|
+
source: "promote",
|
|
10
|
+
});
|
|
11
|
+
expect(event.eventType).toBe("pm.skipped_circuit_breaker");
|
|
12
|
+
expect(event.actor).toBe("pm-agent");
|
|
13
|
+
expect(event.actorType).toBe("pm-agent");
|
|
14
|
+
expect(event.issueId).toBe("BEC-157");
|
|
15
|
+
expect(event.payload).toEqual({
|
|
16
|
+
failureCount: 4,
|
|
17
|
+
threshold: 3,
|
|
18
|
+
source: "promote",
|
|
19
|
+
});
|
|
20
|
+
expect(event.id).toMatch(/^evt_/);
|
|
21
|
+
});
|
|
22
|
+
it("captures source as 'start-todo' when fired from start-todo path", () => {
|
|
23
|
+
const event = pmSkippedCircuitBreakerEvent({
|
|
24
|
+
issueId: "BEC-999",
|
|
25
|
+
failureCount: 5,
|
|
26
|
+
threshold: 3,
|
|
27
|
+
source: "start-todo",
|
|
28
|
+
});
|
|
29
|
+
expect(event.payload.source).toBe("start-todo");
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=pm-skipped-circuit-breaker-event.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pm-skipped-circuit-breaker-event.test.js","sourceRoot":"","sources":["../../../src/__tests__/audit/pm-skipped-circuit-breaker-event.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAErE,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,KAAK,GAAG,4BAA4B,CAAC;YACzC,OAAO,EAAE,SAAS;YAClB,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,SAAS;SAClB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC3D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;YAC5B,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,SAAS;SAClB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,KAAK,GAAG,4BAA4B,CAAC;YACzC,OAAO,EAAE,SAAS;YAClB,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,YAAY;SACrB,CAAC,CAAC;QACH,MAAM,CAAE,KAAK,CAAC,OAA8B,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-model-low-output-ratio-event.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/audit/review-model-low-output-ratio-event.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { reviewModelLowOutputRatioEvent } from "../../audit/events.js";
|
|
3
|
+
describe("reviewModelLowOutputRatioEvent", () => {
|
|
4
|
+
it("returns an audit event with the documented shape", () => {
|
|
5
|
+
const event = reviewModelLowOutputRatioEvent({
|
|
6
|
+
modelId: "gpt-oss-120b:free",
|
|
7
|
+
outputRatio: 0.011,
|
|
8
|
+
runs: 10,
|
|
9
|
+
threshold: 0.05,
|
|
10
|
+
});
|
|
11
|
+
expect(event.eventType).toBe("review.model_low_output_ratio");
|
|
12
|
+
expect(event.actor).toBe("system");
|
|
13
|
+
expect(event.actorType).toBe("system");
|
|
14
|
+
expect(event.payload).toEqual({
|
|
15
|
+
modelId: "gpt-oss-120b:free",
|
|
16
|
+
outputRatio: 0.011,
|
|
17
|
+
runs: 10,
|
|
18
|
+
threshold: 0.05,
|
|
19
|
+
});
|
|
20
|
+
expect(event.id).toMatch(/^evt_/);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=review-model-low-output-ratio-event.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-model-low-output-ratio-event.test.js","sourceRoot":"","sources":["../../../src/__tests__/audit/review-model-low-output-ratio-event.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AAEvE,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,KAAK,GAAG,8BAA8B,CAAC;YAC3C,OAAO,EAAE,mBAAmB;YAC5B,WAAW,EAAE,KAAK;YAClB,IAAI,EAAE,EAAE;YACR,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;YAC5B,OAAO,EAAE,mBAAmB;YAC5B,WAAW,EAAE,KAAK;YAClB,IAAI,EAAE,EAAE;YACR,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -52,7 +52,9 @@ describe("audit_events immutability", () => {
|
|
|
52
52
|
"packages/core/src/pm/scheduler.ts",
|
|
53
53
|
"packages/core/src/pm/actions/triage.ts",
|
|
54
54
|
"packages/core/src/pm/actions/promote.ts",
|
|
55
|
+
"packages/core/src/pm/actions/start-todo.ts",
|
|
55
56
|
"packages/core/src/pm/actions/resolve-approvals.ts",
|
|
57
|
+
"packages/core/src/pipeline/review-providers-runner.ts",
|
|
56
58
|
"packages/core/src/release-manager/scheduler.ts",
|
|
57
59
|
"packages/core/src/release-manager/slack-handler.ts",
|
|
58
60
|
"packages/core/src/repo/agent-branch-sweep-runner.ts",
|
|
@@ -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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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BEC-181 — Fix: circuit breaker now emits pm.skipped_circuit_breaker audit events.
|
|
3
|
+
*
|
|
4
|
+
* This file verifies:
|
|
5
|
+
*
|
|
6
|
+
* 1. WORKING: The circuit breaker correctly skips issues in both promoteReadyIssues
|
|
7
|
+
* and startTodoIssues when an issue has ≥ maxConsecutiveFailures failed runs.
|
|
8
|
+
* countConsecutiveFailures returns 4 for 4 consecutive failed runs with no
|
|
9
|
+
* intervening completion.
|
|
10
|
+
*
|
|
11
|
+
* 2. FIXED: When the breaker fires in promote or start-todo, a `pm.skipped_circuit_breaker`
|
|
12
|
+
* audit event is now written to the database. Operators can distinguish
|
|
13
|
+
* "breaker prevented a re-promotion" from "issue was never a candidate"
|
|
14
|
+
* by querying audit_events.
|
|
15
|
+
*
|
|
16
|
+
* Acceptance criteria from BEC-181 that this test covers:
|
|
17
|
+
* - countConsecutiveFailures is verified to return 4 for 4 consecutive failures
|
|
18
|
+
* - promote and start-todo skip issues at/above the threshold (end-to-end)
|
|
19
|
+
* - audit_events table has 1 row with eventType "pm.skipped_circuit_breaker" after a skip
|
|
20
|
+
* - AuditEventTypeSchema contains "pm.skipped_circuit_breaker"
|
|
21
|
+
* - audit/events.ts exports pmSkippedCircuitBreakerEvent builder
|
|
22
|
+
*/
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=bec-181-circuit-breaker-audit-gap.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bec-181-circuit-breaker-audit-gap.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/bec-181-circuit-breaker-audit-gap.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BEC-181 — Fix: circuit breaker now emits pm.skipped_circuit_breaker audit events.
|
|
3
|
+
*
|
|
4
|
+
* This file verifies:
|
|
5
|
+
*
|
|
6
|
+
* 1. WORKING: The circuit breaker correctly skips issues in both promoteReadyIssues
|
|
7
|
+
* and startTodoIssues when an issue has ≥ maxConsecutiveFailures failed runs.
|
|
8
|
+
* countConsecutiveFailures returns 4 for 4 consecutive failed runs with no
|
|
9
|
+
* intervening completion.
|
|
10
|
+
*
|
|
11
|
+
* 2. FIXED: When the breaker fires in promote or start-todo, a `pm.skipped_circuit_breaker`
|
|
12
|
+
* audit event is now written to the database. Operators can distinguish
|
|
13
|
+
* "breaker prevented a re-promotion" from "issue was never a candidate"
|
|
14
|
+
* by querying audit_events.
|
|
15
|
+
*
|
|
16
|
+
* Acceptance criteria from BEC-181 that this test covers:
|
|
17
|
+
* - countConsecutiveFailures is verified to return 4 for 4 consecutive failures
|
|
18
|
+
* - promote and start-todo skip issues at/above the threshold (end-to-end)
|
|
19
|
+
* - audit_events table has 1 row with eventType "pm.skipped_circuit_breaker" after a skip
|
|
20
|
+
* - AuditEventTypeSchema contains "pm.skipped_circuit_breaker"
|
|
21
|
+
* - audit/events.ts exports pmSkippedCircuitBreakerEvent builder
|
|
22
|
+
*/
|
|
23
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
24
|
+
import { randomBytes } from "node:crypto";
|
|
25
|
+
import { unlinkSync } from "node:fs";
|
|
26
|
+
import { createDb } from "../db/index.js";
|
|
27
|
+
import { pipelineRuns, auditEvents } from "../db/schema.js";
|
|
28
|
+
import { countConsecutiveFailures } from "../pm/actions/db-queries.js";
|
|
29
|
+
import { promoteReadyIssues } from "../pm/actions/promote.js";
|
|
30
|
+
import { startTodoIssues } from "../pm/actions/start-todo.js";
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Helpers
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
function tmpDbPath() {
|
|
35
|
+
return `/tmp/bec-181-repro-${randomBytes(8).toString("hex")}.sqlite`;
|
|
36
|
+
}
|
|
37
|
+
const paths = [];
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
for (const p of paths) {
|
|
40
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
41
|
+
try {
|
|
42
|
+
unlinkSync(p + suffix);
|
|
43
|
+
}
|
|
44
|
+
catch { /* ignore */ }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
paths.length = 0;
|
|
48
|
+
});
|
|
49
|
+
async function makeDb() {
|
|
50
|
+
const path = tmpDbPath();
|
|
51
|
+
paths.push(path);
|
|
52
|
+
return createDb({ driver: "sqlite", connectionString: path });
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Seed N consecutive failed runs for issueId, spaced 5 seconds apart.
|
|
56
|
+
* All are terminal (status="failed") with no completion between them.
|
|
57
|
+
*/
|
|
58
|
+
async function seedConsecutiveFailures(db, issueId, count) {
|
|
59
|
+
const t0 = new Date(Date.now() - 60 * 60_000); // 1 hour ago so not "recent"
|
|
60
|
+
const rows = Array.from({ length: count }, (_, i) => ({
|
|
61
|
+
id: `run-${issueId}-${i}`,
|
|
62
|
+
issueId,
|
|
63
|
+
issueTitle: `Issue ${issueId}`,
|
|
64
|
+
pipelineKey: "auto-implement",
|
|
65
|
+
repoUrl: "https://github.com/org/repo",
|
|
66
|
+
status: "failed",
|
|
67
|
+
startedAt: new Date(t0.getTime() + i * 5_000),
|
|
68
|
+
completedAt: new Date(t0.getTime() + i * 5_000 + 1_000),
|
|
69
|
+
}));
|
|
70
|
+
await db.insert(pipelineRuns).values(rows);
|
|
71
|
+
}
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// PART 1: Verify countConsecutiveFailures returns 4 for 4 consecutive failures
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
describe("BEC-181 Part 1: countConsecutiveFailures (working correctly)", () => {
|
|
76
|
+
it("returns 4 when issue has 4 consecutive failed runs and no completed run", async () => {
|
|
77
|
+
const db = await makeDb();
|
|
78
|
+
await seedConsecutiveFailures(db, "BEC-147", 4);
|
|
79
|
+
const count = await countConsecutiveFailures(db, "BEC-147");
|
|
80
|
+
// EXPECTED: 4 — the circuit breaker should engage at threshold 3
|
|
81
|
+
expect(count).toBe(4);
|
|
82
|
+
});
|
|
83
|
+
it("returns 3 when issue has exactly 3 consecutive failed runs (at default threshold)", async () => {
|
|
84
|
+
const db = await makeDb();
|
|
85
|
+
await seedConsecutiveFailures(db, "BEC-157", 3);
|
|
86
|
+
const count = await countConsecutiveFailures(db, "BEC-157");
|
|
87
|
+
// EXPECTED: 3 — at the default threshold of 3, breaker should engage
|
|
88
|
+
expect(count).toBe(3);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// PART 2: Verify promoteReadyIssues skips the issue (circuit breaker fires)
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
/** Allow fire-and-forget audit DB writes to complete before asserting. */
|
|
95
|
+
async function flushFireAndForget() {
|
|
96
|
+
await new Promise((r) => setImmediate(r));
|
|
97
|
+
await new Promise((r) => setImmediate(r));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Shared helper: runs promoteReadyIssues with the circuit breaker enabled
|
|
101
|
+
* for a single pre-seeded issue and asserts both the skip and the audit event.
|
|
102
|
+
*/
|
|
103
|
+
async function assertPromoteBreakerSkip(opts) {
|
|
104
|
+
const db = await makeDb();
|
|
105
|
+
await seedConsecutiveFailures(db, opts.issueId, opts.failureCount);
|
|
106
|
+
const issues = [
|
|
107
|
+
{
|
|
108
|
+
id: opts.linearUuid,
|
|
109
|
+
identifier: opts.issueId,
|
|
110
|
+
title: opts.issueTitle,
|
|
111
|
+
description: "Some description",
|
|
112
|
+
priority: 2,
|
|
113
|
+
labels: vi.fn().mockResolvedValue({ nodes: [{ name: "auto-implement" }] }),
|
|
114
|
+
team: Promise.resolve({ id: "team-1" }),
|
|
115
|
+
url: `https://linear.app/beckerspace/issue/${opts.issueId}`,
|
|
116
|
+
},
|
|
117
|
+
];
|
|
118
|
+
const client = {
|
|
119
|
+
issues: vi.fn().mockResolvedValue({ nodes: issues }),
|
|
120
|
+
updateIssue: vi.fn(),
|
|
121
|
+
createComment: vi.fn(),
|
|
122
|
+
};
|
|
123
|
+
const stateMap = new Map([["team-1:Todo", "state-todo"]]);
|
|
124
|
+
const conflictChecker = vi.fn();
|
|
125
|
+
// Omit getFailureCount to exercise the batchCountConsecutiveFailures path.
|
|
126
|
+
// The production scheduler also omits getFailureCount after BEC-181 so
|
|
127
|
+
// both promote and start-todo benefit from the batch optimization.
|
|
128
|
+
const results = await promoteReadyIssues({
|
|
129
|
+
linearClient: client,
|
|
130
|
+
teamIds: ["team-1"],
|
|
131
|
+
slotsAvailable: 1,
|
|
132
|
+
checkConflict: conflictChecker,
|
|
133
|
+
stateMap,
|
|
134
|
+
db,
|
|
135
|
+
maxConsecutiveFailures: opts.threshold,
|
|
136
|
+
});
|
|
137
|
+
// Circuit breaker fires and prevents promotion
|
|
138
|
+
expect(results).toHaveLength(1);
|
|
139
|
+
expect(results[0].promoted).toBe(false);
|
|
140
|
+
expect(results[0].reason).toMatch(/circuit.breaker/i);
|
|
141
|
+
expect(results[0].reason).toContain(`${opts.failureCount} consecutive failed runs`);
|
|
142
|
+
expect(client.updateIssue).not.toHaveBeenCalled();
|
|
143
|
+
// Breaker fires before conflict detection (saves tokens)
|
|
144
|
+
expect(conflictChecker).not.toHaveBeenCalled();
|
|
145
|
+
await flushFireAndForget();
|
|
146
|
+
// Audit event is now written when the breaker fires
|
|
147
|
+
const auditRows = await db.select().from(auditEvents);
|
|
148
|
+
expect(auditRows).toHaveLength(1);
|
|
149
|
+
expect(auditRows[0].eventType).toBe("pm.skipped_circuit_breaker");
|
|
150
|
+
expect(auditRows[0].issueId).toBe(opts.issueId);
|
|
151
|
+
expect(JSON.parse(auditRows[0].payload).failureCount).toBe(opts.failureCount);
|
|
152
|
+
expect(JSON.parse(auditRows[0].payload).threshold).toBe(opts.threshold);
|
|
153
|
+
expect(JSON.parse(auditRows[0].payload).source).toBe("promote");
|
|
154
|
+
}
|
|
155
|
+
describe("BEC-181 Part 2: promoteReadyIssues circuit-breaker skip (working correctly)", () => {
|
|
156
|
+
it("skips promotion for issue with 4 consecutive failures and writes a pm.skipped_circuit_breaker audit event (fix verified)", () => assertPromoteBreakerSkip({
|
|
157
|
+
issueId: "BEC-147",
|
|
158
|
+
issueTitle: "Tech debt: changelog UNRELEASED section stale",
|
|
159
|
+
linearUuid: "uuid-bec147",
|
|
160
|
+
failureCount: 4,
|
|
161
|
+
threshold: 3,
|
|
162
|
+
}));
|
|
163
|
+
it("skips promotion for BEC-157 with exactly 3 consecutive failures (at threshold)", () => assertPromoteBreakerSkip({
|
|
164
|
+
issueId: "BEC-157",
|
|
165
|
+
issueTitle: "Pipeline: filter agent scratchpad files",
|
|
166
|
+
linearUuid: "uuid-bec157",
|
|
167
|
+
failureCount: 3,
|
|
168
|
+
threshold: 3,
|
|
169
|
+
}));
|
|
170
|
+
});
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
// PART 3: Verify startTodoIssues skips the issue (circuit breaker fires)
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
describe("BEC-181 Part 3: startTodoIssues circuit-breaker skip (working correctly)", () => {
|
|
175
|
+
const pipelineConfigs = {
|
|
176
|
+
"auto-implement": {
|
|
177
|
+
stages: ["triage", "implement", "review"],
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
const repoConfigs = {
|
|
181
|
+
"team-1": {
|
|
182
|
+
url: "https://github.com/org/repo",
|
|
183
|
+
defaultBranch: "main",
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
it("skips start for issue with 4 consecutive failures WITHOUT touching Linear SDK, and writes an audit event (fix verified)", async () => {
|
|
187
|
+
const db = await makeDb();
|
|
188
|
+
await seedConsecutiveFailures(db, "BEC-147", 4);
|
|
189
|
+
// Spy on Linear SDK lazy relations to prove they are NOT called
|
|
190
|
+
const labelsSpy = vi.fn().mockResolvedValue({ nodes: [{ name: "auto-implement" }] });
|
|
191
|
+
const issue = {
|
|
192
|
+
id: "uuid-bec147",
|
|
193
|
+
identifier: "BEC-147",
|
|
194
|
+
title: "Tech debt: changelog UNRELEASED section stale",
|
|
195
|
+
description: "",
|
|
196
|
+
priority: 2,
|
|
197
|
+
team: Promise.resolve({ id: "team-1" }),
|
|
198
|
+
project: Promise.resolve({ id: "proj-1" }),
|
|
199
|
+
labels: labelsSpy,
|
|
200
|
+
};
|
|
201
|
+
// Use the real DB — seeded rows are 1 hour old, outside the 30-minute recent window,
|
|
202
|
+
// and all are "failed" (not "queued"/"running"), so getActiveAndRecentIssueIds
|
|
203
|
+
// correctly returns empty sets, making BEC-147 appear as an orphaned Todo issue.
|
|
204
|
+
const runner = { start: vi.fn() };
|
|
205
|
+
// Omit getFailureCount to exercise the batchCountConsecutiveFailures path
|
|
206
|
+
// (single DB round-trip). The production scheduler also omits getFailureCount
|
|
207
|
+
// after BEC-181 so it benefits from the batch optimization.
|
|
208
|
+
const input = {
|
|
209
|
+
linearClient: { issues: vi.fn().mockResolvedValue({ nodes: [issue] }) },
|
|
210
|
+
db,
|
|
211
|
+
teamIds: ["team-1"],
|
|
212
|
+
runner: runner,
|
|
213
|
+
pipelineConfigs,
|
|
214
|
+
repoConfigs,
|
|
215
|
+
maxPerTick: 5,
|
|
216
|
+
maxConsecutiveFailures: 3,
|
|
217
|
+
};
|
|
218
|
+
const results = await startTodoIssues(input);
|
|
219
|
+
// VERIFIED WORKING: breaker skips the issue
|
|
220
|
+
expect(results).toHaveLength(1);
|
|
221
|
+
expect(results[0].started).toBe(false);
|
|
222
|
+
expect(results[0].reason).toMatch(/circuit.breaker/i);
|
|
223
|
+
expect(results[0].reason).toContain("4 consecutive failed runs");
|
|
224
|
+
expect(runner.start).not.toHaveBeenCalled();
|
|
225
|
+
// Breaker fires BEFORE Linear SDK calls (saves 3 round-trips per tick per doom-looping issue)
|
|
226
|
+
expect(labelsSpy).not.toHaveBeenCalled();
|
|
227
|
+
// Allow fire-and-forget audit DB writes to complete before asserting.
|
|
228
|
+
await flushFireAndForget();
|
|
229
|
+
// VERIFIED FIX: audit event is now written when the circuit breaker fires in start-todo
|
|
230
|
+
const auditRows = await db.select().from(auditEvents);
|
|
231
|
+
expect(auditRows).toHaveLength(1);
|
|
232
|
+
expect(auditRows[0].eventType).toBe("pm.skipped_circuit_breaker");
|
|
233
|
+
expect(auditRows[0].issueId).toBe("BEC-147");
|
|
234
|
+
expect(JSON.parse(auditRows[0].payload).failureCount).toBe(4);
|
|
235
|
+
expect(JSON.parse(auditRows[0].payload).threshold).toBe(3);
|
|
236
|
+
expect(JSON.parse(auditRows[0].payload).source).toBe("start-todo");
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
// PART 4: Confirm pm.skipped_circuit_breaker is present in AuditEventTypeSchema (fix verified)
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
describe("BEC-181 Part 4: pm.skipped_circuit_breaker event type is now defined (gap closed)", () => {
|
|
243
|
+
it("AuditEventTypeSchema contains pm.skipped_circuit_breaker", async () => {
|
|
244
|
+
const { AuditEventTypeSchema } = await import("../types.js");
|
|
245
|
+
const types = AuditEventTypeSchema.options;
|
|
246
|
+
expect(types).toContain("pm.skipped_circuit_breaker");
|
|
247
|
+
});
|
|
248
|
+
it("audit/events.ts exports pmSkippedCircuitBreakerEvent builder", async () => {
|
|
249
|
+
const auditModule = await import("../audit/events.js");
|
|
250
|
+
expect(typeof auditModule.pmSkippedCircuitBreakerEvent).toBe("function");
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
//# sourceMappingURL=bec-181-circuit-breaker-audit-gap.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bec-181-circuit-breaker-audit-gap.test.js","sourceRoot":"","sources":["../../src/__tests__/bec-181-circuit-breaker-audit-gap.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-feedback-profile-override.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/executor/review-feedback-profile-override.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { applyReviewFeedbackProfileOverride } from "../../executor/executor.js";
|
|
3
|
+
const baseProfile = {
|
|
4
|
+
tools: ["Read", "Write", "Edit"],
|
|
5
|
+
maxInputTokens: 100_000,
|
|
6
|
+
maxTurns: 100,
|
|
7
|
+
model: "claude-sonnet-4-6",
|
|
8
|
+
};
|
|
9
|
+
describe("applyReviewFeedbackProfileOverride (BEC-182)", () => {
|
|
10
|
+
it("caps maxTurns + maxInputTokens for implement stage when review-feedback context is present", () => {
|
|
11
|
+
const out = applyReviewFeedbackProfileOverride(baseProfile, "implement", true);
|
|
12
|
+
expect(out.maxTurns).toBe(30);
|
|
13
|
+
expect(out.maxInputTokens).toBe(60_000);
|
|
14
|
+
// Other fields preserved
|
|
15
|
+
expect(out.tools).toEqual(baseProfile.tools);
|
|
16
|
+
expect(out.model).toBe(baseProfile.model);
|
|
17
|
+
});
|
|
18
|
+
it("returns the profile unchanged on non-implement stages even with review-feedback context", () => {
|
|
19
|
+
const out = applyReviewFeedbackProfileOverride(baseProfile, "test", true);
|
|
20
|
+
expect(out).toEqual(baseProfile);
|
|
21
|
+
});
|
|
22
|
+
it("returns the profile unchanged when review-feedback context is absent", () => {
|
|
23
|
+
const out = applyReviewFeedbackProfileOverride(baseProfile, "implement", false);
|
|
24
|
+
expect(out).toEqual(baseProfile);
|
|
25
|
+
});
|
|
26
|
+
it("does not mutate the input profile", () => {
|
|
27
|
+
const before = JSON.parse(JSON.stringify(baseProfile));
|
|
28
|
+
applyReviewFeedbackProfileOverride(baseProfile, "implement", true);
|
|
29
|
+
expect(baseProfile).toEqual(before);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=review-feedback-profile-override.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-feedback-profile-override.test.js","sourceRoot":"","sources":["../../../src/__tests__/executor/review-feedback-profile-override.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,kCAAkC,EAAE,MAAM,4BAA4B,CAAC;AAEhF,MAAM,WAAW,GAAG;IAClB,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC;IAChC,cAAc,EAAE,OAAO;IACvB,QAAQ,EAAE,GAAG;IACb,KAAK,EAAE,mBAAmB;CAC3B,CAAC;AAEF,QAAQ,CAAC,8CAA8C,EAAE,GAAG,EAAE;IAC5D,EAAE,CAAC,4FAA4F,EAAE,GAAG,EAAE;QACpG,MAAM,GAAG,GAAG,kCAAkC,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;QAC/E,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9B,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,yBAAyB;QACzB,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yFAAyF,EAAE,GAAG,EAAE;QACjG,MAAM,GAAG,GAAG,kCAAkC,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QAC1E,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,GAAG,GAAG,kCAAkC,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;QAChF,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;QACvD,kCAAkC,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;QACnE,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-feedback-prompt.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/executor/review-feedback-prompt.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { implementTemplate } from "../../executor/prompt/templates.js";
|
|
3
|
+
const baseIssue = { id: "BEC-999", identifier: "BEC-999", title: "T", description: "D", priority: 3, labels: [], slug: "bec-999-t" };
|
|
4
|
+
const baseRepo = { url: "https://github.com/x/y", defaultBranch: "main", testCommand: "pnpm test", buildCommand: "pnpm build" };
|
|
5
|
+
describe("implementTemplate — review-feedback prompt (BEC-182)", () => {
|
|
6
|
+
const feedback = {
|
|
7
|
+
prBranch: "agent/BEC-999-foo",
|
|
8
|
+
prUrl: "https://github.com/x/y/pull/42",
|
|
9
|
+
comments: [{ author: "reviewer", body: "rename foo to bar", file: "src/x.ts", line: 12, createdAt: "2026-05-08T00:00:00Z" }],
|
|
10
|
+
};
|
|
11
|
+
it("includes the bounded-scope language", () => {
|
|
12
|
+
const out = implementTemplate(baseIssue, baseRepo, undefined, feedback);
|
|
13
|
+
expect(out).toMatch(/Address ONLY the listed comments/);
|
|
14
|
+
expect(out).toMatch(/Do NOT refactor adjacent code/);
|
|
15
|
+
});
|
|
16
|
+
it("instructs the agent to read the diff first", () => {
|
|
17
|
+
const out = implementTemplate(baseIssue, baseRepo, undefined, feedback);
|
|
18
|
+
expect(out).toMatch(/git diff origin\/main\.\.\.HEAD/);
|
|
19
|
+
});
|
|
20
|
+
it("makes build/test conditional on text-only changes", () => {
|
|
21
|
+
const out = implementTemplate(baseIssue, baseRepo, undefined, feedback);
|
|
22
|
+
expect(out).toMatch(/Skip build\/test ONLY if every change is text-only/);
|
|
23
|
+
});
|
|
24
|
+
it("instructs the agent to stop and report rather than spelunk on failure", () => {
|
|
25
|
+
const out = implementTemplate(baseIssue, baseRepo, undefined, feedback);
|
|
26
|
+
expect(out).toMatch(/stop and report what blocks the resolution/);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=review-feedback-prompt.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-feedback-prompt.test.js","sourceRoot":"","sources":["../../../src/__tests__/executor/review-feedback-prompt.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAEvE,MAAM,SAAS,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAS,CAAC;AAC5I,MAAM,QAAQ,GAAG,EAAE,GAAG,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAS,CAAC;AAEvI,QAAQ,CAAC,sDAAsD,EAAE,GAAG,EAAE;IACpE,MAAM,QAAQ,GAAG;QACf,QAAQ,EAAE,mBAAmB;QAC7B,KAAK,EAAE,gCAAgC;QACvC,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,sBAAsB,EAAE,CAAC;KACtH,CAAC;IAET,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,GAAG,GAAG,iBAAiB,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QACxE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,GAAG,GAAG,iBAAiB,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QACxE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,GAAG,GAAG,iBAAiB,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QACxE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,oDAAoD,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,GAAG,GAAG,iBAAiB,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QACxE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -64,5 +64,28 @@ describe("formatPRCostSummary", () => {
|
|
|
64
64
|
// 1M * $3 + 1M * $15 = $18.00
|
|
65
65
|
expect(out).toContain("**Total: ~$18.00**");
|
|
66
66
|
});
|
|
67
|
+
it("renders cache hit ratio when cache fields are present", () => {
|
|
68
|
+
const stages = [
|
|
69
|
+
{
|
|
70
|
+
stage: "implement",
|
|
71
|
+
inputTokens: 200,
|
|
72
|
+
outputTokens: 750,
|
|
73
|
+
cacheCreationInputTokens: 5000,
|
|
74
|
+
cacheReadInputTokens: 10000,
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
const out = formatPRCostSummary(stages, "auto-implement", ratesConfig);
|
|
78
|
+
// Hit ratio = read / (read + creation + uncached input) = 10000 / (10000 + 5000 + 200) ≈ 65.8% → rounds to 66%
|
|
79
|
+
expect(out).toMatch(/cache hit:\s*66%/);
|
|
80
|
+
expect(out).toContain("read 10.0K");
|
|
81
|
+
expect(out).toContain("created 5.0K");
|
|
82
|
+
});
|
|
83
|
+
it("does not render cache line when both cache fields are zero", () => {
|
|
84
|
+
const stages = [
|
|
85
|
+
{ stage: "implement", inputTokens: 100, outputTokens: 200 },
|
|
86
|
+
];
|
|
87
|
+
const out = formatPRCostSummary(stages, "auto-implement", ratesConfig);
|
|
88
|
+
expect(out).not.toContain("cache hit");
|
|
89
|
+
});
|
|
67
90
|
});
|
|
68
91
|
//# sourceMappingURL=pr-cost-summary.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-cost-summary.test.js","sourceRoot":"","sources":["../../../src/__tests__/pipeline/pr-cost-summary.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,mBAAmB,GAEpB,MAAM,gCAAgC,CAAC;AAExC,MAAM,WAAW,GAAG;IAClB,KAAK,EAAE;QACL,YAAY,EAAE;YACZ,mBAAmB,EAAE,EAAE,eAAe,EAAE,CAAC,EAAE,gBAAgB,EAAE,EAAE,EAAE;YACjE,iBAAiB,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE;SACjE;KACF;IACD,eAAe,EAAE;QACf,gBAAgB,EAAE,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE;KAC9D;CACF,CAAC;AAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,MAAM,GAAyB;YACnC,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE;YAChE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE;YACxD,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE;SAC7D,CAAC;QACF,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC;QAEvE,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC;QACtD,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACjC,yCAAyC;QACzC,2EAA2E;QAC3E,0EAA0E;QAC1E,0EAA0E;QAC1E,oBAAoB;QACpB,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QACxF,MAAM,MAAM,GAAyB;YACnC,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE;YAC7D;gBACE,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,CAAC;gBACd,YAAY,EAAE,CAAC;gBACf,SAAS,EAAE;oBACT,EAAE,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE;oBAC1E,EAAE,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE;oBACzE,EAAE,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE;iBACxE;aACF;SACF,CAAC;QACF,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC;QAEvE,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,CAAC,mBAAmB,CAAC,EAAE,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxE,MAAM,CACJ,mBAAmB,CACjB,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,EACzD,gBAAgB,EAChB,WAAW,CACZ,CACF,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,MAAM,MAAM,GAAyB;YACnC,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE;SACxE,CAAC;QACF,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC;QAC9D,8BAA8B;QAC9B,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"pr-cost-summary.test.js","sourceRoot":"","sources":["../../../src/__tests__/pipeline/pr-cost-summary.test.ts"],"names":[],"mappings":"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"}
|