Skip to content

fix(harness): hook que sai cedo deixa de dar EPIPE em quem escreve o payload - #1039

Merged
GabrielAderaldo merged 1 commit into
devfrom
fix/hooks-stdin-epipe
Oct 6, 2026
Merged

GabrielAderaldo merged 1 commit into
devfrom
fix/hooks-stdin-epipe

Conversation

@GabrielAderaldo

Copy link
Copy Markdown
Contributor

Corrige o vermelho que barrou o #1031. Parecia flake de CI; era corrida.

O que aconteceu

O typecheck + format + lint + test do #1031 falhou em post-compact-rules-reminder.test.ts:201:

Error: spawnSync bash EPIPE
  status: 0, signal: null, code: 'EPIPE'

status: 0 é a pista: o hook terminou com sucesso, e ainda assim o execFileSync lançou.

Causa

Quem invoca um hook escreve o payload JSON no stdin dele. O post-compact-rules-reminder.sh tinha o exit 0 da falta do log antes do payload=$(cat) — saía sem consumir o stdin, e o escritor levava EPIPE.

O sintoma é intermitente porque o buffer do pipe (64 KB) absorve a escrita quando o payload é pequeno e o processo sai rápido. Medido:

payload resultado
~60 B, ~1 KB 5 de 5 OK
~70 KB, ~500 KB 5 de 5 EPIPE

O teste usa ~60 bytes e passava em toda máquina de desenvolvimento. No CI o runner deixou o script sair antes de a escrita completar.

A régua não estava num lugar só

Dos 4 hooks que leem stdin, 3 saíam antes de drenar:

  • post-compact-rules-reminder.sh (o que o CI pegou)
  • logbook.sh
  • log-instructions-loaded.sh

Nos três, a leitura passa para antes de qualquer exit — inclusive antes do cd, que também pode falhar e sair. Varredura depois: nenhum.

O gate, e o erro que ele cometeu primeiro

tests/cleanup/hooks-drain-stdin.test.ts, com payload de 128 KB — acima do buffer, que é o que o torna determinístico. Payload pequeno aprovaria os hooks defeituosos.

⚠️ A primeira versão deste gate passou 4 de 4 com o logbook.sh revertido ao padrão defeituoso. Ela usava um cenário só — CLAUDE_PROJECT_DIR num diretório vazio —, e nele o cd do logbook.sh funciona, então o hook não sai cedo e o defeito não aparece. Media a fronteira errada para dois dos três. O gate roda dois cenários:

cenário cd post-compact logbook · log-instructions
diretório vazio funciona EPIPE ok (não sai cedo)
diretório inexistente falha EPIPE EPIPE

Provado invertido: revertendo o logbook.sh, o gate acusa logbook.sh — projeto inexistente, e só esse caso.

Gate

typecheck ✅ · format:check ✅ · lint ✅ · 11973 testes, fail 0, 20 skipped.

Desbloqueia o #1031.

Assisted-by: Claude-Code:claude-opus-5

…payload

O `typecheck + format + lint + test` do #1031 ficou vermelho em
`post-compact-rules-reminder.test.ts:201` com `spawnSync bash EPIPE`, e o processo
tinha saído com `status: 0`. Parecia flake de CI — não era.

Causa: quem invoca o hook escreve o payload JSON no stdin dele. O
`post-compact-rules-reminder.sh` tinha o `exit 0` da falta do log ANTES do
`payload=$(cat)`: ele saía sem consumir o stdin, e o escritor levava EPIPE. O sintoma
é intermitente porque o buffer do pipe (64 KB) absorve a escrita quando o payload é
pequeno e o processo sai rápido. Medido em 06/10:

| payload | resultado |
| --- | --- |
| ~60 B e ~1 KB | 5 de 5 OK |
| ~70 KB e ~500 KB | 5 de 5 EPIPE |

O CI falhou com ~60 bytes porque o runner deixou o script sair primeiro. Era corrida,
não aleatoriedade — e foi isso que a disfarçou de vermelho de infraestrutura.

A régua não estava num lugar só: dos 4 hooks que leem stdin, **3** saíam antes de
drenar (`post-compact-rules-reminder.sh`, `logbook.sh`, `log-instructions-loaded.sh`).
Nos três, a leitura passa para antes de qualquer `exit` — inclusive antes do `cd`, que
também pode falhar e sair. Varredura depois da correção: nenhum.

O gate que trava a propriedade é `tests/cleanup/hooks-drain-stdin.test.ts`, com payload
de 128 KB — acima do buffer, que é o que o torna determinístico. Payload pequeno
aprovaria os hooks defeituosos, exatamente como o teste existente fazia.

⚠️ A PRIMEIRA versão deste gate passou 4 de 4 com o `logbook.sh` revertido ao padrão
defeituoso: ela usava só um cenário — `CLAUDE_PROJECT_DIR` num diretório vazio —, e
nele o `cd` do `logbook.sh` FUNCIONA, então o hook não sai cedo e o defeito não
aparece. Media a fronteira errada para dois dos três. O gate roda dois cenários:

| cenário | `cd` | post-compact | logbook · log-instructions |
| --- | --- | --- | --- |
| diretório vazio | funciona | EPIPE | ok (não sai cedo) |
| diretório inexistente | falha | EPIPE | EPIPE |

Provado invertido com o segundo cenário no lugar: revertendo o `logbook.sh`, o gate
acusa `logbook.sh — projeto inexistente`, e só esse caso.

Gate: typecheck, format:check e lint verdes; 11973 testes, fail 0, 20 skipped.

Assisted-by: Claude-Code:claude-opus-5
Copilot AI balanced review requested due to automatic review settings October 6, 2026 22:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@GabrielAderaldo
GabrielAderaldo merged commit 685e857 into dev Oct 6, 2026
18 checks passed
@GabrielAderaldo
GabrielAderaldo deleted the fix/hooks-stdin-epipe branch October 6, 2026 23:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants