Phase gate: awaits owner approval (loop/checkpoints/G6.approved) — which is
the trigger for the Vendaval FG phase. Closes the G1-G6 governance epic.
7 open inbox items (proposal/non-vetting) in report §3.
Audit: flag was absent in code (docs/plan only — vendaval chain didn't bring
it) → full implementation, not no-op. ai_dispatch_mode is a new key in
organizations.settings jsonb (Zod enum native|external, .catch('native')
fail-safe) — no schema migration. Native dispatcher skips 'external' orgs
BEFORE claim (pure continue: no claimEvent, no markEventProcessed, consumed_by
untouched) → event stays pending for Vendaval. skipped_external_dispatch is the
only non-consuming skip. Native unchanged (regression tested).
Verified-by: gov-verifier PASS 2026-07-18T21:19:20-0300
Closes INB-13 (runtime bug): dispatcher wrote status 'processed'/'failed'
which violate event_log_status_check (pending|processing|done|dead) — UPDATE
failed at runtime, event stuck in pending (latent reprocessing). Fix:
processed->done (:403), failed->dead (:456, terminal branch — retry stays in
requeueEvent as pending+backoff, not collapsed). No migration (constraint
correct, code wrong). Invariant proves the violation + full done/dead cycle;
no downstream reader of the old statuses. Mirrors G5-02 routing-worker.
Verified-by: gov-verifier PASS 2026-07-18T19:30:19-0300
Closes INB-10 (G6-03 precondition): SELECT of crm_lead_activities/crm_lead_links
now requires parent-lead visibility via EXISTS + fn_can_view_lead (reused from
G4-03, not scalar-subquery). crm_lead_links FOR ALL dropped, re-expressed
per-command. Write kept org-scope (polymorphic timeline written by service
role/AI/panel must not break — service-role-insert=1, agent-own-insert=1).
gov-5e (8 tests): cross-attendant reads = 0, own = 1, manager org-wide.
Verified-by: gov-verifier PASS 2026-07-18T19:07:30-0300
'Atendimento' tab in app/app/team: agent+ roster with honest status
(isHeartbeatStale), current load (OPEN_LOAD_STATUSES single source — worker
imports it), inline capacity/schedule (manager+), routing mode card
(manual|round_robin; 'load' disabled) via PATCH /settings/routing. GET
extended to self-sufficient org-scoped roster (service role + manual org
filter) since /team RLS limits manager to own row. No migration.
config-worker 4/4: mode/capacity/backoff changes reflect in worker.
Verified-by: gov-verifier PASS 2026-07-18T12:37:35-0300 (resumed after auth error)
Queue ordered by wait time (last_inbound_at ASC, id ASC tiebreak) with
position + 'Aguardando há X' — single time source, order matches position.
Count == counts.unassigned. Notification = unread badge + realtime (fallback;
no new system, decision in spec §5). No migration; fn_conversation_assign
already zeroes unread on assign (tested worker path 7->0).
Verified-by: gov-verifier PASS 2026-07-18T11:40:45-0300 (re-verified after hash false-positive)
AFTER INSERT trigger emits conversation.routing_requested only when a
conversation is born unowned (no UPDATE trigger → worker's assign can't
re-emit: anti-echo by construction). Worker claims via event_log status
(pending/processing/done/dead), assigns via fn_conversation_assign(reason=
routing) atomically; pure decide.ts (round_robin/manual/backoff/dead).
Idempotent (optimistic lock), backoff from config, load unreachable by schema.
gov-4b invariant (7 tests): anti-echo count stays 1 after 2 assigns.
Verified-by: gov-verifier PASS 2026-07-18T10:58:19-0300
Nested worktree .claude/worktrees/webhooks/ (Vendaval fusion) polluted vitest:
275 files/5218 tests instead of our 165, plus double-React (worktree node_modules)
breaking component tests with useContext null. Add .claude/** to exclude and
fix node_modules glob to **/node_modules/**. Suite back to 165 tests.
Spec §6 defined before code (won/lost by owner, conversations by assignee,
TTFR = first human outbound minus first inbound, bot excluded via
sent_by_user_id). fn_attendant_metrics SECURITY INVOKER — RLS 0035/0036 is the
gate (agent aggregates own only, manager+ org-wide + filter). Migration 0037:
2 partial indexes; EXPLAIN under agent AND manager roles, no seq scan.
User-scoped route, new Desempenho page. gov-8 asserts exact numbers.
Verified-by: gov-verifier PASS 2026-07-17T15:00:26-0300
Tab 'Todas' hidden for agent when visibility_mode != all (cosmetic); real
guard is G4-01 RLS. Counts via user-scoped GET /conversations/counts (inherits
RLS, never admin — gov-5b proves agent all=2 < manager all=3). Tab in URL
?filter=; out-of-scope deep-link -> clear empty state, no stack trace.
Verified-by: gov-verifier PASS 2026-07-17T13:09:02-0300
Hardening from INB-07: 6 write definers were anon-executable (Group A via
direct grant, Group B via inherited PUBLIC). 0034 revokes accordingly and
re-grants Group B to authenticated/service_role; invariant proves all 6
permission-denied under real anon role. Closes INB-09: bulk owner validation
fails closed when service role absent, org resolved from authz not first lead.
Verified-by: gov-verifier PASS 2026-07-17T10:58:01-0300 (re-spawned after API timeout)
Checkpoint: loop/checkpoints/G2-report.md (COMPLETO, 4/4)
Aprovação: loop/checkpoints/G2.approved (by Rafael via Maestro, opção A)
Conflito em plan/progress.md resolvido preservando ambos os lados (append-only).
Envs de exceção por MERGE DE FASE (conteúdo já verificado na gov/G2):
- MIGRATION_EDIT: 0030 vem da gov/G2 por merge, não é colisão nova.
- INVARIANTS_EDIT: flip da catraca gov-1-rbac (2 GAP(G2) → testes normais),
feito na G2-03 sob a mesma env e citado naquele commit (f3954ab).
4 e2e tests proving the role matrix in the browser (agent 403, admin in
via real TOTP challenge, viewer message denied); seed extended with viewer
+ idempotent admin TOTP; billing page gains the missing admin-only gate.
Verified-by: gov-verifier PASS 2026-07-16T23:29:21-0300
Single handler in _shared.ts (admin gate, last-admin guard, Zod, audit
team.role_changed appended to union); /role kept as thin alias; inline
role selector with optimistic update + rollback; 8 new tests.
Verified-by: gov-verifier PASS 2026-07-16T22:52:28-0300
Typecheck estrito falhava com 12 erros no script da máquina do loop.
Tipagem real (sem any/casts), validações explícitas antes de qualquer escrita.
Verified-by: gov-verifier PASS 2026-07-16T18:50-03:00
Backlog: 27 features em 6 fases (provas/invariantes → RBAC → atribuição →
escopo → roteador/fila/painel → contrato p/ agentes externos), derivado de 7
eixos de feedbacks reais do sistema-modelo (abstraídos, zero PII) + recon do
código (baseline.sql, specs 04/05, MCP tools).
Máquina portada do vendaval-loop: LOOP.md (maker≠checker + hash-check),
checkpoint humano por fase (.approved), gates mecânicos em loop/hooks/
(features.json imutável fora de passes/verification; tripla de migration
migrations+baseline+MANIFEST com NNNN validado contra todas as branches;
tests/invariants/** congelado; push só com DESKCOMM_GOV_PHASE_MERGE=1),
update-feature.ts real, guard PreToolUse com merge aditivo (Lina preservado).
Checkpoint G6 aprovado → dono cria loop/checkpoints/FG-CRM.approved no
Vendaval e destrava a fase FG de lá.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>