teqo-backup/docs/plans/worktree-flags-modelo-launch-impl.md
Francisco Solla 8951f198ca feat(worktree): flags de modelo --cheap/--pro/--zen/--go/--alibaba com --variant max (OPS93)
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
2026-08-24 17:08:39 -03:00

119 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` (e `plan`/`new` nas 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: effort `max` sempre (falha alto se variante não aplicar), fora do terminal (`TEQO_WORKTREE_TERMINAL≠1`) as flags são irrelevantes, sem flag nada muda (preset `deepseek/deepseek-v4-flash`, no-op de `--stay`).
- **O que reavaliar:** hipótese "Direção no codebase" está correta mas incompleta — faltava o `--variant max` na diretiva (OPS78 já debateu TUI sem `--variant` e migrou variantes para config global; aqui o TUI já suporta `--variant max` em `opencode run` e, 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ó `--cheap` e `--zen` tinham exemplos); a forma abaixo propõe valores e deixa o GATE decidir antes de codar.
## Abordagem recomendada
```mermaid
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/model` livre como argumento (ex. `--model deepseek/...`):** vira o `/models` do 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 com `OPENCODE_WORKTREE_MODEL` e perda do "por invocação"; rejeitada pelo anti-goal de persistência.
### Decisões de engenharia (caras, com rejeitadas)
1. **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 em `scripts/worktree.mjs` (acoplado a CLI) | C) mapa em `opencode.json` (config, não código)
- Recomendação: A — lib pura, importável por `worktree.mjs` e por `tests/unit`, sem ciclo `lib -> utilities`, sem tocar `opencode.json` do repo (que hoje é mínimo pós-OPS89); o teste pina o mapa. B rejeitada porque `scripts/worktree.mjs` já é HIGH_RISK_EXACT e não é unit-testável sem stub de GitHub; C rejeitada porque variantes são preferência de máquina (global `opencode.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 do `alibaba-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 com `low/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 max` na config global (ver `opencode models` e `~/.local/state/opencode` recente); se um dia o catálogo mudar, o launch falha alto (`--variant max` rejeitado pelo `opencode run`/`tui`) — guardrail preservado sem código extra.
2. **`opencodeLaunchDirective` passa a emitir `--variant max` sempre**
- Opções: A) sempre emitir `--variant max` junto de `--model` | B) emitir só quando flag de modelo presente | C) configurar variante via `opencode.json` do repo (override de `model.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-flash` com max no global `~/.config/opencode/opencode.jsonc`; emitir `max` na 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, o `opencode.json` do 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).
3. **Resolução de flag: exclusividade, precedência e fallback**
- Opções: A) at-most-one flag; múltiplas → `die` com mensagem | B) last-wins silencioso | C) prioridade fixa (`--cheap` > `--pro` …)
- Recomendação: A — `die` se `>1` flag de modelo presente (`worktree.mjs` valida antes do claim; mensagem lista o mapa). B/C mascaram erro de digitação (`--cheap --pro` acidental) e quebram o "cardápio fixo" (o shell não deve adivinhar intenção). Sem flag → `OPENCODE_PRESET_MODEL` (fallback OPS26).
### 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; recebe `flags` do `parseArgs`, retorna `{ model, flag }` ou `die` via throw).
- `opencodeLaunchDirective({ dir, purpose, terminal, issueNumber, model })` ou reaproveitando `resolveWorktreeModel` dentro (preferir param `model` explícito para manter lib pura sem acoplamento a `process.argv`; `scripts/worktree.mjs` resolve e injeta). Emite ` --model <model> --variant max --auto`.
- `OPENCODE_PRESET_MODEL` permanece 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 do `claim` validar `>1` flag de modelo → `die`; derivar `model = resolveWorktreeModel(flags)` (sem flag → preset); passar `model` para `printLaunchDirective`/`opencodeLaunchDirective` em `cmdNext`/`cmdNamespaceBranch` (todos os 3 propósitos, hipótese B confirmada). Docblock `:1-80` e help `console.log` (`:765-804`) atualizados: flag list com mapa, menção a `--variant max`, `--go` deixa de ser "no-op" e vira entrada do mapa, `--stay`/`--no-migrate` preservados.
- **`.agents/shell/worktree.sh`**: header `:1-18` e comentário da diretiva `:8-12` atualizados (lista de flags com mapa, `--variant max`, `--go` remapeado). 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 `--go` como 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`, talvez `agent-work-issue`): texto que pina `vercel/deepseek/...` ou `deepseek/...` atualizado para mencionar o mapa e o `--variant max` (sem reintroduzir provider `vercel` no repo).
- **Testes unitários:**
- `tests/unit/worktree.unit.spec.ts`: importar `WORKTREE_MODEL_MAP`, `resolveWorktreeModel`; novos suites: `resolveWorktreeModel` (cada flag → model, sem flag → preset, múltiplas → throw), `opencodeLaunchDirective` com `model` explícito (5 flags → `--model <map> --variant max --auto ...`, sem flag → preset + variant max, terminal false → null). Atualizar pins existentes (`:151-205`) para esperar `--variant max` na 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
1. **Tracer / lib pura + diretiva** — `scripts/lib/worktree.mjs` (mapa + `resolveWorktreeModel` + `opencodeLaunchDirective` com `--variant max`) + `tests/unit/worktree.unit.spec.ts` (pins das 5 flags + guardrail de `>1` flag). Quota: ~40% do appetite.
2. **CLI + docs** — `scripts/worktree.mjs` (validação, repasse de `model` para diretiva nos 3 propósitos), `.agents/shell/worktree.sh`, `.opencode/commands/worktree.md`, skills com preset. Quota: ~40%.
3. **Gates** — `pnpm test:unit -t worktree`, `pnpm gate:fast` (lint/format/typecheck/knip/cycles/unit), smoke `TEQO_WORKTREE_TERMINAL=1 node scripts/worktree.mjs next --cheap --stay` imprime 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/model` arbitrário (cardápio aberto) — vira `/models`.
- NÃO persistir última flag (env/arquivo) — `OPENCODE_WORKTREE_MODEL` já é o escape de default fixo manual.
- NÃO voltar com `provider.vercel` no `opencode.json` do 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.json` do repo nem `~/.config/opencode/opencode.jsonc` do humano via commit.
- NÃO estender `parseArgs` para validar valor de `--model` livre — 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`; o `opencode` falha alto se a variante não existir (erro visível em vez de silencioso); documentar no impl que o humano deve ter `variant max` exposto 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 de `model`; sem mudar `provision`/`claim`/`PORT`/`DATABASE_URL`.
- **Quebra de contrato `--go` em 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; `--go` sem flag duplicada não deixa no-op pendurado.
- **Flags fora do terminal (`/worktree` do opencode)** → mitigação: `opencodeLaunchDirective` retorna `null` quando `terminal=false` antes de tocar no mapa; o `/worktree` continua só `cd`.
## Aceite de engenharia
- [ ] Aceite de produto da intenção coberto: 5 flags com mapa, `next`/`plan`/`new` compartilhando diretiva, `--variant max` sempre, falha alto se variante não aplicar, fora do terminal irrelevante, sem flag intacto.
- [ ] Invariantes AGENTS/engineering-standards: sem nova collection, sem `Contact` paralelo, sem `Consent` novo, sem ciclo `lib→utilities`, `push:false` preservado (sem migration).
- [ ] Testes de domínio previstos: unit do mapa + diretiva + guardrail de exclusividade; atualização dos pins de launch; `pnpm gate:fast` verde.
---
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.