OpenPay (1 crate, 2487 LOC, 33 tests)
op-fraud-graph Graph-based fraud detection. EntityKind (card/email/
device/IP/address/phone/BIN+last4/account) with
canonicalization + hashed EntityKey + billing↔shipping
mismatch detection. Adjacency-list FraudGraph with
idempotent upsert + edge-merge. Double-hashing Bloom
filter (capacity+FPR-sized). Union-find connected
components. PageRank with dangling-sink handling.
Louvain community detection. Shared-instrument hub
rings. Sliding ring-buffer velocity counters. Synthetic
identity heuristics (freshness + heavy-use + mail-drop).
Structuring / smurfing / mule-chain DFS. EntityRisk +
TransactionRisk + RiskBand combiner.
Smart Byte (1 crate, ~1844 LOC, 44 tests)
smart-byte-ilp Interledger Protocol v4. OER codec (length-determinant,
var-octet-string, BE u32/u64). Prepare/Fulfill/Reject
packet roundtrip with all 19 IL-RFC-27 reject codes.
SHA-256 Condition + Fulfillment with constant-time
verify. ILP address validator (7 schemes, 1-128 char
segments, 1023-byte cap, segment-aligned prefix match).
STREAM (15 frame types). BTP. SPSP payment-pointer
resolver. Open Payments API. Longest-prefix routing
Connector with fixed-point quote conversion + balance +
rate-limit checks.
EOC (1 crate, 1921 LOC, 36 tests)
eoc-quantize Quantization primitives. int8 (symmetric/asymmetric
with zero-inclusion fix), int4 (GPTQ + AWQ group quant),
int2 (BitNet), fp8 (E4M3/E5M2), nf4 (QLoRA). GGUF v3
header parse. safetensors read sketch. Calibration
datasets + per-channel scales. KV-cache quant. Energy
tradeoff curves (joules-per-token across schemes).
Co-Authored-By: Claude Opus 4.7 <[email protected]>
81 lines
2.3 KiB
Rust
81 lines
2.3 KiB
Rust
//! Integration tests for [`op_fraud_graph::PageRank`].
|
|
|
|
use op_fraud_graph::{
|
|
EdgeKind, Entity, EntityKind, FraudGraph, PageRank,
|
|
};
|
|
|
|
fn acc(g: &mut FraudGraph, name: &str) -> op_fraud_graph::VertexId {
|
|
g.upsert_entity(Entity::new(EntityKind::Account, name), 0, true)
|
|
}
|
|
|
|
#[test]
|
|
fn star_topology_hub_wins() {
|
|
// Build a star: one hub connected to 6 leaves.
|
|
let mut g = FraudGraph::new();
|
|
let hub = acc(&mut g, "hub");
|
|
let leaves: Vec<_> = (0..6).map(|i| acc(&mut g, &format!("leaf-{i}"))).collect();
|
|
for l in &leaves {
|
|
g.add_edge(hub, *l, EdgeKind::CoTransaction, 1.0).expect("ok");
|
|
}
|
|
|
|
let pr = PageRank::default().run(&g).expect("run ok");
|
|
let hub_score = pr.score(hub).expect("hub scored");
|
|
for l in &leaves {
|
|
let leaf_score = pr.score(*l).expect("leaf scored");
|
|
assert!(
|
|
hub_score > leaf_score,
|
|
"hub {hub_score} should exceed leaf {leaf_score}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn scores_sum_close_to_one() {
|
|
let mut g = FraudGraph::new();
|
|
let a = acc(&mut g, "a");
|
|
let b = acc(&mut g, "b");
|
|
let c = acc(&mut g, "c");
|
|
g.add_edge(a, b, EdgeKind::CoTransaction, 1.0).expect("ok");
|
|
g.add_edge(b, c, EdgeKind::CoTransaction, 1.0).expect("ok");
|
|
|
|
let pr = PageRank::default().run(&g).expect("ok");
|
|
let sum: f32 = pr.scores.iter().sum();
|
|
assert!((sum - 1.0).abs() < 0.01, "PageRank sum {sum} should be ~= 1");
|
|
}
|
|
|
|
#[test]
|
|
fn rejects_bad_config() {
|
|
let g = FraudGraph::new();
|
|
let bad = PageRank {
|
|
damping: 1.5,
|
|
..PageRank::default()
|
|
};
|
|
assert!(bad.run(&g).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn empty_graph_is_ok() {
|
|
let g = FraudGraph::new();
|
|
let pr = PageRank::default().run(&g).expect("ok");
|
|
assert!(pr.scores.is_empty());
|
|
assert!(pr.converged);
|
|
}
|
|
|
|
#[test]
|
|
fn top_returns_sorted_results() {
|
|
let mut g = FraudGraph::new();
|
|
let hub = acc(&mut g, "hub");
|
|
let nearby = acc(&mut g, "nearby");
|
|
for i in 0..8 {
|
|
let l = acc(&mut g, &format!("l-{i}"));
|
|
g.add_edge(hub, l, EdgeKind::CoTransaction, 1.0).expect("ok");
|
|
}
|
|
g.add_edge(hub, nearby, EdgeKind::CoTransaction, 1.0).expect("ok");
|
|
|
|
let pr = PageRank::default().run(&g).expect("ok");
|
|
let top = pr.top(3);
|
|
assert_eq!(top.len(), 3);
|
|
assert_eq!(top[0].0, hub);
|
|
assert!(top[0].1 >= top[1].1);
|
|
assert!(top[1].1 >= top[2].1);
|
|
}
|