Skip to content

Commit 33a4dfc

Browse files
JohnCCarterclaude
andcommitted
feat(research): Fib artifact-probe MECHANICS pass (descriptive-only, no verdict)
Commit 2 of the mechanics PLAN (70174df), executed verbatim. Explains the mechanics behind the artifact-probe on the same frozen data / locked detection. Descriptive-only: NO verdict, NO claim, no lock change; the artifact-probe reading is unchanged, crux OPEN. Findings (descriptive): - M1: the 4H "reached less clean" gap is a span/duration confound. Spearman(clean, span) = -0.69; reached legs longer (median 5 vs 3 bars); the -0.056 gap VANISHES when conditioning on span (short-span +0.003, long-span -0.017) -> composition effect, not a detector cleanliness-preference. - M3: 4H snapping deflates because detector pivots sit OUTSIDE the human anchors -> span extends (33% extend vs 1.6% shrink). The 1D sign flip is a TF-dependent geometry: 1D shrinks more (10%) AND the span-delta<->cleanliness Spearman flips sign (-0.19 -> +0.18) -> not purely arithmetic; why the local relationship reverses by TF stays an OPEN investigate-target. - Population guard: M1 (reached vs unreached human legs) != the Stage-2 lead (human-matched vs non-human candidates) -- different population, no bleed. New sibling research/selection_learning_artifact_mechanics.py (own --artifact-mechanics CLI; numpy-only, no bootstrap) + 3 descriptive fields on ArtifactRow (used by no contrast/verdict) + 8 tests. Frozen-data parity (no --refresh). No matched-null, no new universe, no new model feature, no Genesis/1H/ETH, no edge/behaviour claim. Gates green: ruff + format + 586 pytest (cov 74.33%) + bounds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 70174df commit 33a4dfc

5 files changed

Lines changed: 521 additions & 12 deletions

File tree

docs/research_wiki/handoff.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,20 @@ legs/ranges* (labels = facit; **no edge/behaviour/backtest/PnL/Genesis/auto-fib
152152
behaviour/Genesis/1H/ETH. [Results](reviews/btc-fib-selection-learning-artifact-results-20260624.md);
153153
summary + `cells/*.json` gitignored/regenerable. Re-run (deterministic, frozen data, no `--refresh`):
154154
`PYTHONUNBUFFERED=1 uv run --no-sync python -u -m fibengine.research.selection_learning_artifact --artifact`.
155-
- **2026-06-24 Fib SELECTION-LEARNING artifact-MECHANICS investigation — PLAN locked (docs-only),
156-
RUN PENDING separate GO.** Door (i) from the checkpoint: explain the *mechanics* behind the
157-
artifact-probe (why 4H reached-legs less clean; why 4H snapping lowers cleanliness; why snapping
158-
flips sign on 1D), **descriptive-only on frozen data — NO verdict, NO claim, no lock change**. Plan
159-
[artifact-mechanics PLAN](reviews/btc-fib-selection-learning-artifact-mechanics-plan-20260624.md):
160-
feasible cleanly (deterministic from frozen data + locked detection) but NOT answerable from existing
161-
aggregates → needs a small descriptive pass recording per-leg {span_bars, magnitude_atr,
162-
snap_span_delta}. Headline object = the **4H↔1D `snap_span_delta` asymmetry** (detector granularity
163-
vs human-anchoring precision), not the partly-arithmetic span↔cleanliness correlation. Pre-locked
164-
stats (P3) + population guard (M1 reached/unreached ≠ Stage-2 lead) + marginal-gap caveat. No
165-
matched-null/new universe/Genesis/1H/ETH/refresh. Commit 2 needs a separate GO.
155+
- **2026-06-24 Fib SELECTION-LEARNING artifact-MECHANICS — BUILT + RUN (descriptive-only, NO verdict).**
156+
Commit 2 of the [mechanics PLAN](reviews/btc-fib-selection-learning-artifact-mechanics-plan-20260624.md)
157+
(`70174df`), executed verbatim. New sibling `research/selection_learning_artifact_mechanics.py`
158+
(+`--artifact-mechanics` CLI, 3 descriptive fields on `ArtifactRow`, +8 tests). Findings (descriptive,
159+
no claim): **(M1)** the 4H "reached less clean" gap is a **span/duration confound** — Spearman(clean,
160+
span)=**−0.69**, reached longer (median 5 vs 3 bars), and the −0.056 gap **vanishes when conditioning
161+
on span** (short-span +0.003, long-span −0.017): composition effect, not detector cleanliness-
162+
preference. **(M3)** 4H snapping deflates because pivots sit **outside** human anchors → span extends
163+
(33% extend vs 1.6% shrink); the **1D flip** is a TF-dependent geometry (1D shrinks 10% **and** the
164+
span-delta↔clean Spearman flips −0.19→+0.18) — *why* the local relationship reverses stays an **open
165+
investigate-target**. **No verdict, no lock change; artifact-probe reading unchanged; crux OPEN.**
166+
Population guard: M1 ≠ Stage-2 lead (different population). No matched-null/new universe/Genesis/1H/
167+
ETH/refresh. [Mechanics note](reviews/btc-fib-selection-learning-artifact-mechanics-20260624.md);
168+
mechanics_summary.json gitignored/regenerable.
166169

167170
**Next work requires a separate explicit GO. No W/gap, no Stage 1, no new sensitivity, and no Genesis
168171
may be started automatically.** Parked (test-only, separate GO): lock the facit-discipline refusal
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# BTC Fib Selection-Learning — artifact-probe MECHANICS NOTE (2026-06-24)
2+
3+
**Lean Fib Research. Research-only. DESCRIPTIVE-ONLY — NO verdict, NO claim, no edge/behaviour/PnL/
4+
backtest/Genesis/auto-fib/1H/ETH/label-mutation.** Executed per the blind
5+
[mechanics PLAN](btc-fib-selection-learning-artifact-mechanics-plan-20260624.md) (`70174df`) on the
6+
**same frozen data / locked detection** as the
7+
[artifact-probe](btc-fib-selection-learning-artifact-results-20260624.md) (no refresh, no new
8+
universe, no matched-null). It explains the *mechanics* behind the three artifact-probe observations;
9+
**it issues no verdict, changes no lock, and the artifact-probe reading is unchanged.** A clean
10+
mechanical explanation of a gap is **not** evidence for or against "genuine human signal" — the crux
11+
stays OPEN.
12+
13+
> **STATUS — descriptive mechanics, no verdict.** (1) The 4H "reached legs less clean than unreached"
14+
> gap is **fully accounted for by leg span (duration)**: cleanliness falls steeply with span
15+
> (Spearman **−0.69**), reached legs are longer (median 5 vs 3 bars), and the −0.056 gap **vanishes
16+
> when conditioning on span** (short-span gap +0.003, long-span gap −0.017). It is a **composition /
17+
> Simpson-flavoured** effect, not a property of "being reached". (2) 4H snapping **lowers** cleanliness
18+
> because detector pivots mostly sit **outside** the human anchors → snapping **extends** the span
19+
> (extend 33% vs shrink 1.6%) → more path. (3) The **1D sign flip** is the genuine cross-TF asymmetry:
20+
> 1D snaps shrink far more often (10% vs 1.6%) **and** the span-delta→cleanliness relationship itself
21+
> **flips sign** (Spearman 4H −0.19 vs 1D +0.18) — so the flip is **not** purely arithmetic; the deeper
22+
> "why the local relationship reverses by TF" stays an **open investigate-target**, claimed as nothing.
23+
24+
## What was built + run
25+
26+
A small descriptive pass: `src/fibengine/research/selection_learning_artifact_mechanics.py` (own
27+
`--artifact-mechanics` CLI) records three per-leg quantities on the artifact-probe rows —
28+
`span_bars = |pos_b − pos_a|`, `magnitude_atr` (net close-move ÷ causal ATR at `anchor_b`),
29+
`snap_span_delta = |snapped span| − |exact span|` — and the PLAN-P3 summaries (median/IQR, a single
30+
Spearman, a single median split). **Numpy-only, deterministic, no bootstrap, no verdict.** Three new
31+
descriptive fields were added to `ArtifactRow` (used by no contrast/verdict). Run on the frozen
32+
universe (preflight READY; no `--refresh`).
33+
34+
## M1 — 4H "reached less clean" is a span (duration) confound
35+
36+
| quantity | reached (n=314) | unreached (n=51) |
37+
|----------|----------------:|-----------------:|
38+
| `span_bars` median (IQR) | 5.0 (2–11) | 3.0 (2–6) |
39+
| `magnitude_atr` median (IQR) | — see summary.json — ||
40+
| Spearman(`cleanliness`, `span_bars`), all legs | **−0.686** | |
41+
| Spearman(`cleanliness`, `magnitude_atr`), all legs | −0.322 | |
42+
43+
**Attenuation (single median split on `span_bars`):**
44+
45+
| span half | n reached / unreached | mean clean reached | mean clean unreached | **gap** |
46+
|-----------|----------------------:|-------------------:|---------------------:|--------:|
47+
| short-span | 170 / 38 | 0.864 | 0.861 | **+0.003** |
48+
| long-span | 144 / 13 | 0.600 | 0.617 | **−0.017** |
49+
50+
- Cleanliness falls **steeply with span** (−0.69). Unreached legs cluster in the **short-span** bucket
51+
(38/51 ≈ 75%) where cleanliness is high (~0.86); reached legs spread into the **long-span** bucket
52+
(~46%) where it is low (~0.60). The overall −0.056 surfacing gap is that **composition****within
53+
each span half the gap is ≈0** (+0.003 / −0.017). So "reached legs are less clean" is **"reached legs
54+
are longer"**, not a detector preference for clean legs.
55+
- This matches the artifact-probe's `inverse_surfacing` direction and its **marginal** magnitude (CI
56+
upper −0.00095): there is no real surfacing-by-cleanliness effect to explain — just the span confound.
57+
58+
## M3 — the 4H↔1D snapping sign flip (cross-TF asymmetry; the headline object)
59+
60+
| TF | `snap_span_delta`: extend (>0) | no change (=0) | shrink (<0) | Spearman(`snap_span_delta`, `snapped−exact`) † |
61+
|----|----:|----:|----:|----:|
62+
| **4H** | **0.328** | 0.656 | **0.016** | **−0.193** |
63+
| 1D | 0.233 | 0.667 | **0.100** | **+0.180** |
64+
| 1w | 0.211 | 0.737 | 0.053 | −0.057 |
65+
| 1M | 0.667 | 0.333 | 0.000 | +0.165 |
66+
67+
† the bare span-delta↔cleanliness Spearman is **partly arithmetic** (changing the span changes
68+
`net/path` mechanically) — shown for completeness, **not** the finding.
69+
70+
- **4H is extension-dominated** (extend 33% vs shrink **1.6%**, ≈20:1): detector pivots sit at the
71+
fuller swing extremes, the human anchors **inside** them, so snapping extends the span → more path →
72+
cleanliness **down** (consistent with the locked `snapping_deflates`).
73+
- **1D has far more shrinking** (10% vs 1.6%) **and** the span-delta→cleanliness relationship **flips
74+
sign** (+0.18 vs −0.19). That sign flip is the genuinely non-trivial fact (not pure arithmetic): on
75+
1D, where detector pivots land relative to the local price path differs — **detector granularity vs
76+
human-anchoring precision differs by TF**. This is enough to explain *that* the artifact-probe's
77+
snapping contrast flips sign on 1D (it inflates there), **without** claiming a mechanism for the
78+
reversal — *why* the local relationship reverses stays an **open investigate-target**.
79+
80+
## Population guard (binding — carried from the PLAN)
81+
82+
M1 explains the **reached-vs-unreached** contrast (detector-reached vs detector-missed **human** legs).
83+
This is a **different population** from the Stage-2 cleanliness lead (human-matched vs **non-human**
84+
candidates, both *inside* the detector universe). **"Span explains the reached/unreached gap" does NOT
85+
mean "span explains/dissolves the Stage-2 lead"** — different populations, different (un-made) claim.
86+
87+
## Observed / Inferred / Unverified
88+
89+
- **Observed (verified):** the numbers above; Spearman(clean, span)=−0.686 on 4H; reached span median
90+
5 vs 3; the surfacing gap collapses within span halves (+0.003 / −0.017); 4H extend:shrink ≈ 33:1.6;
91+
1D 23:10 with span-delta↔clean Spearman flipping −0.19→+0.18; deterministic; new tests green.
92+
- **Inferred (descriptive, scoped):** the 4H reached-less-clean gap is a **span/duration composition
93+
confound**; the 4H snapping deflation is **span extension** (pivots outside human anchors); the 1D
94+
flip is a **TF-dependent geometry** (more shrinking + reversed local relationship).
95+
- **Unverified / scope limits:**
96+
1. **No verdict, no claim, no lock change** — the artifact-probe reading is unchanged; the crux
97+
stays OPEN.
98+
2. **Why the span-delta↔cleanliness relationship reverses by TF** is **not** explained — an open
99+
investigate-target, claimed as nothing.
100+
3. M1 does **not** touch the Stage-2 lead (population guard).
101+
4. 1M/1w surfacing carry no weight (0 / 2 unreached); context only.
102+
103+
## Non-claims (binding)
104+
105+
Descriptive consolidation only. **No verdict, no positive claim, no lock change, no reproduction, no
106+
edge/behaviour/PnL/backtest/strategy claim.** Explaining the mechanics of the artifact-probe gaps is
107+
**not** evidence that `cleanliness` is or is not "human intuition" — the crux is unchanged and OPEN. No
108+
matched-null, no new candidate universe, no new model feature, no Genesis, no auto-fib-as-truth, no 1H,
109+
no ETH, no label/corpus mutation, no `data.fetch --refresh`.
110+
111+
> The 4H "reached less clean" gap is **span (duration), not detector cleanliness-preference** — it
112+
> vanishes at equal span. 4H snapping deflates because pivots sit **outside** the human anchors
113+
> (span extends); the 1D flip is a **TF-dependent geometry** (more shrinking + a sign-reversed local
114+
> relationship) whose deeper cause stays an open investigate-target. Descriptive only — no verdict, no
115+
> claim, crux unchanged.

src/fibengine/research/selection_learning_artifact.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ class ArtifactRow:
116116
None # cleanliness on the ε-matched detector pivots (reached only)
117117
)
118118
drop: str | None = None # snapping-contrast drop reason (degenerate snap), logged not imputed
119+
# Descriptive-only mechanics fields (mechanics PLAN P3) — NOT used by any contrast/verdict.
120+
span_bars: int = 0 # |pos_b - pos_a| (duration proxy)
121+
magnitude_atr: float | None = None # |close[b] - close[a]| / causal ATR at anchor_b
122+
snap_span_delta: int | None = None # |snapped span| - |exact span| (reached, non-degenerate)
119123

120124

121125
def _quarter_of(ts: pd.Timestamp) -> str:
@@ -147,7 +151,13 @@ def build_artifact_rows(
147151
df_t = df.iloc[: cutoff + 1]
148152
atr_t = atr(df_t, period=cfg.atr_period).to_numpy()
149153
atr_at_b = float(atr_t[pos_b]) if 0 <= pos_b < len(atr_t) else float("nan")
150-
reached, snapped, drop = False, None, None
154+
span_bars = abs(int(pos_b) - int(pos_a)) # descriptive (mechanics P3)
155+
magnitude_atr = (
156+
abs(float(closes[pos_b]) - float(closes[pos_a])) / atr_at_b
157+
if atr_at_b > 0 and np.isfinite(atr_at_b)
158+
else None
159+
)
160+
reached, snapped, drop, snap_span_delta = False, None, None, None
151161
if atr_at_b > 0 and np.isfinite(atr_at_b): # fail-closed on degenerate ATR
152162
price_tol = cfg.eps_price_atr * atr_at_b
153163
pivots = detect_pivots(df_t, pivot_cfg)
@@ -163,6 +173,7 @@ def build_artifact_rows(
163173
drop = "degenerate_snap_pa_eq_pb"
164174
else:
165175
snapped = _cleanliness_idx(closes, piv_a.index, piv_b.index)
176+
snap_span_delta = abs(piv_b.index - piv_a.index) - span_bars # descriptive (P3)
166177
rows.append(
167178
ArtifactRow(
168179
quarter=_quarter_of(leg.anchor_b_ts),
@@ -172,6 +183,9 @@ def build_artifact_rows(
172183
reached=reached,
173184
snapped_clean=snapped,
174185
drop=drop,
186+
span_bars=span_bars,
187+
magnitude_atr=magnitude_atr,
188+
snap_span_delta=snap_span_delta,
175189
)
176190
)
177191
return rows

0 commit comments

Comments
 (0)