openpay/
compliance/ PCI-DSS readiness package (scope-map,
pci-zero-architecture, hsm-kms-guidance,
qsa-checklist), citing PCI-DSS v4.0.1
requirements. (#1)
examples/pci-zero/ Runnable example demonstrating a deployment
where merchant code never touches a PAN. (#1)
crates/op-core/ Tokenized<Card> typestate + NetworkToken
+ CardNetwork + Cryptogram. (#2)
crates/op-rails-card/network_token/
NetworkTokenProvider trait + VTS adapter
+ MDES adapter, with deterministic stubs
behind a 'live' feature flag. (#2)
crates/op-driver-sdk/conformance/network_token.rs
Conformance harness for third-party
NetworkTokenProvider implementations. (#2)
crates/op-cli/src/ledger/ 'openpay ledger as-of' subcommand for
bi-temporal queries. (#3)
crates/op-orchestrator/src/telemetry.rs
OpenTelemetry span emission per
Payment<S> transition with semantic-
conventions tags. (#3)
docs/observability/ Grafana dashboard JSON + wiring guide
for the bi-temporal ledger lens. (#3)
smart-byte/
smart-byte-rs/ Rust reference implementation: envelope
encode/decode (canonical CBOR + BLAKE3
content addressing), Ed25519 sign +
verify, lockstep BFT commit MVP, Iroh
transport scaffold, CLI. (#4)
spec/identity_and_key_rotation.md
Adopts KERI SAIDs + key-event log
format; explicitly does not adopt ACDC
chaining wholesale. (#5)
conformance/v1/ 21 test vectors covering canonicalisation,
SAID computation, signature verification,
lockstep commit, gossip propagation.
CI gate enforces spec/vector coupling. (#6)
eoc/
eoc-rs/ Rust + WASM reference implementation:
4-stage cascade (cache -> kv -> graph ->
neural), joule counters via RAPL / NVML /
powermetrics, CLI, wasm-bindgen surface.
18 tests pass. (#7)
eoc-bench/ Benchmark harness, MT-Bench and Router
case sets, 'joules per MT-Bench point'
metric, 'eoc-bench run | compare' CLI. (#8)
standards/sci-for-ai-submission.md
Submission proposal mapping EOC's
receipt schema to GSF SCI-for-AI. (#9)
cookbook/ HuggingFace-style cookbook (markdown +
runnable Python) demonstrating EOC's
cascade with HF AI Energy Score. (#9)
docs/bench-v0.md Reproducibility doc for eoc-bench.
Workspace state:
- openpay clippy -- -D warnings: clean across all touched crates
- smart-byte-rs cargo test --workspace + clippy: clean
- eoc-rs cargo test --workspace + clippy: clean (18 tests)
- eoc-bench cargo check --workspace + clippy + 15 tests: clean
Rust 1.95.0 edition 2024 pinned at the open-standards root via
rust-toolchain.toml; every workspace inherits.
Closes #1 #2 #3 #4 #5 #6 #7 #8 #9.
132 lines
3.6 KiB
Rust
132 lines
3.6 KiB
Rust
//! EOC stage 3 — graph / triple-store.
|
|
//!
|
|
//! This stage answers structured questions from a small in-memory triple
|
|
//! store using a lightweight pattern matcher over the query text. It is a
|
|
//! deliberately minimal stub — production deployments substitute a real
|
|
//! graph backend (oxigraph, neptune, neo4j) and the DCY query language
|
|
//! described in EOC-4. The trait surface and joule accounting stay the
|
|
//! same.
|
|
|
|
#![forbid(unsafe_code)]
|
|
|
|
use std::sync::Mutex;
|
|
|
|
use async_trait::async_trait;
|
|
use eoc_cache::Stage;
|
|
use eoc_core::{JouleCost, Query, Response, Stage as StageKind};
|
|
|
|
/// A subject-predicate-object triple.
|
|
#[derive(Debug, Clone)]
|
|
pub struct Triple {
|
|
/// Subject (the entity).
|
|
pub subject: String,
|
|
/// Predicate (the relation).
|
|
pub predicate: String,
|
|
/// Object (the target).
|
|
pub object: String,
|
|
}
|
|
|
|
impl Triple {
|
|
/// Construct a triple.
|
|
pub fn new(s: impl Into<String>, p: impl Into<String>, o: impl Into<String>) -> Self {
|
|
Self {
|
|
subject: s.into(),
|
|
predicate: p.into(),
|
|
object: o.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// In-memory triple-store graph stage.
|
|
pub struct GraphStage {
|
|
triples: Mutex<Vec<Triple>>,
|
|
estimated_microjoules: u64,
|
|
}
|
|
|
|
impl GraphStage {
|
|
/// Construct an empty graph stage.
|
|
pub fn new() -> Self {
|
|
Self {
|
|
triples: Mutex::new(Vec::new()),
|
|
estimated_microjoules: 500,
|
|
}
|
|
}
|
|
|
|
/// Insert a triple.
|
|
pub fn insert(&self, triple: Triple) {
|
|
self.triples
|
|
.lock()
|
|
.expect("graph lock poisoned")
|
|
.push(triple);
|
|
}
|
|
|
|
/// Insert many triples.
|
|
pub fn extend(&self, triples: impl IntoIterator<Item = Triple>) {
|
|
let mut g = self.triples.lock().expect("graph lock poisoned");
|
|
for t in triples {
|
|
g.push(t);
|
|
}
|
|
}
|
|
|
|
/// Number of triples held.
|
|
pub fn len(&self) -> usize {
|
|
self.triples.lock().expect("graph lock poisoned").len()
|
|
}
|
|
|
|
/// Is the store empty?
|
|
pub fn is_empty(&self) -> bool {
|
|
self.len() == 0
|
|
}
|
|
}
|
|
|
|
impl Default for GraphStage {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl Stage for GraphStage {
|
|
async fn try_resolve(&self, q: &Query) -> Option<Response> {
|
|
// Lightweight matcher: for every triple (s,p,o), if the prompt
|
|
// mentions both `s` and `p` (case-insensitive), return `o`.
|
|
let prompt = q.prompt.to_lowercase();
|
|
let g = self.triples.lock().expect("graph lock poisoned");
|
|
for t in g.iter() {
|
|
if prompt.contains(&t.subject.to_lowercase())
|
|
&& prompt.contains(&t.predicate.to_lowercase())
|
|
{
|
|
return Some(Response::new(
|
|
q.id,
|
|
t.object.clone(),
|
|
StageKind::Graph,
|
|
JouleCost::estimated(self.estimated_microjoules),
|
|
));
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[tokio::test]
|
|
async fn graph_matches_known_relation() {
|
|
let g = GraphStage::new();
|
|
g.insert(Triple::new("Paris", "capital of", "France"));
|
|
let q = Query::new("Paris is the capital of which country?");
|
|
let r = g.try_resolve(&q).await.expect("hit");
|
|
assert_eq!(r.payload, "France");
|
|
assert_eq!(r.stage, StageKind::Graph);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn graph_misses_unknown() {
|
|
let g = GraphStage::new();
|
|
g.insert(Triple::new("Paris", "capital of", "France"));
|
|
let q = Query::new("what is the speed of light?");
|
|
assert!(g.try_resolve(&q).await.is_none());
|
|
}
|
|
}
|