resolve_unit agora prioriza Captain::Assistant.captain_unit_id sobre o
mapping legado CaptainInbox (que falha quando 2 agentes — interno e
Hermes — compartilham a mesma inbox).
Caso real: Juliana Hermes (unit Qnn01) compartilhava inbox 1 com Juliana
captain_interno (unit Recanto), mas o CaptainInbox da inbox 1 estava
mapeado pra unit Dolce Amore (id=4) por contaminação anterior. Tool
resolvia unit errada, generate_pix retornava "categoria não reconhecida"
e o agente travava em "⏳ Um momento — vou verificar." sem retomar.
bin/hermes-validate ganha 3 checks novos:
- CaptainInbox.unit == Assistant.unit (FAIL — exatamente o bug acima)
- Pricing dry-run (calcula preço da 1ª categoria sem erro)
- Credenciais Inter completas (WARN se faltar cert/key — cai no fallback)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- bin/hermes-validate <slug>: 44 checks de saúde (DB, filesystem, systemd,
routing, MCP tools, humanização). Saída textual ou --json. Exit 0 sem FAIL.
- bin/hermes-provision: sed adicional substitui exemplos hardcoded de
categorias Dolce Amore (Mini Chalé 45 etc) pelas 3 primeiras categorias
da unidade nova; evita resíduo em descrições de tools.
- Fix bash: trocar `|| echo 0` por `|| true` em greps (evita "0\n0" quando
grep -c não acha e ainda imprime contagem).
Validado em juliana_qnn1: 43 PASS / 0 FAIL / 1 WARN (gallery seed pendente).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug: Juliana de Qnn01 oferecia categorias do Dolce Amore (Apartamento,
Mini Chalé 45, Suíte Ouro). Vazamento via:
1. Hermes daemon memory_enabled+user_profile_enabled — acumula contexto
entre turnos no mesmo profile.
2. Codex/ChatGPT memória user-level — todos os profiles compartilham o
mesmo OAuth (borbamachadoo@gmail.com), então ChatGPT lembra de
conversas com Valentina e bleeda no LLM da Juliana.
3. Tool descriptions com exemplos motel-flavored (já corrigido em commit
anterior).
Fix permanente no script hermes-provision:
- sed do config.yaml zera memory_enabled e user_profile_enabled
- append no SOUL.md adiciona "REGRA CRÍTICA — IGNORE OUTRAS UNIDADES"
com lista explícita de categorias válidas (extraída do spec.categories)
e instrução pro LLM ignorar memória de outras unidades.
Aplicado retroativamente em juliana_qnn1 + sessions/state.db limpos.
Próximos agentes do Construtor nascem com essa proteção por padrão.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug: find_or_initialize_by(name: ...) batia em captain_interno existente
com mesmo nome (ex: 'Juliana') e SOBRESCREVIA engine='hermes'. Resultado:
Juliana captain_interno virou Hermes, atendimento legado quebrou.
Fix: chave passa a ser (account_id, hermes_profile_name=slug). Auto-sufixa
nome com ' · Hermes' se colidir com captain_interno do mesmo nome (a não
ser que já tenha 'Hermes' no nome). Também grava captain_unit_id no
record (relação direta agora que existe a coluna).
Reverti manualmente Juliana id=1 + criei id=10 'Juliana · Hermes' fix in
DB. Future provisionamentos pelo Construtor usam o caminho corrigido.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bash script em bin/hermes-provision (instalado em /usr/local/bin/ na VPS)
que recebe spec JSON via stdin e provisiona um agente Hermes ponta-a-ponta:
- Valida spec (slug regex, preços 0-5000, períodos/buckets do catálogo)
- Aloca porta livre no range 8650-8699
- Gera HMAC secret via openssl rand
- Cria Captain::Unit (find_or_create), Captain::PricingCategory/Amount,
Captain::Assistant (engine=hermes) via docker exec rails runner
- Copia template profile da Valentina, patcheia config.yaml com porta +
X-Captain-Assistant-Id (parent_id se setado, senão self id)
- Escreve SOUL.md/SKILL.md do spec
- Gera webhook_subscriptions.json com secret
- Cria systemd unit hermes@<slug>.service e enable+start
- rsync profile pra repo de backup git local
- Idempotente: re-rodar com mesmo slug não duplica nada (find_or_create)
- --dry-run valida sem escrever
- --rollback <slug> destrói tudo (DB + systemd + filesystem)
Construtor (Hermes daemon) chama via terminal skill nativa:
echo '<spec>' | /usr/local/bin/hermes-provision
Próximo passo: atualizar SOUL.md/SKILL.md do Construtor pra invocar
o script ao final do fluxo socrático.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Added a command to sync files in the locale/*/ folder. Run `pnpm
sync:i18n` would copy index.js in `dashboard/locale/en` to every other
folder `dashboard/locale/*/`
---------
Co-authored-by: Pranav <pranavrajs@gmail.com>
By default, Rails does not set a timeout on database statements. For example, this will run for a full day, even if your ruby process goes away. But it's configurable in the database.yml with the statement_timeout variable.
Hence we are enforcing a 14s timeout by default. Migration commands inside chatwoot will run with a 10 minutes timeout. For specific cases like migrations, we can override this timeout using the environment variable POSTGRES_STATEMENT_TIMEOUT while starting a new rails console.
Test the timeouts from the rails console using.
```
ActiveRecord::Base.connection.execute("SELECT pg_sleep(15);")
```
ref: https://github.com/ankane/the-ultimate-guide-to-ruby-timeouts#postgresql
ref: https://til.hashrocket.com/posts/b44baf657d-railspg-statement-timeout-
- feature to store contact IP for accounts
- IP lookup through geocoder gem
- ability to do IP lookup through external APIs
- add commit hook to prevent push to develop and master
- migrations to fix default values for jsonb columns