Lineage and execution-graph commands

Part of the NovaFabric CLI reference. Both nova and novafabric run the same binary.

Lineage commands (v0.4)

nova lineage provenance

nova lineage provenance <ref> [--depth N] [--kind run|asset|artifact] [--edge-type TYPES] [--with-facets] [--output text|json]

Show what the given node depends on (forward traversal).

Options:

nova lineage provenance my-agent --edge-type spawned,delegated_to
nova lineage provenance 01HX... --with-facets

nova lineage blast-radius

nova lineage blast-radius <ref> [--depth N] [--kind run|asset|artifact] [--edge-type TYPES] [--output text|json]

Show what depends on the given node (backward traversal).

Options:

nova lineage blast-radius my-model --edge-type contains,replayed_from

nova lineage replay-chain

nova lineage replay-chain <run-id> [--output text|json]

Show the replay chain back to the original captured run.

nova lineage time-travel

nova lineage time-travel <ref> --asof <iso8601> [--kind run|asset|artifact] [--output text|json]

Show the lineage state of a node as of a given timestamp.

nova lineage import

nova lineage import <path>

(Re-)index lineage from a capsule directory or a parent runs/ directory.

nova lineage metrics

Experimental (ADR-0212).

nova lineage metrics [--top N] [--output text|json]

Rank structurally critical nodes over the whole local lineage graph: degree, PageRank (bounded power iteration), betweenness (seeded sampling above 2 000 nodes — the output says when it sampled), and articulation points ("single points of failure"). Scores are descriptive rankings for attention, not calibrated importance. Oversize graphs fail loudly at the whole-graph read bound instead of silently truncating.

nova lineage root-cause

Experimental (ADR-0213).

nova lineage root-cause <run-id> [--depth N] [--capsule-dir DIR] [--output text|json]

Walk the failed run's upstream provenance and rank suspect nodes with bounded additive signals: error evidence (cues shared with ADR-0084), recency decay, an edge-confidence multiplier, and failure correlation across sibling failed runs. With --capsule-dir, the responsible run is additionally step-attributed via the nova diagnose engine. No error signal upstream → responsible: null; the command never fabricates a culprit.

nova lineage export-graph

Experimental (ADR-0214).

nova lineage export-graph [--format graphml|gexf|cypher] [-o FILE] [--ref R [--kind K] [--depth N]]

Byte-stable export of the lineage graph (whole graph, or one node's provenance + blast-radius neighbourhood via --ref) for enterprise graph tooling: GraphML/GEXF for Gephi/yEd, idempotent Cypher MERGE statements for Neo4j. Topology and attributes only — seal/signature material never travels with this export; nested edge facets are carried as a facets_json string attribute.

nova insights

Experimental (ADR-0215).

nova insights [--top N] [--output table|json|markdown] [-o FILE] [--cost-db PATH]

One synthesized report over the captured lineage graph: top hubs and articulation points (ADR-0212), seeded Louvain communities, orphan nodes, health ratios (largest-component fraction, orphan ratio), and best-effort cost hotspots (lineage node payloads, or a --cost-db evidence-fabric DuckDB aggregate). Unavailable data sources are reported as unavailable, never fabricated. --output markdown -o FILE produces a shareable weekly artifact.

nova lineage emit-openlineage

nova lineage emit-openlineage <path> [--output TARGET] [--with-facets] [--otel-correlation]

Emit capsule runs as OpenLineage 2.0.2 events.

If --output is omitted, the target is resolved from OPENLINEAGE_URL → OPENLINEAGE_FILE → stdout.

# Stdout
nova lineage emit-openlineage .novafabric/runs/01HX.../  --output -

# HTTP endpoint (Marquez, Atlan, etc.)
nova lineage emit-openlineage .novafabric/runs/ --output http://marquez:5000

# With NovaFabric custom facets + OTel correlation
nova lineage emit-openlineage .novafabric/runs/01HX.../ --with-facets --otel-correlation

# Environment variable
OPENLINEAGE_URL=http://marquez:5000 nova lineage emit-openlineage .novafabric/runs/

Dashboard equivalent: Lineage tab → Export OpenLineage Events panel (returns JSON preview + copy button).


nova lineage consume (experimental, cluster-scale)

nova lineage consume [--nats-url URL] [--kuzu-path DIR] [--subject SUBJECT]
                      [--batch-size N] [--fetch-timeout S]
                      [--flush-batch-size N] [--flush-interval-s S]

Runs the LineageConsumer NATS JetStream pull consumer (cap-006) in the foreground: pulls capsule events, derives lineage edges, and bulk-COPYs them into KuzuDB on a size-or-time flush trigger. Runs until interrupted (Ctrl-C). This is the cluster-scale deployment path — local-mode capture never requires this command; lineage is written directly by the local SqliteLineageStore.

Requires the scale extra (nats-py) and the scale-kg extra (kuzu): pip install 'novafabric[scale,scale-kg]'.

nova lineage consume
nova lineage consume --nats-url nats://hub.example.com:4222 \
  --kuzu-path /var/lib/novafabric/lineage.kuzu
nova lineage consume --flush-batch-size 5000 --flush-interval-s 30

Not exactly-once: a NATS message is acked immediately once its edges are extracted, before the size-or-time flush actually persists them to KuzuDB. If a flush fails, the buffered edges for that flush are dropped and logged, not redelivered — lineage is derived, non-authoritative data, not the evidence chain, so this tradeoff favors simplicity over exact-once delivery guarantees.

Producer taxonomy gap — resolved 2026-07-30 (ADR-0220): the real event producer is capture/orchestrator.py (forwarded verbatim by the Go novafabric-spool-forwarder, which never inspects event_type itself — the earlier framing of this as a Go-vs-Python taxonomy problem was itself found to be wrong during the fix). It now emits the canonical RunStarted/RunCompleted/RunFailed event types with parent_run_id populated, so this command correctly derives SPAWNED_BY edges from real captured runs — verified end-to-end by tests/scale_architecture/test_lineage_consumer.py::TestRealProducerEndToEnd. Remaining gap: ArtifactProduced/ArtifactConsumed edges still require a producer that emits those event types, which none currently does — only run-boundary lineage is available from the NATS path today.


Agent execution graph (experimental, ADR-0124)

nova graph agent (experimental, ADR-0124)

nova graph agent <capsule-dir> [--format json|dot|mermaid] [-o FILE] [--digest] [--stats]

Reconstruct one run's execution DAG — which model call invoked which tools, how calls nested under OTel spans, and the observed sibling order — from records the capsule already holds (model-calls.jsonl + tool-calls.jsonl + trace.jsonl). A projection, not a capture: read-only, offline, works on any capsule ever captured (including v0.2), adds no capsule field. Distinct from nova lineage (cross-run causation) and nova kg (fleet security graph); spec: agent-execution-graph-v0 (schemas/agent-execution-graph.schema.json).

The output is content-addressed: nodes and edges are canonically sorted and hashed into a graph_digest, so the same capsule always yields byte-identical JSON — comparing two digests is a cheap "did the control-flow shape change" check. Three deterministic edge types only (span_parent, agent_invokes_tool, follows); nothing is inferred beyond what the spans encode. Calls with no recoverable parentage attach to a synthetic root node with an explicit reconstruction_note (missing_parent, orphan_tool_call, unlinked_span) — never a silent heuristic repair.

# Canonical JSON graph to stdout
nova graph agent .novafabric/capsules/<run_id>

# Only the content hash — for verify/diff pipelines
nova graph agent <capsule> --digest

# Shape summary: node/edge counts, max depth, max fan-out
nova graph agent <capsule> --stats

# Text exports for rendering elsewhere
nova graph agent <capsule> --format mermaid -o run-graph.mmd
nova graph agent <capsule> --format dot | dot -Tsvg > run-graph.svg

Exit codes: 0 success, 1 not a readable capsule directory, 2 bad flags. A partially malformed capsule still yields a best-effort graph plus notes.


Lineage store operations (Phase 6, E-3..E-5)

Commands for migrating lineage edges between backends and generating deployment profiles for cluster-scale lineage infrastructure.

Reference: src/novafabric/cli/lineage_migrate.py, design/adr/0053-lineage-at-scale.md (private).

nova lineage-store migrate

Migrate lineage edges from a Parquet file or an ObjectCapsuleStore to a SQLite store. Runs dry-run by default; pass --commit to actually persist.

nova lineage-store migrate [PARQUET] [--db PATH] [--commit|--dry-run]
    [--no-validate] [--from-ocs] [--ocs-tenant TEXT] [--ocs-run-ids TEXT]
    [--ocs-data-dir PATH]
Flag Default Description
PARQUET (optional) Source Parquet file (deprecated; use --from-ocs for the ADR-0022 canonical path)
--db lineage.db Target SQLite database path
--commit / --dry-run dry-run Commit to target store (default is dry run)
--no-validate off Skip post-load divergence check
--from-ocs off Migrate from ObjectCapsuleStore (ADR-0022 canonical path)
--ocs-tenant "" OCS tenant identifier (required with --from-ocs)
--ocs-run-ids "" Comma-separated run IDs to migrate (required with --from-ocs)
--ocs-data-dir . Local OCS data directory for the fallback adapter
# Parquet migration (deprecated)
nova lineage-store migrate edges.parquet --db lineage.db --commit

# OCS-backed migration (ADR-0022 canonical)
nova lineage-store migrate --from-ocs \
    --ocs-tenant acme \
    --ocs-run-ids run-001,run-002 \
    --db lineage.db --commit

Exit codes: 0 = success, 1 = argument error, 2 = divergence detected.

nova lineage-store profile

Print a docker-compose YAML deployment profile for the chosen lineage backend.

nova lineage-store profile [--target kuzudb-vertical|janusgraph-minimal]
    [--node-size TAG] [--rf N] [--image-tag TAG]
Flag Default Description
--target kuzudb-vertical Profile target: kuzudb-vertical or janusgraph-minimal
--node-size 16g-ram-500g-nvme Node size tag for kuzudb-vertical profiles
--rf 3 Cassandra replication factor (for janusgraph-minimal)
--image-tag (unset) Deprecated. For kuzudb-vertical, sets the single nova-lineage image tag (falls back to latest if unset). For janusgraph-minimal, overrides all three images (janusgraph/cassandra/novafabric) to the same tag — prefer leaving it unset so each image uses its own independently-pinned default (JanusGraph 1.1.0, others latest)
# KuzuDB vertical profile (single-node, NVMe-optimised)
nova lineage-store profile --target kuzudb-vertical --node-size 32g-ram-1t-nvme

# JanusGraph minimal cluster profile (Cassandra RF=3)
nova lineage-store profile --target janusgraph-minimal --rf 3

Prints a complete docker-compose.yml to stdout. Pipe to a file or kubectl apply.


Metadata DB recovery (BQ-013)

nova rebuild-metadata-db

Rebuild the metadata database from the manifest chain log using checkpoint-based replay. Disaster-recovery path when the metadata DB is lost; completes in minutes regardless of chain length (AC-1, BQ-013).

nova rebuild-metadata-db [--prefix TEXT] [--target-db PATH]
    [--backend local|s3|minio|ceph_rgw|azure_blob] [--data-dir PATH]
Flag Default Env var Description
--prefix "" (all tenants) — Tenant or tenant/run_id prefix to scan
--target-db nova-metadata-rebuild.db — Path to the output SQLite database
--backend local NOVA_OCS_BACKEND Storage backend: local, s3, minio, ceph_rgw, azure_blob
--data-dir (optional) — Local backend: path to the object store root directory
# Rebuild from local storage (all tenants)
nova rebuild-metadata-db --target-db recovered.db

# Rebuild a single tenant from an S3 backend
NOVA_OCS_BACKEND=s3 nova rebuild-metadata-db \
    --prefix acme \
    --target-db acme-recovered.db

Prints per-step progress, total capsules found, elapsed time, and any integrity warnings. The output SQLite file is ready for use as a replacement metadata DB.

Reference: src/novafabric/cli/rebuild.py, src/novafabric/object_capsule_store/rebuild.py.