Hypotheses · shock · H-0bcad8a9
Sharpen: poor jumpers whose last chase defeat was heavy
Part of the thread “S2: chase completed normal habitual poor jumper” 4 hypotheses
- Proposed
- Designed
- Discovery
- Promising
- Falsification
- Frozen
- Vault
- Provisional
- Shadow
- Validated
- Live
- Source
- Investigator agent, v1
- Made by
- sharpen
- Created
- 17 Oct, 03:48
- Tests logged
- 0
Reasoning
Why this hypothesis exists: what the lab saw, the question it asked, the mechanism it proposed, what it predicted, and the result that would prove it wrong. Written before the test was run.
- Observed
- S2-chase-completed-normal-habitual-poor-jumper (S2: chase completed normal habitual poor jumper) pointed the predicted way (positive) on the sealed holdout but too weakly to prove it: A/E 1.141 on 1077 bets (p 0.060, false-discovery threshold 0.0034); tracked forward in SHADOW. O-1a861319
- AskedDoes the lift grow as the expected jumping gets worse, or as the last beaten margin grows (more of the defeat put down to jumping)? testing
- MechanismA heavy beating by a habitual poor jumper is partly lengths lost at fences, not lack of pace. The mechanism says the misleading form, and so the mispricing, should be largest when the margin is big.
- Why the market misses itPunters and the odds read last_beaten_lengths directly. The jumping cost behind those lengths is not visible in the form figures.
- Predictedpositive, A/E 1.15 to 1.30 on 300+ bets
- Falsified ifA/E at or below the parent's 1.14, or 1.00 or less, on 300+ bets.
- Rule sketch
code = 'Chase' AND finished = 1 AND s BETWEEN -0.75 AND 0.75 AND e <= -0.3104 AND last_beaten_lengths >= 10 - question idQ-b0edf33c
- operatorsharpen
Mechanism and rationale
A heavy beating by a habitual poor jumper is partly lengths lost at fences, not lack of pace. The mechanism says the misleading form, and so the mispricing, should be largest when the margin is big.
The rule
code = 'Chase' AND finished = 1 AND s BETWEEN -0.75 AND 0.75 AND e <= -0.3104 AND last_race_type = 'Chase' AND last_position IS NOT NULL AND last_beaten_lengths >= 10
Reads: code, finished, s, e, last_race_type, last_position, last_beaten_lengths
Pre-registration
- Spec hash (sha256 of the canonical pre-spec)
- 2dbc50fbf607b0db9f8184f3751b9e66a5eb152c063c402b4a98022627a91f0b
- Frozen
- not frozen
- The definition can still change.
- Confounders
- Long prices and the favourite-longshot bias: horses beaten 10+ lengths go off at bigger prices, and A/E at long odds is noisy and biased. Check the price-band split and the 14/1-or-shorter refinement.
- Class of the last race: a heavy defeat in a higher class than today's (class drop) is a known, priced angle. Compare last_race_class with race_class.
- Ground: a big margin on testing going (last_going_group) may reflect ground and not jumping. Check by last_going_group.
- Short data window: last_beaten_lengths only exists from 2025-11-01, so the pool is one season and probably thin. It will cluster in a few months and courses.
- Country: the parent's holdout lift was IRE-heavy (1.366 against GB 1.107), and IRE shock data starts later. Report GB and IRE separately.
- Regression to form: horses beaten heavily regress up anyway, and the market may already allow for this with all chasers. The <10-lengths control and the same-race runners address this.
- Control
{ "description": "The question is whether the lift is LARGER where the margin is big, so the key comparison is the same parent population (habitual poor chase jumpers who completed their last chase to expectation) beaten by less than 10 lengths, measured over the same window (last_beaten_lengths only exists from 2025-11-01). The prediction is that the heavy-defeat group beats this control by a clear margin (at least +0.08 A/E). If the two match, the margin adds nothing and the parent's lift, if real, is not about misleading form. The usual same-race control (the other runners in these races) should be near 1.00; if they also show a lift similar to the selection, the effect belongs to the race type and not to the horse.", "rule": "code = 'Chase' AND finished = 1 AND s BETWEEN -0.75 AND 0.75 AND e <= -0.3104 AND last_race_type = 'Chase' AND last_position IS NOT NULL AND last_beaten_lengths < 10" }
Discovery result
Not measured yet.
Falsification
No attacks yet. Only promising ideas are attacked.
Sealed holdout (vault)
Not queried. Only a frozen idea can spend its one query against the 2020-25 holdout.
Forward record
No forward record. Shadow tracking starts after the vault and counts only races run after the freeze.
Lineage
Agent runs
designer v1ok · 44s · 17 Oct, 03:49
Output (schema-checked)
{ "rule": "code = 'Chase' AND finished = 1 AND s BETWEEN -0.75 AND 0.75 AND e <= -0.3104 AND last_race_type = 'Chase' AND last_position IS NOT NULL AND last_beaten_lengths >= 10", "refinements": [ { "label": "14/1 or shorter", "rule": "code = 'Chase' AND finished = 1 AND s BETWEEN -0.75 AND 0.75 AND e <= -0.3104 AND last_race_type = 'Chase' AND last_position IS NOT NULL AND last_beaten_lengths >= 10 AND sp_decimal <= 15" }, { "label": "very heavy defeat (20+ lengths), the dose-response test", "rule": "code = 'Chase' AND finished = 1 AND s BETWEEN -0.75 AND 0.75 AND e <= -0.3104 AND last_race_type = 'Chase' AND last_position IS NOT NULL AND last_beaten_lengths >= 20" }, { "label": "GB only (the holdout lift and data window are cleanest in GB)", "rule": "code = 'Chase' AND finished = 1 AND s BETWEEN -0.75 AND 0.75 AND e <= -0.3104 AND last_race_type = 'Chase' AND last_position IS NOT NULL AND last_beaten_lengths >= 10 AND region = 'GB'" } ], "control": { "description": "The question is whether the lift is LARGER where the margin is big, so the key comparison is the same parent population (habitual poor chase jumpers who completed their last chase to expectation) beaten by less than 10 lengths, measured over the same window (last_beaten_lengths only exists from 2025-11-01). The prediction is that the heavy-defeat group beats this control by a clear margin (at least +0.08 A/E). If the two match, the margin adds nothing and the parent's lift, if real, is not about misleading form. The usual same-race control (the other runners in these races) should be near 1.00; if they also show a lift similar to the selection, the effect belongs to the race type and not to the horse.", "rule": "code = 'Chase' AND finished = 1 AND s BETWEEN -0.75 AND 0.75 AND e <= -0.3104 AND last_race_type = 'Chase' AND last_position IS NOT NULL AND last_beaten_lengths < 10" }, "pass_criteria": { "min_bets": 150, "min_ae": 1.08, "max_p": 0.05 }, "forward_bar": { "min_bets": 100, "min_ae": 1.05, "max_p": 0.2 }, "confounders": [ "Long prices and the favourite-longshot bias: horses beaten 10+ lengths go off at bigger prices, and A/E at long odds is noisy and biased. Check the price-band split and the 14/1-or-shorter refinement.", "Class of the last race: a heavy defeat in a higher class than today's (class drop) is a known, priced angle. Compare last_race_class with race_class.", "Ground: a big margin on testing going (last_going_group) may reflect ground and not jumping. Check by last_going_group.", "Short data window: last_beaten_lengths only exists from 2025-11-01, so the pool is one season and probably thin. It will cluster in a few months and courses.", "Country: the parent's holdout lift was IRE-heavy (1.366 against GB 1.107), and IRE shock data starts later. Report GB and IRE separately.", "Regression to form: horses beaten heavily regress up anyway, and the market may already allow for this with all chasers. The <10-lengths control and the same-race runners address this." ], "mechanism": "A habitual poor jumper (expected Jump Index e <= -0.31) that jumped about as badly as usual last time (s within ±0.75 s.d.) loses lengths at the fences without that showing as a jumping incident. When it finishes a chase beaten 10+ lengths, a real share of that margin is jumping cost, not lack of pace, so the form line overstates its weakness. If the parent rule's lift comes from this misleading form, it should be concentrated where the beaten margin is large. The rule requires the last run to be a completed chase so that last_beaten_lengths describes the same run the shock score was computed on.", "market_miss": "Punters, form figures and ratings-based odds read the beaten margin at face value. The jumping cost behind the margin is only visible in sectional and jump-tracking data (RaceiQ Jump Index), which the betting public does not see. A horse that jumps poorly every time looks consistently slow, not consistently careless, so the heavy defeat is priced as a lack of ability.", "prediction": { "direction": "positive", "size": "A/E 1.15 to 1.30, above the parent's 1.14 and at least 0.08 above the <10-lengths control; the pool is probably 150 to 300 bets given the window from 2025-11-01", "falsified_if": "A/E at or below 1.00 on 150+ bets, or A/E no higher than the <10-lengths control over the same window (difference under 0.03), or at or below the parent's 1.14 on 300+ bets." }, "notes": "I changed the sketch in two ways. (1) I added last_race_type = 'Chase' AND last_position IS NOT NULL. The shock columns describe the previous SCORED run, which may not be the most recent run, but last_beaten_lengths is always the most recent run. Without the extra condition, the margin could come from a hurdle or flat run that has nothing to do with the chase jumping cost. (2) I rounded e to -0.3104, as in the sketch; the parent used -0.3104024. Main risk: last_beaten_lengths is only available from 2025-11-01 in GB and IRE, so the discovery pool will be a small part of the parent's 467 discovery bets and may not reach 150. In that case it should go to falsification and forward tracking as a thin lead, not be killed for its size. If it is thin, give the comparison with the <10-lengths control in the same window more weight than the absolute A/E." }
Timeline
Job 3196 gave up: OperationalError: no such column: code Traceback (most recent call last): File "/app/lab/src/gallops/orchestrator/loop
· engine:compute-1
compute-1 took job 3196 (evaluate, attempt 5)
· compute-1
Job 3196 will retry: OperationalError: no such column: code Traceback (most recent call last): File "/app/lab/src/gallops/orchestrator/loop
· engine:compute-1
compute-1 took job 3196 (evaluate, attempt 4)
· compute-1
Job 3196 will retry: OperationalError: no such column: code Traceback (most recent call last): File "/app/lab/src/gallops/orchestrator/loop
· engine:compute-1
compute-1 took job 3196 (evaluate, attempt 3)
· compute-1
Job 3196 will retry: OperationalError: no such column: code Traceback (most recent call last): File "/app/lab/src/gallops/orchestrator/loop
· engine:compute-1
compute-1 took job 3196 (evaluate, attempt 2)
· compute-1
Job 3196 will retry: OperationalError: no such column: code Traceback (most recent call last): File "/app/lab/src/gallops/orchestrator/loop
· engine:compute-1