feat(voyage): S12 — NW3 synthesis-agent built + measured → declined per measurement [skip-docs]

NW3 (CC-26 §6 PoC): delegate trekplan Phase 7 synthesis to a synthesis-agent,
adopt only if Δ main-context ≥30% with no quality loss. Operator chose the
deterministic-proof path (live ≥3-run bake-off was env-blocked: no API key;
installed plugin is a cache copy so a new agent is invisible to `claude -p`).

Decisive structural finding: trekplan Phase 5 runs the swarm FOREGROUND, so its
outputs are already resident in main before Phase 7. Delegating only Phase 7
evicts nothing → Δ_faithful = 0% (BASE-independent). The ≥30% saving needs an
out-of-scope Phase-5 redesign (swarm-writes-to-disk / nested orchestrator).
VERDICT: DECLINED per measurement.

- agents/synthesis-agent.md — dormant, schema-conformant deliverable (NOT wired)
- lib/plan/synthesis-digest-schema.mjs — digest output contract (+ tests)
- scripts/synthesis-measure.mjs — deterministic Δ-accounting core (+ tests)
- tests/fixtures/synthesis/ — 7 exploration outputs + representative digest
- docs/T1-synthesis-poc-results.md — measurement + verdict (reproducible)
- CLAUDE.md — agent table row (doc-consistency: 24 agents)

Tests 670 → 695 (693 pass / 2 skip / 0 fail). `claude plugin validate` clean
(only the pre-existing root-CLAUDE.md warning). commands/trekplan.md untouched.

[skip-docs] rationale: no user-facing feature ships (NW3 declined; agent dormant
and unwired). The substantive doc is docs/T1-synthesis-poc-results.md; the
README/CHANGELOG roll-up for NW1–NW3 is the S13 coordinated release per
docs/W1-narrow-wins-plan.md §S13.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
This commit is contained in:
Kjell Tore Guttormsen 2026-06-18 17:58:39 +02:00
commit 6b30483304
15 changed files with 1312 additions and 0 deletions

View file

@ -0,0 +1,76 @@
# Dependency & Data-Flow Report — output of dependency-tracer
Task: Add a per-wave concurrency cap to trekexecute headless launches.
## Import / call chain relevant to the task
```
commands/trekexecute.md (Phase 2.6 prose)
└─ generates → templates/headless-launch-template.md (Bash here-doc)
├─ reads SHARED_CONTEXT_FILE (append-system-prompt-file)
├─ spawns claude -p ×N (one per wave member, backgrounded with &)
└─ waits via `wait` on collected PIDs
└─ consumes → .session-state.local.json (Handover 7; session graph)
```
## Data flow
1. session-decomposer emits a plan with wave groupings + a dependency graph.
2. trekexecute Phase 2.6 turns each independent wave into a launch batch.
3. The template loops over batch members and backgrounds each `claude -p`,
collecting PIDs into a Bash array, then `wait`s for the whole batch.
4. There is **no slot-limiting** between "background member" and "wait" — the
degree of parallelism equals the batch size.
## Side effects
- Each subprocess does `git` work under `GIT_OPTIONAL_LOCKS=0`; high concurrency
raises the chance of index-lock contention (mitigated, not eliminated).
- `--max-budget-usd` is per-subprocess; total spend scales with batch size, so a
concurrency cap also indirectly bounds burst spend.
## What a cap touches
- **Pure-addable:** a `maxParallel` resolver in `lib/` (reads plan/profile/flag,
returns an integer ≥ 1). No existing module imports would change.
- **Wire-in:** the template's loop must consume slots (e.g. a counting semaphore
in Bash, or `xargs -P <n>`). This is the only behavioral edit.
## No hidden dependents
Grepped for other call sites of the launch template — only trekexecute Phase 2.6
and the headless-launch-template test reference it. A cap is local in blast
radius.
## Resolver input provenance (what the cap reads)
The resolved integer must be derived from, in lookup order:
1. **CLI flag** `--max-parallel <n>` — parsed by `lib/parsers/arg-parser.mjs`;
highest precedence (operator override).
2. **Brief signal** — `phase_signals` already carries per-phase orchestration
shape; a `max_parallel` hint here is honoured if no flag.
3. **Profile** — `lib/profiles/` resolves `--profile economy|balanced|premium`;
each profile can carry a `max_parallel` default. This is the same lookup
order `phase_models` uses, so the resolver should *reuse* profile-resolver,
not re-implement precedence.
4. **Hard default** — `batchSize` (i.e. no cap / current behavior), so the change
is a strict no-op until someone opts in.
## Downstream of the cap
- **Budget:** total burst spend = `min(cap, batchSize) × per-member --max-budget-usd`.
A cap therefore tightens the worst-case spend envelope — worth noting in the
plan's risk/observability section.
- **Git contention:** fewer concurrent `git`-touching subprocesses → fewer
`index.lock` races. `GIT_OPTIONAL_LOCKS=0` reduces lock acquisition but does
not serialize ref updates; the cap is the structural mitigation.
- **Classifier exposure:** a smaller concurrent fan-out under `auto`/`bypass`
lowers the surface the proliferation classifier (S7 F4) scrutinises.
## Data-flow invariant to preserve
`SHARED_CONTEXT_FILE` is built once per wave and read by every member; the cap
must not cause it to be rebuilt per-slot (would defeat the cache prefix). Slot
limiting happens at spawn time only; the context file is wave-scoped, not
slot-scoped.