DOX sistem

This commit is contained in:
2026-06-13 11:51:36 +03:00
parent bb241bf050
commit 39f2439246
8 changed files with 347 additions and 139 deletions

108
AGENTS.md
View File

@@ -1,90 +1,54 @@
# ATM — Automated Trading Monitor # ATM — Automated Trading Monitor
Personal Faza-1 tool for the M2D strategy. Python 3.11+. Personal Faza-1 tool pentru strategia M2D. Python 3.11+.
> Acest repo folosește **DOX**: arborele de `AGENTS.md` de mai jos sunt contracte
> de lucru pentru subarborii lor. Înainte să editezi un path, coboară din rădăcină
> citind fiecare `AGENTS.md` întâlnit. După o schimbare semnificativă, fă un **DOX
> pass**: actualizează `AGENTS.md`-ul cel mai apropiat care „deține" zona + indexul
> părintelui, șterge ce devine învechit.
## Quick Reference ## Quick Reference
```bash ```bash
pip install -e ".[windows]" # Windows: live capture pip install -e ".[windows]" # Windows: live capture
pip install -e ".[dev]" # Linux/macOS: dev + tests (WSL: create venv first) pip install -e ".[dev]" # Linux/macOS: dev + tests (WSL: venv întâi)
cp .env.example .env # secretele Discord/Telegram (vezi README §Secrets) cp .env.example .env # secretele Discord/Telegram (vezi README §Secrets)
atm calibrate # Tk wizard atm calibrate # Tk wizard
atm debug --delay 5 # one-shot capture + detect atm debug --delay 5 # one-shot capture + detect
atm validate-calibration calibration/calibration_labels.json # offline color gate atm validate-calibration calibration/calibration_labels.json # color gate offline
atm run --start-at 16:30 --stop-at 23:00 # live session atm run --start-at 16:30 --stop-at 23:00 # live session
atm run --tz America/New_York --oh-start 09:30 --oh-stop 16:00 # NYSE window override atm run --tz America/New_York --oh-start 09:30 --oh-stop 16:00 # NYSE window
pytest -q # 230+ tests (core + 8 scenarii regresie + env loader) pytest -q # 230+ teste
pytest tests/test_scenarios_regression.py -v # FSM pe imagini reale
``` ```
## Codex sandbox/tooling notes ## DOX Protocol
On this Windows checkout, do not assume `rg` or the global `python` has project deps. - **Citire** — traversează root → path-ul țintă, citind fiecare `AGENTS.md`. Dacă
Use the repo venv for diagnostics that need Pillow/OpenCV: un părinte indexează un copil al cărui scope conține path-ul, citește copilul și
continuă de acolo.
- **Editare** — `AGENTS.md`-ul cel mai apropiat = contract local; părinții = reguli
globale. Un copil nu poate slăbi o constrângere impusă de un părinte.
- **Update (closeout)** — re-verifică path-urile schimbate față de lanțul DOX;
actualizează doc-urile care le dețin + indexurile afectate; șterge textul învechit;
rulează verificarea relevantă.
```powershell ## Durable Rules (repo-wide)
.\.venv\Scripts\python.exe scripts\inspect_image_pixels.py 6033117943853423831.jpg
.\.venv\Scripts\python.exe scripts\inspect_image_pixels.py 6033117943853423831.jpg --point 1780 725
```
If `rg` is missing, use PowerShell fallbacks: - **Pure-logic fără cv2/numpy** în `state_machine.py` și `config.py` (testele rulează
`Get-ChildItem -Recurse -File src,tests,scripts | Select-String -Pattern "needle"`. headless). cv2/I/O greu mereu în `asyncio.to_thread`.
If a command fails due to sandbox permissions and is required for the task, rerun it - **Secretele doar din env** (`.env`), niciodată în TOML sau cod.
with an escalation request instead of stopping the investigation without a verdict. - **Mereu** `atm validate-calibration` după recalibrare (palette gotcha — vezi
`calibration/AGENTS.md`).
- Modul nou în `src/atm/``test_<modul>.py` corespondent.
## Calibration corpus > Skill routing (Claude Code) trăiește în [`CLAUDE.md`](CLAUDE.md) — sursa canonică.
`calibration/` — persistent, auto-suficient. Conține: ## Child DOX Index
- `frames/` — PNG-uri raw `{ts}_{color}.png` scrise **automat** de live loop la fiecare schimbare de culoare (filename = culoarea detectată, poate fi greșită)
- `calibration_labels.json` — ground truth **manual** (gate offline pentru `atm validate-calibration`)
- `scenarios.json` — secvențe FSM pentru `tests/test_scenarios_regression.py`
Workflow după sesiune: review frame-urile noi din `frames/`, adaugi entry-uri în `calibration_labels.json` cu culoarea pe care ai văzut-o TU pe chart (nu neapărat cea din filename), rulezi `atm validate-calibration`. - **`src/atm/`** → `src/atm/AGENTS.md` — motorul: capture/detect/FSM/scheduler/
vision/canary/config. (copil: `notifier/`)
## Telegram commands (live) - **`tests/`** → `tests/AGENTS.md` — suita de teste + regresie FSM.
- **`calibration/`** → `calibration/AGENTS.md` — corpus culori + scenarii + palette gotcha.
`/ss` `/status` `/pause` `/resume` `/rebase` `/3` (interval min) `/stop` - **`configs/`** → `configs/AGENTS.md` — schema TOML (operating_hours, alerts, canary).
- **`scripts/`** → `scripts/AGENTS.md` — diagnostic + note sandbox Windows/venv.
- `/rebase` — propune un `baseline_phash` nou pentru canary: capturează frame, crop pe `canary.roi`, phash → trimite screenshot adnotat (cerc roșu pe ROI) cu old/new hash + distance. `/rebase confirm` în ≤180s aplică: rescrie `baseline_phash` în TOML-ul activ (păstrează comentariile), mirror în `cfg` la runtime, clear `user_paused` + `drift_paused`. Fără confirm, nimic nu se modifică. Folosește-l când layout-ul TS s-a schimbat intenționat și vrei să re-ancorezi canary-ul fără `atm calibrate` full.
- `/ss` — verify multi-bulină: adnotează top-3 buline din `dot_roi` (cerc roșu gros pe pick-ul FSM, cercuri colorate subțiri pe vecini) + caption cu clasificarea fiecăreia (nume, RGB, distanță, confidence) + `config: {version}`. Cercul colorat folosește `cfg.colors[name].rgb` la runtime — DRY cu paleta activă.
- `/resume` clears BOTH user pause and canary drift-pause in one shot (`/resume force` still accepted as legacy alias). Trimite un singur Alert cu screenshot adnotat inline (capture rulează **înainte** de clearing state → zero race cu FSM tick-uri). Dacă capture eșuează, title conține `⚠️ captură eșuată` și resume-ul se execută oricum.
- Drift-pause emits a single Telegram alert on transition. While paused, `/set_interval` is refused and `/ss` captions warn that detection is off.
- Heartbeat shows `⚠️ pauzat (drift)` instead of `activ` while canary is paused.
## Operating-hours config
`[options.operating_hours]` in TOML: `enabled`, `timezone` (NYSE local, e.g. `America/New_York`), `weekdays`, `start_hhmm`, `stop_hhmm`. Timezone validated at load; `_tz_cache` reused per tick. Boundary crossings log `market_open` / `market_closed` and notify once. Startup in-window is silent.
## Phase-skip backstop
`[options.alerts] fire_on_phase_skip = true` (default) — ARMED→light_* direct (dark_* missed) still emits a `⚠️ PHASE SKIP` alert using FSM lockout to suppress spam.
## Palette gotcha (2026-04-21 recalibration)
TradeStation M2D indicators paint the four bright colors at near-pure saturation:
turquoise `(0,253,253)`, yellow `(253,253,0)`, light_green `(0,255,0)`, light_red `(255,0,0)`.
If Tk-wizard calibration samples a slightly desaturated pixel, classifier returns `UNKNOWN`
(distance > tolerance=60) → FSM never sees trigger → stuck in PRIMED → scheduler polls
forever. Always run `atm validate-calibration calibration/calibration_labels.json` after
recalibrating. Current active config: `configs/2026-04-21-recalib.toml`.
## Skill routing
When the user's request matches an available skill, ALWAYS invoke it using the Skill
tool as your FIRST action. Do NOT answer directly, do NOT use other tools first.
The skill has specialized workflows that produce better results than ad-hoc answers.
Key routing rules:
- Product ideas, "is this worth building", brainstorming → invoke office-hours
- Bugs, errors, "why is this broken", 500 errors → invoke investigate
- Ship, deploy, push, create PR → invoke ship
- QA, test the site, find bugs → invoke qa
- Code review, check my diff → invoke review
- Update docs after shipping → invoke document-release
- Weekly retro → invoke retro
- Design system, brand → invoke design-consultation
- Visual audit, design polish → invoke design-review
- Architecture review → invoke plan-eng-review
- Save progress, checkpoint, resume → invoke checkpoint
- Code quality, health check → invoke health

View File

@@ -1,75 +1,32 @@
# ATM — Automated Trading Monitor # ATM — Automated Trading Monitor (Claude Code)
Personal Faza-1 tool for the M2D strategy. Python 3.11+. Personal Faza-1 tool pentru strategia M2D. Python 3.11+.
## Quick Reference ## Sursa de adevăr: arborele DOX
```bash Documentația operațională trăiește în arborele de `AGENTS.md` (format DOX), **nu**
pip install -e ".[windows]" # Windows: live capture aici. Înainte să editezi un path, coboară din rădăcină citind fiecare `AGENTS.md`
pip install -e ".[dev]" # Linux/macOS: dev + tests (WSL: create venv first) întâlnit; după o schimbare semnificativă, fă un DOX pass (actualizează doc-ul care
cp .env.example .env # secretele Discord/Telegram (vezi README §Secrets) deține zona + indexul părintelui).
atm calibrate # Tk wizard
atm debug --delay 5 # one-shot capture + detect
atm validate-calibration calibration/calibration_labels.json # offline color gate
atm run --start-at 16:30 --stop-at 23:00 # live session
atm run --tz America/New_York --oh-start 09:30 --oh-stop 16:00 # NYSE window override
pytest -q # 230+ tests (core + 8 scenarii regresie + env loader)
pytest tests/test_scenarios_regression.py -v # FSM pe imagini reale
```
## Calibration corpus Start: [`AGENTS.md`](AGENTS.md) (root — Quick Reference, reguli globale, index copii).
Copii: `src/atm/` · `src/atm/notifier/` · `tests/` · `calibration/` · `configs/` · `scripts/`.
`calibration/` — persistent, auto-suficient. Conține:
- `frames/` — PNG-uri raw `{ts}_{color}.png` scrise **automat** de live loop la fiecare schimbare de culoare (filename = culoarea detectată, poate fi greșită)
- `calibration_labels.json` — ground truth **manual** (gate offline pentru `atm validate-calibration`)
- `scenarios.json` — secvențe FSM pentru `tests/test_scenarios_regression.py`
Workflow după sesiune: review frame-urile noi din `frames/`, adaugi entry-uri în `calibration_labels.json` cu culoarea pe care ai văzut-o TU pe chart (nu neapărat cea din filename), rulezi `atm validate-calibration`.
## Telegram commands (live)
`/ss` `/status` `/pause` `/resume` `/rebase` `/3` (interval min) `/stop`
- `/rebase` — propune un `baseline_phash` nou pentru canary: capturează frame, crop pe `canary.roi`, phash → trimite screenshot adnotat (cerc roșu pe ROI) cu old/new hash + distance. `/rebase confirm` în ≤180s aplică: rescrie `baseline_phash` în TOML-ul activ (păstrează comentariile), mirror în `cfg` la runtime, clear `user_paused` + `drift_paused`. Fără confirm, nimic nu se modifică. Folosește-l când layout-ul TS s-a schimbat intenționat și vrei să re-ancorezi canary-ul fără `atm calibrate` full.
- `/ss` — verify multi-bulină: adnotează top-3 buline din `dot_roi` (cerc roșu gros pe pick-ul FSM, cercuri colorate subțiri pe vecini) + caption cu clasificarea fiecăreia (nume, RGB, distanță, confidence) + `config: {version}`. Cercul colorat folosește `cfg.colors[name].rgb` la runtime — DRY cu paleta activă.
- `/resume` clears BOTH user pause and canary drift-pause in one shot (`/resume force` still accepted as legacy alias). Trimite un singur Alert cu screenshot adnotat inline (capture rulează **înainte** de clearing state → zero race cu FSM tick-uri). Dacă capture eșuează, title conține `⚠️ captură eșuată` și resume-ul se execută oricum.
- Drift-pause emits a single Telegram alert on transition. While paused, `/set_interval` is refused and `/ss` captions warn that detection is off.
- Heartbeat shows `⚠️ pauzat (drift)` instead of `activ` while canary is paused.
## Operating-hours config
`[options.operating_hours]` in TOML: `enabled`, `timezone` (NYSE local, e.g. `America/New_York`), `weekdays`, `start_hhmm`, `stop_hhmm`. Timezone validated at load; `_tz_cache` reused per tick. Boundary crossings log `market_open` / `market_closed` and notify once. Startup in-window is silent.
## Phase-skip backstop
`[options.alerts] fire_on_phase_skip = true` (default) — ARMED→light_* direct (dark_* missed) still emits a `⚠️ PHASE SKIP` alert using FSM lockout to suppress spam.
## Palette gotcha (2026-04-21 recalibration)
TradeStation M2D indicators paint the four bright colors at near-pure saturation:
turquoise `(0,253,253)`, yellow `(253,253,0)`, light_green `(0,255,0)`, light_red `(255,0,0)`.
If Tk-wizard calibration samples a slightly desaturated pixel, classifier returns `UNKNOWN`
(distance > tolerance=60) → FSM never sees trigger → stuck in PRIMED → scheduler polls
forever. Always run `atm validate-calibration calibration/calibration_labels.json` after
recalibrating. Current active config: `configs/2026-04-21-recalib.toml`.
## Skill routing ## Skill routing
When the user's request matches an available skill, ALWAYS invoke it using the Skill Când cererea userului se potrivește cu un skill disponibil, invocă-l cu tool-ul
tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. Skill ca PRIMĂ acțiune. NU răspunde direct, NU folosi alte tool-uri întâi.
The skill has specialized workflows that produce better results than ad-hoc answers. Skill-ul are workflow-uri specializate care produc rezultate mai bune.
Key routing rules: - Idei de produs, „merită construit", brainstorming → `office-hours`
- Product ideas, "is this worth building", brainstorming → invoke office-hours - Bug-uri, erori, „de ce e stricat", 500`investigate`
- Bugs, errors, "why is this broken", 500 errors → invoke investigate - Ship, deploy, push, PR → `ship`
- Ship, deploy, push, create PR → invoke ship - QA, testează site-ul, găsește bug-uri → `qa`
- QA, test the site, find bugs → invoke qa - Code review, verifică diff-ul → `review`
- Code review, check my diff → invoke review - Update docs după ship → `document-release`
- Update docs after shipping → invoke document-release - Retro săptămânal → `retro`
- Weekly retro → invoke retro - Design system, brand → `design-consultation`
- Design system, brand → invoke design-consultation - Audit vizual, design polish → `design-review`
- Visual audit, design polish → invoke design-review - Architecture review → `plan-eng-review`
- Architecture review → invoke plan-eng-review - Save progress, checkpoint, resume → `checkpoint`
- Save progress, checkpoint, resume → invoke checkpoint - Code quality, health check → `health`
- Code quality, health check → invoke health

45
calibration/AGENTS.md Normal file
View File

@@ -0,0 +1,45 @@
# calibration — Calibration Corpus
## Purpose
Corpus persistent, auto-suficient pentru clasificarea culorilor și regresia FSM.
Sursa de adevăr pentru ce „vede" detectorul.
## Ownership
`frames/`, `calibration_labels.json`, `scenarios.json`.
## Local Contracts
- **`frames/`** — PNG raw `{ts}_{color}.png` scrise **automat** de live loop la
fiecare schimbare de culoare. Filename = culoarea detectată, **poate fi greșită**.
Nu trata filename-ul ca ground truth.
- **`calibration_labels.json`** — ground truth **manual**. Gate offline pentru
`atm validate-calibration`. Pui culoarea pe care ai văzut-o TU pe chart, nu cea
din filename.
- **`scenarios.json`** — secvențe FSM pentru `tests/test_scenarios_regression.py`.
## Work Guidance
**Workflow după sesiune:** review frame-urile noi din `frames/` → adaugi entry-uri
în `calibration_labels.json` cu culoarea reală → rulezi validate-calibration.
### Palette gotcha (recalibrare 2026-04-21)
Indicatorii M2D pictează cele patru culori bright la saturație near-pure:
turquoise `(0,253,253)`, yellow `(253,253,0)`, light_green `(0,255,0)`,
light_red `(255,0,0)`. Dacă Tk-wizard eșantionează un pixel ușor desaturat,
clasificatorul întoarce `UNKNOWN` (distanță > tolerance=60) → FSM nu vede trigger
→ stuck în PRIMED → scheduler polls la infinit. **Mereu** rulează
validate-calibration după recalibrare. Config activ: vezi `configs/current.txt`.
## Verification
```bash
atm validate-calibration calibration/calibration_labels.json # color gate offline
pytest tests/test_scenarios_regression.py -v
```
## Child DOX Index
(none — leaf)

53
configs/AGENTS.md Normal file
View File

@@ -0,0 +1,53 @@
# configs — TOML Configs
## Purpose
Configurațiile de rulare (ROI-uri, paletă, canary baseline, operating-hours,
alerts). Schema e definită și validată în `src/atm/config.py` (fail fast la load).
## Ownership
`*.toml` + `current.txt` (pointer la config-ul activ) + `example.toml` (template).
## Local Contracts
- **`current.txt`** — o singură linie: numele fișierului TOML activ. `atm run`
fără `--config` îl folosește pe acesta.
- Secretele **NU** stau în TOML — vin din env (`.env`). Vezi `notifier/AGENTS.md`.
- Schema (dataclass-uri în `config.py`): `dot_roi`, `colors{name→{rgb,tolerance}}`,
`canary{roi, baseline_phash}`, y-axis calib, `[options.operating_hours]`,
`[options.alerts]`. Modifici schema în `config.py` ⇒ actualizezi `example.toml`
+ acest doc în același commit.
### `[options.operating_hours]`
`enabled`, `timezone` (NYSE local, ex. `America/New_York`), `weekdays`,
`start_hhmm`, `stop_hhmm`. Timezone validat la load; `_tz_cache` reutilizat per
tick. Boundary crossings logează `market_open`/`market_closed` și notifică o dată.
Startup in-window e silent.
### `[options.alerts]`
`fire_on_phase_skip = true` (default) — tranziția ARMED→light_* directă (dark_*
ratat) emite totuși un `⚠️ PHASE SKIP`, cu FSM lockout ca să suprime spam-ul.
### `canary.baseline_phash`
Re-anchor prin comanda `/rebase confirm` (rescrie automat aici, păstrând
comentariile). Nu edita manual decât dacă știi exact ce faci.
## Work Guidance
- Config nou = copiezi `example.toml`, numești `{data}-{tag}.toml`, pui numele în
`current.txt`. Nu șterge config-urile vechi (audit trail al recalibrărilor).
## Verification
```bash
atm validate-calibration calibration/calibration_labels.json
atm debug --delay 5 # confirmă că config-ul activ încarcă & detectează
```
## Child DOX Index
(none — leaf)

42
scripts/AGENTS.md Normal file
View File

@@ -0,0 +1,42 @@
# scripts — Diagnostic Scripts
## Purpose
Scripturi ad-hoc de diagnostic/repro rulate manual. Nu fac parte din suita de
teste și nu sunt importate de aplicație.
## Ownership
`diag_strip_detection.py`, `diag_strip_fixes.py`, `inspect_image_pixels.py`,
`repro_ss_resume.py`.
## Local Contracts
- **`inspect_image_pixels.py`** — citește RGB la coordonate dintr-o imagine.
Util pentru a verifica saturația pixelilor (vezi palette gotcha în
`calibration/AGENTS.md`).
- **`repro_ss_resume.py`** — repro pentru fluxul `/ss` + `/resume`.
## Work Guidance — Sandbox/tooling (Windows checkout)
Nu presupune că `rg` sau `python`-ul global au dependențele proiectului.
Pentru diagnostic care cere Pillow/OpenCV folosește venv-ul repo:
```powershell
.\.venv\Scripts\python.exe scripts\inspect_image_pixels.py 6033117943853423831.jpg
.\.venv\Scripts\python.exe scripts\inspect_image_pixels.py 6033117943853423831.jpg --point 1780 725
```
Dacă `rg` lipsește, fallback PowerShell:
`Get-ChildItem -Recurse -File src,tests,scripts | Select-String -Pattern "needle"`.
Dacă o comandă pică din permisiuni sandbox și e necesară, rerulează cu escalare
în loc să oprești investigația fără verdict.
## Verification
Rulează scriptul vizat manual și inspectează output-ul; nu există teste automate
pentru `scripts/`.
## Child DOX Index
(none — leaf)

55
src/atm/AGENTS.md Normal file
View File

@@ -0,0 +1,55 @@
# 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`.
- **`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`, …).

View File

@@ -0,0 +1,55 @@
# src/atm/notifier — Alerting & Live Commands
## Purpose
Tot ce iese din proces către exterior: alerte Discord/Telegram + poller-ul de
comenzi live Telegram. Fan-out trimite același eveniment pe mai multe canale.
## Ownership
`discord.py`, `telegram.py`, `fanout.py` și poller-ul de comenzi
(`../commands.py` definește dataclass-ul `Command` + long-poll `getUpdates`).
## Local Contracts
- **Secretele** vin DOAR din env (`ATM_DISCORD_URL`, `ATM_TG_TOKEN`,
`ATM_TG_CHAT`), încărcate din `.env` de `config.py`. Nu hardcoda token-uri.
- **`commands.py`** e singurul consumator de **httpx** (async long-poll).
`TelegramNotifier` (sync) rămâne pe **requests**. Nu amesteca cele două.
- **Comenzi live:** `/ss` `/status` `/pause` `/resume` `/rebase` `/3` (interval
min) `/stop`.
### Contracte pe comenzi (nu le slăbi fără update aici)
- **`/rebase`** — propune `baseline_phash` nou: capture → crop pe `canary.roi`
→ phash → screenshot adnotat (cerc roșu pe ROI) cu old/new hash + distance.
`/rebase confirm` în ≤180s rescrie `baseline_phash` în TOML-ul activ (păstrează
comentariile), mirror în `cfg` la runtime, clear `user_paused` + `drift_paused`.
Fără confirm, nimic nu se schimbă.
- **`/ss`** — top-3 buline din `dot_roi`: cerc roșu gros pe pick-ul FSM, cercuri
colorate subțiri pe vecini; caption cu nume/RGB/distanță/confidence +
`config: {version}`. Culoarea cercului = `cfg.colors[name].rgb` (DRY cu paleta).
- **`/resume`** — clear ȘI user-pause ȘI drift-pause într-un shot (`/resume force`
= alias legacy). Capture rulează **înainte** de clear (zero race cu FSM tick).
Dacă capture pică, title conține `⚠️ captură eșuată` și resume se execută oricum.
- **Drift-pause** — un singur alert Telegram pe tranziție. Cât e pauzat,
`/set_interval` e refuzat, caption-ul `/ss` avertizează că detecția e oprită,
heartbeat arată `⚠️ pauzat (drift)` în loc de `activ`.
## Work Guidance
- Orice mesaj nou de alertă → trece prin `fanout.py`, nu chema notifier-ele direct
din `main.py`.
- Schimbi semantica unei comenzi → actualizează contractul de mai sus în ACELAȘI
commit (DOX pass).
## Verification
```bash
pytest tests/test_notifier.py tests/test_commands.py -v
.\.venv\Scripts\python.exe scripts\repro_ss_resume.py # repro /ss + /resume
```
## Child DOX Index
(none — leaf)

37
tests/AGENTS.md Normal file
View File

@@ -0,0 +1,37 @@
# tests — Test Suite
## Purpose
230+ teste: unit pe fiecare modul + 8 scenarii de regresie FSM pe imagini reale +
env loader. Rulează headless pe Linux/WSL (de aceea FSM & config nu importă cv2).
## Ownership
Tot `tests/`. Fiecare `test_<modul>.py` oglindește un modul din `src/atm/`.
## Local Contracts
- Un modul nou în `src/atm/` ⇒ un `test_<modul>.py` corespondent.
- **`test_scenarios_regression.py`** rulează FSM-ul peste secvențele din
`calibration/scenarios.json` pe frame-uri reale. Schimbi FSM ⇒ adaugă/actualizează
scenariu acolo (vezi `calibration/AGENTS.md`).
- **`test_env_loader.py`** monkeypatchează env-ul; păstrează regula „shell wins"
din `config._ensure_env_loaded`.
- Testele nu trebuie să atingă rețeaua reală (Telegram/Discord) — mock-uiește.
## Work Guidance
- Rulează suita completă înainte de orice commit care atinge `src/atm/`.
- Dacă un test cere Pillow/OpenCV pe checkout-ul Windows, folosește venv-ul repo
(vezi `scripts/AGENTS.md`).
## Verification
```bash
pytest -q # toată suita
pytest tests/test_scenarios_regression.py -v # FSM pe imagini reale
```
## Child DOX Index
(none — leaf)