PR #1280 · Sulto4/voost-control · 12 iul 2026

Două teste care trec singure, dar pică împreună. Merge?

pipeline-pause.test.ts și pipeline-watchdog.test.ts trec fiecare separat. Rulate în aceeași comandă, 3 teste ale watchdog-ului pică de fiecare dată — inclusiv pe main curat. PR #1280 repară izolarea, nu regulile. Pagina asta îți arată mecanismul, îl lasă să-l declanșezi tu, și pune pro și contra pe masă.

3 / 3
rulări în pereche picate, înainte de fix (pe main curat, fce08ed7)
18 / 18
rulări-stres verzi după fix (ambele ordini + combo cu 3 fișiere)
2 910
teste unit verzi local, de două ori; CI verde în 2m41s
0
linii de cod de producție atinse — doar tests/ și docs/
ACTUL 1

Trei piese, o singură bază de date

Nu e un bug în watchdog și nu e un rând uitat necurățat. E o coliziune de vecinătate: vitest rulează fișierele de test în paralel, iar toate împart aceeași bază de test.

Distribuția — apasă pe chip-uri
pipeline-pause.test.ts
Scriitorul. Testează pauza pipeline-ului: oprește și repornește comutatoare globale, la fiecare test.
transcription_auto = false extraction_auto = false telegram_review_notifications
voost_control_test_<ticket>
Terenul comun. O singură bază Postgres pentru toate fișierele care rulează în paralel. Comutatoarele sunt rânduri în tabela automation_settings — vizibile pentru toți, instantaneu.
--fileParallelism
pipeline-watchdog.test.ts
Cititorul. Testează câinele de pază al pipeline-ului. Nu scrie niciodată comutatoarele — dar sweep-ul lui le citește, ca să nu alerteze pe o etapă oprită intenționat.
isPipelineStagePaused() apel „stuck” de 11 min
Scriitorulsuita care deține comutatoarele și le flutură
Terenul comunbaza de test partajată între procese
Cititorulsuita care doar citește și suferă
Fix-ulcitirile cititorului, țintuite la default
ACTUL 2

Declanșează flake-ul cu mâna ta

Simularea de mai jos e mecanismul real, pas cu pas. Alege modul de rulare, apoi apasă Rulează. Apoi pornește fix-ul și rulează din nou.

Simulator — perechea de teste pe aceeași bază
fix #1280: oprit
pipeline-pause.test.ts — scriitorul
așteaptă…
automation_settings transcription_auto: — (default: pornit) cititorul e țintuit la default (vi.mock) — nu mai citește rândul ăsta
pipeline-watchdog.test.ts — cititorul
așteaptă…
Poanta: în paralel, fereastra „false” a scriitorului cade fix peste citirea sweep-ului. Nu e ordine greșită, nu e curățenie lipsă — e simultaneitate. De-asta perechea pica 100% din rulări, iar suita întreagă doar „de obicei trecea”.
ACTUL 3

Bonus găsit la diagnoză: furtul de markere

Fiecare sweep începe cu un pas de siguranță: reia din coadă toate apelurile parcate cu marker de pauză — din toată baza. Sub paralelism, sweep-ul unui vecin poate „fura” fixture-ul altcuiva.

Fixture-ul suitei pause, marker la vedere
vitest-pipeline-pause-transcription-…
automationPause: transcription
Markerul spune: „sunt parcat intenționat, reia-mă când repornește etapa.”
fix #1280: oprit
Cu fix-ul pornit, sweep-urile suitei watchdog au pasul de resume anulat (no-op) — nu testează nimeni fallback-ul acolo, iar acoperirea lui reală rămâne în pipeline-pause.test.ts. Vecinul nu mai poate fura.
ACTUL 4

Pro și contra, cinstit

Contra-urile vin din review-ul independent gpt-5.6-sol (Codex, effort ultra) pe branch — patru constatări, toate verificate în cod înainte să ajungă aici. Apasă pe fiecare contra ca să vezi răspunsul.

Pro

Zero risc de producție.
Diff-ul atinge doar două fișiere de test și TESTING.md. Niciun byte din src/. Nu cere deploy, nu poate strica runtime-ul.
Flake-ul reproductibil 100% dispare.
Înainte: 3/3 rulări-pereche picate. După: 18/18 verzi (ambele ordini + combo cu al treilea fișier expus, automations-health-panel).
Verificat pe toate porțile tale.
2 910 teste unit verzi local de două ori, lint + typecheck curate, CI verde pe runner-ul self-hosted. CI e singura poartă — și e trecută.
Review independent, pozitiv pe fix.
Codex: mock-urile sunt corect hoisted, păstrează restul exporturilor, întorc forma validă de raport; acoperirea reală rămâne unde trebuie.
Convenția e scrisă, nu doar aplicată.
TESTING.md primește regula în lecția existentă „parallel unit files share ONE database” — următorul agent nu mai redescoperă mecanismul.

Contra

Watchdog-ul nu mai exercită citirea reală a comutatoarelor.
Suita citește acum prin mock — un strat de realitate în minus.
RăspunsAdevărat, și e o mutare, nu o ștergere: integrarea reală pauză↔watchdog e testată explicit în pipeline-pause.test.ts („Pipeline Watchdog awareness of paused stages”), care rămâne pe citiri reale și e singurul scriitor al cheilor lui. Plus E2E-ul built-server acoperă resume-ul pe ambele etape.
Mock parțial = risc de drift dacă se schimbă registry-ul.
Dacă defaulturile comutatoarelor se schimbă, minte mock-ul?
RăspunsNu: mock-ul nu hardcodează valori — derivă din AUTOMATION_SWITCH_REGISTRY-ul real (importOriginal), deci un default schimbat se propagă singur. O schimbare de semnătură o prinde typecheck-ul din pre-commit și CI.
Nu rezolvă toată clasa de probleme.
Alte suite încă citesc real comutatoarele (canary, intake ClickPhone) și pot flake-ui la fel.
RăspunsCorect — și e documentat, nu ascuns: issue #1282 listează exact hazardurile reziduale, cu fișier și linie, verificate. PR-ul rezolvă perechea care pica garantat și scrie regula pentru restul. Perfectul nu blochează binele aici.
Codex a găsit și un bug de producție (nu din PR).
Claim-ul din resumePausedCallArtifacts nu e atomic: două resume-uri suprapuse pot dubla dispatch-ul.
RăspunsPre-existent — pe main de dinainte de PR, doar că review-ul l-a scos la lumină. E punctul 3 din #1282, cu direcție de fix (claim condițional atomic + test concurent). Nu e un motiv să ții pe loc un fix de teste; e un motiv să deschizi #1282 curând.
ACTUL 5

Verdictul, pe criteriile tale

Regulile casei: „testele sunt singurul code review care există — nu slăbi un test ca să treacă” și „complexitate minimă”. Aplicate:

CriteriuFără mergeCu merge (#1280)
Perechea de teste, rulată împreunăpică mereuverde, 18/18
Suita întreagă sub paralelism„de obicei trece” = norocperechea eliminată din ecuație
Slăbește vreun test ca să treacă?nu — mută acoperirea la proprietar, n-o șterge
Cod de producție atinsnimicnimic
Hazarduri rezidualenecunoscute, nescrisecunoscute, trasate în #1282
Complexitate adăugatăzero2 mock-uri comentate + o regulă în doc
alegerea · merge

Merge #1280. Fix țintit, test-only, verificat pe toate porțile, cu review independent și cu partea nerezolvată documentată la vedere.

parcat · #1282

Restul clasei. Citirile reale din canary/intake + claim-ul neatomic din producție. Trasate cu fișier:linie și direcții de fix. Punctul 3 merită prioritate.

respins · a nu se face

„Lasă-l așa, suita mare trece oricum.” Adică: păstrezi un test care pică în funcție de vecini. Un review process care depinde de noroc nu e review process.

mantra

Un test care depinde de vecini nu păzește codul — păzește norocul.