# ROT stack moved main -> rot-box (Manager, 8 Oct 2026 ~19:50 Bangkok, board #15, Ben approved)

## What moved (rot-box 178.128.50.12 / 10.104.0.7, same paths, same schedules, root crontab)
- rotation.py (:20), rotmap.py --dry (every 4 h), rh_drill.py (:15), chains/chains.py (:35), chains/closes.py (:05), verify_rot.py (:50), rotfix.py (every 10 min, now heals the jobs on rot-box), rotdash_cron.sh (:20, :52 -> rot/map-data.json).
- Code copied: /opt/rotation, /opt/rotdash. On rot-box /opt/common/alertgate.py is a log-only stub (Telegram only from the leader box).

## How main still serves the pages
- main cron every 2 min: `/opt/rotsync/sync.sh`. Pushes inputs to rot-box (stonkfun_top.csv, chain.json, robinhood-indices/market.json, hx-c9ois/rot/*) and pulls outputs back (chains.json, closes.json, rotation.json, rotmap.json, rh_drill.json, hx-c9ois/rot/map-data.json). A pulled file replaces main's copy only if newer and valid JSON.
- Key: main's /opt/pbsync/pbkey is allowed on rot-box only from main (from= restriction).
- Guard mesh on main: 7 new checks "L ROT ... (Manager)" (sync every 10 min; each output 2 h, rotmap 6 h). Fix = run sync; Telegram only if still stale after 30-60 min.

## Off on main (reversible)
- Cron lines marked "MOVED to rot-box 8 Oct (board #15, Manager)"; rotfix.timer and verify_rot.timer disabled + /opt/guard/hold/. Backups: /root/crontab.bak_mgr15_*.
- Retired (they only sent Telegram): rotation/fresh.py, rotation/chains/stale.py. Replaced by the mesh checks above.

## Stayed on main (on purpose)
- giver reader (tg_read.py + giver_fix): it logs in to Telegram as a user; a new IP can kill the session. Hourly, light.
- robinhood-indices (market.json every 5 min): the public page and rh_drill read it on main; moving it adds a sync for no gain.
- Owner of both until ROT has a board role: Manager.

## Undo
Uncomment the main cron lines, `systemctl enable --now rotfix.timer verify_rot.timer`, remove the hold files, comment the rot-box lines and the rotsync cron line.
