docs(trekresearch): deep-research engine is operator-only from CC 2.1.218; document the real window

Claude Code 2.1.218 changed /deep-research to start only when invoked
manually; from there the Skill tool refuses a model invocation outright
with `disable-model-invocation` (measured in a real `--engine deep-research`
run 2026-09-01 18:32Z - the SC3 fallback to swarm held). The engine was
built against 2.1.196 and the prose still promised a path Claude Code has
removed ("requires Claude Code 2.1.154+").

The flag is KEPT as an additive opt-in that never hard-fails. Prose only:
no lib/ change, no adapter-contract change, no default change, no version
bump.

- commands/trekresearch.md: flag bullet states the closed window
  `2.1.154 <= CC < 2.1.218`; the pre-gate gained an UPPER ceiling (still a
  numeric comparison, not a string one) that skips straight to the fallback
  with reason `disable-model-invocation`; step 3 names the Skill-tool
  refusal as a known failure manifestation; step 4 lists the reason tokens.
- docs/command-modes.md + README.md: same window, one sentence each, on the
  reference row itself.
- CHANGELOG.md: Unreleased/Docs entry.

Tests first (Iron Law): tests/lib/doc-consistency.test.mjs gained a pin
requiring 2.1.218 + disable-model-invocation on all three surfaces, on both
reference rows, and in both load-bearing regions of the command (flag
bullet + pre-gate). Seen red on all three surfaces before the prose change.
tests/commands/trekresearch-engine.test.mjs unchanged and green.

New baseline: 1024 tests, 1022 pass / 0 fail / 2 skip (was 1023: 1021/0/2).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-01 22:23:09 +02:00
commit 4e5523fb0a
5 changed files with 94 additions and 11 deletions

View file

@ -4,6 +4,25 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## Unreleased
### Docs
- **`/trekresearch --engine deep-research`: document the real version window.**
Claude Code **2.1.218** changed `/deep-research` to start only when the operator
invokes it; from there the Skill tool refuses a model invocation outright with
`disable-model-invocation` (measured in a real `--engine deep-research` run on
2026-09-01 — the SC3 fallback to `swarm` held). The engine was built against
2.1.196 and the prose still promised a path Claude Code has removed
("requires Claude Code 2.1.154+"). `commands/trekresearch.md` (flag bullet +
pre-gate + fallback reason tokens), `docs/command-modes.md` and `README.md` now
state the closed window `2.1.154 <= CC < 2.1.218` and name
`disable-model-invocation` as the expected fallback reason on any current CC.
The pre-gate gained an upper ceiling (still a numeric comparison, not a string
one). **The flag is kept** as an additive opt-in that never hard-fails; no
`lib/` change, no adapter-contract change, no default change, no version bump.
Pinned by `tests/lib/doc-consistency.test.mjs`.
## v5.10.0 — 2026-08-18 — STORM bounded research loop (default-off) + the Agent-tool `name` spawn defect
Additive. Every new research mechanism ships **inert**: `VOYAGE_STORM_ENABLED` is

View file

@ -212,7 +212,7 @@ Output:
| **External** | `/trekresearch --external <question>` | Only external research agents (skip codebase analysis) |
| **Foreground** | `/trekresearch --fg <question>` | No-op alias (foreground is default since v2.4.0) |
| **Profile** | `/trekresearch --profile <name> <question>` | (v4.1.0) Pin model profile for the research phase. See [Profile system](#profile-system-v410). |
| **Engine** | `/trekresearch --external --engine deep-research <question>` | Delegate the external phase to Claude Code's built-in `/deep-research` workflow; falls back to `swarm` if unavailable. Default `swarm`. |
| **Engine** | `/trekresearch --external --engine deep-research <question>` | Delegate the external phase to Claude Code's built-in `/deep-research` workflow. Only works on `2.1.154 <= CC < 2.1.218`; from **2.1.218** `/deep-research` is operator-invoked only (Skill tool: `disable-model-invocation`), so it always falls back to `swarm`. Never hard-fails. Default `swarm`. |
Flags combine: `--project <dir> --external`.

View file

@ -87,9 +87,14 @@ Supported flags:
behavior). `swarm` runs Voyage's own external-research agent swarm;
`deep-research` delegates the external phase to Claude Code's built-in
`/deep-research` dynamic workflow and adapts its report into the research-brief
schema (requires Claude Code 2.1.154+ and dynamic workflows enabled; falls back
to `swarm` and notes the fallback if unavailable — never hard-fails). Orthogonal
to `--profile`/`phase_signals`; only affects the external phase. Set
schema. **The delegation only works inside a closed version window:
`2.1.154 <= CC < 2.1.218`** (dynamic workflows enabled). From Claude Code
**2.1.218** `/deep-research` starts only when the operator invokes it, and the
Skill tool refuses a model invocation outright (`disable-model-invocation`), so
on 2.1.218 or newer the engine **always** falls back to `swarm`. The flag is
kept as an additive opt-in and **never hard-fails**: outside the window it
degrades to `swarm` and logs the reason. Orthogonal to
`--profile`/`phase_signals`; only affects the external phase. Set
**engine = {swarm|deep-research}** (the *requested* engine).
Flags can be combined:
@ -328,9 +333,13 @@ changes nothing (SC1). Keep the native-swarm anchors intact ("in parallel",
1. **Coarse pre-gate (best-effort, NOT a trust signal).** `Bash: claude --version`;
parse the leading `X.Y.Z` (e.g. from `2.1.196 (Claude Code)`) and compare
numerically against `2.1.154` — split each on `.` and compare major, then minor,
numerically against **both ends** of the supported window
`2.1.154 <= version < 2.1.218` — split each on `.` and compare major, then minor,
then patch as integers (do NOT string-compare; lexical comparison mis-orders
multi-digit patch numbers). If the version is `< 2.1.154`, OR if
multi-digit patch numbers). If the version is `< 2.1.154` (below the
dynamic-workflows floor), OR `>= 2.1.218` (the ceiling: `/deep-research` starts
only when the operator invokes it, and the Skill tool refuses a model invocation
with `disable-model-invocation` — see step 4's reason token), OR if
`disableWorkflows: true` / `CLAUDE_CODE_DISABLE_WORKFLOWS=1` is set, skip to the
fallback (step 4). **If `claude` is not on PATH inside the Bash tool (possible
under `claude -p`) or the version cannot be parsed, treat the pre-gate as
@ -347,14 +356,18 @@ changes nothing (SC1). Keep the native-swarm anchors intact ("in parallel",
`/deep-research` report actually landed in context — substantive findings with
citations, not an empty/denied/errored turn and not bare error text. This check
must be **robust to all failure manifestations** (workflow disabled, approval
denied, runtime error, empty output), because the disabled-headless behavior is
undocumented: no recognizable cited report in context → fall back, regardless of
how the failure surfaces.
denied, runtime error, empty output, or the Skill tool refusing with
`disable-model-invocation` on CC 2.1.218+), because the disabled-headless
behavior is undocumented: no recognizable cited report in context → fall back,
regardless of how the failure surfaces.
4. **On no real report (fallback):** set `effective_engine = swarm`, run the swarm
blocks below, and **log the fallback at this decision point** — print
`Engine: deep-research → swarm (fallback: <reason>)` and carry the reason into the
Phase-8 Present summary and the brief's `## Executive Summary`. **NEVER fabricate
Phase-8 Present summary and the brief's `## Executive Summary`. Known reason
tokens: `disable-model-invocation` (CC >= 2.1.218 — the expected reason on any
current Claude Code), `version-below-floor`, `workflows-disabled`,
`no-cited-report`. **NEVER fabricate
or synthesize a substitute report** — a structurally-valid-but-invented brief
passes the structure-only validator and silently poisons `/trekplan`; that is the
worst outcome of this feature.

View file

@ -26,7 +26,7 @@ Always interactive. Phase 3 is a section-driven completeness loop (no hard cap o
| `--gates {true\|false}` | (v3.4.0) Boolean autonomy-gate flag; present → gating on. Policy (`gates_mode`) detailed under `## Autonomy mode` in `docs/operations.md`. |
| `--min-brief-version <ver>` | (S18) Warn — never block — if an attached `--project` brief declares a version below `<ver>` (e.g. `2.2`), i.e. sidesteps framing enforcement |
| `--profile <name>` | (v4.1.0) Model profile for the research phase. |
| `--engine {swarm\|deep-research}` | (deep-research-engine) Opt-in external-research engine; `deep-research` delegates the external phase to Claude Code's built-in `/deep-research` workflow (CC 2.1.154+), falls back to `swarm`. Default `swarm`. |
| `--engine {swarm\|deep-research}` | (deep-research-engine) Opt-in external-research engine; `deep-research` delegates the external phase to Claude Code's built-in `/deep-research` workflow, which only works on `2.1.154 <= CC < 2.1.218` — from **2.1.218** `/deep-research` is operator-invoked only (the Skill tool refuses with `disable-model-invocation`), so the engine always falls back to `swarm`. Never hard-fails. Default `swarm`. |
Flags combine: `--project <dir> --local`, `--external --quick`.

View file

@ -1117,6 +1117,57 @@ test('deep-research-engine: --engine is documented + consistent across surfaces'
);
});
test('deep-research-engine: the CC 2.1.218 operator-only ceiling is documented on every surface', () => {
// CC 2.1.218 changed /deep-research to "start only when invoked manually"; from
// there the Skill tool refuses a model invocation outright with
// `disable-model-invocation`. The flag stays (additive opt-in, always degrades to
// swarm), but no surface may keep promising a path Claude Code has removed, and
// none may leave `2.1.154+` standing alone as the engine's requirement.
const SURFACES = ['commands/trekresearch.md', 'docs/command-modes.md', 'README.md'];
for (const f of SURFACES) {
const body = read(f);
assert.ok(
body.includes('2.1.218'),
`${f} must document the CC 2.1.218 ceiling for the deep-research engine`,
);
assert.ok(
body.includes('disable-model-invocation'),
`${f} must name disable-model-invocation as the fallback reason from CC 2.1.218`,
);
}
// The one-line reference rows carry the whole truth on their own line — an
// operator reading the flag table never scrolls to the command prose.
const ROWS = [
['docs/command-modes.md', /^.*`--engine \{swarm\\\|deep-research\}`.*$/m],
['README.md', /^\|\s*\*\*Engine\*\*.*$/m],
];
for (const [f, re] of ROWS) {
const m = read(f).match(re);
assert.ok(m, `${f} must still carry the --engine reference row`);
assert.ok(
m[0].includes('2.1.218') && m[0].includes('disable-model-invocation'),
`${f} --engine row must state the real window (2.1.218 + disable-model-invocation)`,
);
}
// Both load-bearing regions of the command itself: the flag bullet and the
// pre-gate that decides whether the delegation is attempted at all.
const research = read('commands/trekresearch.md');
const bullet = research.match(/8\. `--engine <name>`[\s\S]*?Flags can be combined/);
assert.ok(bullet, 'trekresearch.md must still carry the --engine flag bullet');
assert.ok(
bullet[0].includes('2.1.218') && bullet[0].includes('disable-model-invocation'),
'trekresearch.md --engine bullet must state the real window, not just the 2.1.154 floor',
);
const pregate = research.match(/\*\*Coarse pre-gate[\s\S]*?authoritative guard\./);
assert.ok(pregate, 'trekresearch.md must still carry the deep-research pre-gate');
assert.ok(
pregate[0].includes('2.1.218'),
'the pre-gate must carry an upper ceiling at 2.1.218, not only the 2.1.154 floor',
);
});
// ── STORM bounded loop — env-vars documented across the four surfaces ──────
// Same cross-doc shape as the --engine pin above. An operator-facing switch
// documented on one surface is a switch most operators never find; and the