From 4e27065a153c988ebbd435dc3cd8ffd1c0e38c4f Mon Sep 17 00:00:00 2001 From: sergio Date: Wed, 20 May 2026 16:39:07 +0000 Subject: [PATCH] =?UTF-8?q?feat(agorapura):=20app=20demo=20=E2=80=94=20esc?= =?UTF-8?q?enario=20narrado=20del=20=C3=A1gora?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLI que recorre el caso canónico de extremo a extremo: Venezuela atestigua la nacionalidad de Yumaira, otras identidades corroboran, una firma manipulada se rechaza, y tres políticas negociadas dan veredictos distintos sobre la misma evidencia. cargo run -p agorapura. Co-Authored-By: Claude Opus 4.7 --- Cargo.lock | 8 +++ Cargo.toml | 1 + crates/apps/agorapura/Cargo.toml | 17 ++++++ crates/apps/agorapura/src/main.rs | 91 +++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+) create mode 100644 crates/apps/agorapura/Cargo.toml create mode 100644 crates/apps/agorapura/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index cb340e1..69a8e35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,6 +80,14 @@ dependencies = [ "tokio", ] +[[package]] +name = "agorapura" +version = "0.1.0" +dependencies = [ + "agorapura-core", + "agorapura-graph", +] + [[package]] name = "agorapura-core" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 95bf776..f815254 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -235,6 +235,7 @@ members = [ "crates/apps/cosmobiologia-server", "crates/apps/dominium", "crates/apps/fana", + "crates/apps/agorapura", ] [workspace.package] diff --git a/crates/apps/agorapura/Cargo.toml b/crates/apps/agorapura/Cargo.toml new file mode 100644 index 0000000..59436a9 --- /dev/null +++ b/crates/apps/agorapura/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "agorapura" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +authors.workspace = true +publish.workspace = true +description = "agorapura — demostración narrada del ágora de identidad: identidades, claims, atestaciones firmadas y evaluación de confianza bajo políticas negociadas." + +[[bin]] +name = "agorapura" +path = "src/main.rs" + +[dependencies] +agorapura-core = { path = "../../modules/agorapura/agorapura-core" } +agorapura-graph = { path = "../../modules/agorapura/agorapura-graph" } diff --git a/crates/apps/agorapura/src/main.rs b/crates/apps/agorapura/src/main.rs new file mode 100644 index 0000000..b082c35 --- /dev/null +++ b/crates/apps/agorapura/src/main.rs @@ -0,0 +1,91 @@ +//! `agorapura` — demostración narrada del ágora de identidad. +//! +//! Recorre el escenario canónico de extremo a extremo: la institución +//! *Venezuela* atestigua la nacionalidad de la persona *Yumaira*, y +//! otras identidades la corroboran. Imprime la evidencia acumulada y +//! cómo distintas políticas *negociadas* la aceptan o no. +//! +//! No es la app definitiva — es un smoke test legible y la mejor forma +//! de ver el módulo funcionando: `cargo run -p agorapura`. + +use agorapura_core::{Attestation, Claim, IdentityKind, Keypair}; +use agorapura_graph::{TrustGraph, TrustPolicy}; + +/// Segundo Unix fijo para que la demo sea reproducible. +const T0: u64 = 1_700_000_000; + +fn main() { + println!("\n ágora · demostración de identidad federada\n"); + + // --- Identidades. Semillas fijas → demo reproducible. --- + let yumaira = Keypair::from_seed([20; 32]); + let venezuela = Keypair::from_seed([10; 32]); + let comunidad = Keypair::from_seed([30; 32]); + let vecina = Keypair::from_seed([40; 32]); + + let mut agora = TrustGraph::new(); + agora.register(yumaira.identity(IdentityKind::Person, "Yumaira")); + agora.register(venezuela.identity(IdentityKind::Institution, "Venezuela")); + agora.register(comunidad.identity(IdentityKind::Community, "Vecinos del Valle")); + agora.register(vecina.identity(IdentityKind::Person, "Carmen")); + + println!(" identidades registradas:"); + for kp in [&yumaira, &venezuela, &comunidad, &vecina] { + let id = kp.identity_id(); + let name = agora.identity(id).map(|i| i.display_name.as_str()).unwrap_or("?"); + println!(" {id} {name}"); + } + + // --- Atestaciones sobre la nacionalidad de Yumaira. --- + let nacionalidad = |by: &Keypair| { + Attestation::create( + by, + Claim::new(yumaira.identity_id(), "nacionalidad", "venezolana", T0), + ) + }; + println!("\n atestaciones de «nacionalidad = venezolana» sobre Yumaira:"); + for (by, label) in [ + (&venezuela, "Venezuela (institución)"), + (&comunidad, "Vecinos del Valle (comunidad)"), + (&yumaira, "Yumaira (ella misma)"), + ] { + let att = nacionalidad(by); + match agora.add_attestation(att) { + Ok(()) => println!(" ✔ firma verificada — {label}"), + Err(e) => println!(" ✘ rechazada — {label}: {e}"), + } + } + + // --- Intento de fraude: una firma manipulada. --- + let mut falsa = nacionalidad(&vecina); + falsa.claim.value = "marciana".into(); // rompe la firma + print!("\n intento de atestación con firma manipulada: "); + match agora.add_attestation(falsa) { + Ok(()) => println!("ACEPTADA (esto sería un bug)"), + Err(e) => println!("rechazada — {e}"), + } + + // --- Corroboración. --- + let c = agora.corroboration(yumaira.identity_id(), "nacionalidad", "venezolana"); + println!("\n corroboración del claim:"); + println!(" atestadores totales : {}", c.total()); + println!(" terceros (no ella) : {}", c.third_party()); + println!(" auto-atestado : {}", c.self_attested); + + // --- Veredicto según la política negociada. --- + println!("\n veredicto según la política (la verdad depende de lo pactado):"); + for (policy, label) in [ + (TrustPolicy::strict(1), "laxa · 1 tercero basta"), + (TrustPolicy::strict(2), "media · 2 terceros"), + (TrustPolicy::strict(3), "estricta · 3 terceros"), + ] { + let ok = policy.accepts(&c); + let mark = if ok { "ACEPTA" } else { "rechaza" }; + println!(" [{mark}] {label}"); + } + + println!( + "\n el ágora no dicta la verdad: acumula evidencia firmada y\n \ + cada quien la pesa con la política que negocie.\n" + ); +}