17 KiB
Impl: pnpm worktree … --go abre a sessão no DeepSeek V4.1 Flash (opencode-go) na variante max
Status: aprovado
Atualizado em: 2026-09-18
Issue: #1149
Intenção: docs/plans/worktree-go-variant-max.md
Appetite restante: herdado (~0,5 dia eng — plumbing de launch + textos + pins). Sem migration, sem schema, sem UI, sem DB.
Modo: autônomo (--auto) — impl plan nasce aprovado pelo agente.
Leitura da intenção
- Outcome: todo lançamento de worktree (
next,plan,new,fix— inclusivefix --headless/auto-unblock e o preset sem flag) cria a sessão do servidor comSession.model.variant === 'max'para o modelo selecionado, e--gocontinua emopencode-go/deepseek-v4.1-flash. Verificável no body dePOST /sessionviradoSession.model.variant, no argv do driver/headless e nos pins unitários. A TUI anexada (opencode attach, sem flag) herda. - O que NÃO negociar:
- Nenhuma flag
--variantnoopencode attachnem na diretivalaunch(o yargs do TUI rejeita o flag — veto OPS95). - Config global da máquina (
~/.config/opencode/…/ Ctrl+T) intocada;opencode.jsondo repo intocado. - Lançamento nunca quebra por variante: nenhum lookup/
throwlocal por capacidade de modelo; o literal é constante. - Cardápio/modelos tocados só na variante —
WORKTREE_MODEL_MAP/OPENCODE_PRESET_MODELinalterados (OPS112 deixago = opencode-go/deepseek-v4.1-flash). - Docs históricos congelados (
docs/plans/*anteriores, HISTORY) intocados.
- Nenhuma flag
- O que reavaliar: a hipótese "variante nunca entra na diretiva" permanece correta, mas o dono da variante não é
resolveWorktreeModel(que segue devolvendo stringprovider/model); éscripts/lib/agent-session.mjs(dono do ciclo de vida da sessão). Reavalia-se também a hipótese de guardarvariantno estado: não guardar (ver D2). O sintoma "nem no provider correto" já foi atacado pela OPS122 (createSessionpassa o modelo no body); a variante não altera esse caminho — a verificação viva fica no aceite.
Abordagem recomendada
flowchart LR
W["pnpm worktree next|plan|new|fix (--go …)"] --> R["resolveWorktreeModel\n→ 'provider/model' (string, sem variante)"]
W --> H["fix --headless\n(scripts/worktree.mjs:761)"]
R --> D["opencodeLaunchDirective\n--model <model> (SEM --variant)"]
D --> S["agent-session start --model <model>"]
S --> B["buildCreateSessionBody({ model })\n→ model:{ providerID, id, variant:'max' }"]
S --> DR["driverArgs → --model <m> --variant max"]
B --> SV["POST /session\ndirectory=…"]
SV --> P["Session.model.variant = 'max'"]
P --> TUI["opencode attach (sem flags) herda"]
H --> HA["opencodeHeadlessArgs\n→ --model <m> --variant max"]
C["MODEL_VARIANT='max'\n(dono: lib/agent-session.mjs)"] --> B
C --> DR
C --> HA
Opções consideradas: A | B | C | D
Recomendação: A — variante como constante MODEL_VARIANT = 'max' aplicada dentro de scripts/lib/agent-session.mjs (body da sessão + argv do driver) e reusada por opencodeHeadlessArgs em scripts/lib/worktree.mjs. A diretiva launch/attach permanece model-only. É a única opção que (1) faz a variante chegar à sessão pelo caminho já validado pela OPS122 (POST /session), (2) mantém o pin "diretiva sem --variant" verdadeiro (nenhum flag novo no TUI), (3) cobre todos os propósitos — terminal, driverless, driver e headless — com um único dono de literal, e (4) cabe no appetite (poucas linhas + textos/pins).
Rejeitadas:
- B —
--variantroteado pela diretivaopencodeLaunchDirectiveaté o CLI de sessão. Rejeitada: reintroduz o flag no canal tokenizado da diretiva/TUI (a classe exata da quebra OPS95 — yargs do TUI rejeita flag desconhecida) e torna a diretiva inconsistente com o attach, que continua sem o flag. A variante é atributo do modelo da sessão, não um parâmetro de linha do TUI. - C — mapa de capacidade por modelo (só enviar
maxa quem suporta). Rejeitada: over-engineering; a intenção corta explicitamente a revisão do cardápio e diz quemaxé a única variante, em todos os propósitos. Um mapa seria mais um lugar para divergir do provider real. - D — variante só no body da sessão, sem argv no driver/headless. Rejeitada: o driver é um
opencode runseparado (driverArgs,opencodeHeadlessArgs) — sem--variantele abriria no variant default e divergiria da sessão; o aceite exige todos os lançamentos.
Decisões caras registradas:
- D1 — Dono do literal:
scripts/lib/agent-session.mjsexportaMODEL_VARIANT = 'max';scripts/lib/worktree.mjso importa no import já existente comassertKnownFlags, SKILL_AUTO_FLAG(lib/worktree.mjs:10) e o usa emopencodeHeadlessArgs.worktree.mjse o CLIagent-session.mjsnão re-spelam'max'(single source). - D2 — Estado da sessão continua
modelstring, variante implícita. Não gravarvariantno estado: a variante é constante global; registrá-la forçaria migrar estados antigos (semvariant) e a checagem de reuso (agent-session.mjs:520) passaria a falhar fechado por diferença deundefined, quebrando reuso de runs vivos. Gatilho de revisitação: se um dia existir uma segunda variante real ou seleção por sessão, aí sim gravar e comparar. - D3 — Posição do flag no argv headless:
['opencode','run','--model',model,'--variant',MODEL_VARIANT,'--auto','--command',command, report]—--variantantes doreportposicional (não pode ir depois, viraria argumento do report). Pin de array exato no teste. - D4 — Guardrail "nunca quebra": a variante entra como propriedade string constante; helpers seguem puros (aceitam/devolvem string, sem lookup que lance). Se um modelo do cardápio não declarar
max, o servidor persiste o que recebe e o provider decide — comportamento do upstream, não do nosso launch. Verificação viva dos modelos usados nos gates.
Componentes / mudanças
MODEL_VARIANT(scripts/lib/agent-session.mjs, novo, acima debuildCreateSessionBody):export const MODEL_VARIANT = 'max'+ docblock citando 1.18.31 (Session.model.variant) e o porquê de não ir no attach (OPS95/OPS127).buildCreateSessionBody(scripts/lib/agent-session.mjs:245-248): assinatura inalterada({ model = null } = {}); quando há modelo, retorna{ model: { ...parseModelRef(model), variant: MODEL_VARIANT } }(variante incondicional — sem parâmetro de override); sem modelo segue{}. Trocar o comentário "Novariant(OPS95: variants stay on the machine's global config)" (:242) pela nova semântica.driverArgs(scripts/lib/agent-session.mjs:368-394): inserir'--variant', MODEL_VARIANTimediatamente após--model <model>(antes de--auto), incondicional. Nenhum parâmetro de override, nenhumthrownovo (simplify pós-revisão: override era generalidade especulativa — sem caller de produção).opencodeHeadlessArgs(scripts/lib/worktree.mjs:333-345): inserir'--variant', MODEL_VARIANTapós o modelo; importarMODEL_VARIANTde./agent-session.mjsna linha:10.headlessDirective(:351-356) herda o argv sem mudança própria.- CLI
createSession/cmdStart(scripts/agent-session.mjs:272-279,:468-572): sem mudança de código —buildCreateSessionBody({ model })já ganha o default edriverArgs({ …, model, invocation })também; o estadomodel(:538) permanece string (D2). - Migration: sem migration — tooling de launch; nenhum schema/coleção Payload muda.
- Access / Consent: N/A — nenhum dado de cidadão, login de campanha ou Consent envolvido.
- UI: N/A — nenhum componente Next/Payload. O TUI do opencode é consumidor externo (sem superfície de design; Impeccable A).
Dados → forma (se aplicável)
N/A — tooling. Não há dado de negócio modelado; a mudança é uma constante de variante aplicada ao body da sessão e ao argv do driver. Perguntas de data-presentation não se aplicam.
Pins de teste a atualizar (valores exatos)
tests/unit/agentSession.unit.spec.ts:
- L328-337 (
buildCreateSessionBodycom modelo) — passa a esperar:{ model: { providerID: 'opencode-go', id: 'deepseek-v4.1-flash', variant: MODEL_VARIANT } }(referência à constante; o literal é pinado à parte). Os casosnull/undefined/{}/{}(L332-335) seguem{}; othrowde'no-slash'(L336) inalterado. - L339-342 — o
it"never emits a variant (OPS95)" vira o pin único da constante:expect(MODEL_VARIANT).toBe('max')(o body exato de L328 já cobre a emissão). - L458-483 (
driverArgscom invocation) — inserir'--variant', 'max'logo após'--model', 'deepseek/deepseek-flash'(L476-477), antes de--auto. - L486-509 (
driverArgssem argumentos, model'm') — inserir'--variant', 'max'após'--model', 'm'. - L550-560 (
attachArgs) — manter o array exato e acrescentarexpect(argv).not.toContain('--variant')(guardrail OPS127/OPS95). - Import novo no topo —
MODEL_VARIANT(usado no pin e notoEqualdo body).
tests/unit/worktree.unit.spec.ts:
- L296-303 — a asserção
not.toContain('--variant')permanece (a diretiva segue model-only); atualizar só a descrição doitpara "diretiva segue sem --variant; a variante viaja no body/driver (OPS127)". - L426-439 (
opencodeHeadlessArgs) — array esperado vira:['opencode','run','--model','deepseek/deepseek-flash','--variant','max','--auto','--command',OPENCODE_HEADLESS_COMMAND,'run 1 falhou']. - L442-450, L452-463 — sem mudança estrutural (o
:452só confereargv[0]). - L466-479 (mapa/preset) e L482-519 (resolução/diretiva) — inalterados (cardápio intocado).
- Nenhuma mudança em
tests/unit/autoUnblock.unit.spec.ts/autoUnblockWorkflow.unit.spec.ts—parseHeadlessDirectivevalida sódir/branch/argve o wrapper passadirective.argvadiante; o--variant maxflui sem contrato novo.
tests/unit/opencodeCommands.unit.spec.ts — não tocar (pina frontmatter dos comandos; anti-goal).
Textos / superfícies a sincronizar (mesma entrega)
scripts/lib/agent-session.mjs:238-248— docblock debuildCreateSessionBody: remove "Novariant(OPS95)" e explicavariant: 'max'no body (1.18.31), attach sem flag.scripts/lib/agent-session.mjs:360-367— docblock dedriverArgs: acrescentar--variant max.scripts/lib/worktree.mjs:31-38(OPS95 no header),:43-52(mapa "No--variantis emitted") e:333-345— nota OPS127: diretiva/attach sem flag; variante no body e no argv run.scripts/worktree.mjs:33-49(docblock do launch) e help:991-1004— acrescentar que a sessão nasce em variantemax(body/driver), sem alterar a linha--model..agents/shell/worktree.sh:20-27e:76-77— trocar a frase "Sem--variant(OPS95… config global/Ctrl+T)" por: variantemaxaplicada na criação da sessão; o attach não leva flag..opencode/commands/worktree.md:13— nota OPS122 estendida: modelo e variantemaxgravados na sessão (TUI anexado herda, inclusive driverless)..agents/skills/worktree-next-issue/SKILL.md:34— parágrafo de launch: substituir o trecho OPS95 de variante/global pormaxno body da sessão + driver..agents/skills/local-database/SKILL.md:29— menção curta: o modelo selecionado é gravado na sessão na variantemax.docs/AGENT-OPS.md:65(parágrafo "Sessões persistentes") e:70(linha da tabelaagent:session start) — registrar que a criação fixa a variantemax(ex.:--model <M>+ variantemaxno body). Não tocar:24(ladder de design — só cita o modeloopencode-go/…, sem vínculo com variante).- Changelog novo:
docs/changelog/2026-09-18-ops127.md(uma entrada curta; nunca editardocs/CHANGELOG-AGENTS.md/HISTORY).
Fases verificáveis
- Tracer (dono da variante) — quota ~40%:
scripts/lib/agent-session.mjs(MODEL_VARIANT,buildCreateSessionBody,driverArgs) +tests/unit/agentSession.unit.spec.ts(pins L328-342, L458-509, L550-560 + novo pin da constante). Rodarpnpm vitest run tests/unit/agentSession.unit.spec.tsverde antes de seguir. - Launch (headless + textos de código) — quota ~30%:
scripts/lib/worktree.mjsimport:10+opencodeHeadlessArgs:333-345; pins detests/unit/worktree.unit.spec.ts(L426-439; descrição L296-303). Rodarpnpm vitest run tests/unit/worktree.unit.spec.ts. - Superfícies/labels — quota ~20%: textos listados acima (
worktree.mjsdocblock/help,worktree.sh,worktree.md, 2 skills,AGENT-OPS.md) +docs/changelog/2026-09-18-ops127.md. - Gates — quota ~10%:
pnpm gate:fast(lint+typecheck+unit); verificação viva: criar sessão de teste (pnpm worktree plan --goem branch descartável ouagent-session start --model opencode-go/deepseek-v4.1-flash), ler~/.local/state/teqo/agent-sessions/<slug>.jsone a sessão no servidor (Session.model.variant === 'max'/ TUI mostrandomax);pnpm push(origin GitHub) → PR--base main. Atenção CI:scripts/worktree.mjséHIGH_RISK_EXACT— o PR roda unit/int full + e2e curado (esperado, não é surpresa).
Rabbit holes / Não escopo (engenharia)
- Não emitir
--variantna diretivalaunchnem noopencode attach(classe OPS95; attach sem flags por design). - Não criar mapa de capacidade modelo→variante nem lookup que lance (opção C rejeitada).
- Não gravar/derivar
variantno estado da sessão nem na checagem de reuso (D2; gatilho de revisitação registrado). - Não alterar
WORKTREE_MODEL_MAP/OPENCODE_PRESET_MODELnem o cardápio de flags (intenção corta). - Não tocar
opencode.jsondo repo nem a config global da máquina / Ctrl+T. - Não mudar
opencodeCommands.unit.spec.tsnem frontmatter de comandos de execução. - Não editar docs históricos congelados (
docs/plans/*antigos,CHANGELOG-AGENTS.md, HISTORY). - Não adicionar flag nova de variante, nem parâmetro de CLI
--variantnoagent-session start(a variante é default interno).
Riscos e mitigação
- Sessão reusada de antes do OPS127 não tem
variant.startcom driver vivo/sessão busy reusa sem re-aplicar o body (agent-session.mjs:515-526). Mitigação: worktrees deplan/newnascem com sessão nova; para runs longevos,--newforça recriação; documentar o efeito no changelog. Revisitar se virar recorrente. --variantem posição errada no argv dorun. Se cair depois doreportposicional vira parte do report. Mitigação: D3 + pin de array exato (L426-439).- Servidor/provider rejeitar
maxem algum modelo do cardápio. Guardrail pede "nunca quebra"; sem mapa (opção C rejeitada), o risco residual existe. Mitigação: verificação viva no PR para o preset e--go(os usados no fluxo) e flag de revisitação; o body é string constante, semthrowlocal. - Divergência do sintoma "nem sempre no provider correto". O caminho de modelo da sessão é o da OPS122; a variante não o altera. Mitigação: o aceite de engenharia exige sessão viva conferindo provider/modelo e variante antes de marcar aprovado.
- Deriva de texto vs. constante. Vários docblocks citavam OPS95. Mitigação: pins unit + os pontos de texto são atualizados na mesma fase (3), e
MODEL_VARIANTé importado (não re-digitado) emlib/worktree.mjs. - PR dispara suíte ampla por
worktree.mjsser HIGH_RISK_EXACT. Esperado; não é regressão. Mitigação: rodargate:fastlocal antes do push.
Aceite de engenharia
- Aceite de produto da intenção coberto:
next/plan/new/fix(incluifix --headless) e o preset criam a sessão comSession.model.variant === 'max';--gosegue emopencode-go/deepseek-v4.1-flash. - Guardrails: nenhum
--variantemattachArgs/diretivalaunch;opencode.jsone config global intocados; variante é constante sem lookup que lance; cardápio/preset de modelos inalterados. - Invariantes AGENTS/engineering-standards: single owner do literal (
lib/agent-session.mjs), sem twinning, sem migration/schema/Consent/access. - Pins unitários atualizados conforme lista acima (
agentSession.unit.spec.ts,worktree.unit.spec.ts);tests/unit/opencodeCommands.unit.spec.tsintacto. - Superfícies sincronizadas na mesma entrega (código, help/docblocks, shell, command, skills, AGENT-OPS, changelog novo).
pnpm test:unit(specs citados) epnpm gate:fastverdes; verificação viva de sessão emmaxno PR; push viapnpm push.
Self-score decision-quality: 5/5. (1) Decisão cara — dono do literal e formato do body/argv — tem opções e rejeitadas explícitas (A recomendada; B/C/D rejeitadas com motivo técnico). (2) Cabe no appetite: poucas linhas funcionais + textos + pins, sem schema/UI. (3) Rabbit holes nomeados (mapa de capacidade, attach, estado da sessão, config global, cardápio, docs congelados). (4) Depth check: reusa o caminho OPS122 buildCreateSessionBody/driverArgs/opencodeHeadlessArgs em vez de criar passe-through novo; literal em single owner. (5) Outcome preservado: a engenharia cobre todos os propósitos via body/argv e mantém o guardrail do attach, sem reescrever o aceite.