# Lineage

Every registered lineage instance operation, with source-derived inputs, outputs, access policy, and errors.

Source: https://docs.minds.sh/docs/api/instance/lineage



This reference covers **5 HTTP operations** registered by the Akasha daemon. Call these paths on your instance base URL. See [authentication](/docs/api/instance/authentication), [errors](/docs/api/instance/errors), and [coverage](/docs/api/instance/coverage) before integrating.

| Method | Path                    | Operation                                    |
| ------ | ----------------------- | -------------------------------------------- |
| `POST` | `/v1/lineage/graph`     | [Lineage graph](#post-v1-lineage-graph)      |
| `GET`  | `/v1/lineage/nodes/:id` | [Lineage node get](#get-v1-lineage-nodes-id) |
| `POST` | `/v1/lineage/impact`    | [Lineage impact](#post-v1-lineage-impact)    |
| `POST` | `/v1/lineage/verify`    | [Lineage verify](#post-v1-lineage-verify)    |
| `GET`  | `/v1/lineage/stats`     | [Lineage stats](#get-v1-lineage-stats)       |

<a id="post-v1-lineage-graph" />

## POST `/v1/lineage/graph` [#post-v1lineagegraph]

Query the graph for a lineage subgraph starting from an optional root node. POST /v1/lineage/graph

| Availability         | Source contract                                                  |
| -------------------- | ---------------------------------------------------------------- |
| Registration         | `config.enable_graph`                                            |
| Runtime service      | No prefix-level service check; handler dependencies still apply. |
| Handler dependencies | See handler source and return expressions.                       |

**Access:** Daemon authentication and capability namespace authority; memory-domain permissions apply where mapped.

### Request [#request]

**Json** — `LineageGraphReq`

| Field     | Rust type        | Required on input         | Notes |
| --------- | ---------------- | ------------------------- | ----- |
| `root_id` | `Option<String>` | No; optional or defaulted |       |
| `depth`   | `Option<u32>`    | No; optional or defaulted |       |

```rust
struct LineageGraphReq {
    root_id: Option<String>,
    depth: Option<u32>,
}
```

**JSON field accesses in handler:** `id`, `label`, `lineage_type`, `relationship`, `source`, `target`. Nested lookups are included; this list alone does not establish requiredness.

### Response [#response]

**Declared return:** `Result<impl IntoResponse, DaemonError>`

The following are the exact JSON construction expressions in the handler. Values such as `rows`, `result`, and delegated types are runtime values, not literal example payloads.

```rust
serde_json::json!(resp)
```

### Errors and validation [#errors-and-validation]

Directly referenced error variants: `InvalidRequest`. Middleware and delegated services can return additional errors described in the shared error reference.

<Accordions>
  <Accordion title="Inspect implementation">
    This exact source excerpt includes validation, defaults, delegated calls, and response assembly.

    ```rust
    async fn lineage_graph(
        State(state): State<AppState>,
        Extension(db): Extension<Arc<akasha::AkashaDB>>,
        Json(req): Json<LineageGraphReq>,
    ) -> Result<impl IntoResponse, DaemonError> {
        state.record_http_request();

        let depth = req.depth.unwrap_or(3).min(10); // cap traversal depth

        let cypher = if let Some(ref root_id) = req.root_id {
            let safe_id = sanitize_cypher(root_id);
            format!(
                "MATCH p=(n {{id: '{}'}})-[*..{}]-(m) WHERE n.lineage_type IS NOT NULL RETURN p",
                safe_id, depth
            )
        } else {
            format!(
                "MATCH (n) WHERE n.lineage_type IS NOT NULL RETURN n LIMIT {}",
                depth * 20
            )
        };

        let rows = db
            .cypher(&cypher)
            .await
            .map_err(|e| DaemonError::InvalidRequest(e.to_string()))?;

        // Transform raw graph rows into typed nodes and edges.
        // Each row is a Map<String, Value> returned by the cypher engine.
        let mut nodes: Vec<serde_json::Value> = Vec::new();
        let mut edges: Vec<serde_json::Value> = Vec::new();
        let mut seen_node_ids = std::collections::HashSet::new();

        for row in &rows {
            // Nodes may come back with an "id" field at the top level
            if let Some(id_val) = row.get("id") {
                let id_str = id_val.as_str().unwrap_or_default().to_string();
                if seen_node_ids.insert(id_str.clone()) {
                    nodes.push(serde_json::json!({
                        "id": id_str,
                        "lineage_type": row.get("lineage_type").cloned()
                            .unwrap_or(serde_json::Value::String("unknown".into())),
                        "label": row.get("label").cloned()
                            .unwrap_or(serde_json::Value::String("".into())),
                        "properties": serde_json::Value::Object(row.clone()),
                    }));
                }
            }

            // Edges: look for source/target pairs in the row data
            if let (Some(src), Some(tgt)) = (row.get("source"), row.get("target")) {
                edges.push(serde_json::json!({
                    "source": src,
                    "target": tgt,
                    "relationship": row.get("relationship").cloned()
                        .unwrap_or(serde_json::Value::String("related_to".into())),
                }));
            }
        }

        let resp = LineageGraphResponse {
            nodes,
            edges,
            depth,
        };

        Ok(Json(serde_json::json!(resp)))
    }
    ```
  </Accordion>
</Accordions>

Source: `akasha-daemon/src/lineage.rs:100`. Registration: `akasha-daemon/src/lineage.rs:367`.

<a id="get-v1-lineage-nodes-id" />

## GET `/v1/lineage/nodes/:id` [#get-v1lineagenodesid]

Get a single lineage node by its ID. GET /v1/lineage/nodes/:id

| Availability         | Source contract                                                  |
| -------------------- | ---------------------------------------------------------------- |
| Registration         | `config.enable_graph`                                            |
| Runtime service      | No prefix-level service check; handler dependencies still apply. |
| Handler dependencies | See handler source and return expressions.                       |

**Access:** Daemon authentication and capability namespace authority; memory-domain permissions apply where mapped.

### Request [#request-1]

**Path** — `String`

```json
{
  "type": "string"
}
```

**JSON field accesses in handler:** `id`, `label`, `lineage_type`. Nested lookups are included; this list alone does not establish requiredness.

### Response [#response-1]

**Declared return:** `Result<impl IntoResponse, DaemonError>`

The following are the exact JSON construction expressions in the handler. Values such as `rows`, `result`, and delegated types are runtime values, not literal example payloads.

```rust
serde_json::json!({"node": node})
```

### Errors and validation [#errors-and-validation-1]

Directly referenced error variants: `InvalidRequest`. Middleware and delegated services can return additional errors described in the shared error reference.

<Accordions>
  <Accordion title="Inspect implementation">
    This exact source excerpt includes validation, defaults, delegated calls, and response assembly.

    ```rust
    async fn lineage_node_get(
        Path(id): Path<String>,
        State(state): State<AppState>,
        Extension(db): Extension<Arc<akasha::AkashaDB>>,
    ) -> Result<impl IntoResponse, DaemonError> {
        state.record_http_request();

        let safe_id = sanitize_cypher(&id);
        let cypher = format!(
            "MATCH (n {{id: '{}'}}) WHERE n.lineage_type IS NOT NULL RETURN n LIMIT 1",
            safe_id
        );

        let rows = db
            .cypher(&cypher)
            .await
            .map_err(|e| DaemonError::InvalidRequest(e.to_string()))?;

        if rows.is_empty() {
            return Err(DaemonError::InvalidRequest(format!(
                "lineage node '{}' not found",
                id
            )));
        }

        let row = &rows[0];
        let node = LineageNodeResponse {
            id: row
                .get("id")
                .and_then(|v| v.as_str())
                .unwrap_or_default()
                .to_string(),
            lineage_type: row
                .get("lineage_type")
                .and_then(|v| v.as_str())
                .unwrap_or("unknown")
                .to_string(),
            label: row
                .get("label")
                .and_then(|v| v.as_str())
                .unwrap_or("")
                .to_string(),
            properties: serde_json::Value::Object(row.clone()),
        };

        Ok(Json(serde_json::json!({"node": node})))
    }
    ```
  </Accordion>
</Accordions>

Source: `akasha-daemon/src/lineage.rs:172`. Registration: `akasha-daemon/src/lineage.rs:368`.

<a id="post-v1-lineage-impact" />

## POST `/v1/lineage/impact` [#post-v1lineageimpact]

Count downstream nodes affected by a given lineage node via graph traversal. POST /v1/lineage/impact

| Availability         | Source contract                                                  |
| -------------------- | ---------------------------------------------------------------- |
| Registration         | `config.enable_graph`                                            |
| Runtime service      | No prefix-level service check; handler dependencies still apply. |
| Handler dependencies | See handler source and return expressions.                       |

**Access:** Daemon authentication and capability namespace authority; memory-domain permissions apply where mapped.

### Request [#request-2]

**Json** — `LineageImpactReq`

| Field     | Rust type | Required on input | Notes |
| --------- | --------- | ----------------- | ----- |
| `node_id` | `String`  | Yes               |       |

```rust
struct LineageImpactReq {
    node_id: String,
}
```

**JSON field accesses in handler:** `id`. Nested lookups are included; this list alone does not establish requiredness.

### Response [#response-2]

**Declared return:** `Result<impl IntoResponse, DaemonError>`

The following are the exact JSON construction expressions in the handler. Values such as `rows`, `result`, and delegated types are runtime values, not literal example payloads.

```rust
serde_json::json!(resp)
```

### Errors and validation [#errors-and-validation-2]

Directly referenced error variants: `InvalidRequest`. Middleware and delegated services can return additional errors described in the shared error reference.

<Accordions>
  <Accordion title="Inspect implementation">
    This exact source excerpt includes validation, defaults, delegated calls, and response assembly.

    ```rust
    async fn lineage_impact(
        State(state): State<AppState>,
        Extension(db): Extension<Arc<akasha::AkashaDB>>,
        Json(req): Json<LineageImpactReq>,
    ) -> Result<impl IntoResponse, DaemonError> {
        state.record_http_request();

        let safe_id = sanitize_cypher(&req.node_id);
        // Traverse outgoing "derived_from" edges up to 10 hops to find downstream dependants.
        let cypher = format!(
            "MATCH (n {{id: '{}'}})-[*..10]->(m) WHERE n.lineage_type IS NOT NULL RETURN m",
            safe_id
        );

        let rows = db
            .cypher(&cypher)
            .await
            .map_err(|e| DaemonError::InvalidRequest(e.to_string()))?;

        let mut downstream_ids: Vec<String> = Vec::new();
        let mut seen = std::collections::HashSet::new();
        for row in &rows {
            if let Some(mid) = row.get("id").and_then(|v| v.as_str())
                && seen.insert(mid.to_string())
            {
                downstream_ids.push(mid.to_string());
            }
        }

        let resp = LineageImpactResponse {
            node_id: req.node_id,
            downstream_count: downstream_ids.len(),
            downstream_ids,
        };

        Ok(Json(serde_json::json!(resp)))
    }
    ```
  </Accordion>
</Accordions>

Source: `akasha-daemon/src/lineage.rs:223`. Registration: `akasha-daemon/src/lineage.rs:369`.

<a id="post-v1-lineage-verify" />

## POST `/v1/lineage/verify` [#post-v1lineageverify]

Compute a SHA-256 hash of a lineage node's content for integrity verification. POST /v1/lineage/verify

| Availability         | Source contract                                                  |
| -------------------- | ---------------------------------------------------------------- |
| Registration         | `config.enable_graph`                                            |
| Runtime service      | No prefix-level service check; handler dependencies still apply. |
| Handler dependencies | See handler source and return expressions.                       |

**Access:** Daemon authentication and capability namespace authority; memory-domain permissions apply where mapped.

### Request [#request-3]

**Json** — `LineageVerifyReq`

| Field     | Rust type | Required on input | Notes |
| --------- | --------- | ----------------- | ----- |
| `node_id` | `String`  | Yes               |       |

```rust
struct LineageVerifyReq {
    node_id: String,
}
```

**JSON field accesses in handler:** `integrity_hash`. Nested lookups are included; this list alone does not establish requiredness.

### Response [#response-3]

**Declared return:** `Result<impl IntoResponse, DaemonError>`

The following are the exact JSON construction expressions in the handler. Values such as `rows`, `result`, and delegated types are runtime values, not literal example payloads.

```rust
serde_json::json!(resp)
```

### Errors and validation [#errors-and-validation-3]

Directly referenced error variants: `Internal`, `InvalidRequest`. Middleware and delegated services can return additional errors described in the shared error reference.

<Accordions>
  <Accordion title="Inspect implementation">
    This exact source excerpt includes validation, defaults, delegated calls, and response assembly.

    ```rust
    async fn lineage_verify(
        State(state): State<AppState>,
        Extension(db): Extension<Arc<akasha::AkashaDB>>,
        Json(req): Json<LineageVerifyReq>,
    ) -> Result<impl IntoResponse, DaemonError> {
        state.record_http_request();

        let safe_id = sanitize_cypher(&req.node_id);
        let cypher = format!(
            "MATCH (n {{id: '{}'}}) WHERE n.lineage_type IS NOT NULL RETURN n LIMIT 1",
            safe_id
        );

        let rows = db
            .cypher(&cypher)
            .await
            .map_err(|e| DaemonError::InvalidRequest(e.to_string()))?;

        if rows.is_empty() {
            return Err(DaemonError::InvalidRequest(format!(
                "lineage node '{}' not found",
                req.node_id
            )));
        }

        let row = &rows[0];
        // Serialize the entire node content deterministically for hashing.
        let content_bytes = serde_json::to_vec(row)
            .map_err(|e| DaemonError::Internal(format!("serialization error: {}", e)))?;

        let hash = sha256_hex(&content_bytes);

        // If the node already has a stored hash, compare it for verification.
        let stored_hash = row
            .get("integrity_hash")
            .and_then(|v| v.as_str())
            .unwrap_or("");
        let verified = if stored_hash.is_empty() {
            // No stored hash — first time computation. Treat as verified.
            true
        } else {
            stored_hash == hash
        };

        let resp = LineageVerifyResponse {
            node_id: req.node_id,
            integrity_hash: hash,
            algorithm: "sha256".to_string(),
            verified,
        };

        Ok(Json(serde_json::json!(resp)))
    }
    ```
  </Accordion>
</Accordions>

Source: `akasha-daemon/src/lineage.rs:264`. Registration: `akasha-daemon/src/lineage.rs:370`.

<a id="get-v1-lineage-stats" />

## GET `/v1/lineage/stats` [#get-v1lineagestats]

Aggregate counts of lineage nodes and edges from the graph. GET /v1/lineage/stats

| Availability         | Source contract                                                  |
| -------------------- | ---------------------------------------------------------------- |
| Registration         | `config.enable_graph`                                            |
| Runtime service      | No prefix-level service check; handler dependencies still apply. |
| Handler dependencies | See handler source and return expressions.                       |

**Access:** Daemon authentication and capability namespace authority; memory-domain permissions apply where mapped.

### Request [#request-4]

No typed JSON, query, or path extractor is declared in the handler signature. Headers or request objects may still be consumed; the signature below is authoritative.
&#x2A;*JSON field accesses in handler:** `relationship`, `type`. Nested lookups are included; this list alone does not establish requiredness.

### Response [#response-4]

**Declared return:** `Result<impl IntoResponse, DaemonError>`

The following are the exact JSON construction expressions in the handler. Values such as `rows`, `result`, and delegated types are runtime values, not literal example payloads.

```rust
serde_json::json!(resp)
```

### Errors and validation [#errors-and-validation-4]

Directly referenced error variants: `InvalidRequest`. Middleware and delegated services can return additional errors described in the shared error reference.

<Accordions>
  <Accordion title="Inspect implementation">
    This exact source excerpt includes validation, defaults, delegated calls, and response assembly.

    ```rust
    async fn lineage_stats(
        State(state): State<AppState>,
        Extension(db): Extension<Arc<akasha::AkashaDB>>,
    ) -> Result<impl IntoResponse, DaemonError> {
        state.record_http_request();

        // Count all lineage nodes
        let node_cypher = "MATCH (n) WHERE n.lineage_type IS NOT NULL RETURN n";
        let node_rows = db
            .cypher(node_cypher)
            .await
            .map_err(|e| DaemonError::InvalidRequest(e.to_string()))?;

        // Count all edges between lineage nodes
        let edge_cypher = "MATCH (a)-[r]->(b) WHERE a.lineage_type IS NOT NULL AND b.lineage_type IS NOT NULL RETURN r";
        let edge_rows = db
            .cypher(edge_cypher)
            .await
            .map_err(|e| DaemonError::InvalidRequest(e.to_string()))?;

        // Tally relationship types
        let mut rel_counts: std::collections::HashMap<String, usize> = std::collections::HashMap::new();
        for row in &edge_rows {
            let rel_type = row
                .get("type")
                .or_else(|| row.get("relationship"))
                .and_then(|v| v.as_str())
                .unwrap_or("unknown");
            *rel_counts.entry(rel_type.to_string()).or_insert(0) += 1;
        }

        let resp = LineageStatsResponse {
            total_nodes: node_rows.len(),
            total_edges: edge_rows.len(),
            relationship_counts: serde_json::json!(rel_counts),
        };

        Ok(Json(serde_json::json!(resp)))
    }
    ```
  </Accordion>
</Accordions>

Source: `akasha-daemon/src/lineage.rs:321`. Registration: `akasha-daemon/src/lineage.rs:371`.
