fix(commands): the trekplan execute exits run Phase 12 and the research loop names its model

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-26 16:40:24 +01:00
commit 4b59ec7f16
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
5 changed files with 36 additions and 6 deletions

View file

@ -1295,14 +1295,14 @@ Confirm the plan and brief file locations and exit.
Do not implement in this session. Print the line the operator gives Do not implement in this session. Print the line the operator gives
`/trekexecute` — `/trekexecute --project {project_dir}`, or `/trekexecute` — `/trekexecute --project {project_dir}`, or
`/trekexecute {plan_path}` without a project directory — and stop. `/trekexecute {plan_path}` without a project directory — then run Phase 12 (`outcome: execute`).
`/trekexecute` is what checks the plan's approval (K2), locks the tests, runs `/trekexecute` is what checks the plan's approval (K2), locks the tests, runs
one step helper per step and the review. one step helper per step and the review.
### "execute with team" / "team" ### "execute with team" / "team"
There is no team path. Print the same `/trekexecute` line and stop; parallel There is no team path. Print the same `/trekexecute` line, then run Phase 12
work is `--decompose` followed by `/trekexecute`'s session orders. (`outcome: execute_team`); parallel work is `--decompose` followed by `/trekexecute`'s session orders.
## Phase 12 — Session tracking ## Phase 12 — Session tracking

View file

@ -648,6 +648,10 @@ reformulated, not forced through. A gate that *could not run* is neither — no
rewrite can clear it, so treat it as a hard stop and say so, rather than rewrite can clear it, so treat it as a hard stop and say so, rather than
rewriting a query that was never the problem. rewriting a query that was never the problem.
A turn that spawns an agent passes `model: phase_signal_result.model`, else
`opus` — the agent may be one of Claude Code's built-in agents, which have no
Voyage frontmatter to fall back to; see Launch rules.
**Empty turns.** A turn that returns no findings, or findings without **Empty turns.** A turn that returns no findings, or findings without
citations, is marked `empty`. An empty turn is counted in `empty_turns` and citations, is marked `empty`. An empty turn is counted in `empty_turns` and
does NOT re-target the same dimension — re-asking the same question of the does NOT re-target the same dimension — re-asking the same question of the

View file

@ -20,7 +20,7 @@
| schema_id | fields | writer_path | line_ref | v4.1 additive | PII | | schema_id | fields | writer_path | line_ref | v4.1 additive | PII |
|-----------|--------|-------------|----------|---------------|-----| |-----------|--------|-------------|----------|---------------|-----|
| 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:1141-1165 | profile, phase_models, profile_source | none | | 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:1141-1165 | 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:822-855 | profile, phase_models, parallel_agents, external_research_enabled, 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:826-859 | 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:1307-1335 | 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:1307-1335 | 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:2973-2995 | profile, phase_models, 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:2973-2995 | 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 (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 |

View file

@ -337,7 +337,7 @@ test('[#52] Phase 11 "execute": prints the /trekexecute line and stops, never im
neverImplementsHere(block, 'Phase 11 "execute"'); neverImplementsHere(block, 'Phase 11 "execute"');
assert.match(block, /^### "execute" \/ "go" \/ "start" Do not implement in this session\./); assert.match(block, /^### "execute" \/ "go" \/ "start" Do not implement in this session\./);
printsTrekexecuteLine(block, 'Phase 11 "execute"'); printsTrekexecuteLine(block, 'Phase 11 "execute"');
assert.match(block, /without a project directory — and stop\./); assert.match(block, /without a project directory — then run Phase 12 \(`outcome: execute`\)\./);
assert.match(block, /`\/trekexecute` is what checks the plan's approval \(K2\), locks the tests, runs one step helper per step and the review\./); assert.match(block, /`\/trekexecute` is what checks the plan's approval \(K2\), locks the tests, runs one step helper per step and the review\./);
}); });
@ -345,7 +345,7 @@ 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"')); const block = flat(section(read('commands/trekplan.md'), '### "execute with team" / "team"'));
neverImplementsHere(block, 'Phase 11 "team"'); neverImplementsHere(block, 'Phase 11 "team"');
assert.doesNotMatch(block, /proceed exactly as for "execute"/, 'Phase 11 "team": still proceeds as "execute" did'); 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\./); assert.match(block, /There is no team path\. Print the same `\/trekexecute` line, then run Phase 12 \(`outcome: execute_team`\); 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', () => { test('[#52] Phase 10 menu: "execute" is for the /trekexecute line, and a stopped gate withholds it', () => {

View file

@ -323,3 +323,29 @@ test('[K2] the 6a row names Phase 7 with auto_result cancelled', () => {
assert.match(flat(step6a), /If cancelled → fall back to manual path output, run Phase 7 \(`auto_result: cancelled`\) and stop\./, assert.match(flat(step6a), /If cancelled → fall back to manual path output, run Phase 7 \(`auto_result: cancelled`\) and stop\./,
'the sentence after the 6a table no longer names Phase 7 with auto_result cancelled'); 'the sentence after the 6a table no longer names Phase 7 with auto_result cancelled');
}); });
// --- DJ1 / DJ2 ---------------------------------------------------------------------
const TREKPLAN = 'commands/trekplan.md';
test('[DJ1] the execute and team exits run Phase 12', () => {
const execute = flat(between(TREKPLAN, '### "execute" / "go" / "start"', '### "execute with team" / "team"'));
assert.match(execute, /`\/trekexecute \{plan_path\}` without a project directory — then run Phase 12 \(`outcome: execute`\)\./,
`the "execute" exit does not run Phase 12 with outcome execute: ${execute}`);
assert.doesNotMatch(execute, /\band stop\b/, `the "execute" exit still ends in a bare "and stop": ${execute}`);
const team = flat(between(TREKPLAN, '### "execute with team" / "team"', '## Phase 12 — Session tracking'));
assert.match(team, /There is no team path\. Print the same `\/trekexecute` line, then run Phase 12 \(`outcome: execute_team`\);/,
`the "team" exit does not run Phase 12 with outcome execute_team: ${team}`);
assert.doesNotMatch(team, /\band stop\b/, `the "team" exit still ends in a bare "and stop": ${team}`);
const p12 = between(TREKPLAN, '## Phase 12 — Session tracking', '## Profile');
assert.ok(p12.includes('"outcome": "{execute|execute_team|save|refine}"'),
'Phase 12 no longer holds the outcome enum the two exits name');
});
test('[DJ2] the high-effort loop names the model for a turn that spawns', () => {
const loop = between('commands/trekresearch.md', '### Per-turn protocol', '### Exits (all three, always one of them)');
const hits = sentencesWith(loop, 'spawns');
assert.ok(hits.some((s) => /^A turn that spawns an agent passes `model: phase_signal_result\.model`, else `opus`/.test(s)),
`the per-turn protocol does not say a turn that spawns passes model: phase_signal_result.model, else opus: ${hits.join(' | ')}`);
assert.doesNotMatch(loop, /model: "opus"/, 'the per-turn protocol pins a spawn to model: "opus"');
});