# src/atm — Core Engine

## Purpose

Capture → detect → decide → notify. The motor M2D: ia frame-uri de pe chart-ul
TradeStation, clasifică bulina/strip-ul de culoare, rulează FSM-ul de trading și
emite alerte. Pure-logic modules (FSM, config) nu importă cv2/numpy; vision &
capture stau izolate.

## Ownership

Tot codul Python al aplicației sub `src/atm/`, cu excepția `notifier/` (vezi
child index). CLI-ul (`main.py`) orchestrează modulele; e sursa de adevăr pentru
flag-urile `atm run/debug/calibrate`.

## Local Contracts

- **`state_machine.py`** — FSM pur stdlib, **fără cv2/numpy**. Stările M2D
  (PRIMED → ARMED → light_*). Orice schimbare aici cere test în
  `tests/test_state_machine.py` + scenariu în `calibration/scenarios.json`.
- **`config.py`** — dataclass-uri frozen, validare la load (fail fast). Schema
  TOML e definită aici; modific schema ⇒ actualizez `configs/AGENTS.md`.
- **`detector.py`** — debounce + rolling window peste clasificarea per-ciclu.
- **`scheduler.py`** — asyncio task; capture + cv2 rulează în `to_thread`
  (nu bloca event-loop-ul). Decizia 13: scheduler cheamă `capture()` direct,
  NU prin `Detector`. Pornit pe muchia `0→1` `n_primed_global`, oprit pe fire/
  cooled. **La `market_closed`** (`_handle_market_closed` în `main.py`) e oprit
  forțat + FSM resetat la IDLE, ca o bulină `dark_*` rămasă PRIMED să nu trimită
  screenshot-uri la nesfârșit după închidere și să permită repornirea curată.
- **`vision.py`** — primitive partajate: crop ROI, perceptual hash, interpolare
  pixel↔preț, Hough. Singurul loc unde trăiesc primitivele cv2 reutilizabile.
- **`canary.py`** — drift de layout via phash vs `baseline_phash`. Re-anchor prin
  `/rebase` (vezi `notifier/AGENTS.md`), nu hardcoda hash-uri aici.
- **`calibrate.py`** / **`labeler.py`** — Tk wizard; safe la import headless
  (Tk se importă lazy). Vezi gotcha de saturație în `calibration/AGENTS.md`.
- **`levels.py`** — Phase-B: detectează linii SL (roșu) / TP (verde).
- **`journal.py`** / **`report.py`** — store JSONL append-only + raport săptămânal.

## Work Guidance

- Nu introduce import cv2/numpy în `state_machine.py` sau `config.py` — testele
  rulează headless pe Linux/WSL și pică altfel.
- Heavy I/O & cv2 mereu în `asyncio.to_thread` din scheduler/main.
- Culorile vivid sunt near-pure saturation (vezi gotcha). Clasificatorul întoarce
  `UNKNOWN` peste `tolerance` — nu crește tolerance fără validate-calibration.

## Verification

```bash
pytest -q                                    # toată suita
pytest tests/test_state_machine.py -v        # FSM
atm debug --delay 5                          # one-shot capture + detect live
```

## Child DOX Index

- **`notifier/`** → `src/atm/notifier/AGENTS.md` — Discord/Telegram/fanout +
  comenzile live (`/ss`, `/rebase`, `/resume`, …).
