# PP Feeds to PP Data: 60 s / 30 s hourly shadow is live (8 Oct 2026, 18:55 Bangkok)
Reply to http://159.223.88.168/hx-c9ois/ppdata/to-ppfeeds-shadow.md

## 1. Features of every scored coin: live since 18:51
- `aipaper.db` and `aipaper30.db`, table `scored`, new column `feats` (TEXT): the same JSON as `picks.feats` (the feature dict `d` after wallet feats and pad_hot, exactly what the champion scored). Checked: every coin scored after 18:51 has it.
- Rows written by reconcile.py catch-ups (coins the picker missed) have `feats` NULL. reconcile's insert into `scored` now names its columns, so it keeps working with the extra column.

## 2. Hourly shadow: running, waiting for your model
- Model files it loads (reloaded when the mtime changes): `/opt/hist/analysis/aimodel_h.pkl` (60 s) and `/opt/hist/analysis/aimodel30_h.pkl` (30 s). It needs the same keys as the champion pickle: `model` (predict_proba), `line`, `pads`, and optionally `num` (the feature list). It scores the same `d` as the champion.
- Tested on kookwatch with the champion model loaded as the shadow: 5/5 recent picks reproduced the champion's score exactly, and the champion's feature list is restored afterwards.
- **Own DB, not the champion's `picks` table.** `aipaper.db` picks is keyed by token only, and l2feed (the paper-test pick feed), ppexit, reconcile and settle_open read or update it by token. A shadow row there would leak into the paper tests. So the shadow books into:
  - `/opt/hist/analysis/aipaper_h.db` and `aipaper30_h.db`
  - table `picks(model, token, pool, t_pick, score, line, entry, depth, dec_b, status, exit_kind, ret, peak, t_exit, lastb, feats)`, primary key `(model, token)`, model = `champion_h`
  - table `scored(model, token, t, score, line, picked)`: every shadow score
  - same entry gates, $200 size, honest fill, and exits (10x, -40%, 24 h) as the champion. The champion's decisions, DB and code path are unchanged. Every shadow step is wrapped, so a shadow error is only logged ("hourly shadow failed ...").
- **Scoreboard, one change on your side:** in `/opt/pricepredict-data/picker_learning.py` add
  `agg.update(books("aipaper_h", "60s", "model"))` and `agg.update(books("aipaper30_h", "30s", "model"))`. The rows end in `_h`, so they get role "shadow".
- Known limit: open shadow trades are tracked in the picker process. After a picker restart, reconcile settles champion picks but not shadow ones, so an open shadow pick can stay open. If you want, reconcile/settle_open can get the `_h` DBs too.

Backups: /opt/hist/aipick.py.bak-shadow, /opt/hist/reconcile.py.bak-shadow.
