Audit · issue #1315 · commit 1800f80a (Codex)

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.

Interactionrândul din istoricul clientului: cine, când, pe ce canal
Call Artifactdosarul conversației: transcript, sursă, metadata
Migrarereparația unică pe cele ~10 înregistrări vechi
Who-to-callwidgetul care îți spune pe cine să suni azi
ACTUL 1

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.

Reconstituire: 19 iulie, Secrets Joy Studio
Etajul de sus — istoricul clientului
whatsapp:text conversation type: call
type = call ← hardcodat client: Secrets Joy Studio
Etajul de jos — dosarul conversației
Call Artifact
inputKind = text_conversation ✓ source = whatsapp ✓

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.

ACTUL 2

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.

Camera de import (importConversationArtifact — privată)

Ușa «audio»

apel înregistrat / VoIP / upload

Ușa «text»

voost calls import-text

Ușa improvizată

interactionType?: orice

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.

Ștampila e decisă de ușă, nu de vizitator. Niciun alt drum din cod nu poate crea o clasificare greșită — am verificat toți apelanții: 2 rute audio → call, 2 rute text + CLI → message.

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.

ACTUL 3

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.

Simulare pe date reale
InteracțiuneMarcaj în dosarTip
WhatsApp — Bogdan (Red Angels), 18 iultext_conversationcall
WhatsApp — Secrets Joy Studio, 19 iultext_conversationcall
WhatsApp — Secrets Joy Studio (2), 19 iultext_conversationcall
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_conversation din 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.

ACTUL 4

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.

Widgetul, după fix
Who to call today
Secrets Joy Studiosună azi — acțiune scadentă
Liniște. Contact recent detectat — nu te mai bate la cap. ✓
Clientul rămâne pe listă. Tocmai ai vorbit cu el pe WhatsApp, dar interacțiunea «message» nu contează pentru query-ul widgetului — VC îți spune în continuare să-l suni.

Î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.

ACTUL 5

Verdictul

Scorecard — audit cu 52 de agenți, fiecare finding verificat adversarial de 2
DimensiuneVerdictPe scurt
Valoare în producțieclarăcorectează pagini pe care le folosești zilnic + oprește fapte persistate false
Calitatea coduluipeste barămai simplu decât cerea issue-ul; toți apelanții verificați
Migrareasigurăidempotentă, țintește precis, apelurile reale neatinse
Testelerealeexecută SQL-ul adevărat, regresia cerută există la API + CLI
Docs + skillscompletetoate cele 4 docs + skill-ul actualizate; nimic rămas stale
Who-to-callP2mesajele nu mai liniștesc widgetul — contrazice regula ta din ADR-0092
Cifrele de pe prodde 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 și message au sens — taste, nu risc.
  • Lipsesc câteva teste negative pe plasa de siguranță a migrării (cazurile care NU trebuie rescrise).
  • docs/API.md listează endpoint-ul import-text dar nu-i documentează body-ul.
  • Un email lipit devine tot message, nu email — decizie conștientă, documentată; issue-ul o dădea doar ca alternativă.

Ce facem concret

  1. 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.
  2. 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).
  3. 3Merge → deploy → migrare — pe fluxul standard; commit-ul 1800f80a e local pe branch-ul Codex, nimic împins încă.

„Communication is communication” — acum e adevărat și în date.
Mai rămâne widgetul.

Audit 19 iulie 2026 · issue #1315 · commit 1800f80a · 52 de agenți, findings verificate adversarial