# Root-cause assessment — the four questions, answered from evidence

**Date:** 2026-09-06 · **Basis:** the 31 Aug–4 Sep weekly readout (67
crossovers, 21 trades, −₹1,875 gross), the 3–4 Sep session detail, the
2026-09-02 win/loss analysis, and repo verification performed today
(git history + policy/filter source at HEAD).
**Author:** Claude. Analysis only; nothing here changes code.

---

## Finding 1 — A REAL deviation from design existed, is dated, and is fixed

**From 10 Aug to 1 Sep 22:44, the production strategy traded with
regime_ci, m4_exhaustion and signal_quality silently switched off.**

Verified in git today:

- Scope-before-check enforcement (`applies_to` honoured before a filter
  runs) entered `v2/signal_engine/engine.py` on **2026-08-10 18:30**
  (commit 02045dd).
- The filters' manifests then named only `"ema_crossover"`, while the
  production strategy declares `"ema_crossover_v2"` — so the enforcement
  correctly skipped them for every production signal.
- `"ema_crossover_v2"` was added to the manifests on **2026-09-01 22:44**
  (commit 3123c8c — labelled "spike_exit - fixed", it carried more).

This is exactly the defect m4_exhaustion.py's own comment (lines 52–62)
describes as "would have become a live defect" — it WAS live for three
weeks. The weekly table shows its fingerprint plainly: all ten 1 Sep trade
plans carry only `trading_window`; 1 Sep is the only day with ZERO
`regime_choppy_veto` refusals despite whipsaw entries two minutes apart
(12:02 / 12:04); from 2 Sep every plan carries all four verdicts and the
vetoes reappear. 1 Sep was the worst day of the window (−₹975, 10 trades,
also 0-DTE). The unfiltered chain didn't cause every loss, but the
regime veto that blocked seven choppy signals on 3 Sep never got the
chance to block the 1 Sep whipsaws.

**Status: fixed 1 Sep 22:44. The `task_filter_scope_audit` prompt's pin
test exists to make this class of silent skip impossible to repeat —
that prompt is now justified by a measured loss, not just principle.**

---

## Finding 2 — The exit design contains a mathematical contradiction

The plan promises R:R **6.07 : 1** (`runner_target_atr_mult 7.59 ÷
option_stop_atr_mult 1.25`). The trail activates at **+1.0 R** and follows
at **1.0 R behind peak** (verified in trailing_stop_v3.py: both multiples
1.0, activation inclusive).

Consequences, by arithmetic alone — no measurement needed:

1. To reach the target, price must travel **6.07 R without ever retracing
   1 R from its peak**. On 1-minute option premiums that event is nearly
   nonexistent. Result: **0 targets in 21 trades**; `target_exit.v1` is
   dead code under this configuration.
2. A trade that arms the trail at +1.0 R gets its stop moved to
   peak − 1.0 R ≈ **entry**. Realized outcome ≈ MFE − 1 R. Peaks of
   +1.0–1.3 R therefore bank ≈ ₹0 (positions 20, 22, 24, 9, 17: ₹0.00,
   +₹6.50, +₹52.00, +₹3.25, +₹32.50). To bank even +1 R the peak must
   exceed +2 R.
3. So the book's payoff ratio is structurally capped near ~1.3 : 1
   (observed: 1.27), which makes the break-even win rate ~44% — against a
   measured 33% from an entry with no demonstrated pre-entry edge.

**The system is not violating its design here. The design promises a
runner (6 R target) while operating a scalper's trail (1 R). Those two
choices cannot coexist.** Either the target comes down to where moves
actually die, or the trail loosens/partials to let a runner breathe.
WHICH — and the numbers — must come from the MFE/MAE distribution
(Phase 0a), not from a guess. This becomes its own one-variable campaign
after F-7 data accumulates.

---

## Finding 3 — The four questions, answered directly

**Q1 — why do near-profits become losses?** Two distinct populations.
(a) Trades that reached +1 R did NOT become losses — the trail held them
at ≈ breakeven (Finding 2.2). Working as specified; the specification
caps them at ~₹0. (b) Trades that peaked BETWEEN 0 and +1 R have **no
protection mechanism at all** — nothing in the policy registry acts below
+1 R MFE, so a +0.8 R excursion rides all the way back to −1 R. How many
trades die in that unprotected zone, and how wide it effectively is, is
precisely what the still-NULL mfe_pct/mae_pct columns would show. This is
why Phase 0a is first.

**Q2 — why so few tradable signals?** The engine generates them fine (67
detected). The refusals are, case by case, mostly CORRECT: the 31 Aug
blank was the old premium_pct stop model (fixed 1 Sep, reason extinct
since); the choppy vetoes are doing their job — the ONE trade admitted on
3 Sep, with the day's best credentials (CI 42.7 trending, quality 96,
conf 61), still lost ₹383 in 3.5 minutes, which vindicates the other
seven vetoes; late recovered bars are untradable BY DESIGN and should
stay so. The real availability losses are: **broker rate-limit blindness
(23–28% of cycles every day but one)** — external, mitigated for
measurement, untradable by design; and **operational gaps** (4 Sep's
first 1h52m never scanned on 1m because a 5m session occupied the
morning). Fewer signals is not the disease; the disease is that the
admitted ones carry no edge.

**Q3 — why doesn't the manager capture small profits?** Because **no
policy has that job.** The registry's nine policies: hard stop (loss),
target (unreachable, Finding 2), trail + break-even (both act at ~+1 R),
partial exit (never fires below its own activation), spike/session/
volatility (other duties). Below +1 R MFE the design says "give the trade
room". The manager is executing its specification faithfully — every
promotion in the log is monotonic, spike_exit.v3 fixed the v2 backstop
defect (4 spike exits on 1 Sep, zero after). Whether a small-profit
mechanism SHOULD exist (partial at +0.5 R, lower activation, tighter
trail) is a design change whose numbers come from the MFE distribution —
and it trades directly against Finding 2's runner question: you cannot
decide the small-profit rule and the runner rule separately; they are the
same exit-geometry decision.

**Q4 — why is the system not behaving per its designed logic?** Since
2 Sep 22:44, **it is** — verified at every layer the logs can reach:
correct refusal reasons, monotonic promotions, tolerance-honest exits,
policies firing per manifest. The two real answers are: (1) for three
weeks before that, it truly wasn't (Finding 1 — now fixed); (2) the
designed logic itself is contradictory at the exit layer (Finding 2) and
edge-free at the entry layer (the 2026-09-02 analysis, unchanged: gross
≈ ₹25/trade vs cost ≈ ₹108). The system was not built to take
unnecessary losses — it was built to execute, faithfully, a strategy
whose entries don't yet pay and whose exit promise its own trail revokes.

---

## Finding 4 — the window proves nothing about the levers (config churn)

Inside five sessions: threshold 60→40→45→40, stop model premium_pct→
atr_derived, expiry floor added, spike_exit v2→v3, filter chain silently
off→on. Five variables moved; nothing in this window can be attributed
to any one of them. This is the 09-01 lesson at week scale.
**Config freeze from here: no threshold, multiplier, or policy changes
except through the numbered prompts, one per measured block.**

---

## What changes (and what deliberately does not)

1. **Sequence unchanged, urgency raised: Phase 0a (MFE/MAE) first.** Q1
   and Q3 are literally unanswerable without it, and telemetry's
   capture_efficiency (captured ÷ MFE) is already defined in the repo
   waiting for the data.
2. **Filter-scope audit second** — its pin test now has a measured
   justification: ₹975 of 1 Sep loss under silently-skipped filters.
3. **Premium floor (0b), gate honesty (0c), scale fix (0d)** as sequenced.
4. **NEW, after 0a has ~2 weeks of excursion data: the exit-geometry
   coherence campaign** — one decision (scalp-coherent target ~p70 of MFE,
   or runner-coherent trail), numbers from the measured distribution,
   spec-amended, one variable. Not before the data exists.
5. **Phase 1 (context study)** unchanged — the entry edge remains the
   deepest problem: 12 untrailed trades −₹2,661 vs 9 trailed +₹786.
6. **Config freeze** (Finding 4) effective immediately.

The quality gate observation (4 Sep: the four `quality_below_gate`
entries netted −₹481, the one gate-passer +₹52) is noted and NOT acted
on: across the whole week gate-passers were also net negative (−₹165 on
n=5). It goes into the Phase 1 study as candidate C6 — the collector's
own score as a context feature — where n can be hundreds.
