Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ Versionamento independente do OpenClaw — kit segue semver próprio.
## [Unreleased]

### Adicionado
- **Lesson** [`lessons/2026-06-17-toolsallow-incompatible-claude-cli.md`](lessons/2026-06-17-toolsallow-incompatible-claude-cli.md) — (sem TL;DR — ver lesson para detalhes)
- **Lesson** [`lessons/2026-06-21-openclaw-6.8-to-6.9-upgrade-and-skill-symlink-escape.md`](lessons/2026-06-21-openclaw-6.8-to-6.9-upgrade-and-skill-symlink-escape.md) — (sem TL;DR — ver lesson para detalhes)
- **Lesson** [`lessons/2026-06-30-openclaw-6.11-upgrade.md`](lessons/2026-06-30-openclaw-6.11-upgrade.md) — (sem TL;DR — ver lesson para detalhes)
- **Lesson** [`lessons/2026-07-07-toolsallow-legacy-marker-breaks-cli-fallback.md`](lessons/2026-07-07-toolsallow-legacy-marker-breaks-cli-fallback.md) — - claude-cli cannot enforce runtime toolsAllow → fallback silencioso pra um modelo sem Bash → agente "some".
- **Lesson** [`lessons/2026-07-09-reply-session-init-conflict-and-contributing-upstream.md`](lessons/2026-07-09-reply-session-init-conflict-and-contributing-upstream.md) — - reply session initialization conflicted com messageIds distintos + sessão viva = transient drop benigno; com mesma messageId + sessão travada = wedge (real, precisa fix//reset).
- **Lesson** [`lessons/2026-06-20-claude-cli-resume-hang-and-fallback-recovery.md`](lessons/2026-06-20-claude-cli-resume-hang-and-fallback-recovery.md) — Um turn provider=claude-cli model=claude-sonnet-4-6 trigger=user ficou 900s sem emitir um único byte (sem stream, sem rawLines) e foi morto pelo watchdog: claude live session turn failed ... durationM
- **Lesson** [`lessons/2026-06-16-openclaw-6.8-apply-patches-pattern-drift.md`](lessons/2026-06-16-openclaw-6.8-apply-patches-pattern-drift.md) — (sem TL;DR — ver lesson para detalhes)
- **Lesson** [`lessons/2026-06-09-openclaw-6.5-upgrade-patches-not-native-and-backup-retention.md`](lessons/2026-06-09-openclaw-6.5-upgrade-patches-not-native-and-backup-retention.md) — Upgrade planejado 2026.6.5 (primeiro stable do train 6.5, depois de 5 betas). A lição central é o oposto da do upgrade anterior: no 6.1, três monkey-patches viraram correções nativas e foram aposentad
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ openclaw-update-toolkit/
│ ├── upgrade-from-v24-to-v29.md
│ ├── recovery-from-fratricide-loop.md
│ └── recovery-from-cost-explosion.md
└── lessons/ # 30 lições por incident — fonte de truth
└── lessons/ # 35 lições por incident — fonte de truth
```

---
Expand Down
95 changes: 95 additions & 0 deletions lessons/2026-06-17-toolsallow-incompatible-claude-cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Lesson: `toolsAllow` incompatível com backend `claude-cli`

**Data:** 2026-06-17
**Severidade:** Alta (crons críticos falharam silenciosamente por múltiplos dias)
**Agente:** Forge

---

## O que aconteceu

Três crons críticos passaram a falhar com erro consistente:

```
FallbackSummaryError: All models failed (2):
anthropic/claude-haiku-4-5: CLI backend claude-cli cannot enforce runtime toolsAllow;
use an embedded runtime for restricted tool policy (unknown)
openai/gpt-5.5: auth refresh request timed out after 10s (timeout)
```

**Jobs afetados:**
| Job | Agent | `toolsAllow` | Erros consecutivos |
|-----|-------|-------------|-------------------|
| `relatorio-eod` | main | `["exec", "session_status"]` | 4 |
| `auto-update-skills-clawhub` | main | `["exec"]` | 4 |
| `workspace-git-autopush` | forge | `["exec"]` | 4 |

**Job proativamente corrigido antes de falhar:**
| Job | Agent | `toolsAllow` |
|-----|-------|-------------|
| `cipher-weekly-full` | cipher | `["exec", "message"]` |

---

## Root cause

O campo `toolsAllow` no payload de cron jobs define uma allowlist de ferramentas — quando presente, o runtime tenta restringir o agente apenas a essas ferramentas.

**O problema:** o backend `claude-cli` (usado pelo `anthropic/claude-haiku-4-5` e todos os modelos Anthropic via CLI) **não suporta enforcement de `toolsAllow` em runtime**. A verificação passou a ser feita de forma mais rígida em alguma versão recente do gateway, rejeitando o job antes mesmo de iniciar a execução.

O fallback para `openai/gpt-5.5` (OAuth) também falhou por timeout de auth refresh — deixando os jobs sem fallback funcional.

---

## Por que alguns jobs com `toolsAllow` continuaram funcionando?

Os jobs de briefing (`prepare-briefing-context`, `daily-briefing-delivery`, etc.) também tinham `toolsAllow: ["exec"]` mas não falharam imediatamente. Hipótese: o enforcement mais rígido foi introduzido gradualmente ou os jobs afetados têm alguma combinação específica (ex: `lightContext: true` + `toolsAllow`).

**Ação preventiva recomendada:** remover `toolsAllow` de todos os cron jobs que usam modelos Anthropic via CLI.

---

## Fix aplicado

Removido `toolsAllow` (setado para `null`) nos 4 jobs via `cron.update`:

```bash
# Exemplo do patch aplicado em cada job
{
"patch": {
"payload": {
"toolsAllow": null
}
}
}
```

**Por que é seguro remover:** os jobs são todos `sessionTarget: "isolated"` — sessões efêmeras sem histórico de ferramenta. O comportamento do agente já é constrangido pelo prompt (ex: "Execute X, responda HEARTBEAT_OK"). A restrição via `toolsAllow` era redundante.

---

## Regra para novos crons

> **Nunca use `toolsAllow` em cron jobs com `sessionTarget: "isolated"` e modelo Anthropic (claude-cli).**

Se precisar restringir ferramentas em cron jobs:
1. Use **embedded runtime** (não claude-cli) — ex: `openai/gpt-4o` com API key direta
2. Ou constranja via **prompt** — mais confiável e portável entre runtimes

---

## Lições aprendidas

1. **`toolsAllow` ≠ segurança robusta** — depende de suporte do runtime e pode quebrar silenciosamente
2. **Fallback chain deve ser testada** — `gpt-5.5` OAuth estava com timeout; fallback ineficaz
3. **Crons críticos precisam de `failureAlert`** — `workspace-git-autopush` não tinha alerta configurado, ficou 4 falhas silencioso
4. **Alertas de falha chegam tarde** — `relatorio-eod` alertou só na 3ª falha; para crons diários isso é 3 dias perdidos

---

## Ações de follow-up recomendadas

- [ ] Auditar todos os crons restantes com `toolsAllow` e remover onde modelo = Anthropic/CLI
- [ ] Verificar health do OAuth `openai/gpt-5.5` — auth refresh timeout pode indicar token próximo de expirar
- [ ] Adicionar `failureAlert` ao `workspace-git-autopush` (atualmente sem alerta)
- [ ] Considerar reduzir `failureAlert.after` em crons críticos de 3 para 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# 2026-06-21 — Upgrade OpenClaw 6.8→6.9 + 4 achados (Patch 2 re-drift, emoji path, native claude dedup, skill symlink-escape)

> Sessão noturna (~20:30→22:05 BRT). Upgrade estável 6.8→6.9 + revisão completa pós-upgrade (5 itens) + fix sistêmico de skills quebradas em 4 agents. Zero downtime. Antes, fechamento do PR #90450 (rebase + diagnóstico de CI flaky do upstream).

## Contexto
6.9 estável saiu 2026-06-21 ~01:44 UTC. Motivação: retry de empty/thinking-only post-tool turns (#92191/#92383), auth-profiles→SQLite (#93156), restart de gateway pós-update falho (#92111), nox-mem WAL/reindex (#92891), plugin recovery (#93325), secret redaction (#93333). Não-urgente (sem CVE/crash forçando). PR #90450 segue aberto → patches mandatórios.

## Upgrade (6 fases, zero downtime)
`npm install -g openclaw@2026.6.9` (`c645ec4`), 11s. 5 plugins `@openclaw/{acpx,codex,discord,slack,whatsapp}`→6.9. NRestarts=0, smoke `infer`→`provider:anthropic UPGRADE_OK`, Slack socket connected + WhatsApp linked.

## Achado 1 — Patch 2 (tool-only) RE-DRIFTOU: inline → BLOCO
O 6.8 já tinha quebrado o Patch 2 (linha do `FailoverError`). No 6.9 quebrou de novo, mas de forma DIFERENTE: a condição virou **bloco** onde era **inline**.
- 6.8: `if (!assistantText && !output.didSendViaMessagingTool && ...!== true) throw attachCliMessagingDeliveryEvidence(new FailoverError(...))`
- 6.9: `if (!assistantText && !output.didSendViaMessagingTool && ...!== true) {` `\n const emptyOutputDiagnostics = ...;` `\n throw attach...`

**Fix:** nova 1ª variante no array `replacements` do `apply-patches.sh` que casa `...!== true) {` e insere `&& !output.hadToolCalls`. **Novidade boa:** o parser do 6.9 já emite `hadToolCalls = raw.includes('"tool_use"')` NATIVO — upstream foi meio caminho do PR #90450, só não conectou no cli-runner (Patch 1/live agora só marca, sem mudar lógica). Hashes 6.9: `claude-live-session-BFQhL7uS.js` (empty+debug) + `cli-runner-BOYyOIRI.js` (tool-only).
**Lição:** a linha-alvo do tool-only é frágil a refactor — esperar drift NOVO a cada upgrade. Validar SEMPRE `tail /var/log/openclaw-apply-patches.log` por `FAIL`.

## Achado 2 — Emoji patch (regra 2.1) mudou de path
6.9 moveu `status-message-*.js` de `~/.openclaw/plugin-runtime-deps/openclaw-*/dist/` (que sumiu) para o **core dist** `/usr/lib/node_modules/openclaw/dist/`. O `reapply-session-status-emoji-patch.py` dava `no targets found`. Pattern do template-literal NÃO mudou. **Fix:** glob do script atualizado pra cobrir os 2 paths (espelho + VPS). ⚠️ Agora vive no core dist → some a cada `npm install -g`, reaplicar pós-upgrade.

## Achado 3 — DOIS claudes (dedup do harness)
`claude --version` no SSH mostrava 2.1.87 (enganoso). Havia 2 instalações:
- `/usr/bin/claude` → `@anthropic-ai/claude-code` npm global = **2.1.169** (o harness REAL; PATH do systemd `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/snap/bin` NÃO inclui `/root/.local/bin`, logo o gateway SEMPRE usa este)
- `/root/.local/bin/claude` → `~/.local/share/claude/versions/2.1.87` (native installer, só no login shell interativo)
**Fix:** removido o native (reversível, backup `/root/.trash-claude-native-*` 218M; 0 crons/scripts dependiam — só shell-snapshots do Claude Code o referenciavam). Depois **harness atualizado 2.1.169→2.1.185** (npm -g; credentials `chattr +i` intactas; validado por turns REAIS de prod sonnet+haiku `provider=claude-cli` $0).

## Achado 4 — Skill symlink-escape QUEBROU skills de 4 agents (regressão 6.9, #86719)
O 6.9 endureceu skill symlink handling (release "stale plugin skill symlinks are repaired" #86719) e passou a **rejeitar silenciosamente** skills expostas via symlink que resolvem fora do root (`[skills] Skipping escaped skill path outside its configured root ... reason=symlink-escape`). Skills instaladas via ClawHub vivem em `<agent>/.agents/skills/` e eram expostas via symlink em `<agent>/skills/` → todas puladas.
**Impacto:** forge 15, boris 12, atlas 12 (passivo), cipher 1 — skills exclusivas (payment-assistant, binance, fiat, p2p, trading-signal…) silenciosamente perdidas.
**Fix:** resolver symlinks → conteúdo real dentro do root (discriminado: `.agents/skills`→cp; `workspace/skills`→rm redundante; broken→rm). 0 escapes pós-restart. Contagem final: forge 36, boris 20, atlas 28, cipher 10, nox 15, lex 8. Backups `/root/.openclaw/.skill-symlink-backup/<agent>-<ts>`. Memória `symlinks-agents-skills-redundantes` reescrita (estava perigosamente errada — mandava "safe deletar"). ⚠️ Re-checar no próximo upgrade (npm install -g mexe em skill symlinks).

## Itens da revisão que NÃO geraram ação
- **#4 SQLite plugin metadata conflict:** won't-fix benigno. `doctor --fix --non-interactive` NÃO migrou ("left in place" por conflicting metadata) E reinstalou providers fantasma como efeito colateral → REVERTIDO. Conflito é inerente ao npm-direto (regra 2.2). Plugins funcionam.
- **#3 providers fantasma:** removidos 12 (`config unset plugins.entries.*` + `plugins.allow` sem firecrawl/perplexity/kimi) → validate 4→1 warning (só graph-memory, design).

## ⚠️ Gotcha crítico: `doctor --fix` é perigoso em prod
Mesmo `--non-interactive`: NÃO migrou o que prometeu E reinstalou providers que eu tinha limpado. Haiku NÃO está em `agents.defaults.models` (risco de migração haiku→sonnet). **Não rodar `doctor --fix` casualmente** — snapshot de invariantes + backup granular + reverter se driftar.

## Estado final
OpenClaw 6.9 (`c645ec4`) · harness 2.1.185 · 4 patches (empty-response/tool-only/debug-capture/emoji) · 5 plugins · config 1 warning · haiku preservado (4+9) · skills de 6 agents carregando · 1 só claude · gateway active NRestarts=0.

## Pendências
- Deletar backups: `/root/.trash-claude-native-*` (218M, após validar uns dias) + `.skill-symlink-backup/*`
- Sync lesson pro toolkit público (`sync-to-toolkit.sh`)
- Vigiar skill symlink-escape + emoji patch path no PRÓXIMO upgrade
- PR #90450: 3 shards CI vermelhos = flaky universal do upstream (provado em 7 PRs), aguardando maintainer
34 changes: 34 additions & 0 deletions lessons/2026-06-30-openclaw-6.11-upgrade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 2026-06-30 — Upgrade OpenClaw 6.10 → 6.11 (limpo, Patch 2 estável)

**Contexto:** Toto pediu análise dos releases. Recon revelou que a doc dizia "6.9" mas a VPS já estava em **6.10** (subiu 28/jun). Salto real = 1 minor (6.10→6.11). Motivado por fixes de fallback chain.

## Upgrade (6 fases, zero downtime, ~5min)
0. Backup `/var/backups/preupgrade-6.11-20260630-1632` (openclaw.json 43k + chain + catálogo + plugins-list + health + dist-hashes). NRestarts baseline=3.
1. `npm install -g openclaw@2026.6.11` (19s) → `e085fa1`.
2. `apply-patches.sh` → **3/3 `patch applied`, Patch 2 tool-only NÃO driftou.** Hashes 6.11: `claude-live-session-ChcH88T3.js` (empty+debug) + `cli-runner-H97DdWc0.js` (tool-only).
3. Phase 7: 5 plugins `@openclaw/{acpx,codex,discord,slack,whatsapp}` → 2026.6.11.
4. `systemctl restart openclaw-gateway` → apply-patches boot 3/3 `already patched`, `END OK`, NRestarts=0.
5. Validação: smoke `infer model run`→`PONG_611` (provider:anthropic claude-sonnet-4-6), chain íntegra (sonnet-4-6→gpt-5.5→kimi-k2.6→glm-5.2), 3 canais up (Discord@Maestro/Slack healthy/WhatsApp linked), 8 agents, 0 ERROR/fratricide.

## Achado 1 — Patch 2 (tool-only) ESTÁVEL no 6.10 E 6.11
Depois de driftar no 6.8 (inline→`didSendViaMessagingTool`) e 6.9 (inline→**bloco**), o pattern do 6.9 (casa `...!== true) {` e insere `&& !output.hadToolCalls`) **sobreviveu intacto no 6.10 e no 6.11**. Sinal de que o `cli-runner` estabilizou nessa forma. **Não baixar a guarda:** continuar validando `tail /var/log/openclaw-apply-patches.log` por FAIL a cada upgrade — o drift é imprevisível.

## Achado 2 — Warnings de provider plugin são PRÉ-EXISTENTES (não regressão)
`openclaw agents`/doctor read-only listou `plugins.entries.{moonshot,fireworks,tencent,venice,vercel-ai-gateway}: plugin not installed`. **Classificação correta:** `jq '.plugins.entries | keys' openclaw.json.bak` confirmou que `moonshot/fireworks/tencent` já estavam no config ANTES do upgrade. São entries de config de provider sem o plugin-provider instalado — mas a chain usa `agentRuntime` (kimi via ACP, glm via endpoint anthropic-compat), não esses plugins. Benigno. **Lição de método:** sempre comparar warning suspeito contra o snapshot pré-upgrade antes de "consertar" — quase reinstalei plugins desnecessários.

## Achado 3 — "conflicting plugin install metadata" = efeito esperado do Phase 7
Após `npm install` dos 5 plugins externos, o doctor reporta metadata conflitante no SQLite plugin-index ("Left plugin install index in place"). É o efeito conhecido de instalar via npm direto (workaround obrigatório do bug `plugins install` destrutivo). Install-index fica em JSON, plugins carregam normal. Não acionar `doctor --fix` por causa disso.

## Por que 6.11 (fixes que importam pra nós)
- **#95508 / #95489** — `claude-cli` out-of-credits **bypassava a fallback chain** (entregava texto de erro como final). Ataca direto a fragilidade `All models failed`.
- **#95420 / #95400** — credit failures e usage-limit do Codex agora seguem a chain (gpt-5.5 expira 09/jul).
- **#95652** — activate selected harness plugins (anti-unregistered).
- **#95624** — long-context tool-result prompts cache-stable (1M).
- **#94148** — `doctor --fix` não-interativo não reinicia gateway sozinho (alinha com nossa regra "doctor --fix perigoso em prod").

## Lições transferíveis
1. **Doc drift entre upgrades:** o forge subiu pra 6.10 em 28/jun mas não atualizou CLAUDE.md/MEMORY.md (ficou "6.9"). Sempre confirmar versão real via SSH antes de planejar — `openclaw --version` é a fonte de verdade.
2. **Patch 2 pode estar estabilizando** mas validar o log por FAIL segue mandatório.
3. **Warning ≠ regressão:** classificar contra snapshot pré-upgrade.

Memória: `[[openclaw-61-upgrade-patches-native]]`. Plan: `plans/2026-06-30-openclaw-v2026.6.11-upgrade.md`.
Loading
Loading