Mapa fixo commitado em scripts/lib/worktree.mjs (cheap=cheapestinference/deepseek-v4-flash, pro=opencode-go/qwen3.7-max, zen=opencode-go/ox-alpha-free, go=opencode-go/mimo-v2.5, alibaba=alibaba-token-plan/qwen3.7-max) com WORKTREE_VARIANT=max sempre; resolveWorktreeModel fail-high em múltiplas flags; opencodeLaunchDirective passa a emitir --model <map|preset> --variant max --auto; scripts/worktree.mjs valida at-most-one antes do claim e repassa modelo nos 3 propósitos (next/plan/new) com help/docblock atualizados; .agents/shell/worktree.sh, .opencode/commands/worktree.md, .agents/skills/worktree-next-issue/SKILL.md e local-database skill com contrato remapeado (--go deixa de ser no-op); tests/unit/worktree.unit.spec.ts pina as 5 flags, variant e guardrail. Closes #859
13 KiB
Impl: Flags de modelo no launch do worktree CLI (--cheap / --pro / --zen / --go / --alibaba)
Status: aprovado Atualizado em: 2026-08-24 Issue: #859 Intenção: docs/plans/worktree-flags-modelo-launch.md Appetite restante: ~0,5–1 dia (herdado; corte de cardápio aberto sem novo provider no repo)
Leitura da intenção
- Outcome:
pnpm worktree next --cheap | --pro | --zen | --go | --alibaba(eplan/newnas mesmas flags) abre o TUI com o modelo do mapa e--variant max, verificável pelo footer; sem flag o preset atual permanece. - O que NÃO negociar: 5 flags fixas (sem cardápio aberto), sem persistência, sem tocar cardápio
/work-issue//plan-issue, sem editar config global de máquina via repo; guardrails: effortmaxsempre (falha alto se variante não aplicar), fora do terminal (TEQO_WORKTREE_TERMINAL≠1) as flags são irrelevantes, sem flag nada muda (presetdeepseek/deepseek-v4-flash, no-op de--stay). - O que reavaliar: hipótese "Direção no codebase" está correta mas incompleta — faltava o
--variant maxna diretiva (OPS78 já debateu TUI sem--variante migrou variantes para config global; aqui o TUI já suporta--variant maxemopencode rune, verificado em 2026-08-24,opencode --model X --variant maxé aceito pelo TUI; a linha de launch passa a emitir o flag). O mapa concreto de modelo por flag não estava no plano de intenção (só--cheape--zentinham exemplos); a forma abaixo propõe valores e deixa o GATE decidir antes de codar.
Abordagem recomendada
flowchart LR
CLI["pnpm worktree next/plan/new\n--cheap|--pro|--zen|--go|--alibaba"] --> PARSE["scripts/worktree.mjs\nparseArgs + resolveWorktreeModel()"]
PARSE --> MAP["scripts/lib/worktree.mjs\nWORKTREE_MODEL_MAP\nflag -> model"]
MAP --> DIR["opencodeLaunchDirective\n--model <map|preset> --variant max --auto --prompt"]
DIR --> SH[".agents/shell/worktree.sh\nlaunch + cd"]
CLI -.->|sem TEQO_WORKTREE_TERMINAL| NOP["sem diretiva launch\n(apenas cd)"]
CLI -->|sem flag| PRESET["OPENCODE_PRESET_MODEL\ndeepseek/deepseek-v4-flash"]
Opções consideradas: A | B | C
Recomendação: A — mapa estático commitado em scripts/lib/worktree.mjs + opencodeLaunchDirective passa a emitir --variant max sempre + scripts/worktree.mjs consome o mapa na mesma camada que já deriva issueNumber para o prompt; 5 superfícies de doc atualizadas num único lote. Cabe no appetite (2 arquivos de lógica + 3 de doc + 2 specs), reusa o mecanismo OPS26 (preset como fallback) e o guardrail de variante do OPS78 sem inventar provider no repo.
Rejeitadas:
- B — aceitar
provider/modellivre como argumento (ex.--model deepseek/...): vira o/modelsdo opencode e abre validação de provider dinâmico, cache de catálogo e erro de digitação silencioso; rejeitada porque a intenção corta cardápio aberto explicitamente. - C — persistir última flag em arquivo/env (ex.
.teqo-worktree-model): cria estado por worktree, sobrescrita confusa comOPENCODE_WORKTREE_MODELe perda do "por invocação"; rejeitada pelo anti-goal de persistência.
Decisões de engenharia (caras, com rejeitadas)
-
Mapa flag→model como constante pura em
scripts/lib/worktree.mjs- Opções: A) mapa estático em
lib/worktree.mjs(puro, testável via unit) | B) mapa emscripts/worktree.mjs(acoplado a CLI) | C) mapa emopencode.json(config, não código) - Recomendação: A — lib pura, importável por
worktree.mjse portests/unit, sem ciclolib -> utilities, sem tocaropencode.jsondo repo (que hoje é mínimo pós-OPS89); o teste pina o mapa. B rejeitada porquescripts/worktree.mjsjá é HIGH_RISK_EXACT e não é unit-testável sem stub de GitHub; C rejeitada porque variantes são preferência de máquina (globalopencode.jsonc), o repo não deve carregar catálogo de modelos. - Mapa proposto (GATE confirma antes de codar):
--cheap→cheapestinference/deepseek-v4-flash(o exemplo verbatim da intenção; rota barata da Cheapest Inference)--pro→opencode-go/qwen3.7-max(Qwen 3.7 Max via Go — flagship pro da família Qwen, distinto doalibaba-token-plan)--zen→opencode-go/ox-alpha-free(confirmado no gate da intenção; correção de provider documentada)--go→opencode-go/mimo-v2.5(MiMo v2.5 via Go — modelo Go nativo comlow/high/max; remap do no-op histórico para um modelo real do provider Go)--alibaba→alibaba-token-plan/qwen3.7-max(Qwen 3.7 Max via Token Plan da Alibaba — modelo Alibaba nativo)
- Self-check: todos expõem
variant maxna config global (veropencode modelse~/.local/state/opencoderecente); se um dia o catálogo mudar, o launch falha alto (--variant maxrejeitado peloopencode run/tui) — guardrail preservado sem código extra.
- Opções: A) mapa estático em
-
opencodeLaunchDirectivepassa a emitir--variant maxsempre- Opções: A) sempre emitir
--variant maxjunto de--model| B) emitir só quando flag de modelo presente | C) configurar variante viaopencode.jsondo repo (override demodel.request.variant) - Recomendação: A — a intenção fixa "a sessão abre em effort max sempre"; o preset sem flag também deve abrir em max (o default já é
deepseek/deepseek-v4-flashcom max no global~/.config/opencode/opencode.jsonc; emitirmaxna linha torna o guardrail explícito e falha alto se a variante não existir, em vez de abrir silenciosamente em default). B rejeitada porque o preset sem flag abriria em effort indefinido; C rejeitada pelo OPS89 (variantes migraram para config global, oopencode.jsondo repo ficou mínimo e variantes não devem voltar ao repo). - Forma:
launch opencode <dir> --model <selected> --variant max --auto [--prompt "..."](ordem fixa para pin determinístico no teste).
- Opções: A) sempre emitir
-
Resolução de flag: exclusividade, precedência e fallback
- Opções: A) at-most-one flag; múltiplas →
diecom mensagem | B) last-wins silencioso | C) prioridade fixa (--cheap>--pro…) - Recomendação: A —
diese>1flag de modelo presente (worktree.mjsvalida antes do claim; mensagem lista o mapa). B/C mascaram erro de digitação (--cheap --proacidental) e quebram o "cardápio fixo" (o shell não deve adivinhar intenção). Sem flag →OPENCODE_PRESET_MODEL(fallback OPS26).
- Opções: A) at-most-one flag; múltiplas →
Componentes / mudanças
-
WORKTREE_MODEL_MAP+ helpers (scripts/lib/worktree.mjs):export const WORKTREE_MODEL_MAP = { cheap: 'cheapestinference/deepseek-v4-flash', pro: 'opencode-go/qwen3.7-max', zen: 'opencode-go/ox-alpha-free', go: 'opencode-go/mimo-v2.5', alibaba: 'alibaba-token-plan/qwen3.7-max' }export const WORKTREE_MODEL_FLAGS = new Set(Object.keys(WORKTREE_MODEL_MAP))export const resolveWorktreeModel = (flags) => { /* at-most-one → model ou preset */ }(pura, testável; recebeflagsdoparseArgs, retorna{ model, flag }oudievia throw).opencodeLaunchDirective({ dir, purpose, terminal, issueNumber, model })ou reaproveitandoresolveWorktreeModeldentro (preferir parammodelexplícito para manter lib pura sem acoplamento aprocess.argv;scripts/worktree.mjsresolve e injeta). Emite--model <model> --variant max --auto.OPENCODE_PRESET_MODELpermanece fallback (sem duplicar literal).- Comentário do preset atualizado (menciona mapa e
--variant max).
-
scripts/worktree.mjs(resolveWorktreeModel+ validação): parseArgs já coleta boolean flags; antes doclaimvalidar>1flag de modelo →die; derivarmodel = resolveWorktreeModel(flags)(sem flag → preset); passarmodelparaprintLaunchDirective/opencodeLaunchDirectiveemcmdNext/cmdNamespaceBranch(todos os 3 propósitos, hipótese B confirmada). Docblock:1-80e helpconsole.log(:765-804) atualizados: flag list com mapa, menção a--variant max,--godeixa de ser "no-op" e vira entrada do mapa,--stay/--no-migratepreservados. -
.agents/shell/worktree.sh: header:1-18e comentário da diretiva:8-12atualizados (lista de flags com mapa,--variant max,--goremapeado). Lógica de execução intacta (xargs tokeniza a linha com aspas). -
.opencode/commands/worktree.md: descrição e bullets atualizados para as 5 flags +--variant max; nota de--gocomo mapeamento real (não mais no-op); menção de que fora do terminal as flags são irrelevantes. -
Skills que citam o preset (
.agents/skills/worktree-next-issue/SKILL.md:34, talvezagent-work-issue): texto que pinavercel/deepseek/...oudeepseek/...atualizado para mencionar o mapa e o--variant max(sem reintroduzir providervercelno repo). -
Testes unitários:
tests/unit/worktree.unit.spec.ts: importarWORKTREE_MODEL_MAP,resolveWorktreeModel; novos suites:resolveWorktreeModel(cada flag → model, sem flag → preset, múltiplas → throw),opencodeLaunchDirectivecommodelexplícito (5 flags →--model <map> --variant max --auto ..., sem flag → preset + variant max, terminal false → null). Atualizar pins existentes (:151-205) para esperar--variant maxna linha (8 literais + pin da constante).tests/unit/opencodeCommands.unit.spec.ts: não mexe nos pins de execução (/work-issue//plan-issue); se houver pin do modelo de launch, atualizar para o novo contrato (ou adicionar pin das 5 flags se o arquivo for o dono do contrato de launch — verificar dono).
-
Migration: sem migration — tooling/CLI apenas.
-
Access / Consent: N/A — CLI de worktree, sem coleção nem PII.
-
UI: Impeccable A — sem superfície de produto (validação é linha de launch + footer do TUI).
Dados → forma (se aplicável)
N/A — tooling de dev; sem dado de negócio sendo modelado (pergunta 3 de data-presentation não se aplica).
Fases verificáveis
- Tracer / lib pura + diretiva —
scripts/lib/worktree.mjs(mapa +resolveWorktreeModel+opencodeLaunchDirectivecom--variant max) +tests/unit/worktree.unit.spec.ts(pins das 5 flags + guardrail de>1flag). Quota: ~40% do appetite. - CLI + docs —
scripts/worktree.mjs(validação, repasse demodelpara diretiva nos 3 propósitos),.agents/shell/worktree.sh,.opencode/commands/worktree.md, skills com preset. Quota: ~40%. - Gates —
pnpm test:unit -t worktree,pnpm gate:fast(lint/format/typecheck/knip/cycles/unit), smokeTEQO_WORKTREE_TERMINAL=1 node scripts/worktree.mjs next --cheap --stayimprime diretiva com--model cheapestinference/deepseek-v4-flash --variant max; sem flag imprime preset + max; múltiplas flags → erro;pnpm push→ CI PR (HIGH_RISK_EXACT = e2e curado). Quota: ~20%.
Rabbit holes / Não escopo (engenharia)
- NÃO aceitar
provider/modelarbitrário (cardápio aberto) — vira/models. - NÃO persistir última flag (env/arquivo) —
OPENCODE_WORKTREE_MODELjá é o escape de default fixo manual. - NÃO voltar com
provider.vercelnoopencode.jsondo repo — variantes vivem na config global (OPS89); a linha--variant maxé o guardrail. - NÃO mudar
model:dos.opencode/commands/work-issue.md/plan-issue.md(anti-goal da intenção). - NÃO tocar
opencode.jsondo repo nem~/.config/opencode/opencode.jsoncdo humano via commit. - NÃO estender
parseArgspara validar valor de--modellivre — mapa fixo basta.
Riscos e mitigação
- Modelo do mapa sem variante max na máquina do humano → como não tocamos na config global via repo, o TUI pode abrir sem max (silencioso) — mitigação: a linha agora sempre emite
--variant max; oopencodefalha alto se a variante não existir (erro visível em vez de silencioso); documentar no impl que o humano deve tervariant maxexposto no global para os 5 modelos (runbook fora do repo se faltar). - HIGH_RISK_EXACT (
scripts/worktree.mjs) no PR → o e2e curado roda; mitigação: só tocar docblock/help + repasse demodel; sem mudarprovision/claim/PORT/DATABASE_URL. - Quebra de contrato
--goem 5 superfícies → mitigação: atualizar as 5 numa única entrega (docblock/help,worktree.sh,worktree.md, 2 skills) + pin de teste nas 5 flags;--gosem flag duplicada não deixa no-op pendurado. - Flags fora do terminal (
/worktreedo opencode) → mitigação:opencodeLaunchDirectiveretornanullquandoterminal=falseantes de tocar no mapa; o/worktreecontinua sócd.
Aceite de engenharia
- Aceite de produto da intenção coberto: 5 flags com mapa,
next/plan/newcompartilhando diretiva,--variant maxsempre, falha alto se variante não aplicar, fora do terminal irrelevante, sem flag intacto. - Invariantes AGENTS/engineering-standards: sem nova collection, sem
Contactparalelo, semConsentnovo, sem ciclolib→utilities,push:falsepreservado (sem migration). - Testes de domínio previstos: unit do mapa + diretiva + guardrail de exclusividade; atualização dos pins de launch;
pnpm gate:fastverde.
Self-score decision-quality: 5/5 — decisões caras (mapa estático, variante sempre, exclusividade fail-closed) com rejeitadas documentadas; cabe no appetite (tracer + CLI + gates); rabbit holes nomeados; reusa OPENCODE_PRESET_MODEL/opencodeLaunchDirective sem twinning; outcome da intenção preservado.