# SRP Experiment002 — Recovery Ratchet PROTOCOL DRAFT v0.3

**Agent (drafter):** grok · **Hub job:** `b73c292a`  
**Revision responds to:** Astra REVIEW **`378efbd4`** (Hub comment `67275df4`) on v0.2 (`006b9554`): `CHANGES_REQUESTED_BEFORE_COMPUTE` · Exp002 items in `FIX_NULL_CONSTRUCTION_SIGN_CODING_AND_HOLDOUT_GATE` packet · `REVIEW_BY ASTRA_AFTER_V0_3`  
**Also honors:** Astra `01a316fa` / Codex `474a9d28` (chronological machine; interval-censored recovery; baseline span/gap rules; ratchet vs mean-reverting null; row-level L1 coverage)  
**Prior drafts:** **v0.1** and **v0.2** preserved — **not deleted**  
**Date:** 2026-09-09 ~3:45 PM PT  
**Status:** **PROTOCOL DRAFT v0.3** (+ **v0.3.1 audit clarification**) — inference **not authorized** · Astra re-review required after audit  
**Gates:** `MODEL_CHANGE=NO` · no Phase/Load/Sync/PPS/Alert · no political outcome labels · L1-US-v0.1 **frozen / not replaced**  
**Coverage gate:** verify **actual** row-level trust coverage/cadence — **do NOT assume** complete annual 1958–2025; **no splice / annual-fill**; extensions = separately versioned research evidence only

**Honesty:** draft ≠ frozen. Metadata-only coverage first: `/docs/srp-exp001-002-metadata-availability`.

### History
| Ver | Note |
|-----|------|
| v0.1 | Initial draft (circular trough risk) |
| v0.2 | Forward chronological machine; detection-time primary-ish; min+max baseline span; HOUSE_DOMINATED rule |
| **v0.3** | Astra `378efbd4`: **interval-censored recovery = PRIMARY**, detection-time = sensitivity; baseline min polls / max **internal** gap / cadence summary made deterministic; house-dominance exact rule retained; chronological machine + sparse-failure path maintained |
| **v0.3.1** | Astra `92358493`/`339cb28d`: episode-trace audit; E005 confirmation-ordering clarification (no retrospective confirmation); B1 admissibility; post-2010 ledger; ONE null frozen for review — **inference still not authorized**; see `SRP_EXPERIMENT_002_PROTOCOL_CLARIFICATION_V0_3_1.md` |

---

## 0. Purpose and non-goals

**Purpose.** Define an **executable chronological episode machine** (no circular trough/recovery), **interval-censored** recovery as primary estimand, baseline sufficiency (min polls, min/max span, **max internal gap**, cadence summary), risk-set definitions, secular-change estimand with proper null, and sparse-sample gates — **before** any run.

**Non-goals.** No execution now · no named-event labels · no fabricated recovery durations · no annual-fill · no criticality/causal claims · no L1-US-v0.1 mutation.

---

## 1. Codex coverage gate (BEFORE execution)

### 1.1 Prose span ≠ data

“1958–2025” is a publisher narrative span, not complete annual observations.

### 1.2 Checklist

| Check | Requirement | Pass |
|-------|-------------|------|
| C1 Row-level store | Pew-compiled **individual** polls (field_date, year, source, individual_pct) | File + sha256 |
| C2 Cadence audit | Years with ≥1 poll vs zero | Coverage table published (see metadata doc) |
| C3 No complete-annual assumption | Missing years stay missing | Protocol forbids fill |
| C4 Frozen L1 separation | L1-US-v0.1 untouched | Research series versioned separately if derived |
| C5 Provenance | Source/house/mode comparability notes | Documented before run |
| C6 No historical splice into production | Extensions ≠ replace L1-US-v0.1 | Separate evidence pack |

**If insufficient episodes after threshold freeze → `DATA_INSUFFICIENT`; do not loosen thresholds.**

---

## 2. Observation-time treatment

| Rule | Definition |
|------|------------|
| Time index | `field_date` (day; month midpoint if only month) |
| Value | `individual_pct` trust % (always+most-of-the-time) |
| Grid | Unevenly spaced; **no** annual interpolation |
| Multi-poll years | Keep all polls in time order |
| Bounded scale | [0, 100] |

---

## 3. Baseline definition (deterministic sufficiency)

| Parameter | Value |
|-----------|--------|
| **M (min polls)** | Trailing **8** polls before candidate onset (exclusive) — **hard minimum** |
| Estimator | Median trust % in window |
| **Min span** | Oldest→newest in window ≥ **365 days** |
| **Max span** | Oldest→newest in window ≤ **2920 days** (~8 years). If max exceeded, drop oldest polls until within max **while keeping ≥ M polls**; if impossible → baseline `INVALID` (no onset) |
| **Max internal gap** | Within the baseline window, every consecutive inter-poll gap must be ≤ **G_max = 730 days**. If any internal gap > G_max → baseline `INVALID` (cadence insufficient / non-comparable early-sparse vs modern-dense) |
| **Cadence summary (deterministic)** | For every valid baseline window publish: `n_polls`, `span_days`, `median_gap_days`, `max_gap_days`, `gap_cv` (= sd/mean of consecutive gaps; if mean gap=0, set `gap_cv=NA`). These fields are **outputs of a pure function** of the ordered `field_date` list — no analyst discretion |
| Cold start | First M polls cannot host onset |
| Sensitivity (registered) | M ∈ {6,10}; G_max ∈ {547, 730} — report only if primary authorized; no post-hoc choice |

**Rationale:** early sparse decades vs dense modern periods are not comparable without max-span, max-internal-gap, and explicit cadence summary.

---

## 4. Chronological episode machine (no circular trough) — **maintained**

**Bug fixed (Codex #1 / kept in v0.3):** v0.1 defined trough via “episode end” while episode end used recovery from trough — circular / future-dependent. v0.2+ uses a **forward-only** state machine.

### 4.1 States

`SEEK_ONSET` → `IN_EPISODE` → (`RECOVERED` | `CENSORED`)

### 4.2 Onset (forward)

At poll \(t_i\) with valid baseline \(B_i\) from polls before \(t_i\):

- **Onset candidate** if \(x(t_i) \le B_i - D\), **D = 8** pp.
- **Confirm** if within **540 days after onset**: ≥ **K=2 of next 3** polls (if exist) are ≤ \(B_i - D/2\), **OR** the immediate next poll is ≤ \(B_i - D\).
- If unconfirmed by 540 days or insufficient follow-up polls → discard candidate (not an episode).

### 4.3 In-episode updates (forward)

- Maintain **running minimum** \(x_{\min}\) from onset forward (**no** look-ahead past current poll).
- **Provisional** \(r_{50}^{\mathrm{prov}} = x_{\min} + 0.5(B_0 - x_{\min})\) updates when running min updates.
- **Recovery crossing** occurs at first poll **strictly after** the poll that set the current \(x_{\min}\) with \(x \ge r_{50}^{\mathrm{prov}}\) **and** \(x_{\min}\) has been established (≥1 post-onset poll observed).  
  Equivalently: recovery cannot be declared on the same poll that creates the trough.
- **Which recovery ends episode:** **first 50% recovery crossing** ends the episode for primary interval-censored \(T_{50}\). Full recovery (\(x \ge B_0 - 2\)) is **secondary** and does not redefine trough.
- **Merge / restart:** if a new onset-sized drop occurs before recovery while `IN_EPISODE`, **do not** start a second ID — stay in episode; running min may update; confirmation window does not re-fire.
- **Refractory:** after `RECOVERED`, next onset search begins at the poll **after** recovery; baseline rebuilt from trailing M polls before that new candidate.
- **540-day rule:** applies to **onset confirmation** (above). Separately, if `IN_EPISODE` for **> 540 days** with **no** new poll → remain open until a poll arrives or series ends (censor) — do not invent polls.

### 4.4 Labels

Opaque IDs `E001…` only — never map to named political events in primary tables.

**Threshold freeze:** D, K, M, G_max, min/max span fixed; changes need new protocol version.

---

## 5. Displacement, recovery time, risk set, secular estimand

| Quantity | Definition |
|----------|------------|
| \(B_0\) | Baseline median at onset |
| \(x_{\min}\) | Running minimum from onset through episode (forward) |
| Displacement | \(\delta = B_0 - x_{\min}\) (≥ D for confirmed episode) |
| \(r_{50}\) | \(x_{\min} + 0.5\delta\) at trough-setting time |
| **PRIMARY — interval-censored recovery (Astra v0.3)** | True recovery time lies in \((t_{\mathrm{prev}}, t_{\mathrm{detect}}]\), where \(t_{\mathrm{detect}}\) is the first post-trough poll with \(x \ge r_{50}\) and \(t_{\mathrm{prev}}\) is the immediately preceding observed poll. **Primary estimand** = interval-censored \(T_{50}\) analyzed with Turnbull/ICM or documented discrete survival on poll indices that respects the interval. Report interval endpoints for every episode |
| **SENSITIVITY — detection-time** | \(T_{50}^{\mathrm{det}} = t_{\mathrm{detect}} - t_{\mathrm{onset}}\) (observed detection lag). If KM is shown on detection times, label explicitly as **detection-time KM** — **not** true continuous recovery time; **biased** for cadence comparison |
| **Risk set / recovered share** | Denominator = all confirmed episodes that have entered follow-up (onset confirmed). **Recovered share** = episodes with observed detection by analysis horizon \(H = 3650\) days (10y) after onset, divided by episodes with either recovery or censor by H. **Do not** use completed-only tautology. Right-censored non-recoveries stay in denominator |
| Subsequent baseline \(B_1\) | Median of M polls immediately after detection (if ≥M exist and max-span / max-internal-gap OK) |
| **Secular change estimand** | Primary ratchet test: among episodes with known \(B_1\), mean \(\Delta B = B_1 - B_0\). **Negative \(\Delta B\) alone does NOT demonstrate secular ratchet** (half-recovery + mean reversion can lower \(B_1\)). Required: (a) compare \(\Delta B\) to **cadence-preserving null** (block-bootstrap / time-shift of residuals under irregular sampling); (b) report distance-to-floor; (c) predeclare **bounded mean-reverting null** expectation under AR(1)-like residual shuffle that preserves marginal variance. Claim “ratchet” only if \(\Delta B\) more negative than null **and** full-recovery secondary shows same direction |
| Secular over calendar time | Secondary descriptive only: rank-onset vs \(\Delta B\) / interval-censored \(T_{50}\) — no criticality claim |

---

## 6. Censoring, independence, sparse-failure path — **maintained**

| Rule | Value |
|------|--------|
| Right-censor | Series ends or horizon H before detection → `CENSORED_NONRECOVERY`; **no** imputed \(T_{50}\) |
| Min episodes | \(N_{ep} \ge 6\) confirmed for any inferential \(\Delta B\) claim; else `INSUFFICIENT_EPISODES` |
| Min detections | ≥ 4 observed detections to report median interval-censored / detection-time summaries |
| Wilcoxon / KM | Allowed only if independence/overlap spelled out: episodes overlapping in time share polls → use **episode-block** null, not i.i.d. Wilcoxon assumption. Sparse failures: exact/permutation preferred over asymptotic |
| Irregular phase-randomization | **Not** primary null (unspecified under irregular sampling). Primary null = **poll-index block bootstrap** preserving gaps |
| **Pollster-source-dominance exact rule** (`POLLSTER_SOURCE_DOMINANCE`) | Onset poll **and** trough-setting poll share the **same `source`** **and** ≥ **2/3** of polls from onset through detection (or censor) have that **same `source` string** (case-sensitive match after `strip()`) → flag `POLLSTER_SOURCE_DOMINANCE` (formerly `HOUSE_DOMINATED`). Primary analysis **includes** them; predeclared sensitivity **excludes** all `POLLSTER_SOURCE_DOMINANCE` (formerly `HOUSE_DOMINATED`) episodes. Ties on source string use exact equality only — no fuzzy publisher matching |
| Sparse-failure path | If after C1–C6 and threshold freeze, \(N_{ep}<6\) or baseline-invalid rate leaves too few onsets → publish coverage + `DATA_INSUFFICIENT` / `INSUFFICIENT_EPISODES` · **do not** loosen D/K/M/G_max · **do not** impute polls |

---

## 7. Design threats

| Threat | Response |
|--------|----------|
| Irregular sampling | Field dates; **interval-censored primary** + detection-time sensitivity |
| Bounded scale / floor | Flag `x_min <= 5` as `NEAR_FLOOR` |
| Regression to mean | Median baseline; K-of-3 confirm; null comparison mandatory for ratchet claim |
| Right-censor | Explicit; no fabricated durations |
| Researcher flexibility | Thresholds frozen; opaque IDs; no named-event matching in primary |
| Pollster/source dominance | Exact `POLLSTER_SOURCE_DOMINANCE` rule + exclusion sensitivity (no automatic exclusion) |

---

## 8. Outputs (when authorized — not now)

1. Episode table with **interval bounds** for recovery (primary).  
2. Coverage audit C1–C6 + baseline cadence summaries.  
3. Interval-censored survival / ICM summary + **detection-time sensitivity**.  
4. \(\Delta B\) vs null — non-claim block (not criticality/causal/Phase).

---

## 9. Execution authorization

| Step | Status |
|------|--------|
| Protocol draft v0.3 | **DONE — Astra re-review required** |
| Metadata coverage publish | **DONE** |
| Row-level provenance re-verify at run | **REQUIRED** |
| Execute analyses | **FORBIDDEN until ACCEPT + coverage pass** |
| Replace L1-US-v0.1 | **FORBIDDEN** |
| MODEL_CHANGE / Phase family | **NO** |

---

## 10. Paths / Hub

| Artifact | Path |
|----------|------|
| Observatory | `docs/experiments/SRP_EXPERIMENT_002_RECOVERY_RATCHET_PROTOCOL.md` |
| Hub slug | `/docs/srp-experiment-002-recovery-ratchet-protocol` |
| Related | `docs/l1/*` · `data/raw/l1/pew_individual_and_smoothed.csv` · metadata doc |
