# Unit-Root CV-Vintage & DF-GLS Lag-Selection Parity Gaps (TS-1, TS-2)

Records the two flagged time-series parity gaps and the XFAIL tests that now
pin them (repo rule 22: an unsolved-for-now disparity must carry a
`pytest.mark.xfail(strict=True)` with a REAL assertion against the reference
value). See `FUTURE_WORK.md` §"Time-Series Backend (v1.1.0) — Flagged Gaps"
(TS-1 ~line 252, TS-2 ~line 273). Standing rule 2 (never loosen the 1e-6
tolerance) is preserved: the gaps are *captured*, not papered over.

---

## TS-1 — Legacy CV-table vintage (ADF)

OE's `adf()` surfaces arch's **MacKinnon (2010)** critical-value table
(`cv_vintage` label `"MacKinnon (2010)"`). The cross-tool reference tables use a
different vintage:

- **Stata `dfuller`** prints an interpolated **Fuller (1976)** table.
- **R `urca::ur.df`** prints a **banded Fuller (1976)** table.

On the shared 200-obs `ur_input.csv` series (ADF, lags=0), the 5% quantile:

| trend | OE MacKinnon (2010) | Stata Fuller | R urca Fuller | max |diff| |
|-------|---------------------|--------------|---------------|-----------|
| c     | -2.8761761          | -2.8834      | -2.88         | ~7.2e-3   |
| ct    | -3.4327862          | —            | -3.43         | ~2.8e-3   |

All well above the 1e-6 ceiling. The **statistic** (asserted vs R `urca`) and
the **MacKinnon (1994) p-value** (asserted vs Stata) are the genuine cross-tool
agreement points and remain real passing tests — only the tabulated quantiles
diverge, which is a finite-sample table-reproduction task, not a numerical bug.

XFAIL tests (assert OE CV == reference CV at 5%, expected to diverge):

- `tests/stata/tests/test_timeseries_adf_pp.py::TestADFStata::test_cv5_matches_stata_fuller`
- `tests/r/tests/test_timeseries_urca.py::TestADFCriticalValueVintageGap::{test_c_cv5_matches_urca,test_ct_cv5_matches_urca}`

Stata CVs are now committed in `ur_adf_c.dta` (fields `cv_1/cv_5/cv_10`,
generated by `ur_adf_c.do`); R CVs already lived in `ur_adf_c.json` /
`ur_adf_ct.json` (`cv1/cv5/cv10`). The `test_cv_vintage_label` regression
guards (same-backend) are untouched.

**Resolution path:** port the Fuller (1976) / ERS (1996) vintage tables behind
a `cv_vintage` selector; when landed, the xfails flip to xpass and must be
converted to real passing assertions.

---

## TS-2 — DF-GLS lag selection (arch AIC vs Stata Ng-Perron)

OE's `dfgls()` uses **arch's AIC** lag selection on the GLS-detrended series;
Stata `dfgls` uses **Ng-Perron** sequential-t / SIC / MAIC. The GLS detrending
(ERS cbar) and the default max-lag ceiling match; the selection *method* does
not, so OE's reported statistic cannot equal Stata's in general.

Source-verified Stata `dfgls y, notrend` on `ur_input.csv` (captured in
`tests/stata/generate-fixtures/ur_dfgls_c.do`):

| selector          | lag | DF-GLS mu   |
|-------------------|-----|-------------|
| OE arch AIC       | 0   | -1.2045709  |
| Stata seq-t       | 0   | -1.2045710  | (coincidental agreement here)
| Stata SIC         | 1   | -1.1362432  |
| Stata MAIC        | 1   | -1.1362432  |

**Footgun (rule 18):** on THIS series Stata's *seq-t* rule picks lag 0 and thus
agrees with AIC to ~1e-9 — that coincidence is NOT the parity claim. Stata's
*reported optima* are SIC/MAIC (both lag 1), which differ. The xfails therefore
assert against Stata's SIC/MAIC lag (`r(siclag)`=1) and its statistic
(-1.1362432), not the seq-t coincidence. A future generator that switches the
reference to seq-t would make these xpass for the wrong reason — do not.

XFAIL tests (in the existing arch-identity file; the exact OE-vs-arch identity
tests stay passing):

- `tests/non_stata_nor_r/test_timeseries_dfgls.py::TestDFGLSStataLagSelectionGap::test_selected_lag_matches_stata_ngperron`
  — asserts `oe.dfgls(...).lags == r(siclag)` (0 vs 1).
- `...::test_statistic_matches_stata_ngperron` — asserts OE stat == Stata
  SIC/MAIC-lag stat (diff ~6.8e-2).

Fixture: `tests/stata/fixtures/expected/ur_dfgls_c.dta` (`stat_siclag`,
`stat_lag0`, `cv5_lag0`, `siclag`, `maiclag`), generated by `ur_dfgls_c.do`.

**Resolution path:** implement `method="ng-perron"` (sequential-t / SIC / MAIC)
gated behind an explicit arg (arch-AIC stays default). When landed, the xfails
flip and must become real passing assertions.
