Prompt T-3 — Firma did:web del DPP (capa de credenciales verificables)¶
Arte Taxco / ICEDE-USC · 1 Ago 2026 · prompt acotado para el chat de código.
Paridad con PROMPT-T0-PERFIL-TEXTIL.md y PROMPT-T1-ESQUELETO-TEXTIL.md.
Alcance de este chat. SOLO la firma
did:webde lo que el DPP ya emite: emisor único (Arte Taxco), Ed25519 + JWS, VCs por atributo, y verificación de vuelta contra el documento DID servido por HTTPS. Es la fase T-3(a) deRUTA-DEMOSTRADOR-TEXTIL.md. NO hace la conformidad EN completa (EN 18219/18216/18222, PDF/A-3 estricto) ni los DIDs por-actor — eso queda fuera (§ FUERA DE ALCANCE), igual que T-1 acotó su alcance.
Eres el asistente técnico del proyecto Arte Taxco. Antes de tocar nada, LEE en este orden:
- docs/SYSTEM-PROMPT.md, docs/FIXES.md (reglas de trabajo; español; aditivo; NUNCA prisma migrate dev)
- docs/DECISIONES-INTEROPERABILIDAD-DPP.md → Q4 (la decisión ya tomada: did:web v1
anclado por HTTPS/DNS, sin blockchain, faseado; AT firma; DIDs por-actor = después)
- docs/RUTA-DEMOSTRADOR-TEXTIL.md (la ruta; T-3 es "Conformidad EN" — este chat es su
primer trozo: la firma did:web)
- docs/MAPA-ECOSISTEMA-DPP.md (VC/firmas como transversal; gate anti-sobreafirmación)
- docs/ARQUITECTURA-DPP-CADENA-PROPIEDAD.md (cada registro = una claim firmable / VC-ready)
- apps/web/lib/dpp/atributos.ts (AtributoVista, Estatus ya con ATESTADO, PERFILES)
- apps/web/lib/dpp/atestacion.ts (write-path T-1 registrarAtributoAtestado — dónde firmar)
- apps/web/lib/dpp/export.ts (dónde se emite el DPP: XML/EPCIS/PDF)
- apps/web/app/api/dpp/[folio]/route.ts (endpoint de export — para añadir f=vc)
- apps/web/public/dpp/dpp-1.0.xsd (para extender el XSD de forma aditiva)
- el modelo AtributoDPP y el enum EstatusAtributo en apps/web/prisma/schema.prisma
CONTEXTO: T-0 dio el perfil textil (nivelExigido por atributo) y T-1 la cadena de
atestación (CONFECCION/MARCA escriben AtributoDPP con emisorRol y estatus acotado:
ATESTADO para hechos de cadena, DECLARADO para el resto). Hoy el DPP se emite en
XML/EPCIS/PDF con el estatus y el emisor por atributo, pero sin firma: un tercero no
puede probar criptográficamente que ese registro lo emitió Arte Taxco y no fue alterado.
T-3(a) añade esa capa: una identidad did:web de Arte Taxco y una firma por atributo
(Verifiable Credential), verificable resolviendo el DID por HTTPS. Es lo que convierte el
"atestado por CONFECCION" de T-1 en una claim verificable por máquina.
REGLA DE HONESTIDAD (la línea roja de todo el proyecto): la firma prueba (a) integridad
del registro y (b) identidad del emisor (la plataforma Arte Taxco) — NO la veracidad del
hecho atestado. Un DECLARADO firmado sigue siendo declarado; el gap
nivelExigido↔estatus sigue visible. Firmar NO sube el estatus. Y v1 = un solo emisor
(AT); que cada operador firme con su propia llave (DID por-actor) es incremento posterior.
TAREA T-3(a) — en pasos, cada uno con su commit:
0) DEPENDENCIA Y SUITE DE FIRMA. Añade jose a apps/web (JWS puro, sin binarios nativos).
Suite: Ed25519 (EdDSA) + JWS compacto. Decisión documentada: JWS (no W3C Data
Integrity/JSON-LD) en v1 — se verifica resolviendo did:web por HTTPS, sin
canonicalización RDF. Data Integrity queda como incremento posterior.
1) IDENTIDAD did:web (documento DID).
- Script one-off scripts/generar-clave-didweb.ts: genera UNA vez el par Ed25519 e
imprime la JWK pública y la privada. La privada NUNCA se commitea — va a env
(DIDWEB_PRIVATE_JWK en .env local + Vercel). La pública a DIDWEB_PUBLIC_JWK.
- Ruta app/.well-known/did.json/route.ts (GET) que sirve el DID Document:
id: did:web:certificados.artetaxco.mx, un verificationMethod con la JWK pública
(leída de env), assertionMethod apuntando a esa clave. did:web:certificados.
artetaxco.mx resuelve por spec a https://certificados.artetaxco.mx/.well-known/did.json.
- DECISIÓN A RESOLVER (recomendación incluida): el dominio del DID. Q4 dice "anclado en
artetaxco.mx", pero ese dominio es Shopify y no sirve /.well-known arbitrario; la app
Next que emite el DPP vive en certificados.artetaxco.mx. Recomendado:
did:web:certificados.artetaxco.mx. Documenta la divergencia con Q4 y su razón.
2) PRIMITIVA DE FIRMA — punto único lib/dpp/firma.ts:
- firmarClaim(payload): Promise<string> → JWS compacto EdDSA, kid = did:web:…#key-1.
- verificarClaim(jws): Promise<payload|null> → resuelve la clave pública (de env o del
did.json) y valida firma + expiración. Nunca lanza en verificación fallida: devuelve null.
3) FIRMAR CADA AtributoDPP COMO VC. Construye una VC mínima por atributo
(issuer = did:web AT, credentialSubject = {folio, clave, valor, estatus,
nivelExigido, emisorRol}, issuanceDate) y fírmala → guarda el JWS.
- Almacenamiento aditivo (prisma db push, NUNCA migrate dev): columnas nuevas
pruebaJws String? y firmadoEn DateTime? en AtributoDPP.
- Cablea la firma dentro de registrarAtributoAtestado (best-effort, como el bloque
epistémico de verificarOferta: si falla, NO rompe la escritura del atributo).
- Script scripts/backfill-firmas-didweb.ts (--dry-run/--limit) para firmar los
atributos ya persistidos (incluida la prenda demo ATA-DEMO-TEXTIL-T1).
- Comentario anti-sobreafirmación: la firma NO altera estatus ni nivelExigido.
4) EMITIR LA FIRMA + VERIFICAR.
- Export: en f=xml, por atributo firmado, un <Prueba tipo="JWS-EdDSA" did="did:web:…"/>
con el JWS; extiende AtributoType en el XSD de forma aditiva (atributo/elemento
opcional → documentos previos siguen válidos; xmllint --schema en verde).
- Nuevo formato f=vc en app/api/dpp/[folio]/route.ts: devuelve las VCs firmadas (JSON)
de esa pieza.
- scripts/verificar-didweb.ts <folio>: resuelve el did.json servido, verifica cada
JWS, reporta válidas/inválidas y demuestra que manipular un valor invalida la firma.
5) VERIFICACIÓN END-TO-END de la prenda demo: firma sus 6 atributos (backfill), sirve el
did.json, y corre verificar-didweb.ts ATA-DEMO-TEXTIL-T1 → todas válidas; altera un
valor a mano y comprueba que la verificación falla.
RESTRICCIONES DURAS:
- 100% aditivo. Enum/columnas nuevas: npx prisma db push, NUNCA migrate dev. (Recuerda
el gotcha de red 5432; si está bloqueado, aplicar db push desde hotspot con la URL directa.)
- La clave privada NUNCA en el repo — solo env (.env local + Vercel). El .env no se
toca salvo AÑADIR las dos claves nuevas (comentar, nunca borrar variables).
- No toques joyería, PERFILES.joyeria, ni el flujo de recertificación (verificarOferta)
salvo lo mínimo para adjuntar la firma.
- Anti-sobreafirmación: la firma prueba integridad + emisor, NO veracidad; el gap
nivelExigido↔estatus sigue visible; v1 = un solo emisor (AT).
- Español en código, comentarios y commits. Documenta en docs/FIXES.md
(sugerido FEAT-DPP-TEXTIL-T3-001) y anota la decisión de dominio del DID en
DECISIONES-INTEROPERABILIDAD-DPP.md (cierre de Q4-firmas v1).
CRITERIO DE ACEPTACIÓN:
- npx tsc --noEmit → 0 errores (el proyecto está en 0; mantenerlo).
- GET /.well-known/did.json sirve un DID Document válido con la clave pública de AT.
- Las VCs de la prenda demo ATA-DEMO-TEXTIL-T1 verifican contra ese DID (script en
verde); alterar cualquier valor invalida la firma.
- El export f=xml lleva la <Prueba> por atributo firmado y valida con xmllint
--schema; f=vc devuelve las VCs. Joyería y recertificación intactos.
- MUÉSTRAME EL DIFF ANTES DE HACER PUSH. Dame el comando de commit explícito, en español.
FUERA DE ALCANCE (son T-3 posteriores u otras fases — NO los hagas aquí):
- DIDs por-actor (cada operador firma con su propia llave) — v2 de firmas.
- W3C Data Integrity / JSON-LD (proof eddsa-rdfc-2022) — alternativa al JWS, después.
- EN 18219 (GS1 Digital Link), EN 18216/18222 (API contra norma), PDF/A-3 estricto
(XMP + OutputIntent) — el resto de la conformidad EN de T-3.
- eIDAS/EUDI wallet, revocación/estado de credencial, blockchain, timestamping externo.
- Laboratorio (T-2), endpoint de la planta de clasificación (T-4), empresas reales.
Decisiones (resueltas para este chat)¶
- Suite → Ed25519 + JWS compacto (lib
jose). Verificable condid:webpor HTTPS, sin deps nativas ni canonicalización RDF. Data Integrity = incremento posterior. - Un solo emisor (AT) en v1. DIDs por-actor diferidos (Q4). AT firma el REGISTRO de cada
atributo; el
emisorRoldel operador viaja DENTRO de la VC como dato, no como firmante. - Dominio del DID →
did:web:certificados.artetaxco.mx(la app Next sirve/.well-known/did.json;artetaxco.mxes Shopify y no puede). Divergencia documentada de la letra de Q4, fiel a su intención (anclaje HTTPS/DNS, bajo-ops). - Prenda de prueba → la demo T-1 ya sembrada (
ATA-DEMO-TEXTIL-T1), reutilizada como banco de pruebas de la firma.
Arte Taxco / ICEDE-USC · Prompt T-3(a) firma did:web · 1 Ago 2026 · alcance, no implementación. Deriva de RUTA-DEMOSTRADOR-TEXTIL.md (T-3) y cierra Q4-firmas v1.