docs(trekresearch): document STORM mechanisms across four surfaces
This commit is contained in:
parent
b194630842
commit
9c91211fc0
5 changed files with 104 additions and 0 deletions
13
CLAUDE.md
13
CLAUDE.md
|
|
@ -24,6 +24,19 @@ Voyage — a contract-driven Claude Code pipeline: brief, research, plan, execut
|
|||
|
||||
Full flag reference for each command (modes, `--gates`, `--profile`, breaking changes): see `docs/command-modes.md`.
|
||||
|
||||
> **STORM bounded loop — default-off, env-gated.** `/trekresearch` Phase 4.5
|
||||
> (dimension discovery, under the existing `maxDimensions: 8` ceiling) and
|
||||
> Phase 5 (bounded multi-turn follow-up) run only at `effort: high` **and** only
|
||||
> when `VOYAGE_STORM_ENABLED=1`; unset, `lib/util/research-loop-cap.mjs` grants
|
||||
> a budget of 0 and both are inert. `TREKRESEARCH_MAX_CONV_TURNS` (default `3`,
|
||||
> invalid values fall back to `3`) sets turns per dimension; the budget is that
|
||||
> × `maxDimensions`. `VOYAGE_DISABLE_CAP_HOOK=1` switches off
|
||||
> `hooks/scripts/pre-agent-cap.mjs`, the `PreToolUse` gate that enforces the
|
||||
> budget in the harness rather than trusting prose. The cap counts turns from
|
||||
> its own append-only ledger. Adoption as a default is gated on the
|
||||
> pre-registered measurement in `docs/storm-measurement.md` — decline is a
|
||||
> no-op, adopt is one constant.
|
||||
|
||||
## Agents
|
||||
|
||||
| Agent | Model | Role |
|
||||
|
|
|
|||
18
README.md
18
README.md
|
|
@ -216,6 +216,24 @@ Output:
|
|||
|
||||
Flags combine: `--project <dir> --external`.
|
||||
|
||||
#### Bounded conversation loop (default-off)
|
||||
|
||||
At `effort: high`, research can discover additional dimensions (Phase 4.5) and
|
||||
run a bounded multi-turn follow-up loop on under-illuminated ones (Phase 5).
|
||||
Both are **default-off** and env-gated rather than flag-gated, because enabling
|
||||
them costs turns:
|
||||
|
||||
| Env-var | Default | Behavior |
|
||||
|---------|---------|----------|
|
||||
| `VOYAGE_STORM_ENABLED` | _(unset — default-off)_ | `=1` gives the loop a non-zero turn budget. Unset, the budget is 0 and the loop is inert. |
|
||||
| `TREKRESEARCH_MAX_CONV_TURNS` | `3` | Turns per under-illuminated dimension. Invalid values fall back to `3`, never to unbounded. |
|
||||
| `VOYAGE_DISABLE_CAP_HOOK` | _(unset)_ | `=1` disables the `PreToolUse` hook that enforces the turn budget. |
|
||||
|
||||
The cap counts turns itself from an append-only ledger — it never asks the loop
|
||||
how many turns it has used. Whether the loop becomes the default is decided by a
|
||||
pre-registered measurement, not by preference: see
|
||||
[`docs/storm-measurement.md`](docs/storm-measurement.md).
|
||||
|
||||
Research uses up to 5 local agents (architecture-mapper, dependency-tracer, task-finder, git-historian, convention-scanner) and 4 external agents (docs-researcher, community-researcher, security-researcher, contrarian-researcher) plus the optional Gemini bridge for an independent second opinion. Per-agent details in [`agents/`](agents/).
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ Imported from `CLAUDE.md` via pointer.
|
|||
- `lib/stats/event-emit.mjs` — single-source stats event emitter for autonomy-gate transitions and main-merge-gate (v3.4.0)
|
||||
- `lib/validators/{brief,research,plan,progress,session-state}-validator.mjs` — schema validators with CLI shims (`node lib/validators/X.mjs --json <path>`)
|
||||
- `lib/validators/architecture-discovery.mjs` — drift-WARN external-contract discovery for `architecture/overview.md`
|
||||
- `lib/util/research-loop-cap.mjs` — stateful, **default-off** turn budget for the `/trekresearch` bounded conversation loop. `allowTurn()` derives the used-turn count from its own append-only JSONL ledger; it never asks the caller how many turns it has spent, because a cap that does is not a cap. Budget = `TREKRESEARCH_MAX_CONV_TURNS` (default `3`, invalid values fall back to `3`) × `maxDimensions` (8, `settings.json:16`). Grants 0 unless `VOYAGE_STORM_ENABLED=1`; missing `CLAUDE_PLUGIN_DATA` denies (fail-closed — the opposite of `event-emit.mjs`, which is telemetry and must never block). CLI shim: `node lib/util/research-loop-cap.mjs --run-id ID --dimension D --effort E`
|
||||
- `lib/validators/query-privacy-gate.mjs` — gates **every** outbound research query before it leaves the machine; the hard-block tier (secret-shaped strings) is not operator-overridable, so a query that trips it must be reformulated rather than forced through. CLI shim: `node lib/validators/query-privacy-gate.mjs "<query>"`
|
||||
|
||||
Wiring points (replaces previous prose-grep instructions):
|
||||
- `/trekbrief` Phase 4g → `brief-validator` (post-write sanity check)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,22 @@ Always interactive. Phase 3 is a section-driven completeness loop (no hard cap o
|
|||
|
||||
Flags combine: `--project <dir> --local`, `--external --quick`.
|
||||
|
||||
### Bounded conversation loop (Phase 4.5 + Phase 5) — env-vars
|
||||
|
||||
Dimension discovery and the multi-turn follow-up loop are **default-off** and
|
||||
have no flag; they are environment-gated, because turning them on costs turns.
|
||||
They run only at `effort: high` (resolved from the brief's `phase_signals`).
|
||||
|
||||
| Env-var | Default | Behavior |
|
||||
|---------|---------|----------|
|
||||
| `VOYAGE_STORM_ENABLED` | _(unset — default-off)_ | `=1` grants the loop a non-zero turn budget. Unset, `research-loop-cap.mjs` grants 0 turns and the loop is inert: doing nothing keeps the mechanism off. |
|
||||
| `TREKRESEARCH_MAX_CONV_TURNS` | `3` | Max turns per under-illuminated dimension. Budget = this × `maxDimensions` (8, `settings.json:16`). Empty, non-numeric, zero, or negative values fall back to `3` — never to unbounded. |
|
||||
| `VOYAGE_DISABLE_CAP_HOOK` | _(unset)_ | `=1` disables `hooks/scripts/pre-agent-cap.mjs`, the `PreToolUse` enforcement of the turn budget. The cap primitive still applies; only the second gate is switched off. |
|
||||
|
||||
Adoption of the loop as a default is gated on a pre-registered measurement —
|
||||
protocol, thresholds, and the exact commands in
|
||||
[`docs/storm-measurement.md`](storm-measurement.md).
|
||||
|
||||
## /trekplan modes
|
||||
|
||||
| Flag | Behavior |
|
||||
|
|
|
|||
|
|
@ -1117,6 +1117,61 @@ test('deep-research-engine: --engine is documented + consistent across surfaces'
|
|||
);
|
||||
});
|
||||
|
||||
// ── 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
|
||||
// three below decide cost, so they are the ones worth pinning.
|
||||
|
||||
const STORM_SURFACES = ['docs/command-modes.md', 'CLAUDE.md', 'README.md', 'docs/architecture.md'];
|
||||
const STORM_ENV_VARS = ['VOYAGE_STORM_ENABLED', 'TREKRESEARCH_MAX_CONV_TURNS', 'VOYAGE_DISABLE_CAP_HOOK'];
|
||||
|
||||
for (const envVar of STORM_ENV_VARS) {
|
||||
test(`STORM: ${envVar} is documented on all four reference surfaces`, () => {
|
||||
for (const f of STORM_SURFACES) {
|
||||
assert.ok(read(f).includes(envVar), `${f} must document ${envVar} (STORM bounded-loop env-vars)`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
test('STORM: VOYAGE_STORM_ENABLED is documented WITH its default-off contract', () => {
|
||||
// Naming a switch without its default is how a default-on mechanism ships by
|
||||
// accident. Default-off is also the decline branch: declining costs nothing.
|
||||
for (const f of STORM_SURFACES) {
|
||||
const t = read(f);
|
||||
const i = t.indexOf('VOYAGE_STORM_ENABLED');
|
||||
const window = t.slice(Math.max(0, i - 400), i + 400);
|
||||
assert.match(
|
||||
window,
|
||||
/default-off|default off|opt-in/i,
|
||||
`${f}: VOYAGE_STORM_ENABLED must be documented together with its default-off contract`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('STORM: README research-dimension prose stays at the existing 3–8 ceiling', () => {
|
||||
// Phase 4.5 discovers dimensions UNDER settings.json:16's maxDimensions: 8.
|
||||
// Rewriting this prose upward would raise a ceiling the brief asked us to hold.
|
||||
assert.ok(
|
||||
read('README.md').includes('3–8 research dimensions'),
|
||||
'README.md must keep the "3–8 research dimensions" prose — augmentation happens under the existing cap, it does not raise it',
|
||||
);
|
||||
});
|
||||
|
||||
test('STORM: no banned Sonnet-swarm phrase introduced on any STORM surface', () => {
|
||||
const BANNED = [
|
||||
'Sonnet exploration',
|
||||
'Sonnet runs the exploration',
|
||||
'front-loads cheap Sonnet',
|
||||
'exploration agents stay on Sonnet',
|
||||
];
|
||||
for (const f of STORM_SURFACES) {
|
||||
const t = read(f);
|
||||
for (const phrase of BANNED) {
|
||||
assert.ok(!t.includes(phrase), `${f} must not claim "${phrase}" — sub-agents are opus-pinned`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('S18: HANDOVER-CONTRACTS documents the pre-2.2 zero-framing-enforcement hole', () => {
|
||||
// The framing defense is producer-elective: a brief declaring ≤ 2.1 sidesteps
|
||||
// it entirely. Handover 1 (PUBLIC CONTRACT) must disclose this and name the remedy.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue