activeloopai / activeloopai/hivemind

Silent capture loss when target workspace/table is unreachable or has a stale schema

Aberta
#84 0 comentários 0 reações 0 responsáveis Ver no GitHub
Linguagem predominante
TypeScript
Estrelas
1.6k
Forks
107
Merge médio
17h 30min
PRs com merge (30d)
6

Descrição

## Problem

When the workspace selected by `~/.deeplake/credentials.json` (or `HIVEMIND_WORKSPACE_ID`) routes the capture INSERT to a `sessions` table that the hook cannot write to — wrong workspace, missing column, revoked permission, body-size cap — **the capture is dropped silently**. The host agent (Claude Code, Codex, Cursor, Hermes) gets no signal, the user sees no warning, and every tool call/prompt/response in that session is lost from memory.

## How we hit it today

While testing Phase 1 embedding work I switched the active org to `test_plugin/default`. That workspace has a legacy `sessions` table with a schema that predates the `agent` column. Every PostToolUse INSERT then failed with one of:

- `403 Forbidden` (write blocked by ACL on a foreign workspace)
- `Column does not exist: column "agent" does not exist` (legacy schema)

The hook caught the error, ran `await api.ensureSessionsTable(sessionsTable)` (a no-op `CREATE TABLE IF NOT EXISTS` because the table already exists at the old schema), retried the INSERT, failed again, then `throw e` → caught by the outer `main().catch(...)` → `process.exit(0)`. From the host's POV the hook returned cleanly. From the DB's POV no row landed. Side-effect: the host's tool-call wrapper saw a non-zero status from somewhere in the hook chain and started returning exit code 144 on every Bash call until the org was switched back — confusing and unrelated-looking.

## Evidence

- 0 captured rows in the destination table during the broken window
- `~/.deeplake/hook-debug.log` (only available when `HIVEMIND_DEBUG=1` is set) shows the real error:

```
2026-05-01T06:34:49.802Z [sdk] query fail (3950ms): INSERT INTO "sessions_ide_test" ... :: Query failed: 403: 403 Forbidden...
2026-05-01T06:34:49.802Z [cursor-capture] fatal: Query failed: 403: ...
```

- Without `HIVEMIND_DEBUG=1` the user gets nothing — no stderr line, no status banner, no surfaced count of dropped rows.

## Why it's bad

Hivemind's whole value prop is \"never lose a session.\" A misconfigured workspace today degrades us to silently-zero capture. Users only notice when they ask their agent to `grep ~/.deeplake/memory/` weeks later and find nothing.

## Repro

1. Have an org/workspace with a legacy `sessions` table missing the current schema (e.g. no `agent` column), or where the API token lacks INSERT permission.
2. Point `~/.deeplake/credentials.json` (or `HIVEMIND_*` env) at it.
3. Run any Claude Code / Codex / Cursor / Hermes tool call.
4. Inspect destination table → no row. Inspect hook stderr / agent transcript → no warning. The only signal is `~/.deeplake/hook-debug.log` if `HIVEMIND_DEBUG=1` happens to be set.

## Proposed mitigations (non-binding, pick one or several)

1. **Surface the first capture failure to the host.** Once per session, write one short stderr line from the hook (`hivemind: capture INSERT failed (403 Forbidden) — see ~/.deeplake/hook-debug.log`). Claude Code and Codex pipe hook stderr into the transcript by default, so this becomes visible without breaking the \"don't block the agent\" contract.
2. **Persist a per-session failure counter** to a small file under `~/.deeplake/` and emit a warning at SessionEnd if any captures were dropped (`hivemind: 27 captures lost this session due to repeated 403 — check workspace/credentials`).
3. **Schema preflight at SessionStart**, similar to the existing `ensureEmbeddingColumn`: if the `sessions` table exists but is missing required columns, log a hard warning to stderr and abort capture for the session (better dead-loud than dead-silent).
4. **`hivemind status` should include a \"recent capture errors\" line** sourced from the debug log so users can see drift without setting `HIVEMIND_DEBUG=1` first.

## Notes

- The error-classifier substring check (`includes(\"permission denied\") || includes(\"does not exist\")`) is what triggers the no-op retry on schema-mismatch errors. Worth tightening so a column-not-exist error doesn't get mistaken for a table-not-exist error.
- The 144 exit-code side-effect on the host's Bash wrapper deserves its own follow-up — investigate whether a hook subprocess error is leaking back through Claude Code's tool-call stack.

Guia de contribuição

Nenhum guia de contribuição indexado para este repositório

Avaliação

Esta issue ainda não foi avaliada.

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.