fix(console): Config de Risco salva com confirmação explícita (M1)#113
Merged
Conversation
Bug revelado pelo uso real na VPS (dividendo do de-mock 5.x — a UI passou a bater na
API real): a Config de Risco não salvava. Duas causas em screen_settings:
(1) cada slider/campo disparava PATCH direto no onChange (chatty), e
(2) patchRiskConfig não enviava confirm → o backend (risk.py:310) responde 400
confirmation_required a cada arraste.
Fix (padrão do aviso do A5): as edições dos 3 cards (Sistema, Risco, Guardrails)
acumulam num DRAFT local; um botão "Salvar" por card abre um modal de confirmação
com o resumo before→after; só ao confirmar o PATCH é enviado — e o de risco vai com
confirm:true. Nada mais de PATCH-a-cada-onChange.
Auditoria dos irmãos (pedida): só /v1/risk/config tem o gate confirm=true; /v1/config
e /v1/alerts/config não têm o gate, mas ganham o mesmo fluxo acumular+confirmar
(elimina a chattiness). /v1/agents/{id}/config é editado no drawer de Agentes (fora
deste screen, sem gate). Nota: o card de Guardrails hoje não renderiza (alertConfig
nunca é buscado no load) — refatorado por consistência/futuro, mas é caminho morto.
Fixture (regressão trava para sempre): PATCH /v1/risk/config passa a EXIGIR
confirm===true (400 confirmation_required sem ele), espelhando o backend; +PATCH
/v1/config canned. Novo spec config_save.spec: edição só acumula (0 PATCH no
onChange) → Salvar mostra o diff before→after → Confirmar envia 1 PATCH com
confirm:true (sucesso; sem confirm o fixture 400 → o teste quebraria); + cancelar
não envia PATCH.
Validação: config_save 2/2; suíte completa 77 verdes (retries=1); build+guard OK.
Diff 100% frontend (docs/design/pages/); backend intacto.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UZ3vLNTHKekjQVtjFVRi5D
danzeroum
pushed a commit
that referenced
this pull request
Jul 21, 2026
…ona (M4)
reset_paper_state.py estava "inoperável como documentado" na VPS. A exploração
mostrou que o fix é menor que o descrito: --yes JÁ existe e o docstring JÁ usa
`python -m`. Os tropeços reais eram dois:
1. EOFError: sem --yes e sem TTY (`docker compose exec` sem -it), o input() do prompt
estourava um traceback. Fix: try/except EOFError em main() → aborta limpo
(return 1, sem traceback) com mensagem apontando --yes.
2. Doc de operação: o fluxo documentado era `stop orchestrator → python -m … → start`,
mas (a) rodar `python -m` no HOST não tem o ambiente (é dockerizado) e (b)
`docker compose exec orchestrator` falharia — exec exige container DE PÉ e o
fluxo para o orchestrator. Fix: a linha não-interativa passa a mirar o container
`app` (fica de pé, compartilha o mesmo volume ./data / LEDGER_DIR que o
orchestrator — confirmado no docker-compose.vps.yml), com --yes (sem TTY):
docker compose -f docker-compose.vps.yml stop orchestrator
docker compose -f docker-compose.vps.yml exec app python -m scripts.reset_paper_state --yes
docker compose -f docker-compose.vps.yml start orchestrator
Reforçado também que a invocação é SEMPRE `python -m` (rodar `python
scripts/reset_paper_state.py` daria ModuleNotFoundError: src).
NÃO adicionei bootstrap de sys.path: bateria no gate E402 do ruff (select E4) e
fugiria da convenção `python -m` de todos os scripts do repo.
Testes (tests/test_reset_paper_state.py — antes só cobriam a função pura, não o
main() CLI; LEDGER_DIR isola ledger E app db via get_db_path):
- +test_main_yes_resets_without_prompting (--yes pula o prompt e reseta; input()
não é chamado).
- +test_main_eof_without_yes_aborts_cleanly (EOFError → return 1, sem traceback,
estado intacto).
Validação: pytest completo verde, cobertura 78.12% ≥ 72%; ruff (gate) limpo.
Fecha a faixa de manutenção M1–M4 (M1 #113, M2+M3 #114, M4 este PR).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UZ3vLNTHKekjQVtjFVRi5D
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
M1 · Config de Risco salva com confirmação explícita
Primeiro da faixa de manutenção pós-validação VPS. Bug revelado pelo uso real (dividendo do de-mock 5.x — a UI passou a bater na API real). Diff 100% frontend (
docs/design/pages/); backend intacto.Bug
A Config de Risco não salvava. Duas causas em
screen_settings:PATCHdireto noonChange(chatty);patchRiskConfignão enviavaconfirm→ o backend (risk.py:310) responde 400confirmation_requireda cada arraste.Fix (padrão do aviso do A5)
As edições dos 3 cards (Sistema, Risco, Guardrails) acumulam num draft local; um botão "Salvar" por card abre um modal de confirmação com resumo before→after; só ao confirmar o PATCH é enviado — e o de risco vai com
confirm:true. Fim do PATCH-a-cada-onChange.Auditoria dos irmãos (pedida)
/v1/risk/configtem o gateconfirm=true;/v1/confige/v1/alerts/confignão têm o gate, mas ganham o mesmo fluxo acumular+confirmar (elimina a chattiness)./v1/agents/{id}/configé editado no drawer de Agentes (fora deste screen, sem gate).alertConfignunca é buscado no load) — refatorado por consistência/futuro, mas é caminho morto (finding separado, fora do M1).Fixture (regressão trava para sempre)
PATCH /v1/risk/configpassa a exigirconfirm===true(400 sem ele), espelhando o backend; +PATCH /v1/configcanned. Novoconfig_save.spec: edição só acumula (0 PATCH no onChange) → Salvar mostra o diff before→after → Confirmar envia 1 PATCH comconfirm:true(sucesso; sem confirm o fixture 400 → o teste quebraria); + cancelar não envia PATCH.Validação
config_save2/2; suíte completa 77 verdes (--retries=1);node build.mjs+ mock-guard OK.🤖 Generated with Claude Code
Generated by Claude Code