# E019 — Collateral Form / Opponent-Graph Information: results **Request:** [racing5-additional-experiments-3.md](racing5-additional-experiments-3.md) · **Plan:** [racing5-additional-experiments-3_plan.md](racing5-additional-experiments-3_plan.md) · **Registered as [EXP-0029](artifacts/experiments/EXP-0029/report.md) (Stage 1) + [EXP-0030](artifacts/experiments/EXP-0030/report.md) (Stage 2)** (registry N 28 → 30) ## What was done **Recon.** Collateral form had never been tested anywhere in the project (zero hits across results.md and all EXP reports), and the original plan's E007 spec had actually *specified* a "Bradley-Terry horse rating as collateral-form feature" ([racing5-plan.md:89](racing5-plan.md#L89)) that was silently dropped during implementation. The margin data existed unused: `mLengthsBehind` is 100% non-NULL on every finalised runner row 2009–2026, selected by the orphaned `SqlText.ResultsHistoryChronological` constant, and absent from the Parquet snapshots ([FormFold.cs](src/Racing5.Features/FormFold.cs) hardcoded `null`). **Plan.** Per user decisions: two pre-registered stages (auto-chain, not stop-and-report); explicit depth-0 + depth-1 features exactly as theorized PLUS a chronological pairwise Elo/Bradley-Terry rating representing depth ≥ 2 (explicit depth-2 path enumeration explodes combinatorially and compounds margin noise); margin primitive with a **mechanical pre-run audit** (winner=0, non-decreasing in finish position, ≥99% of races clean) and an automatic order-based fallback. Verdict-bearing family: 3 primary terms (d0, d1, eloDiff) in the market-controlled Fit B — race-cluster |t|≥3 ∧ two-way (race, horse) |t|≥3 ∧ sign-stable halves ∧ ≥1,000 informative rows/half ∧ S-binary/S-K sign preservation ∧ BH-FDR q=0.10 — with a Fit C kill (career + field-adjusted + recent form + official **Merit Rating**, the handicapper's own collateral-form estimate). Stage 2 (fires only on a surviving pass): the frozen EXP-0016 config + surviving families as blend regressors, judged against pre-registered rungs vs +2.50% @ 1,198 bets. **Implementation.** New pure `CollateralState` accumulator in [Racing5.Features](src/Racing5.Features/CollateralState.cs) (per-horse opponent maps over the FormState 60-run window with eviction, shared-race-excluded depth-1 pair values computed once per unordered pair, two all-history Elo tables K=32/K=16 with per-race-bounded updates ΔR = K/(n−1)·Σ(s−e)); cluster-robust **Wald block test** + χ² upper tail in [LogisticRegression](src/Racing5.Modeling/LogisticRegression.cs)/[Statistics](src/Racing5.Backtest/Statistics.cs); `RacingDataReader.GetResultsHistoryAsync` adopting the orphaned SQL; optional margin lookup on `FormFold.ToRuns` (default null — frozen paths untouched); `BlendCore` extended with an optional `IBlendFeatureSource` (default null = bit-identical); the whole pre-registered family hardcoded in [AnalyzeCollateralCommand](src/Racing5.Cli/Commands/AnalyzeCollateralCommand.cs) (`analyze collateral`), which auto-chains [WalkForwardCommand.RunAsync](src/Racing5.Cli/Commands/WalkForwardCommand.cs) on rung 1. 21 new unit tests (margin clamp/normalisation, pair-mean-then-field-mean, shared-race exclusion, dead-heats, Elo arithmetic, retention/eviction, chronological guard, read-before-fold, audit rule, Wald ≡ t² identity, χ² critical values, blend-source vectors) — suite 165 → 186, all green. Implementation deviations were resolved and recorded in the plan's §8 review log (a)–(k) BEFORE the registered run. **Execution.** One registered Stage 1 run (EXP-0029) which fired the pre-registered Stage 2 auto-chain (EXP-0030). Post-run: results.md §Session 3, retired-angles + backlog updates, INDEX.md regenerated, plan stamped EXECUTED. ## The answer to the hypothesis **Yes — information can be inferred from opponent-graph relationships, and at depth 1 it is not fully priced.** This is the first fundamental (non-microstructure) signal in the project to survive a market-conditional test. It still failed promotion into the betting strategy on the pre-registered streak guard. ### Stage 1 (EXP-0029) — where the information lives First, the audit: **`mLengthsBehind` is NOT lengths-behind-winner** — only 3.17% of Tier A races satisfy "winner=0 + non-decreasing" (vs the 99% floor), so the pre-registered order-based fallback fired and every comparison below is beat/beaten, not margin-sized. | Test | Statistic | Result | Bar | Outcome | |--|--|--:|--|--| | T-info — any information, market-blind | Wald, all 8 collateral terms, Fit A | W = 9,287 (df 8), p ≈ 0, both halves ≈ 0 | p<0.001 ∧ halves <0.05 | **PASS** | | T-depth, market-blind | Wald per nested increment | D0 3,318 · +D1 4,152 · +Elo 1,166 | descriptive | all pass | | T-depth, market-controlled | same in B0/B1/B | D0 12.1 (p=0.007) · **+D1 96.1 (p=1e-20)** · +Elo 27.7 | descriptive | d1 dominates | | d0BeatPct (direct H2H) | Fit B | β=+0.050, t=1.7 | full §3 rule | fail | | **d1CollatBinary (common-opponent)** | Fit B | **β=+0.185, t=9.2 race, 9.2 two-way, halves +0.220/+0.145, 125.6k/96.3k info rows** | full §3 rule | **PASS** | | eloDiff (all-depth latent rating) | Fit B | β=−0.059, t=−0.5, sign-unstable | full §3 rule | fail | | d1 vs Fit C (career/field-adj/recency/**Merit Rating**) | kill rule | β=0.182, t=9.0, sign preserved | \|t\|≥3 ∧ same sign | **survives** | Nuances worth keeping: - **The depth structure is exactly what the theory predicted, and the census explains why.** Depth-0 is too sparse to carry much (mean coverage 0.26 — 24% of runners never met anyone in today's field); depth-1 is dense (0.755 coverage, median 64 common-opponent paths per runner). The signal sits where the connectivity is. - **The market prices the aggregate rating but not the pair-specific chains.** The Elo/BT rating — the statistically "optimal" all-depth aggregate — is fully absorbed by the price (t=−0.5), consistent with every scalar-form null before it (EXP-0014/15/27/28). What survives is the *relational residual*: how runner i compares to **today's specific rivals** through shared opponents, net of both horses' aggregate ability. That is combinatorial, race-specific information that a scalar rating cannot encode — plausibly exactly what the market fails to aggregate. - **It is not the handicap in disguise.** Fit C adds the official Merit Rating (the handicapper's own collateral-form estimate) plus career/field-adjusted/recent form, and the d1 coefficient barely moves (0.185 → 0.182). - **Per-unit magnitude is small**: Δp ≈ +0.0017 win-probability points at consensus 0.10 per 0.1 of net-beats superiority, against a 7.7% best-book overround + 6% tax — which is why the bettable expression matters more than the t-statistic. ### Stage 2 (EXP-0030) — the bettable expression, and the pre-registered rejection `e019-assembled-collateral-d1-bin` = frozen EXP-0016 pmin45 core + `d1CollatBinary`/`noD1` as blend regressors, Tier A walk-forward 2016-H2 → 2022-H2: | Metric | EXP-0030 (d1 blend) | EXP-0016 baseline | Pre-registered bar | |--|--:|--:|--| | Bets | **1,565** (1 / 19.2 races) | 1,198 (1 / 27.5) | ≥ 1,318 for the volume arm ✔ | | ROI (tax-net) | **+3.86%** [−0.36%, +8.19%] | +2.50% [−2.3%, +7.3%] | ≥ +2.0% ✔ | | Hit rate / avg odds | 59.4% / 1.86 | 59.2% / — | — | | Bank low | 100.0 (= start, never below) | 99.8 | never below start ✔ | | **Longest losing streak** | **12** | 6 | **< 10 ✘ → rung 3 DEGRADE** | **Verdict: rung 3 — collateral terms rejected as a strategy input in this config.** The frontier arms were beaten — this is the first config to push volume past 1/24 races at positive ROI, which EXP-0017/18/19 proved impossible with threshold dials alone — but the streak guard exists because the project goals say losing streak < 10, and 12 breaches it. Two further honesty notes: the deflated noise floor at N=30 is 5.98%, so +3.86% remains statistically inseparable from search noise (as every config has been); and the whole e010 family is still gated behind the unresolved EP-3.11 timing-decay question that only production shadow mode can answer. ## Follow-ups (each requires a NEW pre-registration) 1. **Decode `mLengthsBehind` semantics** (E000-style micro-audit). The audit fail means the margin-informed d1 — likely stronger than binary — was never actually tested. If the column is gap-to-horse-in-front, cumulative sums reconstruct margins trivially. 2. **Streak-shaping on the d1 core** (pMin/θ interplay at the new volume level; the streak MC machinery already exists). Tier A tuning is unlimited, but every evaluation burns registry N against a floor already at 5.98%. 3. **d1 in the market-only core** (EXP-0015 ablation logic — the form model channel is nil; d1 might not need it). 4. Everything remains subordinate to **live shadow mode**, still the decisive experiment for the whole family.