SPB Git

spb/wp41_uqo

Public

WP41: release gate (27 tests), phase 9 report, CI test fix, empty-split guard

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed (Nov 3, 2026) parent bab8603 Browse files

3 changed files +39 −1

added docs/PHASE_9_REPORT.md +35 −0
@@ -0,0 +1,35 @@
1 +# PHASE 9 — Release (2026-11-03)
2 +
3 +## Package
4 +- Repository `wp41_uqo` (git, `origin = gitsrv:srv/git/wp41_uqo.git`, branch `main`), installable package `chronos_x`
5 + (`pyproject.toml`, `make install`), CLI `chronos-x` (forecast at one origin from a saved model and a cached grid).
6 +- Configs: `pilot`, `feasibility`, `main`, `ablations`, `baselines`, `final`, `synthetic_smoke`.
7 +- Scripts: audit → universe → coverage → download → experiment (3 stages) → benchmark → pairwise/economic → evaluate →
8 + figures → static tables → references; `node_run.sh` for detached runs; `make_synthetic.py` for license-free fixtures.
9 +- Docs: `DATA_CARD`, `MODEL_CARD`, `REPRODUCIBILITY`, `LICENSE`, `OPERATIONS`, `PHASE_0..9_REPORT`, `README`, `CLAUDE.md`.
10 +- Paper: `paper/main.tex` + sections + generated tables/figures/macros + verified `references.bib` + `main.pdf`.
11 +
12 +## License review (FirstRate Data private use)
13 +Committed / released: code, configs, manifests (tickers and selection rules), aggregate scores (summaries, leaderboards,
14 +comparisons, pairwise, subgroups, calibration), figures of scores, benchmark, API audit (no bars), coverage audit
15 +(bar counts per instrument — allowed aggregate), synthetic fixtures, the manuscript.
16 +Excluded by `.gitignore` and kept only on the compute node / laptop mirror: Parquet bars, grids, `origins_*.csv`
17 +(realised returns per origin), `pred_*.npz`, `per_origin_*.npz`, checkpoints. Checked with `git ls-files | grep -E 'parquet|origins_|pred_|\.pt$'`
18 +(empty). Attribution line in the paper: "Intraday data: FirstRate Data (private license), accessed through FinData OS."
19 +
20 +## Reproducibility instructions
21 +`docs/REPRODUCIBILITY.md` (environment, license-free example, full study command list in order, seeds, artifact map).
22 +The synthetic example reproduces the software path end to end in about three minutes on an Apple-silicon laptop
23 +and is also the slow integration test.
24 +
25 +## Gates at release
26 +- Offline tests: 27 passed (unit 6, synthetic 5, leakage 5, numerical 10, slow synthetic end-to-end pipeline 1), 5 live tests skipped without `WP41_LIVE` — `results/logs/release_tests.out`, 2026-11-03.
27 +- Live contract tests: 5/5 on 2026-11-02 (`WP41_LIVE=1`).
28 +- Manuscript: `latexmk` exit 0, 0 undefined references/citations, every table and figure generated from saved results.
29 +- Figures/tables ↔ outputs: `paper/tables/*.tex` and `paper/figures/*` regenerated from `results/metrics` immediately before
30 + the final build (`scripts/evaluate.py`, `make_figures.py`, `make_static_tables.py`); macros count 3 468.
31 +
32 +## Not done / deferred (honest list)
33 +- SSRN deposit and www.spboucher.ai entry (owner's decision).
34 +- Extended-hours experiments, delisted-instrument backfill, quote data, mixed precision, Large (50–100 M) preset.
35 +- Foundation-model baselines (Chronos/TimesFM), iTransformer, EGARCH.
modified scripts/run_experiment.py +3 −0
@@ -53,6 +53,9 @@ def setup(a):
53 53 idx = P.build_indices(dirs, cfg["splits"], wcfg, d["warmup_sessions"], tr["origins_per_session"], ev["stride"], tr["seed"],
54 54 embargo_sessions=cfg["splits"].get("embargo_sessions", 1))
55 55 tag = a.eval_split + ("_heldout" if a.heldout else "")
56 + empty = [k for k, v in idx.items() if len(v) == 0 and k in ("train", a.eval_split)]
57 + if empty:
58 + raise SystemExit(f"no eligible origins for split(s) {empty}: check splits/data window in {a.config}")
56 59 return cfg, exp, out, man, rows, dirs, idx, tag
57 60
58 61
modified tests/integration/test_synthetic_pipeline.py +1 −1
@@ -17,8 +17,8 @@ def test_synthetic_pipeline(tmp_path):
17 17 capture_output=True, text=True, cwd=ROOT)
18 18 assert r.returncode == 0, r.stderr[-2000:]
19 19 cfg = (ROOT / "configs" / "synthetic_smoke.yaml").read_text()
20 − cfg = cfg.replace("cache: data/synthetic/cache", f"cache: {cache}").replace('end: "2024-05-31"', 'end: "2024-04-30"')
21 20 cfg = cfg.replace('train_end: "2024-04-05", val_end: "2024-04-30", test_end: "2024-05-31"', 'train_end: "2024-03-15", val_end: "2024-04-05", test_end: "2024-04-30"')
21 + cfg = cfg.replace("cache: data/synthetic/cache", f"cache: {cache}").replace('end: "2024-05-31"', 'end: "2024-04-30"')
22 22 cfg = cfg.replace("max_steps: 60", "max_steps: 20").replace("name: synthetic_smoke", "name: synthetic_ci")
23 23 cfg = cfg.replace(" - {name: mlp, kind: mlp}\n", "")
24 24 cfg_path = tmp_path / "ci.yaml"; cfg_path.write_text(cfg)
25 25
Menu

Theme