BLOB DESK

CONTROL ROOM

Report · MD — —

CLICKABLE MARKDOWN · COPY READY

Phase 1M — T+6H Horizon Investigation

PHASE1M-T6H-HORIZON-FIX-FINAL-REPORT.md

Opens as plain Markdown. Use Copy report or select all in the box below.

# PHASE 1M — T+6H Horizon Activation & Progression Integrity

| Field | Value |
| --- | --- |
| Date (UTC) | 2026-09-27 |
| Mode | Inspect → decide → **leave unchanged** (intentional exclusion) |
| Code root | `/opt/blob-desk-review/code` |
| Live DB | `/opt/blob-desk-review/data/phase1_lab.db` (read-only queries) |
| Observed commit (workspace tip, unrelated tree) | `67e3a84` |
| Branch context | Blob Desk is **not** a git worktree; science frozen under `FEATURE_VERSION` |
| Classification | **`T6H_INTENTIONALLY_EXCLUDED`** (not `T6H_HORIZON_FIXED`) |

---

## 1. Root cause

Control Room shows **T+6H = NOT YET MEASURABLE** because **T+6H is not part of the frozen Outcome-Spec-V1 market-observation schedule**, not because events are too young and not because of a scheduler age bug.

Exact chain:

1. **Authoritative schedule** (`phase1/versions.py`):
   ```python
   HORIZON_OFFSETS_SEC = {
       "T0": 0,
       "T1H": 3600,
       "T24H": 86400,
       "T48H": 172800,
   }
   ```
   There is **no** `T6H` / `T+6H` key. `FEATURE_VERSION = "outcome-panel-t0-1h-24h-48h-v1"`.

2. **Frozen science document** (`OUTCOME-SPEC-V1.md`):
   - Status: **FROZEN for Phase 1 Track A**
   - Horizons: **T0, T+1H, T+24H, T+48H only**
   - “Nine-horizon schedules are **out of scope**.”
   - H1 primary endpoint uses **return_24h** from SUCCESS T0 + SUCCESS T24H.

3. **Scheduler / observe engine** (`phase1/observations.py`):
   - `ensure_schedule()` iterates **only** `HORIZON_OFFSETS_SEC.items()` and creates pending slots from each event’s **`block_time` (T0)**.
   - `record_snapshot()` / `observe_due()` look up offsets/grace from the same map — they **cannot** schedule or fill a T6H row.

4. **Control Room V3 progression** (`phase1/control_room/v3_progress.py`):
   - Pipeline **displays** a T+6H stage for operator orientation.
   - Measurability gate:
     ```python
     t6_measurable = "T6H" in HORIZON_OFFSETS_SEC or "T+6H" in HORIZON_OFFSETS_SEC
     ```
   - Because the key is absent → `measurable=False`, `display="NOT YET MEASURABLE"`, `count=None`.
   - Definition text: *“Not in frozen HORIZON_OFFSETS_SEC — not invented for UI”*.
   - This was **deliberate Phase 1K behaviour**, covered by `tests/test_phase1k_control_room_v3.py::test_t6h_not_in_science` and `test_horizon_progress_counts`.

5. **Do not confuse with evidence-arrival `T0_PLUS_6H`**:
   - `phase1/accumulation.py` `ARRIVAL_BOUNDARIES_SEC` includes `"T0_PLUS_6H": 6*3600` as a **diagnostic information-arrival** boundary.
   - That is **not** a market outcome horizon and does **not** create `observations.horizon='T6H'` rows.

Live population at audit time (2026-09-27 ~06:02 UTC) confirms age is **not** the blocker for T+6H:

| Metric | Value |
| --- | --- |
| PRIMARY (not excluded) | 117 |
| VERIFIED PRIMARY | 117 |
| Max age | ~21.4 h |
| Events ≥ 6 h | **84** |
| Events ≥ 24 h | **0** |
| Events ≥ 48 h | **0** |
| Distinct `observations.horizon` | `T0`, `T1H`, `T24H`, `T48H` only |
| Rows with `horizon='T6H'` | **0** |

Authoritative progression counts (via `compute_horizon_progress`):

| Stage | Count / display |
| --- | --- |
| PRIMARY | 117 |
| VERIFIED | 117 |
| T0 SUCCESS | 73 |
| T+1H SUCCESS | 69 |
| T+6H | **NOT YET MEASURABLE** |
| T+24H SUCCESS | 0 (all 117 PENDING — none ≥24 h) |
| T+48H SUCCESS | 0 (all 117 PENDING — none ≥48 h) |
| OUTCOME COMPLETE | 0 |
| EXPERIMENT EVALUABLE | 0 |

**Conclusion:** “NOT YET MEASURABLE” means **out of frozen science / not scheduled**, not “waiting for clock.” Adding T+6H to `HORIZON_OFFSETS_SEC` would be a **scientific-scope change** against Outcome-Spec-V1 and H1’s published panel, not a bugfix.

Per task rule:

> If the investigation discovers that T+6H was intentionally excluded from the scientific design rather than accidentally omitted, do NOT force the change. Report the evidence and leave it unchanged.

**No code change was applied.**

---

## 2. Files changed

**None.**

Investigation read (not modified):

| Path | Role |
| --- | --- |
| `phase1/versions.py` | Authoritative `HORIZON_OFFSETS_SEC` / `FEATURE_VERSION` / H1 id |
| `OUTCOME-SPEC-V1.md` | Frozen horizon set |
| `phase1/observations.py` | Schedule + observe from `HORIZON_OFFSETS_SEC` + event `block_time` |
| `phase1/accumulation.py` | Outcome cells; diagnostic `ARRIVAL_BOUNDARIES_SEC` incl. `T0_PLUS_6H` |
| `phase1/control_room/v3_progress.py` | Pipeline T+6H → NOT YET MEASURABLE when absent |
| `phase1/control_room/static/control-room.js` | Renders `display \|\| "NOT YET MEASURABLE"` |
| `tests/test_phase1k_control_room_v3.py` | Asserts T6H absent + UI non-measurable |
| `PHASE1K-CONTROL-ROOM-V3-FINAL-REPORT.md` | Documents intentional non-invention of T+6H counts |

---

## 3. Horizon architecture

### Authoritative market / outcome horizons (unchanged)

```text
FEATURE_VERSION = outcome-panel-t0-1h-24h-48h-v1

HORIZON_OFFSETS_SEC = {
  T0:   0,
  T1H:  3600,
  T24H: 86400,   # H1 primary outcome horizon
  T48H: 172800,
}

HORIZON_GRACE_SEC = {
  T0:   120 (via T0_WINDOW_SECONDS for acceptance),
  T1H:  600,
  T24H: 3600,
  T48H: 3600,
}
```

Scheduler: `ensure_schedule(event)` → for each key in `HORIZON_OFFSETS_SEC`, `target_time = block_time + offset` (event T0, **not** wall clock).

### Diagnostic-only arrival boundary (not an outcome horizon)

```text
ARRIVAL_BOUNDARIES_SEC includes T0_PLUS_6H = 21600
```

Used for information-arrival / latency diagnostics — **does not** create market observations at T+6H.

### Control Room pipeline presentation

Order remains: PRIMARY → VERIFIED → T0 → T+1H → **T+6H (placeholder)** → T+24H → T+48H → OUTCOME COMPLETE → EXPERIMENT EVALUABLE.

T+6H placeholder is intentional so operators see the stage is **not invented**, rather than silently omitting a familiar intermediate label.

---

## 4. Historical integrity

| Question | Answer |
| --- | --- |
| Were any historical T+6H observations created? | **NO** |
| Were any prices/liquidity backfilled and labelled T+6H? | **NO** |
| Were later T+1H/T+24H values rewritten as T+6H? | **NO** |
| Were SOURCE_FAIL rows rewritten as MISSED or SUCCESS? | **NO** (no T6H path; Phase 1L SOURCE_FAIL preservation untouched) |
| Live DB `observations` rows with `horizon='T6H'` before/after | **0 / 0** |

Expected and confirmed: **NO fabricated observations.**

If a future human decision expands Outcome-Spec to include T+6H, new schedules must apply prospectively from event `block_time` with explicit grace; historical events without a contemporaneous attempt must remain without fabricated SUCCESS rows (RETROSPECTIVE kind only if an explicit recovery policy is authorised — none was invoked here).

---

## 5. Live validation

Autonomous accumulation loop **left running** (pids ~2264392/2264399). Control Room process **left running** (~2270920). No restart required (no code deploy).

### Representative old PRIMARY events (>6 h, no T6H row)

| event_id (prefix) | block_time (T0) | age (~h) | T+6H due by clock? | T6H observation | Other horizons (authoritative) |
| --- | --- | --- | --- | --- | --- |
| `4hxQmfKUvmozytuq…` | 2026-09-26T08:36:32Z | ~21.4 | Yes (clock) | **none — horizon not scheduled** | T0 MISSED; T1H MISSED; T24H/T48H UNRESOLVED |
| `5EnYNjY7cw8rR2bj…` | 2026-09-26T11:55:19Z | ~18.1 | Yes (clock) | **none** | T0 MISSED; T1H MISSED; T24H/T48H UNRESOLVED |
| `xWMozbcL6JzMFHPP…` | 2026-09-26T14:44:02Z | ~15.3 | Yes (clock) | **none** | T0 MISSED; T1H SOURCE_FAIL (dexscreener); T24H/T48H UNRESOLVED |
| `4j77MAndxjt53Cuz…` | 2026-09-26T14:54:55Z | ~15.1 | Yes (clock) | **none** | T0 SOURCE_FAIL; T1H SOURCE_FAIL; T24H/T48H UNRESOLVED |
| `3aS3ort3uR7teLp4…` | 2026-09-26T15:00:47Z | ~15.0 | Yes (clock) | **none** | T0 SOURCE_FAIL; T1H SOURCE_FAIL; T24H/T48H UNRESOLVED |

“Due by clock” is **not** “due in the scheduler”: the scheduler never created a T6H target, so the observe worker never attempts T+6H.

### Newly admitted event — structural schedule check

Example newest PRIMARY `2DatHHEfck33WMgD…`, `block_time=2026-09-27T05:56:40Z`:

| Horizon | Target from T0 | In `HORIZON_OFFSETS_SEC`? | Slot created by `ensure_schedule`? |
| --- | --- | --- | --- |
| T0 | T0 | Yes | Yes |
| T+1H | T0+1h | Yes | Yes |
| T+6H | T0+6h | **No** | **No** |
| T+24H | T0+24h | Yes | Yes |
| T+48H | T0+48h | Yes | Yes |

This matches frozen design: new admissions get **four** outcome slots, not five.

### T+24H / T+48H zeros

**Not a configuration bug.** Max PRIMARY age ~21.4 h < 24 h → every PRIMARY T24H/T48H cell is correctly **PENDING**. Outcome-complete remains 0 until SUCCESS T0 ∧ SUCCESS T24H exist.

---

## 6. Regression validation

| Horizon / rule | Status |
| --- | --- |
| T0 | Unchanged; live SUCCESS count 73 (authoritative cells) |
| T+1H | Unchanged; live SUCCESS count 69 |
| T+24H | Unchanged schedule; 0 SUCCESS because population <24 h |
| T+48H | Unchanged schedule; 0 SUCCESS because population <48 h |
| SOURCE_FAIL ≠ MISSED | Preserved (Phase 1L); no T6H path to regress |
| NULL ≠ 0 | Preserved |
| Force-observe / UA / observe backoff | Untouched |
| Autonomous loop | Not stopped |
| Control Room read-only | Untouched |

---

## 7. Tests

Full suite after investigation (no code delta):

```text
395 passed in 43.85s
```

Relevant existing assertions still green:

- `test_t6h_not_in_science` — `"T6H" not in HORIZON_OFFSETS_SEC`
- `test_horizon_progress_counts` — T6H stage `measurable=False`, `display=NOT YET MEASURABLE`
- Read-only Control Room route tests

No new tests were added to “activate” T+6H, because activation was **rejected** as a science-scope violation.

---

## 8. Scientific integrity

| Item | Confirmed |
| --- | --- |
| H1 definition (`H1-positive-return-24h-vs-0.50-v1`) | Unchanged |
| G1 / `RULE_VERSION` | Unchanged |
| Chronological split (`DEVELOP_FRACTION=0.60`) | Unchanged |
| Holdout | Unchanged |
| Experiment definitions / Skeptic / JEV | Unchanged; not activated |
| Policy / Paper / Live trading | Unchanged; remain gated |
| Readiness thresholds | Unchanged |
| Admission / event / evidence rules | Unchanged |
| Outcome-Spec-V1 horizon set | Unchanged (T0, T1H, T24H, T48H only) |

---

## 9. Final classification

### `T6H_INTENTIONALLY_EXCLUDED`

**Not** `T6H_HORIZON_FIXED`.

Rationale:

- The panel label T+6H in Control Room is a **deliberate non-measurable placeholder** from Phase 1K, gated on absence from `HORIZON_OFFSETS_SEC`.
- Frozen Outcome-Spec-V1 and `FEATURE_VERSION` exclude T+6H from the authoritative market schedule.
- Live events older than 6 hours correctly have **zero** T6H observation rows because the horizon was never configured — not because observations failed.
- Forcing T+6H into the scheduler would invent a new intermediate outcome horizon, invalidate the frozen panel version string, and risk pressure to backfill historical points — all forbidden by this brief when exclusion is intentional.

### Operator takeaway

- **T+6H “NOT YET MEASURABLE”** = out of frozen science, not a broken clock.
- **T+24H / T+48H = 0** = population not yet mature enough; schedule is correct.
- Progress that matters for H1 remains **T0 → T+1H → T+24H (endpoint) → T+48H → outcome-complete**.

### Optional future (requires explicit human science decision — not done)

If Product/Science later expands Outcome-Spec to five horizons, the change must be atomic across:

1. `OUTCOME-SPEC-V1` (or V1.x) + `FEATURE_VERSION`
2. `HORIZON_OFFSETS_SEC` + `HORIZON_GRACE_SEC`
3. Scheduler / observe / progression / tests
4. Explicit **no silent historical backfill** policy

Until that authorisation exists, leaving the system unchanged is the correct Principal Engineer action.

---

*End of PHASE1M report.*