activeloopai / activeloopai/hivemind

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

Abierto
#84 0 comentarios 0 reacciones 0 asignados Ver en GitHub
Lenguaje dominante
TypeScript
Estrellas
1.6k
Forks
107
Merge medio
17 h 30 min
PR fusionados (30 d)
6

Descripción

## 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.

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.