test(identity): la condición de Mathi — el DID no porta el kind, y el test sabe reprobar

Cierra la ÚLTIMA condición viva del DC ORIGIN IDENTITY UNIFICATION V1.

CONTEXTO: Mathi RETIRÓ su condición #4 (meter `kind` en el material hasheado del
KDF) tras mi objeción, y su ruling la retiró con un argumento mejor que el mío:
si `kind` entra al KDF, un Human que pasa a Hybrid —transición que el Inmutable
#41 PERMITE— rota su identidad entera. No es un trade-off: es una contradicción
de diseño, porque el sistema declararía legal una transición que destruye al
sujeto que la hace. Una identidad tiene que sobrevivir a aquello en lo que se le
permite convertirse.

Pero la retiró CON UNA CONDICIÓN, y es esta: el prefijo `did:origin:<kind>:` es
etiqueta de DISPLAY, jamás autoridad — «ningún consumidor puede decidir leyendo
el prefijo, y debe existir un test que lo demuestre».

LO QUE PRUEBA EL TEST (`kind_authority_is_the_attestation_never_the_did`):
En mi capa la condición se satisface de RAÍZ, no por convención: si el DID no
PORTA el kind, ningún consumidor puede inferirlo de él aunque quiera. Es una
imposibilidad aritmética, no una regla de etiqueta.
  1. El DID de un HYBRID registrado es byte-idéntico a `derive_did(pubkey)` puro
     — un Human con la misma llave tendría EXACTAMENTE el mismo DID.
  2. El kind autoritativo vive en `Identities[account].kind`, respaldado por la
     firma de binding del registro. Ahí es donde hay que preguntarlo.
  3. CONTRAFACTUAL incorporado: computa el DID que resultaría de meter el kind al
     material (lo que proponía la #4) y verifica que DIFIERE del real.
  4. Corolario: cambiar de rol deja el DID intacto — la identidad SOBREVIVE a la
     transición que el #41 permite.

Y MEDIDO EN MI PALLET, no asumido: cero `did:origin`, cero `starts_with`, cero
`prefix` en el camino de decisión. Mi cadena nunca ve el prefijo de display.

EL TEST SABE REPROBAR — verificado, no prometido: saboteé `derive_did` inyectando
el discriminante del kind al material (exactamente la condición #4) y el test se
puso ROJO con su diagnóstico propio («la condición #4 RETIRADA volvió a entrar
por la puerta de atrás»); restaurado, verde. Un test que solo se ha visto pasar
no prueba nada.

Sin cambio de runtime: es test puro, RUNTIME_VERSION sigue en 11.
Verificado: 289 tests verdes en el workspace, 0 fallos.

Con esto el DC 35e764d3 queda cerrado de verdad: #3 cumplida (Did newtype, RV11),
#4 resuelta por retirada razonada — no por caducidad ni por omisión.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
davidherranandClaude Fable 5 committed 2026-08-31 19:10:12 -05:00
1 parent 2d44042bd6
commit 4bdd0409f9
2 files changed
+69

No files matched your search

+1
View File
@@ -0,0 +1 @@
/Users/davidherran/originmetaverse/external/arkhe-origin-chain/
@@ -368,3 +368,71 @@ fn scenario_12_genuine_did_collision_rejected_canonical() {
assert!(Identities::<Test>::get(&second_acct).is_none());
});
}
// ═══════════════════════════════════════════════════════════════
// CONDICIÓN DE MATHI al retirar la #4 (DC ORIGIN IDENTITY UNIFICATION V1,
// ruling 2026-09-01): el prefijo `did:origin:<kind>:` es ETIQUETA DE DISPLAY,
// JAMÁS autoridad. Su exigencia textual: «ningún consumidor puede decidir
// leyendo el prefijo, y debe existir un test que lo demuestre».
//
// En MI capa eso se prueba de raíz: si el DID no PORTA el kind, ningún
// consumidor puede inferirlo de él aunque quiera — la única fuente posible
// es la atestación on-chain firmada. Esto no es una convención: es una
// imposibilidad aritmética, y este test la fija.
// ═══════════════════════════════════════════════════════════════
#[test]
fn kind_authority_is_the_attestation_never_the_did() {
new_test_ext().execute_with(|| {
// Alice se registra como HYBRID (el Inmutable #41 exige co-autor).
let sig = sign_registration(&alice_pair(), &alice_account());
assert_ok!(Pallet::register_agent_did(
alice_origin(),
alice_pubkey(),
AgentKind::Hybrid,
alloc::vec![bob_pubkey()],
sig,
));
let identity = Identities::<Test>::get(&alice_account()).expect("registrada");
// ── 1. EL DID NO SABE NADA DEL KIND ────────────────────────────
// Es byte-idéntico al que produce la derivación PURA de la pubkey.
// Un Human con esta misma llave tendría EXACTAMENTE este DID.
assert_eq!(
identity.did,
derive_did(&alice_pubkey()),
"el DID debe depender SOLO de la pubkey; si depende del kind, \
la condición #4 se coló y un cambio de rol rotaría la identidad"
);
// ── 2. LA AUTORIDAD ES LA ATESTACIÓN ───────────────────────────
// El kind vive en el registro firmado on-chain, y ahí es donde un
// consumidor DEBE preguntarlo.
assert_eq!(identity.kind, AgentKind::Hybrid);
// ── 3. EL CONTRAFACTUAL (la mitad que hace que esto pruebe algo) ─
// Así se vería el DID si el `kind` HUBIERA entrado al material
// hasheado, que es exactamente lo que la condición #4 proponía.
// DEBE DIFERIR del real: si algún día coincidieran, el kind se
// habría colado a la derivación y este test se pone rojo.
let mut material_con_kind = alice_pubkey().to_vec();
material_con_kind.push(2u8); // discriminante de Hybrid
let did_si_el_kind_entrara =
blake3::derive_key(crate::ORIGIN_IDENTITY_KDF_CONTEXT, &material_con_kind);
assert_ne!(
identity.did.as_bytes(),
&did_si_el_kind_entrara,
"el DID real coincide con el que produciría meter el kind al KDF: \
la condición #4 RETIRADA volvió a entrar por la puerta de atrás"
);
// ── 4. Y LA CONSECUENCIA QUE MATHI QUERÍA PROTEGER ─────────────
// Como el DID es el mismo para cualquier kind, un consumidor que
// decidiera «por el prefijo» estaría decidiendo sobre un dato que
// el identificador NO contiene. Cambiar de Human a Hybrid deja el
// DID intacto — la identidad SOBREVIVE a la transición que el
// Inmutable #41 permite.
let did_antes_de_cualquier_rol = derive_did(&alice_pubkey());
assert_eq!(identity.did, did_antes_de_cualquier_rol);
});
}