12 Commits

Author SHA1 Message Date
Nicolò Boschi bd853be356 fix(vector-index): repair per-bank index coverage after restore/upgrade (#2645) (#2872)
Per-(bank, fact_type) partial vector indexes are created only at fresh-bank
creation. A bank populated outside that path (logical restore, cross-version
upgrade, extension switch) never gets them, so its recall silently falls back
to the global index + post-filter — slower and under-returning (~0.63-0.72
recall@10 measured by the reporter).

Two fixes:

- import-bank: create the per-bank indexes explicitly after restoring the
  banks row. The prior get_or_create_bank_profile call was a no-op here (the
  row already exists, so it takes the SELECT branch), leaving every restored
  bank uncovered.

- hindsight-admin repair-bank (--bank ID | --all): re-runnable operator escape
  hatch for the out-of-app routes (raw pg_dump restore, extension switch) that
  a one-time migration can't cover (a restore carries alembic_version at head,
  so the migration is already stamped). Detects missing OR invalid coverage
  (INVALID leftovers / drifted access method count as missing, unlike a
  name-only check) and rebuilds with CREATE INDEX CONCURRENTLY off any txn.
  Idempotent; concurrency handled by idempotency, not advisory locks.

Deliberately excludes the boot/periodic background reconcile and retain-path
self-heal: a bank restored and only ever read stays degraded until an operator
runs repair-bank. That background layer can be a follow-up.
2026-07-21 16:05:40 +02:00
Evo f183b09b93 docs(admin-cli): document run-db-migration --skip-extension-reconcile and --embedding-dimension (#2327)
The run-db-migration Options table listed only `--schema`, but the command
also exposes two operator-facing flags (hindsight_api/admin/cli.py):

- `--embedding-dimension` — enforce an expected embedding dimension after
  migrations (omit to skip the dimension sync).
- `--skip-extension-reconcile` — added in #2309; skip the post-migration
  vector/text-search index reconcile to speed up no-change re-migrations across
  many tenant schemas when the backend is unchanged.

Add both rows to the canonical Options table and regenerate the docs skill
mirror.
2026-06-23 10:00:54 +02:00
Evo d3eff9fba2 docs(admin-cli): document full backup table coverage from #1903 (#1929)
#1903 expanded BACKUP_TABLES to all 15 tables (the 7 previously-missing ones that could be silently dropped on restore), but the "backup includes" list still reflected the old ~8-table coverage. Update it to match: mental models, directives, webhooks, file storage, plus internal operational tables for a faithful full-database snapshot. Oracle-only observation_sources stays excluded (PostgreSQL-only backup). Regenerated skills/hindsight-docs mirror.
2026-06-05 11:23:39 +02:00
Evo 72985b6153 docs(admin-cli): document decommission-worker --yes/-y confirmation-skip flag (#1957) 2026-06-05 10:53:32 +02:00
Nicolò Boschi 602c9f55e2 feat(transfer): whole-bank export/import for cross-instance migration (#1884) (#1953)
* feat(transfer): admin export-bank command (whole-bank portable archive)

Add 'hindsight admin export-bank --bank <id> [--schema] [--include-history]'
that exports an entire bank to a portable ZIP for migrating it to a new
instance configured with a different embedding model / vector / text-search
backend. No embeddings are written — they are regenerated on import.

The archive is a superset of the documents archive:
  * logical document/fact/observation export (replayed + re-embedded on import);
  * bank config, mental models (vector stripped → re-embed), directives, webhooks
    carried as JSON rows;
  * audit_log / llm_requests only with --include-history.

Every bank-scoped table (BACKUP_TABLES) is classified logical / carried /
history / skipped; test_export_bank_covers_schema fails if a future migration
adds a table without classifying it. Import of the new sections is a follow-up.

Tests: schema-coverage guard + a contents test (archive_type, carried bank
config + webhook, no embeddings, history gated by the flag).

* feat(transfer): import-bank — restore a whole-bank archive (cross-instance migration)

Add the import half of bank migration:
  * transfer.import_bank: restores bank config, then docs/facts/observations
    (re-embedded with the TARGET instance's model via import_documents), then
    mental models, directives, webhooks as verbatim rows. Restores exact state —
    fires no webhooks and triggers no consolidation (observations/mental models
    are restored, not regenerated). _restore_rows coerces JSON values back to
    column types (timestamps/uuids/jsonb) and is idempotent (ON CONFLICT DO NOTHING).
  * MemoryEngine.import_bank_async / export_bank_async wrappers.
  * admin 'import-bank' command (boots a MemoryEngine for the target model);
    plus engine-backed export.

Tests: exact round-trip (export -> delete -> import) asserts every section —
bank config, documents, facts, observations, entities, temporal links, webhooks,
directives, mental models — matches exactly, with facts re-embedded (no NULL
vectors). Semantic links compared loosely (ANN index regenerated). Also a guard
that import-bank rejects a documents-only archive.

* docs(transfer): bank migration runbook (export-bank / import-bank)

Document the admin export-bank/import-bank commands and the blue-green runbook
for moving a bank to a new instance with a different embedding model / vector /
text-search backend, re-embedding on import without LLM re-extraction.

* refactor(transfer): drop unused export_bank_async engine method

Code-review: the engine wrapper had no caller but the test — the export-bank CLI
reads rows directly via transfer.export_bank (no engine/embeddings boot needed
for a read-only export). Call transfer.export_bank directly in the test instead.

* docs(transfer): document export-bank/import-bank + migration playbook on the Admin CLI page

Use the installed 'hindsight-admin <cmd>' convention (not 'uv run'). Add the full
export-bank/import-bank command reference and blue-green migration runbook to the
Admin CLI page; reduce the memory-banks section to a short summary that links there.

* refactor(transfer): _admin_connect helper + clearer _REPLAYED_TABLES naming

- Extract _admin_connect(db_url); resolve_database_url already handles pg0:// vs
  postgres://, so export-bank no longer re-implements the connect dance inline.
- Rename _LOGICAL_TABLES -> _REPLAYED_TABLES + clarify: entities/unit_entities/
  memory_links/entity_cooccurrences are NOT exported (rebuilt by the import
  pipeline); the bucket only exists for the coverage guard.

* fix(transfer): import-bank requires a non-existent target bank (no merge)

Importing into an existing bank silently merged: bank config kept (ON CONFLICT
DO NOTHING), docs per on_conflict, and mental_models/directives/webhooks added
alongside existing rows. import-bank restores a WHOLE bank, so refuse when the
target already exists — delete it or pass a fresh --target-bank.

Since a fresh target has no document conflicts, drop the now-meaningless
on_conflict knob from import_bank / import_bank_async / the import-bank CLI.

Test: importing an archive whose bank still exists raises.

* test(transfer): add manual two-instance bank-migration e2e script

scripts/dev/e2e-bank-migration.sh spins instance A (bge-small/384) and B
(bge-base/768), retains into A, runs export-bank -> import-bank, and asserts
recall on B returns the migrated fact ranked first with both instances on
different embedding dims. Self-asserting (exits non-zero on failure); not run in
CI (needs two cached models + an LLM key). Verified passing locally.

* test(transfer): drop manual e2e-bank-migration.sh script

Remove the two-instance migration e2e script from the repo (kept as a local-only
dev tool). Engine-level integration tests in test_document_transfer.py cover the
export/import round-trip.

* docs(admin-cli): add 'Running the CLI' intro (how to run, what it points to)

Explain that hindsight-admin connects directly to PostgreSQL (not the HTTP API),
uses the same config/.env as the API (HINDSIGHT_API_DATABASE_URL), is PostgreSQL-only,
and is typically run inside the API host/container (docker exec / kubectl exec).
2026-06-04 11:26:48 +02:00
Nicolò Boschi 312bde1b4d docs: surface stable worker_id guidance and zombie-operation recovery (#1522)
* docs: surface stable worker_id guidance and zombie-operation recovery

Worker identity defaults to the container hostname, which Docker rotates
on every restart. That stranded several real deployments' consolidation
queues (issue #1470 and the related closed tickets #991 / #696 / #624).
Move the guidance from the configuration reference table — where it
only gets read after the bug bites — into the install path and add a
recovery section next to the decommission commands.

* docs(faq): add zombie-operations entry
2026-05-07 18:31:22 +02:00
r266-tech b79caa9aa8 docs(admin-cli): document decommission-workers and worker-status (#1180)
* docs(admin-cli): document decommission-workers and worker-status

PR #1165 added two new admin CLI commands (decommission-workers,
worker-status) but admin-cli.md was not updated. Readers scanning the
Commands section could only find the singular decommission-worker.

Added dedicated sections for each new command following the existing
style (Arguments/Options/Examples/When to Use). Pure docs, mirrors
behavior documented in typer command help strings.

* docs(admin-cli skill): sync decommission-workers and worker-status

Mirror change from hindsight-docs/docs/developer/admin-cli.md so the
docs skill reference stays in sync (matches the pattern set by #1137).
2026-04-21 10:30:09 +02:00
Chris Bartholomew 9a694f64b8 Fix run-db-migration for all-tenant upgrades (#530)
* Add release-scoped migration admin command

* Fix run-db-migration for all-tenant upgrades
2026-03-10 10:10:03 +01:00
Nicolò Boschi 5b52a84fff chore: internal renames (#204)
This commit renames the terminology across the entire codebase:
- "mental models" (fact_type='mental_model' in memory_units) → "observations"
- "reflections" table (stored reflect responses) → "mental_models"

Changes include:
- Database migration to rename tables, indexes, and constraints
- API endpoints: /reflections → /mental-models, /mental-models → /observations
- Config: ENABLE_MENTAL_MODELS → ENABLE_OBSERVATIONS
- Response models and Pydantic classes
- Reflect agent tools and prompts
- Control plane UI and routes
- Documentation and examples
- Regenerated OpenAPI spec and client SDKs (Python, TypeScript)
- Rust CLI: reflection commands → mental-model commands
- LiteLLM: updated fact_types documentation
2026-01-27 09:53:28 +01:00
Nicolò Boschi 522b71aab8 doc: mental models (#199)
* doc: mental models

* doc: mental models
2026-01-26 14:27:08 +01:00
Nicolò Boschi 4c792400c1 feat: new 'worker' service (#176)
* feat: new 'worker' service

* doc

* docs

* tests
2026-01-20 10:17:56 +01:00
Nicolò Boschi 233bd2e5d4 feat: run db migrations offline (optionally) (#114)
* feat: run db migrations offline (optionally)

* fix
2026-01-07 15:49:51 +01:00