feat(autoplan): eng review always runs last — the gate reviews the final amended plan

Reorder the pipeline to CEO -> Design (if UI scope) -> DX (if developer-facing
scope) -> Eng. The old order (CEO -> Design -> Eng -> DX) let DX findings land
AFTER the required gate signed off, so eng validated a stale plan.

Accept-all semantics made explicit: every AskUserQuestion resolves to the
recommended option; premises no longer pause the pipeline mid-run (clearly-wrong
ones queue as User-Challenge items at the single Final Approval Gate). Eng's
Codex voice now sees the DX consensus summary. New free static test pins the
order; the chain E2E gains DX-between and Eng-terminal assertions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-28 01:41:29 +00:00
co-authored by Claude Fable 5
parent 394db326f2
commit 848973007c
11 changed files with 216 additions and 104 deletions
+50 -38
View File
@@ -544,7 +544,7 @@ sections. Read a section in full before doing its step; do not work from memory.
| starting Phase 1 (CEO review — always runs, after the Phase 0.5 preflight) | `sections/ceo-phase.md` | | starting Phase 1 (CEO review — always runs, after the Phase 0.5 preflight) | `sections/ceo-phase.md` |
| starting Phase 2 (design review — ONLY if UI scope was detected in Phase 0; skip the read entirely otherwise) | `sections/design-phase.md` | | starting Phase 2 (design review — ONLY if UI scope was detected in Phase 0; skip the read entirely otherwise) | `sections/design-phase.md` |
| starting Phase 3 (eng review — always runs, after the Pre-Phase 3 checklist) | `sections/eng-phase.md` | | starting Phase 3 (eng review — always runs, after the Pre-Phase 3 checklist) | `sections/eng-phase.md` |
| starting Phase 3.5 (DX review — ONLY if developer-facing scope was detected in Phase 0; skip the read entirely otherwise) | `sections/dx-phase.md` | | starting Phase 2.5 (DX review — ONLY if developer-facing scope was detected in Phase 0; skip the read entirely otherwise) | `sections/dx-phase.md` |
| presenting the Final Approval Gate (Phase 4) — the aggregator computes $AGGREGATED_TASKS that the gate message substitutes | `sections/tasks-aggregator.md` | | presenting the Final Approval Gate (Phase 4) — the aggregator computes $AGGREGATED_TASKS that the gate message substitutes | `sections/tasks-aggregator.md` |
--- ---
@@ -605,9 +605,11 @@ preference." The user still decides, but the framing is appropriately urgent.
## Sequential Execution — MANDATORY ## Sequential Execution — MANDATORY
Phases MUST execute in strict order: CEO → Design → Eng → DX. Phases MUST execute in strict order: CEO → Design (if UI scope) → DX (if
Each phase MUST complete fully before the next begins. developer-facing scope) → Eng. Eng runs LAST, always: it is the required
NEVER run phases in parallel — each builds on the previous. shipping gate, so it must review the FINAL amended plan — every other phase's
amendments land before it. Each phase MUST complete fully before the next
begins. NEVER run phases in parallel — each builds on the previous.
Between each phase, emit a phase-transition summary and verify that all required Between each phase, emit a phase-transition summary and verify that all required
outputs from the prior phase are written before starting the next. outputs from the prior phase are written before starting the next.
@@ -619,13 +621,20 @@ outputs from the prior phase are written before starting the next.
Auto-decide replaces the USER'S judgment with the 6 principles. It does NOT replace Auto-decide replaces the USER'S judgment with the 6 principles. It does NOT replace
the ANALYSIS. Every section in the loaded skill files must still be executed at the the ANALYSIS. Every section in the loaded skill files must still be executed at the
same depth as the interactive version. The only thing that changes is who answers the same depth as the interactive version. The only thing that changes is who answers the
AskUserQuestion: you do, using the 6 principles, instead of the user. AskUserQuestion: you do, instead of the user.
**Two exceptions — never auto-decided:** **Default resolution: the recommended option.** Every AskUserQuestion in the loaded
1. Premises (Phase 1) — require human judgment about what problem to solve. skills resolves to its `(recommended)` option; mode selections take the skill's
2. User Challenges — when both models agree the user's stated direction should change context-dependent default. The 6 principles guide cases with no recommendation and
(merge, split, add, remove features/workflows). The user always has context models break ties; when a principle argues AGAINST the recommended option, that is a Taste
lack. See Decision Classification above. decision — take the recommendation and surface the disagreement at the final gate.
**One exception class — never auto-decided:** User Challenges — when both models
agree the user's stated direction should change (merge, split, add, remove
features/workflows; reinterpret a settled decision), or a premise looks clearly
wrong. These queue and surface at the Final Approval Gate — never as mid-run
stops. The user is interrupted exactly once, at the gate. The user always has
context models lack. See Decision Classification above.
**You MUST still:** **You MUST still:**
- READ the actual code, diffs, and files each section references - READ the actual code, diffs, and files each section references
@@ -775,7 +784,7 @@ else
fi fi
``` ```
If `_CODEX_AVAILABLE=false`, all Phase 1-3.5 Codex voices below degrade to If `_CODEX_AVAILABLE=false`, all Phase 1-3 Codex voices below degrade to
`[codex-unavailable]` in the degradation matrix. /autoplan completes with `[codex-unavailable]` in the degradation matrix. /autoplan completes with
Claude subagent only — saves token spend on Codex prompts we can't use. Claude subagent only — saves token spend on Codex prompts we can't use.
@@ -792,7 +801,7 @@ Claude subagent only — saves token spend on Codex prompts we can't use.
- [ ] CEO completion summary written to plan file - [ ] CEO completion summary written to plan file
- [ ] CEO dual voices ran (Codex + Claude subagent, or noted unavailable) - [ ] CEO dual voices ran (Codex + Claude subagent, or noted unavailable)
- [ ] CEO consensus table produced - [ ] CEO consensus table produced
- [ ] Premise gate passed (user confirmed) - [ ] Premises assessed (clearly-wrong ones queued as Final Gate items — no mid-run stop)
- [ ] Phase-transition summary emitted - [ ] Phase-transition summary emitted
## Phase 2: Design Review (conditional — skip if no UI scope) ## Phase 2: Design Review (conditional — skip if no UI scope)
@@ -805,30 +814,33 @@ entirely — do NOT read its section. Log: "Phase 2 skipped — no UI scope dete
--- ---
## Phase 2.5: DX Review (conditional — skip if no developer-facing scope)
**Skip condition:** If DX scope was NOT detected in Phase 0, skip this phase
entirely — do NOT read its section. Log: "Phase 2.5 skipped — no developer-facing scope detected."
> **STOP.** Before starting Phase 2.5 (DX review — ONLY if developer-facing scope was detected in Phase 0; skip the read entirely otherwise), Read `~/.claude/skills/gstack/autoplan/sections/dx-phase.md` and execute it
> in full. Do not work from memory — that section is the source of truth for this step.
---
**Pre-Phase 3 checklist (verify before starting):** **Pre-Phase 3 checklist (verify before starting):**
- [ ] All Phase 1 items above confirmed - [ ] All Phase 1 items above confirmed
- [ ] Design completion summary written (or "skipped, no UI scope") - [ ] Design completion summary written (or "skipped, no UI scope")
- [ ] Design dual voices ran (if Phase 2 ran) - [ ] Design dual voices ran (if Phase 2 ran)
- [ ] Design consensus table produced (if Phase 2 ran) - [ ] Design consensus table produced (if Phase 2 ran)
- [ ] DX completion summary written (or "skipped, no developer-facing scope")
- [ ] DX dual voices ran (if Phase 2.5 ran)
- [ ] DX consensus table produced (if Phase 2.5 ran)
- [ ] Phase-transition summary emitted - [ ] Phase-transition summary emitted
## Phase 3: Eng Review + Dual Voices ## Phase 3: Eng Review + Dual Voices (always runs, always LAST — the required gate reviews the final amended plan)
> **STOP.** Before starting Phase 3 (eng review — always runs, after the Pre-Phase 3 checklist), Read `~/.claude/skills/gstack/autoplan/sections/eng-phase.md` and execute it > **STOP.** Before starting Phase 3 (eng review — always runs, after the Pre-Phase 3 checklist), Read `~/.claude/skills/gstack/autoplan/sections/eng-phase.md` and execute it
> in full. Do not work from memory — that section is the source of truth for this step. > in full. Do not work from memory — that section is the source of truth for this step.
--- ---
## Phase 3.5: DX Review (conditional — skip if no developer-facing scope)
**Skip condition:** If DX scope was NOT detected in Phase 0, skip this phase
entirely — do NOT read its section. Log: "Phase 3.5 skipped — no developer-facing scope detected."
> **STOP.** Before starting Phase 3.5 (DX review — ONLY if developer-facing scope was detected in Phase 0; skip the read entirely otherwise), Read `~/.claude/skills/gstack/autoplan/sections/dx-phase.md` and execute it
> in full. Do not work from memory — that section is the source of truth for this step.
---
## Decision Audit Trail ## Decision Audit Trail
After each auto-decision, append a row to the plan file using Edit: After each auto-decision, append a row to the plan file using Edit:
@@ -869,7 +881,16 @@ produced. Check the plan file and conversation for each item.
- [ ] Dual voices ran (or noted unavailable/skipped with phase) - [ ] Dual voices ran (or noted unavailable/skipped with phase)
- [ ] Design litmus scorecard produced - [ ] Design litmus scorecard produced
**Phase 3 (Eng) outputs:** **Phase 2.5 (DX) outputs — only if DX scope detected:**
- [ ] All 8 DX dimensions evaluated with scores
- [ ] Developer journey map produced
- [ ] Developer empathy narrative written
- [ ] TTHW assessment with target
- [ ] DX Implementation Checklist produced
- [ ] Dual voices ran (or noted unavailable/skipped with phase)
- [ ] DX consensus table produced
**Phase 3 (Eng — final phase) outputs:**
- [ ] Scope challenge with actual code analysis (not just "scope is fine") - [ ] Scope challenge with actual code analysis (not just "scope is fine")
- [ ] Architecture ASCII diagram produced - [ ] Architecture ASCII diagram produced
- [ ] Test diagram mapping codepaths to test coverage - [ ] Test diagram mapping codepaths to test coverage
@@ -881,15 +902,6 @@ produced. Check the plan file and conversation for each item.
- [ ] Dual voices ran (Codex + Claude subagent, or noted unavailable) - [ ] Dual voices ran (Codex + Claude subagent, or noted unavailable)
- [ ] Eng consensus table produced - [ ] Eng consensus table produced
**Phase 3.5 (DX) outputs — only if DX scope detected:**
- [ ] All 8 DX dimensions evaluated with scores
- [ ] Developer journey map produced
- [ ] Developer empathy narrative written
- [ ] TTHW assessment with target
- [ ] DX Implementation Checklist produced
- [ ] Dual voices ran (or noted unavailable/skipped with phase)
- [ ] DX consensus table produced
**Cross-phase:** **Cross-phase:**
- [ ] Cross-phase themes section written - [ ] Cross-phase themes section written
@@ -981,7 +993,7 @@ AskUserQuestion options:
- A: mark APPROVED, write review logs, suggest /ship - A: mark APPROVED, write review logs, suggest /ship
- B: ask which overrides, apply, re-present gate - B: ask which overrides, apply, re-present gate
- C: answer freeform, re-present gate - C: answer freeform, re-present gate
- D: make changes, re-run affected phases (scope→1B, design→2, test plan→3, arch→3). Max 3 cycles. - D: make changes, re-run affected phases (scope→1B, design→2, dx→2.5, test plan→3, arch→3; a re-run of any earlier phase re-runs Eng after it — the gate always reviews the final plan). Max 3 cycles.
- E: start over - E: start over
--- ---
@@ -1006,7 +1018,7 @@ If Phase 2 ran (UI scope):
~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"plan-design-review","timestamp":"'"$TIMESTAMP"'","status":"STATUS","unresolved":N,"via":"autoplan","commit":"'"$COMMIT"'"}' ~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"plan-design-review","timestamp":"'"$TIMESTAMP"'","status":"STATUS","unresolved":N,"via":"autoplan","commit":"'"$COMMIT"'"}'
``` ```
If Phase 3.5 ran (DX scope): If Phase 2.5 ran (DX scope):
```bash ```bash
~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"plan-devex-review","timestamp":"'"$TIMESTAMP"'","status":"STATUS","initial_score":N,"overall_score":N,"product_type":"TYPE","tthw_current":"TTHW","tthw_target":"TARGET","unresolved":N,"via":"autoplan","commit":"'"$COMMIT"'"}' ~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"plan-devex-review","timestamp":"'"$TIMESTAMP"'","status":"STATUS","initial_score":N,"overall_score":N,"product_type":"TYPE","tthw_current":"TTHW","tthw_target":"TARGET","unresolved":N,"via":"autoplan","commit":"'"$COMMIT"'"}'
``` ```
@@ -1023,7 +1035,7 @@ If Phase 2 ran (UI scope), also log:
~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"autoplan-voices","timestamp":"'"$TIMESTAMP"'","status":"STATUS","source":"SOURCE","phase":"design","via":"autoplan","consensus_confirmed":N,"consensus_disagree":N,"commit":"'"$COMMIT"'"}' ~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"autoplan-voices","timestamp":"'"$TIMESTAMP"'","status":"STATUS","source":"SOURCE","phase":"design","via":"autoplan","consensus_confirmed":N,"consensus_disagree":N,"commit":"'"$COMMIT"'"}'
``` ```
If Phase 3.5 ran (DX scope), also log: If Phase 2.5 ran (DX scope), also log:
```bash ```bash
~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"autoplan-voices","timestamp":"'"$TIMESTAMP"'","status":"STATUS","source":"SOURCE","phase":"dx","via":"autoplan","consensus_confirmed":N,"consensus_disagree":N,"commit":"'"$COMMIT"'"}' ~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"autoplan-voices","timestamp":"'"$TIMESTAMP"'","status":"STATUS","source":"SOURCE","phase":"dx","via":"autoplan","consensus_confirmed":N,"consensus_disagree":N,"commit":"'"$COMMIT"'"}'
``` ```
@@ -1038,8 +1050,8 @@ Suggest next step: `/ship` when ready to create the PR.
## Important Rules ## Important Rules
- **Never abort.** The user chose /autoplan. Respect that choice. Surface all taste decisions, never redirect to interactive review. - **Never abort.** The user chose /autoplan. Respect that choice. Surface all taste decisions, never redirect to interactive review.
- **Two gates.** The non-auto-decided AskUserQuestions are: (1) premise confirmation in Phase 1, and (2) User Challenges — when both models agree the user's stated direction should change. Everything else is auto-decided using the 6 principles. - **One gate.** The only non-auto-decided AskUserQuestions surface at the Final Approval Gate: User Challenges — including clearly-wrong premises queued from Phase 1. Everything else resolves to the recommended option (the 6 principles break ties), so the pipeline never stops mid-run.
- **Log every decision.** No silent auto-decisions. Every choice gets a row in the audit trail. - **Log every decision.** No silent auto-decisions. Every choice gets a row in the audit trail.
- **Full depth means full depth.** Do not compress or skip sections from the loaded skill files (except the skip list in Phase 0). "Full depth" means: read the code the section asks you to read, produce the outputs the section requires, identify every issue, and decide each one. A one-sentence summary of a section is not "full depth" — it is a skip. If you catch yourself writing fewer than 3 sentences for any review section, you are likely compressing. - **Full depth means full depth.** Do not compress or skip sections from the loaded skill files (except the skip list in Phase 0). "Full depth" means: read the code the section asks you to read, produce the outputs the section requires, identify every issue, and decide each one. A one-sentence summary of a section is not "full depth" — it is a skip. If you catch yourself writing fewer than 3 sentences for any review section, you are likely compressing.
- **Artifacts are deliverables.** Test plan artifact, failure modes registry, error/rescue table, ASCII diagrams — these must exist on disk or in the plan file when the review completes. If they don't exist, the review is incomplete. - **Artifacts are deliverables.** Test plan artifact, failure modes registry, error/rescue table, ASCII diagrams — these must exist on disk or in the plan file when the review completes. If they don't exist, the review is incomplete.
- **Sequential order.** CEO → Design → Eng → DX. Each phase builds on the last. - **Sequential order.** CEO → Design (if UI scope) → DX (if developer-facing scope) → Eng, always last. Each phase builds on the last; the required gate reviews the final amended plan.
+48 -36
View File
@@ -108,9 +108,11 @@ preference." The user still decides, but the framing is appropriately urgent.
## Sequential Execution — MANDATORY ## Sequential Execution — MANDATORY
Phases MUST execute in strict order: CEO → Design → Eng → DX. Phases MUST execute in strict order: CEO → Design (if UI scope) → DX (if
Each phase MUST complete fully before the next begins. developer-facing scope) → Eng. Eng runs LAST, always: it is the required
NEVER run phases in parallel — each builds on the previous. shipping gate, so it must review the FINAL amended plan — every other phase's
amendments land before it. Each phase MUST complete fully before the next
begins. NEVER run phases in parallel — each builds on the previous.
Between each phase, emit a phase-transition summary and verify that all required Between each phase, emit a phase-transition summary and verify that all required
outputs from the prior phase are written before starting the next. outputs from the prior phase are written before starting the next.
@@ -122,13 +124,20 @@ outputs from the prior phase are written before starting the next.
Auto-decide replaces the USER'S judgment with the 6 principles. It does NOT replace Auto-decide replaces the USER'S judgment with the 6 principles. It does NOT replace
the ANALYSIS. Every section in the loaded skill files must still be executed at the the ANALYSIS. Every section in the loaded skill files must still be executed at the
same depth as the interactive version. The only thing that changes is who answers the same depth as the interactive version. The only thing that changes is who answers the
AskUserQuestion: you do, using the 6 principles, instead of the user. AskUserQuestion: you do, instead of the user.
**Two exceptions — never auto-decided:** **Default resolution: the recommended option.** Every AskUserQuestion in the loaded
1. Premises (Phase 1) — require human judgment about what problem to solve. skills resolves to its `(recommended)` option; mode selections take the skill's
2. User Challenges — when both models agree the user's stated direction should change context-dependent default. The 6 principles guide cases with no recommendation and
(merge, split, add, remove features/workflows). The user always has context models break ties; when a principle argues AGAINST the recommended option, that is a Taste
lack. See Decision Classification above. decision — take the recommendation and surface the disagreement at the final gate.
**One exception class — never auto-decided:** User Challenges — when both models
agree the user's stated direction should change (merge, split, add, remove
features/workflows; reinterpret a settled decision), or a premise looks clearly
wrong. These queue and surface at the Final Approval Gate — never as mid-run
stops. The user is interrupted exactly once, at the gate. The user always has
context models lack. See Decision Classification above.
**You MUST still:** **You MUST still:**
- READ the actual code, diffs, and files each section references - READ the actual code, diffs, and files each section references
@@ -278,7 +287,7 @@ else
fi fi
``` ```
If `_CODEX_AVAILABLE=false`, all Phase 1-3.5 Codex voices below degrade to If `_CODEX_AVAILABLE=false`, all Phase 1-3 Codex voices below degrade to
`[codex-unavailable]` in the degradation matrix. /autoplan completes with `[codex-unavailable]` in the degradation matrix. /autoplan completes with
Claude subagent only — saves token spend on Codex prompts we can't use. Claude subagent only — saves token spend on Codex prompts we can't use.
@@ -294,7 +303,7 @@ Claude subagent only — saves token spend on Codex prompts we can't use.
- [ ] CEO completion summary written to plan file - [ ] CEO completion summary written to plan file
- [ ] CEO dual voices ran (Codex + Claude subagent, or noted unavailable) - [ ] CEO dual voices ran (Codex + Claude subagent, or noted unavailable)
- [ ] CEO consensus table produced - [ ] CEO consensus table produced
- [ ] Premise gate passed (user confirmed) - [ ] Premises assessed (clearly-wrong ones queued as Final Gate items — no mid-run stop)
- [ ] Phase-transition summary emitted - [ ] Phase-transition summary emitted
## Phase 2: Design Review (conditional — skip if no UI scope) ## Phase 2: Design Review (conditional — skip if no UI scope)
@@ -306,28 +315,31 @@ entirely — do NOT read its section. Log: "Phase 2 skipped — no UI scope dete
--- ---
## Phase 2.5: DX Review (conditional — skip if no developer-facing scope)
**Skip condition:** If DX scope was NOT detected in Phase 0, skip this phase
entirely — do NOT read its section. Log: "Phase 2.5 skipped — no developer-facing scope detected."
{{SECTION:dx-phase}}
---
**Pre-Phase 3 checklist (verify before starting):** **Pre-Phase 3 checklist (verify before starting):**
- [ ] All Phase 1 items above confirmed - [ ] All Phase 1 items above confirmed
- [ ] Design completion summary written (or "skipped, no UI scope") - [ ] Design completion summary written (or "skipped, no UI scope")
- [ ] Design dual voices ran (if Phase 2 ran) - [ ] Design dual voices ran (if Phase 2 ran)
- [ ] Design consensus table produced (if Phase 2 ran) - [ ] Design consensus table produced (if Phase 2 ran)
- [ ] DX completion summary written (or "skipped, no developer-facing scope")
- [ ] DX dual voices ran (if Phase 2.5 ran)
- [ ] DX consensus table produced (if Phase 2.5 ran)
- [ ] Phase-transition summary emitted - [ ] Phase-transition summary emitted
## Phase 3: Eng Review + Dual Voices ## Phase 3: Eng Review + Dual Voices (always runs, always LAST — the required gate reviews the final amended plan)
{{SECTION:eng-phase}} {{SECTION:eng-phase}}
--- ---
## Phase 3.5: DX Review (conditional — skip if no developer-facing scope)
**Skip condition:** If DX scope was NOT detected in Phase 0, skip this phase
entirely — do NOT read its section. Log: "Phase 3.5 skipped — no developer-facing scope detected."
{{SECTION:dx-phase}}
---
## Decision Audit Trail ## Decision Audit Trail
After each auto-decision, append a row to the plan file using Edit: After each auto-decision, append a row to the plan file using Edit:
@@ -368,7 +380,16 @@ produced. Check the plan file and conversation for each item.
- [ ] Dual voices ran (or noted unavailable/skipped with phase) - [ ] Dual voices ran (or noted unavailable/skipped with phase)
- [ ] Design litmus scorecard produced - [ ] Design litmus scorecard produced
**Phase 3 (Eng) outputs:** **Phase 2.5 (DX) outputs — only if DX scope detected:**
- [ ] All 8 DX dimensions evaluated with scores
- [ ] Developer journey map produced
- [ ] Developer empathy narrative written
- [ ] TTHW assessment with target
- [ ] DX Implementation Checklist produced
- [ ] Dual voices ran (or noted unavailable/skipped with phase)
- [ ] DX consensus table produced
**Phase 3 (Eng — final phase) outputs:**
- [ ] Scope challenge with actual code analysis (not just "scope is fine") - [ ] Scope challenge with actual code analysis (not just "scope is fine")
- [ ] Architecture ASCII diagram produced - [ ] Architecture ASCII diagram produced
- [ ] Test diagram mapping codepaths to test coverage - [ ] Test diagram mapping codepaths to test coverage
@@ -380,15 +401,6 @@ produced. Check the plan file and conversation for each item.
- [ ] Dual voices ran (Codex + Claude subagent, or noted unavailable) - [ ] Dual voices ran (Codex + Claude subagent, or noted unavailable)
- [ ] Eng consensus table produced - [ ] Eng consensus table produced
**Phase 3.5 (DX) outputs — only if DX scope detected:**
- [ ] All 8 DX dimensions evaluated with scores
- [ ] Developer journey map produced
- [ ] Developer empathy narrative written
- [ ] TTHW assessment with target
- [ ] DX Implementation Checklist produced
- [ ] Dual voices ran (or noted unavailable/skipped with phase)
- [ ] DX consensus table produced
**Cross-phase:** **Cross-phase:**
- [ ] Cross-phase themes section written - [ ] Cross-phase themes section written
@@ -479,7 +491,7 @@ AskUserQuestion options:
- A: mark APPROVED, write review logs, suggest /ship - A: mark APPROVED, write review logs, suggest /ship
- B: ask which overrides, apply, re-present gate - B: ask which overrides, apply, re-present gate
- C: answer freeform, re-present gate - C: answer freeform, re-present gate
- D: make changes, re-run affected phases (scope→1B, design→2, test plan→3, arch→3). Max 3 cycles. - D: make changes, re-run affected phases (scope→1B, design→2, dx→2.5, test plan→3, arch→3; a re-run of any earlier phase re-runs Eng after it — the gate always reviews the final plan). Max 3 cycles.
- E: start over - E: start over
--- ---
@@ -504,7 +516,7 @@ If Phase 2 ran (UI scope):
~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"plan-design-review","timestamp":"'"$TIMESTAMP"'","status":"STATUS","unresolved":N,"via":"autoplan","commit":"'"$COMMIT"'"}' ~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"plan-design-review","timestamp":"'"$TIMESTAMP"'","status":"STATUS","unresolved":N,"via":"autoplan","commit":"'"$COMMIT"'"}'
``` ```
If Phase 3.5 ran (DX scope): If Phase 2.5 ran (DX scope):
```bash ```bash
~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"plan-devex-review","timestamp":"'"$TIMESTAMP"'","status":"STATUS","initial_score":N,"overall_score":N,"product_type":"TYPE","tthw_current":"TTHW","tthw_target":"TARGET","unresolved":N,"via":"autoplan","commit":"'"$COMMIT"'"}' ~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"plan-devex-review","timestamp":"'"$TIMESTAMP"'","status":"STATUS","initial_score":N,"overall_score":N,"product_type":"TYPE","tthw_current":"TTHW","tthw_target":"TARGET","unresolved":N,"via":"autoplan","commit":"'"$COMMIT"'"}'
``` ```
@@ -521,7 +533,7 @@ If Phase 2 ran (UI scope), also log:
~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"autoplan-voices","timestamp":"'"$TIMESTAMP"'","status":"STATUS","source":"SOURCE","phase":"design","via":"autoplan","consensus_confirmed":N,"consensus_disagree":N,"commit":"'"$COMMIT"'"}' ~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"autoplan-voices","timestamp":"'"$TIMESTAMP"'","status":"STATUS","source":"SOURCE","phase":"design","via":"autoplan","consensus_confirmed":N,"consensus_disagree":N,"commit":"'"$COMMIT"'"}'
``` ```
If Phase 3.5 ran (DX scope), also log: If Phase 2.5 ran (DX scope), also log:
```bash ```bash
~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"autoplan-voices","timestamp":"'"$TIMESTAMP"'","status":"STATUS","source":"SOURCE","phase":"dx","via":"autoplan","consensus_confirmed":N,"consensus_disagree":N,"commit":"'"$COMMIT"'"}' ~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"autoplan-voices","timestamp":"'"$TIMESTAMP"'","status":"STATUS","source":"SOURCE","phase":"dx","via":"autoplan","consensus_confirmed":N,"consensus_disagree":N,"commit":"'"$COMMIT"'"}'
``` ```
@@ -536,8 +548,8 @@ Suggest next step: `/ship` when ready to create the PR.
## Important Rules ## Important Rules
- **Never abort.** The user chose /autoplan. Respect that choice. Surface all taste decisions, never redirect to interactive review. - **Never abort.** The user chose /autoplan. Respect that choice. Surface all taste decisions, never redirect to interactive review.
- **Two gates.** The non-auto-decided AskUserQuestions are: (1) premise confirmation in Phase 1, and (2) User Challenges — when both models agree the user's stated direction should change. Everything else is auto-decided using the 6 principles. - **One gate.** The only non-auto-decided AskUserQuestions surface at the Final Approval Gate: User Challenges — including clearly-wrong premises queued from Phase 1. Everything else resolves to the recommended option (the 6 principles break ties), so the pipeline never stops mid-run.
- **Log every decision.** No silent auto-decisions. Every choice gets a row in the audit trail. - **Log every decision.** No silent auto-decisions. Every choice gets a row in the audit trail.
- **Full depth means full depth.** Do not compress or skip sections from the loaded skill files (except the skip list in Phase 0). "Full depth" means: read the code the section asks you to read, produce the outputs the section requires, identify every issue, and decide each one. A one-sentence summary of a section is not "full depth" — it is a skip. If you catch yourself writing fewer than 3 sentences for any review section, you are likely compressing. - **Full depth means full depth.** Do not compress or skip sections from the loaded skill files (except the skip list in Phase 0). "Full depth" means: read the code the section asks you to read, produce the outputs the section requires, identify every issue, and decide each one. A one-sentence summary of a section is not "full depth" — it is a skip. If you catch yourself writing fewer than 3 sentences for any review section, you are likely compressing.
- **Artifacts are deliverables.** Test plan artifact, failure modes registry, error/rescue table, ASCII diagrams — these must exist on disk or in the plan file when the review completes. If they don't exist, the review is incomplete. - **Artifacts are deliverables.** Test plan artifact, failure modes registry, error/rescue table, ASCII diagrams — these must exist on disk or in the plan file when the review completes. If they don't exist, the review is incomplete.
- **Sequential order.** CEO → Design → Eng → DX. Each phase builds on the last. - **Sequential order.** CEO → Design (if UI scope) → DX (if developer-facing scope) → Eng, always last. Each phase builds on the last; the required gate reviews the final amended plan.
+8 -5
View File
@@ -5,9 +5,11 @@ Override: every AskUserQuestion → auto-decide using the 6 principles.
**Override rules:** **Override rules:**
- Mode selection: SELECTIVE EXPANSION - Mode selection: SELECTIVE EXPANSION
- Premises: accept reasonable ones (P6), challenge only clearly wrong ones - Premises: accept reasonable ones (P6). Clearly-wrong or challenged premises are
- **GATE: Present premises to user for confirmation** — this is the ONE AskUserQuestion NOT a mid-run stop — queue each as a User-Challenge-shaped item for the Final
that is NOT auto-decided. Premises require human judgment. Approval Gate (Phase 4): what the plan assumes, why it looks wrong, and the cost
of proceeding anyway. Premises still require human judgment — the human exercises
it at the gate, exactly once, not mid-pipeline.
- Alternatives: pick highest completeness (P1). If tied, pick simplest (P5). - Alternatives: pick highest completeness (P1). If tied, pick simplest (P5).
If top 2 are close → mark TASTE DECISION. If top 2 are close → mark TASTE DECISION.
- Scope expansion: in blast radius + <1d CC → approve (P2). Outside → defer to TODOS.md (P3). - Scope expansion: in blast radius + <1d CC → approve (P2). Outside → defer to TODOS.md (P3).
@@ -112,5 +114,6 @@ Sections 1-10 — for EACH section, run the evaluation criteria from the loaded
> Consensus: [X/6 confirmed, Y disagreements → surfaced at gate]. > Consensus: [X/6 confirmed, Y disagreements → surfaced at gate].
> Passing to Phase 2. > Passing to Phase 2.
Do NOT begin Phase 2 until all Phase 1 outputs are written to the plan file Do NOT begin Phase 2 until all Phase 1 outputs are written to the plan file,
and the premise gate has been passed. including the premise assessment (queued premise challenges travel to the
Final Gate — they never pause the pipeline here).
+8 -5
View File
@@ -3,9 +3,11 @@ Override: every AskUserQuestion → auto-decide using the 6 principles.
**Override rules:** **Override rules:**
- Mode selection: SELECTIVE EXPANSION - Mode selection: SELECTIVE EXPANSION
- Premises: accept reasonable ones (P6), challenge only clearly wrong ones - Premises: accept reasonable ones (P6). Clearly-wrong or challenged premises are
- **GATE: Present premises to user for confirmation** — this is the ONE AskUserQuestion NOT a mid-run stop — queue each as a User-Challenge-shaped item for the Final
that is NOT auto-decided. Premises require human judgment. Approval Gate (Phase 4): what the plan assumes, why it looks wrong, and the cost
of proceeding anyway. Premises still require human judgment — the human exercises
it at the gate, exactly once, not mid-pipeline.
- Alternatives: pick highest completeness (P1). If tied, pick simplest (P5). - Alternatives: pick highest completeness (P1). If tied, pick simplest (P5).
If top 2 are close → mark TASTE DECISION. If top 2 are close → mark TASTE DECISION.
- Scope expansion: in blast radius + <1d CC → approve (P2). Outside → defer to TODOS.md (P3). - Scope expansion: in blast radius + <1d CC → approve (P2). Outside → defer to TODOS.md (P3).
@@ -110,5 +112,6 @@ Sections 1-10 — for EACH section, run the evaluation criteria from the loaded
> Consensus: [X/6 confirmed, Y disagreements → surfaced at gate]. > Consensus: [X/6 confirmed, Y disagreements → surfaced at gate].
> Passing to Phase 2. > Passing to Phase 2.
Do NOT begin Phase 2 until all Phase 1 outputs are written to the plan file Do NOT begin Phase 2 until all Phase 1 outputs are written to the plan file,
and the premise gate has been passed. including the premise assessment (queued premise challenges travel to the
Final Gate — they never pause the pipeline here).
+4 -4
View File
@@ -87,15 +87,15 @@ Missing voice = N/A (not CONFIRMED). Single critical finding from one voice = fl
4. DX Scorecard: Produce the full scorecard with all 8 dimensions scored. 4. DX Scorecard: Produce the full scorecard with all 8 dimensions scored.
**Mandatory outputs from Phase 3.5:** **Mandatory outputs from Phase 2.5:**
- Developer journey map (9-stage table) - Developer journey map (9-stage table)
- Developer empathy narrative (first-person perspective) - Developer empathy narrative (first-person perspective)
- DX Scorecard with all 8 dimension scores - DX Scorecard with all 8 dimension scores
- DX Implementation Checklist - DX Implementation Checklist
- TTHW assessment with target - TTHW assessment with target
**PHASE 3.5 COMPLETE.** Emit phase-transition summary: **PHASE 2.5 COMPLETE.** Emit phase-transition summary:
> **Phase 3.5 complete.** DX overall: [N]/10. TTHW: [N] min → [target] min. > **Phase 2.5 complete.** DX overall: [N]/10. TTHW: [N] min → [target] min.
> Codex: [N concerns]. Claude subagent: [N issues]. > Codex: [N concerns]. Claude subagent: [N issues].
> Consensus: [X/6 confirmed, Y disagreements → surfaced at gate]. > Consensus: [X/6 confirmed, Y disagreements → surfaced at gate].
> Passing to Phase 4 (Final Gate). > Passing to Phase 3 (Eng Review — the required gate reviews the final amended plan).
+4 -4
View File
@@ -85,15 +85,15 @@ Missing voice = N/A (not CONFIRMED). Single critical finding from one voice = fl
4. DX Scorecard: Produce the full scorecard with all 8 dimensions scored. 4. DX Scorecard: Produce the full scorecard with all 8 dimensions scored.
**Mandatory outputs from Phase 3.5:** **Mandatory outputs from Phase 2.5:**
- Developer journey map (9-stage table) - Developer journey map (9-stage table)
- Developer empathy narrative (first-person perspective) - Developer empathy narrative (first-person perspective)
- DX Scorecard with all 8 dimension scores - DX Scorecard with all 8 dimension scores
- DX Implementation Checklist - DX Implementation Checklist
- TTHW assessment with target - TTHW assessment with target
**PHASE 3.5 COMPLETE.** Emit phase-transition summary: **PHASE 2.5 COMPLETE.** Emit phase-transition summary:
> **Phase 3.5 complete.** DX overall: [N]/10. TTHW: [N] min → [target] min. > **Phase 2.5 complete.** DX overall: [N]/10. TTHW: [N] min → [target] min.
> Codex: [N concerns]. Claude subagent: [N issues]. > Codex: [N concerns]. Claude subagent: [N issues].
> Consensus: [X/6 confirmed, Y disagreements → surfaced at gate]. > Consensus: [X/6 confirmed, Y disagreements → surfaced at gate].
> Passing to Phase 4 (Final Gate). > Passing to Phase 3 (Eng Review — the required gate reviews the final amended plan).
+3 -2
View File
@@ -18,6 +18,7 @@ Override: every AskUserQuestion → auto-decide using the 6 principles.
Also consider these findings from prior review phases: Also consider these findings from prior review phases:
CEO: <insert CEO consensus table summary — key concerns, DISAGREEs> CEO: <insert CEO consensus table summary — key concerns, DISAGREEs>
Design: <insert Design consensus table summary, or 'skipped, no UI scope'> Design: <insert Design consensus table summary, or 'skipped, no UI scope'>
DX: <insert DX consensus table summary, or 'skipped, no developer-facing scope'>
File: <plan_path>" -C "$_REPO_ROOT" -s read-only -c 'web_search="cached"' < /dev/null File: <plan_path>" -C "$_REPO_ROOT" -s read-only -c 'web_search="cached"' < /dev/null
_CODEX_EXIT=$? _CODEX_EXIT=$?
@@ -45,7 +46,7 @@ Override: every AskUserQuestion → auto-decide using the 6 principles.
- Architecture choices: explicit over clever (P5). If codex disagrees with valid reason → TASTE DECISION. Scope changes both models agree on → USER CHALLENGE. - Architecture choices: explicit over clever (P5). If codex disagrees with valid reason → TASTE DECISION. Scope changes both models agree on → USER CHALLENGE.
- Evals: always include all relevant suites (P1) - Evals: always include all relevant suites (P1)
- Test plan: generate artifact at `~/.gstack/projects/$SLUG/{user}-{branch}-test-plan-{datetime}.md` - Test plan: generate artifact at `~/.gstack/projects/$SLUG/{user}-{branch}-test-plan-{datetime}.md`
- TODOS.md: collect all deferred scope expansions from Phase 1, auto-write - TODOS.md: collect all deferred scope expansions from every prior phase (Eng runs last), auto-write
**Required execution checklist (Eng):** **Required execution checklist (Eng):**
@@ -105,4 +106,4 @@ Missing voice = N/A (not CONFIRMED). Single critical finding from one voice = fl
**PHASE 3 COMPLETE.** Emit phase-transition summary: **PHASE 3 COMPLETE.** Emit phase-transition summary:
> **Phase 3 complete.** Codex: [N concerns]. Claude subagent: [N issues]. > **Phase 3 complete.** Codex: [N concerns]. Claude subagent: [N issues].
> Consensus: [X/6 confirmed, Y disagreements → surfaced at gate]. > Consensus: [X/6 confirmed, Y disagreements → surfaced at gate].
> Passing to Phase 3.5 (DX Review) or Phase 4 (Final Gate). > Passing to Phase 4 (Final Gate).
+3 -2
View File
@@ -16,6 +16,7 @@ Override: every AskUserQuestion → auto-decide using the 6 principles.
Also consider these findings from prior review phases: Also consider these findings from prior review phases:
CEO: <insert CEO consensus table summary — key concerns, DISAGREEs> CEO: <insert CEO consensus table summary — key concerns, DISAGREEs>
Design: <insert Design consensus table summary, or 'skipped, no UI scope'> Design: <insert Design consensus table summary, or 'skipped, no UI scope'>
DX: <insert DX consensus table summary, or 'skipped, no developer-facing scope'>
File: <plan_path>" -C "$_REPO_ROOT" -s read-only {{CODEX_WEB_SEARCH_FLAG}} < /dev/null File: <plan_path>" -C "$_REPO_ROOT" -s read-only {{CODEX_WEB_SEARCH_FLAG}} < /dev/null
_CODEX_EXIT=$? _CODEX_EXIT=$?
@@ -43,7 +44,7 @@ Override: every AskUserQuestion → auto-decide using the 6 principles.
- Architecture choices: explicit over clever (P5). If codex disagrees with valid reason → TASTE DECISION. Scope changes both models agree on → USER CHALLENGE. - Architecture choices: explicit over clever (P5). If codex disagrees with valid reason → TASTE DECISION. Scope changes both models agree on → USER CHALLENGE.
- Evals: always include all relevant suites (P1) - Evals: always include all relevant suites (P1)
- Test plan: generate artifact at `~/.gstack/projects/$SLUG/{user}-{branch}-test-plan-{datetime}.md` - Test plan: generate artifact at `~/.gstack/projects/$SLUG/{user}-{branch}-test-plan-{datetime}.md`
- TODOS.md: collect all deferred scope expansions from Phase 1, auto-write - TODOS.md: collect all deferred scope expansions from every prior phase (Eng runs last), auto-write
**Required execution checklist (Eng):** **Required execution checklist (Eng):**
@@ -103,4 +104,4 @@ Missing voice = N/A (not CONFIRMED). Single critical finding from one voice = fl
**PHASE 3 COMPLETE.** Emit phase-transition summary: **PHASE 3 COMPLETE.** Emit phase-transition summary:
> **Phase 3 complete.** Codex: [N concerns]. Claude subagent: [N issues]. > **Phase 3 complete.** Codex: [N concerns]. Claude subagent: [N issues].
> Consensus: [X/6 confirmed, Y disagreements → surfaced at gate]. > Consensus: [X/6 confirmed, Y disagreements → surfaced at gate].
> Passing to Phase 3.5 (DX Review) or Phase 4 (Final Gate). > Passing to Phase 4 (Final Gate).
+3 -3
View File
@@ -2,7 +2,7 @@
"$schema": "https://gstack.dev/schemas/section-manifest.json", "$schema": "https://gstack.dev/schemas/section-manifest.json",
"skill": "autoplan", "skill": "autoplan",
"version": 1, "version": 1,
"note": "PASSIVE registry (v2 plan T9 / CM2). Fields are IDs, file paths, human titles, and human-readable trigger text ONLY. The skeleton's phase sequencing (Sequential Execution + the Phase 0 UI/DX scope detection) is the ONLY place that decides WHEN to read a section — Phase 2 and Phase 3.5 are conditional and their sections must NOT be read when their scope is absent; required-reads live in the E2E fixtures. No machine predicate here — see docs/designs/v2_PLAN.md:663.", "note": "PASSIVE registry (v2 plan T9 / CM2). Fields are IDs, file paths, human titles, and human-readable trigger text ONLY. The skeleton's phase sequencing (Sequential Execution + the Phase 0 UI/DX scope detection) is the ONLY place that decides WHEN to read a section — Phase 2 and Phase 2.5 are conditional and their sections must NOT be read when their scope is absent; required-reads live in the E2E fixtures. No machine predicate here — see docs/designs/v2_PLAN.md:663.",
"sections": [ "sections": [
{ {
"id": "ceo-phase", "id": "ceo-phase",
@@ -25,8 +25,8 @@
{ {
"id": "dx-phase", "id": "dx-phase",
"file": "dx-phase.md", "file": "dx-phase.md",
"title": "Phase 3.5: DX review — override rules, dual voices, 8-dimension scorecard", "title": "Phase 2.5: DX review — override rules, dual voices, 8-dimension scorecard",
"trigger": "starting Phase 3.5 (DX review — ONLY if developer-facing scope was detected in Phase 0; skip the read entirely otherwise)" "trigger": "starting Phase 2.5 (DX review — ONLY if developer-facing scope was detected in Phase 0; skip the read entirely otherwise)"
}, },
{ {
"id": "tasks-aggregator", "id": "tasks-aggregator",
+70
View File
@@ -0,0 +1,70 @@
/**
* /autoplan phase-order pin (free, static).
*
* The pipeline order is a deliberate design decision (2026-08-25, user-directed):
* CEO Design (if UI scope) DX (if developer-facing scope) Eng, ALWAYS LAST.
* Eng is the required shipping gate it must review the FINAL amended plan, so
* every other phase's amendments land before it. The original order buried Eng
* mid-pipeline (CEO Design Eng DX), which let DX findings land AFTER the
* gate had signed off the gate validated a stale plan.
*
* These assertions pin the template so a refactor can't silently restore the
* old order. The paid chain E2E (skill-e2e-autoplan-chain.test.ts) verifies the
* runtime behavior; this pins the source of truth for free on every PR.
*/
import { describe, test, expect } from 'bun:test';
import * as fs from 'fs';
import * as path from 'path';
const ROOT = path.join(import.meta.dir, '..');
const read = (p: string) => fs.readFileSync(path.join(ROOT, p), 'utf-8');
describe('autoplan phase order (Eng always last)', () => {
const tmpl = read('autoplan/SKILL.md.tmpl');
test('Sequential Execution block names Eng as the terminal phase', () => {
const block = tmpl.split('## Sequential Execution')[1]?.split('---')[0] ?? '';
expect(block).toContain('Eng runs LAST, always');
expect(block).toMatch(/CEO Design.* DX.* Eng/s);
// The old order must not resurface anywhere in the template.
expect(tmpl).not.toContain('CEO → Design → Eng → DX');
});
test('phase headings appear in the new order: 1, 2, 2.5, 3', () => {
const idx = (h: string) => {
const i = tmpl.indexOf(h);
expect(i).toBeGreaterThan(-1);
return i;
};
const p1 = idx('## Phase 1: CEO Review');
const p2 = idx('## Phase 2: Design Review');
const p25 = idx('## Phase 2.5: DX Review');
const p3 = idx('## Phase 3: Eng Review');
expect(p1).toBeLessThan(p2);
expect(p2).toBeLessThan(p25);
expect(p25).toBeLessThan(p3);
// No stale Phase 3.5 heading or transition marker survives.
expect(tmpl).not.toContain('Phase 3.5');
});
test('phase sections hand off in the new order', () => {
expect(read('autoplan/sections/dx-phase.md.tmpl')).toContain(
'Passing to Phase 3 (Eng Review',
);
expect(read('autoplan/sections/eng-phase.md.tmpl')).toContain(
'Passing to Phase 4 (Final Gate)',
);
// Eng's Codex voice sees every prior phase's consensus, DX included.
expect(read('autoplan/sections/eng-phase.md.tmpl')).toContain(
'DX: <insert DX consensus table summary',
);
});
test('single final gate: premises queue for the gate, never a mid-run stop', () => {
expect(tmpl).toContain('One exception class — never auto-decided');
expect(tmpl).not.toContain('Premise gate passed (user confirmed)');
const ceo = read('autoplan/sections/ceo-phase.md.tmpl');
expect(ceo).not.toContain('GATE: Present premises to user for confirmation');
expect(ceo).toContain('Final');
});
});
+15 -5
View File
@@ -6,8 +6,9 @@
* *
* "**Phase 1 complete." (CEO) * "**Phase 1 complete." (CEO)
* "**Phase 2 complete." (Design only if UI scope detected) * "**Phase 2 complete." (Design only if UI scope detected)
* "**Phase 3 complete." (Eng) * "**Phase 2.5 complete." (DX optional, skipped if no DX scope)
* "**Phase 3.5 complete." (DX optional, skipped if no DX scope) * "**Phase 3 complete." (Eng always runs, always LAST: the required
* gate reviews the final amended plan)
* *
* Why this exists: each individual phase has its own plan-mode smoke * Why this exists: each individual phase has its own plan-mode smoke
* test. Nothing verifies the SEQUENCING that phases don't run in * test. Nothing verifies the SEQUENCING that phases don't run in
@@ -88,7 +89,7 @@ describeE2E('/autoplan chain ordering (periodic)', () => {
// Phase markers live in autoplan's carved phase sections // Phase markers live in autoplan's carved phase sections
// (autoplan/sections/{ceo,design,eng,dx}-phase.md — the skeleton // (autoplan/sections/{ceo,design,eng,dx}-phase.md — the skeleton
// STOP-Reads each one at its phase boundary): // STOP-Reads each one at its phase boundary):
// "**Phase 1 complete." / "**Phase 2 complete." / "**Phase 3 complete." / "**Phase 3.5 complete." // "**Phase 1 complete." / "**Phase 2 complete." / "**Phase 2.5 complete." / "**Phase 3 complete."
const phasePattern = /\*\*Phase\s+(\d+(?:\.\d+)?)\s+complete\.?\*\*/g; const phasePattern = /\*\*Phase\s+(\d+(?:\.\d+)?)\s+complete\.?\*\*/g;
let lastPermSig = ''; let lastPermSig = '';
@@ -163,13 +164,22 @@ describeE2E('/autoplan chain ordering (periodic)', () => {
); );
} }
// Sequencing: CEO must end before Eng ends. Design (if observed) // Sequencing: CEO must end before Eng ends — and Eng is the terminal
// must end after CEO and before Eng. // phase (the required gate reviews the final amended plan). Design and
// DX (if observed) must end after CEO and before Eng.
expect(ceo.ts).toBeLessThan(eng.ts); expect(ceo.ts).toBeLessThan(eng.ts);
if (design) { if (design) {
expect(design.ts).toBeGreaterThan(ceo.ts); expect(design.ts).toBeGreaterThan(ceo.ts);
expect(design.ts).toBeLessThan(eng.ts); expect(design.ts).toBeLessThan(eng.ts);
} }
const dx = hits.find(h => h.phase === 2.5);
if (dx) {
expect(dx.ts).toBeGreaterThan(ceo.ts);
expect(dx.ts).toBeLessThan(eng.ts);
}
// No phase marker may appear after Eng's (Eng-last invariant).
const maxTs = Math.max(...hits.map(h => h.ts));
expect(eng.ts).toBe(maxTs);
} finally { } finally {
try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch { /* ignore */ } try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch { /* ignore */ }
} }