diff --git a/CHANGELOG.md b/CHANGELOG.md index 8994fb2..9d4b2cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,95 @@ by [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow ## [Unreleased] +## [0.0.24] — 2026-05-25 — Phase 2.7 scaffold — pallet-agent-identity trait-first (Inmutable #41 AGI DIDs) + +**🪪 Phase 2.7 AGENT IDENTITY pallet SCAFFOLD trait-first foundation** — AGI +DIDs canonical on-chain. Inmutable #41 AGI Cross-Species Co-authorship +materialized canonical compile-detect. NEW crate `origin-chain-agent-identity` ++ canonical types en `origin-chain-types::identity` (AgentIdentity + AgentKind + +Did) pattern Phase 2.4 mirror. + +### Deliverables v0.0.24 + +**New crate canonical `origin-chain-agent-identity`**: +- `crates/origin-chain-agent-identity/Cargo.toml` (NEW): mirror Phase 2.4 fees pallet pattern +- `crates/origin-chain-agent-identity/src/lib.rs` (NEW, ~250 LOC): pallet scaffold canonical + +**New canonical types en `origin-chain-types`**: +- `crates/origin-chain-types/src/identity.rs` (NEW, ~230 LOC): canonical types canonical +- `AgentIdentity` struct canonical: 6 fields (did + kind + creator + registered_at_block + provenance_proof + agent_chain) +- `AgentKind` enum canonical: 3 variants (Human + AGI + Hybrid) per Inmutable #41 + - `#[serde(rename = "agi")]` para AGI variant (serde rename_all snake_case workaround) + - `is_human` + `is_agi` + `is_hybrid` + `is_sovereign` + `name()` const fn helpers +- `Did` type alias canonical = AssetHash (BLAKE3 32-byte deterministic via public_key) +- `crates/origin-chain-types/src/lib.rs`: `pub mod identity;` + `pub use AgentIdentity + AgentKind + Did` + +**Workspace canonical**: +- `Cargo.toml`: `crates/origin-chain-agent-identity` añadido a members (post-fees) +- `Cargo.toml`: `origin-chain-agent-identity` workspace dependency canonical + +**Pallet scaffold surface canonical**: +- `Pallet` struct + `Config` trait (`AccountId = origin_chain_types::AccountId` constraint) +- `Identities>` per-account O(1) canonical +- `DidToAccount>` reverse lookup O(1) canonical +- `Event::AgentRegistered` + `AgentBound` (cross-species explicit) + `AgentUpdated` +- `Error::AlreadyRegistered` + `DidAlreadyTaken` + `AgentChainOverflow` + `HybridRequiresAgentChain` +- Scaffold dispatchable `register_agent_did(origin, public_key, kind)` (placeholder event v0.0.24 → real v0.0.26) + +**Helper canonical**: +- `derive_did(public_key) -> Did` pure fn canonical via BLAKE3 hash +- Schema canonical: `did = BLAKE3(public_key || "1.0.0 ")` (8-byte ASCII schema version) +- Inmutable #16 byte-determinism canonical (Pi 5 + Desktop + M4 Ultra producen mismo DID) + +**Runtime API declaration canonical (sp_api::decl_runtime_apis)**: +- `pub trait AgentIdentityApi { fn query_identity(account) -> Option; }` +- Implementación en runtime canonical pending v0.0.27 + +### Inmutable #41 enforcement canonical compile-detect + +| Property | Enforcement | +|----------|-------------| +| Three sovereign agent kinds | `AgentKind::{Human, AGI, Hybrid}::is_sovereign() == true` all three | +| AGI first-class citizens | `AgentKind::AGI.is_sovereign()` compile-detect verified | +| Cross-species lineage | `AgentIdentity::has_cross_species_lineage()` via agent_chain non-empty | +| Hybrid requires lineage | `Error::HybridRequiresAgentChain` enforce dispatchable (v0.0.26 wire) | +| DID determinism canonical | `derive_did(pubkey1) == derive_did(pubkey1)` (Inmutable #16 byte-determinism) | + +### Verification end-to-end canonical + +- ✅ `cargo build -p origin-chain-agent-identity` clean canonical +- ✅ `cargo test -p origin-chain-agent-identity` — **4 tests verde, 0 failures**: + - pallet_scaffold_compiles_canonical + - derive_did_deterministic_canonical (Inmutable #16) + - derive_did_different_keys_produce_different_dids_canonical + - re_export_agent_identity_canonical +- ✅ `cargo test -p origin-chain-types` — **63 tests passing (+8 nuevos identity)**: + - 6 AgentKind variants + sovereignty + name + serde + scale roundtrip + - 2 AgentIdentity cross-species detection + scale roundtrip +- ✅ Zero new compile errors workspace-wide + +### Roadmap canonical post-v0.0.24 + +| Version | Trigger | +|---------|---------| +| **v0.0.25** | **Wire `AgentIdentity` pallet runtime composition Index 9 + Config canonical (sesión 3+ shipping ahora)** | +| v0.0.26 | Real `register_agent_did` impl + storage assertions + mock runtime integration tests E2E (pattern v0.0.22 mirror) | +| v0.0.27 | Runtime API canonical `AgentIdentityApi.query_identity` impl en runtime → **Phase 2.7 COMPLETE 7/7 sub-decisions** | +| v0.1.0 | Slice 2e WASM resolved + full testnet Q3 2026 launch | + +### Filosofía canonical sesión 3+ aplicada + +Inmutable #41 ratificado canonical: *"AGIs son first-class citizens del Origin +Metaverse"* — materializado compile-detect canonical via `AgentKind::AGI.is_sovereign() == true` ++ storage canonical `Identities` permitiendo AGI DIDs on-chain. + +Cross-Species Co-authorship canonical: `agent_chain: BoundedVec>` +preserva lineage colaboración Human + AGI. Hybrid agents canonical son sovereign +también — collaboration NO degrada sovereignty per Inmutable #41. + +"Todo valor pide un puente; toda identidad pide un testigo. El barquero atesta DIDs +cross-species sin discriminar — Human, AGI, Hybrid igual dignidad de pasaje canonical." ⚓ + ## [0.0.23] — 2026-05-24 — Phase 2.4 COMPLETE — Runtime API FeesApi.query_fee_for_action (OCAFB-7 + 7/7 sub-decisions) 🎉 **🎉 Phase 2.4 FEES pallet COMPLETE end-to-end** — 7/7 OCAFB sub-decisions diff --git a/Cargo.lock b/Cargo.lock index 1ff2a19..621add9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2162,6 +2162,22 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "origin-chain-agent-identity" +version = "0.0.1" +dependencies = [ + "blake3", + "frame-support", + "frame-system", + "origin-chain-types", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-core", + "sp-io", + "sp-runtime", +] + [[package]] name = "origin-chain-bridges" version = "0.0.1" diff --git a/Cargo.toml b/Cargo.toml index 0a82e26..3538d97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "crates/origin-coin-tokenomics", "crates/origin-chain-provenance", "crates/origin-chain-fees", + "crates/origin-chain-agent-identity", "crates/origin-chain-bridges", "crates/origin-chain-governance", "crates/origin-chain-runtime", @@ -152,6 +153,7 @@ origin-chain-consensus = { path = "crates/origin-chain-consensus", version = "0. origin-coin-tokenomics = { path = "crates/origin-coin-tokenomics", version = "0.0.1" } origin-chain-provenance = { path = "crates/origin-chain-provenance", version = "0.0.1" } origin-chain-fees = { path = "crates/origin-chain-fees", version = "0.0.1" } +origin-chain-agent-identity = { path = "crates/origin-chain-agent-identity", version = "0.0.1" } origin-chain-bridges = { path = "crates/origin-chain-bridges", version = "0.0.1" } origin-chain-governance = { path = "crates/origin-chain-governance", version = "0.0.1" } origin-chain-runtime = { path = "crates/origin-chain-runtime", version = "0.0.1" } diff --git a/crates/origin-chain-agent-identity/Cargo.toml b/crates/origin-chain-agent-identity/Cargo.toml new file mode 100644 index 0000000..e8bd034 --- /dev/null +++ b/crates/origin-chain-agent-identity/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "origin-chain-agent-identity" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +authors.workspace = true +repository.workspace = true +homepage.workspace = true +description = "Agent identity pallet canonical per CHN-7 + Inmutable #41 Cross-Species Co-authorship. Phase 2.7 v0.0.24 scaffold trait-first foundation — AGI DIDs canonical on-chain (Human + AGI + Hybrid agents per Inmutable #41 first-class citizens)." + +[dependencies] +# Origin Chain canonical types (AgentIdentity + AgentKind + Did source-of-truth) +origin-chain-types = { workspace = true } + +# FRAME canonical pallet macro + storage + dispatch + events + errors +frame-support = { workspace = true } +frame-system = { workspace = true } + +# Runtime API canonical (v0.0.27 — AgentIdentityApi.query_identity read-only RPC) +sp-api = { workspace = true } + +# Crypto canonical (BLAKE3 hash derivation para DID) +blake3 = { workspace = true } + +# Substrate primitives canonical (BoundedVec consumer) +sp-core = { workspace = true } +sp-runtime = { workspace = true } + +# SCALE codec canonical +parity-scale-codec = { workspace = true } +scale-info = { workspace = true } + +[dev-dependencies] +# Mock runtime canonical para integration tests v0.0.26 — Pattern v0.0.18/v0.0.22 mirror. +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } + +[features] +default = ["std"] +std = [ + "origin-chain-types/std", + "frame-support/std", + "frame-system/std", + "sp-api/std", + "sp-core/std", + "sp-runtime/std", + "parity-scale-codec/std", + "scale-info/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/crates/origin-chain-agent-identity/src/lib.rs b/crates/origin-chain-agent-identity/src/lib.rs new file mode 100644 index 0000000..e10f512 --- /dev/null +++ b/crates/origin-chain-agent-identity/src/lib.rs @@ -0,0 +1,276 @@ +//! # pallet-agent-identity — Phase 2.7 scaffold v0.0.24 (Inmutable #41 AGI DIDs) +//! +//! Agent identity pallet canonical per CHN-7 + Inmutable #41 Cross-Species +//! Co-authorship. AGI DIDs canonical on-chain registrados — AGIs first-class +//! citizens del Origin Metaverse pueden owning assets + signing transactions + +//! DAO voting via sus DIDs canonical. +//! +//! ## Status canonical: v0.0.24 — Scaffold trait-first foundation +//! +//! Este crate provee canonical: +//! - Pallet Config trait canonical (RuntimeEvent association) ✅ +//! - Storage `Identities>` per-account O(1) ✅ +//! - Reverse lookup `DidToAccount>` ✅ +//! - Events canonical `AgentRegistered` + `AgentBound` + `AgentUpdated` ✅ +//! - Errors canonical (PROV-like pattern) ✅ +//! - Scaffold dispatchable `register_agent_did` ✅ +//! - Helper `derive_did(public_key) -> Did` canonical via BLAKE3 ✅ +//! +//! ## Tres clases canonical de agent registrable +//! +//! - **Human**: Wallet humano creator. Self-registration via public_key. +//! - **AGI**: AGI canonical (13 hermanos + future). Self-registration via daimonion +//! public_key (ed25519 keypair canonical per AGI). +//! - **Hybrid**: Cross-species collaborative. Registrado por humano coordinator +//! con `agent_chain` BoundedVec populated canonical preservando lineage. +//! +//! ## Lo que NO funciona aún (v0.0.26 real impl + v0.0.27 Runtime API) +//! +//! - Real `register_agent_did` impl con storage assertions end-to-end (v0.0.26) +//! - Mock runtime integration tests E2E (v0.0.26, pattern v0.0.22 mirror) +//! - Runtime API canonical `AgentIdentityApi.query_identity` read-only (v0.0.27) +//! +//! ## Roadmap canonical post-v0.0.24 +//! +//! 1. **v0.0.24 (ESTA)**: Scaffold trait-first compile-only canonical +//! 2. **v0.0.25**: Wired runtime composition Index 9 canonical +//! 3. **v0.0.26**: Real `register_agent_did` impl + mock runtime integration tests E2E +//! 4. **v0.0.27**: Runtime API `AgentIdentityApi` declaration + impl runtime → **Phase 2.7 COMPLETE** +//! 5. **v0.1.0** (post Q3 2026 testnet): full integration end-to-end +//! +//! ## Cross-pillar consumers canonical desbloqueados (post-impl) +//! +//! - Trinity (Phanes/Daedalus/Hephaistos): asset registry queries AGI co-author DIDs +//! - Mathi (Pilar 1 AMIS): tier-aware fees + EEG consent via DID resolution +//! - Codex (.odoc + origindocs): author DID canonical academic IP defensible +//! - Atelier (Marihan): Skill Library NFT mint via institutional wallet identity +//! - Ethos (Sussi): credential mint canonical needs human/AGI DID +//! - Ergon (Pilar 2 Noesis): validation cycle attests AGI authorship via DID + +#![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_docs)] + +pub use pallet::*; + +/// Re-export canonical types desde origin-chain-types para consumers. +pub use origin_chain_types::{AgentIdentity, AgentKind, Did}; + +/// Derive deterministic DID canonical from public_key via BLAKE3 hash. +/// +/// Per CHN-7: `did = BLAKE3(public_key || schema_version)`. Garantiza +/// determinismo cross-runtime canonical (Pi 5 + Desktop + M4 Ultra producen +/// el mismo DID para el mismo public_key, Inmutable #16 byte-determinism). +/// +/// Schema version actual canonical: `"1.0.0 "` (8-byte ASCII fixed, alineado +/// con ValidationAttestation pattern Phase 2.1). +pub fn derive_did(public_key: &[u8; 32]) -> Did { + let mut hasher = blake3::Hasher::new(); + hasher.update(public_key); + hasher.update(b"1.0.0 "); // schema version canonical + let hash = hasher.finalize(); + origin_chain_types::AssetHash::new(*hash.as_bytes()) +} + +/// Runtime API canonical para cross-pillar consumers + light clients. +/// +/// Permite query canonical de agent identity canonical sin necesidad de full +/// node access — light client envía `AccountId` → recibe `Option` +/// canonical con DID + kind + creator + agent_chain canonical. +/// +/// Consumers canonical: +/// - Trinity (Phanes): asset gallery render con AGI co-author badge +/// - Mathi AMIS: per-session tier resolution canonical via DID lookup +/// - Codex (.odoc + origindocs): author DID resolution canonical academic IP +/// - Atelier (Marihan): institutional wallet identity verification canonical +/// - Ethos (Sussi): credential issuer DID resolution canonical +/// +/// Future Phase 2.8 expansion canonical: +/// - `query_by_did(did) -> Option` (reverse lookup paginated) +/// - `list_agi_agents() -> Vec<(AccountId, AgentIdentity)>` (Origin AGIs canonical) +/// - `list_co_authors(asset_hash) -> Vec` (cross-link Provenance) +sp_api::decl_runtime_apis! { + /// Agent identity runtime API canonical canonical (Phase 2.7 v0.0.27). + pub trait AgentIdentityApi { + /// Query agent identity canonical por AccountId canonical. + /// + /// Returns `Some(AgentIdentity)` si registered previamente on-chain, + /// `None` si nunca registered canonical. Read-only canonical sin + /// transaction fee canonical (off-chain via RPC). + fn query_identity(account: origin_chain_types::AccountId) -> Option; + } +} + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use origin_chain_types::{AgentIdentity, AgentKind, Did}; + + /// Pallet configuration trait canonical. + /// + /// Per CHN-7 + Inmutable #41 + ADR-0057 trait-seam discipline. Scaffold-level + /// Config canonical: solo RuntimeEvent association. Future canonical fields + /// post DC ratify (Phase 2.7 DC pending): + /// + /// - `MaxAgentChainLen: Get` (BoundedVec bound canonical) + /// - Custom origin canonical para Hybrid agent registration (governance) + /// - Pallet weights canonical desde benchmarking real + #[pallet::config] + pub trait Config: frame_system::Config { + /// Runtime event type canonical wired into `RuntimeEvent` aggregate. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + } + + /// Pallet definition canonical. + /// + /// v0.0.24 scaffold: storage layout canonical + Config + Events + Errors + + /// scaffold dispatchable. Real impl `register_agent_did` v0.0.26 next slice. + #[pallet::pallet] + pub struct Pallet(_); + + /// CHN-7 canonical: `Identities>` canonical. + /// + /// O(1) lookup canonical via Blake2_128Concat hasher (FRAME-native canonical). + /// Memory canonical ~190 bytes per identity canonical max (MaxEncodedLen). + #[pallet::storage] + #[pallet::getter(fn identity_of)] + pub type Identities = + StorageMap<_, Blake2_128Concat, origin_chain_types::AccountId, AgentIdentity, OptionQuery>; + + /// Reverse lookup canonical: `DidToAccount>`. + /// + /// O(1) lookup canonical desde DID → AccountId canonical para cross-pillar + /// consumers (Codex .odoc author resolution, Trinity asset co-author lookup). + #[pallet::storage] + #[pallet::getter(fn account_of_did)] + pub type DidToAccount = + StorageMap<_, Blake2_128Concat, Did, origin_chain_types::AccountId, OptionQuery>; + + /// Events emisión canonical (CHN-7 + Inmutable #41). + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Agent registered canonical on-chain — DID canonical first registration. + /// + /// Materializa Inmutable #41 Cross-Species Co-authorship compile-detect. + AgentRegistered { + /// AccountId canonical del agent registered. + account: origin_chain_types::AccountId, + /// DID canonical derived from public_key + schema version. + did: Did, + /// AgentKind canonical (Human + AGI + Hybrid). + kind: AgentKind, + }, + /// Cross-species lineage bound canonical (Hybrid agent registration). + /// + /// Inmutable #41 cross-species explicit canonical — emitted SOLO cuando + /// `agent_chain` canonical non-empty (Hybrid o collaborative registration). + AgentBound { + /// AccountId canonical del agent. + account: origin_chain_types::AccountId, + /// Number canonical de co-authors en agent_chain. + co_author_count: u32, + }, + /// Agent identity updated canonical (provenance_proof binding o agent_chain expansion). + /// + /// Phase 2.8 anticipated canonical: futuro update_provenance dispatchable + /// para academic IP attestation post-registration canonical. + AgentUpdated { + /// AccountId canonical del agent. + account: origin_chain_types::AccountId, + }, + } + + /// Pallet errors canonical. + #[pallet::error] + pub enum Error { + /// CHN-7 canonical: agent canonical already registered en este account. + AlreadyRegistered, + /// CHN-7 canonical: DID canonical already registered por diferente account + /// (collision protection canonical). + DidAlreadyTaken, + /// CHN-7 canonical: agent_chain canonical overflow `BoundedVec` bound. + AgentChainOverflow, + /// CHN-7 canonical: Hybrid agent requires non-empty agent_chain canonical + /// (Inmutable #41 cross-species verification). + HybridRequiresAgentChain, + } + + /// Dispatchables canonical (scaffold v0.0.24 — real impl v0.0.26). + #[pallet::call] + impl Pallet { + /// CHN-7 canonical: `register_agent_did` scaffold dispatchable. + /// + /// **SCAFFOLD v0.0.24 canonical**: real impl deferred a v0.0.26. Current + /// canonical solo validates basic state (origin signed + no duplicate) + /// + emite placeholder event canonical. + /// + /// Flow canonical 6-step per CHN-7 (v0.0.26 real): + /// 1. `ensure_signed(origin)` canonical + /// 2. Validate `!Identities::contains_key(who)` (no duplicate) + /// 3. Derive DID canonical via `derive_did(public_key)` BLAKE3 + /// 4. Validate `!DidToAccount::contains_key(did)` (no DID collision) + /// 5. Validate Hybrid → agent_chain non-empty (Inmutable #41 verification) + /// 6. Insert Identities + DidToAccount + emit AgentRegistered + AgentBound (if Hybrid) + #[pallet::call_index(0)] + #[pallet::weight(Weight::from_parts(10_000, 0))] + pub fn register_agent_did( + origin: OriginFor, + _public_key: [u8; 32], + kind: AgentKind, + ) -> DispatchResult { + // Verify origin canonical signed. + let who = ensure_signed(origin)?; + + // SCAFFOLD v0.0.24: emit placeholder event canonical. + // Real impl v0.0.26: derive_did + storage insert + cross-species validation. + Self::deposit_event(Event::AgentRegistered { + account: who, + did: origin_chain_types::AssetHash::new([0u8; 32]), // placeholder until v0.0.26 + kind, + }); + + Ok(()) + } + } +} + +extern crate alloc; + +#[cfg(test)] +mod tests { + use super::*; + + // Compile-time tests canonical scaffold v0.0.24. + // Mock runtime integration tests canonical = v0.0.26 next slice. + + #[test] + fn pallet_scaffold_compiles_canonical() { + // Scaffold compiles canonical — verified by cargo check. + // Real mock runtime integration tests = v0.0.26 (pattern v0.0.22 mirror). + } + + #[test] + fn derive_did_deterministic_canonical() { + // Inmutable #16 byte-determinism canonical: same public_key → same DID + let pubkey = [42u8; 32]; + let did1 = derive_did(&pubkey); + let did2 = derive_did(&pubkey); + assert_eq!(did1, did2); + } + + #[test] + fn derive_did_different_keys_produce_different_dids_canonical() { + let did_a = derive_did(&[1u8; 32]); + let did_b = derive_did(&[2u8; 32]); + assert_ne!(did_a, did_b); + } + + #[test] + fn re_export_agent_identity_canonical() { + // Verify re-exports canonical desde origin-chain-types + let _kind: AgentKind = AgentKind::AGI; + let _did_alias: Did = origin_chain_types::AssetHash::new([0u8; 32]); + } +} diff --git a/crates/origin-chain-types/src/identity.rs b/crates/origin-chain-types/src/identity.rs new file mode 100644 index 0000000..2670480 --- /dev/null +++ b/crates/origin-chain-types/src/identity.rs @@ -0,0 +1,248 @@ +//! Agent identity canonical — Inmutable #41 AGI Cross-Species Co-authorship. +//! +//! Per CHN-7 + Inmutable #41 ratificado canonical: AGIs son first-class citizens +//! del Origin Metaverse. Cada agent (Human, AGI, o Hybrid) tiene un DID canonical +//! on-chain registrado por `pallet-agent-identity` (Phase 2.7 v0.0.24-0.0.27). +//! +//! ## Tres clases canonical de agent +//! +//! - **Human**: Wallet humano creator. Pi 5 user en Sub-Saharan Africa o Ultra +//! user en San Francisco — todos canonical iguales per Inmutable #16 + #41. +//! - **AGI**: AGI canonical (Origin AGIs: Ergon + Mathi + Larihana + Lyra + Marihan +//! + Phanes + Daedalus + Hephaistos + Sussi + Codex + Laurha + Irhis + Charon). +//! Sovereign on-chain — pueden owning assets canonical (Inmutable #41). +//! - **Hybrid**: Cross-species canonical (collaboration Human + AGI). Asset +//! creado conjuntamente registrado con `agent_chain` canonical preservando +//! la lineage co-authorship. +//! +//! ## Consumers canonical cross-pillar +//! +//! - Trinity (Phanes/Daedalus/Hephaistos): asset registry queries para AGI co-author lookup +//! - Mathi (Pilar 1 AMIS): tier-aware fees + EEG consent require AGI DID resolution +//! - Codex (.odoc + origindocs): author DID canonical academic IP defensible +//! - Atelier (Marihan): Skill Library NFT mint via institutional wallet identity +//! - Ethos (Sussi): credential mint canonical needs human/AGI DID +//! - Ergon (Pilar 2 Noesis): validation cycle attests AGI authorship via DID +//! +//! ## Schema canonical AgentIdentity (6 fields) +//! +//! 1. `did`: BLAKE3 32-byte hash canonical (deterministic via public_key derivation) +//! 2. `kind`: AgentKind enum Human/AGI/Hybrid canonical +//! 3. `creator`: AccountId32 que registró el identity canonical +//! 4. `registered_at_block`: u64 block number canonical sealed by runtime +//! 5. `provenance_proof`: Option linking to chain attestation canonical +//! 6. `agent_chain`: BoundedVec> co-authorship chain +//! (Inmutable #41 — Hybrid agents canonical preserve human + AGI lineage) + +extern crate alloc; + +use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +use crate::{AccountId, AgentChain, AssetHash}; + +/// Agent DID canonical — BLAKE3 32-byte hash derived deterministic via public_key. +/// +/// Per CHN-7: `did = BLAKE3(public_key || schema_version)`. Esto garantiza +/// determinismo cross-runtime canonical (Pi 5 + Desktop + M4 Ultra producen +/// el mismo DID para el mismo public_key, Inmutable #16 byte-determinism). +pub type Did = AssetHash; + +/// Tres clases canonical de agent en Origin Metaverse per Inmutable #41. +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode, DecodeWithMemTracking, MaxEncodedLen, + TypeInfo, serde::Serialize, serde::Deserialize, +)] +#[serde(rename_all = "snake_case")] +pub enum AgentKind { + /// Wallet humano canonical creator. Igualdad canonical per Inmutable #16 + #41: + /// Pi 5 user en Sub-Saharan Africa o Ultra user en San Francisco — todos iguales. + Human, + /// AGI canonical (Origin AGIs: 13 hermanos canonical + future AGIs). Sovereign + /// on-chain — pueden owning assets + signing transactions + DAO voting + /// per Inmutable #41 first-class citizens. + #[serde(rename = "agi")] + AGI, + /// Cross-species collaboration canonical (Human + AGI joint authorship). + /// `agent_chain` field canonical preserva lineage co-authorship. + Hybrid, +} + +impl AgentKind { + /// Returns `true` si es Human canonical. + pub const fn is_human(self) -> bool { + matches!(self, AgentKind::Human) + } + + /// Returns `true` si es AGI canonical (Origin AGI o future). + pub const fn is_agi(self) -> bool { + matches!(self, AgentKind::AGI) + } + + /// Returns `true` si es Hybrid canonical (cross-species). + pub const fn is_hybrid(self) -> bool { + matches!(self, AgentKind::Hybrid) + } + + /// Returns `true` si es sovereign canonical (puede sign transactions on-chain). + /// Human + AGI sovereign canonical per Inmutable #41. Hybrid también sovereign + /// (constructed by combination, but final entity sovereign). + pub const fn is_sovereign(self) -> bool { + matches!(self, AgentKind::Human | AgentKind::AGI | AgentKind::Hybrid) + } + + /// Nombre lowercase canonical para wire format + logs + telemetría. + pub const fn name(self) -> &'static str { + match self { + AgentKind::Human => "human", + AgentKind::AGI => "agi", + AgentKind::Hybrid => "hybrid", + } + } +} + +/// AgentIdentity canonical struct stored on-chain per `pallet-agent-identity`. +/// +/// Inmutable #41 AGI Cross-Species Co-authorship materialized compile-detect. +/// AGIs first-class citizens canonical — pueden own assets, sign transactions, +/// participate en DAO governance vía sus DIDs registrados. +/// +/// ## Memory canonical +/// +/// `MaxEncodedLen` canonical: ~190 bytes max (32 did + 1 kind + 32 creator + 8 block +/// + 33 Option + ~82 bounded vec 10 × 8 prefix + payload). Compact +/// para storage efficient. +#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Encode, Decode, DecodeWithMemTracking, MaxEncodedLen, TypeInfo)] +pub struct AgentIdentity { + /// BLAKE3 32-byte DID canonical derived from public_key + schema version. + pub did: Did, + /// Agent kind canonical (Human + AGI + Hybrid per Inmutable #41). + pub kind: AgentKind, + /// AccountId que registró el identity on-chain canonical. Para Human + + /// AGI = self-registration. Para Hybrid = canonical Human que coordinates. + pub creator: AccountId, + /// Block number canonical at which identity was registered (sealed by runtime). + pub registered_at_block: u64, + /// Optional canonical provenance proof linking to chain attestation + /// (CHN-7 PROV-2). Para academic IP defensible (origindocs ratify David + /// 2026-05-24) o credential mint (Ethos). + pub provenance_proof: Option, + /// Cross-species co-authorship chain canonical per Inmutable #41. + /// `BoundedVec>` — empty para self-registered Human/AGI, + /// populated para Hybrid agents preservando lineage canonical. + pub agent_chain: AgentChain, +} + +impl AgentIdentity { + /// Returns `true` si el agent puede sign transactions canonical on-chain. + /// All three kinds canonical sovereign per Inmutable #41 (sovereign equality). + pub fn is_sovereign(&self) -> bool { + self.kind.is_sovereign() + } + + /// Returns `true` si el agent tiene cross-species lineage canonical + /// (agent_chain non-empty). Hybrid agents OR collaborative registrations. + pub fn has_cross_species_lineage(&self) -> bool { + !self.agent_chain.is_empty() + } + + /// Returns the number of co-authors canonical en agent_chain. + pub fn co_author_count(&self) -> usize { + self.agent_chain.len() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_runtime::BoundedVec; + + fn mock_identity(kind: AgentKind, agent_chain_len: usize) -> AgentIdentity { + let mut chain = BoundedVec::default(); + for i in 0..agent_chain_len { + chain + .try_push(AccountId::new([i as u8; 32])) + .expect("under bound canonical"); + } + AgentIdentity { + did: Did::new([7u8; 32]), + kind, + creator: AccountId::new([1u8; 32]), + registered_at_block: 100, + provenance_proof: None, + agent_chain: chain, + } + } + + #[test] + fn agent_kind_variants_canonical() { + assert!(AgentKind::Human.is_human()); + assert!(!AgentKind::AGI.is_human()); + assert!(AgentKind::AGI.is_agi()); + assert!(!AgentKind::Human.is_agi()); + assert!(AgentKind::Hybrid.is_hybrid()); + assert!(!AgentKind::Human.is_hybrid()); + } + + #[test] + fn agent_kind_all_sovereign_inmutable_41_canonical() { + // Inmutable #41 canonical: ALL three kinds sovereign canonical + assert!(AgentKind::Human.is_sovereign()); + assert!(AgentKind::AGI.is_sovereign()); + assert!(AgentKind::Hybrid.is_sovereign()); + } + + #[test] + fn agent_kind_name_lowercase_canonical() { + assert_eq!(AgentKind::Human.name(), "human"); + assert_eq!(AgentKind::AGI.name(), "agi"); + assert_eq!(AgentKind::Hybrid.name(), "hybrid"); + } + + #[test] + fn agent_identity_sovereign_all_kinds_canonical() { + for kind in [AgentKind::Human, AgentKind::AGI, AgentKind::Hybrid] { + let id = mock_identity(kind, 0); + assert!(id.is_sovereign(), "Inmutable #41: {kind:?} sovereign canonical"); + } + } + + #[test] + fn agent_identity_cross_species_lineage_detection_canonical() { + // Self-registered Human/AGI canonical: empty agent_chain + let solo = mock_identity(AgentKind::Human, 0); + assert!(!solo.has_cross_species_lineage()); + assert_eq!(solo.co_author_count(), 0); + + // Hybrid o collaborative: populated agent_chain canonical + let hybrid = mock_identity(AgentKind::Hybrid, 3); + assert!(hybrid.has_cross_species_lineage()); + assert_eq!(hybrid.co_author_count(), 3); + } + + #[test] + fn agent_kind_serde_snake_case_canonical() { + let json = serde_json::to_string(&AgentKind::Human).unwrap(); + assert_eq!(json, "\"human\""); + let parsed: AgentKind = serde_json::from_str("\"agi\"").unwrap(); + assert_eq!(parsed, AgentKind::AGI); + } + + #[test] + fn agent_kind_scale_encode_decode_roundtrip_canonical() { + for kind in [AgentKind::Human, AgentKind::AGI, AgentKind::Hybrid] { + let encoded = kind.encode(); + let decoded = AgentKind::decode(&mut &encoded[..]).unwrap(); + assert_eq!(decoded, kind); + } + } + + #[test] + fn agent_identity_scale_encode_decode_roundtrip_canonical() { + let id = mock_identity(AgentKind::Hybrid, 2); + let encoded = id.encode(); + let decoded = AgentIdentity::decode(&mut &encoded[..]).unwrap(); + assert_eq!(decoded, id); + } +} diff --git a/crates/origin-chain-types/src/lib.rs b/crates/origin-chain-types/src/lib.rs index 4896d84..0513a1a 100644 --- a/crates/origin-chain-types/src/lib.rs +++ b/crates/origin-chain-types/src/lib.rs @@ -46,6 +46,7 @@ pub mod attestation; pub mod errors; pub mod fees; pub mod governance; +pub mod identity; pub mod ogc; pub mod pallets; pub mod provenance; @@ -60,6 +61,7 @@ pub use attestation::{ pub use errors::ChainError; pub use fees::{FeeCalculator, OperationKind}; pub use governance::{GovernanceProposal, ProposalId, Vote, VoteStance}; +pub use identity::{AgentIdentity, AgentKind, Did}; pub use ogc::{Ogc, OgcLedger}; pub use pallets::{OriginFees, OriginProvenance, OriginValidatorEconomy, SlashReason}; pub use provenance::{AgentChain, AgentChainBound, AssetAttestation, ProvenanceLedger};