0023 — Exceção sob comando à mão única do write-back¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-09 · Decidido em: 2026-09-09
Contexto¶
A decisão 0013 fixou a mão única do fluxo de entrada PIED: o
upsert do PUT /api/v1/xadm nunca sobrescreve o que o X-Adm gravou pelo write-back —
cod_retorno, msg_retorno, chave_*. A regra existe por um motivo caro: sem ela, todo re-push
de rotina apagaria o retorno de um pedido já gravado no ERP, e o integrador-client o mandaria
de novo — pedido duplicado.
O efeito colateral só apareceu em produção. 1XX é erro terminal: o integrador-client coleta
cod_retorno = '000' OR LIKE '9%' e nada mais. Junte as duas coisas e o resultado é que
reimportar o pedido no painel do int-pied nunca destrava um 1XX — os pushes chegam, são
aplicados, e o cod_retorno continua o mesmo. Do lado do operador, o botão dizia "ENFILEIRADO" e
nada saía: pedido 260079421, 2026-09-08, três cliques, zero reenvios.
A saída era UPDATE na mão no banco de produção, por quem tem acesso — o que não escala e não
deixa rastro.
Decisão¶
Abrir uma exceção sob comando à mão única: POST /api/v1/xadm/retorno/pedido/reenfileirar?xPed=
devolve a 000 (e limpa msg_retorno) as linhas do pedido que morreram em 1XX.
Sob comando é o ponto: a mão única continua valendo para todo caminho automático. O que muda é que passa a existir um caminho explícito, autenticado e auditável para o operador destravar o pedido depois de corrigir o dado na origem.
Recorte deliberado:
- Só
1XX. O filtrocod_retorno LIKE '1%'é o que torna a operação segura.006(já gravado no ERP) re-armado faria o cliente reenviar cadastro que o ERP já tem — duplicaria, exatamente o que a mão única evita.9XXjá retenta sozinho.001(em processamento, marcado pelo cliente) começa com0e não é alcançado. - Só as três tabelas chaveadas por pedido —
contratos,itensped,formulas.propriedadesefonessão chaveadas pelo documento do cliente;estoque, pelo produto. Linha delas presa em1XXcontinua sendo SQL na mão — caso raro, e a alternativa (re-armar por chave de cliente) atingiria pedidos que ninguém pediu para mexer. - Não toca linha soft-deletada. A contagem devolvida é o que o painel mostra ao operador, e ela não pode incluir linha que, para ele, não existe mais.
- Uma transação para as três. O PowerSync replica no commit, então o cliente nunca vê as três tabelas em estado intermediário.
Quem chama é o botão Reimportar do painel do int-pied, sempre depois do push do pedido — a
linha só volta a ser coletável já com o dado corrigido. O curl do
runbook é o mesmo comando na mão, para diagnóstico.
Consequências¶
Zero não é erro. Pedido inexistente e pedido cujas linhas estão todas em 006 respondem igual:
200 com contagens zeradas. 404 seria pior — obrigaria quem chama a distinguir "não existe" de
"nada preso", que para o operador é a mesma frase: não havia o que reabrir.
Uma corrida aceita, não resolvida. O write-back do integrador-client pode carimbar 1XX de
novo logo depois do re-armar. A operação roda sob o XADM_LOCK, mas esse lock não cobre esse
caminho: ele serializa contra o applyPut, que por definição da mão única não escreve
cod_retorno. Quem escreve é o PowersyncController, que não o pega. Estender o lock até lá
significaria serializar o write-back de todos os clientes — caminho quente do sistema — para
fechar uma janela estreita numa operação idempotente, em que o operador vê a contagem e repete.
Trocaríamos uma corrida rara por um gargalo permanente. Fica declarado em vez de escondido.
A 0013 continua em pé. Esta decisão não afrouxa a mão única; nomeia a única porta por onde ela pode ser aberta, e por quem.
Alternativas descartadas¶
- Deixar o upsert zerar
cod_retornoquando o payload muda. Reabre exatamente o buraco que a 0013 fechou: o X-Adm reenvia payload idêntico de rotina, e "mudou" é frágil de definir sobre camposCHARcom padding. - Endpoint que aceita o
cod_retornoalvo. Poder mais amplo do que o problema pede — e o único alvo sensato é000. Parâmetro livre convidaria a re-armar006. - Job que re-arma
1XXsozinho depois de N minutos.1XXé terminal porque alguém precisa corrigir o dado; re-armar sem correção só recria o mesmo erro em laço.
Revisão (2026-09-17) — re-arme automático de cadastro compartilhado com dado novo¶
O caso ADEMIR STEIN (pedido 260081441) mostrou o outro lado da mão única: o PUT de 16/09
atualizou o endereço no espelho (frete novo), mas a linha ficou 006 — e o client só coleta
000/9XX, então o ERP nunca viu a correção. Divergência silenciosa espelho × ERP, sem caminho
operacional (o re-arme sob comando só toca 1XX).
Exceção automática, mais estreita que a alternativa descartada acima — por isso não reabre o buraco da 0013:
- Só cadastros compartilhados (
propriedades,fones,estoque— chave por documento/produto). Linhas de pedido (contratos,itensped,formulas) mantêm a mão única absoluta: re-armá-las duplicaria pedido no ERP, que é o que a 0013 evita. - Só
006com dado realmente mudado.000/9XXjá são coletáveis;1XXsegue com o operador. "Mudou" é comparação insensível a padding/blank (mesmoTexto) e a escala (compareTo) — re-PUT idêntico sossega no006(cobertura emFluxoEntradaIngestIntegrationTest). - O reset limpa
msg_retornoe carimbaupdated_at(mesmo gesto do re-arme por remessa).
Acordo com a equipe X-Adm (Tiago): divergência de endereço em cliente existente se resolve com
uma linha, código 0, endereço do frete — o que o pAbast faz com ela é combinado lá, não aqui.