Skip to main content

Knowledge Graph health & migration

The KG consolidation pipeline is a queue-driven background worker. When it gets stuck — embedder timeouts, schema drift, slow disk — the agent stops being able to write decisions to the graph. Five MCP admin tools surface the pipeline’s state and let an operator unblock it without touching the database file: Permissions are dotted-string flags in the granular registry. kg_health and kg_dead_letter_list are read-only and ride on the standard kg.query.* / kg.admin.settings_read flags most presets ship with. The two that mutate state — kg_dead_letter_reprocess and kg_migrate_schema (and the historical-consolidation CLI path) — are gated by kg.admin.historical_consolidation and the broader kg.admin.* namespace. Operator presets layer these in deliberately. Source: okto-pulse-core/src/okto_pulse/core/mcp/server.py:12484–12857 and core/infra/permissions.py:PERMISSION_REGISTRY under the kg.admin key. Citations: 80-pulse-feature-inventory.md:493–501. For consolidation flow itself, see consolidation. For the schema, see overview.

okto_pulse_kg_health

The board’s pipeline health summary. The Pulse dashboard polls this every 30 seconds.
The MCP tool returns a 12-field aggregate computed in-process (cheap to poll). Implemented in okto-pulse-core/src/okto_pulse/core/services/kg_health_service.py:get_kg_health. Real shape:
Field meanings (per docstring at server.py:12484 and the service implementation): CLI equivalent — note that the CLI uses a different layered check set rather than this 12-field aggregate:
cli.py:683–744 (cmd_verify_pipeline) runs 5 layered checks: queue depth, graph file presence + node count, graph-vs-SQLite ref mirror, outbox staleness, global discovery file. Exit code 0 if healthy, 1 if any layer fails. Use the CLI for monitoring scripts; use kg_health from agents.

okto_pulse_kg_dead_letter_list

Consolidation entries that exceeded kg_queue_max_attempts (default 5) land in the dead-letter table. Pulse never auto-reprocesses them — an operator must inspect and replay.

okto_pulse_kg_dead_letter_reprocess

Move dead-letter entries back to the active queue for another attempt. Use after the underlying cause is resolved (embedder up, disk space available, schema migrated).
The reprocess increments the attempts counter back to 0 for each requeued entry. If the same root cause persists, entries will land back in dead-letter after another kg_queue_max_attempts failures.

okto_pulse_kg_migrate_schema

Run schema migrations on a board’s graph.lbug. Use after upgrading okto-pulse-core to a version with a higher schema version than the file on disk.
Migrations are idempotent: a board already at target_version returns migrations_applied: [] and ok: true.
Always take a copy of ~/.okto-pulse/boards/{board_id}/graph.lbug before running a migration with dry_run: false. Migrations rewrite the file in place. The okto-pulse kg backfill --apply flow is a safer rebuild path when a migration corrupts data.

okto_pulse_kg_tick_run_now

Trigger the decay tick worker immediately instead of waiting for the schedule (default daily, kg_decay_tick_interval_minutes = 1440). The tick recomputes relevance_score for nodes whose last_recomputed_at is older than kg_decay_tick_staleness_days (default 7).
The decay formula is documented in kg/workers/kg_decay_tick.py. Note that find_similar_decisions uses a separate search reranking formula at retrieval time — do not conflate the two (80-pulse-feature-inventory.md:957).

Hot-reloadable settings

You don’t need to restart Pulse to change pipeline tuning: Source: 80-pulse-feature-inventory.md:790. The full settings table lives in Knowledge Graph and the inventory.

CLI fallbacks

The MCP tools are the primary surface, but three CLI commands cover deeper recovery scenarios:

okto-pulse verify-pipeline <board_id>

cli.py:683–744. Wraps the same 5 checks as kg_health but exits 1 on failure — useful in CI / monitoring scripts.

okto-pulse kg backfill <board_id>

cli.py:747–902. Runs the Layer 1 deterministic KG worker against every artifact on the board.
This is the recovery path when the graph is structurally out of sync (e.g., after a partial migration or a manual file restore). It rebuilds the deterministic skeleton; it does not replay cognitive-agent decisions.

okto-pulse kg dedup-entities <board_id>

cli.py:908–936. Consolidate duplicate nodes per (node_type, source_artifact_ref).
kg dedup-entities writes by default. Always run with --dry-run first.

Underlying REST endpoints

The MCP tools wrap REST endpoints exposed by the API server. They are documented here for completeness — most callers should prefer the MCP tools. Source: 80-pulse-feature-inventory.md:729–735.

Common operational scenarios

”Consolidations stopped landing”

  1. Call kg_health — check queue_depth, oldest_pending_age_s, and dead_letter_count.
  2. If dead_letter_count > 0, call kg_dead_letter_list to see error reasons.
  3. Fix the root cause (embedder, disk, schema mismatch).
  4. Call kg_dead_letter_reprocess with the entry ids.
  5. Re-call kg_health. Expect dead_letter_count: 0 and queue_depth draining.

”Just upgraded Pulse, dashboard shows schema drift”

  1. Inspect the graph schema with kg_schema_info or run the migration tool when a schema error points to drift.
  2. Take a backup of graph.lbug.
  3. Call kg_migrate_schema with default target_version (= runtime version).
  4. Re-check the graph schema. Expect it to match the runtime schema.

”Relevance scores look stale”

  1. Call kg_tick_run_now. Expect nodes_recomputed > 0.
  2. If always 0 nodes recomputed, increase kg_decay_tick_staleness_days lower bound or check that nodes are being touched at all.

”Need to rebuild the deterministic skeleton from scratch”

  1. CLI only: okto-pulse kg backfill <board_id> (dry-run) — review.
  2. okto-pulse kg backfill <board_id> --apply.
  3. Call kg_health — confirm graph_node_refs is balanced.

Next steps

Consolidation

The 7 transactional write primitives the queue is feeding.

Archive & retention

Cascading entity archive, supersedence as soft-archive, and KG retention policy.
Last modified on May 9, 2026