ADR-0009: Composite domains — combined multi-component autoresearch
Status: accepted | Date: 2026-06-27
References: ADR-0001, ADR-0002, ADR-0006, ADR-0008, RFC-0002
Context
Every domain so far is single-component: one upstream repo, one judge, one world. That shape cannot express the cross-cut features that matter most in llm-d, where a behavior is split across the router (EPP) and the engine (vLLM) and neither side's gate can see the payoff. Two real examples: (1) LoRA-aware routing — vLLM exposes adapter residency metrics but the EPP cannot distinguish warm from cold adapters, and the win (avoided cold-load TTFT) is only measurable end-to-end across the EPP-vLLM path. (2) P/D rollout protection — during a rolling update the EPP must avoid pairing prefill/decode endpoints with incompatible KV-transfer configs, but vLLM exposes no config hash for filtering. Both share a shape: vLLM exposes a signal, the EPP routes/filters on it, and the fitness is a property of the assembled system. A single-component manifest cannot represent this.
Decision
Introduce composite domains: a domain that composes N component domains into one autoresearch run. A composite reuses the component domains (each an ADR-0008 immutable compose) and adds three things: (1) A multi-workspace world — the agent may edit any component's checkout in a turn; keep/discard and git memory span all components as a tuple of overlay commits. (2) A single combined gate — one measure_cmd that stands up the assembled system and runs the frozen cross-cut workload. (3) The union of component surfaces — both components' tools, skills, and profiler backends available in one run. The engine stays component-agnostic: "combined" is a composite manifest plus a combined gate command, not per-feature code. Run identity extends to a vector of per-component (digest, overlay) tuples plus a cross-cut workload hash.
Consequences
Positive: the cross-cut feature class becomes optimizable at all; the win is measured where it actually exists (end-to-end); the engine gains one general capability (multi-workspace runs) rather than per-feature code; component packs are reused verbatim. Negative/cost: the heaviest rig to stand up and keep reversible; multi-workspace git memory + tuple run-identity is new engine work; the combined gate is bespoke per cross-cut feature (authoring, not engine); a re-compose of any component retires the composite's cross-run memory epoch. Composites are opt-in for exactly these costs. Validates the component-agnostic discipline (generic broker, name-prefixed tools, measure_cmd as the sole contract). RFC-0002 carves out the unscored case: a composite whose workflow type is "playbook" carries no combined gate and produces no combined score, because it composes work rather than fitness. The combined-gate requirement above governs a composite that is optimizing something, which is every composite this ADR was written for.
Alternatives Considered
Introduce composite domains: a domain that composes N component domains into one autoresearch run with a multi-workspace world, single combined gate, and union of component surfaces (accepted)
- Pros: Cross-cut feature class becomes optimizable — measured where the win actually exists (end-to-end), Engine gains one general capability (multi-workspace runs) rather than per-feature code, Component packs are reused verbatim; a composite is mostly a manifest + a combined gate
- Cons: Heaviest rig to stand up and keep reversible (GPU P/D + EPP + rollout/mix harness), Multi-workspace git memory + tuple run-identity is new engine work
Vendor EPP into vLLM (or vice versa) to create a merged single-repo domain (rejected)
- Rejected because: Each stays its own upstream repo with its own toolchain (Go vs CUDA/Python) and compose; the kept patch must upstream to its repo as a normal PR. A composite is an assembly of frozen worlds, not a third repo.