Trust Proof Layers
Architecture: trust persistence is sled-backed
TrustGraph stores edges in Arc<dyn Store> (backed by SledStore).
- Write path:
TrustGraph::add_edge()→store.put("{prefix}/edges/{source}:{target}", serde_json(edge)) - Read path:
TrustGraph::get_edge()→store.get(key)→serde_json::from_slice - Storage prefix:
"trust"by default; typed graphs use"trust/social","trust/economic","trust/technical"
What is persisted:
TrustEdge— source DID, target DID, score (f64), graph_type, evidence, created_at, expires_at
In-memory only (not persisted):
TrustCache(LRU score cache with TTL) — rebuilt from sled on first access after restartReachabilityFilter(Bloom filter) — rebuilt from edges on startup
NOTE: All existing tests use SledStore::temporary() — an ephemeral in-memory
store. None of them test durability. This file closes that gap.
Layer 1 — Direct Sled Write Proof ✅
What it proves: A TrustEdge written through TrustGraph::add_edge() with
a real SledStore::open(path) (not temporary()) survives a sled drop-and-reopen
boundary with exact field values.
After the drop:
- The sled file lock is released.
- The
TrustCacheLRU is gone — the fresh graph has no cached values. get_edge()reads exclusively from sled.
Artifact: crates/icn-trust/tests/trust_persistence.rs →
test_trust_edge_survives_sled_drop_and_reopen
Run:
cargo test -p icn-trust --test trust_persistence
What is asserted:
- Edge is present after reopen (not silently lost).
- Source DID survives exact round-trip.
- Target DID survives exact round-trip.
- Score survives exact round-trip (within f64 epsilon).
Key note: TrustEdge::new() sets expires_at: None — no expiry to manage.
The is_expired() check in get_edge() is a no-op for these edges.
Layer 2 — Facade-backed Sled Write Proof ✅
What it proves: A TrustEdge written through the full production abstraction
stack (TrustGraphFacade → MultiTrustGraph → TypedTrustGraph →
TrustGraph::new_with_prefix(store, did, "trust/social")) survives a sled
drop-and-reopen boundary with exact field values.
Also proves graph-type namespace isolation: a Social edge is not retrievable
via the Economic graph prefix (trust/economic/...), confirming that the three
typed graphs are truly isolated in sled storage.
Write path confirmed:
facade.add_edge(edge) // edge.graph_type == Social
→ multi.add_edge_to(Social, edge)
→ typed_graph.inner.add_edge(edge)
→ store.put("trust/social/edges/{src}:{tgt}", json)
Artifact: crates/icn-trust/tests/trust_persistence.rs →
test_trust_edge_survives_facade_sled_drop_and_reopen
Run:
cargo test -p icn-trust --test trust_persistence
What is asserted:
- Source DID survives the full facade round-trip (exact match).
- Target DID survives exact round-trip.
- Score survives exact round-trip (within f64 epsilon).
- Social edge is absent from the Economic graph namespace (prefix isolation).
Layer 3 — Same-Runtime Facade Drop + Recreate Proof ✅
What it proves: Trust state survives a same-runtime lifecycle boundary:
the original TrustGraphFacade and Arc<SledStore> are fully dropped (all Arc
refs released, sled file lock returned to the OS), and a brand-new
TrustGraphFacade constructed in the same process restores exact state from disk.
Trust has no background scheduler and no JoinHandle — dropping the Arc
is the complete shutdown. No shutdown().await is needed (unlike governance).
The sled file on disk is the sole bridge between Phase 1 and Phase 2.
Artifact: crates/icn-trust/tests/trust_persistence.rs →
test_trust_facade_survives_same_runtime_drop_and_recreate
Run:
cargo test -p icn-trust --test trust_persistence
What is asserted:
- Source DID survives the lifecycle boundary (exact match).
- Target DID survives (exact match).
- Score survives (exact, within f64 epsilon).
- Graph-type isolation holds through the fresh facade (Social absent from Economic).
Layer 4 — Cross-Process Restart Proof ✅
What it proves: A TrustEdge written through TrustGraphFacade in one OS
process is readable by a completely fresh OS process — no shared memory, no shared
sled handle, no Arc continuity across the process boundary. The sled file on disk
is the only bridge.
Implementation:
- Helper binary:
crates/icn-trust/src/bin/trust_restart_helper.rswrite <sled_path>: generates two KeyPairs, createsTrustGraphFacade, callsadd_edge(), prints"src_did,tgt_did,score"to stdout, exits 0.read <sled_path> <src_did> <tgt_did> <score>: opens freshSledStore, constructs freshTrustGraphFacade, reads edge viaget_edge(), asserts exact DID and score values, exits 0 on success, 1 on failure.
- Runtime:
new_current_thread()— noblock_in_placein trust path (unlike ledger). drop(rt)beforeprocess::exit()— flushes sled WAL before exit.
Artifact: crates/icn-trust/tests/trust_persistence.rs →
test_trust_edge_survives_cross_process_restart
Run:
cargo test -p icn-trust --test trust_persistence
What is asserted:
- Write subprocess exits 0, prints
"src_did,tgt_did,score". - Source and target DIDs are valid
did:icn:prefixed strings. - Read subprocess (fresh OS process, fresh sled, fresh facade) exits 0.
- Inside read subprocess: source DID, target DID, and score match exactly.
What Is NOT Yet Proven
| Gap | Layer | Next step |
|---|---|---|
| Evidence fields survive round-trip | Future | Add evidence: Vec<TrustEvidence> assertions |
Comparison with Other Subsystems
| Layer | Governance | Ledger | Gossip | Trust |
|---|---|---|---|---|
| 1 — Direct persistence | ✅ | ✅ | ✅ | ✅ |
| 2 — Production path | ✅ | ✅ | ✅ | ✅ |
| 3 — Same-runtime lifecycle | ✅ | ✅ | ✅ | ✅ |
| 4 — Cross-process restart | ✅ | ✅ | ✅ | ✅ |