fix(plan): execute hands the plan to /trekexecute instead of building it in the planning session

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-22 14:34:57 +02:00
commit eafe023c74
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
4 changed files with 81 additions and 12 deletions

View file

@ -487,7 +487,7 @@ When done, your output message should contain:
You can:
- Review the full plan at {plan path}
- Ask questions or request changes
- Say "execute" to implement
- Say "execute" for the /trekexecute line
- Say "save" to keep for later
```

View file

@ -1126,13 +1126,13 @@ Present a summary to the user:
You can:
- Say which open minors to fix ("fix 1 and 3")
- Ask questions or request changes to refine the plan
- Say **"execute"** to start implementing ← only when the gate exited 0
- Say **"execute"** for the `/trekexecute` line to run ← only when the gate exited 0
- Say **"save"** to keep the plan for later
```
When the gate exited 1, replace the "execute" line with
`Execution is blocked: {the gate's reasons}` and do not start implementing,
whatever is said next, until the gate exits 0.
`Execution is blocked: {the gate's reasons}` and do not print the `/trekexecute`
line, whatever is said next, until the gate exits 0.
**What counts as approval.** "Execute", "go" or "start" (or the plan-mode
approval below) approves the plan. A hedged reply — "sounds good", "looks
@ -1172,7 +1172,8 @@ plan-approval prompt:
3. **Approved:** the session leaves plan mode. Copy the plan file to the plan
destination from Phase 3, then run the gate on the destination — it must
exit 0 again, which also proves the copy is the reviewed text. Then
continue with the operator's choice (Phase 11).
print the `/trekexecute` line (Phase 11) and stop — leaving plan mode is
not an order to implement.
4. **"No, keep planning":** revise per the operator's words, run one Phase 9
round, and present again from step 1.
@ -1260,15 +1261,16 @@ Confirm the plan and brief file locations and exit.
### "execute" / "go" / "start"
Begin implementing the plan step by step in this session. Follow the plan exactly.
Mark each step complete as you go.
Do not implement in this session. Print the line the operator gives
`/trekexecute` — `/trekexecute --project {project_dir}`, or
`/trekexecute {plan_path}` without a project directory — and stop.
`/trekexecute` is what checks the plan's approval (K2), locks the tests, runs
one step helper per step and the review.
### "execute with team" / "team"
There is no team path. Tell the user that parallel team execution is not available
from `/trekplan`, then proceed exactly as for "execute" (sequential, in this
session). Parallel implementation is `--decompose` followed by `/trekexecute`'s
multi-session waves.
There is no team path. Print the same `/trekexecute` line and stop; parallel
work is `--decompose` followed by `/trekexecute`'s session orders.
## Phase 12 — Session tracking

View file

@ -21,7 +21,7 @@
|-----------|--------|-------------|----------|---------------|-----|
| trekbrief-stats | ts, task, slug, mode, interview_turns, review_iterations, brief_quality, research_topics, auto_research, auto_result, intent_approved, project_dir, order_id, order_claimed_at, order_reason | commands/trekbrief.md (orchestrator-emit Phase 7; order_* added by lib/stats/stats-append.mjs) | trekbrief.md:1125-1149 | profile, phase_models, profile_source | none |
| trekresearch-stats | ts, question, mode, scope, engine, slug, project_dir, brief_path, dimensions, dimensions_baseline, dimensions_baseline_preserved, effort, conv_turns, empty_turns, unique_sources, agents_local, agents_external, gemini_used, confidence, contradictions, open_questions | lib/stats/stats-append.mjs (trekresearch.md Stats tracking) | trekresearch.md:782-808 | profile, phase_models, parallel_agents, external_research_enabled, profile_source | none |
| trekplan-stats | ts, task, mode, slug, brief_path, project_dir, codebase_size, codebase_files, agents_deployed, deep_dives, research_briefs_used, research_scout_used, critic_verdict, guardian_verdict, outcome | lib/stats/stats-append.mjs (trekplan.md Phase 12) | trekplan.md:1273-1301 | profile, phase_models, parallel_agents, profile_source | none |
| trekplan-stats | ts, task, mode, slug, brief_path, project_dir, codebase_size, codebase_files, agents_deployed, deep_dives, research_briefs_used, research_scout_used, critic_verdict, guardian_verdict, outcome | lib/stats/stats-append.mjs (trekplan.md Phase 12) | trekplan.md:1275-1303 | profile, phase_models, parallel_agents, profile_source | none |
| trekexecute-stats (Phase 9 record) | ts, plan, plan_type, mode, result, steps_total, steps_passed, steps_failed, steps_skipped, failed_at_step | lib/stats/stats-append.mjs (trekexecute.md Phase 9) | trekexecute.md:2909-2931 | profile, phase_models, profile_source | none |
| trekexecute-stats (autonomy events) | ts, event, known_event, payload | lib/stats/event-emit.mjs `emit()` | event-emit.mjs:78-99 | payload.profile, payload.phase_models, payload.profile_source | none |
| trekexecute-stats (PostToolUse Bash) | ts, session_id, command_excerpt, duration_ms, success | hooks/scripts/post-bash-stats.mjs (Bash PostToolUse) | post-bash-stats.mjs:42-54 | none (hook is plugin-level, not profile-aware) | command_excerpt (CWE-212) |

View file

@ -234,3 +234,70 @@ test('[#26] the three reference documents hold read-only tools', () => {
assert.equal(fm.fields.model.value, 'opus', `${name}: model stays opus`);
}
});
// --- #52 ---------------------------------------------------------------------------
// /trekplan's "execute" answer began implementing the plan in the planning
// session, past /trekexecute's approval check (K2), test lock and step helpers.
// It now prints the /trekexecute line and stops.
/** The `/trekexecute` line /trekplan prints, in both forms. */
function printsTrekexecuteLine(part, where) {
assert.match(part, /`\/trekexecute --project \{project_dir\}`/, `${where}: must print the /trekexecute --project line`);
assert.match(part, /`\/trekexecute \{plan_path\}`/, `${where}: must print the /trekexecute {plan_path} line`);
}
/**
* No text that has /trekplan build the plan itself: no "Begin implementing",
* and no "in this session" other than the one prohibition sentence.
*/
function neverImplementsHere(part, where) {
const rest = part.split('Do not implement in this session.').join('');
assert.doesNotMatch(rest, /Begin implementing/i, `${where}: still begins implementing`);
assert.doesNotMatch(rest, /in this session/i, `${where}: still implements in this session`);
}
test('[#52] Phase 11 "execute": prints the /trekexecute line and stops, never implements in this session', () => {
const block = flat(section(read('commands/trekplan.md'), '### "execute" / "go" / "start"'));
neverImplementsHere(block, 'Phase 11 "execute"');
assert.match(block, /^### "execute" \/ "go" \/ "start" Do not implement in this session\./);
printsTrekexecuteLine(block, 'Phase 11 "execute"');
assert.match(block, /without a project directory — and stop\./);
assert.match(block, /`\/trekexecute` is what checks the plan's approval \(K2\), locks the tests, runs one step helper per step and the review\./);
});
test('[#52] Phase 11 "team": no team path, the same /trekexecute line, then stop', () => {
const block = flat(section(read('commands/trekplan.md'), '### "execute with team" / "team"'));
neverImplementsHere(block, 'Phase 11 "team"');
assert.doesNotMatch(block, /proceed exactly as for "execute"/, 'Phase 11 "team": still proceeds as "execute" did');
assert.match(block, /There is no team path\. Print the same `\/trekexecute` line and stop; parallel work is `--decompose` followed by `\/trekexecute`'s session orders\./);
});
test('[#52] Phase 10 menu: "execute" is for the /trekexecute line, and a stopped gate withholds it', () => {
const p10 = flat(section(read('commands/trekplan.md'), '## Phase 10 — Present and refine'));
assert.doesNotMatch(p10, /start implementing/i, 'Phase 10 still offers or withholds "start implementing"');
assert.match(p10, /- Say \*\*"execute"\*\* for the `\/trekexecute` line to run ← only when the gate exited 0/);
assert.match(p10, /`Execution is blocked: \{the gate's reasons\}` and do not print the `\/trekexecute` line, whatever is said next, until the gate exits 0\./);
});
test('[#52] sibling: plan mode step 3 prints the /trekexecute line and stops', () => {
const pm = flat(section(read('commands/trekplan.md'), '### In plan mode'));
assert.doesNotMatch(pm, /Then continue with the operator's choice \(Phase 11\)\./, 'plan mode still continues with the operator\'s choice');
assert.match(pm, /Then print the `\/trekexecute` line \(Phase 11\) and stop — leaving plan mode is not an order to implement\./);
});
test('[#52] hard rule: "No premature execution" holds, and nothing in Phases 10-11 implements the plan', () => {
const text = read('commands/trekplan.md');
const rules = flat(section(text, '## Hard rules'));
assert.match(rules, /\*\*No premature execution\*\*: Do not modify any project files until the user explicitly approves the plan, and never while `plan-gate\.mjs` exits non-zero on it\./);
for (const h of ['## Phase 10 — Present and refine', '## Phase 11 — Handoff']) {
const part = flat(section(text, h));
neverImplementsHere(part, h);
assert.doesNotMatch(part, /start implementing|Follow the plan exactly|Mark each step complete/i, `${h}: still has /trekplan build the plan`);
}
});
test('[#52] sibling: agents/planning-orchestrator.md says "execute" gives the /trekexecute line', () => {
const text = read('agents/planning-orchestrator.md');
assert.doesNotMatch(text, /Say "execute" to implement/, 'planning-orchestrator still says "execute" implements');
assert.ok(text.split('\n').includes('- Say "execute" for the /trekexecute line'), 'missing line: - Say "execute" for the /trekexecute line');
});