Skip to content

Commit dc37543

Browse files
authored
Integrate orch batch 20260320T111421 (#112)
* feat(TP-036): complete Step 0 — Preflight * feat(TP-036): complete Step 1 — implement review skip logic for low-risk steps * feat(TP-036): complete Step 1 — skip reviews for low-risk steps (Step 0 and final step) * feat(TP-036): complete Step 2 — Testing & Verification * hydrate: add R004 revision items to Step 3 * checkpoint: TP-036 task artifacts (.DONE, STATUS.md) * checkpoint: wave 1 task artifacts (.DONE, STATUS.md, REVIEW_VERDICT.json)
1 parent a08b1fe commit dc37543

13 files changed

Lines changed: 462 additions & 7 deletions

File tree

docs/explanation/execution-model.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ For each step:
5959
- `1`: plan review before implementation
6060
- `2+`: plan review + code review
6161

62+
**Low-risk step exception:** Step 0 (Preflight) and the final step
63+
(Documentation & Delivery) always skip both plan and code reviews, regardless
64+
of the configured review level. These steps perform file reading and `.DONE`
65+
creation respectively — cross-model review adds overhead without catching
66+
meaningful issues. Middle steps are unaffected by this exception.
67+
6268
---
6369

6470
## Worker iteration loop

docs/explanation/review-loop.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ Task `Review Level` controls review rigor:
5050

5151
Current runner behavior applies plan review at `>=1` and code review at `>=2`.
5252

53+
**Exception:** Step 0 (Preflight) and the final step (Documentation & Delivery)
54+
always skip both plan and code reviews, regardless of review level. These
55+
low-risk steps don't benefit from cross-model review.
56+
5357
---
5458

5559
## Loop mechanics in task-runner

extensions/task-runner.ts

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,20 @@ export const _readExitSummary = readExitSummary;
14061406
export const _buildExitDiagnostic = buildExitDiagnostic;
14071407
export type { BuildExitDiagnosticInput };
14081408

1409+
/**
1410+
* Determine whether a step is "low-risk" and should skip reviews.
1411+
* Low-risk steps: Step 0 (Preflight) and the final step (Delivery/Docs).
1412+
*
1413+
* @param stepNumber The 0-based step number being evaluated
1414+
* @param totalSteps Total number of steps in the task
1415+
* @returns true if the step should skip plan and code reviews
1416+
*/
1417+
export function isLowRiskStep(stepNumber: number, totalSteps: number): boolean {
1418+
if (totalSteps <= 0) return false;
1419+
const lastStepIndex = totalSteps - 1;
1420+
return stepNumber === 0 || stepNumber === lastStepIndex;
1421+
}
1422+
14091423
// ── TMUX Agent Spawner ───────────────────────────────────────────────
14101424

14111425
/**
@@ -2081,11 +2095,20 @@ export default function (pi: ExtensionAPI) {
20812095
logExecution(statusPath, `Step ${step.number} started`, step.name);
20822096
updateWidgets();
20832097

2098+
// Skip reviews for low-risk steps (Step 0 / Preflight and final step / Delivery)
2099+
const _isLowRiskStep = isLowRiskStep(step.number, task.steps.length);
2100+
20842101
// Plan review (level ≥ 1)
20852102
if (task.reviewLevel >= 1) {
2086-
const verdict = await doReview("plan", step, ctx, stepBaselineCommit);
2087-
if (verdict === "RETHINK") {
2088-
ctx.ui.notify(`Reviewer: RETHINK on Step ${step.number} plan. Proceeding with caution.`, "warning");
2103+
if (_isLowRiskStep) {
2104+
const label = step.number === 0 ? "Preflight" : "final step";
2105+
logExecution(statusPath, `Skip plan review`, `Step ${step.number} (${label}) — low-risk`);
2106+
ctx.ui.notify(`⏭️ Skipping plan review for Step ${step.number} (${label})`, "info");
2107+
} else {
2108+
const verdict = await doReview("plan", step, ctx, stepBaselineCommit);
2109+
if (verdict === "RETHINK") {
2110+
ctx.ui.notify(`Reviewer: RETHINK on Step ${step.number} plan. Proceeding with caution.`, "warning");
2111+
}
20892112
}
20902113
}
20912114

@@ -2135,10 +2158,16 @@ export default function (pi: ExtensionAPI) {
21352158

21362159
// Code review (level ≥ 2)
21372160
if (task.reviewLevel >= 2 && state.phase === "running") {
2138-
const verdict = await doReview("code", step, ctx, stepBaselineCommit);
2139-
if (verdict === "REVISE") {
2140-
ctx.ui.notify(`Reviewer: REVISE on Step ${step.number}. Running worker to fix...`, "warning");
2141-
await runWorker(step, ctx); // One more pass to address issues
2161+
if (_isLowRiskStep) {
2162+
const label = step.number === 0 ? "Preflight" : "final step";
2163+
logExecution(statusPath, `Skip code review`, `Step ${step.number} (${label}) — low-risk`);
2164+
ctx.ui.notify(`⏭️ Skipping code review for Step ${step.number} (${label})`, "info");
2165+
} else {
2166+
const verdict = await doReview("code", step, ctx, stepBaselineCommit);
2167+
if (verdict === "REVISE") {
2168+
ctx.ui.notify(`Reviewer: REVISE on Step ${step.number}. Running worker to fix...`, "warning");
2169+
await runWorker(step, ctx); // One more pass to address issues
2170+
}
21422171
}
21432172
}
21442173

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
/**
2+
* Task-Runner Review Skip Tests — TP-036
3+
*
4+
* Tests for the low-risk step detection logic that skips plan and code
5+
* reviews for Step 0 (Preflight) and the final step (Delivery/Docs).
6+
*
7+
* Test categories:
8+
* 1.x — isLowRiskStep pure function (boundary detection)
9+
* 2.x — Review level interactions (level 0, 1, 2 with low-risk steps)
10+
* 3.x — Edge cases (single-step task, two-step task, large step counts)
11+
*
12+
* Run: npx vitest run tests/task-runner-review-skip.test.ts
13+
*/
14+
15+
import { describe, it, expect } from "vitest";
16+
import { isLowRiskStep } from "../task-runner.ts";
17+
18+
// ══════════════════════════════════════════════════════════════════════
19+
// 1.x — isLowRiskStep pure function
20+
// ══════════════════════════════════════════════════════════════════════
21+
22+
describe("1.x: isLowRiskStep boundary detection", () => {
23+
// ── Standard 4-step task (Steps 0, 1, 2, 3) ─────────────────────
24+
25+
it("1.1: Step 0 in a 4-step task → low-risk (Preflight)", () => {
26+
expect(isLowRiskStep(0, 4)).toBe(true);
27+
});
28+
29+
it("1.2: Step 3 (last) in a 4-step task → low-risk (final step)", () => {
30+
expect(isLowRiskStep(3, 4)).toBe(true);
31+
});
32+
33+
it("1.3: Step 1 in a 4-step task → NOT low-risk (middle step)", () => {
34+
expect(isLowRiskStep(1, 4)).toBe(false);
35+
});
36+
37+
it("1.4: Step 2 in a 4-step task → NOT low-risk (middle step)", () => {
38+
expect(isLowRiskStep(2, 4)).toBe(false);
39+
});
40+
41+
// ── Review level 2 interactions ──────────────────────────────────
42+
// The review decision logic uses isLowRiskStep to gate BOTH plan
43+
// and code reviews. Verify that:
44+
// - review level ≥ 1: plan review gated by isLowRiskStep
45+
// - review level ≥ 2: code review gated by isLowRiskStep
46+
// Since the gating is: if (reviewLevel >= N) { if (isLowRiskStep) skip; else review; }
47+
// the pure function test verifies the correct inputs produce the right skip decision.
48+
49+
it("1.5: Step 0 at review level 2 — both plan and code reviews should skip", () => {
50+
// isLowRiskStep returns true → both plan (level≥1) and code (level≥2) skip
51+
const reviewLevel = 2;
52+
const skip = isLowRiskStep(0, 4);
53+
expect(skip).toBe(true);
54+
// Plan review: reviewLevel >= 1 && skip → skipped ✓
55+
// Code review: reviewLevel >= 2 && skip → skipped ✓
56+
expect(reviewLevel >= 1 && skip).toBe(true);
57+
expect(reviewLevel >= 2 && skip).toBe(true);
58+
});
59+
60+
it("1.6: Final step at review level 2 — both plan and code reviews should skip", () => {
61+
const reviewLevel = 2;
62+
const skip = isLowRiskStep(3, 4);
63+
expect(skip).toBe(true);
64+
expect(reviewLevel >= 1 && skip).toBe(true);
65+
expect(reviewLevel >= 2 && skip).toBe(true);
66+
});
67+
68+
it("1.7: Middle step at review level 2 — reviews should NOT skip", () => {
69+
const reviewLevel = 2;
70+
const skip = isLowRiskStep(1, 4);
71+
expect(skip).toBe(false);
72+
// Plan review: reviewLevel >= 1 && !skip → review runs ✓
73+
// Code review: reviewLevel >= 2 && !skip → review runs ✓
74+
expect(reviewLevel >= 1 && !skip).toBe(true);
75+
expect(reviewLevel >= 2 && !skip).toBe(true);
76+
});
77+
78+
// ── Review level 0 (all reviews disabled) ────────────────────────
79+
80+
it("1.8: Review level 0 — no reviews regardless of step position", () => {
81+
const reviewLevel = 0;
82+
// Even if isLowRiskStep returns true, level 0 means no reviews at all
83+
// The outer gate: if (reviewLevel >= 1) never fires
84+
expect(reviewLevel >= 1).toBe(false);
85+
expect(reviewLevel >= 2).toBe(false);
86+
// isLowRiskStep is never consulted, but let's verify it still works
87+
expect(isLowRiskStep(0, 4)).toBe(true);
88+
expect(isLowRiskStep(1, 4)).toBe(false);
89+
expect(isLowRiskStep(3, 4)).toBe(true);
90+
});
91+
92+
// ── Review level 1 (plan only) ──────────────────────────────────
93+
94+
it("1.9: Review level 1, Step 0 — plan review skipped, no code review", () => {
95+
const reviewLevel = 1;
96+
const skip = isLowRiskStep(0, 4);
97+
expect(reviewLevel >= 1 && skip).toBe(true); // plan review gate → skip
98+
expect(reviewLevel >= 2).toBe(false); // code review gate never fires
99+
});
100+
101+
it("1.10: Review level 1, middle step — plan review runs, no code review", () => {
102+
const reviewLevel = 1;
103+
const skip = isLowRiskStep(2, 4);
104+
expect(reviewLevel >= 1 && !skip).toBe(true); // plan review runs
105+
expect(reviewLevel >= 2).toBe(false); // code review gate never fires
106+
});
107+
});
108+
109+
// ══════════════════════════════════════════════════════════════════════
110+
// 2.x — Edge cases
111+
// ══════════════════════════════════════════════════════════════════════
112+
113+
describe("2.x: Edge cases", () => {
114+
it("2.1: Single-step task — Step 0 is both first AND last → low-risk", () => {
115+
// totalSteps=1, lastStepIndex=0, stepNumber=0 matches both conditions
116+
expect(isLowRiskStep(0, 1)).toBe(true);
117+
});
118+
119+
it("2.2: Two-step task — Step 0 is low-risk", () => {
120+
expect(isLowRiskStep(0, 2)).toBe(true);
121+
});
122+
123+
it("2.3: Two-step task — Step 1 (last) is low-risk", () => {
124+
expect(isLowRiskStep(1, 2)).toBe(true);
125+
});
126+
127+
it("2.4: Two-step task — both steps are low-risk (no middle steps)", () => {
128+
// In a 2-step task, Step 0 is first and Step 1 is last
129+
// No middle steps exist — all reviews would be skipped
130+
expect(isLowRiskStep(0, 2)).toBe(true);
131+
expect(isLowRiskStep(1, 2)).toBe(true);
132+
});
133+
134+
it("2.5: Three-step task — only Step 1 is NOT low-risk", () => {
135+
expect(isLowRiskStep(0, 3)).toBe(true); // first
136+
expect(isLowRiskStep(1, 3)).toBe(false); // middle
137+
expect(isLowRiskStep(2, 3)).toBe(true); // last
138+
});
139+
140+
it("2.6: Large task (10 steps) — only first and last are low-risk", () => {
141+
expect(isLowRiskStep(0, 10)).toBe(true); // first
142+
expect(isLowRiskStep(9, 10)).toBe(true); // last
143+
// All middle steps
144+
for (let i = 1; i < 9; i++) {
145+
expect(isLowRiskStep(i, 10)).toBe(false);
146+
}
147+
});
148+
149+
it("2.7: Zero totalSteps → false (defensive)", () => {
150+
expect(isLowRiskStep(0, 0)).toBe(false);
151+
});
152+
153+
it("2.8: Negative totalSteps → false (defensive)", () => {
154+
expect(isLowRiskStep(0, -1)).toBe(false);
155+
});
156+
});
157+
158+
// ══════════════════════════════════════════════════════════════════════
159+
// 3.x — Integration: review gating decision matrix
160+
// ══════════════════════════════════════════════════════════════════════
161+
162+
describe("3.x: Review gating decision matrix", () => {
163+
// This simulates the full decision logic from task-runner.ts:
164+
// Plan review: if (reviewLevel >= 1) { if (isLowRisk) skip; else review; }
165+
// Code review: if (reviewLevel >= 2) { if (isLowRisk) skip; else review; }
166+
167+
type ReviewDecision = "skip" | "review" | "no-gate";
168+
169+
function planReviewDecision(reviewLevel: number, stepNumber: number, totalSteps: number): ReviewDecision {
170+
if (reviewLevel < 1) return "no-gate";
171+
return isLowRiskStep(stepNumber, totalSteps) ? "skip" : "review";
172+
}
173+
174+
function codeReviewDecision(reviewLevel: number, stepNumber: number, totalSteps: number): ReviewDecision {
175+
if (reviewLevel < 2) return "no-gate";
176+
return isLowRiskStep(stepNumber, totalSteps) ? "skip" : "review";
177+
}
178+
179+
// ── Level 0: no reviews at all ──────────────────────────────────
180+
181+
it("3.1: Level 0, Step 0 — no plan review, no code review", () => {
182+
expect(planReviewDecision(0, 0, 4)).toBe("no-gate");
183+
expect(codeReviewDecision(0, 0, 4)).toBe("no-gate");
184+
});
185+
186+
it("3.2: Level 0, middle step — no plan review, no code review", () => {
187+
expect(planReviewDecision(0, 2, 4)).toBe("no-gate");
188+
expect(codeReviewDecision(0, 2, 4)).toBe("no-gate");
189+
});
190+
191+
it("3.3: Level 0, final step — no plan review, no code review", () => {
192+
expect(planReviewDecision(0, 3, 4)).toBe("no-gate");
193+
expect(codeReviewDecision(0, 3, 4)).toBe("no-gate");
194+
});
195+
196+
// ── Level 1: plan reviews only ──────────────────────────────────
197+
198+
it("3.4: Level 1, Step 0 — plan review SKIPPED, no code review gate", () => {
199+
expect(planReviewDecision(1, 0, 4)).toBe("skip");
200+
expect(codeReviewDecision(1, 0, 4)).toBe("no-gate");
201+
});
202+
203+
it("3.5: Level 1, middle step — plan review RUNS, no code review gate", () => {
204+
expect(planReviewDecision(1, 1, 4)).toBe("review");
205+
expect(codeReviewDecision(1, 1, 4)).toBe("no-gate");
206+
});
207+
208+
it("3.6: Level 1, final step — plan review SKIPPED, no code review gate", () => {
209+
expect(planReviewDecision(1, 3, 4)).toBe("skip");
210+
expect(codeReviewDecision(1, 3, 4)).toBe("no-gate");
211+
});
212+
213+
// ── Level 2: plan + code reviews ────────────────────────────────
214+
215+
it("3.7: Level 2, Step 0 — plan review SKIPPED, code review SKIPPED", () => {
216+
expect(planReviewDecision(2, 0, 4)).toBe("skip");
217+
expect(codeReviewDecision(2, 0, 4)).toBe("skip");
218+
});
219+
220+
it("3.8: Level 2, middle step — plan review RUNS, code review RUNS", () => {
221+
expect(planReviewDecision(2, 1, 4)).toBe("review");
222+
expect(codeReviewDecision(2, 1, 4)).toBe("review");
223+
});
224+
225+
it("3.9: Level 2, final step — plan review SKIPPED, code review SKIPPED", () => {
226+
expect(planReviewDecision(2, 3, 4)).toBe("skip");
227+
expect(codeReviewDecision(2, 3, 4)).toBe("skip");
228+
});
229+
230+
// ── Level 2, single-step task ───────────────────────────────────
231+
232+
it("3.10: Level 2, single step (Step 0 is also final) — all reviews SKIPPED", () => {
233+
expect(planReviewDecision(2, 0, 1)).toBe("skip");
234+
expect(codeReviewDecision(2, 0, 1)).toBe("skip");
235+
});
236+
237+
// ── Level 3+ (future-proofing) ──────────────────────────────────
238+
239+
it("3.11: Level 3, Step 0 — both reviews still skip (higher levels don't change skip logic)", () => {
240+
expect(planReviewDecision(3, 0, 4)).toBe("skip");
241+
expect(codeReviewDecision(3, 0, 4)).toBe("skip");
242+
});
243+
244+
it("3.12: Level 3, middle step — both reviews run", () => {
245+
expect(planReviewDecision(3, 1, 4)).toBe("review");
246+
expect(codeReviewDecision(3, 1, 4)).toBe("review");
247+
});
248+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
completed: 2026-03-20
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## Plan Review: Step 0: Preflight
2+
3+
### Verdict: APPROVE
4+
5+
### Summary
6+
The Step 0 plan is correctly scoped to the stated preflight outcomes: find the existing review-gating decision points and confirm where current-step and total-step metadata are available. That is sufficient preparation for Step 1 without over-constraining implementation details. I do not see any blocking gaps that would risk incorrect behavior later.
7+
8+
### Issues Found
9+
1. **[Severity: minor]** — No blocking issues found.
10+
11+
### Missing Items
12+
- None.
13+
14+
### Suggestions
15+
- During preflight, explicitly note both gating locations in `extensions/task-runner.ts` (`plan` and `code` review checks in `executeStep`) plus the source of total steps (`task.steps.length`) so Step 1 can apply the skip condition consistently.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## Plan Review: Step 1: Implement Review Skip Logic
2+
3+
### Verdict: APPROVE
4+
5+
### Summary
6+
The Step 1 plan is correctly aligned with the task outcomes: it adds boundary-step skip logic for both plan and code reviews, defines how to detect the final step, and preserves existing behavior for middle steps. It also includes explicit logging requirements so operators can see why reviews were not run. I do not see any blocking gaps that would prevent the step from achieving its stated goal.
7+
8+
### Issues Found
9+
1. **[Severity: minor]** — No blocking issues found.
10+
11+
### Missing Items
12+
- None.
13+
14+
### Suggestions
15+
- In `extensions/task-runner.ts` (current review gates around `executeStep`), compute a single boolean for boundary-step skipping and reuse it for both the plan-review gate and code-review gate to prevent drift.
16+
- For final-step detection, prefer using position in `task.steps` (or last parsed step identity) rather than assuming contiguous numeric step labels.
17+
- Keep skip log messages distinct for Step 0 vs final step so future debugging clearly shows which rule triggered.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## Plan Review: Step 2: Testing & Verification
2+
3+
### Verdict: APPROVE
4+
5+
### Summary
6+
The Step 2 plan covers all required behavioral outcomes from `PROMPT.md`: boundary-step review skipping (Step 0 and final step), unchanged middle-step behavior, unchanged review-level-0 behavior, and the single-step edge case. It also includes full-suite verification, which is appropriate for guarding regressions in `task-runner.ts` behavior. I do not see any blocking gaps that would prevent this step from validating the change correctly.
7+
8+
### Issues Found
9+
1. **[Severity: minor]** — No blocking issues found.
10+
11+
### Missing Items
12+
- None.
13+
14+
### Suggestions
15+
- In the new test file (`extensions/tests/task-runner-review-skip.test.ts`), assert both review types explicitly for each scenario (plan + code where applicable), so a partial skip regression is caught.
16+
- For “no review spawned” assertions, prefer checking durable artifacts/state transitions (e.g., review request files or counters) rather than only log text.
17+
- Keep scenario names mapped 1:1 to the Step 2 checklist items to make STATUS.md updates and future triage straightforward.

0 commit comments

Comments
 (0)