voyage/tests/fixtures/synthesis/exploration/architecture-mapper.md
Kjell Tore Guttormsen 6b30483304 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
2026-06-18 17:58:39 +02:00

4.7 KiB

Architecture Report — output of architecture-mapper

Task being planned: Add a per-wave concurrency cap to trekexecute headless launches.

Summary

Voyage is a contract-driven Claude Code plugin (Node ESM, zero runtime deps). The pipeline is six commands (commands/*.md) backed by a lib/ of pure, unit-tested validators/parsers and a thin scripts/ layer of measurement and codegen harnesses. trekexecute is the disciplined plan/session-spec executor; its headless path (Phase 2.6) fans out parallel "waves" of claude -p subprocesses driven by a Bash launcher template.

Tech stack

Layer Choice Evidence
Language JavaScript (ESM, .mjs) lib/**/*.mjs, "type":"module" in package.json
Tests node:test + node:assert/strict every tests/**/*.test.mjs
Validation hand-rolled validators returning {valid,errors,warnings} lib/util/result.mjs
Orchestration substrate command prose + Bash + Agent/Task tool commands/trekexecute.md
Headless launch Bash here-doc template, backgrounded subprocesses templates/headless-launch-template.md

Key patterns

  • 3-layer module pattern — Content validator → raw-text wrapper → CLI shim (if (import.meta.url === \file://${process.argv[1]}`)), repeated across lib/validators, lib/parsers, lib/review`. Any new lib must follow it.
  • Structured Result typeissue(code,message,hint,location) + fail() / ok() from lib/util/result.mjs. Stable error codes are the contract.
  • Prose-as-orchestrator — commands carry the control flow in markdown; the harness executes it. Schema-drift defenses are inlined into command prose so they survive even when agent docs are not implicitly loaded.

Anti-patterns / debt near the task

  • The headless launcher backgrounds all wave members at once with no upper bound on concurrent claude -p processes; concurrency is implicit in how many steps a wave contains. No central place caps it.
  • Wave composition (which steps go in which wave) is computed by session-decomposer, but the launch fan-out is template Bash, so a cap would straddle a JS (decomposer) / Bash (launcher) boundary.

Module map (task-relevant)

commands/trekexecute.md         # Phase 2.6 parallel-wave orchestration prose
templates/headless-launch-template.md  # the Bash fan-out site
lib/util/result.mjs             # error shape any new guard returns
agents/session-decomposer.md    # produces the wave/dependency graph

Boundaries

The cap is a launch-time concern (Bash template + the Phase 2.6 prose that generates it). It does not belong in the pure lib/ validators unless we add a small "max parallelism" resolver that the prose reads. Recommend a lib resolver (testable) + a template wire-in (the actual xargs -P / job-slot mechanism).

How Phase 2.6 assembles a wave (detail)

The executor reads the plan's ## Step N blocks and the dependency edges session-decomposer emitted (depends_on: frontmatter). Steps with no unmet dependency at the current frontier form a wave. For each wave the prose:

  1. builds a SHARED_CONTEXT_FILE (brief + plan + relevant exploration digest) passed to every member via --append-system-prompt-file (cache-prefix material — see q3 experiment);
  2. emits one claude -p … & invocation per member from the here-doc, each with --max-turns, --max-budget-usd, GIT_OPTIONAL_LOCKS=0, and the GH#36071 push-before-cleanup workaround;
  3. collects the backgrounded PIDs and waits for the batch to drain before advancing the frontier.

The cap belongs strictly between (2) and (3): bound how many of the emitted members run concurrently, leaving wave composition (1) untouched.

Layering verdict

Three layers, in increasing blast radius: (a) a pure resolver in lib/ (arithmetic only — trivially testable, follows the 3-layer module pattern); (b) Phase 2.6 prose passing the resolved integer + a --max-parallel flag into the template; (c) the template's fan-out mechanism. Keep (a) the single source of the number; (c) should only consume it. This matches every prior launcher hardening, which added one bounded externality (budget, locks, turns) at a time without reshaping wave composition.

Cross-cutting observations

  • The launcher is the most operationally sensitive file in the repo (it spends money and mutates git). Every edit here is co-reviewed with its doc-consistency needle list — treat the needle test as part of the contract, not an afterthought.
  • Nothing in lib/ currently imports anything launcher-related; the resolver will be a leaf module. Good — it can be tested and shipped independently of the template wire-in, enabling a TDD-first slice.