Skip to content

feat: Semantic DAG v0.6.0 — append-only causal graph with signing and sync#76

Merged
ApiliumDevTeam merged 8 commits intodevfrom
feature/semantic-dag-v0.6.0
Mar 13, 2026
Merged

feat: Semantic DAG v0.6.0 — append-only causal graph with signing and sync#76
ApiliumDevTeam merged 8 commits intodevfrom
feature/semantic-dag-v0.6.0

Conversation

@ApiliumDevTeam
Copy link
Copy Markdown
Contributor

@ApiliumDevTeam ApiliumDevTeam commented Mar 13, 2026

Summary

Full implementation of the Semantic DAG (Directed Acyclic Graph) for AIngle, adding an append-only causal graph on top of the existing triple store — enabling full traceability, time-travel queries, and cross-node synchronization.

Phases included

  1. Data model & persistent storageDagAction, DagActionHash (BLAKE3), DagPayload (7 variants), DagTipSet, DagStore with pluggable backends (memory + Sled). Author and affected-triple indexes, schema versioning, index rebuild on restart. Pruning with 4 retention policies (KeepAll / KeepSince / KeepLast / KeepDepth).

  2. Time-travel, export & sync protocol — State reconstruction at any point in the DAG via replay onto an ephemeral GraphDB. DagDiff for ancestry comparison. Portable export (DagGraph) with DOT (Graphviz), Mermaid, and JSON renderers. Pull-based sync protocol (SyncRequest / SyncResponse) with compute_missing and ingest.

  3. GraphDB integration — 18 new public methods on GraphDB (feature-gated). Constructors: memory_with_dag(), sled_with_dag(). Methods: insert_via_dag(), delete_via_dag(), dag_tips(), dag_action(), dag_history(), dag_chain(), dag_prune(), dag_at(), dag_at_timestamp(), dag_sign(), dag_verify(), dag_export(), dag_ingest(), dag_compute_missing(), dag_diff(), etc. Full backward compatibility with existing insert() / delete().

  4. WAL + Raft state machineWalEntryKind::DagAction variant for serialization without circular dependencies. State machine applies actions to DagStore and materialized view. Snapshot includes dag_tips with backward compat (#[serde(default)]).

  5. Write path through Raftcreate_triple and delete_triple construct DagActions when the dag feature is enabled: determine tips → build action → serialize to WAL → Raft. AppState gains dag_author and dag_seq_counter. Startup creates a Genesis action if the DAG is empty.

  6. REST endpoints — 12 new endpoints under /api/v1/dag/:

    • GET tips, action/:hash, history, chain, stats, at/:hash, diff, export
    • POST prune, sync, sync/pull
    • GET verify/:hash
    • Content-type negotiation for DOT / Mermaid / JSON on export
  7. Mandatory Ed25519 signing — Every DagAction is signed with the node's Ed25519 key before Raft submission. The state machine rejects unsigned actions (Genesis exempt). Key derived from the existing P2P identity seed. Verification endpoint at GET /api/v1/dag/verify/:hash. Transparent to all exposed APIs.

Key changes

  • 24 files changed, ~5,300 lines added
  • New modules: aingle_graph::dag::* (action, backend, export, signing, store, sync, timetravel, tips, pruning)
  • Feature gates: dag, dag-sign, sled-backend
  • Crate dependencies: blake3, ed25519-dalek, rand_core, petgraph (dag feature only)

Test plan

  • Verify compilation with cargo build --features dag
  • Run unit tests: cargo test --features dag
  • Confirm compilation without dag feature is unaffected
  • Test REST endpoints against a test cluster
  • Verify Ed25519 signing and rejection of unsigned actions
  • Test time-travel and DOT/Mermaid export
  • Validate pull-based sync between two nodes

…ith indexes

Core Semantic DAG types: DagAction, DagActionHash (BLAKE3), DagPayload
(7 variants), DagTipSet, DagStore with pluggable backends.

- Content-addressable hashing: blake3(parents || author || seq || ts || payload)
- DagBackend trait with MemoryDagBackend and SledDagBackend implementations
- Author index, affected-triple index, tip persistence
- Schema versioning with forward-compat rejection
- Rebuild indexes from backend on restart
- Pruning with 4 retention policies (KeepAll/KeepSince/KeepLast/KeepDepth)
- Topological sort via Kahn's algorithm
- Feature gates: dag, dag-sign, sled-backend
…nc protocol

- Time-travel: replay DagPayload onto ephemeral GraphDB to reconstruct
  state at any point in DAG history; DagDiff for ancestry comparison
- Export: DagGraph portable structure with DOT (Graphviz), Mermaid, and
  JSON renderers with color-coded node types
- Signing: Ed25519 via ed25519-dalek; sign/verify action hashes;
  DagSigningKey/DagVerifyingKey with hex serialization (dag-sign feature)
- Sync: pull-based protocol — SyncRequest/SyncResponse with
  compute_missing and ingest (no tip mutation)
GraphDB gains optional DagStore field (feature-gated). Existing insert()
and delete() are unchanged — full backward compatibility.

New constructors: memory_with_dag(), sled_with_dag()
New methods: enable_dag(), enable_dag_persistent(), insert_via_dag(),
delete_via_dag(), dag_tips(), dag_action(), dag_history(), dag_chain(),
dag_prune(), dag_at(), dag_at_timestamp(), dag_sign(), dag_verify(),
dag_export(), dag_ingest(), dag_compute_missing(), dag_diff()
…AG tips

- WalEntryKind::DagAction { action_bytes } — serialized bytes to avoid
  circular deps with aingle_graph
- State machine apply_dag_action(): deserialize → DagStore.put() →
  apply payload to materialized view (exhaustive match on all variants)
- ClusterSnapshot gains dag_tips with #[serde(default)] for backward compat
- Snapshot builder reads DAG tips; restore rebuilds tip set
- create_triple and delete_triple construct DagActions when dag feature
  is enabled: determine tips → build action → serialize to WAL → Raft
- AppState gains dag_author (NodeId) and dag_seq_counter (AtomicU64)
- Startup: enable persistent DAG (Sled) or fallback to in-memory;
  create genesis action if DAG is empty; set author from cluster node ID
- Feature gates: dag = ["cluster", "aingle_graph/dag", "aingle_raft/dag"]
12 new endpoints under /api/v1/dag/:
  GET  tips, action/:hash, history, chain, stats, at/:hash, diff, export
  POST prune, sync, sync/pull
  GET  verify/:hash (dag-sign feature)

Includes DOT/Mermaid/JSON export with content-type negotiation,
pull-based cross-node sync, and time-travel state reconstruction.
Every DagAction is now signed with the node's Ed25519 key before Raft
submission. The state machine rejects unsigned actions (Genesis exempt).

- Merge dag-sign into dag feature (signing always enabled with DAG)
- AppState gains dag_signing_key (Arc<DagSigningKey>) loaded from node.key
- Signing key initialized from existing P2P identity seed or generated
- create_triple/delete_triple sign actions before Raft write
- State machine rejects unsigned non-Genesis actions with clear error
- Verify endpoint available at GET /api/v1/dag/verify/:hash
- Transparent to all exposed APIs — no request/response changes
Update version fields and internal dependency references across
all 13 product crates to align with the v0.6.0 release.
@ApiliumDevTeam ApiliumDevTeam merged commit 64b61b7 into dev Mar 13, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant