fix(worktree): OPS101 — preset canônico deepseek-flash e commands sem pin de modelo (Closes #944)

This commit is contained in:
Francisco Solla 2026-09-12 01:52:27 -03:00
parent eed5a59a31
commit e4550384b1
12 changed files with 139 additions and 14 deletions

View file

@ -19,7 +19,7 @@
# Modelo por invocação: `--cheap` (cheapestinference/deepseek-v4-flash),
# `--pro` (deepseek/deepseek-v4-pro), `--zen` (opencode-go/ox-alpha-free),
# `--go` (opencode-go/hy3), `--alibaba` (alibaba-token-plan/deepseek-v4-flash) no
# mapa fixo `WORKTREE_MODEL_MAP` (OPS93 menu; valores OPS95); sem flag o preset `deepseek/deepseek-v4-flash`
# mapa fixo `WORKTREE_MODEL_MAP` (OPS93 menu; valores OPS95); sem flag o preset `deepseek/deepseek-flash`
# permanece. Sem `exec` de propósito: ao sair do opencode, o terminal volta ao
# shell dentro do worktree. Presets são constantes em scripts/lib/worktree.mjs;
# o marcador TEQO_WORKTREE_TERMINAL=1 é o que separa esta superfície da do comando

View file

@ -31,7 +31,7 @@ No opencode, isso é o comando **`/worktree next`** / **`/worktree kill`** (`.op
**Default-go:** `next`, `plan` e `new` imprimem `cd <dir>` na última linha **por padrão**; `--stay` suprime; modelos por invocação via `--cheap/--pro/--zen/--go/--alibaba/--glm/--free` (mapa fixo `WORKTREE_MODEL_MAP`, at-most-one; sem flag o preset permanece); `--go` remapeado em OPS93 para o provider OpenCode Go e em OPS95 para `opencode-go/hy3` (antes no-op do OPS24). No terminal interativo, use a função `worktree()` de **`.agents/shell/worktree.sh`** (uma linha de `source` no profile) para o `cd` ser aplicado de verdade no shell que te chamou — node não consegue mudar o cwd do shell pai. `kill` também imprime `cd <main>` no fim (a sessão nunca fica num diretório destruído).
**Launch do opencode (OPS26 + OPS33 + OPS31 + OPS93 + OPS95):** só a função shell marca `TEQO_WORKTREE_TERMINAL=1`; com o marcador, `next`/`plan`/`new` imprimem também a diretiva `launch opencode <dir> --model <preset|map> --auto [--prompt "/work-issue --issue <N>"]` **antes** do `cd`, e a função a executa depois do cd — `next` abre o TUI com `/work-issue --issue <N>` já enviado (a Issue claimada vai no prompt; a skill lê o resto do GitHub); `plan` abre com `/plan-issue` já enviado (OPS31: o TUI já cai no fluxo de planejamento); `new` abre sem `--prompt` ("apenas conversar"). Sem `--variant` na diretiva (OPS95: o yargs do TUI rejeita o flag desconhecido e só imprime o helper — variantes ficam na config global do opencode, selecionáveis via Ctrl+T; `opencode run --variant max` segue sendo a via CLI para runs headless). Modelo por invocação via `--cheap` (cheapestinference/deepseek-v4-flash), `--pro` (deepseek/deepseek-v4-pro), `--zen` (opencode-go/ox-alpha-free), `--go` (opencode-go/hy3), `--alibaba` (alibaba-token-plan/deepseek-v4-flash) — valores corrigidos no OPS95 — e `--glm` (opencode-go/glm-5.3-flash, OPS100), `--free` (openrouter/openrouter/free, OPS100); sem flag o preset `deepseek/deepseek-v4-flash` permanece. Sem `exec`: sair do opencode volta ao shell no worktree. Presets e mapa são constantes em `scripts/lib/worktree.mjs`. **O comando `/worktree` do opencode (e qualquer automação sem o marcador) nunca lança o TUI.**
**Launch do opencode (OPS26 + OPS33 + OPS31 + OPS93 + OPS95):** só a função shell marca `TEQO_WORKTREE_TERMINAL=1`; com o marcador, `next`/`plan`/`new` imprimem também a diretiva `launch opencode <dir> --model <preset|map> --auto [--prompt "/work-issue --issue <N>"]` **antes** do `cd`, e a função a executa depois do cd — `next` abre o TUI com `/work-issue --issue <N>` já enviado (a Issue claimada vai no prompt; a skill lê o resto do GitHub); `plan` abre com `/plan-issue` já enviado (OPS31: o TUI já cai no fluxo de planejamento); `new` abre sem `--prompt` ("apenas conversar"). Sem `--variant` na diretiva (OPS95: o yargs do TUI rejeita o flag desconhecido e só imprime o helper — variantes ficam na config global do opencode, selecionáveis via Ctrl+T; `opencode run --variant max` segue sendo a via CLI para runs headless). Modelo por invocação via `--cheap` (cheapestinference/deepseek-v4-flash), `--pro` (deepseek/deepseek-v4-pro), `--zen` (opencode-go/ox-alpha-free), `--go` (opencode-go/hy3), `--alibaba` (alibaba-token-plan/deepseek-v4-flash) — valores corrigidos no OPS95 — e `--glm` (opencode-go/glm-5.3-flash, OPS100), `--free` (openrouter/openrouter/free, OPS100); sem flag o preset `deepseek/deepseek-flash` permanece. Sem `exec`: sair do opencode volta ao shell no worktree. Presets e mapa são constantes em `scripts/lib/worktree.mjs`. **O comando `/worktree` do opencode (e qualquer automação sem o marcador) nunca lança o TUI.**
## Fluxo quando invocado como skill (agentes que não têm opencode)

View file

@ -1,6 +1,5 @@
---
description: Corrige um bug de ponta a ponta: diagnóstico → causa-raiz → fix → verificação → prevenção → post-mortem
model: deepseek/deepseek-v4-flash
---
Carregue a skill `bug-fix` (ferramenta de skills, nome exato) e siga o fluxo dela de ponta a ponta. A fonte canônica é `.agents/skills/bug-fix/SKILL.md` — não a transcreva nem recrie o fluxo.

View file

@ -1,6 +1,5 @@
---
description: Transforma ideias humanas em Issues GitHub + planos de intenção em docs/plans/ (com gate e registro)
model: deepseek/deepseek-v4-flash
---
Carregue a skill `plan-issue` (ferramenta de skills, nome exato) e siga o fluxo dela de ponta a ponta. A fonte canônica é `.agents/skills/plan-issue/SKILL.md` — não a transcreva nem recrie o fluxo.

View file

@ -1,6 +1,5 @@
---
description: Auditoria autônoma noturna da suíte de testes — inventário e métricas por camada, melhorias seguras aplicadas com prova verde antes/depois, relatório único no PR ready
model: deepseek/deepseek-v4-flash
---
Carregue a skill `testing-audit` (ferramenta de skills, nome exato) e siga o fluxo dela de ponta a ponta até o fecho noturno completo. A fonte canônica é `.agents/skills/testing-audit/SKILL.md` — não a transcreva nem recrie o fluxo.

View file

@ -1,6 +1,5 @@
---
description: Executa uma Issue já claimada de ponta a ponta com supervisão humana (plano de implementação → pausa → execução → simplify → débitos → PR)
model: deepseek/deepseek-v4-flash
---
Carregue a skill `work-issue` (ferramenta de skills, nome exato) e siga o fluxo dela de ponta a ponta. A fonte canônica é `.agents/skills/work-issue/SKILL.md` — não a transcreva nem recrie o fluxo.

View file

@ -0,0 +1 @@
**Worktree nasce no nome canônico do DeepSeek V4.1 Flash (`deepseek/deepseek-flash`) (2026-09-12):** o preset sem flag do fluxo `pnpm worktree next/plan/new/fix` ainda apontava para o nome legado `deepseek/deepseek-v4-flash`, e os comandos `/work-issue`, `/plan-issue`, `/bug-fix` e `/testing-audit` pinavam o mesmo nome no frontmatter — o pin sobrescrevia o modelo default da sessão e anulava as flags/override do launch. O fix (Issue #944) troca o fallback em `OPENCODE_PRESET_MODEL` (`scripts/lib/worktree.mjs`) para o nome canônico `deepseek/deepseek-flash` (DeepSeek-V4.1-Flash, lançado em 2026-09-10; o alias legado segue servido ao preço Flash, mas pode sumir sem aviso) e remove a linha `model:` dos 4 commands, que passam a herdar o modelo da sessão; o guard unit de frontmatter (`opencodeCommands.unit.spec.ts`) passa a exigir ausência de pin (reintrodução de qualquer pin falha o teste, com mensagem explicando a origem do modelo). O override `OPENCODE_WORKTREE_MODEL` e as 7 flags do `WORKTREE_MODEL_MAP` ficam intactos, incluindo os aliases de outros providers (`cheapestinference/…`, `alibaba-token-plan/…`) e os usos diretos do app (`ai-chat`, `campaignDemandTitle`) — fora do escopo. Verificação: unit full 2687 passed com e sem `OPENCODE_WORKTREE_MODEL` exportado (RED→GREEN nos dois guards), smoke da diretiva imprimindo `--model deepseek/deepseek-flash --auto --prompt "/work-issue --issue 944"` e override ainda vencendo, `pnpm gate:fast` verde; e2e curado local, CI do PR e prod a preencher (deploy manual).

View file

@ -0,0 +1,125 @@
# Impl: Modelo padrão do worktree → DeepSeek V4.1 Flash (`deepseek/deepseek-flash`)
Status: aprovado (gate humano 2026-09-12)
Atualizado em: 2026-09-12
Issue: #944
Intenção: docs/plans/worktree-modelo-canonico-deepseek-flash.md
Appetite restante: ~0,5 dia eng (herdado; config-only + textos + pins)
## Leitura da intenção
- **Outcome:** o fluxo sem flag (`pnpm worktree next/plan/new/fix` → `launch opencode <dir> --model <preset> --auto [--prompt …]`) nasce em `deepseek/deepseek-flash`; os 4 commands do fluxo deixam de pinar modelo no frontmatter; help/docblocks/comentários citam o nome novo; override e as 7 flags intactos; unit de preset/frontmatter verde com os literais novos.
- **O que NÃO negociar:**
- `OPENCODE_WORKTREE_MODEL` segue como override (precedência env > fallback) e as 7 flags (`--cheap/--pro/--zen/--go/--alibaba/--glm/--free`) + `WORKTREE_MODEL_MAP` intactos — incluindo os aliases legados de outros providers (`cheapestinference/deepseek-v4-flash`, `alibaba-token-plan/deepseek-v4-flash`).
- Nada além do nome do modelo muda: sem `--variant`/variantes/Ctrl+T, sem config global, sem `opencode.json`, sem mudança de lógica no CLI.
- Usos diretos do app (`src/app/(campaign)/campanha/api/ai-chat/route.ts:62`, `src/utilities/ai/campaignDemandTitle.ts:31`) fora — plano irmão Sollinha; docs históricos congelados.
- É future-proofing de nome canônico, **não** economia (o alias legado já é servido pelo V4.1 ao preço Flash).
- **O que reavaliar:**
- Remover o pin `model:` dos 4 commands muda a semântica desejada: o comando passa a **herdar o modelo da sessão** (o `--model` do launch) em vez de forçá-lo por cima — é isso que faz flags/override valerem dentro da sessão. Precisa de guard de teste para não regredir (decisão 1).
- `tests/unit/worktree.unit.spec.ts:46` (`presetInEffect()`) duplica o literal do fallback — sem trocar junto, o unit quebra no CI (env não exportado). Trocar na mesma fase da constante.
- `tests/unit/opencodeCommands.unit.spec.ts:36-38` é o único guard do frontmatter dos 4 commands — tem de mudar na mesma entrega (decisão 1).
- O docblock do preset (`scripts/lib/worktree.mjs:22-35`) cita `.forgejo/worktree.env` como caminho de override por repo — referência stale (nenhum código lê, pós-cutover GitHub). Fica **fora** desta entrega (não é o nome do modelo); registrar como follow-up.
- `scripts/worktree.mjs:877` (help) interpola `${OPENCODE_PRESET_MODEL}` — auto-atualiza; não há literal para editar ali (só o docblock `:30` tem o literal).
## Estado atual verificado (explorador)
- **Fonte executável única:** `OPENCODE_PRESET_MODEL` em `scripts/lib/worktree.mjs:36-37` (`process.env.OPENCODE_WORKTREE_MODEL || 'deepseek/deepseek-v4-flash'`); consumida em `resolveWorktreeModel` (`:74`) e `opencodeLaunchDirective` (`:214`). `WORKTREE_MODEL_MAP:49` (`cheapestinference/...`) e `:53` (`alibaba-token-plan/...`) ficam intactos.
- **Superfícies com o literal legado do preset (fora de docs):** `scripts/lib/worktree.mjs:37` (constante), `scripts/worktree.mjs:30` (docblock; help `:877` interpola a constante, sem literal), `.agents/shell/worktree.sh:22`, `.agents/skills/worktree-next-issue/SKILL.md:34`, `.opencode/commands/work-issue.md:3` / `plan-issue.md:3` / `bug-fix.md:3` / `testing-audit.md:3`, `tests/unit/worktree.unit.spec.ts:46` (espelho) e `:245` (título), `tests/unit/opencodeCommands.unit.spec.ts:37` (regex).
- **Ausência de pin já é padrão do repo:** `.opencode/commands/issue.md` e `worktree.md` não têm `model:` no frontmatter.
- **Diretiva cobre os 4 propósitos:** `cmdNext` (`scripts/worktree.mjs:619`), `cmdNamespaceBranch` (`:706`, usado por `plan`/`new`/`fix` via `cmdFix:762`) chamam `printLaunchDirective` → `opencodeLaunchDirective`.
- **Blast radius:** `scripts/worktree.mjs` está em `HIGH_RISK_EXACT` (`scripts/lib/test-affected-core.mjs:36`) → diff nele = unit/int full + e2e curado no PR (OPS86). `scripts/lib/worktree.mjs` não é high-risk.
- **Fora do fluxo (intocados):** usos do app em `ai-chat/route.ts:62` e `campaignDemandTitle.ts:31`; `opencode.json`, README, `.husky`, workflows e pool sem refs; `deepseek-v4-flash-vision-exp` sem ocorrência viva.
## Abordagem recomendada
```mermaid
flowchart LR
CLI["pnpm worktree next/plan/new/fix\nsem flag"] --> LIB["scripts/lib/worktree.mjs\nOPENCODE_PRESET_MODEL = env || deepseek/deepseek-flash"]
LIB --> DIR["opencodeLaunchDirective\n--model deepseek/deepseek-flash --auto --prompt"]
DIR --> SH[".agents/shell/worktree.sh\ncd + launch"]
SH --> TUI["TUI opencode\nsessão no nome canônico"]
CMD[".opencode/commands/*.md\nfrontmatter SEM model:"] -->|herda a sessão| TUI
GUARD["opencodeCommands.unit.spec.ts\nausência de pin de modelo"] -.->|protege| CMD
TEST["worktree.unit.spec.ts\npresetInEffect canônico"] -.->|protege| LIB
ENV["OPENCODE_WORKTREE_MODEL"] -.->|override intacto| LIB
FLAGS["7 flags do WORKTREE_MODEL_MAP"] -.->|mapa intacto| LIB
```
**Opções consideradas:** A | B | C
**Recomendação:** A — trocar o fallback na constante única + remover o pin `model:` dos 4 commands + trocar o guard do frontmatter para proibir qualquer pin + sincronizar os textos vivos e os pins de teste. É o menor diff que cumpre o aceite integral e ataca a causa (o pin que sobrescreve a sessão), sem tocar mapa, override ou config.
**Rejeitadas:**
- **B — preset canônico + pin trocado para `deepseek/deepseek-flash` nos 4 commands:** cumpre o nome, mas mantém o acoplamento que anula as flags/override dentro da sessão e recria o débito na próxima renomeação; a intenção manda "deixar de pinar".
- **C — preset canônico apenas (commands intocados):** deixaria o frontmatter pinando o legado — falha o aceite (2) e mantém o override do pin sobre a sessão.
### Decisões de engenharia (caras, com rejeitadas)
1. **Guard do frontmatter após remover o pin (decisão cara desta entrega)**
- Hoje: `tests/unit/opencodeCommands.unit.spec.ts:36-38` exige `model: deepseek/deepseek-v4-flash` no frontmatter de cada um dos 4 commands.
- Opções: **A)** remover a linha `model:` e trocar a asserção por **ausência de qualquer pin** (`expect(frontmatter![1]).not.toMatch(/^model:/m)`); **B)** remover a linha e apagar a asserção; **C)** manter o pin, só trocando o valor para o canônico.
- **Recomendação: A** — única que preserva a intenção ("deixam de pinar") **e** evita regressão silenciosa: se alguém reintroduzir um pin (legado ou canônico), o teste falha e obriga a decisão explícita. Ausência de pin é o padrão já praticado no repo (`.opencode/commands/issue.md` e `worktree.md` vivem sem `model:`), e o comando herda o modelo da sessão — que o launch define via `--model` (preset/flag/override). Forma: remover a linha dos 4 arquivos (frontmatter fica só com `description`); a asserção continua dentro do `it.each(commands)` e cobre os 4 de uma vez, com mensagem explicando que o modelo vem da sessão.
- **Rejeitadas:** **B** — apagar a asserção deixa o frontmatter sem guard: um pin reintroduzido passa em silêncio e volta a anular flags/override (exatamente a classe de bug desta entrega). **C** — contradiz o aceite (2) e recria o acoplamento: com pin, `/work-issue` numa sessão `--cheap`/`--pro` roda no modelo pinado, não no da sessão; a próxima renomeação repetiria a OPS101.
2. **Espelho do fallback no teste (`presetInEffect()`)**
- Opções: **A)** trocar o literal nos dois pontos (constante e espelho); **B)** exportar um `DEFAULT_PRESET_MODEL` e importar no teste; **C)** o teste comparar `OPENCODE_PRESET_MODEL` consigo mesmo.
- **Recomendação: A** — o espelho é deliberado (comentário `:41-45`: "o lib resolve exatamente nessa precedência") e é o que detecta deriva; sem env no CI, espelho = fallback e a comparação em `:246` falha se um dos dois ficar para trás. Menor diff, sem superfície nova.
- **Rejeitadas:** **B** — abstração prematura para um literal com 2 usos (engineering-standards: sem abstração especulativa); **C** — tautologia; teste que sempre passa não protege nada.
3. **Escopo da sincronização de textos**
- Opções: **A)** trocar o literal do preset nas superfícies vivas levantadas (docblock de `scripts/lib/worktree.mjs`, `scripts/worktree.mjs:30`, `.agents/shell/worktree.sh:22`, `SKILL.md:34`, título do teste `:245`); **B)** só a constante; **C)** varrer o repo inteiro por `deepseek-v4-flash`.
- **Recomendação: A** — o aceite pede "textos/help/docblocks refletem o nome novo"; B deixa a doc mentindo; C atinge aliases de outros providers e os usos do app (fora de escopo).
- **Rejeitadas:** **B** — os 3 textos fixos ficariam errados (só o help auto-atualiza); **C** — quebra o anti-goal dos aliases e invade o plano irmão do app.
### Componentes / mudanças
- **`OPENCODE_PRESET_MODEL`** (`scripts/lib/worktree.mjs:36-37`): fallback `'deepseek/deepseek-v4-flash'` → `'deepseek/deepseek-flash'`; `process.env.OPENCODE_WORKTREE_MODEL ||` intacto. Docblock `:22-35`: 1 frase registrando o nome canônico (OPS101, V4.1 Flash) — sem tocar no caminho stale `.forgejo/worktree.env` (fora de escopo). `WORKTREE_MODEL_MAP:49/:53` intactos.
- **`scripts/worktree.mjs:30`** (docblock): literal → nome novo. Help `:877` não muda (interpola a constante). Nenhuma mudança de lógica.
- **`.agents/shell/worktree.sh:22`** (comentário): literal → nome novo; aliases `:19`/`:21` intactos.
- **`.agents/skills/worktree-next-issue/SKILL.md:34`**: prosa do preset → nome novo; aliases da mesma linha intactos.
- **`.opencode/commands/work-issue.md:3`, `plan-issue.md:3`, `bug-fix.md:3`, `testing-audit.md:3`**: remover a linha `model: deepseek/deepseek-v4-flash` (frontmatter fica só com `description`).
- **`tests/unit/worktree.unit.spec.ts:46`**: `presetInEffect()` → literal novo; `:245` título do teste → nome novo (cosmético; evita doc mentirosa); `:294`/`:298` aliases intactos.
- **`tests/unit/opencodeCommands.unit.spec.ts:36-38`**: asserção → ausência de pin (decisão 1).
- **Migration:** sem migration — tooling/config-only, nenhuma collection/global.
- **Access / Consent:** N/A — sem coleção, sem PII, sem write path.
- **UI:** Impeccable A — N/A sem UI (verificação = linha de launch + unit).
### Dados → forma (se aplicável)
N/A — config-only de tooling; nenhum dado de negócio modelado (pergunta 3 de data-presentation não se aplica).
## Fases verificáveis
1. **TDD do preset** — `tests/unit/worktree.unit.spec.ts:46/:245` primeiro (vermelho: constante ainda legada), depois `scripts/lib/worktree.mjs` (constante + docblock); `pnpm test:unit -t worktree` verde, com e sem `OPENCODE_WORKTREE_MODEL` exportado. Quota ~30%.
2. **TDD do frontmatter** — trocar o guard em `opencodeCommands.unit.spec.ts:36-38` para ausência de pin (vermelho com os pins atuais), depois remover a linha `model:` dos 4 `.opencode/commands/*.md`; `pnpm test:unit -t opencodeCommands` verde; `grep -n "^model:" .opencode/commands/*.md` vazio. Quota ~30%.
3. **Textos vivos + gates + entrega** — `scripts/worktree.mjs:30`, `.agents/shell/worktree.sh:22`, `SKILL.md:34`; smoke seguro (sem claim) `node -e "import('./scripts/lib/worktree.mjs').then(m => console.log(m.opencodeLaunchDirective({ dir: '/tmp/wt', purpose: 'next', terminal: true })))"` → `--model deepseek/deepseek-flash`; grep final de `deepseek/deepseek-v4-flash` fora de `docs/` deve sobrar só os 2 usos do app (Sollinha); changelog NOVA entrada `docs/changelog/2026-09-12-ops101.md`; `pnpm gate:fast`; `pnpm push` → PR `Closes #944`. Nota: `scripts/worktree.mjs` é `HIGH_RISK_EXACT` (`scripts/lib/test-affected-core.mjs:36`) → PR roda unit/int full + e2e curado (OPS86), mesmo com diff só de docblock. Quota ~40%.
## Rabbit holes / Não escopo (engenharia)
- NÃO trocar o cardápio/mapa (`WORKTREE_MODEL_MAP`, chaves ou values) nem os aliases de outros providers.
- NÃO mexer em variante/thinking/`--variant`/Ctrl+T/config global/`opencode.json` do repo.
- NÃO "vender economia" — registrar como nome canônico/future-proofing.
- NÃO trocar os usos diretos do app (plano irmão Sollinha: `ai-chat/route.ts:62`, `campaignDemandTitle.ts:31`).
- NÃO corrigir o caminho stale `.forgejo/worktree.env` no docblock do preset (follow-up; não é o nome do modelo).
- NÃO editar docs históricos (`docs/plans/*` antigos, `docs/changelog/*`, `docs/CHANGELOG-AGENTS*`).
- NÃO criar constante/abstração nova para o fallback (2 usos; espelho do teste é o guard).
- NÃO varrer o repo inteiro por `deepseek-v4-flash` (atinge app e aliases).
- NÃO usar `pnpm worktree next` como smoke (claimaria Issue real) — o smoke é a chamada direta da lib.
## Riscos e mitigação
- **Sessões manuais que invocam `/work-issue` fora do launch passam a herdar o modelo da sessão** (antes o pin forçava o legado) → é o comportamento desejado (o launch/flags/override mandam); registrar como mudança intencional no PR.
- **HIGH_RISK_EXACT (`scripts/worktree.mjs`)** → PR roda unit/int full + e2e curado; mitigação: tocar só docblock (`:30`), sem claim/provision/PORT/env.
- **Deriva entre constante e `presetInEffect()`** → CI sem env quebra; mitigação: trocar os dois na mesma fase (Fase 1).
- **Pin reintroduzido por engano** → guard de ausência (Fase 2) falha com mensagem explicando a origem do modelo.
- **Varredura ampla apagar aliases do mapa** → mitigação: troca só do literal `deepseek/deepseek-v4-flash` (com namespace), nunca dos aliases; pins `:294/:298` cobrem o mapa.
- **Usos do app trocados por engano** → mitigação: grep final mostra os 2 `deepSeek('deepseek-v4-flash')` intocados.
- **Override `OPENCODE_WORKTREE_MODEL`** → intacto (só o fallback muda); teste cobre a precedência env > fallback.
## Aceite de engenharia
- [ ] Aceite de produto da intenção ainda coberto: preset sem flag = `deepseek/deepseek-flash`; 4 commands sem pin; help/docblocks/comentários com o nome novo; override + 7 flags intactos; unit verde com literais novos.
- [ ] Invariantes AGENTS/engineering-standards: sem collection/global/migration; sem twin (constante única editada no dono); Consent/LGPD intocados; `push:false` preservado; `pnpm gate:fast` verde; identificadores em inglês.
- [ ] Testes de domínio previstos (unit/int) onde access/write paths mudam: N/A (sem access/write path) — unit de preset (`worktree.unit.spec.ts`) e de frontmatter (`opencodeCommands.unit.spec.ts`) atualizados e verdes; smoke da diretiva registrado no PR.
---
Self-score decision-quality: 5/5 — decisão cara (guard do frontmatter) deliberada com rejeitadas e forma exata; cabe no appetite (constante + 4 remoções de linha + 3 textos + 2 specs); rabbit holes nomeados com gatilhos; depth check reusa o dono (`OPENCODE_PRESET_MODEL`) e os guards existentes sem criar twin; outcome da intenção preservado (incluindo o não-ganho de economia).

View file

@ -31,10 +31,12 @@ export const WORKTREE_TERMINAL_ENV = 'TEQO_WORKTREE_TERMINAL'
* `--cheap/--pro/--zen/--go/--alibaba/--glm/--free` o mapa `WORKTREE_MODEL_MAP`
* escolhe o modelo por invocação; sem flag o preset permanece. OPS95: sem
* `--variant` na diretiva (o TUI rejeita o flag) — variantes ficam na config
* global da máquina, via Ctrl+T.
* global da máquina, via Ctrl+T. OPS101: o fallback passou ao nome canônico
* `deepseek/deepseek-flash` (DeepSeek V4.1 Flash, lançado em 2026-09-10; o
* alias legado segue servido ao preço Flash, mas pode sumir sem aviso).
*/
export const OPENCODE_PRESET_MODEL =
process.env.OPENCODE_WORKTREE_MODEL || 'deepseek/deepseek-v4-flash'
process.env.OPENCODE_WORKTREE_MODEL || 'deepseek/deepseek-flash'
/**
* Per-invocation model map — fixed menu of named flags (OPS93; values

View file

@ -27,7 +27,7 @@
* hy3, alibaba=alibaba-token-plan/deepseek-v4-flash,
* glm=opencode-go/glm-5.3-flash, free=openrouter/
* openrouter/free; OPS95 + OPS100) — sem flag o preset
* `deepseek/deepseek-v4-flash` permanece.
* `deepseek/deepseek-flash` permanece.
* Chamado do terminal interativo (com
* `TEQO_WORKTREE_TERMINAL=1`, que só a função shell
* seta), imprime também a diretiva `launch

View file

@ -33,8 +33,9 @@ describe('opencode commands couple to their skill by exact name', () => {
expect(frontmatter![1], 'frontmatter must declare a TUI description').toMatch(
/^description: .+$/m,
)
expect(frontmatter![1], 'frontmatter must pin the preference model').toMatch(
/^model: deepseek\/deepseek-v4-flash$/m,
)
expect(
frontmatter![1],
'frontmatter must NOT pin a model — the command inherits the session model (OPS101)',
).not.toMatch(/^model:/m)
})
})

View file

@ -43,7 +43,7 @@ type TestIssue = {
* OPENCODE_WORKTREE_MODEL não está exportado (CI), ou o valor exportado
* (shell local) — o lib resolve exatamente nessa precedência.
*/
const presetInEffect = () => process.env.OPENCODE_WORKTREE_MODEL || 'deepseek/deepseek-v4-flash'
const presetInEffect = () => process.env.OPENCODE_WORKTREE_MODEL || 'deepseek/deepseek-flash'
const issue = (over: Partial<TestIssue> = {}): TestIssue => ({
number: 1,
@ -242,7 +242,7 @@ describe('opencodeLaunchDirective (terminal-only opencode launch, OPS26 + OPS33
).toBe(`launch opencode ${dir} --model ${presetInEffect()} --auto`)
})
it('pins the preset constants — fallback comum deepseek-v4-flash, override via OPENCODE_WORKTREE_MODEL', () => {
it('pins the preset constants — fallback comum deepseek-flash, override via OPENCODE_WORKTREE_MODEL', () => {
expect(OPENCODE_PRESET_MODEL).toBe(presetInEffect())
expect(WORKTREE_TERMINAL_ENV).toBe('TEQO_WORKTREE_TERMINAL')
expect(OPENCODE_SKILL_COMMAND_BY_PURPOSE).toEqual({