From e7bf7096474f72d2e1d747ddcc116cb74d27465c Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Sat, 12 Sep 2026 01:52:27 -0300 Subject: [PATCH] =?UTF-8?q?fix(worktree):=20OPS101=20=E2=80=94=20preset=20?= =?UTF-8?q?can=C3=B4nico=20deepseek-flash=20e=20commands=20sem=20pin=20de?= =?UTF-8?q?=20modelo=20(Closes=20#944)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .agents/shell/worktree.sh | 2 +- .agents/skills/worktree-next-issue/SKILL.md | 2 +- .opencode/commands/bug-fix.md | 1 - .opencode/commands/plan-issue.md | 1 - .opencode/commands/testing-audit.md | 1 - .opencode/commands/work-issue.md | 1 - docs/changelog/2026-09-12-ops101.md | 1 + ...ree-modelo-canonico-deepseek-flash-impl.md | 125 ++++++++++++++++++ scripts/lib/worktree.mjs | 6 +- scripts/worktree.mjs | 2 +- tests/unit/opencodeCommands.unit.spec.ts | 7 +- tests/unit/worktree.unit.spec.ts | 4 +- 12 files changed, 139 insertions(+), 14 deletions(-) create mode 100644 docs/changelog/2026-09-12-ops101.md create mode 100644 docs/plans/worktree-modelo-canonico-deepseek-flash-impl.md diff --git a/.agents/shell/worktree.sh b/.agents/shell/worktree.sh index a9d45c67..617acbfb 100644 --- a/.agents/shell/worktree.sh +++ b/.agents/shell/worktree.sh @@ -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 diff --git a/.agents/skills/worktree-next-issue/SKILL.md b/.agents/skills/worktree-next-issue/SKILL.md index 93060ed1..5e4f1567 100644 --- a/.agents/skills/worktree-next-issue/SKILL.md +++ b/.agents/skills/worktree-next-issue/SKILL.md @@ -31,7 +31,7 @@ No opencode, isso é o comando **`/worktree next`** / **`/worktree kill`** (`.op **Default-go:** `next`, `plan` e `new` imprimem `cd ` 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
` 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 --model --auto [--prompt "/work-issue --issue "]` **antes** do `cd`, e a função a executa depois do cd — `next` abre o TUI com `/work-issue --issue ` 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 --model --auto [--prompt "/work-issue --issue "]` **antes** do `cd`, e a função a executa depois do cd — `next` abre o TUI com `/work-issue --issue ` 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) diff --git a/.opencode/commands/bug-fix.md b/.opencode/commands/bug-fix.md index d7e4fce2..f2a56b1d 100644 --- a/.opencode/commands/bug-fix.md +++ b/.opencode/commands/bug-fix.md @@ -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. diff --git a/.opencode/commands/plan-issue.md b/.opencode/commands/plan-issue.md index a0cb74e9..a4bfa1ea 100644 --- a/.opencode/commands/plan-issue.md +++ b/.opencode/commands/plan-issue.md @@ -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. diff --git a/.opencode/commands/testing-audit.md b/.opencode/commands/testing-audit.md index 42726c58..a9ffcf05 100644 --- a/.opencode/commands/testing-audit.md +++ b/.opencode/commands/testing-audit.md @@ -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. diff --git a/.opencode/commands/work-issue.md b/.opencode/commands/work-issue.md index ca9724ec..0c619712 100644 --- a/.opencode/commands/work-issue.md +++ b/.opencode/commands/work-issue.md @@ -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. diff --git a/docs/changelog/2026-09-12-ops101.md b/docs/changelog/2026-09-12-ops101.md new file mode 100644 index 00000000..0505cb1b --- /dev/null +++ b/docs/changelog/2026-09-12-ops101.md @@ -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). diff --git a/docs/plans/worktree-modelo-canonico-deepseek-flash-impl.md b/docs/plans/worktree-modelo-canonico-deepseek-flash-impl.md new file mode 100644 index 00000000..d6dc8d82 --- /dev/null +++ b/docs/plans/worktree-modelo-canonico-deepseek-flash-impl.md @@ -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 --model --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). diff --git a/scripts/lib/worktree.mjs b/scripts/lib/worktree.mjs index 34e74c7d..cb3646e8 100644 --- a/scripts/lib/worktree.mjs +++ b/scripts/lib/worktree.mjs @@ -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 diff --git a/scripts/worktree.mjs b/scripts/worktree.mjs index f6696b46..a419a203 100644 --- a/scripts/worktree.mjs +++ b/scripts/worktree.mjs @@ -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 diff --git a/tests/unit/opencodeCommands.unit.spec.ts b/tests/unit/opencodeCommands.unit.spec.ts index 30a5ba76..f618cf5b 100644 --- a/tests/unit/opencodeCommands.unit.spec.ts +++ b/tests/unit/opencodeCommands.unit.spec.ts @@ -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) }) }) diff --git a/tests/unit/worktree.unit.spec.ts b/tests/unit/worktree.unit.spec.ts index 0acab872..32f20802 100644 --- a/tests/unit/worktree.unit.spec.ts +++ b/tests/unit/worktree.unit.spec.ts @@ -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 => ({ 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({