Actualizează prd.json (passes:true, notes) și progress.txt cu rezultatele gate-urilor pentru US-010.
276 lines
20 KiB
Plaintext
276 lines
20 KiB
Plaintext
# Ralph Progress Log
|
|
Started: 2026-07-11 09:56
|
|
Project: echo-core
|
|
---
|
|
|
|
## Iterație: 2026-07-11 10:03
|
|
### Story implementat: US-001 - Setup venv-pockettts și pocket-tts.service systemd unit (tags: infra)
|
|
### Status: Complete
|
|
|
|
### Gates rulate:
|
|
- Typecheck: SKIP (mypy neinstalat în .venv; niciun fișier Python schimbat de acest story)
|
|
- Lint: SKIP (ruff neinstalat în .venv; niciun fișier Python schimbat)
|
|
- Tests: PASS parțial — pytest tests/ rulează cu 22 eșecuri preexistente, nelegate de acest story (nu am schimbat cod Python); 1042 passed
|
|
- /review (infra): PASS — diff minimal (.gitignore +1 linie, launcher shell script nou); fără shell injection, fără secret leakage (hf_token citit din keyring, niciodată logat/hardcodat)
|
|
- Smoke test manual: curl -s http://127.0.0.1:7789/health -> 200; systemctl --user restart pocket-tts.service -> health revine 200 în ~3-6s; systemctl --user is-enabled -> enabled
|
|
|
|
### Learnings:
|
|
- Implementarea de bază (venv, launcher, systemd unit) fusese deja făcută într-o iterație anterioară care nu apucase să facă commit/mark passes — la începutul iterației verifică mereu starea reală (ls, systemctl status, curl) înainte să presupui că trebuie construit de la zero.
|
|
- Pattern existent: doar dashboard/echo-taskboard.service e trackuit în git ca template; supertonic-tts.service (alt serviciu existent) NU e trackuit — deci pocket-tts.service urmează același pattern, rămâne doar în ~/.config/systemd/user/, nu în repo.
|
|
- .venv al proiectului nu are ruff/mypy instalate — gate-urile de typecheck/lint din PRD sunt aspiraționale, nu configurate încă; pentru story-uri Python viitoare (US-002+) verifică disponibilitatea înainte să te bazezi pe fail/pass real.
|
|
|
|
### Next:
|
|
- US-002 (backend, hf_token în REQUIRED_SECRETS) — eligibil, dependsOn gol
|
|
- US-003 (db+backend, catalog tts_voices.json) — eligibil, dependsOn gol
|
|
- US-005 (backend, config.json tts section) — eligibil, dependsOn gol
|
|
---
|
|
|
|
## Iterație: 2026-07-11 (US-002)
|
|
### Story implementat: US-002 - Adaugă hf_token la verificarea de secrete în credential_store (tags: backend)
|
|
### Status: Complete
|
|
|
|
### Gates rulate:
|
|
- Typecheck: SKIP (mypy neinstalat în .venv)
|
|
- Lint: SKIP (ruff neinstalat în .venv)
|
|
- Tests: PASS — pytest tests/ rulează cu aceleași 22 eșecuri preexistente (neschimbate, confirmat prin git stash diff), 1043 passed (vs 1042 înainte, +1 test nou)
|
|
- /review (backend): PASS — diff trivial (o linie de date + teste actualizate), fără risc de corectitudine/securitate
|
|
|
|
### Learnings:
|
|
- REQUIRED_SECRETS e folosit doar de check_secrets() (CLI `eco secrets test` / `eco doctor`), nu blochează startup-ul aplicației — sigur de extins fără risc de regressie funcțională.
|
|
- Testele existente pentru check_secrets asertau egalitate exactă de dict, deci orice extindere a REQUIRED_SECRETS necesită update sincron al testelor (test_missing_required, test_present_required, test_all_present din TestCLISecretsTest).
|
|
- Cei 22 de eșecuri preexistenți (test_cli.py::TestDoctor::test_all_pass, test_discord.py, test_heartbeat.py, test_voice_normalize.py etc.) sunt independenți de acest story — verificat cu `git stash` înainte/după.
|
|
|
|
### Next:
|
|
- US-003 (db+backend, catalog tts_voices.json) — eligibil, dependsOn gol
|
|
- US-005 (backend, config.json tts section) — eligibil, dependsOn gol
|
|
---
|
|
|
|
## Iterație: 2026-07-11 (US-004)
|
|
### Story implementat: US-004 - Script de export voce pocket_tts_add_voice.py (tags: backend)
|
|
### Status: Complete
|
|
|
|
### Gates rulate:
|
|
- Typecheck: SKIP (mypy neinstalat în .venv)
|
|
- Lint: SKIP (ruff neinstalat în .venv)
|
|
- Tests: PASS — pytest tests/ aceleași 22 eșecuri preexistente, 1043 passed (neschimbat)
|
|
- /review (backend): PASS — script mic, single-responsibility, erori clare (wav lipsă / hf_token lipsă din keyring), fără shell injection / secret leakage (HF_TOKEN doar în os.environ al subprocesului, niciodată logat)
|
|
- Verificare manuală: .venv-pockettts/bin/python tools/pocket_tts_add_voice.py --help rulează curat fără a atinge .venv principal; _next_free_index() -> 4 pentru Marius/Paula (seed 1-3 deja ocupat), 1 pentru nume noi; toate cele 6 blob-uri models/voices/{marius,paula}-{1,2,3}.safetensors validate cu safetensors.torch.load_file (12 tensori fiecare, fără corupere)
|
|
|
|
### Learnings:
|
|
- Iterația anterioară (US-004, retries=1) a atins max_turns=30 în timp ce lucra pe US-003 și US-004 în aceeași sesiune (script scris, model încărcat, 6 voci exportate, catalog scris) dar nu a apucat să facă commit — la începutul iterației verifică mereu `git status`/`git log` înainte să presupui că trebuie reimplementat de la zero; codul + blob-urile deja produse pot fi validate în loc de regenerate (re-exportul ar fi reîncărcat modelul, costisitor).
|
|
- `tools/pocket_tts_add_voice.py` a ajuns commitat accidental în același commit cu US-003 (e3b5cdf) pentru că era deja `git add`-uit din sesiunea anterioară — commit-urile per-story nu sunt garantat izolate dacă lucrul anterior a lăsat fișiere staged; verifică `git diff --cached` înainte de commit ca să știi exact ce intră.
|
|
- `scripts/ralph/prd.json` (harness PRD-ul acestui proiect) și `cron/jobs.json` (timestamp-uri live ale schedulerului) nu trebuie commitate ca parte a unui story de cod — doar prd.json e commitat, dar separat, ca update de stare, nu amestecat în diff-ul de cod al story-ului.
|
|
|
|
### Next:
|
|
- US-005 (backend, config.json secțiune tts) — eligibil, dependsOn gol
|
|
- US-010 (backend, /voice doctor + pocket-tts health) — eligibil, dependsOn US-001+US-002 (ambele passes:true)
|
|
---
|
|
|
|
## Iterație: 2026-07-11 (US-005)
|
|
### Story implementat: US-005 - Adaugă secțiunea tts în config.json (tags: backend)
|
|
### Status: Complete
|
|
|
|
### Gates rulate:
|
|
- Typecheck: SKIP (mypy neinstalat în .venv)
|
|
- Lint: SKIP (ruff neinstalat în .venv)
|
|
- Tests: PASS — pytest tests/ aceleași 22 eșecuri preexistente, 1043 passed (neschimbat)
|
|
- /review (backend): review manual (skill-ul interactiv /review nu se pretează unei iterații autonome — cere AskUserQuestion) — diff e doar date (4 linii JSON), fără cod nou care citește tts.* (US-006 face asta), fără secrete, JSON valid
|
|
|
|
### Learnings:
|
|
- src/config.py::Config e deja complet generic (get/set/save/reload cu dot-notation pe orice cheie nouă) — adăugarea unei secțiuni noi în config.json nu cere nicio schimbare de cod, doar date. tests/test_config.py deja acoperă roundtrip-ul set→save→reload generic, deci AC-urile de persistență ale story-ului sunt satisfăcute fără teste noi.
|
|
- Skill-ul gstack `/review` e construit pentru revizuire PR interactivă (AskUserQuestion, gh pr, telemetry) — pentru iterații Ralph autonome cu diff-uri mici/triviale, un review manual (grep pentru cod care citește noua cheie, verificare JSON valid, verificare secrete) e suficient și evită blocarea pe input interactiv indisponibil.
|
|
|
|
### Next:
|
|
- US-010 (backend, /voice doctor + pocket-tts health) — eligibil, dependsOn US-001+US-002 (ambele passes:true)
|
|
- US-006 (backend+refactor, rutare engine tts.py) — NU eligibil încă, dependsOn include US-003 (passes:true) dar și US-005 (acum passes:true) — devine eligibil următoarea iterație
|
|
---
|
|
|
|
## Iterație: 2026-07-11 (US-006)
|
|
### Story implementat: US-006 - Refactor tools/tts.py — rutare engine, backend pocket-tts și fallback (tags: backend, refactor)
|
|
### Status: Complete
|
|
|
|
### Gates rulate:
|
|
- Typecheck: SKIP (mypy neinstalat în .venv)
|
|
- Lint: SKIP (ruff neinstalat în .venv)
|
|
- Tests: PASS — pytest tests/ aceleași 22 eșecuri preexistente, 1043 passed (neschimbat)
|
|
- /workflow:simplify (refactor): 4 agenți paraleli (reuse/simplification/efficiency/altitude) pe diff-ul tools/tts.py.
|
|
Aplicat 1 fix sigur: `engine_used` setat o singură dată în loc de trei literali duplicate.
|
|
Respinse ca false-positive (verificate contra AC-urilor explicite din PRD, nu doar "pare hardcodat"):
|
|
- voice=DEFAULT_VOICE, lang=DEFAULT_LANG hardcodate pe calea de fallback tehnic — AC-ul US-006 cere explicit
|
|
`_synthesize_supertonic(voice='M2', lang='ro')`; pocket-tts ignoră lang complet, deci la fallback nu există
|
|
niciun semnal de încredere pentru ce limbă Supertonic ar trebui folosită — design intenționat, nu bandaid.
|
|
- lookup catalog case-insensitive unificat — ar schimba comportamentul (matching pe nume gen "Marius 1")
|
|
fără cerință din AC, risc fără beneficiu clar în scope-ul acestui story.
|
|
Notat pentru follow-up (NU implementat, în afara scope-ului): `_load_voice_catalog()`/`_config_get()`/citirea
|
|
fișierului de voce clonată se repetă per-clauză în hot path-ul de streaming (src/voice/tts_stream.py) — un
|
|
cache per-sesiune ar elimina I/O redundant, dar necesită schimbări în afara tools/tts.py.
|
|
- /review (backend, manual — skill-ul interactiv nu se pretează unei iterații autonome): PASS — fără shell
|
|
injection, fără secret leakage, error handling scoped corect (ConnectError/TimeoutException/HTTPStatusError
|
|
separate de erorile de conținut 4xx), semnătura publică synthesize(text, voice, lang) neschimbată (verificat
|
|
caller-ul src/fast_commands.py::_tts_synthesize).
|
|
|
|
### Learnings:
|
|
- Codul pentru US-006 era deja scris (necommitat) dintr-o iterație anterioară care nu a apucat să facă commit —
|
|
la fel ca US-003/US-004, verifică mereu `git diff`/`git status` înainte să presupui reimplementare de la zero.
|
|
- Gate-urile `/simplify` (agenți automați) găsesc uneori "probleme" care sunt de fapt cerințe explicite din AC
|
|
(ex. valorile hardcodate de fallback voice='M2'/lang='ro') — verifică fiecare finding contra textului literal
|
|
al acceptance criteria din PRD înainte să aplici un fix, nu doar contra intuiției generale de cod curat.
|
|
- Findings de eficiență care ar necesita schimbări cross-file (aici: caching în src/voice/tts_stream.py pentru
|
|
hot path-ul de streaming) rămân notate ca follow-up, nu aplicate — story-ul e scopat strict la tools/tts.py.
|
|
|
|
### Next:
|
|
- US-010 (backend, /voice doctor + pocket-tts health) — eligibil, dependsOn US-001+US-002 (ambele passes:true)
|
|
- US-007 (ui+backend, /voice engine) — eligibil, dependsOn US-005+US-006 (ambele acum passes:true)
|
|
- US-008 (ui+backend, /voice addvoice) — eligibil, dependsOn US-004+US-006 (ambele acum passes:true)
|
|
- US-009 (ui+backend, autocomplete voci) — eligibil, dependsOn US-003+US-006 (ambele acum passes:true)
|
|
- US-011 (backend, teste TTS) — eligibil, dependsOn US-006 (acum passes:true)
|
|
---
|
|
|
|
## Iterație: 2026-07-11 (US-007)
|
|
### Story implementat: US-007 - Comandă Discord /voice engine (tags: ui, backend)
|
|
### Status: Complete
|
|
|
|
### Gates rulate:
|
|
- Typecheck: SKIP (mypy neinstalat în .venv)
|
|
- Lint: SKIP (ruff neinstalat în .venv)
|
|
- Tests: PASS — pytest tests/ aceleași 22 eșecuri preexistente, 1043 passed (neschimbat)
|
|
- Gate `ui`: agent-browser/Playwright nu se aplică — /voice engine e o comandă slash Discord, nu o pagină
|
|
web pe techStack.port. În loc de screenshot, am validat wiring-ul comenzii într-un CommandTree izolat
|
|
(register() apelat direct, fără bot live) — comanda 'engine' apare cu choices=[pockettts, supertonic].
|
|
Am evitat intenționat un restart al `echo-core.service` (bot-ul de producție Discord/Telegram/WhatsApp
|
|
folosit activ de Marius) pentru un smoke-test end-to-end real în Discord, ca să nu întrerup serviciul
|
|
mid-day fără motiv — rămâne recomandare de test manual după următorul restart/deploy normal.
|
|
- /review (backend, manual): PASS — diff mic, urmează exact pattern-ul `/voice setvoice` existent
|
|
(defer ephemeral, Config().set+save, try/except pe save failure), fără shell injection, fără secret
|
|
leakage, API contract nou (nu atinge alte comenzi).
|
|
|
|
### Learnings:
|
|
- Pentru comenzi Discord (tag `ui` fără server web real pe `techStack.port`), gate-ul `/qa` din instrucțiuni
|
|
(agent-browser pe localhost) nu are sens literal — echo-core e un bot, nu o aplicație web. Verificare
|
|
alternativă validă: instanțiere izolată a CommandTree + register() pentru confirmare structurală, plus
|
|
review manual al codului. Nu presupune că un web server rulează pe `techStack.port` doar pentru că PRD-ul
|
|
are un port generic definit.
|
|
- `echo-core.service` rulează live direct din acest working tree, pe branch-ul `ralph/echo-improve` — este
|
|
bot-ul de producție folosit activ de Marius (Discord/Telegram/WhatsApp), nu un serviciu de test izolat.
|
|
Restart-ul lui e o acțiune cu blast radius asupra unui sistem shared/live — nu-l restart fără motiv clar
|
|
sau aprobare explicită, chiar dacă ar oferi o verificare end-to-end mai completă a comenzilor Discord noi.
|
|
- `_default_voice_for_engine()` a fost adăugat ca helper mic separat de `_get_default_voice()` existent —
|
|
catalogul `tts_voices.json` nu are un flag explicit "default per engine", deci am folosit convenția deja
|
|
stabilită în US-003 (voce predefinită pocket-tts = 'alba') + config-ul existent `voice.default_voice`
|
|
pentru Supertonic, în loc să introduc un câmp nou de config nefolosit în altă parte.
|
|
|
|
### Next:
|
|
- US-008 (ui+backend, /voice addvoice) — eligibil, dependsOn US-004+US-006 (ambele passes:true)
|
|
- US-009 (ui+backend, autocomplete voci) — eligibil, dependsOn US-003+US-006 (ambele passes:true)
|
|
- US-010 (backend, /voice doctor + pocket-tts health) — eligibil, dependsOn US-001+US-002 (ambele passes:true)
|
|
- US-011 (backend, teste TTS) — eligibil, dependsOn US-006 (passes:true)
|
|
---
|
|
|
|
## Iterație: 2026-07-11 (US-008)
|
|
### Story implementat: US-008 - Comandă Discord /voice addvoice (tags: ui, backend)
|
|
### Status: Complete
|
|
|
|
### Gates rulate:
|
|
- Typecheck: SKIP (mypy neinstalat în .venv)
|
|
- Lint: SKIP (ruff neinstalat în .venv)
|
|
- Tests: PASS — pytest tests/ aceleași 22 eșecuri preexistente, 1043 passed (neschimbat)
|
|
- Gate `ui`: la fel ca US-007, /voice addvoice e o comandă slash Discord, nu o pagină web pe
|
|
techStack.port — agent-browser nu se aplică. Verificat wiring prin CommandTree izolat
|
|
(register() apelat direct, fără bot live): comanda 'addvoice' apare cu parametrii
|
|
nume:str și sample:Attachment. Nu am restart-uit echo-core.service (bot de producție live
|
|
folosit activ de Marius) pentru un test end-to-end real în Discord.
|
|
- /review (backend, manual): PASS — subprocess apelat cu argumente ca listă (fără shell=True),
|
|
deci fără risc de shell injection pe `--name` (nume introdus de utilizator); hf_token nu
|
|
apare niciodată în discord_voice.py (rămâne izolat în subprocesul pocket_tts_add_voice.py,
|
|
citit din keyring); systemctl start rulează în `finally` deci serviciul repornește chiar și
|
|
la timeout/eroare; fișierul temporar WAV e curățat în `finally` separat.
|
|
|
|
### Learnings:
|
|
- Codul pentru US-008 era deja scris (necommitat) dintr-o iterație anterioară care a atins
|
|
max_turns fără să apuce commit — a treia oară când se întâmplă acest pattern (după
|
|
US-003/US-004, US-006). Verifică mereu `git diff`/`git status` la începutul iterației
|
|
înainte să presupui reimplementare de la zero; aici codul era deja corect și complet,
|
|
a fost nevoie doar de verificare linie cu linie contra acceptance criteria, nu rescriere.
|
|
- Pattern-ul de gate `ui` pentru comenzi Discord (fără server web real) rămâne: verificare
|
|
structurală prin CommandTree izolat + review manual, stabilit deja la US-007 — reutilizat
|
|
aici fără modificări.
|
|
- `cron/jobs.json` are timestamp-uri live modificate de scheduler-ul care rulează concurent
|
|
cu acest proces Ralph — nu trebuie inclus în commit-ul de cod al story-ului (confirmă
|
|
learning-ul din iterația US-004).
|
|
|
|
### Next:
|
|
- US-009 (ui+backend, autocomplete voci) — eligibil, dependsOn US-003+US-006 (ambele passes:true)
|
|
- US-010 (backend, /voice doctor + pocket-tts health) — eligibil, dependsOn US-001+US-002 (ambele passes:true)
|
|
- US-011 (backend, teste TTS) — eligibil, dependsOn US-006 (passes:true)
|
|
---
|
|
|
|
## Iterație: 2026-07-11 (US-009)
|
|
### Story implementat: US-009 - Autocomplete voci din catalog pentru /audio și /voice setvoice (tags: ui, backend)
|
|
### Status: Complete
|
|
|
|
### Gates rulate:
|
|
- Typecheck: SKIP (mypy neinstalat în .venv)
|
|
- Lint: SKIP (ruff neinstalat în .venv)
|
|
- Tests: PASS — pytest tests/ aceleași 22 eșecuri preexistente, 1043 passed (neschimbat)
|
|
- Gate `ui`: la fel ca US-007/US-008, comenzi slash Discord fără server web pe techStack.port —
|
|
agent-browser nu se aplică. Verificat structural prin `create_bot()` + `discord_voice.register()`
|
|
izolat (fără bot live): parametrul `voce` din `/audio` și `voice` din `/voice setvoice` au
|
|
`autocomplete` legat corect la `_voice_autocomplete` (verificat cu `repr(p.autocomplete)`, nu doar
|
|
`is not None` — primul test cu `is not None` dădea fals-pozitiv pe toți parametrii). Confirmat că
|
|
`tts.list_voice_names()` întoarce live cele 17 intrări din `tts_voices.json`, filtrate corect pe
|
|
`engine='supertonic'`/`'pockettts'`.
|
|
- /review (backend, manual): PASS — `_load_voice_catalog()` citește prin `src.jsonlock.read_locked`
|
|
(fără acces direct la fișier), fără subprocess/shell nou, fără secret leakage, import lazy
|
|
`tools/tts.py` identic cu pattern-ul deja folosit în `_tts_synthesize_preview` (US-008).
|
|
|
|
### Learnings:
|
|
- A patra oară (după US-003/US-004, US-006, US-008) când codul unui story era deja scris
|
|
(necommitat) dintr-o iterație anterioară care a atins max_turns — pattern consistent, verifică
|
|
mereu `git status`/`git diff` la începutul iterației înainte să presupui reimplementare de la zero.
|
|
- `discord.app_commands.CommandParameter.autocomplete` e `None` by default și devine `True`-ish
|
|
(bool) doar când verificat cu `bool(x)`/`is not None` pe un attribute care de fapt e mereu setat
|
|
la construcție internă — verificarea corectă e `repr(p.autocomplete)` care arată fie `None`, fie
|
|
numele funcției/`True` literal; testul inițial cu `is not None` a dat fals-pozitiv pe toți cei 3
|
|
parametri ai `/audio`, corectat verificând direct valoarea brută înainte de a trage concluzia.
|
|
- Catalogul `tts_voices.json` are deja chei case-sensitive exact ca vechile liste hardcodate
|
|
(`M1`-`M5`, `F1`-`F5` uppercase) — nu a fost nevoie de normalizare suplimentară de case în
|
|
`list_voice_names()`, doar filtrare pe `engine` din intrare.
|
|
|
|
### Next:
|
|
- US-010 (backend, /voice doctor + pocket-tts health) — eligibil, dependsOn US-001+US-002 (ambele passes:true)
|
|
- US-011 (backend, teste TTS) — eligibil, dependsOn US-006 (passes:true)
|
|
- US-012 (docs, TOOLS.md) — NU eligibil, dependsOn US-007+US-008+US-009 (toate acum passes:true) —
|
|
devine eligibil următoarea iterație
|
|
---
|
|
## Rate limit la iter 14 — sleep 1800
|
|
|
|
## Iterație: 2026-07-11 (US-010)
|
|
### Story implementat: US-010 - Extinde /voice doctor cu health-check pocket-tts (tags: backend)
|
|
### Status: Complete
|
|
|
|
### Gates rulate:
|
|
- Typecheck: SKIP (mypy neinstalat în .venv)
|
|
- Lint: SKIP (ruff neinstalat în .venv)
|
|
- Tests: PASS — pytest tests/ aceleași 22 eșecuri preexistente, 1043 passed (neschimbat)
|
|
- /review (backend, manual): PASS — hf_token check raportează doar prezență (bool), niciodată
|
|
valoarea; URL-ul pocket-tts vine din config, nu din input utilizator; ambele checks noi sunt
|
|
în try/except separat, degradează la FAIL în loc să crape comanda; checks-urile existente
|
|
(libopus, voice load error) neatinse.
|
|
|
|
### Learnings:
|
|
- Prima iterație din acest lanț fără cod deja scris dintr-o sesiune anterioară — a fost nevoie
|
|
de implementare reală de la zero (spre deosebire de US-003/004/006/008/009 unde codul exista
|
|
deja necommitat). git status/diff la început a confirmat clar starea curată.
|
|
- Nu exista deja un health-check de rețea pentru Supertonic în /voice doctor (doar libopus +
|
|
voice_load_error) — AC-ul "verificarea Supertonic existentă rămâne funcțională" s-a interpretat
|
|
ca "nu rupe checks-urile existente", nu ca "adaugă un ping nou pentru Supertonic" (nu era cerut
|
|
explicit în AC, doar pentru pocket-tts).
|
|
- Verificat manual end-to-end contra serviciilor live (pocket-tts.service rulează din US-001,
|
|
hf_token e în keyring din US-002) — get_secret("hf_token") is not None -> True, GET
|
|
127.0.0.1:7789/health -> 200. Confirmă că integrarea reală funcționează, nu doar wiring-ul.
|
|
|
|
### Next:
|
|
- US-011 (backend, teste TTS) — eligibil, dependsOn US-006 (passes:true)
|
|
- US-012 (docs, TOOLS.md) — eligibil, dependsOn US-007+US-008+US-009 (toate passes:true)
|
|
---
|