feat(voyage): S11 — NW2 part B, integrate opt-in --workflow flag
Make the bake-off-validated Workflow substrate (Arm B) reachable behind an opt-in --workflow flag for /trekreview. Default Phase 5-6 path stays prose to preserve the lower portability floor; --workflow raises the consumer floor to Claude Code 2.1.154+ (the Workflow tool). - arg-parser: --workflow added to trekreview boolean flags - commands/trekreview.md: flag row + Phase 5 substrate-routing gate + new section 'Phase 5-6 via the Workflow substrate' (invocation contract, S10 gotchas, bake-off citation, auto/bypass residual as Known limitation) - docs/command-modes.md: --workflow row in /trekreview table - routes to existing scripts/trekreview-armB.workflow.mjs (byte-identical to the S10 part-B POSITIVE build); integration is pure routing, no script change TDD: 8 new tests (arg-parser flag recognition + combine; command/doc prose pins for route, opt-in posture, 2.1.154+ floor, bake-off evidence). Suite 662 -> 670 (668 pass / 2 skip / 0 fail). plugin validate clean modulo known root-CLAUDE.md warning. Resolves W1-narrow-wins-plan.md S11.
This commit is contained in:
parent
f7c8aa45ab
commit
9fb536e2d8
5 changed files with 130 additions and 1 deletions
|
|
@ -52,6 +52,7 @@ FLAG_SCHEMA `trekreview` entry):
|
|||
| `--validate` | boolean | Schema-only check on existing `{project_dir}/review.md`. No LLM calls. |
|
||||
| `--dry-run` | boolean | Print the discovered scope and triage map. Skip writes. |
|
||||
| `--fg` | boolean | No-op alias (foreground is default). |
|
||||
| `--workflow` | boolean | **(opt-in, NW2)** Run Phase 5–6 on the bake-off-validated Workflow substrate (`scripts/trekreview-armB.workflow.mjs`) instead of the default prose Agent-tool path. Requires **Claude Code 2.1.154+**. Combines with `--quick`. See *§ Phase 5–6 via the Workflow substrate*. |
|
||||
|
||||
Resolution:
|
||||
1. If `--project` is missing, print usage and stop:
|
||||
|
|
@ -75,6 +76,13 @@ Set `mode`:
|
|||
- `quick` if `--quick` is set.
|
||||
- `default` otherwise.
|
||||
|
||||
Set `workflow_substrate` (orthogonal to `mode` — a substrate choice, not a behavior mode):
|
||||
- `true` if `--workflow` is set — Phase 5–6 run on the Workflow substrate (see the Phase 5
|
||||
routing gate). The Workflow tool requires **Claude Code 2.1.154+**; if it is unavailable,
|
||||
fall back to the prose path and note the fallback in the Executive Summary.
|
||||
- `false` otherwise. **Default stays prose**: the substrate is opt-in, so the lower
|
||||
portability floor of the prose path is preserved unless the operator opts in.
|
||||
|
||||
## Phase 2 — Validate brief
|
||||
|
||||
Run the brief validator in soft mode — the brief is upstream context, not
|
||||
|
|
@ -181,6 +189,12 @@ If `mode == dry-run`: print the triage map and exit.
|
|||
|
||||
## Phase 5 — Launch parallel reviewers
|
||||
|
||||
**Substrate routing (opt-in `--workflow`).** When `workflow_substrate == true`, run
|
||||
Phases 5–6 via the Workflow substrate documented in *§ Phase 5–6 via the Workflow
|
||||
substrate* (below Phase 6), then resume at Phase 7 with the returned
|
||||
`{verdict, findings}`. When `false` (the default), run the prose Agent-tool path
|
||||
described in the rest of this phase.
|
||||
|
||||
Launch two reviewer agents **in parallel** via the Agent tool — one
|
||||
message, multiple tool calls.
|
||||
|
||||
|
|
@ -240,6 +254,54 @@ The coordinator's output is the full review.md content — frontmatter +
|
|||
body sections + trailing JSON block. Do NOT re-run the reviewers based
|
||||
on the coordinator's output.
|
||||
|
||||
## Phase 5–6 via the Workflow substrate (opt-in `--workflow`)
|
||||
|
||||
Runs **only** when `workflow_substrate == true`. This is the **NW2 port**: it expresses
|
||||
the SAME Phase 5–6 pipeline (parallel reviewers → triplet-dedup → coordinator verdict) as
|
||||
a single Workflow, reusing the NW1 findings schema. The S10 bake-off found it
|
||||
**fidelity-equivalent** to the prose path — see `docs/T2-bakeoff-results.md` (verdict
|
||||
**POSITIVE**: verdict-match 1.0, issue-coverage 100%, `(file,rule_key)` jaccard ≥
|
||||
within-arm, tokens +4.4%). It stays **opt-in**, not the default, because the Workflow tool
|
||||
raises the consumer floor to **Claude Code 2.1.154+** (outward-facing; the prose path
|
||||
keeps the lower floor).
|
||||
|
||||
Invoke the port via the **Workflow** tool with the Phase 1–4 output pinned into `args`:
|
||||
|
||||
```
|
||||
Workflow({
|
||||
scriptPath: "${CLAUDE_PLUGIN_ROOT}/scripts/trekreview-armB.workflow.mjs",
|
||||
args: {
|
||||
briefPath: "{brief_path}",
|
||||
diffPath: "{path to the unified diff file from Phase 3}",
|
||||
triage: "{triage map as 'path → treatment' lines from Phase 4}",
|
||||
quick: {true if mode == quick, else false}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Contract (verified in S10 part B — follow exactly):
|
||||
- **Pass `args` as a JSON object.** The script defensively re-parses a JSON *string*, but
|
||||
the object form is the contract.
|
||||
- **Reviewers are `StructuredOutput`-schema-forced** — `rule_key` is enum-enforced at the
|
||||
tool layer (stronger than the prose path's post-hoc NW1 check), so there is no
|
||||
`JSON.parse`/re-ask dance.
|
||||
- **Recover the result from the `RESULT_JSON:{…}` line** inside the workflow output logs.
|
||||
The script returns `{verdict, findings, ...}` AND logs it as that line; the
|
||||
notification's `<result>` may be truncated, so parse the logged line.
|
||||
- The reviewer/coordinator agentTypes are namespaced inside the script
|
||||
(`voyage:brief-conformance-reviewer`, `voyage:code-correctness-reviewer`,
|
||||
`voyage:review-coordinator`).
|
||||
|
||||
Then continue at **Phase 7** exactly as the prose path does — Phase 7 rendering, Phase 8
|
||||
validation, and the operator gate are **shared** and substrate-independent (both paths
|
||||
return the same `{verdict, findings}` shape).
|
||||
|
||||
**Known limitation (per bake-off §Posture, surfaced not hidden).** Classifier interference
|
||||
was measured **0** at 9-agent concurrency in the session's default permission mode; an
|
||||
explicit `auto`/`bypass`-mode re-run was not performed (the permission mode is operator-set,
|
||||
not settable from within a session). trekreview's small fan-out showed 0 interference in S8
|
||||
and S10. The large fan-out case (the trekplan swarm) is out of NW2 scope.
|
||||
|
||||
## Phase 7 — Write review.md
|
||||
|
||||
Write the coordinator's output verbatim to:
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ If `{project_dir}/architecture/overview.md` exists (typically produced by an opt
|
|||
| `--validate` | Schema-only check on existing `{dir}/review.md`. No LLM calls |
|
||||
| `--dry-run` | Print discovered scope + triage map; skip writes |
|
||||
| `--fg` | No-op alias (foreground is default) |
|
||||
| `--workflow` | (opt-in, NW2) Run Phase 5–6 on the bake-off-validated Workflow substrate (`scripts/trekreview-armB.workflow.mjs`) instead of the default prose path. Default stays prose; requires **Claude Code 2.1.154+** (raises the consumer floor — opt-in for portability). Fidelity-equivalent per `docs/T2-bakeoff-results.md` |
|
||||
| `--profile <name>` | (v4.1.0) Model profile for the review phase. |
|
||||
|
||||
## /trekcontinue modes
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ const FLAG_SCHEMA = {
|
|||
aliases: {},
|
||||
},
|
||||
trekreview: {
|
||||
boolean: ['--quick', '--fg', '--dry-run', '--validate'],
|
||||
boolean: ['--quick', '--fg', '--dry-run', '--validate', '--workflow'],
|
||||
valued: ['--project', '--since', '--profile'],
|
||||
aliases: {},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@ import { parseDocument } from '../../lib/util/frontmatter.mjs';
|
|||
const HERE = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = join(HERE, '..', '..');
|
||||
const COMMAND_FILE = join(ROOT, 'commands', 'trekreview.md');
|
||||
const MODES_DOC = join(ROOT, 'docs', 'command-modes.md');
|
||||
const PHASE = 'review';
|
||||
|
||||
function read() { return readFileSync(COMMAND_FILE, 'utf8'); }
|
||||
function readModes() { return readFileSync(MODES_DOC, 'utf8'); }
|
||||
function readFixture(name) { return readFileSync(join(ROOT, 'tests', 'fixtures', name), 'utf8'); }
|
||||
function frontmatterOf(text) {
|
||||
const doc = parseDocument(text);
|
||||
|
|
@ -72,3 +74,50 @@ test('trekreview — SC7: brief_version 2.1 + no phase_signals + no partial →
|
|||
`sequencing gate must fire; errors=${JSON.stringify(r.errors)}`,
|
||||
);
|
||||
});
|
||||
|
||||
// --- S11 (NW2 part B) — opt-in --workflow substrate routing ---
|
||||
|
||||
test('trekreview — Phase 1 flag table documents the --workflow opt-in flag', () => {
|
||||
const text = read();
|
||||
assert.match(text, /--workflow/,
|
||||
'commands/trekreview.md must document the --workflow opt-in flag (NW2 part B)');
|
||||
});
|
||||
|
||||
test('trekreview — --workflow routes Phase 5–6 to the validated NW2 Workflow port script', () => {
|
||||
const text = read();
|
||||
assert.ok(text.includes('scripts/trekreview-armB.workflow.mjs'),
|
||||
'the --workflow route must reference the bake-off-validated NW2 Workflow port script');
|
||||
});
|
||||
|
||||
test('trekreview — Workflow path is opt-in; default stays prose (portability floor)', () => {
|
||||
const text = read();
|
||||
assert.match(text, /opt-in/i, '--workflow must be described as opt-in');
|
||||
assert.ok(text.includes('Default stays prose'),
|
||||
'the command must state the default Phase 5–6 path stays prose (not Workflow)');
|
||||
});
|
||||
|
||||
test('trekreview — Workflow opt-in documents the Claude Code 2.1.154+ floor', () => {
|
||||
const text = read();
|
||||
assert.match(text, /2\.1\.154/,
|
||||
'the --workflow path raises the consumer floor and must document Claude Code 2.1.154+');
|
||||
});
|
||||
|
||||
test('trekreview — bake-off evidence (fidelity-equivalent / T2 results) is cited for the opt-in', () => {
|
||||
const text = read();
|
||||
assert.ok(
|
||||
text.includes('T2-bakeoff-results.md') && /fidelity-equivalent/i.test(text),
|
||||
'the opt-in must cite the S10 bake-off (docs/T2-bakeoff-results.md) fidelity-equivalence verdict',
|
||||
);
|
||||
});
|
||||
|
||||
test('command-modes.md — /trekreview table documents --workflow + its CC floor', () => {
|
||||
const text = readModes();
|
||||
const start = text.indexOf('## /trekreview modes');
|
||||
assert.ok(start >= 0, 'command-modes.md missing "## /trekreview modes" section');
|
||||
const end = text.indexOf('\n## ', start + 1);
|
||||
const section = text.slice(start, end === -1 ? undefined : end);
|
||||
assert.match(section, /--workflow/,
|
||||
'command-modes.md /trekreview table must list the --workflow opt-in flag');
|
||||
assert.match(section, /2\.1\.154/,
|
||||
'command-modes.md /trekreview --workflow row must note the Claude Code 2.1.154+ floor');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -97,6 +97,23 @@ test('trekreview — unknown flag goes to unknown[]', () => {
|
|||
assert.ok(r.unknown.includes('--mystery'));
|
||||
});
|
||||
|
||||
// --- S11 (NW2 part B) — opt-in --workflow substrate flag ---
|
||||
|
||||
test('trekreview — --workflow boolean flag (NW2 opt-in substrate)', () => {
|
||||
const r = parseArgs('--workflow', 'trekreview');
|
||||
assert.equal(r.flags['--workflow'], true);
|
||||
assert.ok(!r.unknown.includes('--workflow'),
|
||||
'--workflow must be a recognized trekreview flag, not unknown[]');
|
||||
});
|
||||
|
||||
test('trekreview — --workflow combines with --quick + --project', () => {
|
||||
const r = parseArgs('--workflow --quick --project .claude/projects/x', 'trekreview');
|
||||
assert.equal(r.flags['--workflow'], true);
|
||||
assert.equal(r.flags['--quick'], true);
|
||||
assert.equal(r.flags['--project'], '.claude/projects/x');
|
||||
assert.deepEqual(r.unknown, []);
|
||||
});
|
||||
|
||||
test('trekcontinue — empty args produce no flags and no positional', () => {
|
||||
const r = parseArgs('', 'trekcontinue');
|
||||
assert.equal(r.command, 'trekcontinue');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue