Commit Graph
5320 Commits
Author SHA1 Message Date
Ian Couto 2e1ecfe4bd Merge branch 'main' of https://github.com/IanCouto/DeskcommCRM into develop
# Conflicts:
#	app/app/agenda/_client.tsx
#	supabase/baseline.sql
2026-09-18 09:12:52 -03:00
Ian Couto 155b2308fb fix(agenda): o e-mail da ficha não derruba o Google, e o campo do cliente volta a ser o rotulado
O lint recusava ler ref no render dos cartões de lembrete — e isso escondia a suíte unitária. A leitura de contacts.email estourava nos invariantes (cliente só com rpc) e o Meet nascia failed. O rótulo 'Quem será atendido' não apontava para o input com o id do contato.
2026-09-18 08:56:15 -03:00
Rafael Melgaço d86fcea95c Merge pull request #1059 from webtecnica/feat/989-gatilho-de-dias-ate-a-data-do-funil
feat(automation): "N days from a funnel date" trigger fires the rule on the deal date field
2026-09-18 08:43:49 -03:00
Rafael Melgaço ed42ad1197 Merge pull request #1146 from melgarafael/fix/cartoes-do-fluxo-legiveis
fix(followup): o construtor de fluxos diz a verdade sobre a regra — etapa escolhida na lista, cartão sem corte e sem jargão
2026-09-18 08:18:24 -03:00
Rafael Melgaço dba2ff9ca0 Merge pull request #1117 from joaopaulomirandamatias/test/EPIC-12-runtime-image-namespace-anchor
test(packaging): ancora namespace no dono do runner
2026-09-18 07:48:44 -03:00
Rafael Melgaço 12d3d31529 Merge pull request #1051 from joaopaulomirandamatias/fix/EPIC-12-e2e-channel-session-cleanup
test(e2e): limpa sessões de WhatsApp semeadas ao fim da suíte
2026-09-18 07:48:40 -03:00
Rafael Melgaço 3b982fa38a Merge pull request #1036 from webtecnica/fix/990-fila-reordena
fix(fila): a espera para de recomeçar a cada mensagem do cliente — quem insiste não desce mais
2026-09-18 07:48:36 -03:00
Rafael Melgaço ba51a53c56 Merge pull request #1005 from Gervanno/fix/worker-pdf-sem-tsx-no-heap
fix(worker): um PDF recebido no WhatsApp não derruba mais o agente
2026-09-18 07:48:31 -03:00
Pessoa 78ddad17a9 Merge remote-tracking branch 'origin/main' into HEAD 2026-09-18 07:06:33 -03:00
Rafael Melgaço 149cc9b5d3 Merge pull request #1135 from webtecnica/feat/1033-localizacao-por-organizacao
feat(organizacao): o país da organização governa documento, lei, prazo e anonimizador (migration 0269)
2026-09-18 07:02:05 -03:00
PessoaandClaude Opus 5 a3b1b4ba0b fix(e2e): a guarda de CLI do cleanup deixa de usar import.meta
O `tests/e2e/global-teardown.ts` deste PR IMPORTA
`scripts/cleanup-e2e-channel-sessions.ts`, e o Playwright transpila o teardown
para CommonJS — onde `import.meta` é erro de SINTAXE.

O sintoma no CI não é o teardown reprovar. Os testes passam:

  134 passed (10.1m) · 2 skipped
  SyntaxError: Cannot use 'import.meta' outside a module  at global-teardown.ts:1
  1 error was not a part of any test
  ##[error]Process completed with exit code 1

A rodada inteira sai vermelha DEPOIS de tudo passar, sob uma linha que não nomeia
teste nenhum — e a `e2e-parte (1)` reprova o agregador `e2e`.

A forma escolhida tem precedente medido neste repo: `scripts/cortar-release.ts`
usa `require.main === module` e é invocado por `tsx` em `release:conferir`, que
roda no CI. O `package.json` não declara `"type": "module"`, então o pacote é CJS.

Controle rodado nos dois ramos, sob `tsx`: executar o arquivo direto entra no if
("RAMO: CLI"); importá-lo não entra ("RAMO: importado").

NÃO PROVADO LOCALMENTE: o controle negativo NÃO reproduziu a falha — com
`import.meta` de volta, o `tsx` importa sem estourar. Quem quebra é o
transpilador do Playwright, e reproduzir isso exige uma rodada de Playwright.
A sonda local não distingue os dois estados, então ela não vale como prova.
Quem prova é o `e2e` do CI.

Crédito do PR: @joaopaulomirandamatias.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 06:27:52 -03:00
Rafael Melgaço f7b86cbb8d Merge pull request #1156 from melgarafael/triagem/cerca-le-cliente-injetado
test(seguranca): a cerca de organizations passa a ler o cliente admin injetado — pelo TIPO, não pelo nome
2026-09-18 06:24:37 -03:00
Rafael Melgaço 429c802a49 Merge pull request #1120 from joaopaulomirandamatias/fix/EPIC-12-test-db-update-readiness
fix(ci): evita corrida com Postgres temporário no test:db:update
2026-09-18 06:24:33 -03:00
PessoaandClaude Opus 5 54213085dd fix(dreno): o backoff da volta entra na SEGUNDA, não na primeira (opção A)
O PR conserta um laço real: o processo morria antes de o handler devolver erro,
`attempts` não subia, e o evento envenenado tinha tentativas infinitas — 313
reinícios do worker em produção. A contagem na volta conserta isso.

O backoff junto da contagem, porém, colide com o invariante
`tests/invariants/event-log-drain.test.ts` caso 9, que afirma — com a razão
escrita lá — que o órfão volta para a fila E É PROCESSADO NO MESMO TIQUE. Com
`backoffAt(1)` = agora + 2 min, o evento sai do tique e o caso reprova.

Esta é a opção (A) que a triagem ofereceu a @Gervanno: o backoff entra a partir
da SEGUNDA volta (`preso.attempts >= 1`). O laço quebra igual — o envenenado
volta uma vez de graça e da segunda em diante paga 2, 4, 8… min até
`MAX_ATTEMPTS` —, e o órfão legítimo de deploy não passa a pagar espera.

A escolha entre (A) e (B) era do autor e ele não respondeu em dois dias, com um
P0 parado. Escolhi a (A) e a razão mudou desde o parecer: a (B) exigiria EDITAR
`tests/invariants/event-log-drain.test.ts`, e o caminho sancionado pelo hook de
congelamento é acrescentar arquivo, não editar (issue #1161). @Gervanno pode
vetar — é o desenho dele.

Guarda, em par, no arquivo de teste que já existia:
  · primeira volta ⇒ `next_attempt_at` NULO (elegível no mesmo tique)
  · segunda volta  ⇒ `next_attempt_at` no futuro

O par importa: sem o segundo caso, trocar a condição por "nunca dar backoff"
passaria verde e traria os 313 reinícios de volta.

Crédito do PR: @Gervanno.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 06:18:23 -03:00
Pessoa ae0786a0e2 Merge remote-tracking branch 'origin/main' into HEAD 2026-09-18 06:12:33 -03:00
PessoaandClaude Opus 5 581853b1d6 merge: traz a main (#1135) — o apêndice do baseline fica com os DOIS blocos
Conflito único, em `supabase/baseline.sql`: os dois lados acrescentaram bloco no
mesmo ponto de inserção — a 0277 (país da organização, desta branch) e a 0266
(transferência entre funis não é perda, que entrou na main pelo #1057).

Resolução: ficam os DOIS, em ordem de número — 0266 antes de 0277, e os dois
antes do bloco da VARREDURA anon, que segue sendo o último do arquivo.

Provado por md5, não por leitura:
  bloco 0266 resolvido == bloco 0266 da main .......... df5a9869…  idêntico
  bloco 0277 resolvido == bloco 0277 do head anterior . 4397f359…  idêntico
  cabeçalho do bloco 0266 aparece 1x (as outras 2 ocorrências são os
  comentários de filtro DENTRO de fn_atrito_metrics e fn_attendant_metrics)
  ordem no arquivo: 0266 < 0277 < VARREDURA anon

DUAS válvulas de governança foram usadas, e as duas por disparo fora do objeto
do guard. Um merge IMPORTA o que a main já decidiu; ele não escolhe nem edita.

  DESKCOMM_GOV_MIGRATION_EDIT=1 — o hook acusou colisão de 0276 entre a main e a
  branch local `triagem/resgate-gyanu2507`. As duas migrations que este commit
  encena (0266 e 0276) JÁ ESTÃO na main: `git cat-file -e origin/main:<arquivo>`
  passa nas duas, com controle negativo num caminho inventado. Nenhum número foi
  escolhido aqui. A colisão real é da branch local (main venceu o 0276).

  DESKCOMM_GOV_INVARIANTS_EDIT=1 — o merge encena UM invariante,
  `tests/invariants/automation-actions-crud.test.ts`, e ele é byte a byte igual
  ao da main (md5 idêntico, controle: md5 de arquivo inexistente difere). A
  versão veio do #1057, já mesclado. Nenhum invariante foi editado aqui.

Consequência que vale mais que este commit: com os dois hooks como estão, a
doutrina de higiene de branch ("atualize a branch com a main ANTES de trabalhar")
é impossível nesta máquina sempre que a main tiver tocado em migration ou
invariante. Reportado na issue #1161.

Crédito do PR: @webtecnica.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 06:11:21 -03:00
PessoaandClaude Opus 5 61a89d7c56 test(fila): invariante novo guarda a régua VIVA da ordem, e discrimina
O `gov-5d-queue-assign-unread` afirma a coerência ordem↔posição com a própria
cópia do ORDER BY (`last_inbound_at asc`) — a régua ANTERIOR à #990. Com a
régua deste PR (`awaiting_since`) ele segue VERDE afirmando uma pergunta que o
produto deixou de fazer, porque calcula a ordem em SQL e não consulta nada.

Ele é o eval congelado do épico de governança e não se edita
(`loop/hooks/freeze-invariants.sh` bloqueia M/D/R; acrescentar é permitido).
Então a proteção que faltava entra como arquivo NOVO, sem driblar a guarda.

Duas propriedades, e a segunda sustenta a primeira:

1. A coluna vem de `ORDEM_DA_ESPERA`, a mesma constante que o handler pede ao
   banco e que numera a posição na tela. Ela não se reescreve aqui.

2. A fixture SEPARA `awaiting_since` de `last_inbound_at` e semeia o defeito da
   #990 — a conversa mais antiga acabou de insistir. Com os dois campos iguais,
   o caso passaria com qualquer uma das duas colunas: verde sem guardar nada. O
   terceiro caso afirma que as duas réguas DIVERGEM nesta fixture, para que
   igualá-las um dia reprove em vez de esvaziar o teste em silêncio.

Commit da triagem, não do autor — o parecer dizia "é a gente que encosta", e
isto não pode entrar antes deste PR porque a coluna nasce na 0267.

Crédito do PR: @webtecnica.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 05:57:57 -03:00
Rafael Melgaço e8a536ce5d Merge pull request #1145 from webtecnica/fix/1040-atualizacao-conta-a-disputa
A rodada de atualização conta o que aconteceu com o banco — disputa, retentativas e passada
2026-09-18 05:51:46 -03:00
Rafael Melgaço 13e0e4f2b3 Merge pull request #1057 from webtecnica/fix/992-regra-nao-cria-segundo-negocio
fix(automacao): a regra transfere o negócio entre funis em vez de criar um segundo
2026-09-18 05:51:11 -03:00
Rafael Melgaço c1cd9b7b94 Merge pull request #1158 from joaopaulomirandamatias/fix/issue-1155-colisao-mede-refs
fix(infra): o conselho de colisão de migration mede as refs do clone e nomeia quem tem
2026-09-18 05:44:47 -03:00
Rafael Melgaço d925799aae Merge pull request #1152 from melgarafael/triagem/proveniencia-939
Proveniência do #939 (@webtecnica) — para ele fechar como MERGED, não CLOSED
2026-09-18 05:31:30 -03:00
Rafael Melgaço 59ec2e1015 Merge pull request #1047 from joaopaulomirandamatias/fix/EPIC-12-sentry-consent-install
fix(kit): pede consentimento antes de ligar telemetria
2026-09-18 05:31:19 -03:00
Rafael Melgaço 0aa9218641 Merge pull request #1042 from joaopaulomirandamatias/fix/issue-993-arm64-kit-diagnostic
fix(kit): recusa ARM64 antes do pull com a causa correta
2026-09-18 05:31:07 -03:00
Rafael Melgaço 21b789062c Merge pull request #1107 from webtecnica/fix/896-agenda-do-atendente-sem-motivo
fix(agenda): o Atendente vê por que a agenda trava, e de quem é o horário (#896)
2026-09-18 05:30:54 -03:00
Rafael Melgaço 8c6b04835f Merge pull request #1143 from webtecnica/fix/1060-update-recupera-sozinho
fix(1060): a atualização numa VPS de outra arquitetura se vira sozinha
2026-09-18 05:30:43 -03:00
Rafael Melgaço ce8f74e8f6 Merge pull request #1010 from webtecnica/fix/888-assign-owner-erro-de-consulta
fix(automacoes): a consulta de membro que falha deixa de virar user_not_in_org — falha transitória com a mensagem do erro
2026-09-18 05:30:31 -03:00
Rafael Melgaço c6d75010bb Merge pull request #1160 from melgarafael/release/1.34.0
Release 1.34.0
v1.34.0
2026-09-18 05:28:29 -03:00
deskcomm-release[bot] 3a4df3cb51 release(1.34.0): a versão montada a partir dos fragmentos declarados 2026-09-18 07:57:39 +00:00
João Paulo 8062cdd4ec test(infra): casos 13-15 da #1155 — ref de fora levanta o teto, régua declarada, alvo não mede a si mesmo 2026-09-18 03:02:22 -03:00
João Paulo 19367c0e9f fix(infra): o conselho de colisão de migration mede as refs do clone e declara a régua
O 'próximo livre' era calculado só em BASE ∪ HEAD: branch local de outra
sessão e head de outro PR aberto ocupavam número invisíveis ao conselho —
num único dia a 0275 nasceu em dois PRs e numa branch local (issue #1155).
Agora mede-se também refs/heads e refs/remotes, excluindo refs que resolvem
para o MESMO commit da base ou do HEAD (o alvo não mede a si mesmo). Quando
outra ref levanta o teto, a saída nomeia QUEM tem o número; onde não há
outras refs (clone raso do CI), a saída declara que não as mediu.
2026-09-18 03:02:22 -03:00
Rafael Melgaço e49062315d Merge pull request #1148 from melgarafael/triagem/lote-extensoes-37
test(kit): o scan do namespace para de reprovar em toda VPS instalada (do #683, @luiscgc91)
2026-09-18 02:28:15 -03:00
PessoaandClaude Opus 5 78cb036833 test(cerca): organizations aceita o cliente admin injetado e TIPADO
A cerca de `organizations` acusava escrita irregular num arquivo CORRETO
(PR #1017, `lib/ai/pontos/padrao-da-organizacao.ts`): ele faz
`p.admin.from("organizations").update(...)` com
`admin: ReturnType<typeof createAdminClient>` declarado no próprio arquivo, e
a cerca via "cliente `p`". Dois mecanismos, os dois medidos em origin/main:
`raizDaCadeia` devolve a RAIZ da cadeia e a propriedade se perde; e
`nomesDoClienteAdmin` só coleta cliente CRIADO no arquivo, então cliente que
chega por parâmetro nunca entra na conta.

Não era furo antigo: 21 arquivos já recebem o cliente por parâmetro e quatro
deles tocam `organizations`, mas todos os quatro só `.select()`. O #1017 é o
primeiro a MUTAR assim, e `MUTACOES` é o que esta cerca olha.

O reconhecimento é prova de TIPO, nunca de nome. Aceitar qualquer `x.admin`
seria trocar a prova por uma senha: bastaria batizar de `admin` um parâmetro
com o cliente de SESSÃO para escrever por baixo da cerca — e essa falha
devolve SUCESSO com zero linhas, então ninguém a descobre pelo sintoma. O que
autoriza é a anotação resolvida no arquivo em
`ReturnType<typeof <fábrica importada de lib/supabase/admin>>`, direto, por
`type` local, por membro de `interface`/tipo literal, ou por desestruturação.

Só PARÂMETRO entra. Variável anotada fica de fora de propósito: o cliente
criado no arquivo já é medido pela ORIGEM, e aceitar a anotação de uma
variável trocaria essa origem por uma promessa que um cast desfaz em silêncio.

`raizDaCadeia`, `ehClienteDeServico` e `passosDaCadeia` não mudam de
comportamento — `admin-client-exige-filtro-de-tenant.test.ts` mede o mesmo
conjunto de cadeias de antes (6/6 verde).

A sabotagem não ficou na minha sessão: dois CONTROLE novos alimentam a
varredura com fonte sintética e cobram as duas direções — as cinco formas
tipadas passam, e `admin` de sessão / `any` / sem anotação continuam
reprovados. Trocar a prova de tipo por prova de nome no helper deixa o
segundo vermelho.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 02:24:33 -03:00
João Paulo 2aeb174fa9 Merge remote-tracking branch 'origin/main' into fix/issue-993-arm64-kit-diagnostic 2026-09-18 02:17:55 -03:00
João Paulo b14041bbf6 Merge remote-tracking branch 'origin/main' into fix/EPIC-12-sentry-consent-install 2026-09-18 02:16:13 -03:00
João Paulo 0eba1a69ad Merge remote-tracking branch 'origin/main' into fix/EPIC-12-e2e-channel-session-cleanup 2026-09-18 02:15:21 -03:00
João Paulo f797fdc978 Merge remote-tracking branch 'origin/main' into fix/EPIC-12-test-db-update-readiness 2026-09-18 02:13:50 -03:00
João Paulo a1c4b9c68c Merge remote-tracking branch 'origin/main' into test/EPIC-12-runtime-image-namespace-anchor 2026-09-18 02:13:03 -03:00
Rafael Melgaço 1911e80913 Merge pull request #1127 from joaopaulomirandamatias/test/EPIC-12-docker-image-list-guard
test(packaging): prende listas de imagens à matriz Docker
2026-09-18 02:10:27 -03:00
PessoaandClaude Opus 5 9d82442146 docs(release): credito do #1051 no fragmento, como nos dois irmaos
Os outros dois PRs do mesmo contribuidor nesta rodada creditam no corpo do fragmento
("Credito: @joaopaulomirandamatias.") e este nao creditava — conferido nos tres:
#1042 credita, #1047 credita (commit 9d53141fb), #1051 nao.

Isto tambem TORNA VERDADEIRA a mensagem do commit 9d53141fb, que afirmava que "os outros
dois PRs do mesmo contribuidor nesta rodada creditam no corpo do fragmento". A afirmacao
estava falsa quanto a este PR, e reescrever a mensagem exigiria reescrever historico da
branch do autor, o que nao se faz. Consertar o mundo em vez do texto e o caminho certo aqui:
o credito no changelog e o que o projeto quer de qualquer forma.

Impacto segue `nada_mudou`: nenhuma frase nova sobre quem ja instalou.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 01:34:59 -03:00
webtecnica 493ba8de7e test(#1040): isola a asserção do corpo do run_result (o nome da função de leitura não é a chave aninhada) 2026-09-18 01:33:49 -03:00
PessoaandClaude Opus 5 8d74787adf Merge de proveniência do #939 (@webtecnica) — o conteúdo dele já está na main
Isto NÃO traz código: é o registro de proveniência para o GitHub fechar o #939 como
MERGED, no nome do autor, em vez de CLOSED — que para quem contribui lê como recusa.

Medido antes, arquivo por arquivo contra `origin/main`: dos 11 que o PR toca, **10 são
IDÊNTICOS** ao da main (incluindo `lib/leads/origem-do-site.ts`, `lib/channels/pos-entrada.ts`,
`lib/leads/nascimento-do-lead.ts` e os três testes). O único que diverge é
`lib/i18n/dicionario.ts`, o dicionário compartilhado que quase todo PR toca — divergência ali
é acúmulo de outras entradas, não trabalho dele que faltou.

O único commit fora da main na branch dele é o merge da main que ele próprio fez
(`9f3d85fc3`), não trabalho novo. Por isso `-s ours` aqui não descarta nada.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 01:32:54 -03:00
Rafael Melgaço bc35e0d876 Merge pull request #1125 from melgarafael/integracao/triagem-17set-37-desbloqueio
Triagem 17/09 — lote desbloqueio: a origem do site no WhatsApp (#939) e a latência do turno de IA (#849)
2026-09-18 01:30:10 -03:00
PessoaandClaude Opus 5 f92ad28dbd docs(release): o fragmento do #1010 promete o que a tela faz hoje
O texto dizia que "o historico da regra mostra a mensagem do erro da consulta". Medido em
`origin/main`, isso nao acontece: `detail.erro` tem ZERO ocorrencias em
`app/app/webhooks/_components/ActivityTab.tsx`, e `membro_indeterminado` nao esta no mapa
`MOTIVO_DA_PARADA` (:73), cujo `explicacaoDe` (:95) devolve o codigo CRU quando a chave falta.
Ou seja: o operador le `membro_indeterminado`, nao a mensagem do erro.

O PR continua melhorando de verdade, e o texto novo diz exatamente isso: antes o historico
dizia que o responsavel escolhido estava FORA da organizacao — acusava a configuracao e mandava
mexer no que estava certo. Agora nao acusa. A frase amigavel na aba Atividade e outro trabalho,
que corre a parte (issue #1090).

Fragmento que promete tela inexistente vira changelog falso na mao de quem opera a VPS: ele
procura a mensagem do erro, nao acha, e conclui que a atualizacao nao pegou.

Autoria do conserto de codigo permanece com @webtecnica; este commit toca so o texto do fragmento.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 01:21:36 -03:00
Pessoa ea238b8d83 Merge main 946313098 na branch do PR #1010 — base 504 commits atras; sem force, sem rebase 2026-09-18 01:21:11 -03:00
Rafael Melgaço 9463130988 Merge pull request #1132 from melgarafael/triagem/prova-de-tela-agenda-17set
test(e2e): as duas jornadas de tela do lote de agenda (#1013, #1070) — primeira execução é o CI deste PR
2026-09-18 01:20:15 -03:00
webtecnica 9f505ced8d Merge remote-tracking branch 'origin/main' into fix/990-fila-reordena 2026-09-18 01:14:10 -03:00
webtecnica 29edd973fb test(#990): o caso que vermelhece se a linha da espera sair
O mantenedor pediu o conserto das duas linhas "mais um caso que vermelhece se a
linha sair". O caso afirma as duas metades: a coluna `last_inbound_at` no
`select` da conversa e o `awaiting_since` no update da resposta — a régua que a
Fila usa para posição e para a média que o cliente ouve.
2026-09-18 01:13:58 -03:00
webtecnica 7f791046aa Merge remote-tracking branch 'origin/main' into fix/1040-atualizacao-conta-a-disputa 2026-09-18 01:12:31 -03:00
webtecnica ad7da221f1 fix(#1040): a rodada do banco chega na rota — e não afirma fechamento que não houve
Os três consertos do review, todos com prova:

- O fio. `ler_rodada_do_banco` passa a imprimir as três chaves PLANAS e com os
  nomes que a rota lê (`disputa_de_banco`, `retentativas_do_banco`,
  `passada_do_banco`), e o `agent.sh` as manda no corpo do `run_result`. Antes
  ele aninhava um objeto em `rodada_do_banco` com `disputa`/`retentativas`/
  `passada`: o `z.object` descarta chave desconhecida em SILÊNCIO, os três campos
  opcionais chegavam `undefined` e as colunas eram gravadas NULAS em toda rodada
  — a tela ficava calada, que é exatamente o silêncio que este PR veio tirar.
  Trava: caso em `route.test.ts` com o corpo literal do kit, e caso de unidade
  que amarra os mesmos nomes nos três arquivos (kit, agent.sh e rota).

- O desfecho. Rodada que NÃO fechou o banco não registra mais nada: o esgotamento
  gravava os MESMOS números do sucesso, e o erro fatal gravava um `0 0 1` que
  ninguém mediu. As frases da tela são todas escritas como "…até a atualização do
  banco fechar", então silêncio é o degrau certo. Trava: seção 10 da prova de
  shell — o arquivo fica vazio, com controle positivo de que a rodada aconteceu.

- O ramo morto. `disputa: false` com `retentativas >= 1` é impossível por
  construção (os dois saem do mesmo contador de passadas: `disputa = passadas > 1`
  e `retentativas = passadas - 1`), então virou `null` em vez de uma frase para um
  estado que ninguém produz — e o teste que o cobria saiu junto.

A coluna da rodada também deixa de poder derrubar o desfecho: ela sai numa escrita
própria, antes da que fecha o run, e best-effort. Na escrita única de antes, um
42703 (banco anterior à migration da rodada) ou a CHECK recusando o número virava
500, o `post` do agente voltava vazio e o run ficava preso em `dispatched` para
sempre — o desfecho que ninguém detecta.
2026-09-18 01:12:09 -03:00
Rafael Melgaço 9032ce7252 Merge pull request #1088 from Drmachado0/feat/agenda-abrir-dia
feat(agenda): abrir um dia de atendimento pela tela, e não só fechar
2026-09-18 01:11:44 -03:00