From 39f24392463dddadd4e981d51d32b6803cf7136e Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Sat, 13 Jun 2026 11:51:36 +0300 Subject: [PATCH] DOX sistem --- AGENTS.md | 108 +++++++++++++------------------------ CLAUDE.md | 91 +++++++++---------------------- calibration/AGENTS.md | 45 ++++++++++++++++ configs/AGENTS.md | 53 ++++++++++++++++++ scripts/AGENTS.md | 42 +++++++++++++++ src/atm/AGENTS.md | 55 +++++++++++++++++++ src/atm/notifier/AGENTS.md | 55 +++++++++++++++++++ tests/AGENTS.md | 37 +++++++++++++ 8 files changed, 347 insertions(+), 139 deletions(-) create mode 100644 calibration/AGENTS.md create mode 100644 configs/AGENTS.md create mode 100644 scripts/AGENTS.md create mode 100644 src/atm/AGENTS.md create mode 100644 src/atm/notifier/AGENTS.md create mode 100644 tests/AGENTS.md diff --git a/AGENTS.md b/AGENTS.md index 2280e4b..7d75a26 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,90 +1,54 @@ # 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 ```bash 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) 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 +atm validate-calibration calibration/calibration_labels.json # color gate offline +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 +pytest -q # 230+ teste ``` -## Codex sandbox/tooling notes +## DOX Protocol -On this Windows checkout, do not assume `rg` or the global `python` has project deps. -Use the repo venv for diagnostics that need Pillow/OpenCV: +- **Citire** — traversează root → path-ul țintă, citind fiecare `AGENTS.md`. Dacă + 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 -.\.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 -``` +## Durable Rules (repo-wide) -If `rg` is missing, use PowerShell fallbacks: -`Get-ChildItem -Recurse -File src,tests,scripts | Select-String -Pattern "needle"`. -If a command fails due to sandbox permissions and is required for the task, rerun it -with an escalation request instead of stopping the investigation without a verdict. +- **Pure-logic fără cv2/numpy** în `state_machine.py` și `config.py` (testele rulează + headless). cv2/I/O greu mereu în `asyncio.to_thread`. +- **Secretele doar din env** (`.env`), niciodată în TOML sau cod. +- **Mereu** `atm validate-calibration` după recalibrare (palette gotcha — vezi + `calibration/AGENTS.md`). +- Modul nou în `src/atm/` ⇒ `test_.py` corespondent. -## Calibration corpus +> Skill routing (Claude Code) trăiește în [`CLAUDE.md`](CLAUDE.md) — sursa canonică. -`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` +## Child DOX Index -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 - -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 +- **`src/atm/`** → `src/atm/AGENTS.md` — motorul: capture/detect/FSM/scheduler/ + vision/canary/config. (copil: `notifier/`) +- **`tests/`** → `tests/AGENTS.md` — suita de teste + regresie FSM. +- **`calibration/`** → `calibration/AGENTS.md` — corpus culori + scenarii + palette gotcha. +- **`configs/`** → `configs/AGENTS.md` — schema TOML (operating_hours, alerts, canary). +- **`scripts/`** → `scripts/AGENTS.md` — diagnostic + note sandbox Windows/venv. diff --git a/CLAUDE.md b/CLAUDE.md index f6ba64c..ed0e620 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 -pip install -e ".[windows]" # Windows: live capture -pip install -e ".[dev]" # Linux/macOS: dev + tests (WSL: create venv first) -cp .env.example .env # secretele Discord/Telegram (vezi README §Secrets) -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 -``` +Documentația operațională trăiește în arborele de `AGENTS.md` (format DOX), **nu** +aici. Î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ă doc-ul care +deține zona + indexul părintelui). -## Calibration corpus - -`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`. +Start: [`AGENTS.md`](AGENTS.md) (root — Quick Reference, reguli globale, index copii). +Copii: `src/atm/` · `src/atm/notifier/` · `tests/` · `calibration/` · `configs/` · `scripts/`. ## 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. +Când cererea userului se potrivește cu un skill disponibil, invocă-l cu tool-ul +Skill ca PRIMĂ acțiune. NU răspunde direct, NU folosi alte tool-uri întâi. +Skill-ul are workflow-uri specializate care produc rezultate mai bune. -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 +- Idei de produs, „merită construit", brainstorming → `office-hours` +- Bug-uri, erori, „de ce e stricat", 500 → `investigate` +- Ship, deploy, push, PR → `ship` +- QA, testează site-ul, găsește bug-uri → `qa` +- Code review, verifică diff-ul → `review` +- Update docs după ship → `document-release` +- Retro săptămânal → `retro` +- Design system, brand → `design-consultation` +- Audit vizual, design polish → `design-review` +- Architecture review → `plan-eng-review` +- Save progress, checkpoint, resume → `checkpoint` +- Code quality, health check → `health` diff --git a/calibration/AGENTS.md b/calibration/AGENTS.md new file mode 100644 index 0000000..e9751c7 --- /dev/null +++ b/calibration/AGENTS.md @@ -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) diff --git a/configs/AGENTS.md b/configs/AGENTS.md new file mode 100644 index 0000000..76e38a1 --- /dev/null +++ b/configs/AGENTS.md @@ -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) diff --git a/scripts/AGENTS.md b/scripts/AGENTS.md new file mode 100644 index 0000000..6259e78 --- /dev/null +++ b/scripts/AGENTS.md @@ -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) diff --git a/src/atm/AGENTS.md b/src/atm/AGENTS.md new file mode 100644 index 0000000..ba0e3f8 --- /dev/null +++ b/src/atm/AGENTS.md @@ -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`, …). diff --git a/src/atm/notifier/AGENTS.md b/src/atm/notifier/AGENTS.md new file mode 100644 index 0000000..7758cce --- /dev/null +++ b/src/atm/notifier/AGENTS.md @@ -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) diff --git a/tests/AGENTS.md b/tests/AGENTS.md new file mode 100644 index 0000000..84a2657 --- /dev/null +++ b/tests/AGENTS.md @@ -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_.py` oglindește un modul din `src/atm/`. + +## Local Contracts + +- Un modul nou în `src/atm/` ⇒ un `test_.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)