diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f0ddbf..d7a3f70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Versionamento independente do OpenClaw — kit segue semver próprio. ## [Unreleased] ### Adicionado +- **Lesson** [`lessons/2026-05-24-upgrade-5.22-harness-restart-latency-and-plugin-config-env.md`](lessons/2026-05-24-upgrade-5.22-harness-restart-latency-and-plugin-config-env.md) — (sem TL;DR — ver lesson para detalhes) - **Lesson** [`lessons/2026-05-08-09-invariant-upgrade-and-health-probe-race.md`](lessons/2026-05-08-09-invariant-upgrade-and-health-probe-race.md) — (sem TL;DR — ver lesson para detalhes) - **Lesson** [`lessons/2026-05-09-upgrade-5.7-and-f18-f17-mitigation.md`](lessons/2026-05-09-upgrade-5.7-and-f18-f17-mitigation.md) — | Item | Estado | - **Lesson** [`lessons/2026-05-17-launchagent-mac-stale-openclaw-version.md`](lessons/2026-05-17-launchagent-mac-stale-openclaw-version.md) — (sem TL;DR — ver lesson para detalhes) diff --git a/README.md b/README.md index 4cf6d01..086eb96 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ openclaw-update-toolkit/ │ ├── upgrade-from-v24-to-v29.md │ ├── recovery-from-fratricide-loop.md │ └── recovery-from-cost-explosion.md -└── lessons/ # 22 lições por incident — fonte de truth +└── lessons/ # 23 lições por incident — fonte de truth ``` --- diff --git a/lessons/2026-05-24-upgrade-5.22-harness-restart-latency-and-plugin-config-env.md b/lessons/2026-05-24-upgrade-5.22-harness-restart-latency-and-plugin-config-env.md new file mode 100644 index 0000000..6acff82 --- /dev/null +++ b/lessons/2026-05-24-upgrade-5.22-harness-restart-latency-and-plugin-config-env.md @@ -0,0 +1,51 @@ +# Lesson 2026-05-24 — Upgrade 5.20→5.22: harness pós-update, latência = trabalho, e `${VAR}` não resolve em config de plugin + +Upgrade 5.20→5.22. Logo após, Nox (WhatsApp) e Forge (Discord) pararam de responder. Três problemas distintos numa cadeia — diagnosticados e resolvidos em sequência. + +## 1. Canais mudos: harness `claude-cli` not registered (causa = restart in-process) + +**Sintoma:** transporte conectado (WhatsApp `connected/healthy`, Discord reconectando), mas TODO dispatch de canal falha com `MissingAgentHarnessError: Requested agent harness "claude-cli" is not registered`. + +**Diagnóstico:** o `openclaw update` reinicia o gateway via `[restart-sentinel]` (restart **in-process**), visível no journal como `Gateway restart restart ok (gateway.restart)`. Restart in-process **NÃO re-registra o harness** (o plugin `anthropic` lazy não re-ativa). É diferente de um cold start do systemd. + +**Fix:** `systemctl restart openclaw-gateway` (cold). Confirma no journal: `http server listening (N plugins: ...anthropic...whatsapp...)`. + +**Resíduo de boot (NÃO confundir com falha):** 1-2 `MissingAgentHarnessError` nos primeiros ~50s pós-cold-restart são a fila de retry do restart-sentinel reprocessando mensagens antigas ANTES do harness subir (`channel=webchat source=replyResolver messageId=restart-sentinel:...`). Validação correta: contar erros numa janela DEPOIS do boot (`journalctl -u openclaw-gateway --since ""` deve dar 0), e procurar um `claude live session turn` de sucesso. + +**Fonte de log:** `journalctl -u openclaw-gateway` (o wrapper `openclaw-gateway-wrapper` loga tudo lá) — tão válido quanto `/tmp/openclaw/*.log`. + +## 2. Latência alta = trabalho do turn, não overhead de prompt + +**Sintoma:** "responde mas demora uma eternidade", intermitente. + +**Diagnóstico:** a latência de um turn escala com `rawLines` (tool calls em cadeia + tamanho da resposta), NÃO com o tamanho do system prompt: + +| rawLines (trabalho) | tempo (sonnet) | +|---|---| +| ~17 | 2-4s | +| 51-56 | 14-15s | +| 157-199 | 60-67s | + +Turns leves já respondem em 2-4s mesmo no modelo grande; os de 60s fazem 150-200 rawLines (muita ferramenta). **Enxugar prompt/skills dá ganho modesto** (custo fixo de prefill já é ~2-7s). Alavancas reais pros turns longos: modelo mais leve no chat casual, ou instrução de concisão (menos tool calls). + +**Falso suspeito:** fetch-timeout de 120s pro provider de embedding logo após restart = **event-loop starvation** (`eventLoopDelayMax ~9s` durante o boot pesado), não rede nem chave. + +**Cortar skills do prompt:** skills em `skills.load.extraDirs` SEM entry em `skills.entries` são auto-ativadas e injetadas no prompt. Desativar = adicionar `{"enabled": false}` em `skills.entries.`. Cada skill ≈ 1 linha na seção `## Skills`. Sempre backup + `openclaw config validate` + restart. + +## 3. `${VAR}` NÃO resolve em `plugins.entries..config` + +**Sintoma:** o plugin de memória (graph-memory) falha o embedding com `Embedding API 400: API key expired` — apesar da chave do `.env` estar **válida** (HTTP 200 nos endpoints). + +**Causa raiz:** o openclaw interpola `${VAR}` no config CORE (`models.providers.*`, `channels.*`, `gateway.auth.token`) mas passa `plugins.entries..config` **cru** pro plugin, sem interpolar. O plugin recebia a string literal `${...}` e a mandava como credencial → o provider respondia "expired"/inválido. + +**Pegadinha de diagnóstico:** `openclaw config get` redacta TODO campo `apiKey` como `__OPENCLAW_REDACTED__` — isso **NÃO prova** que o `${VAR}` resolveu; mascara a string crua. Confirmar lendo o valor real (começa com `${` = ref não-resolvida vs credencial real). + +**Fix aplicado:** chave literal no `embedding.apiKey` + `llm.apiKey` do plugin config (lida do `.env` no host, sem expor). Pós-restart: `[graph-memory] vector search ready`. **Alternativa limpa** (não usada — exige projeto dedicado): ativar o sistema SecretRef formal do 5.22 (`openclaw secrets configure` + `secrets.providers`), que re-resolve refs no runtime snapshot e cobriria config de plugin. + +**Trade-off de segurança:** a chave literal vira a única exceção ao padrão `.env`+`${VAR}`. Mitigar: `openclaw.json` (e seus backups) não devem ser commitados; na rotação da credencial, atualizar o `openclaw.json` ALÉM do `.env`. + +## Lições + +1. **Pós `openclaw update`: SEMPRE `systemctl restart openclaw-gateway` (cold).** Restart in-process não re-registra o harness. Reincidência do tema de 2026-05-22, agora com a mecânica (`restart-sentinel`) isolada. +2. **Latência de chat: diagnosticar por `rawLines`, não por tamanho de prompt.** Enxugar overhead é ganho marginal; os turns longos são trabalho real. +3. **Secrets em config de PLUGIN não aceitam `${VAR}`** — só literal ou o sistema SecretRef formal. O `${VAR}`→`.env` funciona em todo o config core, só não dentro de `plugins.entries.*.config`.