# Cycle γ D1 — query-decomposition results: INSUFFICIENT → iterative pivot

**Date**: 2026-06-10 (same session as Phase C.2)
**Status**: D1 (static query decomposition) **closed as INSUFFICIENT**
(honest negative). Pre-registration §3 verdict reached without post-hoc
fit. Root cause identified (hop-2 anaphora). Next = iterative retrieval.

---

## 1. Headline

Phase C.2 proved single-shot dense retrieval misses the 2nd hop. D1
added **query decomposition** (LLM splits the multi-hop question into
sub-questions, each becomes an extra retrieval path). Pre-registered
(`docs/research/cycle-gamma-d1-query-decomposition-preregistration-2026-06-10.md`,
commit hash before implementation = post-hoc-fit barred).

**Result: D1 does not lift multi-hop retrieval.** The decomposer fires
correctly (25/25 queries, 59 sub-question paths added) but the hop-2
sub-question is an **anaphora** ("Who is the spouse of *that person*?")
that cannot retrieve the hop-2 supporting paragraph.

| Metric (mxtral n=25) | R0 single-shot | D1 decomposed | Δ | §3 threshold |
|---|---|---|---|---|
| **gold-in-answer** | 8% (2/25) | 12% (3/25) | +1 (noise) | <15% → INSUFFICIENT |
| **supporting recall** | 0.600 | 0.600 | **flat** | ≤0.65 → INSUFFICIENT |
| both-supporting caught | 5/25 | 5/25 | 0 | |
| abstain | 19/25 | 20/25 | +1 | |
| f1 (confounded) | 0.060 | 0.048 | −0.012 | not verdict-bearing |

Pre-registration §3 verdict: **D1 INSUFFICIENT → iterative retrieval
pivot** (gold-in-answer < 15% AND supporting recall flat).

---

## 2. Why it failed — hop-2 anaphora

The decomposer output is correct *as decomposition* but useless *as
retrieval queries* for the 2nd hop:

```
"Who is the spouse of the Green performer?"
 → hop1: "Who is referred to as the Green performer?"   ← retrievable
 → hop2: "Who is the spouse of that person?"            ← "that person" = dead query

"Who is the founder of the company that distributed UHF?"
 → hop1: "Who distributed the film UHF?"                ← retrievable
 → hop2/3: "...of that company?"                        ← "that company" = dead query
```

Static decomposition splits **before** hop1 is answered, so every 2nd+
hop carries an unresolved pronoun. The hop-1 sub-question helps (it is
query-similar to hop-1 supporting), but the hop-2 sub-question retrieves
noise, and the final answer does not improve. This is **exactly** the
failure mode the pre-registration anticipated (§3 "supporting recall
flat → iterative pivot").

Wiring was verified live (`_d1_run.log`: 25 `[D1] decomposed` lines, 59
`[ORCH] subq` paths) — this is a genuine mechanism limit, not a bug.

---

## 3. What's preserved + what's next

### Preserved infrastructure (reused by iterative)
- `core/retrieval/query_decomposer.py` — LLM decompose, env-gate,
  `[]`-on-failure no-op.
- `core/orchestrator.py` `extra_queries` param — multi-path merge for
  sub-questions (`None`/`[]` byte-identical).
- `core/reasoning/pipeline_loops.py` STEP 0.5c wiring +
  `JAMES_ENABLE_QUERY_DECOMP` gate (**default OFF byte-identical**,
  verified).

All default-OFF; production behaviour unchanged. This is negative
evidence, permanently recorded (cf. D2 V2 / PR #746 pattern).

### Next = iterative retrieval (separate pre-registration)
The fix for hop-2 anaphora is to **resolve the pronoun before
retrieving hop-2**:

```
round 1: retrieve hop-1 sub-q → synth/extract hop-1 answer ("Steve Hillage")
round 2: substitute "that person" → "Steve Hillage" in hop-2 sub-q
         → retrieve hop-2 supporting → union → final synth
```

This is the textbook iterative-RAG / self-ask / IRCoT pattern (prior
art — JAMES contribution = reproducible measurement on its own stack,
⭐⭐ ceiling, not mechanism novelty). Pre-register again:
- Primary axis: gold-in-answer (target: lift R0's 8% toward oracle 72%)
- Secondary: supporting recall (does round-2 land hop-2 supporting?)
- Cost axis: 2 retrieval rounds + 1 extra synth/extract call — must be
  weighed before any default flip.

Build note: the decomposer already produces ordered sub-questions; the
new piece is (a) an intermediate extract step after round-1 retrieve,
(b) pronoun/entity substitution into later sub-questions, (c) a 2nd
retrieve round. The query-rewrite layer
(`core/reasoning/pipeline_query_expansion.py`) is the natural host.

---

## 4. Artifacts

| Purpose | Path |
|---|---|
| Pre-registration (LOCKED before impl) | `docs/research/cycle-gamma-d1-query-decomposition-preregistration-2026-06-10.md` |
| Decomposer | `core/retrieval/query_decomposer.py` |
| Orchestrator extra_queries | `core/orchestrator.py` |
| Wiring + gate | `core/reasoning/pipeline_loops.py` |
| Result JSONs | `reports/cycle_gamma/phase-c2/musique-ans-mxtral-{R0,D1}.json` |
| Phase C.2 handover (retrieval bottleneck) | `docs/handovers/v0.4-cycle-gamma-phase-c2-musique-retrieval-bottleneck-2026-06-10.md` |

### Carry-forward
- `feedback_oracle_phrase_artifacts` 4-step rule caught the "is this a
  wiring no-op or a real negative?" question — log inspection confirmed
  decompose fired, so the negative is genuine.
- Honest framing held: D1 reported as INSUFFICIENT (not spun as "+4pp
  improvement"). The +1 query is inside the noise band.
- env-gate default-OFF discipline: no flip without multi-axis + cost.
