Contexto
Segue diretamente de #67 e do hub cross-repo simplicio-loop#579. O framework de DoD escopado (DOD.md, adicionado nesta sessão) e o primeiro property test (crates/codegen/simplicio-runtime-client/tests/fake_server_handshake_proptest.rs, cobrindo o handshake MCP) já implementam a base do item 1 de #67 para simplicio-runtime-client. Esta issue detalha os próximos passos concretos que ficaram fora do escopo cirúrgico daquele PR: os itens (b) e (c) de #67, mais a extensão de (a) para o resto do escopo genuinamente Simplicio.
Motivação (recapitulando #67): 3 bugs reais encontrados nesta sessão no escopo genuinamente Simplicio — code#63 (rede no build sem fallback), code#64 (search_backend construído e descartado do struct-literal de AgentRebuildSpec), code#66 (--always-approve trava indefinidamente em modo headless).
Plano passo a passo
(a) Expandir proptest/fuzzing — só nos crates genuinamente Simplicio
Escopo confirmado em DOD.md: crates/codegen/simplicio-runtime-client, crates/codegen/xai-grok-models, lógica de permissão/aprovação headless. Fora de escopo: a árvore xai-grok-*/xai-acp-* herdada (66+ crates upstream).
simplicio-runtime-client — já tem o property test de handshake (esta sessão). Próximo: um segundo property test para secure_relative_path/secure_glob (as funções de sandbox/path-escape) — gerar combinações de segmentos ../, paths absolutos, símbolos Windows (C:\), unicode/paths mistos /+\, e verificar que a função nunca deixa escapar do repo (nunca retorna Ok para um path fora de repo). Essas funções já têm testes por exemplo; fuzzing generalizaria a garantia de sandbox que é o ponto mais crítico do crate.
xai-grok-models — inspecionar crates/codegen/xai-grok-models/src/lib.rs (196 linhas) e identificar qualquer função de parsing/validação de config de modelo (ex. resolução de aliases, parsing de tencent/hy3:free, seleção de provider) que mereça um property test equivalente.
- Lógica de permissão/aprovação headless — hoje vive espalhada entre
xai-grok-pager/xai-grok-shell (flags --always-approve, --permission-mode). Depois que code#66 fechar (correção em andamento nesta sessão numa branch separada), adicionar um property test ou pelo menos uma tabela de casos exaustiva cobrindo toda combinação {--always-approve, --permission-mode=*} × {-p, posicional} × {tty, sem tty} contra o dispatch de aprovação, para travar a classe de bug que code#66 é (duas flags documentadas como equivalentes divergindo silenciosamente).
(b) Lint customizado — pegar "campo construído, nunca passado ao struct"
Proposto originalmente em #67 item 2. Abordagem sugerida (grep-based, sem exigir plugin de clippy):
- Script
scripts/check-unused-struct-locals.sh (ou .py) que, para cada .rs sob o escopo Simplicio (mesma lista de DOD.md), varre funções que:
- declaram uma
let <nome> = ...; (variável local simples, não _-prefixada), E
- depois, dentro do mesmo bloco de função, constroem um struct-literal (
SomeStruct { ... }) que não referencia <nome> em nenhum campo (nem por shorthand nome, nem por campo: nome / campo: nome.clone()/Some(nome...)),
- reporta como candidato a revisão manual (não é 100% preciso — variáveis legitimamente não usadas no struct são comuns — então o script deve ser um relatório de candidatos para revisão humana em PR, não um gate hard-fail automático inicialmente).
- Rodar o script como um step não-bloqueante em
.github/workflows/ci.yml (comentário informativo no PR, não falha o build), pelo menos até calibrar a taxa de falso-positivo em algumas rodadas contra o histórico do repo (git log dos últimos commits que tocaram struct literals).
- Se a taxa de falso-positivo for baixa o suficiente após calibração, promover a hard-fail scoped aos crates Simplicio (nunca à árvore
xai-grok-* herdada).
- Alternativa mais barata caso o grep-based prove ruidoso demais: adicionar
#[deny(dead_code)]/#[warn(unused_variables)] mais agressivo já cobre parte disso via o compilador quando a variável realmente não é usada em lugar nenhum — mas o bug code#64 especificamente tinha a variável usada (só não nesse struct-literal específico), então o lint do compilador não pega; documentar essa limitação explicitamente se a alternativa mais barata for escolhida em vez do script.
(c) Matriz de modos de invocação em CI — o gate que pegaria code#66
- Novo job em
.github/workflows/ci.yml (ou workflow dedicado invocation-matrix.yml) que roda simplicio-code (ou o binário xai-grok-pager-bin) contra uma matriz cruzando:
- modo de prompt:
-p "ping" vs. posicional ("ping" sem -p);
- presença de TTY: dentro de
script -qec "..." (pty real) vs. execução direta (sem pty — já documentado em code#66 como falhando com os error 6, então esse cruzamento específico é esperado falhar de forma rápida e com mensagem clara, não travar);
--permission-mode (bypassPermissions, outros valores documentados) vs. --always-approve;
- cada combinação com
timeout <N> curto (ex. 15-20s) e asserção de que o processo termina (sucesso OU erro rápido e claro) — nunca trava até o timeout externo matar.
- Requer um provider/modelo mockável ou um modo
--check/dry-run que não precise de OPENROUTER_API_KEY real em CI — investigar se simplicio-code já tem esse modo (ver docs/ e --help) antes de decidir se o job precisa de um secret de CI real ou consegue rodar 100% offline/mockado.
- Este job teria pego
code#66 diretamente: a combinação --always-approve + posicional + pty real é exatamente a que trava; qualquer combinação que trave até o timeout externo falha o job com um log claro de qual combinação travou, em vez de exigir que alguém tropece nisso manualmente rodando um benchmark real.
Referências
- #67 — proposta original, itens (a)/(b)/(c)/(d) fonte deste plano.
- simplicio-loop#579 — hub cross-repo, motivação completa dos 2 bugs achados em outros repos que geraram a rodada de issues irmãs.
code#63, code#64, code#66 — os 3 bugs reais motivadores citados em DOD.md.
DOD.md (raiz do repo, adicionado junto com esta issue) — escopo dos 4 gates e do que fica fora.
crates/codegen/simplicio-runtime-client/tests/fake_server_handshake_proptest.rs — primeiro property test já implementado (parte de (a) para este crate).
Contexto
Segue diretamente de #67 e do hub cross-repo simplicio-loop#579. O framework de DoD escopado (
DOD.md, adicionado nesta sessão) e o primeiro property test (crates/codegen/simplicio-runtime-client/tests/fake_server_handshake_proptest.rs, cobrindo o handshake MCP) já implementam a base do item 1 de#67parasimplicio-runtime-client. Esta issue detalha os próximos passos concretos que ficaram fora do escopo cirúrgico daquele PR: os itens (b) e (c) de#67, mais a extensão de (a) para o resto do escopo genuinamente Simplicio.Motivação (recapitulando #67): 3 bugs reais encontrados nesta sessão no escopo genuinamente Simplicio —
code#63(rede no build sem fallback),code#64(search_backendconstruído e descartado do struct-literal deAgentRebuildSpec),code#66(--always-approvetrava indefinidamente em modo headless).Plano passo a passo
(a) Expandir proptest/fuzzing — só nos crates genuinamente Simplicio
Escopo confirmado em
DOD.md:crates/codegen/simplicio-runtime-client,crates/codegen/xai-grok-models, lógica de permissão/aprovação headless. Fora de escopo: a árvorexai-grok-*/xai-acp-*herdada (66+ crates upstream).simplicio-runtime-client— já tem o property test de handshake (esta sessão). Próximo: um segundo property test parasecure_relative_path/secure_glob(as funções de sandbox/path-escape) — gerar combinações de segmentos../, paths absolutos, símbolos Windows (C:\), unicode/paths mistos/+\, e verificar que a função nunca deixa escapar do repo (nunca retornaOkpara um path fora derepo). Essas funções já têm testes por exemplo; fuzzing generalizaria a garantia de sandbox que é o ponto mais crítico do crate.xai-grok-models— inspecionarcrates/codegen/xai-grok-models/src/lib.rs(196 linhas) e identificar qualquer função de parsing/validação de config de modelo (ex. resolução de aliases, parsing detencent/hy3:free, seleção de provider) que mereça um property test equivalente.xai-grok-pager/xai-grok-shell(flags--always-approve,--permission-mode). Depois quecode#66fechar (correção em andamento nesta sessão numa branch separada), adicionar um property test ou pelo menos uma tabela de casos exaustiva cobrindo toda combinação{--always-approve, --permission-mode=*} × {-p, posicional} × {tty, sem tty}contra o dispatch de aprovação, para travar a classe de bug quecode#66é (duas flags documentadas como equivalentes divergindo silenciosamente).(b) Lint customizado — pegar "campo construído, nunca passado ao struct"
Proposto originalmente em
#67item 2. Abordagem sugerida (grep-based, sem exigir plugin de clippy):scripts/check-unused-struct-locals.sh(ou.py) que, para cada.rssob o escopo Simplicio (mesma lista deDOD.md), varre funções que:let <nome> = ...;(variável local simples, não_-prefixada), ESomeStruct { ... }) que não referencia<nome>em nenhum campo (nem por shorthandnome,nem porcampo: nome/campo: nome.clone()/Some(nome...)),.github/workflows/ci.yml(comentário informativo no PR, não falha o build), pelo menos até calibrar a taxa de falso-positivo em algumas rodadas contra o histórico do repo (git logdos últimos commits que tocaram struct literals).xai-grok-*herdada).#[deny(dead_code)]/#[warn(unused_variables)]mais agressivo já cobre parte disso via o compilador quando a variável realmente não é usada em lugar nenhum — mas o bugcode#64especificamente tinha a variável usada (só não nesse struct-literal específico), então o lint do compilador não pega; documentar essa limitação explicitamente se a alternativa mais barata for escolhida em vez do script.(c) Matriz de modos de invocação em CI — o gate que pegaria
code#66.github/workflows/ci.yml(ou workflow dedicadoinvocation-matrix.yml) que rodasimplicio-code(ou o binárioxai-grok-pager-bin) contra uma matriz cruzando:-p "ping"vs. posicional ("ping"sem-p);script -qec "..."(pty real) vs. execução direta (sem pty — já documentado emcode#66como falhando comos error 6, então esse cruzamento específico é esperado falhar de forma rápida e com mensagem clara, não travar);--permission-mode(bypassPermissions, outros valores documentados) vs.--always-approve;timeout <N>curto (ex. 15-20s) e asserção de que o processo termina (sucesso OU erro rápido e claro) — nunca trava até o timeout externo matar.--check/dry-run que não precise deOPENROUTER_API_KEYreal em CI — investigar sesimplicio-codejá tem esse modo (verdocs/e--help) antes de decidir se o job precisa de um secret de CI real ou consegue rodar 100% offline/mockado.code#66diretamente: a combinação--always-approve+ posicional + pty real é exatamente a que trava; qualquer combinação que trave até o timeout externo falha o job com um log claro de qual combinação travou, em vez de exigir que alguém tropece nisso manualmente rodando um benchmark real.Referências
code#63,code#64,code#66— os 3 bugs reais motivadores citados emDOD.md.DOD.md(raiz do repo, adicionado junto com esta issue) — escopo dos 4 gates e do que fica fora.crates/codegen/simplicio-runtime-client/tests/fake_server_handshake_proptest.rs— primeiro property test já implementado (parte de (a) para este crate).