Skip to content

Tratar redirect em escritas como resultado incerto TG-274 - #16

Merged
cedric-lamalle merged 5 commits into
mainfrom
TG-274
Oct 4, 2026
Merged

cedric-lamalle merged 5 commits into
mainfrom
TG-274

Conversation

@cedric-lamalle

@cedric-lamalle cedric-lamalle commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

US #274, fase 4 da taiga-cli (épico #242). Nenhuma escrita curada já enviada sai mais com exit 7 (repetível) quando a resposta é redirect 3xx. Vale também para rede depois de aberta a conexão e para 5xx. Exit 7 fica para leitura pura, para conexão que nem abriu (DNS, conexão recusada) e para taiga api e login, que não têm como conferir. A CLI continua sem seguir Location.

Levantamento

escrita antes (3xx) depois código
story update/close (bloqueio, swimlane, campos) unexpected_redirect, exit 7 releitura: campos lá = sucesso story_update_unconfirmed (1)
story update com responsáveis exit 7 releitura + conferências do pós-condição de responsáveis + version seguinte story_update_unconfirmed (1)
story field set exit 7 releitura com version seguinte (como na task) story_update_unconfirmed (1)
story comment exit 7 sempre incerto, nomeia comentários novos comment_unconfirmed (1)
story create (com ou sem --epic) exit 7 sempre incerto, nomeia candidatas, não vincula o épico story_create_unconfirmed (1)
attachment upload exit 7 sempre incerto, nomeia ids novos attachment_unconfirmed (1)
field create (e campo do project apply) exit 7 sempre incerto, nomeia a definição achada field_create_unconfirmed (1)
project apply: status exit 7 (5xx também) sempre incerto, nomeia o status achado status_create_unconfirmed (1)
project apply: reordenação tratado como recusa, exit 7 releitura decide; releitura falha: incerto status_order_unconfirmed (1)
task create/update/close/field set, epic link, DELETE da troca de épico já incerto sem mudança de comportamento —
task comment sucesso se achava o comentário sempre incerto (opção B) comment_unconfirmed (1)

Decisões

  • Um critério só, uncertain(err), para story e task: kind.confirmUncertain e kind.unsure saíram. O PATCH de story passa a conferir por releitura também em 5xx e rede, que antes davam exit 7.
  • A opção B (decisão de 2026-10-03) foi estendida a story create, comentário de story e de task, anexo, field create e status do project apply. Resposta inconclusiva nunca vira sucesso, mesmo com a candidata encontrada, e o recovery não sugere criar de novo. Isso muda o contrato documentado de comentário e anexo, que antes davam sucesso quando achavam a escrita (também em 5xx). Corpo perdido depois de um 2xx continua sucesso: a gravação é certa.
  • story create lê users/me e as stories desta conta antes do POST (baseline sem relógio, como a task). Candidata é uma story nova desta conta com o mesmo subject.
  • Em campo e status, o recovery informa que o Taiga recusa nome repetido (probes já existentes), então rodar de novo nunca duplica.
  • findTask virou unconfirmedCreate, compartilhado por story e task.

Revisão adversarial

A revisão encontrou quatro pontos, nenhum crítico. Os quatro foram corrigidos, cada um com um teste que antes falhava:

  • project apply saía com exit 7 quando uma leitura falhava depois de ações já aplicadas. Agora sai project_apply_interrupted (exit 1), com o código original na cause.
  • Um PATCH recusado por version cuja releitura para a nova tentativa falhava saía como *_update_unconfirmed ("may have been applied"). Agora sai o erro dessa leitura (taiga.RefusedWriteError), porque nada foi gravado.
  • O corpo do 3xx, que cita para onde o redirect aponta, ia para a cause. Agora sai "redirect not followed". O fake dos testes passou a mandar Location e esse corpo também no caso não aplicado.
  • O recovery de story create --epic incerto não citava o épico. Agora indica taiga epic link EPIC REF.

Rodada 1 da revisão

A revisão apontou um caso no project apply. O POST do status na primeira ação recebia 201 com o corpo perdido e a releitura de conferência falhava (3xx, 5xx ou rede). A CLI saía com o erro dessa leitura, exit 7, e o status já estava gravado. Agora o 400 de nome duplicado, que é recusa, é tratado separado do corpo perdido depois de 2xx, e o segundo caso sai write_applied (exit 1). Testes novos, de unidade e de integração, falham sem a correção. Nas demais escritas o caso já terminava em exit 1.

Testes

  • go test -race ./..., go vet e golangci-lint (com e sem --build-tags integration): verdes.
  • TestEveryCuratedWriteRedirectIsUncertain (unidade): 15 escritas × 301/302/303/307/308 × aplicado e não aplicado. O teste fixa exit, código, envio único, stdout vazio na falha e Location nunca citado. Fica vermelho no main para cada escrita alterada.
  • TestIntegrationCuratedWritesRedirectIsUncertain (Taiga local): 20 escritas, aplicado e não aplicado, por um proxy que responde 302 com Location para uma armadilha que conta acessos. Também fica vermelho no main.
  • Testes ajustados ao contrato novo: comentário e anexo achados, status com 502 no project apply, story PATCH com 503.
  • Códigos novos entram em TestEveryCuratedCommandHidesTokens.

Documentação

docs/errors.md ganhou uma regra geral, os códigos novos (story_create_unconfirmed, story_update_unconfirmed, field_create_unconfirmed, status_create_unconfirmed, status_order_unconfirmed) e linhas revistas para comment_unconfirmed, attachment_unconfirmed, network_error, server_error e unexpected_redirect. README, docs/guia.md e docs/api-notes.md foram alinhados.

@cedric-lamalle
cedric-lamalle merged commit 557596d into main Oct 4, 2026
2 checks passed
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.

1 participant