Sprint 007 — destravar a sincronização presa¶
Período: 2026-08-12 a 2026-08-18 (cadência de uma semana) Feature: 008 — destravar sync presa Plano: plan.md · Origem: #175, product backlog Análise: rodada antes do código, e mudou a decisão central
Objetivo do sprint¶
Ao fim deste sprint, uma coleta que morreu deixa de bloquear a ferramenta — sem SQL, e sem ninguém precisar abrir a tela.
Hoje o índice único que impede duas coletas simultâneas vira bloqueio permanente quando o trabalho morre. Duas execuções já foram destravadas à mão, e o procedimento está registrado em RETOMAR.md. Precisar de SQL duas vezes é o argumento do sprint.
Lições aplicadas¶
Do registro acumulado, 33 lições. As que entram como restrição:
| Lição | Origem | Como está sendo aplicada |
|---|---|---|
| L02 | Sprint 001 | é a lição que derrubou o resgate automático: coleta duplicada produz número plausível e errado. Ver a seção abaixo |
| L08 | Sprint 002 | contrato escrito antes da primeira função pública, e corrigido quando a implementação mostrou que faltava uma terceira função |
| L11 | Sprint 002 | não vou tocar a configuração de iterations |
| L18 | Sprint 003 | critério atendido não é suficiente: a aceitação avalia os 13 SC com evidência |
| L21 | Sprint 004 | F1 sozinha não entrega nada visível — decisão sem gatilho não destrava nada, e é por isso que F2 está no mesmo sprint |
| L22, L23 | Sprint 004 | gate por código de saída, mix gates, sem \| tail |
| L26 | Sprint 004 | casar o envelope certo: aqui o análogo é conferir o resultado do Oban.insert, que hoje vai para o vazio |
| L27 | Sprint 005 | ciclo completo antes do código — e é a terceira feature seguida na ordem |
| L29 | Sprint 005 | o motivo distingue falha transitória de permanente; um motivo genérico é o defeito que custou 899 issues |
| L30 | Sprint 005 | os números do sprint vêm do banco, não de estimativa: 32 execuções, 5 descartados, 1 órfão de três dias |
| L33 | Sprint 006 | a pergunta "o que a tela diz no dia seguinte" foi feita, e virou a carência de 1 minuto |
A L02 é a que decidiu o desenho, e vale dizer como. O plano tinha aceito configurar o resgate
automático de trabalho órfão com um rescue_after de 60 minutos — 3,7× a coleta mais longa medida.
A análise perguntou se existia proteção além do tempo, e a leitura da fonte respondeu que não:
# deps/oban/lib/oban/engines/basic.ex:189
where([j], j.state == "executing" and j.attempted_at < ^cut)
Nenhuma verificação de nó vivo. A coleta cresce com o número de repositórios, e no dia em que passar de 60 minutos existem duas execuções da mesma coleta, cada uma funcionando. É exatamente a L02 — 32 registros no lugar de 16, e o número passou por correto.
O resgate saiu do desenho. Órfão é encerrado, e a coleta nova recoleta sem duplicar linha, porque a gravação é por chave natural.
O terceiro caminho de travamento, que ninguém tinha visto¶
A mesma análise leu a abertura da execução e achou isto: Repo.insert() e Oban.insert() são
operações separadas, e o resultado da segunda é descartado. Se a criação do trabalho falhar, o
registro fica running sem nada para executá-lo.
Não está nos 5 descartados nem no órfão medido — porque ninguém saberia se já aconteceu. É a T006, e é o tipo de defeito que só aparece lendo o código com a pergunta certa.
Sprint no GitHub¶
Projeto: The Band
Iteração: não existe para este sprint, e é limitação declarada — não esquecimento. Configurar iterations do ProjectV2 recria as existentes (L11), e já custou reatribuir 96 itens. Os sprints 003 a 007 rodam sem iteração própria pelo mesmo motivo.
Tipos: a organização tem Task, Bug e Feature, e não tem Epic nem User Story. Épico
e user stories são tipados Feature, como nos sprints anteriores. A hierarquia carrega o que o tipo
não carrega.
User stories selecionadas¶
| # | User story | Épico | Issue | Priority | Estimate | Estado |
|---|---|---|---|---|---|---|
| US1 | Coletar de novo depois de uma falha | #198 | #199 | P0 | 13 | a fazer |
| US2 | Entender por que a execução morreu | #198 | #200 | P0 | 3 | a fazer |
| US3 | Encerrar à mão o que a plataforma não prova | #198 | #201 | P1 | 5 | a fazer |
US1 e US2 são P0, e é a primeira vez neste projeto. A importance aqui não é preferência: sem elas a ferramenta fica inutilizável e a única saída é SQL no banco de produção. US3 é P1 porque cobre o caso que a plataforma não consegue provar — real, e menos frequente.
Priority é a importance da SRO; Estimate é a complexity. Campo em branco significa
desconhecido, nunca zero.
Tarefas¶
Detalhadas em 008/tasks.md. Cada tarefa é filha da
user story que ela atende — nunca do épico: tarefa sob épico viola sro.rule07.
| # | Tarefa | Atende | Issue | Estimate | Fase | Estado |
|---|---|---|---|---|---|---|
| T001 | Registrar quem encerrou a execução | US1 | #202 | 2 | F1 | a fazer |
| T002 | Achar o trabalho de uma execução | US1 | #203 | 3 | F1 | a fazer |
| T003 | Decidir se a execução está presa | US1 | #204 | 5 | F1 | a fazer |
| T004 | Dizer por que a execução morreu | US2 | #205 | 3 | F1 | a fazer |
| T005 | Não mudar o encerramento já feito | US1 | #206 | 2 | F1 | a fazer |
| T006 | Encerrar quando o trabalho não nasce | US1 | #207 | 3 | F2 | a fazer |
| T007 | Reconciliar a cada cinco minutos | US1 | #208 | 3 | F2 | a fazer |
| T008 | Encerrar a execução presa pela tela | US3 | #209 | 5 | F3 | a fazer |
| T009 | Dizer quem encerrou a execução | US3 | #210 | 2 | F3 | a fazer |
Tarefa não recebe Priority: herda a da user story que atende.
Total: 28 de complexity, nove tarefas.
Escopo confirmado¶
Feature 008 completa — F1 a F3, T001 a T009.
O MVP é F1+F2, e resolve a issue #175 inteira: o bloqueio sai sozinho, sem SQL e sem ninguém abrir a tela. F3 acrescenta o caso que a plataforma não consegue provar — o trabalho consta como executando e quem administra sabe que o processo morreu.
F1 sozinha não entrega nada visível, e está declarado: decisão sem gatilho não destrava nada. É a L21, e é por isso que F2 não é opcional.
Fora do escopo deste sprint¶
| Fora | Por quê |
|---|---|
| resgate automático de trabalho órfão | decide por tempo sem saber se o processo vive; a constante envelhece com a coleta — R1, e é a L02 |
| cancelar coleta em andamento | é outra pergunta: parar o que está vivo, e ninguém pediu |
| painel de trabalhos da fila | a tela mostra coleta, não infraestrutura |
| repetir a coleta automaticamente | quem decide tentar de novo é quem administra; automatizar esconderia falha permanente |
| fila própria para a reconciliação | ela compete por slot em ingestion e, com 5 coletas, espera — atrasa, não impede |
estado stuck |
interrupted serve; a distinção vive no motivo e no autor |
| página de detalhe da pessoa | pedida durante este sprint e registrada em #211 — entra no próximo, com ciclo próprio |
Riscos e dependências¶
| Risco | Mitigação |
|---|---|
| encerrar coleta viva — o defeito oposto, e pior que o problema | a decisão exige ausência de trabalho ativo, nunca idade; o teste insere job executing de verdade |
| lista de estados ativos escrita de memória | são cinco, derivados de Oban.Job.states/0; o teste falha se o Oban acrescentar estado |
| encerrar execução que acabou de começar | carência de 1 minuto, três ordens de grandeza acima da corrida real |
| o motivo apagar a diferença entre falha do momento e permanente | motivo por causa, e o teste exige textos diferentes — L29 |
| gatilho automático apagar decisão humana | age só sobre running; o teste encerra por pessoa e reconcilia depois |
| a reconciliação esperar slot na fila | aceito e declarado: atrasa o destravamento, não o impede |
Nenhuma dependência de outra branch. A 009-destravar-sync-presa sai de main, com os
artefatos já commitados. O PR #197 — a
tagline — está aberto e não bloqueia: nenhum arquivo em comum.
Definition of Done do sprint¶
- [ ]
mix gatesverde pelo código de saída — dez gates - [ ] V1 a V9 do quickstart verificados
- [ ] o job órfão de 2026-08-09 encerrado pela plataforma, não por SQL — é a prova no dado real
- [ ] as nove issues encerradas ou repriorizadas com justificativa
- [ ] PR com revisor pedido e conferido por
requested_reviewers(L14), ligado ao projeto - [ ]
sprint-review.mdescrito, separando feito de não feito - [ ]
licoes-aprendidas.mdatualizado - [ ]
aceitacao.mdcom os 13 SC avaliados um a um