fix(brief): a brief with no research topics prints its next steps instead of entering the auto-only phase

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-22 15:12:59 +02:00
commit 8f9b0abfad
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
3 changed files with 35 additions and 3 deletions

View file

@ -965,7 +965,10 @@ printed `stamped: true`, then stop and print the next step:
## Phase 5 — Auto-orchestration opt-in (if research_topics > 0)
**Skip this phase if research_topics = 0.** Proceed directly to Phase 6.
**With research_topics = 0**, print the manual-path output below without the
`/trekresearch` lines (Brief, then `/trekplan --project {PROJECT_DIR}`, then
`/trekexecute --project {PROJECT_DIR}`), then run Phase 7 and stop. Phase 6 is
never entered without the operator's opt-in.
Ask the user via `AskUserQuestion`:
@ -1025,7 +1028,7 @@ Proceed to Phase 6.
## Phase 6 — Auto research dispatch (auto path only)
**Runs only when user opted into auto mode.**
**Runs only when user opted into auto mode, and only after Phase 4h approved the intent.**
### Step 6a — Confirm proceed

View file

@ -19,7 +19,7 @@
| 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:1125-1149 | 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:1128-1152 | 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:1294-1322 | 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 |

View file

@ -494,3 +494,32 @@ for (const rel of ['README.md', 'docs/operations.md']) {
assert.doesNotMatch(p, /stats/i, `${rel}: the profile paragraph still names stats`);
});
}
// --- #47 ---------------------------------------------------------------------------
// /trekbrief Phase 5 said "Skip this phase if research_topics = 0. Proceed
// directly to Phase 6.", so a brief with no research topics walked into the
// auto-only research dispatch nobody opted into. It now prints the manual
// next steps without the /trekresearch lines, runs Phase 7 and stops.
test('[#47] Phase 5: a brief with no research topics prints /trekplan --project and stops, never proceeds to Phase 6', () => {
const text = read('commands/trekbrief.md');
const p5 = flat(section(text, '## Phase 5 — Auto-orchestration opt-in (if research_topics > 0)'));
assert.doesNotMatch(p5, /Skip this phase if research_topics = 0/, 'Phase 5 still skips straight on with zero topics');
const opening = partAt('commands/trekbrief.md', '## Phase 5 — Auto-orchestration opt-in', (l) => l.startsWith('Ask the user'));
assert.doesNotMatch(opening, /proceed directly to Phase 6/i, 'a zero-topic brief still proceeds directly to Phase 6');
assert.match(opening, /\*\*With research_topics = 0\*\*, print the manual-path output below without the `\/trekresearch` lines \(Brief, then `\/trekplan --project \{PROJECT_DIR\}`, then `\/trekexecute --project \{PROJECT_DIR\}`\), then run Phase 7 and stop\./);
assert.match(opening, /Phase 6 is never entered without the operator's opt-in\./);
const manual = flat(section(text, '### Manual path (default)'));
assert.match(manual, /Then: \/trekplan --project \{PROJECT_DIR\} Then: \/trekexecute --project \{PROJECT_DIR\}/);
assert.match(manual, /Stop\. Do not continue to Phase 6\./);
});
test('[#47] Phase 6 runs only after the operator opted into auto mode and Phase 4h approved the intent', () => {
const p6 = flat(section(read('commands/trekbrief.md'), '## Phase 6 — Auto research dispatch (auto path only)'));
assert.match(p6, /^## Phase 6 — Auto research dispatch \(auto path only\) \*\*Runs only when user opted into auto mode,? and only after Phase 4h approved the intent\.\*\*/);
});
test('keep: /trekbrief\'s auto path still requires an approved intent', () => {
assert.equal(partAt('commands/trekbrief.md', '**Auto requires an approved intent.**', toBlank),
'**Auto requires an approved intent.** If Phase 4h ended "Leave unapproved", the auto chain would halt at `/trekplan` anyway — print the manual-path output instead and stop.');
});