Un WhatsApp nu e un apel telefonic
Când lipeai o conversație WhatsApp în Voost Control, ea apărea în istoricul clientului ca apel telefonic. Zece înregistrări din producție mint așa acum. Fix-ul făcut de Codex oprește minciuna — l-am auditat cu 52 de agenți: merită, codul e curat, și am găsit un singur gol real.
Bug-ul: două etaje, două adevăruri
Un import de conversație scrie două înregistrări. Etajul de jos (dosarul) spunea adevărul. Etajul de sus (istoricul clientului) mințea.
Apasă Importă, apoi dă click pe câmpuri ca să vezi cine mințea și cine nu.
Consecința nu era doar o etichetă urâtă: din interacțiunile «call» sistemul deriva fapte false — de exemplu «apel telefonic, a răspuns» pentru un lead, când de fapt fusese un schimb de mesaje. Exact genul de înregistrare pe care pilonul de încredere al VC îl interzice.
Fix-ul: două uși, fiecare cu ștampila ei
Issue-ul propunea un buton public: orice apelant să poată alege tipul. Codex a făcut ceva mai simplu — o cameră privată cu două uși fixe.
Ușa «audio»
Ușa «text»
Ușa improvizată
Cu param public, orice apelant viitor ar fi putut ștampila greșit. Ușa asta nu există în varianta Codex — funcția e privată, cu exact două intrări.
Apasă pe câte o ușă; apoi pe Arată varianta din issue ca să vezi ce s-a evitat.
Verdictul de simplitate: soluția e mai mică decât cerea issue-ul — API-ul public rămâne neschimbat, invariantul stă în două linii adiacente, ~10 linii net. Exact bara ta de complexitate minimă. Fără schimbare de schemă, fără ghicit din metadata.
Migrarea: repară trecutul, o singură dată
Fix-ul oprește minciuna de-acum încolo. Pentru cele ~10 rânduri vechi există o migrare — identifică precis conversațiile text (după marcajul din dosar, nu după titluri) și le corectează eticheta.
| Interacțiune | Marcaj în dosar | Tip |
|---|---|---|
| WhatsApp — Bogdan (Red Angels), 18 iul | text_conversation | call |
| WhatsApp — Secrets Joy Studio, 19 iul | text_conversation | call |
| WhatsApp — Secrets Joy Studio (2), 19 iul | text_conversation | call |
| Apel înregistrat — Anca (Necesit) | — | call |
Apasă Rulează migrarea de două ori — a doua rulare nu mai schimbă nimic. Asta înseamnă «idempotentă»: poate rula în siguranță de oricâte ori.
Ce am verificat la migrare (auditul de siguranță)
- Idempotență — dovedită și logic, și în test (testul chiar execută SQL-ul real pe un Postgres izolat și îl rulează de două ori).
- Apelurile reale rămân neatinse — corecția se leagă strict de marcajul
text_conversationdin dosar. - Plasa de siguranță de 40 de linii — migrarea repară și eventuale «fapte derivate» (contact attempts) din conversațiile greșit etichetate. Pe producție, populația lor e probabil zero — am cântărit dacă e over-engineering și verdictul e: acceptabil, pentru că fără ea o bază restaurată ar putea rămâne cu fapte contradictorii.
- Cinci suspiciuni ridicate de reviewers au fost respinse la verificare ca teoretice (ex. scenarii de date care nu pot exista în cod).
Un singur asterisc: cifrele «10 rânduri afectate / 0 fapte derivate» sunt auditul lui Codex — nu le-am putut verifica independent (citirea directă din baza de producție cere aprobarea ta). Două SELECT-uri simple înainte de aplicare închid subiectul.
Golul găsit: widgetul te pune să suni degeaba
Regula e a ta, din 13 iulie:
„Recent contact on any channel relaxes the phone CTA, because communication is communication.”
Decizia ta de produs, ADR-0092 §5 — widgetul Who-to-call
Problema: widgetul caută «contact recent» doar printre interacțiunile de tip call. Înainte de fix, WhatsApp-urile treceau drept «call» și — din greșeală — linișteau widgetul. Acum, corect etichetate «message», devin invizibile pentru el.
Încearcă ambele butoane. Doar apelul real liniștește widgetul — WhatsApp-ul, deși e contact, nu.
Severitate P2, confirmată de 4 verificatori independenți. Nuanță corectă: golul exista deja pentru mesajele logate manual — fix-ul îl extinde la importurile de text și la cele 10 rânduri istorice, nu îl creează. Reparația e o linie: query-ul widgetului să accepte toate tipurile de contact (call, meeting, message, email), plus un test. De făcut în același branch, înainte de merge.
Verdictul
| Dimensiune | Verdict | Pe scurt |
|---|---|---|
| Valoare în producție | clară | corectează pagini pe care le folosești zilnic + oprește fapte persistate false |
| Calitatea codului | peste bară | mai simplu decât cerea issue-ul; toți apelanții verificați |
| Migrarea | sigură | idempotentă, țintește precis, apelurile reale neatinse |
| Testele | reale | execută SQL-ul adevărat, regresia cerută există la API + CLI |
| Docs + skills | complete | toate cele 4 docs + skill-ul actualizate; nimic rămas stale |
| Who-to-call | P2 | mesajele nu mai liniștesc widgetul — contrazice regula ta din ADR-0092 |
| Cifrele de pe prod | de verificat | «10 rânduri / 0 derivate» = claim Codex; 2 SELECT-uri le confirmă |
Mărunțișurile (P3 — niciunul blocant)
- Parametrul seam-ului acceptă tot enum-ul de tipuri, deși doar
callșimessageau sens — taste, nu risc. - Lipsesc câteva teste negative pe plasa de siguranță a migrării (cazurile care NU trebuie rescrise).
docs/API.mdlistează endpoint-ul import-text dar nu-i documentează body-ul.- Un email lipit devine tot
message, nuemail— decizie conștientă, documentată; issue-ul o dădea doar ca alternativă.
Ce facem concret
- 1Fix who-to-call în același branch — query-ul lărgit la toate tipurile de contact + un test. Singura condiție reală pentru merge.
- 2Cele 2 SELECT-uri pe producție — confirmă «10 rânduri / 0 derivate» înainte de a aplica migrarea (le rulezi tu, sau eu cu aprobarea ta).
- 3Merge → deploy → migrare — pe fluxul standard; commit-ul
1800f80ae local pe branch-ul Codex, nimic împins încă.
„Communication is communication” — acum e adevărat și în date.
Mai rămâne widgetul.