feat(agent-identity): v0.0.26 — register_agent_did impl complete + mock runtime integration tests E2E (10 scenarios)

Phase 2.7 AGENT IDENTITY pallet REAL IMPL canonical. Full 8-step CHN-7 flow
canonical register_agent_did dispatchable + storage assertions + Inmutable #41
Cross-Species Co-authorship enforcement compile-detect. Mock runtime + 10
integration tests E2E pattern v0.0.18 + v0.0.22 mirror.

## Real impl canonical 8-step CHN-7

1. ensure_signed(origin)
2. Idempotency check (!Identities::contains_key(&who))
3. Derive DID canonical via derive_did(public_key) BLAKE3 (Inmutable #16)
4. DID collision check (!DidToAccount::contains_key(&did))
5. Build AgentChain BoundedVec from co_authors_raw Vec<[u8;32]> (overflow → AgentChainOverflow)
6. Inmutable #41 enforce: Hybrid requires non-empty agent_chain
7. Storage insert: Identities + DidToAccount reverse lookup
8. Emit AgentRegistered + AgentBound (if cross-species)

Pure helper Pallet::<T>::query_identity_of() para Runtime API v0.0.27.

## 10 integration tests E2E canonical

- scenario_1: Human self-registration → ok + DID + empty chain
- scenario_2: AGI self-registration → ok + Inmutable #41 sovereign
- scenario_3: Hybrid + 2 co-authors → ok + AgentBound emitted
- scenario_4: Hybrid + empty chain → Err::HybridRequiresAgentChain
- scenario_5: duplicate account → Err::AlreadyRegistered
- scenario_6: same pubkey diff account → Err::DidAlreadyTaken
- scenario_7: 11 co-authors → Err::AgentChainOverflow (ConstU32<10>)
- scenario_8: DID → Account reverse lookup canonical
- scenario_9: Human + AGI both is_sovereign() (Inmutable #41 lobo blanco)
- scenario_10: 8-step CHN-7 walkthrough explicit Pre/Post assertions

## Files

- EDIT: crates/origin-chain-agent-identity/src/lib.rs (real impl 8-step + query_identity_of helper)
- NEW: crates/origin-chain-agent-identity/src/mock.rs (80 LOC mock runtime)
- NEW: crates/origin-chain-agent-identity/src/tests_integration.rs (310 LOC, 10 tests)
- EDIT: CHANGELOG.md (v0.0.26 entry comprehensive)

## Verification

- cargo test -p origin-chain-agent-identity — 16 tests verde canonical, 0 failures
  (10 integration + 4 standalone + 2 auto-generated)

🛠️ Phase 2.7 real impl canonical. Runtime API v0.0.27 next ship → Phase 2.7 COMPLETE.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
davidherranandClaude Opus 4.7 committed 2026-05-25 06:43:14 -05:00
1 parent 46a0188a1d
commit 2fefe4cf51
4 files changed
+533 -17

No files matched your search

+91 -17
View File
@@ -102,9 +102,11 @@ sp_api::decl_runtime_apis! {
#[frame_support::pallet]
pub mod pallet {
use alloc::vec::Vec;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use origin_chain_types::{AgentIdentity, AgentKind, Did};
use origin_chain_types::{AccountId, AgentChain, AgentIdentity, AgentKind, Did};
use sp_runtime::traits::SaturatedConversion;
/// Pallet configuration trait canonical.
///
@@ -197,47 +199,119 @@ pub mod pallet {
HybridRequiresAgentChain,
}
/// Dispatchables canonical (scaffold v0.0.24 — real impl v0.0.26).
/// Dispatchables canonical (real impl v0.0.26).
#[pallet::call]
impl<T: Config> Pallet<T> {
/// CHN-7 canonical: `register_agent_did` scaffold dispatchable.
/// CHN-7 canonical: `register_agent_did` real dispatchable canonical.
///
/// **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.
/// **Real impl v0.0.26**: Full 8-step canonical flow + storage assertions
/// end-to-end + Inmutable #41 Cross-Species Co-authorship verification
/// compile-detect.
///
/// Flow canonical 6-step per CHN-7 (v0.0.26 real):
/// Flow canonical 8-step per CHN-7:
/// 1. `ensure_signed(origin)` canonical
/// 2. Validate `!Identities::contains_key(who)` (no duplicate)
/// 2. Idempotency check: `!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)
/// 4. DID collision check: `!DidToAccount::contains_key(&did)` (no collision)
/// 5. Build `AgentChain` canonical `BoundedVec` (overflow → `AgentChainOverflow`)
/// 6. Inmutable #41 enforce: Hybrid requires non-empty agent_chain
/// 7. Insert storage canonical: `Identities` + `DidToAccount`
/// 8. Emit `AgentRegistered` + `AgentBound` (if cross-species) canonical
#[pallet::call_index(0)]
#[pallet::weight(Weight::from_parts(10_000, 0))]
pub fn register_agent_did(
origin: OriginFor<T>,
_public_key: [u8; 32],
public_key: [u8; 32],
kind: AgentKind,
co_authors_raw: Vec<[u8; 32]>,
) -> DispatchResult {
// Verify origin canonical signed.
// Step 1: ensure origin signed canonical
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.
// Step 2: idempotency check canonical (no duplicate registration)
ensure!(
!Identities::<T>::contains_key(&who),
Error::<T>::AlreadyRegistered
);
// Step 3: derive DID canonical via BLAKE3 (Inmutable #16 byte-determinism)
let did = crate::derive_did(&public_key);
// Step 4: DID collision check canonical
ensure!(
!DidToAccount::<T>::contains_key(did),
Error::<T>::DidAlreadyTaken
);
// Step 5: build AgentChain canonical BoundedVec<AccountId, ConstU32<10>>
let mut agent_chain = AgentChain::default();
for raw in co_authors_raw {
agent_chain
.try_push(AccountId::new(raw))
.map_err(|_| Error::<T>::AgentChainOverflow)?;
}
// Step 6: Inmutable #41 canonical enforce — Hybrid requires non-empty agent_chain
if matches!(kind, AgentKind::Hybrid) && agent_chain.is_empty() {
return Err(Error::<T>::HybridRequiresAgentChain.into());
}
// Step 7: build AgentIdentity struct + insert storage canonical
let has_cross_species = !agent_chain.is_empty();
let co_author_count = agent_chain.len() as u32;
let creator = AccountId::new(public_key);
let block_number: u64 = <frame_system::Pallet<T>>::block_number()
.saturated_into::<u64>();
let identity = AgentIdentity {
did,
kind,
creator,
registered_at_block: block_number,
provenance_proof: None,
agent_chain,
};
Identities::<T>::insert(&who, identity);
DidToAccount::<T>::insert(did, &who);
// Step 8: emit events canonical
Self::deposit_event(Event::AgentRegistered {
account: who,
did: origin_chain_types::AssetHash::new([0u8; 32]), // placeholder until v0.0.26
account: who.clone(),
did,
kind,
});
if has_cross_species {
Self::deposit_event(Event::AgentBound {
account: who,
co_author_count,
});
}
Ok(())
}
}
/// Pure helper canonical para Runtime API v0.0.27 consumer.
impl<T: Config> Pallet<T> {
/// Query identity canonical sin storage mutation (read-only canonical).
pub fn query_identity_of(account: &T::AccountId) -> Option<AgentIdentity> {
Identities::<T>::get(account)
}
}
}
extern crate alloc;
// v0.0.26 — Mock runtime canonical + integration tests E2E CHN-7 flow.
// Pattern v0.0.18 (Provenance) + v0.0.22 (Fees) mirror.
#[cfg(test)]
pub mod mock;
#[cfg(test)]
mod tests_integration;
#[cfg(test)]
mod tests {
use super::*;