Skip to content

test:db (job obrigatório invariants) reprova em conjunto e passa isolado — gate por sorteio #207

Description

@melgarafael

Medido na main 38888ba, durante a triagem do lote #188#201.

O defeito

pnpm test:db (o job obrigatório invariants) reprova em arquivos que passam quando rodados
sozinhos. Os 82 arquivos de invariante compartilham um Postgres, e o resultado depende de com quem
cada um dividiu o banco.

Rodada cheia, na main 38888ba:

$ pnpm test:db
 Test Files  2 failed | 80 passed (82)
      Tests  2 failed | 578 passed | 1 skipped (581)      EXIT=1

 FAIL tests/invariants/followup-engine.test.ts
   × trigger → end leva 2 ticks (1 avanço de nó por tick)
     AssertionError: expected +0 to be 1
 FAIL tests/invariants/followup-reactivity.test.ts
   × marca next_eval_at=now + wake marker; o TICK do engine classifica…
     AssertionError: expected 0 to be greater than or equal to 1

Os mesmos dois arquivos, isolados, no MESMO commit:

$ pnpm test:db tests/invariants/followup-engine.test.ts tests/invariants/followup-reactivity.test.ts
 Test Files  2 passed (2)
      Tests  20 passed (20)                                EXIT=0

Não é contenção de máquina. As falhas são AssertionError sobre valores de negócio (contagem de
ticks, marcador de wake), não Test timed out — a assinatura de sobrecarga é outra e eu a vi
separadamente nesta mesma sessão, em test:unit, com 10 timeouts e 4 workers que nem subiram.

Já apareceu antes, em outro par

Na triagem do #200, o mesmo padrão com tests/invariants/agent-send-template-turn.test.ts:
AI_NoSuchToolError: … unavailable tool 'send_template' na rodada cheia, verde isolado. Na época eu
não abri issue porque não reproduzi numa rodada limpa — a explicação chata (contenção) explicava o
que eu tinha. Agora reproduziu num par diferente, com assinatura de asserção, e não explica mais.

Por que importa mais do que "teste instável"

invariants é check obrigatório na branch protection. Um gate que passa ou reprova por sorteio:

  1. bloqueia merge legítimo — e o caminho de menor resistência vira "roda de novo até passar", que
    é como um gate deixa de significar alguma coisa;
  2. deixa passar regressão de verdade — se a ordem foi favorável, o vermelho que importava não
    aparece. O CI da main neste mesmo commit ficou verde enquanto eu media vermelho localmente.

O segundo é o caro: o gate de isolamento multi-tenant é justamente este.

NÃO MEDIDO

  • O mecanismo. "Passa isolado, falha em conjunto" é compatível com poluição de estado no banco
    compartilhado e com dependência de ordem/tempo. Não isolei qual, e não vou afirmar o que não medi.
  • Qual arquivo contamina qual. Não fiz bisseção de ordem.
  • Se o CI reproduz. No CI o invariants passou neste commit; a diferença pode ser ordem, paralelismo
    ou carga. Um --sequence.shuffle no CI provavelmente exporia — e é o primeiro experimento que eu faria.

Aceite sugerido

  • identificar o mecanismo (estado compartilhado × ordem), com bisseção
  • tornar cada arquivo de invariante hermético — fixture por arquivo, ou truncate no beforeAll
  • rodar com ordem embaralhada no CI, para o defeito parar de depender de sorte

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions