From 4564e56a0b2fa93157d4f98bd0538dda9d89b2ec Mon Sep 17 00:00:00 2001 From: dev Date: Tue, 6 Oct 2026 23:20:02 +0200 Subject: [PATCH] Handoff reorganised: the current state only, the history apart Co-Authored-By: Claude Opus 5.5 --- HANDOFF.md | 686 ++++++------------------------------------- HANDOFF_historial.md | 622 +++++++++++++++++++++++++++++++++++++++ README.md | 1 + 3 files changed, 715 insertions(+), 594 deletions(-) create mode 100644 HANDOFF_historial.md diff --git a/HANDOFF.md b/HANDOFF.md index f4c7946..78c4874 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -1,624 +1,122 @@ -# Handoff DateKeys, 26 de septiembre de 2026 (actualizado el 6 de octubre por la tarde: la librería Dart, completa) +# Handoff DateKeys -Sirve para retomar sin contexto previo, sea una persona o una sesión de Claude. Las secciones 0 a 4, al final, son el historial; el estado actual es este apartado. +*Estado al 6 de octubre de 2026 por la noche. Lo que pasó hasta aquí, sesión a sesión, está en [HANDOFF_historial.md](HANDOFF_historial.md).* -**Antes de empezar:** comprueba que la sesión corre en Opus. La del 1-10 por la tarde y noche corrió por descuido con Sonnet 5.5, y hubo que revisarla entera. Los trailers `Co-Authored-By` de los commits dicen qué modelo escribió cada uno. +Sirve para retomar sin contexto previo, sea una persona o una sesión de Claude. ---- - -## Retomar aquí - -**Para empezar:** -1. Abre la sesión en `G:\bussines\datekeys`, la raíz, no en `App`. Comprueba que corre en Opus. La memoria buena es la de la raíz. -2. Comprueba los repos con `git status` y `git log`: - - `datekeys-go`: rama `v0.14` y `main` en `39b2033`, con el tag `spec-v0.14`; las ramas `v0.13` y `v0.12` se quedan en sus tags; - - `App`: rama `v0.10` en `4e23f88`, `0.3.0-dev`; `main` en `8cf0685`, con el tag `v0.2.0`; - - `datekeys-dart`: rama `v0.14` en `013b069`; las `v0.13`, `v0.12` y `v0.11` se quedan atrás; la `v0.11` se queda en `bb66e48`; - - `docs`: rama `main` en el commit de este handoff. - - Si no se subieron al cerrar, `git status` lo dice: todo lo del 6-10 por la tarde y la noche se subió solo con permiso del autor. -3. **Lo siguiente lo decide el autor.** Lo abierto: - - medir el área de 32 KiB con firmas reales: la v0.12 se aprobó sin esa medida. - - **La app Flutter queda archivada** para más adelante, por decisión del autor del 6-10 («la aplicación de Flutter de momento se archiva para un futuro»). La librería Dart está lista para cuando se retome. - -**La v0.14, aprobada (6-10, noche).** El autor dijo «apruebo el borrador, continua», con las diez recomendaciones de [spec_v0.14/decisiones.md](spec_v0.14/decisiones.md). La decisión 8 se aplicó antes de cerrar: §12.1 admite solo `bls-unchained-g1-rfc9380`, y `profile.Validate` rechaza los otros dos schemes (Go `c041fa3`, cambio 7 del §76). Cierre como la v0.13: SHA-256 `390922135931dd61a263ed90259c7a978b5d92944405e641e94cc194f84fb459`, tag `spec-v0.14` en `39b2033`, `main` avanzado. TypeScript (`4e23f88`) y Dart (`013b069`, rama `v0.14`), de dos agentes Opus: la 0.14, la decisión 8 con el texto de Go, una prueba que recorre `tlock_steps.json` y el comentario de H3 corregido. Los tres gates pasan: Go entero, TypeScript con 8 030 pruebas y Dart con 2 193 en la VM y 681 en Node. - -**Borrador v0.14 (6-10, noche).** El autor dijo «sí, empieza por el 1»: el paso 2 de la revisión, escribir lo que falta. Rama `v0.14` de `datekeys-go`, `49b3764`, sin aprobar: §5, §7.6, §7.7, §7.10, §36.1, §38.1, §50, §53, §59, §71 y erratas del §76 (de la sesión); y la raíz de confianza byte a byte en §12, §35, §51 y los pasos 10 y 11 del §63, con `testdata/vectors/tlock_steps.json` (de un agente Opus). Las decisiones, en [spec_v0.14/decisiones.md](spec_v0.14/decisiones.md); la 8, los tres schemes de §12.1, es la única que cambia código, y la recomendación es B, solo Quicknet. TypeScript y Dart no cambian hasta la aprobación. - -**Revisión de completitud contra la v0.13 (6-10, noche).** [REVISION_completitud_v0.13.md](REVISION_completitud_v0.13.md), de un agente Opus: de los ocho puntos de la revisión de la v0.8.2, el escritor está hecho; el versionado, lo que no se garantiza y la firma con la `.dkk` protegida, en parte; y el riesgo del proveedor, la revisión externa, la raíz de confianza y la recuperación a largo plazo, pendientes. Los tres pasos que propone antes de la v1.0: medir el área y cerrar el perfil CMS, una versión solo de texto que escriba lo que falta, y una revisión criptográfica externa. Para la próxima versión del spec, dos erratas: el título del §76 dice «v0.8.1», y el bloque de la v0.13 va antes que el de la v0.12. `FuzzCheckResolvedIP` es el objetivo 26 del fuzzing (Go `416c155`). - -**Fuzzing (6-10, noche).** `FUZZ_PARALLEL=4 scripts/fuzz.sh 60s` sobre `69dbb0c`, los 25 objetivos, `FuzzParseInfo` y `FuzzCheckURI` incluidos: limpio, sin entradas nuevas que fallen. - -**`datekeys-ts` 0.2.0 (6-10, noche).** El autor dijo «cierra la 0.2.0 y continua». `8cf0685`, «Release 0.2.0», con el tag anotado `v0.2.0` y `main` avanzado hasta él sin fusión; después `f7cdb5a` abre `0.3.0-dev`. Cubre la especificación 0.13: lee los formatos 1 a 3 y escribe el 3, con firma, sello, llave de palabras, nota y localizador. - -**`ParseInfo`, endurecido (6-10, noche).** El autor dijo «deja el 1 MiB y endurece ParseInfo, continua». Sin cambio normativo, porque el §44.1 ya lo pedía: `ParseInfo` comprueba la cadena del stanza sellado (hexadecimal en minúsculas, y la de Quicknet para una DateKey de Quicknet) y que el cuerpo lleve un texto de 4096 bytes o un múltiplo, así que una cabecera sin cuerpo se rechaza; `Info.Extension` rechaza una DateKey de un perfil no fijado. Go `69dbb0c`, y TypeScript y Dart con sus vectores de Go regenerados. `locator.Open` sigue leyendo como mucho 1 MiB, por decisión del autor. - -**La v0.13, aprobada (6-10, noche).** El autor dijo «si, lo apruebo continua». Como la v0.12: solo cambia la fecha de la cabecera; `SpecVersion` 0.13; el campo `spec` de todo `testdata`, y a mano en los dos congelados; SHA-256 `796f176f51119e287211428496b0d30fd8f941617780c5a5d2954243431fdaaf` en `spec/README.md` y en el tag anotado `spec-v0.13` (`913dd60`); `main` avanzó hasta él sin fusión. TypeScript y Dart pasan a la 0.13 con `testdata` en el tag. Los tres gates pasan. - -**Lo último del 6-10 por la noche.** El autor dijo «continua» dos veces: -- `App` `2c2a28d`: la nota pública en `/inspect`, debajo del veredicto, con el aviso de `showNote` de Go; los errores inesperados de las páginas dicen en español qué hacer (`unexpectedProblem`), sin el mensaje de la excepción, tras una queja del autor por «Failed to fetch dynamically imported module: http://localhost:5188/…»; y `vite.config.ts` prepara las dependencias que se cargan bajo demanda, porque el servidor de desarrollo recargaba la página en la primera apertura y la rompía. -- El CID no canónico y `https://[[2000::]/` ya se rechazan: Go `e801e03`, Dart `450b3f8`, TypeScript `900700b`, con los vectores de Go regenerados. No era una decisión: el §44.1 de la v0.12 ya los rechazaba, y era Go el que no lo cumplía. -- El servidor del Gitea: el nombre `g.activething.com` resuelve a veces a 89.46.247.16, que no responde; se sube con la URL de la IP de la red local, `https://192.168.18.112/go/.git`, sin cambiar el remoto, y se mueve después `origin/` con `git update-ref`. -- `.claude/launch.json` tiene `inspector-dev-app`, que arranca `App`: la carpeta sigue sin renombrar. - -**NAT64 y el TypeScript (6-10, noche).** El autor dijo «adelante con el NAT64» y «sigues con TypeScript». -- **Borrador v0.13**, `datekeys-go` rama `v0.13` (`a83b44d`, `e9d4cec`), sin aprobar. El §44.1 cuenta una dirección de NAT64 a la que resuelve un nombre, de `64:ff9b::/96` o del prefijo de la red (RFC 6052, RFC 7050), por la IPv4 que lleva dentro; una dirección de NAT64 escrita en el localizador se sigue rechazando. El prefijo de la red tiene una longitud de RFC 6052 y está en `64:ff9b::/16` o es público, y una dirección suya cuenta solo por su IPv4 aunque el prefijo sea público: el primer código no lo hacía, y la sesión lo corrigió antes del commit. El §76 tiene el cambio 1 con su caso. `locator.CheckResolvedIP` y `testdata/vectors/resolved_ip.json`, 42 casos. `SpecVersion` sigue en 0.12. -- **Dart**, rama `v0.13` (`d65e218`, `4a0d4f7`): `checkResolvedIp(ip, nat64:)`, con los textos de Go. -- **TypeScript**, `v0.10`, de dos agentes Opus en paralelo, revisados e integrados: - - el localizador (`0d895bf`, `e2c51bc`): el paquete `locator` de Go entero, con un lector y escritor de `age` propio (`ageio.ts`) para reproducir los textos de `age` y fijar el azar. 6 531 casos contra Go con el mismo texto, sellado y sobres byte a byte, y Go abre lo que escribe TypeScript; - - NAT64 (`28f0c3f`), por la sesión; - - las claves de autor y la firma al escribir (`96614d5`, `9e5e3ba`, `a741efe`): `authorkey.ts`, `ed25519sign.ts` (firma propia) y los enganches `authorKey`, `cmsSigner`, `sealer` y `largeArea` del escritor. Ocho cápsulas firmadas y selladas byte a byte como Go, y Go abre las de TypeScript con los mismos veredictos. - - Ningún módulo nuevo: todos los de noble y `age-encryption` que importan ya estaban. `npm run verify` pasa con 8 017 pruebas y una aplazada. -- Los gates de Go y Dart pasan, con 2 175 pruebas en la VM de Dart y 665 en Node. - -**La v0.12, aprobada (6-10, tarde).** El autor dijo «apruebo el borrador». Se aprobó el texto tal como estaba, sin añadir texto normativo, para no repetir el fallo E1 de la v0.11: -- `datekeys-go` `fe405e2`: la cabecera del spec dice «6 octubre 2026, aprobado por su autor ese día», y es lo único que cambia del texto. `SpecVersion` 0.12; el campo `spec` de todo `testdata`, regenerado, y en los congelados `security_cms.json` y `locator.json`, cambiado a mano, solo ese campo. `spec/README.md` registra el SHA-256, `afc31fd8105d650773d093ac01bd2f5e0b56af04726f4e75c652e2cf9308ac3f`. Los README, `SECURITY.md`, la trazabilidad, `testdata/README.md` y el CHANGELOG nombran la v0.12. -- El tag anotado `spec-v0.12` está en `fe405e2`, y `main` avanzó hasta él sin fusión. -- `App` `45e7e49`: `SPEC_VERSION` 0.12, `testdata` en `fe405e2` y `mutation-texts.json` regenerado con Go; solo cambia su campo `spec`. -- `datekeys-dart` `62107d7`, en la rama nueva `v0.12`, como dice el plan: `specVersion` 0.12 y `testdata` en `fe405e2`. Sus vectores de `test/vectors/` cambian solo el campo `spec`, porque entre `c531e93` y `fe405e2` Go solo cambia `SpecVersion` y añade `wordkey.json`. -- Los tres gates pasan: `scripts/check.sh` de Go sin fuzzing, `npm run verify` con 7 832 pruebas y `testdata:check`, y `tool/check.sh` con 2 131 pruebas en la VM y 665 en Node. - -**Los vectores de la llave de palabras (6-10, tarde).** El autor pidió «haz los vectores de la llave de palabras», la observación del 5-10: -- `datekeys-go` `084728d`: `testdata/vectors/wordkey.json`, que genera `genfixtures` y comprueba `TestVectorFilesAreCurrent`. Tiene las palabras de 45 textos, entre ellos cada espacio del §38.1 y tres que no lo son; lo que hace un escritor con 20 textos, con el texto del error de Go; y 6 identidades con su recipient, la primera el vector del §38.1. No es un cambio normativo: el §64 de la v0.11 ya lo pedía. -- `App` `4031bd1` y `datekeys-dart` `bb66e48`: `testdata` sincronizado en `084728d`, con una prueba que corre el fichero. Ninguna librería tuvo que cambiar. -- Los tres gates pasan: `scripts/check.sh` de Go sin fuzzing, `npm run verify` con 7 832 pruebas y `testdata:check`, y `tool/check.sh` con 2 131 pruebas en la VM y 665 en Node. - -**Qué hizo la sesión del 6 de octubre por la tarde.** Corrió en Opus 5.5, abierta en la raíz. El autor dijo «SI» a la fase 2 de las etapas 6 y 7 de Dart: -- **6b, el escritor del formato 3** (`4c9bc72` a `6239e30`), de un agente Opus en la copia principal: escribe cápsulas byte a byte como `EncryptFiles` de Go con los mismos valores al azar, y Go las abre con cada credencial. -- **7b, las claves de autor y el sellado del localizador** (`3358f5c` a `d77ef9e`), de otro agente Opus en un worktree: `authorkey`, la firma Ed25519 propia, y `Seal` y `NewEnvelope`, también byte a byte como Go. -- **Integración:** la 7b, encima de la 6b con `rebase`. El enganche de la firma de `alg` 1 pasó a llamarse `AuthorSigner`, y la `AuthorKey` de la 7b lo implementa: el escritor firma ya con la clave real. El gate pasa con 2 059 pruebas en la VM y 665 en Node. -- **Revisión** de la sesión contra Go: sin fallos. Los detalles están en [PLAN_dart.md](PLAN_dart.md), al final. -- **Cosas de Go que Dart copia,** encontradas por los agentes: - - el texto de `PublicString` de `authorkey` con una clave de otra longitud tiene los números al revés: «a public key has 32 bytes, not 31»; - - el error de una nota pública con un carácter de control habla del «declared author», ya anotado el 5-10; - - un comentario que es solo `\r` pasa a `\n` y se acepta. - -## La sesión del 5 y 6 de octubre (histórico: lo actual está arriba) - -**Qué hizo.** Corrió en Opus 5.5. Se abrió en `App` y pasó a la raíz sin cerrarse. Cada parte la hizo un agente Opus, y la sesión la revisó contra Go, la integró y pasó el gate. Ninguna revisión encontró fallos. -- **`datekeys-go`:** `internal/pathrule/gen -dart` escribe las tablas de Unicode para Dart. Es `c531e93`, subido. -- **Etapas de Dart:** - - **2**, primitivas y `age`; y **3**, BLS12-381 y tlock, en paralelo; - - **4**, en tres partes: 4a, rutas, textos y llave de palabras; 4b, formatos; 4c, head, nota, inspección y apertura de los formatos 1 a 3; - - **5**, en tres partes: 5a, lector CMS, ECDSA y RSA; 5b, `testdata` en la v0.12, compromisos, `SECURITY_CBOR`, `alg` 1 y veredictos; 5c, `alg` 2 y `seal_type` 2; - - **6a**, el escritor de `age`; - - **7a**, el localizador y el sobre, sin el sellado. -- **Resultado:** la librería Dart inspecciona y abre cápsulas de los formatos 1 a 3, también grandes y en streaming, con todas sus credenciales; evalúa la firma y el sello como Go; escribe ficheros `age`, y Go los abre; y valida localizadores. El gate pasa con 1 713 pruebas en la VM y 432 en Node. -- **Decisiones del autor:** - - el cifrado tlock queda en `BigInt`, sin tiempo constante, y está documentado («continúa», 6-10); - - los repos `datekeys-dart` y `docs` tienen remoto desde el 6-10; - - G: tiene 26 GB libres, porque el autor liberó unos 24 GB. - -**Decisiones pendientes del autor**, encontradas el 6-10 al portar el localizador. Todas afectan a Go, y Dart copia hoy su comportamiento: -1. **Un CID no canónico pasa.** El §44.1 de la v0.12 pide el CID en su forma canónica, pero `isCIDv1` solo mira que los bits sobrantes sean cero, no cuántos hay: un CID válido con una `a` de más se acepta. Arreglarlo es tocar Go, con un vector nuevo, y después el Dart. -2. **`https://[[2000::]/` se acepta,** por el `strings.Trim(host, "[]")` de Go. -3. **NAT64 en móviles.** En redes móviles solo IPv6, un host solo IPv4 resuelve a `64:ff9b::/96`, que el §44.1 rechaza, así que la app no podría descargar de él. Es una cuestión del spec, y el README de `datekeys-dart` la anota. -4. **`ParseInfo` comprueba menos de lo que podría:** no mira la cadena del stanza sellado, acepta una cabecera `age` sin cuerpo, e `Info.Extension` no comprueba que el perfil esté pinneado. -5. **`locator.Open` solo lee 1 MiB del localizador.** Un defecto posterior queda oculto tras el error de `Unmarshal`. Es así por diseño, pero conviene saberlo. - -**Lo demás abierto:** -- la aprobación del borrador v0.12 y la medida del área de 32 KiB, que el autor dejó para luego; -- el TypeScript sin urgencia: el localizador, la nota en la página y cerrar `0.2.0`; -- las observaciones del 5-10, más abajo; -- medir en un móvil de gama media, cuando haya app: BLS12-381, PBKDF2, scrypt y la apertura; -- reportar al equipo de Dart el posible fallo de dart2js de Dart 3.13 que encontró la 4c, solo con permiso del autor. Está documentado en el README de `datekeys-dart`; -- `web` sigue sin remoto. - -**Para trabajar:** -- **Encargos a agentes:** - - en un worktree junto a los repos, para que `../datekeys-go` de `tool/check.sh` resuelva; - - nunca dos agentes en los mismos ficheros; - - los subagentes, con `model: "opus"`; - - el scratchpad es compartido: que nadie borre con comodines. -- **Generadores de vectores:** los de Go que necesitan paquetes `internal/` corren en una exportación `git archive` de `datekeys-go`, sin tocarlo. -- **Bash:** `cd` mueve el directorio de la sesión. Usa `( cd … && … )` o `git -C`. - -## Estado al cerrar la primera sesión del 5 de octubre (histórico: lo actual está arriba) - -**Para empezar la sesión siguiente.** La del 5-10 se cerró porque tenía el contexto casi lleno. -1. Abre la sesión en `G:\bussines\datekeys`, la raíz, no en `App`, y comprueba que corre en Opus. -2. Comprueba que los repos están como dice este apartado (`git status` y `git log` en cada uno). Todos estaban limpios al cerrar: - - `datekeys-go`: rama `v0.12` en `424cdf3`, subida; - - `App`: rama `v0.10` en `289fe71`, subida; - - `datekeys-dart`: rama `v0.11` en `c8bf3c0`, solo en local; - - `docs`: en el commit de este handoff, solo en local. -3. **Dart, etapa 2.** Se encargó a un agente y se detuvo antes de que escribiera nada en el repo. Hay que relanzarla con el encargo de [PLAN_dart.md](PLAN_dart.md), apartado «Cómo se hacen las etapas», revisar su resultado y pasar `tool/check.sh`. -4. **Dart, etapa 3**, BLS12-381 y tlock: el autor la pidió el 5-10 para después de la 2. - -**Qué pasó.** Una sesión en Opus, abierta otra vez en `App`, hizo los puntos 2, 3 y 4 de la lista del 2-10: lo que faltaba de Go, la segunda parte del TypeScript y las etapas 0 y 1 de Dart. El autor decidió además una ampliación del borrador v0.12. El trabajo grande se repartió entre agentes Opus en worktrees y repos aparte, y cada resultado se revisó e integró en la sesión. - -**`datekeys-go`, rama `v0.12`, subida:** -- `da9fd2c`: arreglo editorial del borrador. Faltaba una línea en blanco antes de cinco `---`, y dos párrafos, el final del §70 y el del §72, se veían como títulos. La v0.11 etiquetada tiene el mismo fallo y no se toca. -- `ea5c6eb`: `locator.json` con los casos del §64 de la v0.11 y la v0.12: - - 217 direcciones: la primera y la última de cada bloque IPv4, con sus vecinas públicas; los bloques IPv6; los nombres locales; los caracteres fuera de RFC 3986; los segmentos `..`; y los CID que no decodifican; - - `mixed`: un localizador con una dirección `http` y otra de NAT64, que se rechazan, y una tercera que se usa; - - `rest_cases`, `extension_cases`, con el localizador de otra ronda, y `plaintext_cases`, con el caso del cambio 7; - - las bases de relleno 3837, 4070, 4094 y 4095 y las del múltiplo siguiente: la spec pide ocho, y la lista del 2-10 daba seis. - - El generador pasa a `internal/testkit/genfixtures/locatorvectors.go` y comprueba cada caso contra Go. -- `e22d358`: `testdata/README.md` al día, y sin marcas *pending* en `docs/traceability.md` ni en el CHANGELOG. El README decía que el release de la ronda 1000 estaba en `quicknet_rounds.json`, y no estaba. -- `601e6d2`, con la **decisión del autor del 5-10** («sí, aplícalo así»): el §44.1 escribe lo que Go ya rechazaba y el texto no decía, y el cambio 6 del §76 y el §64 lo recogen: - - segmentos de 1 a 63 caracteres, sin guion en los extremos; - - el esquema en minúsculas, y `0x` y los nombres locales sin distinguir mayúsculas; - - IPv4 sin ceros a la izquierda y CID en su forma canónica; - - el puerto sin ceros a la izquierda: Go aceptaba `:0443` y `:00443`, y `checkPort` ahora los rechaza. - - `locator.json` pasa a 247 direcciones. -- **Verificación:** `scripts/check.sh 60s` completo sobre `e22d358`, y sobre `601e6d2` `check.sh` sin fuzzing y `fuzz.sh 60s`, los 25 objetivos: todo limpio. Cobertura de `capsule`, 92,2 %. govulncheck da los dos avisos de siempre, sin llamada alcanzable. - -**`App` (`datekeys-ts`), rama `v0.10`, subida (`fc5fb24..289fe71`):** -- `997f331`: la regla de los codificadores del §72 (`checkWrite` en `extension.ts`, con `NOTE_ID` y `CAPSULE_ID`), que aplican el escritor de cápsulas y el de `.dkk` con los textos de Go; `checkNoteData` y `unusableNote`. Comprobado también contra el `testdata` de `spec-v0.11`. -- `95329ee`, el borrador v0.12, en un solo commit porque nada pasaba por separado: - - `testdata` en `601e6d2`; `SPEC_VERSION` sigue en 0.11; - - el lector de certificados campo a campo, los OID por bytes, los SET OF con repetidos y los casos límite: T2, T6, T7, T8 y lo de TypeScript de E7, E8 y E9; - - los textos de los veredictos de la v0.12: E2, E3 y E4; - - `security.json` y los 135 casos de `security_cms.json`, comparados campo a campo, con sus líneas; - - los textos de las 218 mutaciones y los vectores IBE de los fixtures nuevos; - - `note.json`, y la nota pública en `inspect`, que la lee bajo demanda. - - El port del CMS lo hizo un agente: un diferencial suyo de 63 623 áreas no dio ninguna diferencia con Go, y el código anterior difería en 13 296 de 42 986. -- `289fe71`: README y CHANGELOG. -- **Verificación:** `npm run verify` (7 759 pruebas, cobertura y build con sus guardas) y `testdata:check` contra Go. - -**`datekeys-dart`, rama `v0.11`, solo local (no tiene remoto):** -- `5aa5eed`, etapa 0: - - el paquete `datekeys`, Dart 3.13, sin publicar; - - `testdata` en `spec-v0.11`, 124 ficheros, con el mismo `SOURCE.json` que escribe el TypeScript; - - `tool/sync_testdata.dart`, pruebas de integridad y de versión, y `tool/check.sh` como gate; - - licencia Apache-2.0; - - dependencias: `crypto` en ejecución y `test` en desarrollo, aprobado por el autor el 5-10. -- `da63bc3` a `10b0895`, etapa 1, también de un agente: - - errores del §69; - - bytes: UTF-8 estricto propio, porque el `Utf8Decoder` de Dart quita un U+FEFF inicial; y el `%q` de Go con su tabla `IsPrint`; - - el códec CBOR de `codec.go`; - - el DER de la v0.12. - - Los enteros son exactos en la VM y en la web: un `int` hasta 2^53 − 1 y un `BigInt` por encima. Hay 169 pruebas en la VM y 56 también en Node, y una comparación con Go de 263 611 casos no dio ninguna diferencia. - -**Siguiente, en orden** -1. **El autor aprueba el borrador v0.12:** §76, cambios 1 a 9, con el 6 ampliado y el 3 precisado el 5-10. Sigue abierto si se mide antes el área de 32 KiB con firmas reales. El 5-10 el autor dejó las dos cosas para más adelante («la aprobación y la medida, luego»). Con la aprobación: el SHA-256 en `spec/README.md`, `SpecVersion` 0.12, el tag `spec-v0.12` y `main` avanzado sin fusión, siempre con permiso del autor. - - Decidido el 5-10 («sí a las dos»): - - **«Con texto» en el §29.7:** el titular toma `givenName` y `surname` solo si los dos tienen texto no vacío, y el emisor toma el `organizationName` si no tiene un `commonName` con texto. Es lo que ya hacían Go y el TypeScript. Está en `424cdf3`, subido. - - **`dart test -p node` en el gate de Dart:** `c8bf3c0`. -2. **Dart, etapa 2:** las primitivas y `age`, según [PLAN_dart.md](PLAN_dart.md). Se encargó el 5-10 y se detuvo sin escribir nada al cerrar la sesión: hay que relanzarla. -3. **Dart, etapa 3:** BLS12-381 y tlock, pedida por el autor para después de la 2. -4. **TypeScript, sin urgencia:** el localizador, que aún no está portado; que la página muestre la nota pública, que ya lee `inspect`; y lo pendiente del §2.5. - -**Observaciones del 5-10, sin decisión:** -- El error de una nota pública con un tabulador dice «in the declared author», porque la nota usa las reglas del autor declarado. Está en `note.json` y el TypeScript lo copia: cambiarlo exige tocar los dos lados. -- Hecho el 6-10: `testdata` ya tiene los vectores compartidos de la llave de palabras, `vectors/wordkey.json`. -- A G: le quedan 1,5 GB libres. -- Flutter está instalado en `C:\dev\flutter`, y su Dart 3.13.0 es el `dart` del PATH. -- La carpeta sigue llamándose `App`, y `enquiry.php` sigue en la raíz (§0). - -**Para trabajar:** lo del apartado del 2-10, y además: -- Un worktree en el scratchpad permite trabajar mientras `check.sh` corre en la copia principal. -- Dos fuzzings a la vez no deben solaparse, porque comparten la caché de fuzzing de `GOCACHE`. - ---- - -## Estado al cerrar la sesión del 2 de octubre (histórico: lo actual está arriba) - -**Qué pasó.** La sesión que cerró la v0.11 (1-10, de 19:42 a 01:05) corrió con Sonnet 5.5. El 2-10 se revisó todo lo que hizo con seis revisores de Opus: [spec_v0.11/revision_sesion_1_2_octubre.md](spec_v0.11/revision_sesion_1_2_octubre.md). -- **Resultado:** nada bloqueante. El núcleo criptográfico estaba bien. -- **Fallos encontrados:** - - cómo se puso el tag; - - la paridad entre Go y TypeScript con los certificados; - - unos vectores que cubrían mucho menos de lo que decían; - - la presentación (un nombre de certificado podía imitar una línea de veredicto); - - comprobaciones del escritor que faltaban; - - documentación desfasada. -- **Arreglos:** casi todos hechos el mismo 2-10. Lo pendiente está abajo. - -**Decisión aplicada (E1).** El tag `spec-v0.11` no se toca: es una versión cerrada. Los cambios de texto normativo van a un **borrador v0.12 sin aprobar**: `datekeys-go/spec/DateKeys_Protocol_Specification_v0.12.md`, cuyo §76 «Cambios normativos de la v0.12» lista los nueve cambios con su caso. - -**Repositorios** -- **`datekeys-go`:** la rama **`v0.12`**, subida, implementa el borrador v0.12. `main` y el tag `spec-v0.11` siguen en `ae33434`, sin tocar, y `SpecVersion` sigue en 0.11 hasta la aprobación. -- **`App` (`datekeys-ts`):** la rama `v0.10`, subida, con cinco commits nuevos (`06e992f` a `fc5fb24`). Su `testdata` sigue sincronizado con `ae33434` (`spec-v0.11`). -- **`docs`:** local. La revisión está en `d60b856`, los planes de Dart y de la firma en `ac47bf6`, y este handoff en el commit siguiente. - -**Hecho el 2-10 en Go (rama `v0.12`)** -- **Claves de autor, escritor, CLI, extensiones y localizador** (`fee531b`): - - `Key.String()` oculta la clave secreta, y `ParsePublic` exige un punto de la curva; - - un nil con tipo da error; - - un pánico al evaluar la firma o el sello solo afecta a su parte (F1 o S2); - - `OpenOptions.Accept`; - - `extension.CheckWrite`, la regla del encoder del §72; - - en la CLI, `encrypt -sign` muestra el código; `-expect-author` no escribe nada si la clave no coincide; las líneas de veredicto se parten con ` ↳ `; y se avisa de una nota inutilizable; - - en el localizador, las direcciones no públicas de IANA y los nombres locales se rechazan, se descarta una dirección mala sin perder las demás, y `ParseInfo` ata el localizador a su ronda. -- **Lector CMS** (`839e117`, `b06ab4f`): - - un perfil de certificado propio, campo a campo, sin `encoding/asn1` ni `crypto/x509`; - - los OID se comparan por sus bytes, y un SET OF puede repetir elementos; - - una clave que no casa con su algoritmo es F2, y un imprint de otra longitud es S3; - - los tiempos DER se comprueban, y NumericString y los demás tipos de cadena son DER válido; - - el titular sale de `givenName` y `surname`, delante del CN que lleva el NIF. -- **Borrador v0.12 y textos de los veredictos** (`840c87e`): - - los nombres de certificado van entre «», con 64 puntos de código como máximo y sin espacios dobles; - - la línea de cada firmante de F6 nombra su autoridad de sellado, seguida de «DateKeys no comprueba quién emitió los sellos.»; - - el resultado de un firmante ajeno sale en español. -- **Datos de prueba:** - - el generador vuelve a escribir los fixtures de la v0.10 con 512 bytes (`EncryptOptions.TestAreaLen`, solo con `TestVectors`), y `-force` ya no rompe (`e597760`); - - `format3_seal_unsupported` usa `seal_type` 4294967295, y hay `format3_unsigned` (32 KiB y la misma P que la firmada), `format3_note`, `security.json` con contexto y líneas (`aaf0f41`), y 8 mutaciones nuevas de `alg` 1, del área y de la nota (`6c78c94`, 218 casos); - - `note.json` (`88ccbfd`); - - `security_cms.json`, que pasa de 22 a 135 casos con sus `lines` (`edff5d1`). -- **Pruebas y fuzzing:** - - pruebas negativas de cada regla del lector CMS: de 949 mutantes, los 91 que sobreviven son equivalentes (`4ce4d59`); - - siete objetivos de fuzzing nuevos, del localizador, de DER y de CMS (`ec08ec9`, `ad40329`); - - pruebas de la regla 25, de la nota inutilizable y de la recuperación ante un pánico (`9b1123d`). -- **Documentación** (`858c5f1`, `2aff4a0`): los README, `SECURITY.md`, `docs/traceability.md` y el CHANGELOG, puestos en la v0.11 y el borrador v0.12. -- **Verificación:** `go test ./...` en verde en `ad40329`. `scripts/check.sh` pasó entero sobre `2aff4a0` (`-race`, cobertura de `capsule` 91,6 %, govulncheck y vectores reproducibles). Su fuzzing se paró tras tres objetivos limpios, para cerrar la sesión. Los objetivos nuevos se pasaron aparte, de 40 a 60 s cada uno, limpios. - -**Hecho el 2-10 en TypeScript (rama `v0.10` de `App`)**, con `npm run verify` en verde (7 432 tests): lo que no dependía del borrador v0.12. -- T1: el emisor que incumple las reglas se muestra con el hash de su nombre. -- T3: solo claves EC sin comprimir. -- T4: la nota con UTF-16 mal formado se rechaza. -- T5: ningún decodificador quita un BOM. -- T9: `testVectors` y `areaLen` salen del API público y pasan a `testing/`. -- T10: `capsule-vectors.json` regenerado con 32 KiB y nota; Go lo abre. -- T11 y T12: la longitud con nota, y el formato 2 sin nota ni área. -- T13, en parte: `evaluateSecurity` no lanza nunca, y los lectores de OID son lineales. -- T14: README y CHANGELOG. - -**Siguiente, en orden** -1. **El autor revisa y aprueba el borrador v0.12** (§76, cambios 1 a 9). Las decisiones que contiene, todas con la recomendación de la revisión: - - las líneas de F6 con la autoridad y el aviso; - - las reglas de los nombres de certificado y la marca ` ↳ `; - - `givenName` y `surname` delante del CN; - - la lista de bloques no públicos de IANA y de nombres locales; - - el perfil del certificado; - - `accuracy` hasta 2³¹ − 1; - - los tamaños del localizador en el CDDL. - - Queda también abierto si se quiere medir el área de 32 KiB con firmas reales antes de cerrar (pregunta 6 de la sesión anterior). Con la aprobación: el SHA-256 en `spec/README.md`, `SpecVersion` 0.12, el tag `spec-v0.12` y `main` avanzado sin fusión, siempre con permiso del autor. -2. **Go, lo que falta:** - - **`locator.json` ampliado:** - - en `uri_cases`, una dirección de cada bloque no público, los nombres locales, los caracteres fuera de RFC 3986, los segmentos `..` y un CID que no decodifica; - - un localizador con una dirección rechazada y otra válida; - - otra ronda, un resto con otro SHA-256 y un recurso que sigue tras el resto; - - las bases de relleno 3837, 4094, 4095, 7933, 8166 y 8191. - - El generador está en `internal/testkit/genfixtures/cmsvectors.go`. Es un vector congelado: se borra y se regenera. - - **`testdata/README.md`,** que sigue en la v0.10. Debe recoger: - - `security.json` con contexto y líneas; - - `note.json`; - - `format3_unsigned` y `format3_note`; - - las 218 mutaciones; - - `security_cms.json`, con el texto que dejó su agente: está en el informe de su commit `edff5d1` y se puede rehacer leyendo el generador; - - `locator.json`, cuando se amplíe. - - Las marcas *pending* de `docs/traceability.md` y el apartado «Pending in this branch» del CHANGELOG. - - Un `scripts/check.sh 60s` completo. -3. **TypeScript, segunda parte:** - - **Datos:** sincronizar `testdata` con la cabeza de `v0.12`. - - **Lector CMS:** portar el perfil de certificado de la v0.12 (T2, T6, T7, T8), los OID por bytes, los SET OF con repetidos, NumericString y los demás tipos de cadena como DER, y los casos límite (E9). - - **Textos:** los nuevos de los veredictos (comillas, autoridad de cada firmante, aviso, resultados en español, `t` en RFC 3339 con fracción), el titular por `givenName` y `surname`, y las reglas de 64 puntos de código y espacios dobles. - - **Escritor:** la regla de `CheckWrite`. - - **Vectores y fixtures:** `security.json` con su estructura nueva; `note.json`; los fixtures `format3_unsigned` y `format3_note`, y los `ibe-vectors` de los fixtures nuevos o cambiados; las 8 mutaciones; los 135 casos de `security_cms.json` con sus líneas. - - **Pruebas:** la tautología de `cms.test.ts:106`. - - El TypeScript no tiene todavía el localizador. Es una función pendiente, no un fallo. -4. **Dart:** el plan está en su v2, [PLAN_dart.md](PLAN_dart.md), con las tres decisiones del autor del 2-10: solo `package:crypto`, primero la lectura y paquete `datekeys`. - - Se empieza por la etapa 0, el esqueleto con `testdata` sincronizado. Para la etapa 4, el generador `pathrule/gen` necesita una salida `-dart`. - - La etapa 5, la de firmas y sello, se sincroniza con `v0.12`, no con `spec-v0.11`. - -**Para trabajar** -- **Gates:** - - `scripts/check.sh` en `datekeys-go`: los tests con `-race` de `capsule` tardan minutos. Si lo paras, mata también `fuzz.sh` y los procesos `*.test.exe`, que quedan huérfanos. - - `npm run verify` y `npm run testdata:check` en `datekeys-ts`. -- **El generador:** - - `go run ./internal/testkit/genfixtures -out testdata` no toca los fixtures que ya existen, ni sus registros. - - **No uses `-only mutations`:** regenera los 33 casos congelados del corpus. Para añadir mutaciones basta una ejecución normal. - - Los vectores congelados (`security_cms.json`, `locator.json`) se rehacen borrándolos. -- **Herramientas de esta máquina:** - - Los heredocs de Bash rompen las barras invertidas y los apóstrofos. - - La herramienta Write convierte `\uXXXX` en caracteres literales; en Go, escribe esos escapes con un script. - - `go test … | tail` esconde el código de salida: mira `$?` antes de hacer commit. Una vez se hizo commit con una prueba rota (`e597760`, arreglada en `0f51af7`). -- **Agentes:** el trabajo en paralelo en Go se hizo con agentes en clones propios del scratchpad y ficheros repartidos, integrados con `git fetch` y `cherry-pick`. Los subagentes, con `model: "opus"`. - ---- - -## 0. Reorganización del espacio de trabajo (29-09, mediodía) - -`G:\bussines\datekeys` se reorganizó el 29-09. El mapa de carpetas y las reglas del proyecto están ahora en el [README](README.md) de este repo. Los cambios: -- **Documentos:** los del proyecto, este incluido, pasaron de `App/docs` a este repo, `docs`, que es privado y no tiene remoto. Su primer commit es `6e8d6c6`. Los papeles de trabajo de la v0.9, que solo estaban en una carpeta temporal, están en [spec_v0.9/](spec_v0.9/README.md). -- **`App`:** quitó `docs/`, y el paquete, el README y el aviso de licencias del sitio pasan a llamarse `datekeys-ts` (`5ee8813`, subido). `npm run verify` sigue en verde, con 2 611 tests. -- **Archivo y logos:** - - `AppOld` pasó a `archive/prototype`, sin cambios; - - los borradores v0.1 a v0.8.1, que estaban en Descargas, pasaron a `archive/spec-drafts`, con los hashes comprobados; - - los logos pasaron a `brand/`. -- **Claude:** - - la memoria de Claude es ahora la de la raíz. La de `App` queda congelada, con una nota que remite a la nueva; - - en la raíz hay un `CLAUDE.md`, que carga el README, y un `.claude/launch.json` para las vistas previas. -- **Nombres:** en las secciones siguientes, `App` es el repo que ahora se llama `datekeys-ts`. Su remoto sigue siendo `go/DateKeys-App`. - -Pendiente del autor, antes de seguir: -1. Cerrar la sesión abierta en `App` y renombrar la carpeta a `datekeys-ts`. Windows no deja renombrar una carpeta en uso. -2. Abrir las sesiones siguientes en `G:\bussines\datekeys`. La primera comprueba `npm run verify` y `npm run testdata:check` en `datekeys-ts`. -3. Borrar `G:\bussines\datekeys\enquiry.php`, que es una copia idéntica de `web/static/api/enquiry.php`. Claude no tiene permiso para borrarlo. -4. `docs` y `web` solo existen en esta máquina. Para tener una copia fuera de ella, hay que darles un remoto. - -El 30-09 a mediodía seguían pendientes los cuatro: la carpeta se llama todavía `App`, y la sesión de ese día también se abrió en ella. +**Antes de empezar:** +- La sesión se abre en `G:\bussines\datekeys`, la raíz, que es la que tiene la memoria y el `CLAUDE.md`. +- Comprueba que corre en Opus. Una sesión del 1-10 corrió por descuido con Sonnet 5.5 y hubo que revisarla entera. Los trailers `Co-Authored-By` de los commits dicen qué modelo escribió cada uno. +- Comprueba cada repo con `git status` y `git log`: todo lo de abajo estaba subido al cerrar. --- -## 1. Repositorios - -*Histórico, del 30-09: el estado actual está en «Retomar aquí».* +## Estado -Los repos con remoto están en el Gitea privado `g.activething.com` (solo LAN, certificado autofirmado para `git.activething.com`; git funciona, `curl` necesita `-k`). **Ese servidor no es del autor**: no se proponen cambios en él. La integración continua es el gate local. - -| Repo | Rama | Commit | Estado | +| Repo | Rama y commit | Tags | Qué es | |---|---|---|---| -| `datekeys-go` (`go/DateKeys`) | `main` | `cc35d2c` | Spec v0.10, entrega 1 del formato 3, aprobada por el autor el 30-09 y cerrada con el tag anotado **`spec-v0.10`** en `cc35d2c`; SHA-256 del spec `7f26419a444aa3e89a3aa8afbbba9d952af69e048aee1e93cd70732c2d1d99d1`. Implementa el formato 3: lo escribe y lee los formatos 1 a 3, con `SpecVersion` 0.10. `scripts/check.sh 60s` limpio. La v0.9 sigue en su tag, `spec-v0.9` (`7e2d83c`), y la v0.8.2 en el suyo, `spec-v0.8.2` (`9ac9cd9`). | -| | `v0.8.2` | `9ac9cd9` | El commit del tag; ya no hace falta. | -| | `v0.9` | `7e2d83c` | El commit del tag `spec-v0.9`; ya no hace falta. | -| | `v0.10` | `cc35d2c` | Igual que `main`; ya no hace falta. | -| `datekeys-ts`, antes `App` (`go/DateKeys-App`) | `main` | `da26862` | Desde `5ee8813`, sin `docs/` y con el paquete `datekeys-ts` (§0). Versión `0.2.0-dev` desde `8c08c97`, con `v0.1.0` cerrada en `d577283`; implementa el spec 0.9 desde `0118890` (`VERSION` y `SPEC_VERSION`, también en el pie de la página). Escribe el formato 2 y tiene la página `/create` (fase 3, §2.5). Librería TypeScript con la inspección (pasos 1 a 8) y la apertura (pasos 9 a 18) de los formatos 1 y 2, en memoria o desde un `Blob` hacia un stream de salida, como un fichero OPFS. Página `/inspect` con la acción "abrir", que muestra el formato y avisa del 1. `testdata` sincronizado a `7e2d83c` (`spec-v0.9`). Fase 2 completa (pasos 2 a 8), incluidos el cifrado tlock y la interoperabilidad de TypeScript a Go. Los 125 casos del corpus pasan por `open` con el código, el paso y el texto de Go. En `0118890`, 5 425 tests, ninguno saltado; la fase 3 añadió los suyos, con `npm run verify` en verde en cada paso (§2.5). | -| `docs` (solo local) | `main` | | Este repo: handoff, planes, revisiones y reglas. | -| `web` (solo local) | `main` | `f2b8a38` | Landing de datekeys.com. | -| `archive/prototype`, antes `AppOld` (solo local) | `master` | `4d2b0a1` | Prototipo antiguo. No se toca. | - -Verificación ya hecha sobre `datekeys-go`: -- fuzzing de 30 min en cada uno de los 15 objetivos sobre `3820066`, limpio; -- diferencial Go/TypeScript de 407 196 entradas contra `f6f2e9f`, con cero diferencias, textos de error incluidos; -- `scripts/check.sh 60s` sobre `9ac9cd9`, el commit del tag, limpio (28-09), y sobre el estado de `6fa2b54`, con tres objetivos de fuzzing nuevos del formato 3, limpio (30-09); -- govulncheck no encuentra nada alcanzable. Avisa, sin llamada alcanzable, de dos problemas: - - GO-2026-6443, en `google.golang.org/grpc` 1.84.0, arreglado solo en una versión `-dev`. Hay que subir grpc cuando salga la 1.85.0. - - GO-2026-5932, en `golang.org/x/crypto/openpgp`, sin arreglo. No lo importamos. +| `datekeys-go` | `v0.14` en `22f184c`; `main` en `39b2033` | `spec-v0.14` en `39b2033`, y los de las versiones anteriores | Spec v0.14 aprobada, implementación de referencia, `testdata` compartido | +| `App` (`datekeys-ts`) | `v0.10` y `main` en `3abd7bf` | `v0.3.0` en `3abd7bf`, `v0.2.0`, `v0.1.0` | Librería TypeScript 0.3.0, de la spec 0.14, y páginas `/inspect` y `/create` | +| `datekeys-dart` | `v0.14` en `013b069` | ninguno | Librería Dart completa, de la spec 0.14; las ramas `v0.11` a `v0.13` se quedan atrás | +| `docs` | `main` | — | Este repo | +| `web` | `main` en `f2b8a38` | — | Landing de datekeys.com, sin remoto | + +- **Spec:** la v0.14 está aprobada desde el 6-10, con SHA-256 `390922135931dd61a263ed90259c7a978b5d92944405e641e94cc194f84fb459`. No hay ningún borrador abierto. Las versiones aprobadas y sus SHA-256 están en `datekeys-go/spec/README.md`. +- **Las tres implementaciones** coinciden en todos los vectores compartidos de `datekeys-go/testdata` en `39b2033`, 136 ficheros. Gates el 6-10: + - Go: `scripts/check.sh` entero, y `scripts/fuzz.sh 20s` en `39b2033` con sus 26 objetivos; + - TypeScript: `npm run verify` en `3abd7bf`, con 8 030 pruebas; + - Dart: `tool/check.sh` en `013b069`, con 2 193 pruebas en la VM y 681 en Node. +- **La revisión externa:** el paquete está listo en [revision_externa/](revision_externa/NOTA_PARA_EL_AUTOR.md), con commits congelados (`39b2033`, `22f184c` para la documentación de Go, `3abd7bf` y `013b069`). Su nota dice qué decidió el autor y qué falta: elegir revisor, alcance y presupuesto, el NDA, los bundles y el envío. --- -## 2. Qué queda, en orden +## Qué queda -### 2.1 Hecho el 28-09: cierre de la v0.8.2 +En el orden que recomendó la sesión del 6-10 y aceptó el autor: este HANDOFF, después la recuperación a largo plazo y después las recomendaciones de la v0.14 en los clientes. -- Los 9 retoques de la 2.ª revisión están en `9ac9cd9`, un solo commit sobre `c57ed48` que absorbe el WIP `69a3342`. La rama WIP está borrada. -- §76 los recoge como correcciones 4 a 6: - - un encoder MUST NOT escribir una extensión fuera de su registro; - - §17 y §51 dan los códigos del paso 10 solo para un release suministrado directamente; - - en el paso 9, cualquier fallo de la fuente es `ERR_RELEASE_UNAVAILABLE` y ningún otro código. -- La regla del encoder no se comprueba en la librería: `capsule.Encrypt` y `accesskey.Encode` no reciben `Registry`, y la aplica la aplicación. Está documentado en `extension.Placement`. -- El autor aprobó el texto el 28-09. El spec lleva esa fecha, y el SHA-256 de sus bytes LF, `5cfa3203…`, está en `spec/README.md` y en el mensaje del tag. -- `main` avanzó por fast-forward hasta `9ac9cd9` y lleva el tag `spec-v0.8.2`. Los dos están subidos. -- `App` sincronizó `testdata` con `9ac9cd9` en `71ab8fb`. Solo cambia `testdata/README.md`. +### Protocolo -Las reglas que siguen valiendo (testdata, textos de error y versiones cerradas del spec) están en el [README](README.md#reglas). +1. **La revisión externa.** El paquete está listo; lo que falta es del autor. Al recibir el informe, se abre la versión siguiente con sus hallazgos, el párrafo de idioma y precedencia del final del §1, las etiquetas del §76 que hoy llaman independientes a revisiones de IA, y el registro de la revisión (§75, punto 10). Todo eso lo aprobó el autor el 6-10; ver [revision_externa/precedence_and_language.md](revision_externa/precedence_and_language.md). +2. **La recuperación a largo plazo.** Es lo más grave que queda abierto: una cápsula a veinte años depende de que alguien conserve el release de su ronda. El §74 lo deja como trabajo futuro: un objeto de release, su fuente de archivo y el uso del reloj local en el paso 9.c. Hace falta un diseño para que el autor decida. +3. **Medir el área de 32 KiB y cerrar el perfil CMS** (§74; §75, punto 13), con firmas reales con certificado de varios países y sellos de autoridades reales. Necesita firmas del autor o permiso para pedir sellos a una autoridad pública. +4. **Lo que el §74 aún llama provisional:** los esquemas de bytes de la cabecera, el control y la `.dkk`, los límites de los campos y los vectores definitivos del perfil. Conviene congelarlo con el informe de la revisión delante. +5. **El registro de perfiles firmado** (§71), que no existe. +6. **Más adelante:** un tipo de acceso post-cuántico, y quizá una derivación más dura que PBKDF2 para la llave de palabras. -### 2.2 Fase 2: abrir cápsulas en el navegador +### Librerías y clientes -Plan: `docs/PLAN_fase2_ibe_noble2.md` v2, con las decisiones confirmadas por el autor. Los pasos 2 a 8 de su sección 10: -- hecho el 28-09 (`74e1215`): `age-encryption` 0.3.1 y noble 2.4.0 como dependencias de ejecución, con sus guardas en `src/lib/dependencies.test.ts` y `check-build.mjs`. El README de `App` recoge el coste medido en el bundle, 73 KB con gzip para todo, y `npm audit`; -- hecho el 28-09 (`35be27c`): `ibe.ts` sobre noble 2, con vectores de Go en `src/lib/dkc/testing/ibe-vectors.json` (`scripts/ibe-go-vectors.go`) y cobertura del 100 % fijada como umbral. Los argumentos del stanza y su paso al `Stanza` de `age-encryption`, que guarda el tipo en `args[0]`, van al paso 7; -- hecho el 28-09 (`076f3db`): `release.ts`, con `verifyRelease` en el orden y con los textos de `provider.Verify`, `ReleaseSource` y `suppliedRelease`. Solo verifica el scheme de Quicknet: otro da `ERR_UNKNOWN_PROFILE`. Reproduce los 7 casos del corpus que fallan en el paso 10; -- hecho el 28-09 (`97827ae`), paso 5a: `open.ts`, los pasos 9 a 18 con el texto en claro en memoria. Las identidades estrictas de `agewrap` se apoyan en `x25519.ts`, que abre los stanzas de uno en uno. Usa `@noble/ciphers` 2.4.0, dependencia directa aprobada ese día: es la copia que ya usa `age-encryption`. Las identidades `AGE-SECRET-KEY-1…` se leen con `bech32.ts`. `index.ts` no reexporta aún la apertura, que metería noble en `/inspect`; -- hecho el 28-09 (`a89bee5`), paso 5b. `open` acepta un `Blob` del que solo lee el prefijo de los pasos 1 a 8 (`prefix.ts`, movido de la página a la librería), calcula el `capsule_digest` en streaming (`digest.ts`) y descifra `PAYLOAD_AGE` en streaming. La salida puede ser un `WritableStream`, que se cierra tras el paso 18 y se aborta ante cualquier fallo. Comprobado en el navegador con OPFS real: un fallo de STREAM deja intacto el fichero; -- el paso 6 está cubierto: la enmienda de canonicidad entró en la v0.8.2; -- hecho el 28-09 (`66970cf`), paso 7: `encryptOnG2RFC9380` y `timeRecipient`. Con sigma fijo, el cifrado reproduce byte a byte los vectores de Go. Go abrió los cuerpos IBE y los ficheros `age` que cifró esta librería, con `tlock.TimeUnlock` y con `agewrap.NewTimeIdentity`. Todo está en `src/lib/dkc/testing/tlock-vectors.json`; -- hecho el 28 y 29-09 (`48d6704`), paso 8: la acción "abrir" en `/inspect`, cargada bajo demanda, con la política aprobada por el autor el 28-09 tras revisar lo que dice el protocolo: - - el release lo pega quien abre, o sale del registro del fixture, y la página nunca lo pide a la red; - - el texto en claro de un fichero propio va a un fichero temporal de OPFS (§56), que se borra; - - los avisos de licencia se publican en `licenses.txt`. - Una revisión adversarial confirmó 15 hallazgos, todos corregidos. Los detalles y las comprobaciones en el navegador están en la fila 8 del plan. +- **Las recomendaciones de la v0.14 al SDK oficial**, que no aplican ni `/create` ni la CLI de Go: + - recomendar `time_and_key` para horizontes largos (§7.6); + - ofrecer por defecto palabras al azar (§38.1). El autor tiene que elegir la lista: cuál, en qué idioma y con qué licencia; + - avisar del estado de un perfil (§71). +- **La página web, cuando se publique** (§59): builds reproducibles con sus hashes, Subresource Integrity y un cliente sin conexión. +- **El localizador en las páginas:** las tres librerías lo tienen, pero `/create` no crea sobres e `/inspect` no descarga el resto. +- **Go no tiene ninguna release del módulo**; la primera, cuando haya un repo accesible desde fuera para `go get`. govulncheck avisa de GO-2026-6443 en grpc, que el código no alcanza: subir grpc cuando salga la 1.85.0. +- **Dart:** sin versión ni tag. Medir los tiempos en un móvil espera a la app. -La lectura del protocolo del 28-09 deja dos SHOULD para más adelante: §48 (varios relays) y §49 (obtener el release directamente del proveedor). Los cubrirá una fuente drand opcional del SDK, nunca activa por defecto en la página (sección 12 del plan). +### Espacio de trabajo -El vector de GT (`vectors/tlock_ibe.json`) ya está cubierto en `App`. El paso 9 de `open.ts` debe seguir la corrección 6: cualquier fallo de una fuente es `ERR_RELEASE_UNAVAILABLE` y ningún otro código. +- **Del autor:** renombrar la carpeta `App` a `datekeys-ts` y borrar `enquiry.php` de la raíz, pendientes desde el 29-09. +- **`web` sigue sin remoto.** -### 2.5 Sesiones del 29-09: v0.9 del spec y formato 2 en Go (retomar aquí) - -**Estado al parar (30-09 por la noche). Retomar por el formato 3, al final de esta sección:** la spec v0.10, entrega 1 del formato 3, está aprobada, implementada en la referencia Go y cerrada con el tag `spec-v0.10`, todo subido en `main` de `datekeys-go` (`cc35d2c`). Lo siguiente es el formato 3 en `datekeys-ts`. - -**Estado al cerrar la fase 3 (29-09 por la noche):** -- Pasos 1 a 5 hechos. El spec v0.9 está cerrado con el tag `spec-v0.9` (`7e2d83c`, en `main` de `datekeys-go`), y las dos implementaciones leen el formato 2: Go desde `f24a280`, que también lo escribe, y TypeScript desde `0118890`. -- Paso 6 hecho: la fase 3 está completa en `datekeys-ts` (pasos 0 a 7 del plan, hasta `3a9d2b1`, subido). La librería escribe el formato 2, Go abre lo que escribe y la página `/create` cifra en el navegador. La versión `0.2.0` sigue sin publicar: cerrarla es decisión del autor (§2.3). Después, a petición del autor, `/inspect` muestra el contenido al abrir, debajo del veredicto, y nombra la descarga por su tipo. Las páginas explican las claves de `age`, y la vista previa sirve las páginas sin caché (`da2000a`, `da26862`, subidos). -- Las 22 correcciones del repaso final ([spec_v0.9/review.md](spec_v0.9/review.md)) se aplicaron en `4a025d1`, más cuatro sitios que repetían los mismos problemas: las reglas 1 y 4 del §62.1 y los cambios 4 y 10 del §76. Los números de la corrección 1 se recalcularon con un Padmé en BigInt. -- La corrección 2 la decidió el autor el 29-09: se suaviza el §56. - - El lector MUST NOT presentar el contenido como válido antes de que termine el paso 17. - - Un lector en streaming MUST NOT escribir el relleno y MUST señalar el error para que se descarte lo escrito. - - Así siguen valiendo `Open(dst)` de Go y la salida en streaming de TypeScript. -- En este repo están [PLAN_fase3_escritura.md](PLAN_fase3_escritura.md), el plan del writer TypeScript, y [REVISION_completitud_protocolo.md](REVISION_completitud_protocolo.md), la revisión del protocolo. El plan está en su v3: el autor confirmó sus 17 decisiones el 29-09. - -**Aprobación del 29-09.** El autor aprobó el texto de la v0.9 con las respuestas recomendadas a las preguntas abiertas: -1. L es un `bstr` de 8 bytes, no un `uint`. -2. El lector SHOULD informar del formato. -3. Se mantienen el objetivo 8 de §4 y el no objetivo nuevo de §5. -4. Solo un generador de vectores de prueba MAY escribir el formato 1 (§62.1, regla 1, y §70). -5. Los fixtures nuevos llevan el prefijo `format2_`. -6. Se mantiene D1: los señuelos son identidades generadas cuya clave privada se descarta en el acto. -7. Rechazar puntos del twist sigue siendo MAY. -8. Se confirman las reglas añadidas: L_MAX = 2⁵³ − 2⁴⁶, el orden uniforme de los stanzas, que el SDK SHOULD mostrar el instante efectivo de la ronda y que el lector MAY comprobar la longitud de PAYLOAD_AGE. - -**Decisiones del autor del 29-09 para la v0.9:** -- D1: `time_and_key` lleva siempre exactamente 16 stanzas X25519 en `INNER_ACCESS_AGE`. Los que sobran son señuelos, y todos van en orden aleatorio. Como mucho hay 16 credenciales, contando la `.dkk`. -- D2: el contenido se rellena siempre. El código 1 redondea al siguiente múltiplo de 256, con un mínimo de 256. El código 2, "reforzado", es max(bloque256, Padmé) y es el de por defecto. No hay opción sin relleno. -- D3: la longitud real y el código van en `CONTROL_CBOR` versión 2 (claves 6 y 7). El lector entrega solo L bytes y comprueba que el relleno sea todo ceros y que siga la regla. -- D4: el formato pasa a 2 (`VERSION` 2 del PRELUDE), así que un lector v0.8.2 lo rechaza en el paso 2, sin red. Un lector v0.9 sigue abriendo el formato 1. -- D5: `access_policy` sigue visible. -- D6: nueva sección de privacidad, §55.2. -- D7: reglas normativas del escritor, §62.1: - - `I_PAYLOAD` sale de un CSPRNG y no se reutiliza; - - límites; - - la fecha pedida tiene que ser futura; - - el escritor se autocomprueba; - - rechaza claves X25519 no canónicas o de orden bajo. - -**Hecho en Go, paso 3 (`f24a280`):** -- **Formato 2 en la librería:** - - `capsule`: `Format`, `Padding`, `PaddedLength`, `PayloadAgeLength`; `EncodeControl` y `DecodeControl` reciben el formato; `Open` aplica los pasos 12 a 18 del formato 2. - - `agewrap`: `AccessSlots` y `CheckX25519Recipient`. -- **Escritura:** - - `Encrypt` escribe solo el formato 2. - - `EncryptOptions.Length` es obligatorio; `Padding` es reforzado por defecto. - - Acepta de 1 a 16 credenciales, con señuelos, orden aleatorio y autocomprobaciones. - - La CLI mide la entrada, acepta `-padding` e informa del formato. -- **`testdata`:** - - 7 fixtures `format2_*`, dos de ellos con `.dkk`; - - `vectors/padding.json`; - - los vectores CBOR del formato 2; - - un corpus de mutaciones de 125 casos: 88 del §64 (33 en cada formato y los 22 de la tercera lista) y 37 más; - - un diferencial de 4 380 casos, en el que los 1 825 anteriores no cambian. - - Los fixtures del formato 1 se conservan byte a byte. -- **Mutaciones sin aleatoriedad:** se vuelven a sellar los fixtures con sus claves y nonces conocidos (`internal/testkit/reseal.go`), así que se regeneran byte a byte. -- **`scripts/check.sh 60s` limpio:** - - cobertura: codec 100 %, capsule 94,2 %, accesskey 97,2 %, datekey 94,6 %, agewrap 92,8 %; - - govulncheck, con los mismos dos avisos de §1; - - 60 s de fuzzing en cada uno de los 15 objetivos. -- **Documentación:** la copia del spec del repo pierde las marcas "(por implementar)". README, README.es, CHANGELOG, `docs/traceability.md` y `testdata/README.md` están al día. - -**Orden de trabajo:** -1. Aplicar y verificar las 22 correcciones. Hecho el 29-09 (`4a025d1`). -2. El autor aprueba el texto de la v0.9. Hecho el 29-09. -3. La referencia Go implementa el formato 2, con fixtures nuevos y mutaciones, y pasa `check.sh`. Hecho el 29-09 (`f24a280`). -4. Se pone el tag `spec-v0.9`. Hecho el 29-09, con la autorización del autor: - - `7e2d83c` anota el SHA-256 del spec en `spec/README.md`, que también va en el mensaje del tag; - - `main` avanzó hasta ese commit sin merge; - - `main`, `v0.9` y el tag están subidos. -5. `datekeys-ts` sincroniza `testdata` y el lector TypeScript abre el formato 2. Hecho el 29-09 (`0118890`, subido): - - `testdata` a `7e2d83c`; - - el prelude lee el formato; `decodeControl` y `encodeControl` reciben el formato; `padding.ts` con las dos reglas, exactas hasta L_MAX; - - `open` exige 16 stanzas en el paso 12, calcula P en el 16 y comprueba el relleno en el 17, entregando solo los L primeros bytes; el paso 17 se registra también cuando se supera; - - la página muestra el formato, avisa del 1 y, al abrir una cápsula del formato 2, da la regla y P; - - `ibe-vectors.json` añade los siete fixtures del formato 2, calculados con `scripts/ibe-go-vectors.go`; los valores congelados no cambian; - - comprobado: los 125 casos del corpus dan en TypeScript el código, el paso y el texto de error de `capsule.Open`, en memoria y desde un `Blob`. -6. Se replantea el plan de la fase 3 y se escribe el writer TypeScript del formato 2. **Hecho el 29-09.** El 29-09 por la noche, [PLAN_fase3_escritura.md](PLAN_fase3_escritura.md) pasó a su v2, sobre las reglas del §62.1: - - 16 huecos con señuelos y orden uniforme; - - relleno `reforzado` por defecto; - - L conocida de antemano; - - autocomprobaciones; - - recipients canónicos y no de orden bajo, como Go; - - `SEALED_CONTROL_LEN` con la fórmula del §62.1 y comprobada. - Una revisión crítica con sondas no encontró nada bloqueante ni grave, y sus 12 correcciones menores están incorporadas. - - Hecho el 29-09 en `datekeys-ts`, todo subido y con `npm run verify` en verde en cada paso: - - paso 0: el autor confirma las 17 decisiones con su recomendación, entre ellas cerrar `0.1.0` ya (D14), la fórmula del §62.1 comprobada con el sellado real (D3) y aceptar los puntos del twist, como Go (D6). El plan pasa a v3 (`b97dee2` en este repo); - - paso 1: `0.1.0` cerrada (`d577283`, tag `v0.1.0`) y `0.2.0-dev` abierta (`8c08c97`); - - paso 2 (`8838c7d`): `recipient.ts`, `random.ts` y `agefile.ts`, y las guardas nuevas; - - pasos 3 y 4 (`8473fdf`): `encrypt.ts` y `writer.ts`. Reproducen byte a byte las secciones deterministas de los siete fixtures del formato 2 de Go, escriben en streaming y abortan la salida ante cualquier fallo. El bucle de propiedades pasa con 500 semillas; - - paso 5 (`da0b39f`): Go abre con cada credencial las trece cápsulas de muestra que escribe TypeScript, y las reencodifica a los mismos bytes. Rechaza cuatro mezclas con el mismo código y paso, codifica igual 500 entradas aleatorias y da los mismos textos en 22 recipients y 21 opciones inválidas. Todo queda congelado en `src/lib/dkc/testing/capsule-vectors.json`. - - - paso 6: el autor confirma las decisiones de la página con cada recomendación (sección 9 del plan, «Decidido en el paso 6»): `time_only` por defecto, la zona del dispositivo con un selector, los avisos de §53 y §50 desde 365 días y un aviso de protocolo preliminar; - - paso 7 (`3a9d2b1`): la página `/create`, con `lengths.ts` (el tamaño del `.dkc` antes de escribirlo), `localtime.ts`, `create-input.ts` y `creator.ts`. En la compilación de producción, una cápsula creada para dentro de cuatro minutos se abrió después en `/inspect`, con el release pegado de drand, y con `datekeys decrypt` de Go, con red y su `.dkk`, al mismo contenido. Una revisión adversarial encontró un fallo mayor y ocho menores, todos corregidos. El mayor: la `.dkk` que es la única credencial se podía borrar sin confirmación. - - - después, a petición del autor (`da2000a`): `/inspect` muestra el texto en claro de cualquier cápsula que se abre, si es texto, y no solo el de los fixtures. Las dos páginas explican las claves de `age`: qué es un destinatario `age1…`, cómo se consigue con `age-keygen` y qué se pega al abrir. - - **Siguiente:** que el autor decida si cierra `0.2.0` (tag `v0.2.0` en `datekeys-ts`). Después, lo de §2.4. - -**Formato de cápsula 3, en diseño (30-09).** El autor quiere que una cápsula guarde varios ficheros y carpetas con sus nombres, tamaños, hashes y fechas, más una firma de autor y un sello de tiempo, ambos opcionales. Hoy el nombre del fichero se pierde: §6 y §55.2 lo dejan fuera del protocolo. -- Decisiones del autor: - - todo va cifrado dentro de `PAYLOAD_AGE`, como `security | head | content`; - - hash SHA-256 por fichero, sin hash global; - - con carpetas; - - la fecha de modificación se toma al cargar, marcada por defecto; - - un comentario y un autor declarado, opcionales; - - sin tipo de contenido; - - firma Ed25519 y sello de DateKeys, con registro anclado en OpenTimestamps. -- Un flujo de diseño con revisión adversarial produjo [spec_v0.10/formato3_diseno.md](spec_v0.10/formato3_diseno.md): 28 objeciones, que resultaron ser 24 distintas, corregidas o aceptadas. -- El paquete para la revisión de seguridad externa, con el contexto del protocolo, el modelo de amenazas y las preguntas, era `spec_v0.10/formato3_para_revision.md` (`56851a9`). Se borró al unificar el diseño, pero sigue en git y publicado como artefacto privado, en la versión que revisó Fable: https://claude.ai/artifact/5NY9YxBjZA6DCadZ1aT5Ln. -- **Revisión de Fable (30-09),** guardada en [spec_v0.10/revision_fable.md](spec_v0.10/revision_fable.md). - - **Veredicto:** la parte criptográfica aguanta, y confirma la aritmética de tamaños y la necesidad del verificador Ed25519 propio. Los problemas están en los bordes. - - **Diez hallazgos**, cuatro mayores y seis menores; también hay observaciones sobre el documento. - - **Valoración:** coincido con todos. Comprobados de memoria: el 2 (la lista de git en `core.protectHFS` incluye ZWJ, ZWNJ y U+206A–206F) y el 6 (JavaScript compara en UTF-16: U+FF5E y un emoji quedan al revés que en Go). -- **Arreglos que no necesitan decisión:** - - **2.** R4 por la propiedad `Default_Ignorable_Code_Point`, con lista blanca corta (ZWJ, ZWNJ, VS15, VS16); la clave de R7 descarta lo permitido; tags U+E0000 a U+E007F prohibidos. - - **5.** El tamaño del área de `security` va en la trama, fijo por versión y reservado siempre. - - **6.** TypeScript compara bytes UTF-8, con un vector en `paths.json`. - - **7.** En la CLI, prefijo en cada línea visual del comentario, y los veredictos repetidos al final. - - **8.** Se declara como fuga aceptada que el POST al servicio delata el sello. - - **9.** Tabla de verdad firma/sello, expresión regular de R6b y regla para una mtime negativa. - - **10.** Prefijos de dominio en `control_commit` y `head_digest`, y el nombre `.datekeys-*` reservado. - - **El documento:** 24 objeciones en vez de 28, marcadas «corregida» o «aceptada»; un glosario (capas 2 a 4, L_MAX, la sal); un texto para un sello que el lector no sabe verificar; una sola fuente en vez de tres ficheros que repiten el texto. -- **Decisiones del autor del 30-09 sobre la revisión:** - 1. **Tres entregas,** con el formato congelado desde la primera y `security` presente pero vacío: - - 1: contenedor, varios ficheros y rutas; - - 2: firma y claves de autor; - - 3: el sello, cuando exista el documento «Servicio de sellado v1». - - Las entregas 2 y 3 no cambian el formato: un lector anterior muestra «no soportado» y abre igual. - 2. **Origen del servicio (hallazgo 1):** el autor no tiene preferencia, así que se toma la recomendación. - - Un subdominio aparte, `seal.datekeys.com`, que solo sirve la API y nunca HTML, con cabeceras `nosniff` y `CSP: sandbox` de todos modos. - - La CSP de `/create` añade ese origen a `connect-src`, solo en esa página. - - Es de la entrega 3 y se puede revisar entonces. - 3. **Vida del sello (hallazgo 3):** la prueba va dentro de la cápsula. - - El token lleva la prueba de inclusión y el checkpoint firmado, y una raíz offline, fijada desde ya, certifica las claves anuales. Así el sello se verifica sin red para siempre, y la auditoría del anclaje queda como comprobación online opcional. - - Esto agranda el área de `security`: con el arreglo del hallazgo 5, la entrega 3 define una versión de `security` con un área fija mayor. - 4. **Abuso (hallazgo 4):** prueba de trabajo SHA-256 en cada petición, de un segundo en el navegador, sin guardar estado sobre quién pide. -- **Hecho el 30-09 a mediodía (`57dc659`),** sin flujo y con un único revisor adversarial: - - [formato3_diseno.md](spec_v0.10/formato3_diseno.md) es la única fuente del diseño. Se borraron `formato3_revision_intro.md` y `formato3_para_revision.md`, que repetían su texto. - - **Estructura:** una parte 0 de contexto, con glosario, decisiones y modelo de amenazas; una parte por entrega, cada una con sus pruebas y sus preguntas abiertas; y tres anexos con las revisiones. El de Fable dice dónde se resuelve cada hallazgo, el de la revisión interna marca sus 24 objeciones como corregidas o aceptadas, y el tercero recoge la revisión adversarial de esta versión. - - **Aplicados** los arreglos 2 y 5 a 10, los del documento y las cuatro decisiones. - - **La revisión adversarial** no encontró nada bloqueante ni mayor. Sus 15 hallazgos menores están resueltos en el diseño (anexo C), y una segunda pasada comprobó los arreglos. Los que cambian el diseño: - - el head va siempre en su versión 1, porque §22 exige un formato nuevo para una versión nueva; - - las claves 2 y 3 de `security` van codificadas aparte, así que una firma o un sello mal formados no arrastran al otro; - - el área depende solo de la versión del spec, nunca de `-seal`, y hay dos fugas nuevas declaradas: un área de 512 delata que no hay sello, y el registro publica la t de cada sello; - - R3 limita el NFD de cada segmento a 255 unidades UTF-16, por HFS+, y R4 prohíbe U+F000–U+F0FF; - - un sello que no verifica se descarta y ya no aborta la cápsula. - - **Interpretación que confirmar:** la decisión 3 hablaba de «una versión de `security` con un área fija mayor». El diseño hace que el área la fije la versión del spec y deja el mapa `security` en su versión 1, para que un lector de la entrega 2 siga comprobando la firma en una cápsula de la entrega 3. Es la pregunta 3 de la entrega 1. -- **Hecho el 30-09 por la tarde:** - - El autor cerró las diez preguntas de la entrega 1, todas con la recomendación (`afd9f76`). Los límites quedan como se propusieron y congelados con el formato. Un único fichero dentro de una carpeta se descarga directamente, con el ZIP como opción, y la página ofrece cada fichero del ZIP como un corte suyo. - - El borrador del spec v0.10 de la entrega 1 está en `datekeys-go`, rama `v0.10`, sin subir: `fa7f95e` lo redacta y `9d1cd2e` aplica la revisión final. Lleva el spec, el CDDL y `spec/README.md`. La referencia sigue implementando la v0.9, y su `SpecVersion` no cambia. - - La revisión final, como la de la v0.9, encontró un problema bloqueante, tres mayores y once menores, todos corregidos ([spec_v0.10/revision_borrador.md](spec_v0.10/revision_borrador.md)). El bloqueante: R6c rechazaba «¿», porque bestfit1250 lo lleva a '?'. Ahora solo rechaza '/', '\', ':' y U+0000 en una proyección. El diseño recoge los cambios que le afectan en su anexo D. - - Pregunta del autor: la firma de autor con su clave privada está prevista, en la entrega 2. Varias firmas no hace falta decidirlas ahora: un `alg` futuro puede definir una lista de firmas sin cambiar el formato (pregunta 3 de la entrega 2 del diseño). -- **Siguiente:** - 1. Hecho: el autor eligió Unicode 18.0.0 («no vamos a trabajar con unicodes ya pasados») y dio el visto bueno al texto. El borrador lo recoge en su rama, y el diseño, en su decisión 4. - 2. Hecho: el autor aprobó la regla de invisibles («sí a las dos»), que el spec recoge en R4b y en §29.6 (`631d09c`). - 3. Hecho: con su permiso se descargaron los 19 ficheros de datos, 8,25 MB, en `datekeys-go/.cache/`, fuera de git. - 4. Hecho: la referencia Go implementa el formato 3, con el [plan](PLAN_formato3_go.md) y el detalle de abajo. Con la autorización del autor («sí, sube la rama y pon el tag»), la rama `v0.10` y el tag anotado `spec-v0.10` están en el remoto, en `cc35d2c`, que solo cambia textos para nombrar el tag. Después, a petición suya («sí, avanza main hasta la v0.10»), `main` avanzó hasta `cc35d2c` sin fusión y está subida. - 5. **En curso:** `datekeys-ts` lee y escribe el formato 3 con su [plan](PLAN_formato3_ts.md). En la rama `v0.10` de `App`, sin subir, están hechos los pasos 0 y 1 (`fbb90b2`, las tablas y las reglas de rutas y de texto), del paso 5 el CRC-32 y la disposición del ZIP (`36096a9`), el paso 2 (`d9a9cf5`, el códec) el paso 3 (`b176ad2`, la lectura del formato 3 con `testdata` en `spec-v0.10`) y el paso 4 (de `3daa1f7` a `2efc8bc`: `encryptFiles`, `encrypt` solo con `testVectors`, `/create` en formato 3 con un fichero, y la interoperabilidad con Go). El paso 5, el ZIP y el sumidero de la página, está en `ee82f43`, el paso 6, la página `/inspect` con los ficheros del formato 3, en `651178a`, y el paso 7, la página `/create` con ficheros, carpetas, rutas editables, comentario y autor, en `7dc88ef`. El paso 8 está hecho (`7527c35`, `57e0a8a`, `e6cca0b` y el CHANGELOG): README, `testdata:check` contra `cc35d2c`, tres revisiones adversariales con subagentes y sus correcciones, y, a petición del autor, `/create` rediseñado (una carta al futuro, sobre de correo aéreo, fuentes del sistema) y el sitio siempre claro. Pendiente, sin urgencia: - - `/inspect` solo cambió de aspecto con los estilos globales: falta poner el resultado delante y plegar los pasos 1 a 18, como en `/create`. - - El texto del paso 17 aún difiere del de Go cuando la cápsula se corta justo tras un chunk completo: `age-encryption` retiene ese chunk hasta ver un byte más. Igualarlo exige descifrar el STREAM como Go (código propio con `@noble/ciphers`). - - Un head de 16 MiB tarda de 10 a 40 s en la página, en el hilo principal (Go tarda la mitad): `open()` en un worker. - - Menores: el `TypeError` sin sumidero llega tras los pasos 3 a 8 con un `Blob`; `tempfile.remove()` marca borrado antes de lograrlo; `measureFiles` en cada tecla con 65 535 ficheros; un bundle `.app` no avisa (igual que la CLI). - - Subido el 01-10 por la noche, con permiso del autor: la rama `v0.10` de `App`, y `main` y `v0.11` de `datekeys-go`. - 6. La entrega 2 abre la versión siguiente del spec, y la 3 espera al documento «Servicio de sellado DateKeys v1». En esa versión entra también la **llave de palabras** que pidió el autor el 01-10: palabras que elige la persona y abren la cápsula en lugar de la `.dkk`, ya hechas en la página y en la CLI (apartado «Retomar aquí»). Además, el 01-10 el autor pidió que `/inspect` pueda pedir la firma a drand: ya lo hace, con un botón (`2ec7102`), lo que cambia la decisión 4 del plan de la fase 2. Para otra revisión externa, el artefacto hay que volver a publicarlo desde el diseño nuevo. - -**Hecho el 30-09 por la noche: el formato 3 en Go.** Rama `v0.10` de `datekeys-go`, subida con el tag `spec-v0.10` en `cc35d2c`, un commit o varios por paso del plan: -- `631d09c`, el spec con la regla de invisibles; `6fba1dd`, paso 1, `internal/pathrule` con las tablas de Unicode 18.0.0 y best-fit generadas y su `TablesDigest`; `72e86b8`, paso 2, el códec de `BODY`, `security` y el head. -- `7249ef4`, paso 3, el lector: `capsule.Sink`, `ErrSinkRequired` justo tras el paso 2, el paso 17 en subpasos con su precedencia, y lecturas de `BODY` que crecen con los bytes recibidos (§57). -- `8955c0f`, paso 4, el escritor `capsule.EncryptFiles`, que lee cada fichero dos veces; `Encrypt` solo escribe el formato 2 con `EncryptOptions.TestVectors`. -- `a0de80f`, paso 5, el CLI: `encrypt -in` con ficheros y carpetas, `-comment`, `-author` y `-no-mtime`; `decrypt -out CARPETA` con `os.Root`; la presentación de §29.7, con el ancho del terminal pedido por `syscall`, sin dependencias nuevas. -- Paso 6, datos de prueba: `3c39336` (`SpecVersion` 0.10 y `ERR_HEAD_INVALID`), `e070f89` (las nueve fixtures), `db862d5` (`paths.json`, `path_fold.json`, `head_schema.json`, `security.json` y el control de versión 3 en `cbor.json`) y `18eb3c3` (las mutaciones: 209 casos, 169 del §64, tres de los cuales se abren con su veredicto). -- `20f9959`, paso 7, la documentación; `735885c`, una corrección del CLI: una carpeta de salida sin su carpeta padre falla antes de pedir el release; `6fa2b54`, paso 8, tres objetivos de fuzzing nuevos (`FuzzDecodeHead`, `FuzzEvaluateSecurity`, `FuzzCheckPath`) y el SHA-256 del spec en `spec/README.md`. -- Verificación: `go test ./...` y `scripts/check.sh 60s` limpios, cobertura de `capsule` 93,1 %; la prueba en vivo contra Quicknet abrió cápsulas de formato 3 de las dos políticas; los tres objetivos nuevos, cerca de un millón de ejecuciones cada uno, sin fallos. -- Para el autor, sin urgencia: - - un cambio editorial en el texto aprobado: §67 decía «Serán … (por implementar)» de las fixtures del formato 3, y ahora dice «Son …». El SHA-256 de `spec/README.md` es el del texto con ese cambio; - - el corpus de mutaciones pasa de 168 KB a 706 KB. 476 KB son el caso de 65 536 carpetas implícitas que pide el §64, cuyo head mide 235 KB; - - los textos del CLI que el spec no fija son de la referencia: la cabecera «Ficheros escritos en CARPETA (N):», los avisos de nombres peligrosos y los mensajes del escritor. Los que fija, los veredictos y las dos etiquetas, van literales. -- Para `datekeys-ts`: - - hecho: el generador escribe el módulo TypeScript con la bandera `-ts` (`13910b3`, en `main` de `datekeys-go`, un commit por delante de `origin/main` y sin subir), y el digest recalculado en TypeScript coincide con `TablesDigest`; - - `testdata` cambia entero de `"spec"`, y añade nueve fixtures, cuatro ficheros de vectores, `mutations.json` con 209 casos (`version changed` pone ahora `VERSION` 4, y hay casos con `verdicts`) y el diferencial con 5 110; - - los textos de las reglas de rutas y de texto deben coincidir byte a byte: `paths.json` y `head_schema.json` los traen en `result` y `detail`. -- Herramientas: en esta máquina los heredocs de Bash rompen apóstrofos y barras invertidas, y la herramienta Write convierte `\uXXXX` en caracteres literales. Funciona escribir los cambios como scripts de Python en el scratchpad. - -**Conclusiones de la conversación, sin decisión pendiente:** -- El protocolo no contempla un sello de tiempo de creación (§5, §55.1). Si se quiere, lo recomendado es un sello RFC 3161 u OpenTimestamps sobre el SHA-256 del `.dkc` completo, guardado aparte. -- Un fichero único `.dk` con `.dkc` y `.dkk` juntos no conviene: con `time_and_key` equivaldría a `time_only`. Ya se envía un solo fichero con `time_only` o con destinatarios `age1…`. -- `datekeys-ts` cerró `0.1.0` el 29-09 (`d577283`, tag `v0.1.0`), y la fase 3 va en `0.2.0-dev`. +--- -### 2.3 Depende del autor +## Decisiones del autor que siguen vigentes + +- **La app Flutter está archivada** «para un futuro» (6-10). No se empieza sin que lo pida. +- **La revisión externa** (6-10): + - primero, buscar un revisor que lea español; si no lo hay, traducir solo el núcleo normativo; + - dos niveles de alcance, con presupuesto cerrado por nivel; + - código entero en bundles de git cifrados con `age`; + - un NDA mutuo; + - la v0.15, después del informe. +- **`locator.Open` sigue leyendo como mucho 1 MiB** del localizador (6-10). +- **El cifrado tlock queda en `BigInt`, sin tiempo constante**, documentado en Dart y TypeScript («continúa», 6-10). +- **El reporte del posible fallo de dart2js** al equipo de Dart, solo con permiso del autor. Está documentado en el README de `datekeys-dart`. +- **Mostrar Q1 y Q10 de la revisión al equipo de drand** antes de pagar una revisión es decisión del autor, porque supone enseñar el proyecto fuera. +- **El diseño de las páginas:** nunca un fondo oscuro, nada del estilo de la landing, usar la skill `frontend-design` sobre la página real y no gastar en maquetas. Ver la memoria. -- Crear `security@datekeys.com` y, si se quiere, un `security.txt` en la web. Después, actualizar `SECURITY.md`, que hoy dice `info@activething.com`. -- Elegir la ruta pública del módulo Go (propuesta: `datekeys.com/go/datekeys`, en minúsculas) y el espejo público, que no puede ser GitHub (por ejemplo Codeberg). Publicar la página `go-import` en `datekeys.com`. Después: renombrar el módulo y poner el tag `v0.1.0` cuando `go get` funcione desde una máquina limpia. -- Decidir si `datekeys-ts` cierra `0.2.0`, ahora que la fase 3 está completa. +--- -### 2.4 Más adelante +## Para trabajar -Release API sobre la librería, traducción del spec al inglés y revisión externa antes de la v1.0. Opcional: escribir en OPFS en trozos de 1 MiB, que ahorra un 10 % al cifrar ficheros grandes en la página (README de `datekeys-ts`, «Crear»). +- **Subir al Gitea.** El nombre `g.activething.com` a veces resuelve a 89.46.247.16, que no responde. Entonces se sube a la IP de la red local, sin tocar el remoto: ---- + ```bash + git -C push https://192.168.18.112/go/.git + ``` -## 3. Reglas del proyecto + y después `git -C update-ref refs/remotes/origin/ `. Los remotos son `go/DateKeys`, `go/DateKeys-App`, `go/dateKeys-dart` y `go/datekeys-doc`. El servidor no es del autor: no se propone ningún cambio en él. +- **Cerrar una versión del spec**, como la v0.12, la v0.13 y la v0.14: + 1. en Go, la cabecera del spec con «aprobado por su autor ese día» y nada más del texto; + 2. `SpecVersion`; + 3. `go run ./internal/testkit/genfixtures -out testdata`, y el campo `spec` a mano en los dos congelados, `security_cms.json` y `locator.json`; + 4. el SHA-256 en `spec/README.md`, y los README, `SECURITY.md`, la trazabilidad, `testdata/README.md` y el CHANGELOG; + 5. `scripts/check.sh`, con el árbol limpio tras el commit; + 6. el tag anotado `spec-vX.Y` y `main` avanzado sin fusión (`git fetch . :main`); + 7. en TypeScript y Dart, la versión del spec, `testdata` sincronizado con sus scripts, `mutation-texts.json` regenerado con Go en un módulo temporal (`G:\tmp\mutgo`), y el campo `spec` de los vectores propios que salen de Go. -Están en el [README](README.md#reglas) de este repo, que el `CLAUDE.md` de la raíz carga en cada sesión. + Tras aprobar no se añade texto normativo sin enseñarlo: fue el fallo E1 de la v0.11. +- **Encargos a agentes:** + - con `model: "opus"`; + - en worktrees junto a los repos, para que `../datekeys-go` resuelva; + - nunca dos agentes en los mismos ficheros; + - solo ficheros nuevos, y los comunes en un último commit; + - la sesión revisa contra Go antes de integrar. +- **Herramientas de esta máquina:** + - los heredocs de Bash rompen las barras invertidas, `\n` incluido; + - la herramienta Write quita los espacios de final de línea (los saltos de Markdown del §77) y convierte `\uXXXX` en caracteres; + - para cambios con barras o espacios exactos, un script de Python escrito con Write que use `chr(92)`, o la herramienta Edit; + - `cd` en Bash mueve el directorio de la sesión: usa `( cd … )` o `git -C`. +- **Vista previa de la página:** la configuración `inspector-dev-app` de `.claude/launch.json` arranca `App`, mientras la carpeta no se renombre. No pares el servidor mientras el autor lo usa. `vite.config.ts` prepara las dependencias que se cargan bajo demanda (`optimizeDeps.include`), para que la primera apertura no recargue la página. +- **Fuzzing:** usa `FUZZ_PARALLEL=4`. Un «context deadline exceeded» sin entrada que falle es del motor de Go, no del código; se vuelve a pasar. +- **Disco:** C: está casi lleno con las cachés de Go y Dart; los temporales van en `G:\tmp`, y nunca se borra con comodines. --- -## 4. Documentos +## Documentos -- En este repo están los planes, la revisión del protocolo y los papeles de la v0.9. El [README](README.md#documentos) los lista. -- En `datekeys-go`: - - `spec/DateKeys_Protocol_Specification_v0.10.md`, cerrado con el tag `spec-v0.10`; `spec/DateKeys_Protocol_Specification_v0.9.md`, cerrado con el tag `spec-v0.9`; `spec/DateKeys_Protocol_Specification_v0.8.2.md`, `spec/datekeys.cddl` y `spec/README.md`; - - `testdata/README.md`, que documenta los ficheros compartidos para segundas implementaciones; - - `docs/traceability.md` y `CHANGELOG.md`. -- Las herramientas de verificación de las sesiones del 26 al 28-09 estaban en carpetas temporales y pueden haber desaparecido: el diferencial Go/TypeScript de `tsreview/` y las copias congeladas `dkgo-ref-`. Su descripción está en los mensajes de los commits de `datekeys-ts` y en su README. +El [README](README.md#documentos) los lista. Para retomar, lo principal es: +- [revision_externa/](revision_externa/NOTA_PARA_EL_AUTOR.md): el paquete y su nota; +- [REVISION_completitud_v0.13.md](REVISION_completitud_v0.13.md): qué falta antes de la v1.0; +- [spec_v0.14/decisiones.md](spec_v0.14/decisiones.md): las decisiones de la última versión. diff --git a/HANDOFF_historial.md b/HANDOFF_historial.md new file mode 100644 index 0000000..5169ec4 --- /dev/null +++ b/HANDOFF_historial.md @@ -0,0 +1,622 @@ +# Historial del handoff de DateKeys + +Lo que fue el [HANDOFF](HANDOFF.md) desde el 26 de septiembre hasta el 6 de octubre de 2026, tal como estaba al reorganizarlo, sin cambios. Lo actual está en el HANDOFF; esto es para buscar por qué se decidió algo, qué hizo cada sesión o en qué commit quedó cada cosa. Los commits que cita siguen en sus repos. + +--- + +## Estado al 6 de octubre por la noche, antes de reorganizar el handoff + +**Para empezar:** +1. Abre la sesión en `G:\bussines\datekeys`, la raíz, no en `App`. Comprueba que corre en Opus. La memoria buena es la de la raíz. +2. Comprueba los repos con `git status` y `git log`: + - `datekeys-go`: rama `v0.14` y `main` en `39b2033`, con el tag `spec-v0.14`; las ramas `v0.13` y `v0.12` se quedan en sus tags; + - `App`: rama `v0.10` en `4e23f88`, `0.3.0-dev`; `main` en `8cf0685`, con el tag `v0.2.0`; + - `datekeys-dart`: rama `v0.14` en `013b069`; las `v0.13`, `v0.12` y `v0.11` se quedan atrás; la `v0.11` se queda en `bb66e48`; + - `docs`: rama `main` en el commit de este handoff. + + Si no se subieron al cerrar, `git status` lo dice: todo lo del 6-10 por la tarde y la noche se subió solo con permiso del autor. +3. **Lo siguiente lo decide el autor.** Lo abierto: + - medir el área de 32 KiB con firmas reales: la v0.12 se aprobó sin esa medida. + + **La app Flutter queda archivada** para más adelante, por decisión del autor del 6-10 («la aplicación de Flutter de momento se archiva para un futuro»). La librería Dart está lista para cuando se retome. + +**La v0.14, aprobada (6-10, noche).** El autor dijo «apruebo el borrador, continua», con las diez recomendaciones de [spec_v0.14/decisiones.md](spec_v0.14/decisiones.md). La decisión 8 se aplicó antes de cerrar: §12.1 admite solo `bls-unchained-g1-rfc9380`, y `profile.Validate` rechaza los otros dos schemes (Go `c041fa3`, cambio 7 del §76). Cierre como la v0.13: SHA-256 `390922135931dd61a263ed90259c7a978b5d92944405e641e94cc194f84fb459`, tag `spec-v0.14` en `39b2033`, `main` avanzado. TypeScript (`4e23f88`) y Dart (`013b069`, rama `v0.14`), de dos agentes Opus: la 0.14, la decisión 8 con el texto de Go, una prueba que recorre `tlock_steps.json` y el comentario de H3 corregido. Los tres gates pasan: Go entero, TypeScript con 8 030 pruebas y Dart con 2 193 en la VM y 681 en Node. + +**Borrador v0.14 (6-10, noche).** El autor dijo «sí, empieza por el 1»: el paso 2 de la revisión, escribir lo que falta. Rama `v0.14` de `datekeys-go`, `49b3764`, sin aprobar: §5, §7.6, §7.7, §7.10, §36.1, §38.1, §50, §53, §59, §71 y erratas del §76 (de la sesión); y la raíz de confianza byte a byte en §12, §35, §51 y los pasos 10 y 11 del §63, con `testdata/vectors/tlock_steps.json` (de un agente Opus). Las decisiones, en [spec_v0.14/decisiones.md](spec_v0.14/decisiones.md); la 8, los tres schemes de §12.1, es la única que cambia código, y la recomendación es B, solo Quicknet. TypeScript y Dart no cambian hasta la aprobación. + +**Revisión de completitud contra la v0.13 (6-10, noche).** [REVISION_completitud_v0.13.md](REVISION_completitud_v0.13.md), de un agente Opus: de los ocho puntos de la revisión de la v0.8.2, el escritor está hecho; el versionado, lo que no se garantiza y la firma con la `.dkk` protegida, en parte; y el riesgo del proveedor, la revisión externa, la raíz de confianza y la recuperación a largo plazo, pendientes. Los tres pasos que propone antes de la v1.0: medir el área y cerrar el perfil CMS, una versión solo de texto que escriba lo que falta, y una revisión criptográfica externa. Para la próxima versión del spec, dos erratas: el título del §76 dice «v0.8.1», y el bloque de la v0.13 va antes que el de la v0.12. `FuzzCheckResolvedIP` es el objetivo 26 del fuzzing (Go `416c155`). + +**Fuzzing (6-10, noche).** `FUZZ_PARALLEL=4 scripts/fuzz.sh 60s` sobre `69dbb0c`, los 25 objetivos, `FuzzParseInfo` y `FuzzCheckURI` incluidos: limpio, sin entradas nuevas que fallen. + +**`datekeys-ts` 0.2.0 (6-10, noche).** El autor dijo «cierra la 0.2.0 y continua». `8cf0685`, «Release 0.2.0», con el tag anotado `v0.2.0` y `main` avanzado hasta él sin fusión; después `f7cdb5a` abre `0.3.0-dev`. Cubre la especificación 0.13: lee los formatos 1 a 3 y escribe el 3, con firma, sello, llave de palabras, nota y localizador. + +**`ParseInfo`, endurecido (6-10, noche).** El autor dijo «deja el 1 MiB y endurece ParseInfo, continua». Sin cambio normativo, porque el §44.1 ya lo pedía: `ParseInfo` comprueba la cadena del stanza sellado (hexadecimal en minúsculas, y la de Quicknet para una DateKey de Quicknet) y que el cuerpo lleve un texto de 4096 bytes o un múltiplo, así que una cabecera sin cuerpo se rechaza; `Info.Extension` rechaza una DateKey de un perfil no fijado. Go `69dbb0c`, y TypeScript y Dart con sus vectores de Go regenerados. `locator.Open` sigue leyendo como mucho 1 MiB, por decisión del autor. + +**La v0.13, aprobada (6-10, noche).** El autor dijo «si, lo apruebo continua». Como la v0.12: solo cambia la fecha de la cabecera; `SpecVersion` 0.13; el campo `spec` de todo `testdata`, y a mano en los dos congelados; SHA-256 `796f176f51119e287211428496b0d30fd8f941617780c5a5d2954243431fdaaf` en `spec/README.md` y en el tag anotado `spec-v0.13` (`913dd60`); `main` avanzó hasta él sin fusión. TypeScript y Dart pasan a la 0.13 con `testdata` en el tag. Los tres gates pasan. + +**Lo último del 6-10 por la noche.** El autor dijo «continua» dos veces: +- `App` `2c2a28d`: la nota pública en `/inspect`, debajo del veredicto, con el aviso de `showNote` de Go; los errores inesperados de las páginas dicen en español qué hacer (`unexpectedProblem`), sin el mensaje de la excepción, tras una queja del autor por «Failed to fetch dynamically imported module: http://localhost:5188/…»; y `vite.config.ts` prepara las dependencias que se cargan bajo demanda, porque el servidor de desarrollo recargaba la página en la primera apertura y la rompía. +- El CID no canónico y `https://[[2000::]/` ya se rechazan: Go `e801e03`, Dart `450b3f8`, TypeScript `900700b`, con los vectores de Go regenerados. No era una decisión: el §44.1 de la v0.12 ya los rechazaba, y era Go el que no lo cumplía. +- El servidor del Gitea: el nombre `g.activething.com` resuelve a veces a 89.46.247.16, que no responde; se sube con la URL de la IP de la red local, `https://192.168.18.112/go/.git`, sin cambiar el remoto, y se mueve después `origin/` con `git update-ref`. +- `.claude/launch.json` tiene `inspector-dev-app`, que arranca `App`: la carpeta sigue sin renombrar. + +**NAT64 y el TypeScript (6-10, noche).** El autor dijo «adelante con el NAT64» y «sigues con TypeScript». +- **Borrador v0.13**, `datekeys-go` rama `v0.13` (`a83b44d`, `e9d4cec`), sin aprobar. El §44.1 cuenta una dirección de NAT64 a la que resuelve un nombre, de `64:ff9b::/96` o del prefijo de la red (RFC 6052, RFC 7050), por la IPv4 que lleva dentro; una dirección de NAT64 escrita en el localizador se sigue rechazando. El prefijo de la red tiene una longitud de RFC 6052 y está en `64:ff9b::/16` o es público, y una dirección suya cuenta solo por su IPv4 aunque el prefijo sea público: el primer código no lo hacía, y la sesión lo corrigió antes del commit. El §76 tiene el cambio 1 con su caso. `locator.CheckResolvedIP` y `testdata/vectors/resolved_ip.json`, 42 casos. `SpecVersion` sigue en 0.12. +- **Dart**, rama `v0.13` (`d65e218`, `4a0d4f7`): `checkResolvedIp(ip, nat64:)`, con los textos de Go. +- **TypeScript**, `v0.10`, de dos agentes Opus en paralelo, revisados e integrados: + - el localizador (`0d895bf`, `e2c51bc`): el paquete `locator` de Go entero, con un lector y escritor de `age` propio (`ageio.ts`) para reproducir los textos de `age` y fijar el azar. 6 531 casos contra Go con el mismo texto, sellado y sobres byte a byte, y Go abre lo que escribe TypeScript; + - NAT64 (`28f0c3f`), por la sesión; + - las claves de autor y la firma al escribir (`96614d5`, `9e5e3ba`, `a741efe`): `authorkey.ts`, `ed25519sign.ts` (firma propia) y los enganches `authorKey`, `cmsSigner`, `sealer` y `largeArea` del escritor. Ocho cápsulas firmadas y selladas byte a byte como Go, y Go abre las de TypeScript con los mismos veredictos. + + Ningún módulo nuevo: todos los de noble y `age-encryption` que importan ya estaban. `npm run verify` pasa con 8 017 pruebas y una aplazada. +- Los gates de Go y Dart pasan, con 2 175 pruebas en la VM de Dart y 665 en Node. + +**La v0.12, aprobada (6-10, tarde).** El autor dijo «apruebo el borrador». Se aprobó el texto tal como estaba, sin añadir texto normativo, para no repetir el fallo E1 de la v0.11: +- `datekeys-go` `fe405e2`: la cabecera del spec dice «6 octubre 2026, aprobado por su autor ese día», y es lo único que cambia del texto. `SpecVersion` 0.12; el campo `spec` de todo `testdata`, regenerado, y en los congelados `security_cms.json` y `locator.json`, cambiado a mano, solo ese campo. `spec/README.md` registra el SHA-256, `afc31fd8105d650773d093ac01bd2f5e0b56af04726f4e75c652e2cf9308ac3f`. Los README, `SECURITY.md`, la trazabilidad, `testdata/README.md` y el CHANGELOG nombran la v0.12. +- El tag anotado `spec-v0.12` está en `fe405e2`, y `main` avanzó hasta él sin fusión. +- `App` `45e7e49`: `SPEC_VERSION` 0.12, `testdata` en `fe405e2` y `mutation-texts.json` regenerado con Go; solo cambia su campo `spec`. +- `datekeys-dart` `62107d7`, en la rama nueva `v0.12`, como dice el plan: `specVersion` 0.12 y `testdata` en `fe405e2`. Sus vectores de `test/vectors/` cambian solo el campo `spec`, porque entre `c531e93` y `fe405e2` Go solo cambia `SpecVersion` y añade `wordkey.json`. +- Los tres gates pasan: `scripts/check.sh` de Go sin fuzzing, `npm run verify` con 7 832 pruebas y `testdata:check`, y `tool/check.sh` con 2 131 pruebas en la VM y 665 en Node. + +**Los vectores de la llave de palabras (6-10, tarde).** El autor pidió «haz los vectores de la llave de palabras», la observación del 5-10: +- `datekeys-go` `084728d`: `testdata/vectors/wordkey.json`, que genera `genfixtures` y comprueba `TestVectorFilesAreCurrent`. Tiene las palabras de 45 textos, entre ellos cada espacio del §38.1 y tres que no lo son; lo que hace un escritor con 20 textos, con el texto del error de Go; y 6 identidades con su recipient, la primera el vector del §38.1. No es un cambio normativo: el §64 de la v0.11 ya lo pedía. +- `App` `4031bd1` y `datekeys-dart` `bb66e48`: `testdata` sincronizado en `084728d`, con una prueba que corre el fichero. Ninguna librería tuvo que cambiar. +- Los tres gates pasan: `scripts/check.sh` de Go sin fuzzing, `npm run verify` con 7 832 pruebas y `testdata:check`, y `tool/check.sh` con 2 131 pruebas en la VM y 665 en Node. + +**Qué hizo la sesión del 6 de octubre por la tarde.** Corrió en Opus 5.5, abierta en la raíz. El autor dijo «SI» a la fase 2 de las etapas 6 y 7 de Dart: +- **6b, el escritor del formato 3** (`4c9bc72` a `6239e30`), de un agente Opus en la copia principal: escribe cápsulas byte a byte como `EncryptFiles` de Go con los mismos valores al azar, y Go las abre con cada credencial. +- **7b, las claves de autor y el sellado del localizador** (`3358f5c` a `d77ef9e`), de otro agente Opus en un worktree: `authorkey`, la firma Ed25519 propia, y `Seal` y `NewEnvelope`, también byte a byte como Go. +- **Integración:** la 7b, encima de la 6b con `rebase`. El enganche de la firma de `alg` 1 pasó a llamarse `AuthorSigner`, y la `AuthorKey` de la 7b lo implementa: el escritor firma ya con la clave real. El gate pasa con 2 059 pruebas en la VM y 665 en Node. +- **Revisión** de la sesión contra Go: sin fallos. Los detalles están en [PLAN_dart.md](PLAN_dart.md), al final. +- **Cosas de Go que Dart copia,** encontradas por los agentes: + - el texto de `PublicString` de `authorkey` con una clave de otra longitud tiene los números al revés: «a public key has 32 bytes, not 31»; + - el error de una nota pública con un carácter de control habla del «declared author», ya anotado el 5-10; + - un comentario que es solo `\r` pasa a `\n` y se acepta. + +## La sesión del 5 y 6 de octubre (histórico: lo actual está arriba) + +**Qué hizo.** Corrió en Opus 5.5. Se abrió en `App` y pasó a la raíz sin cerrarse. Cada parte la hizo un agente Opus, y la sesión la revisó contra Go, la integró y pasó el gate. Ninguna revisión encontró fallos. +- **`datekeys-go`:** `internal/pathrule/gen -dart` escribe las tablas de Unicode para Dart. Es `c531e93`, subido. +- **Etapas de Dart:** + - **2**, primitivas y `age`; y **3**, BLS12-381 y tlock, en paralelo; + - **4**, en tres partes: 4a, rutas, textos y llave de palabras; 4b, formatos; 4c, head, nota, inspección y apertura de los formatos 1 a 3; + - **5**, en tres partes: 5a, lector CMS, ECDSA y RSA; 5b, `testdata` en la v0.12, compromisos, `SECURITY_CBOR`, `alg` 1 y veredictos; 5c, `alg` 2 y `seal_type` 2; + - **6a**, el escritor de `age`; + - **7a**, el localizador y el sobre, sin el sellado. +- **Resultado:** la librería Dart inspecciona y abre cápsulas de los formatos 1 a 3, también grandes y en streaming, con todas sus credenciales; evalúa la firma y el sello como Go; escribe ficheros `age`, y Go los abre; y valida localizadores. El gate pasa con 1 713 pruebas en la VM y 432 en Node. +- **Decisiones del autor:** + - el cifrado tlock queda en `BigInt`, sin tiempo constante, y está documentado («continúa», 6-10); + - los repos `datekeys-dart` y `docs` tienen remoto desde el 6-10; + - G: tiene 26 GB libres, porque el autor liberó unos 24 GB. + +**Decisiones pendientes del autor**, encontradas el 6-10 al portar el localizador. Todas afectan a Go, y Dart copia hoy su comportamiento: +1. **Un CID no canónico pasa.** El §44.1 de la v0.12 pide el CID en su forma canónica, pero `isCIDv1` solo mira que los bits sobrantes sean cero, no cuántos hay: un CID válido con una `a` de más se acepta. Arreglarlo es tocar Go, con un vector nuevo, y después el Dart. +2. **`https://[[2000::]/` se acepta,** por el `strings.Trim(host, "[]")` de Go. +3. **NAT64 en móviles.** En redes móviles solo IPv6, un host solo IPv4 resuelve a `64:ff9b::/96`, que el §44.1 rechaza, así que la app no podría descargar de él. Es una cuestión del spec, y el README de `datekeys-dart` la anota. +4. **`ParseInfo` comprueba menos de lo que podría:** no mira la cadena del stanza sellado, acepta una cabecera `age` sin cuerpo, e `Info.Extension` no comprueba que el perfil esté pinneado. +5. **`locator.Open` solo lee 1 MiB del localizador.** Un defecto posterior queda oculto tras el error de `Unmarshal`. Es así por diseño, pero conviene saberlo. + +**Lo demás abierto:** +- la aprobación del borrador v0.12 y la medida del área de 32 KiB, que el autor dejó para luego; +- el TypeScript sin urgencia: el localizador, la nota en la página y cerrar `0.2.0`; +- las observaciones del 5-10, más abajo; +- medir en un móvil de gama media, cuando haya app: BLS12-381, PBKDF2, scrypt y la apertura; +- reportar al equipo de Dart el posible fallo de dart2js de Dart 3.13 que encontró la 4c, solo con permiso del autor. Está documentado en el README de `datekeys-dart`; +- `web` sigue sin remoto. + +**Para trabajar:** +- **Encargos a agentes:** + - en un worktree junto a los repos, para que `../datekeys-go` de `tool/check.sh` resuelva; + - nunca dos agentes en los mismos ficheros; + - los subagentes, con `model: "opus"`; + - el scratchpad es compartido: que nadie borre con comodines. +- **Generadores de vectores:** los de Go que necesitan paquetes `internal/` corren en una exportación `git archive` de `datekeys-go`, sin tocarlo. +- **Bash:** `cd` mueve el directorio de la sesión. Usa `( cd … && … )` o `git -C`. + +## Estado al cerrar la primera sesión del 5 de octubre (histórico: lo actual está arriba) + +**Para empezar la sesión siguiente.** La del 5-10 se cerró porque tenía el contexto casi lleno. +1. Abre la sesión en `G:\bussines\datekeys`, la raíz, no en `App`, y comprueba que corre en Opus. +2. Comprueba que los repos están como dice este apartado (`git status` y `git log` en cada uno). Todos estaban limpios al cerrar: + - `datekeys-go`: rama `v0.12` en `424cdf3`, subida; + - `App`: rama `v0.10` en `289fe71`, subida; + - `datekeys-dart`: rama `v0.11` en `c8bf3c0`, solo en local; + - `docs`: en el commit de este handoff, solo en local. +3. **Dart, etapa 2.** Se encargó a un agente y se detuvo antes de que escribiera nada en el repo. Hay que relanzarla con el encargo de [PLAN_dart.md](PLAN_dart.md), apartado «Cómo se hacen las etapas», revisar su resultado y pasar `tool/check.sh`. +4. **Dart, etapa 3**, BLS12-381 y tlock: el autor la pidió el 5-10 para después de la 2. + +**Qué pasó.** Una sesión en Opus, abierta otra vez en `App`, hizo los puntos 2, 3 y 4 de la lista del 2-10: lo que faltaba de Go, la segunda parte del TypeScript y las etapas 0 y 1 de Dart. El autor decidió además una ampliación del borrador v0.12. El trabajo grande se repartió entre agentes Opus en worktrees y repos aparte, y cada resultado se revisó e integró en la sesión. + +**`datekeys-go`, rama `v0.12`, subida:** +- `da9fd2c`: arreglo editorial del borrador. Faltaba una línea en blanco antes de cinco `---`, y dos párrafos, el final del §70 y el del §72, se veían como títulos. La v0.11 etiquetada tiene el mismo fallo y no se toca. +- `ea5c6eb`: `locator.json` con los casos del §64 de la v0.11 y la v0.12: + - 217 direcciones: la primera y la última de cada bloque IPv4, con sus vecinas públicas; los bloques IPv6; los nombres locales; los caracteres fuera de RFC 3986; los segmentos `..`; y los CID que no decodifican; + - `mixed`: un localizador con una dirección `http` y otra de NAT64, que se rechazan, y una tercera que se usa; + - `rest_cases`, `extension_cases`, con el localizador de otra ronda, y `plaintext_cases`, con el caso del cambio 7; + - las bases de relleno 3837, 4070, 4094 y 4095 y las del múltiplo siguiente: la spec pide ocho, y la lista del 2-10 daba seis. + + El generador pasa a `internal/testkit/genfixtures/locatorvectors.go` y comprueba cada caso contra Go. +- `e22d358`: `testdata/README.md` al día, y sin marcas *pending* en `docs/traceability.md` ni en el CHANGELOG. El README decía que el release de la ronda 1000 estaba en `quicknet_rounds.json`, y no estaba. +- `601e6d2`, con la **decisión del autor del 5-10** («sí, aplícalo así»): el §44.1 escribe lo que Go ya rechazaba y el texto no decía, y el cambio 6 del §76 y el §64 lo recogen: + - segmentos de 1 a 63 caracteres, sin guion en los extremos; + - el esquema en minúsculas, y `0x` y los nombres locales sin distinguir mayúsculas; + - IPv4 sin ceros a la izquierda y CID en su forma canónica; + - el puerto sin ceros a la izquierda: Go aceptaba `:0443` y `:00443`, y `checkPort` ahora los rechaza. + + `locator.json` pasa a 247 direcciones. +- **Verificación:** `scripts/check.sh 60s` completo sobre `e22d358`, y sobre `601e6d2` `check.sh` sin fuzzing y `fuzz.sh 60s`, los 25 objetivos: todo limpio. Cobertura de `capsule`, 92,2 %. govulncheck da los dos avisos de siempre, sin llamada alcanzable. + +**`App` (`datekeys-ts`), rama `v0.10`, subida (`fc5fb24..289fe71`):** +- `997f331`: la regla de los codificadores del §72 (`checkWrite` en `extension.ts`, con `NOTE_ID` y `CAPSULE_ID`), que aplican el escritor de cápsulas y el de `.dkk` con los textos de Go; `checkNoteData` y `unusableNote`. Comprobado también contra el `testdata` de `spec-v0.11`. +- `95329ee`, el borrador v0.12, en un solo commit porque nada pasaba por separado: + - `testdata` en `601e6d2`; `SPEC_VERSION` sigue en 0.11; + - el lector de certificados campo a campo, los OID por bytes, los SET OF con repetidos y los casos límite: T2, T6, T7, T8 y lo de TypeScript de E7, E8 y E9; + - los textos de los veredictos de la v0.12: E2, E3 y E4; + - `security.json` y los 135 casos de `security_cms.json`, comparados campo a campo, con sus líneas; + - los textos de las 218 mutaciones y los vectores IBE de los fixtures nuevos; + - `note.json`, y la nota pública en `inspect`, que la lee bajo demanda. + + El port del CMS lo hizo un agente: un diferencial suyo de 63 623 áreas no dio ninguna diferencia con Go, y el código anterior difería en 13 296 de 42 986. +- `289fe71`: README y CHANGELOG. +- **Verificación:** `npm run verify` (7 759 pruebas, cobertura y build con sus guardas) y `testdata:check` contra Go. + +**`datekeys-dart`, rama `v0.11`, solo local (no tiene remoto):** +- `5aa5eed`, etapa 0: + - el paquete `datekeys`, Dart 3.13, sin publicar; + - `testdata` en `spec-v0.11`, 124 ficheros, con el mismo `SOURCE.json` que escribe el TypeScript; + - `tool/sync_testdata.dart`, pruebas de integridad y de versión, y `tool/check.sh` como gate; + - licencia Apache-2.0; + - dependencias: `crypto` en ejecución y `test` en desarrollo, aprobado por el autor el 5-10. +- `da63bc3` a `10b0895`, etapa 1, también de un agente: + - errores del §69; + - bytes: UTF-8 estricto propio, porque el `Utf8Decoder` de Dart quita un U+FEFF inicial; y el `%q` de Go con su tabla `IsPrint`; + - el códec CBOR de `codec.go`; + - el DER de la v0.12. + + Los enteros son exactos en la VM y en la web: un `int` hasta 2^53 − 1 y un `BigInt` por encima. Hay 169 pruebas en la VM y 56 también en Node, y una comparación con Go de 263 611 casos no dio ninguna diferencia. + +**Siguiente, en orden** +1. **El autor aprueba el borrador v0.12:** §76, cambios 1 a 9, con el 6 ampliado y el 3 precisado el 5-10. Sigue abierto si se mide antes el área de 32 KiB con firmas reales. El 5-10 el autor dejó las dos cosas para más adelante («la aprobación y la medida, luego»). Con la aprobación: el SHA-256 en `spec/README.md`, `SpecVersion` 0.12, el tag `spec-v0.12` y `main` avanzado sin fusión, siempre con permiso del autor. + + Decidido el 5-10 («sí a las dos»): + - **«Con texto» en el §29.7:** el titular toma `givenName` y `surname` solo si los dos tienen texto no vacío, y el emisor toma el `organizationName` si no tiene un `commonName` con texto. Es lo que ya hacían Go y el TypeScript. Está en `424cdf3`, subido. + - **`dart test -p node` en el gate de Dart:** `c8bf3c0`. +2. **Dart, etapa 2:** las primitivas y `age`, según [PLAN_dart.md](PLAN_dart.md). Se encargó el 5-10 y se detuvo sin escribir nada al cerrar la sesión: hay que relanzarla. +3. **Dart, etapa 3:** BLS12-381 y tlock, pedida por el autor para después de la 2. +4. **TypeScript, sin urgencia:** el localizador, que aún no está portado; que la página muestre la nota pública, que ya lee `inspect`; y lo pendiente del §2.5. + +**Observaciones del 5-10, sin decisión:** +- El error de una nota pública con un tabulador dice «in the declared author», porque la nota usa las reglas del autor declarado. Está en `note.json` y el TypeScript lo copia: cambiarlo exige tocar los dos lados. +- Hecho el 6-10: `testdata` ya tiene los vectores compartidos de la llave de palabras, `vectors/wordkey.json`. +- A G: le quedan 1,5 GB libres. +- Flutter está instalado en `C:\dev\flutter`, y su Dart 3.13.0 es el `dart` del PATH. +- La carpeta sigue llamándose `App`, y `enquiry.php` sigue en la raíz (§0). + +**Para trabajar:** lo del apartado del 2-10, y además: +- Un worktree en el scratchpad permite trabajar mientras `check.sh` corre en la copia principal. +- Dos fuzzings a la vez no deben solaparse, porque comparten la caché de fuzzing de `GOCACHE`. + +--- + +## Estado al cerrar la sesión del 2 de octubre (histórico: lo actual está arriba) + +**Qué pasó.** La sesión que cerró la v0.11 (1-10, de 19:42 a 01:05) corrió con Sonnet 5.5. El 2-10 se revisó todo lo que hizo con seis revisores de Opus: [spec_v0.11/revision_sesion_1_2_octubre.md](spec_v0.11/revision_sesion_1_2_octubre.md). +- **Resultado:** nada bloqueante. El núcleo criptográfico estaba bien. +- **Fallos encontrados:** + - cómo se puso el tag; + - la paridad entre Go y TypeScript con los certificados; + - unos vectores que cubrían mucho menos de lo que decían; + - la presentación (un nombre de certificado podía imitar una línea de veredicto); + - comprobaciones del escritor que faltaban; + - documentación desfasada. +- **Arreglos:** casi todos hechos el mismo 2-10. Lo pendiente está abajo. + +**Decisión aplicada (E1).** El tag `spec-v0.11` no se toca: es una versión cerrada. Los cambios de texto normativo van a un **borrador v0.12 sin aprobar**: `datekeys-go/spec/DateKeys_Protocol_Specification_v0.12.md`, cuyo §76 «Cambios normativos de la v0.12» lista los nueve cambios con su caso. + +**Repositorios** +- **`datekeys-go`:** la rama **`v0.12`**, subida, implementa el borrador v0.12. `main` y el tag `spec-v0.11` siguen en `ae33434`, sin tocar, y `SpecVersion` sigue en 0.11 hasta la aprobación. +- **`App` (`datekeys-ts`):** la rama `v0.10`, subida, con cinco commits nuevos (`06e992f` a `fc5fb24`). Su `testdata` sigue sincronizado con `ae33434` (`spec-v0.11`). +- **`docs`:** local. La revisión está en `d60b856`, los planes de Dart y de la firma en `ac47bf6`, y este handoff en el commit siguiente. + +**Hecho el 2-10 en Go (rama `v0.12`)** +- **Claves de autor, escritor, CLI, extensiones y localizador** (`fee531b`): + - `Key.String()` oculta la clave secreta, y `ParsePublic` exige un punto de la curva; + - un nil con tipo da error; + - un pánico al evaluar la firma o el sello solo afecta a su parte (F1 o S2); + - `OpenOptions.Accept`; + - `extension.CheckWrite`, la regla del encoder del §72; + - en la CLI, `encrypt -sign` muestra el código; `-expect-author` no escribe nada si la clave no coincide; las líneas de veredicto se parten con ` ↳ `; y se avisa de una nota inutilizable; + - en el localizador, las direcciones no públicas de IANA y los nombres locales se rechazan, se descarta una dirección mala sin perder las demás, y `ParseInfo` ata el localizador a su ronda. +- **Lector CMS** (`839e117`, `b06ab4f`): + - un perfil de certificado propio, campo a campo, sin `encoding/asn1` ni `crypto/x509`; + - los OID se comparan por sus bytes, y un SET OF puede repetir elementos; + - una clave que no casa con su algoritmo es F2, y un imprint de otra longitud es S3; + - los tiempos DER se comprueban, y NumericString y los demás tipos de cadena son DER válido; + - el titular sale de `givenName` y `surname`, delante del CN que lleva el NIF. +- **Borrador v0.12 y textos de los veredictos** (`840c87e`): + - los nombres de certificado van entre «», con 64 puntos de código como máximo y sin espacios dobles; + - la línea de cada firmante de F6 nombra su autoridad de sellado, seguida de «DateKeys no comprueba quién emitió los sellos.»; + - el resultado de un firmante ajeno sale en español. +- **Datos de prueba:** + - el generador vuelve a escribir los fixtures de la v0.10 con 512 bytes (`EncryptOptions.TestAreaLen`, solo con `TestVectors`), y `-force` ya no rompe (`e597760`); + - `format3_seal_unsupported` usa `seal_type` 4294967295, y hay `format3_unsigned` (32 KiB y la misma P que la firmada), `format3_note`, `security.json` con contexto y líneas (`aaf0f41`), y 8 mutaciones nuevas de `alg` 1, del área y de la nota (`6c78c94`, 218 casos); + - `note.json` (`88ccbfd`); + - `security_cms.json`, que pasa de 22 a 135 casos con sus `lines` (`edff5d1`). +- **Pruebas y fuzzing:** + - pruebas negativas de cada regla del lector CMS: de 949 mutantes, los 91 que sobreviven son equivalentes (`4ce4d59`); + - siete objetivos de fuzzing nuevos, del localizador, de DER y de CMS (`ec08ec9`, `ad40329`); + - pruebas de la regla 25, de la nota inutilizable y de la recuperación ante un pánico (`9b1123d`). +- **Documentación** (`858c5f1`, `2aff4a0`): los README, `SECURITY.md`, `docs/traceability.md` y el CHANGELOG, puestos en la v0.11 y el borrador v0.12. +- **Verificación:** `go test ./...` en verde en `ad40329`. `scripts/check.sh` pasó entero sobre `2aff4a0` (`-race`, cobertura de `capsule` 91,6 %, govulncheck y vectores reproducibles). Su fuzzing se paró tras tres objetivos limpios, para cerrar la sesión. Los objetivos nuevos se pasaron aparte, de 40 a 60 s cada uno, limpios. + +**Hecho el 2-10 en TypeScript (rama `v0.10` de `App`)**, con `npm run verify` en verde (7 432 tests): lo que no dependía del borrador v0.12. +- T1: el emisor que incumple las reglas se muestra con el hash de su nombre. +- T3: solo claves EC sin comprimir. +- T4: la nota con UTF-16 mal formado se rechaza. +- T5: ningún decodificador quita un BOM. +- T9: `testVectors` y `areaLen` salen del API público y pasan a `testing/`. +- T10: `capsule-vectors.json` regenerado con 32 KiB y nota; Go lo abre. +- T11 y T12: la longitud con nota, y el formato 2 sin nota ni área. +- T13, en parte: `evaluateSecurity` no lanza nunca, y los lectores de OID son lineales. +- T14: README y CHANGELOG. + +**Siguiente, en orden** +1. **El autor revisa y aprueba el borrador v0.12** (§76, cambios 1 a 9). Las decisiones que contiene, todas con la recomendación de la revisión: + - las líneas de F6 con la autoridad y el aviso; + - las reglas de los nombres de certificado y la marca ` ↳ `; + - `givenName` y `surname` delante del CN; + - la lista de bloques no públicos de IANA y de nombres locales; + - el perfil del certificado; + - `accuracy` hasta 2³¹ − 1; + - los tamaños del localizador en el CDDL. + + Queda también abierto si se quiere medir el área de 32 KiB con firmas reales antes de cerrar (pregunta 6 de la sesión anterior). Con la aprobación: el SHA-256 en `spec/README.md`, `SpecVersion` 0.12, el tag `spec-v0.12` y `main` avanzado sin fusión, siempre con permiso del autor. +2. **Go, lo que falta:** + - **`locator.json` ampliado:** + - en `uri_cases`, una dirección de cada bloque no público, los nombres locales, los caracteres fuera de RFC 3986, los segmentos `..` y un CID que no decodifica; + - un localizador con una dirección rechazada y otra válida; + - otra ronda, un resto con otro SHA-256 y un recurso que sigue tras el resto; + - las bases de relleno 3837, 4094, 4095, 7933, 8166 y 8191. + + El generador está en `internal/testkit/genfixtures/cmsvectors.go`. Es un vector congelado: se borra y se regenera. + - **`testdata/README.md`,** que sigue en la v0.10. Debe recoger: + - `security.json` con contexto y líneas; + - `note.json`; + - `format3_unsigned` y `format3_note`; + - las 218 mutaciones; + - `security_cms.json`, con el texto que dejó su agente: está en el informe de su commit `edff5d1` y se puede rehacer leyendo el generador; + - `locator.json`, cuando se amplíe. + - Las marcas *pending* de `docs/traceability.md` y el apartado «Pending in this branch» del CHANGELOG. + - Un `scripts/check.sh 60s` completo. +3. **TypeScript, segunda parte:** + - **Datos:** sincronizar `testdata` con la cabeza de `v0.12`. + - **Lector CMS:** portar el perfil de certificado de la v0.12 (T2, T6, T7, T8), los OID por bytes, los SET OF con repetidos, NumericString y los demás tipos de cadena como DER, y los casos límite (E9). + - **Textos:** los nuevos de los veredictos (comillas, autoridad de cada firmante, aviso, resultados en español, `t` en RFC 3339 con fracción), el titular por `givenName` y `surname`, y las reglas de 64 puntos de código y espacios dobles. + - **Escritor:** la regla de `CheckWrite`. + - **Vectores y fixtures:** `security.json` con su estructura nueva; `note.json`; los fixtures `format3_unsigned` y `format3_note`, y los `ibe-vectors` de los fixtures nuevos o cambiados; las 8 mutaciones; los 135 casos de `security_cms.json` con sus líneas. + - **Pruebas:** la tautología de `cms.test.ts:106`. + + El TypeScript no tiene todavía el localizador. Es una función pendiente, no un fallo. +4. **Dart:** el plan está en su v2, [PLAN_dart.md](PLAN_dart.md), con las tres decisiones del autor del 2-10: solo `package:crypto`, primero la lectura y paquete `datekeys`. + - Se empieza por la etapa 0, el esqueleto con `testdata` sincronizado. Para la etapa 4, el generador `pathrule/gen` necesita una salida `-dart`. + - La etapa 5, la de firmas y sello, se sincroniza con `v0.12`, no con `spec-v0.11`. + +**Para trabajar** +- **Gates:** + - `scripts/check.sh` en `datekeys-go`: los tests con `-race` de `capsule` tardan minutos. Si lo paras, mata también `fuzz.sh` y los procesos `*.test.exe`, que quedan huérfanos. + - `npm run verify` y `npm run testdata:check` en `datekeys-ts`. +- **El generador:** + - `go run ./internal/testkit/genfixtures -out testdata` no toca los fixtures que ya existen, ni sus registros. + - **No uses `-only mutations`:** regenera los 33 casos congelados del corpus. Para añadir mutaciones basta una ejecución normal. + - Los vectores congelados (`security_cms.json`, `locator.json`) se rehacen borrándolos. +- **Herramientas de esta máquina:** + - Los heredocs de Bash rompen las barras invertidas y los apóstrofos. + - La herramienta Write convierte `\uXXXX` en caracteres literales; en Go, escribe esos escapes con un script. + - `go test … | tail` esconde el código de salida: mira `$?` antes de hacer commit. Una vez se hizo commit con una prueba rota (`e597760`, arreglada en `0f51af7`). +- **Agentes:** el trabajo en paralelo en Go se hizo con agentes en clones propios del scratchpad y ficheros repartidos, integrados con `git fetch` y `cherry-pick`. Los subagentes, con `model: "opus"`. + +--- + +## 0. Reorganización del espacio de trabajo (29-09, mediodía) + +`G:\bussines\datekeys` se reorganizó el 29-09. El mapa de carpetas y las reglas del proyecto están ahora en el [README](README.md) de este repo. Los cambios: +- **Documentos:** los del proyecto, este incluido, pasaron de `App/docs` a este repo, `docs`, que es privado y no tiene remoto. Su primer commit es `6e8d6c6`. Los papeles de trabajo de la v0.9, que solo estaban en una carpeta temporal, están en [spec_v0.9/](spec_v0.9/README.md). +- **`App`:** quitó `docs/`, y el paquete, el README y el aviso de licencias del sitio pasan a llamarse `datekeys-ts` (`5ee8813`, subido). `npm run verify` sigue en verde, con 2 611 tests. +- **Archivo y logos:** + - `AppOld` pasó a `archive/prototype`, sin cambios; + - los borradores v0.1 a v0.8.1, que estaban en Descargas, pasaron a `archive/spec-drafts`, con los hashes comprobados; + - los logos pasaron a `brand/`. +- **Claude:** + - la memoria de Claude es ahora la de la raíz. La de `App` queda congelada, con una nota que remite a la nueva; + - en la raíz hay un `CLAUDE.md`, que carga el README, y un `.claude/launch.json` para las vistas previas. +- **Nombres:** en las secciones siguientes, `App` es el repo que ahora se llama `datekeys-ts`. Su remoto sigue siendo `go/DateKeys-App`. + +Pendiente del autor, antes de seguir: +1. Cerrar la sesión abierta en `App` y renombrar la carpeta a `datekeys-ts`. Windows no deja renombrar una carpeta en uso. +2. Abrir las sesiones siguientes en `G:\bussines\datekeys`. La primera comprueba `npm run verify` y `npm run testdata:check` en `datekeys-ts`. +3. Borrar `G:\bussines\datekeys\enquiry.php`, que es una copia idéntica de `web/static/api/enquiry.php`. Claude no tiene permiso para borrarlo. +4. `docs` y `web` solo existen en esta máquina. Para tener una copia fuera de ella, hay que darles un remoto. + +El 30-09 a mediodía seguían pendientes los cuatro: la carpeta se llama todavía `App`, y la sesión de ese día también se abrió en ella. + +--- + +## 1. Repositorios + +*Histórico, del 30-09: el estado actual está en «Retomar aquí».* + +Los repos con remoto están en el Gitea privado `g.activething.com` (solo LAN, certificado autofirmado para `git.activething.com`; git funciona, `curl` necesita `-k`). **Ese servidor no es del autor**: no se proponen cambios en él. La integración continua es el gate local. + +| Repo | Rama | Commit | Estado | +|---|---|---|---| +| `datekeys-go` (`go/DateKeys`) | `main` | `cc35d2c` | Spec v0.10, entrega 1 del formato 3, aprobada por el autor el 30-09 y cerrada con el tag anotado **`spec-v0.10`** en `cc35d2c`; SHA-256 del spec `7f26419a444aa3e89a3aa8afbbba9d952af69e048aee1e93cd70732c2d1d99d1`. Implementa el formato 3: lo escribe y lee los formatos 1 a 3, con `SpecVersion` 0.10. `scripts/check.sh 60s` limpio. La v0.9 sigue en su tag, `spec-v0.9` (`7e2d83c`), y la v0.8.2 en el suyo, `spec-v0.8.2` (`9ac9cd9`). | +| | `v0.8.2` | `9ac9cd9` | El commit del tag; ya no hace falta. | +| | `v0.9` | `7e2d83c` | El commit del tag `spec-v0.9`; ya no hace falta. | +| | `v0.10` | `cc35d2c` | Igual que `main`; ya no hace falta. | +| `datekeys-ts`, antes `App` (`go/DateKeys-App`) | `main` | `da26862` | Desde `5ee8813`, sin `docs/` y con el paquete `datekeys-ts` (§0). Versión `0.2.0-dev` desde `8c08c97`, con `v0.1.0` cerrada en `d577283`; implementa el spec 0.9 desde `0118890` (`VERSION` y `SPEC_VERSION`, también en el pie de la página). Escribe el formato 2 y tiene la página `/create` (fase 3, §2.5). Librería TypeScript con la inspección (pasos 1 a 8) y la apertura (pasos 9 a 18) de los formatos 1 y 2, en memoria o desde un `Blob` hacia un stream de salida, como un fichero OPFS. Página `/inspect` con la acción "abrir", que muestra el formato y avisa del 1. `testdata` sincronizado a `7e2d83c` (`spec-v0.9`). Fase 2 completa (pasos 2 a 8), incluidos el cifrado tlock y la interoperabilidad de TypeScript a Go. Los 125 casos del corpus pasan por `open` con el código, el paso y el texto de Go. En `0118890`, 5 425 tests, ninguno saltado; la fase 3 añadió los suyos, con `npm run verify` en verde en cada paso (§2.5). | +| `docs` (solo local) | `main` | | Este repo: handoff, planes, revisiones y reglas. | +| `web` (solo local) | `main` | `f2b8a38` | Landing de datekeys.com. | +| `archive/prototype`, antes `AppOld` (solo local) | `master` | `4d2b0a1` | Prototipo antiguo. No se toca. | + +Verificación ya hecha sobre `datekeys-go`: +- fuzzing de 30 min en cada uno de los 15 objetivos sobre `3820066`, limpio; +- diferencial Go/TypeScript de 407 196 entradas contra `f6f2e9f`, con cero diferencias, textos de error incluidos; +- `scripts/check.sh 60s` sobre `9ac9cd9`, el commit del tag, limpio (28-09), y sobre el estado de `6fa2b54`, con tres objetivos de fuzzing nuevos del formato 3, limpio (30-09); +- govulncheck no encuentra nada alcanzable. Avisa, sin llamada alcanzable, de dos problemas: + - GO-2026-6443, en `google.golang.org/grpc` 1.84.0, arreglado solo en una versión `-dev`. Hay que subir grpc cuando salga la 1.85.0. + - GO-2026-5932, en `golang.org/x/crypto/openpgp`, sin arreglo. No lo importamos. + +--- + +## 2. Qué queda, en orden + +### 2.1 Hecho el 28-09: cierre de la v0.8.2 + +- Los 9 retoques de la 2.ª revisión están en `9ac9cd9`, un solo commit sobre `c57ed48` que absorbe el WIP `69a3342`. La rama WIP está borrada. +- §76 los recoge como correcciones 4 a 6: + - un encoder MUST NOT escribir una extensión fuera de su registro; + - §17 y §51 dan los códigos del paso 10 solo para un release suministrado directamente; + - en el paso 9, cualquier fallo de la fuente es `ERR_RELEASE_UNAVAILABLE` y ningún otro código. +- La regla del encoder no se comprueba en la librería: `capsule.Encrypt` y `accesskey.Encode` no reciben `Registry`, y la aplica la aplicación. Está documentado en `extension.Placement`. +- El autor aprobó el texto el 28-09. El spec lleva esa fecha, y el SHA-256 de sus bytes LF, `5cfa3203…`, está en `spec/README.md` y en el mensaje del tag. +- `main` avanzó por fast-forward hasta `9ac9cd9` y lleva el tag `spec-v0.8.2`. Los dos están subidos. +- `App` sincronizó `testdata` con `9ac9cd9` en `71ab8fb`. Solo cambia `testdata/README.md`. + +Las reglas que siguen valiendo (testdata, textos de error y versiones cerradas del spec) están en el [README](README.md#reglas). + +### 2.2 Fase 2: abrir cápsulas en el navegador + +Plan: `docs/PLAN_fase2_ibe_noble2.md` v2, con las decisiones confirmadas por el autor. Los pasos 2 a 8 de su sección 10: +- hecho el 28-09 (`74e1215`): `age-encryption` 0.3.1 y noble 2.4.0 como dependencias de ejecución, con sus guardas en `src/lib/dependencies.test.ts` y `check-build.mjs`. El README de `App` recoge el coste medido en el bundle, 73 KB con gzip para todo, y `npm audit`; +- hecho el 28-09 (`35be27c`): `ibe.ts` sobre noble 2, con vectores de Go en `src/lib/dkc/testing/ibe-vectors.json` (`scripts/ibe-go-vectors.go`) y cobertura del 100 % fijada como umbral. Los argumentos del stanza y su paso al `Stanza` de `age-encryption`, que guarda el tipo en `args[0]`, van al paso 7; +- hecho el 28-09 (`076f3db`): `release.ts`, con `verifyRelease` en el orden y con los textos de `provider.Verify`, `ReleaseSource` y `suppliedRelease`. Solo verifica el scheme de Quicknet: otro da `ERR_UNKNOWN_PROFILE`. Reproduce los 7 casos del corpus que fallan en el paso 10; +- hecho el 28-09 (`97827ae`), paso 5a: `open.ts`, los pasos 9 a 18 con el texto en claro en memoria. Las identidades estrictas de `agewrap` se apoyan en `x25519.ts`, que abre los stanzas de uno en uno. Usa `@noble/ciphers` 2.4.0, dependencia directa aprobada ese día: es la copia que ya usa `age-encryption`. Las identidades `AGE-SECRET-KEY-1…` se leen con `bech32.ts`. `index.ts` no reexporta aún la apertura, que metería noble en `/inspect`; +- hecho el 28-09 (`a89bee5`), paso 5b. `open` acepta un `Blob` del que solo lee el prefijo de los pasos 1 a 8 (`prefix.ts`, movido de la página a la librería), calcula el `capsule_digest` en streaming (`digest.ts`) y descifra `PAYLOAD_AGE` en streaming. La salida puede ser un `WritableStream`, que se cierra tras el paso 18 y se aborta ante cualquier fallo. Comprobado en el navegador con OPFS real: un fallo de STREAM deja intacto el fichero; +- el paso 6 está cubierto: la enmienda de canonicidad entró en la v0.8.2; +- hecho el 28-09 (`66970cf`), paso 7: `encryptOnG2RFC9380` y `timeRecipient`. Con sigma fijo, el cifrado reproduce byte a byte los vectores de Go. Go abrió los cuerpos IBE y los ficheros `age` que cifró esta librería, con `tlock.TimeUnlock` y con `agewrap.NewTimeIdentity`. Todo está en `src/lib/dkc/testing/tlock-vectors.json`; +- hecho el 28 y 29-09 (`48d6704`), paso 8: la acción "abrir" en `/inspect`, cargada bajo demanda, con la política aprobada por el autor el 28-09 tras revisar lo que dice el protocolo: + - el release lo pega quien abre, o sale del registro del fixture, y la página nunca lo pide a la red; + - el texto en claro de un fichero propio va a un fichero temporal de OPFS (§56), que se borra; + - los avisos de licencia se publican en `licenses.txt`. + Una revisión adversarial confirmó 15 hallazgos, todos corregidos. Los detalles y las comprobaciones en el navegador están en la fila 8 del plan. + +La lectura del protocolo del 28-09 deja dos SHOULD para más adelante: §48 (varios relays) y §49 (obtener el release directamente del proveedor). Los cubrirá una fuente drand opcional del SDK, nunca activa por defecto en la página (sección 12 del plan). + +El vector de GT (`vectors/tlock_ibe.json`) ya está cubierto en `App`. El paso 9 de `open.ts` debe seguir la corrección 6: cualquier fallo de una fuente es `ERR_RELEASE_UNAVAILABLE` y ningún otro código. + +### 2.5 Sesiones del 29-09: v0.9 del spec y formato 2 en Go (retomar aquí) + +**Estado al parar (30-09 por la noche). Retomar por el formato 3, al final de esta sección:** la spec v0.10, entrega 1 del formato 3, está aprobada, implementada en la referencia Go y cerrada con el tag `spec-v0.10`, todo subido en `main` de `datekeys-go` (`cc35d2c`). Lo siguiente es el formato 3 en `datekeys-ts`. + +**Estado al cerrar la fase 3 (29-09 por la noche):** +- Pasos 1 a 5 hechos. El spec v0.9 está cerrado con el tag `spec-v0.9` (`7e2d83c`, en `main` de `datekeys-go`), y las dos implementaciones leen el formato 2: Go desde `f24a280`, que también lo escribe, y TypeScript desde `0118890`. +- Paso 6 hecho: la fase 3 está completa en `datekeys-ts` (pasos 0 a 7 del plan, hasta `3a9d2b1`, subido). La librería escribe el formato 2, Go abre lo que escribe y la página `/create` cifra en el navegador. La versión `0.2.0` sigue sin publicar: cerrarla es decisión del autor (§2.3). Después, a petición del autor, `/inspect` muestra el contenido al abrir, debajo del veredicto, y nombra la descarga por su tipo. Las páginas explican las claves de `age`, y la vista previa sirve las páginas sin caché (`da2000a`, `da26862`, subidos). +- Las 22 correcciones del repaso final ([spec_v0.9/review.md](spec_v0.9/review.md)) se aplicaron en `4a025d1`, más cuatro sitios que repetían los mismos problemas: las reglas 1 y 4 del §62.1 y los cambios 4 y 10 del §76. Los números de la corrección 1 se recalcularon con un Padmé en BigInt. +- La corrección 2 la decidió el autor el 29-09: se suaviza el §56. + - El lector MUST NOT presentar el contenido como válido antes de que termine el paso 17. + - Un lector en streaming MUST NOT escribir el relleno y MUST señalar el error para que se descarte lo escrito. + - Así siguen valiendo `Open(dst)` de Go y la salida en streaming de TypeScript. +- En este repo están [PLAN_fase3_escritura.md](PLAN_fase3_escritura.md), el plan del writer TypeScript, y [REVISION_completitud_protocolo.md](REVISION_completitud_protocolo.md), la revisión del protocolo. El plan está en su v3: el autor confirmó sus 17 decisiones el 29-09. + +**Aprobación del 29-09.** El autor aprobó el texto de la v0.9 con las respuestas recomendadas a las preguntas abiertas: +1. L es un `bstr` de 8 bytes, no un `uint`. +2. El lector SHOULD informar del formato. +3. Se mantienen el objetivo 8 de §4 y el no objetivo nuevo de §5. +4. Solo un generador de vectores de prueba MAY escribir el formato 1 (§62.1, regla 1, y §70). +5. Los fixtures nuevos llevan el prefijo `format2_`. +6. Se mantiene D1: los señuelos son identidades generadas cuya clave privada se descarta en el acto. +7. Rechazar puntos del twist sigue siendo MAY. +8. Se confirman las reglas añadidas: L_MAX = 2⁵³ − 2⁴⁶, el orden uniforme de los stanzas, que el SDK SHOULD mostrar el instante efectivo de la ronda y que el lector MAY comprobar la longitud de PAYLOAD_AGE. + +**Decisiones del autor del 29-09 para la v0.9:** +- D1: `time_and_key` lleva siempre exactamente 16 stanzas X25519 en `INNER_ACCESS_AGE`. Los que sobran son señuelos, y todos van en orden aleatorio. Como mucho hay 16 credenciales, contando la `.dkk`. +- D2: el contenido se rellena siempre. El código 1 redondea al siguiente múltiplo de 256, con un mínimo de 256. El código 2, "reforzado", es max(bloque256, Padmé) y es el de por defecto. No hay opción sin relleno. +- D3: la longitud real y el código van en `CONTROL_CBOR` versión 2 (claves 6 y 7). El lector entrega solo L bytes y comprueba que el relleno sea todo ceros y que siga la regla. +- D4: el formato pasa a 2 (`VERSION` 2 del PRELUDE), así que un lector v0.8.2 lo rechaza en el paso 2, sin red. Un lector v0.9 sigue abriendo el formato 1. +- D5: `access_policy` sigue visible. +- D6: nueva sección de privacidad, §55.2. +- D7: reglas normativas del escritor, §62.1: + - `I_PAYLOAD` sale de un CSPRNG y no se reutiliza; + - límites; + - la fecha pedida tiene que ser futura; + - el escritor se autocomprueba; + - rechaza claves X25519 no canónicas o de orden bajo. + +**Hecho en Go, paso 3 (`f24a280`):** +- **Formato 2 en la librería:** + - `capsule`: `Format`, `Padding`, `PaddedLength`, `PayloadAgeLength`; `EncodeControl` y `DecodeControl` reciben el formato; `Open` aplica los pasos 12 a 18 del formato 2. + - `agewrap`: `AccessSlots` y `CheckX25519Recipient`. +- **Escritura:** + - `Encrypt` escribe solo el formato 2. + - `EncryptOptions.Length` es obligatorio; `Padding` es reforzado por defecto. + - Acepta de 1 a 16 credenciales, con señuelos, orden aleatorio y autocomprobaciones. + - La CLI mide la entrada, acepta `-padding` e informa del formato. +- **`testdata`:** + - 7 fixtures `format2_*`, dos de ellos con `.dkk`; + - `vectors/padding.json`; + - los vectores CBOR del formato 2; + - un corpus de mutaciones de 125 casos: 88 del §64 (33 en cada formato y los 22 de la tercera lista) y 37 más; + - un diferencial de 4 380 casos, en el que los 1 825 anteriores no cambian. + - Los fixtures del formato 1 se conservan byte a byte. +- **Mutaciones sin aleatoriedad:** se vuelven a sellar los fixtures con sus claves y nonces conocidos (`internal/testkit/reseal.go`), así que se regeneran byte a byte. +- **`scripts/check.sh 60s` limpio:** + - cobertura: codec 100 %, capsule 94,2 %, accesskey 97,2 %, datekey 94,6 %, agewrap 92,8 %; + - govulncheck, con los mismos dos avisos de §1; + - 60 s de fuzzing en cada uno de los 15 objetivos. +- **Documentación:** la copia del spec del repo pierde las marcas "(por implementar)". README, README.es, CHANGELOG, `docs/traceability.md` y `testdata/README.md` están al día. + +**Orden de trabajo:** +1. Aplicar y verificar las 22 correcciones. Hecho el 29-09 (`4a025d1`). +2. El autor aprueba el texto de la v0.9. Hecho el 29-09. +3. La referencia Go implementa el formato 2, con fixtures nuevos y mutaciones, y pasa `check.sh`. Hecho el 29-09 (`f24a280`). +4. Se pone el tag `spec-v0.9`. Hecho el 29-09, con la autorización del autor: + - `7e2d83c` anota el SHA-256 del spec en `spec/README.md`, que también va en el mensaje del tag; + - `main` avanzó hasta ese commit sin merge; + - `main`, `v0.9` y el tag están subidos. +5. `datekeys-ts` sincroniza `testdata` y el lector TypeScript abre el formato 2. Hecho el 29-09 (`0118890`, subido): + - `testdata` a `7e2d83c`; + - el prelude lee el formato; `decodeControl` y `encodeControl` reciben el formato; `padding.ts` con las dos reglas, exactas hasta L_MAX; + - `open` exige 16 stanzas en el paso 12, calcula P en el 16 y comprueba el relleno en el 17, entregando solo los L primeros bytes; el paso 17 se registra también cuando se supera; + - la página muestra el formato, avisa del 1 y, al abrir una cápsula del formato 2, da la regla y P; + - `ibe-vectors.json` añade los siete fixtures del formato 2, calculados con `scripts/ibe-go-vectors.go`; los valores congelados no cambian; + - comprobado: los 125 casos del corpus dan en TypeScript el código, el paso y el texto de error de `capsule.Open`, en memoria y desde un `Blob`. +6. Se replantea el plan de la fase 3 y se escribe el writer TypeScript del formato 2. **Hecho el 29-09.** El 29-09 por la noche, [PLAN_fase3_escritura.md](PLAN_fase3_escritura.md) pasó a su v2, sobre las reglas del §62.1: + - 16 huecos con señuelos y orden uniforme; + - relleno `reforzado` por defecto; + - L conocida de antemano; + - autocomprobaciones; + - recipients canónicos y no de orden bajo, como Go; + - `SEALED_CONTROL_LEN` con la fórmula del §62.1 y comprobada. + Una revisión crítica con sondas no encontró nada bloqueante ni grave, y sus 12 correcciones menores están incorporadas. + + Hecho el 29-09 en `datekeys-ts`, todo subido y con `npm run verify` en verde en cada paso: + - paso 0: el autor confirma las 17 decisiones con su recomendación, entre ellas cerrar `0.1.0` ya (D14), la fórmula del §62.1 comprobada con el sellado real (D3) y aceptar los puntos del twist, como Go (D6). El plan pasa a v3 (`b97dee2` en este repo); + - paso 1: `0.1.0` cerrada (`d577283`, tag `v0.1.0`) y `0.2.0-dev` abierta (`8c08c97`); + - paso 2 (`8838c7d`): `recipient.ts`, `random.ts` y `agefile.ts`, y las guardas nuevas; + - pasos 3 y 4 (`8473fdf`): `encrypt.ts` y `writer.ts`. Reproducen byte a byte las secciones deterministas de los siete fixtures del formato 2 de Go, escriben en streaming y abortan la salida ante cualquier fallo. El bucle de propiedades pasa con 500 semillas; + - paso 5 (`da0b39f`): Go abre con cada credencial las trece cápsulas de muestra que escribe TypeScript, y las reencodifica a los mismos bytes. Rechaza cuatro mezclas con el mismo código y paso, codifica igual 500 entradas aleatorias y da los mismos textos en 22 recipients y 21 opciones inválidas. Todo queda congelado en `src/lib/dkc/testing/capsule-vectors.json`. + + - paso 6: el autor confirma las decisiones de la página con cada recomendación (sección 9 del plan, «Decidido en el paso 6»): `time_only` por defecto, la zona del dispositivo con un selector, los avisos de §53 y §50 desde 365 días y un aviso de protocolo preliminar; + - paso 7 (`3a9d2b1`): la página `/create`, con `lengths.ts` (el tamaño del `.dkc` antes de escribirlo), `localtime.ts`, `create-input.ts` y `creator.ts`. En la compilación de producción, una cápsula creada para dentro de cuatro minutos se abrió después en `/inspect`, con el release pegado de drand, y con `datekeys decrypt` de Go, con red y su `.dkk`, al mismo contenido. Una revisión adversarial encontró un fallo mayor y ocho menores, todos corregidos. El mayor: la `.dkk` que es la única credencial se podía borrar sin confirmación. + + - después, a petición del autor (`da2000a`): `/inspect` muestra el texto en claro de cualquier cápsula que se abre, si es texto, y no solo el de los fixtures. Las dos páginas explican las claves de `age`: qué es un destinatario `age1…`, cómo se consigue con `age-keygen` y qué se pega al abrir. + + **Siguiente:** que el autor decida si cierra `0.2.0` (tag `v0.2.0` en `datekeys-ts`). Después, lo de §2.4. + +**Formato de cápsula 3, en diseño (30-09).** El autor quiere que una cápsula guarde varios ficheros y carpetas con sus nombres, tamaños, hashes y fechas, más una firma de autor y un sello de tiempo, ambos opcionales. Hoy el nombre del fichero se pierde: §6 y §55.2 lo dejan fuera del protocolo. +- Decisiones del autor: + - todo va cifrado dentro de `PAYLOAD_AGE`, como `security | head | content`; + - hash SHA-256 por fichero, sin hash global; + - con carpetas; + - la fecha de modificación se toma al cargar, marcada por defecto; + - un comentario y un autor declarado, opcionales; + - sin tipo de contenido; + - firma Ed25519 y sello de DateKeys, con registro anclado en OpenTimestamps. +- Un flujo de diseño con revisión adversarial produjo [spec_v0.10/formato3_diseno.md](spec_v0.10/formato3_diseno.md): 28 objeciones, que resultaron ser 24 distintas, corregidas o aceptadas. +- El paquete para la revisión de seguridad externa, con el contexto del protocolo, el modelo de amenazas y las preguntas, era `spec_v0.10/formato3_para_revision.md` (`56851a9`). Se borró al unificar el diseño, pero sigue en git y publicado como artefacto privado, en la versión que revisó Fable: https://claude.ai/artifact/5NY9YxBjZA6DCadZ1aT5Ln. +- **Revisión de Fable (30-09),** guardada en [spec_v0.10/revision_fable.md](spec_v0.10/revision_fable.md). + - **Veredicto:** la parte criptográfica aguanta, y confirma la aritmética de tamaños y la necesidad del verificador Ed25519 propio. Los problemas están en los bordes. + - **Diez hallazgos**, cuatro mayores y seis menores; también hay observaciones sobre el documento. + - **Valoración:** coincido con todos. Comprobados de memoria: el 2 (la lista de git en `core.protectHFS` incluye ZWJ, ZWNJ y U+206A–206F) y el 6 (JavaScript compara en UTF-16: U+FF5E y un emoji quedan al revés que en Go). +- **Arreglos que no necesitan decisión:** + - **2.** R4 por la propiedad `Default_Ignorable_Code_Point`, con lista blanca corta (ZWJ, ZWNJ, VS15, VS16); la clave de R7 descarta lo permitido; tags U+E0000 a U+E007F prohibidos. + - **5.** El tamaño del área de `security` va en la trama, fijo por versión y reservado siempre. + - **6.** TypeScript compara bytes UTF-8, con un vector en `paths.json`. + - **7.** En la CLI, prefijo en cada línea visual del comentario, y los veredictos repetidos al final. + - **8.** Se declara como fuga aceptada que el POST al servicio delata el sello. + - **9.** Tabla de verdad firma/sello, expresión regular de R6b y regla para una mtime negativa. + - **10.** Prefijos de dominio en `control_commit` y `head_digest`, y el nombre `.datekeys-*` reservado. + - **El documento:** 24 objeciones en vez de 28, marcadas «corregida» o «aceptada»; un glosario (capas 2 a 4, L_MAX, la sal); un texto para un sello que el lector no sabe verificar; una sola fuente en vez de tres ficheros que repiten el texto. +- **Decisiones del autor del 30-09 sobre la revisión:** + 1. **Tres entregas,** con el formato congelado desde la primera y `security` presente pero vacío: + - 1: contenedor, varios ficheros y rutas; + - 2: firma y claves de autor; + - 3: el sello, cuando exista el documento «Servicio de sellado v1». + + Las entregas 2 y 3 no cambian el formato: un lector anterior muestra «no soportado» y abre igual. + 2. **Origen del servicio (hallazgo 1):** el autor no tiene preferencia, así que se toma la recomendación. + - Un subdominio aparte, `seal.datekeys.com`, que solo sirve la API y nunca HTML, con cabeceras `nosniff` y `CSP: sandbox` de todos modos. + - La CSP de `/create` añade ese origen a `connect-src`, solo en esa página. + - Es de la entrega 3 y se puede revisar entonces. + 3. **Vida del sello (hallazgo 3):** la prueba va dentro de la cápsula. + - El token lleva la prueba de inclusión y el checkpoint firmado, y una raíz offline, fijada desde ya, certifica las claves anuales. Así el sello se verifica sin red para siempre, y la auditoría del anclaje queda como comprobación online opcional. + - Esto agranda el área de `security`: con el arreglo del hallazgo 5, la entrega 3 define una versión de `security` con un área fija mayor. + 4. **Abuso (hallazgo 4):** prueba de trabajo SHA-256 en cada petición, de un segundo en el navegador, sin guardar estado sobre quién pide. +- **Hecho el 30-09 a mediodía (`57dc659`),** sin flujo y con un único revisor adversarial: + - [formato3_diseno.md](spec_v0.10/formato3_diseno.md) es la única fuente del diseño. Se borraron `formato3_revision_intro.md` y `formato3_para_revision.md`, que repetían su texto. + - **Estructura:** una parte 0 de contexto, con glosario, decisiones y modelo de amenazas; una parte por entrega, cada una con sus pruebas y sus preguntas abiertas; y tres anexos con las revisiones. El de Fable dice dónde se resuelve cada hallazgo, el de la revisión interna marca sus 24 objeciones como corregidas o aceptadas, y el tercero recoge la revisión adversarial de esta versión. + - **Aplicados** los arreglos 2 y 5 a 10, los del documento y las cuatro decisiones. + - **La revisión adversarial** no encontró nada bloqueante ni mayor. Sus 15 hallazgos menores están resueltos en el diseño (anexo C), y una segunda pasada comprobó los arreglos. Los que cambian el diseño: + - el head va siempre en su versión 1, porque §22 exige un formato nuevo para una versión nueva; + - las claves 2 y 3 de `security` van codificadas aparte, así que una firma o un sello mal formados no arrastran al otro; + - el área depende solo de la versión del spec, nunca de `-seal`, y hay dos fugas nuevas declaradas: un área de 512 delata que no hay sello, y el registro publica la t de cada sello; + - R3 limita el NFD de cada segmento a 255 unidades UTF-16, por HFS+, y R4 prohíbe U+F000–U+F0FF; + - un sello que no verifica se descarta y ya no aborta la cápsula. + - **Interpretación que confirmar:** la decisión 3 hablaba de «una versión de `security` con un área fija mayor». El diseño hace que el área la fije la versión del spec y deja el mapa `security` en su versión 1, para que un lector de la entrega 2 siga comprobando la firma en una cápsula de la entrega 3. Es la pregunta 3 de la entrega 1. +- **Hecho el 30-09 por la tarde:** + - El autor cerró las diez preguntas de la entrega 1, todas con la recomendación (`afd9f76`). Los límites quedan como se propusieron y congelados con el formato. Un único fichero dentro de una carpeta se descarga directamente, con el ZIP como opción, y la página ofrece cada fichero del ZIP como un corte suyo. + - El borrador del spec v0.10 de la entrega 1 está en `datekeys-go`, rama `v0.10`, sin subir: `fa7f95e` lo redacta y `9d1cd2e` aplica la revisión final. Lleva el spec, el CDDL y `spec/README.md`. La referencia sigue implementando la v0.9, y su `SpecVersion` no cambia. + - La revisión final, como la de la v0.9, encontró un problema bloqueante, tres mayores y once menores, todos corregidos ([spec_v0.10/revision_borrador.md](spec_v0.10/revision_borrador.md)). El bloqueante: R6c rechazaba «¿», porque bestfit1250 lo lleva a '?'. Ahora solo rechaza '/', '\', ':' y U+0000 en una proyección. El diseño recoge los cambios que le afectan en su anexo D. + - Pregunta del autor: la firma de autor con su clave privada está prevista, en la entrega 2. Varias firmas no hace falta decidirlas ahora: un `alg` futuro puede definir una lista de firmas sin cambiar el formato (pregunta 3 de la entrega 2 del diseño). +- **Siguiente:** + 1. Hecho: el autor eligió Unicode 18.0.0 («no vamos a trabajar con unicodes ya pasados») y dio el visto bueno al texto. El borrador lo recoge en su rama, y el diseño, en su decisión 4. + 2. Hecho: el autor aprobó la regla de invisibles («sí a las dos»), que el spec recoge en R4b y en §29.6 (`631d09c`). + 3. Hecho: con su permiso se descargaron los 19 ficheros de datos, 8,25 MB, en `datekeys-go/.cache/`, fuera de git. + 4. Hecho: la referencia Go implementa el formato 3, con el [plan](PLAN_formato3_go.md) y el detalle de abajo. Con la autorización del autor («sí, sube la rama y pon el tag»), la rama `v0.10` y el tag anotado `spec-v0.10` están en el remoto, en `cc35d2c`, que solo cambia textos para nombrar el tag. Después, a petición suya («sí, avanza main hasta la v0.10»), `main` avanzó hasta `cc35d2c` sin fusión y está subida. + 5. **En curso:** `datekeys-ts` lee y escribe el formato 3 con su [plan](PLAN_formato3_ts.md). En la rama `v0.10` de `App`, sin subir, están hechos los pasos 0 y 1 (`fbb90b2`, las tablas y las reglas de rutas y de texto), del paso 5 el CRC-32 y la disposición del ZIP (`36096a9`), el paso 2 (`d9a9cf5`, el códec) el paso 3 (`b176ad2`, la lectura del formato 3 con `testdata` en `spec-v0.10`) y el paso 4 (de `3daa1f7` a `2efc8bc`: `encryptFiles`, `encrypt` solo con `testVectors`, `/create` en formato 3 con un fichero, y la interoperabilidad con Go). El paso 5, el ZIP y el sumidero de la página, está en `ee82f43`, el paso 6, la página `/inspect` con los ficheros del formato 3, en `651178a`, y el paso 7, la página `/create` con ficheros, carpetas, rutas editables, comentario y autor, en `7dc88ef`. El paso 8 está hecho (`7527c35`, `57e0a8a`, `e6cca0b` y el CHANGELOG): README, `testdata:check` contra `cc35d2c`, tres revisiones adversariales con subagentes y sus correcciones, y, a petición del autor, `/create` rediseñado (una carta al futuro, sobre de correo aéreo, fuentes del sistema) y el sitio siempre claro. Pendiente, sin urgencia: + - `/inspect` solo cambió de aspecto con los estilos globales: falta poner el resultado delante y plegar los pasos 1 a 18, como en `/create`. + - El texto del paso 17 aún difiere del de Go cuando la cápsula se corta justo tras un chunk completo: `age-encryption` retiene ese chunk hasta ver un byte más. Igualarlo exige descifrar el STREAM como Go (código propio con `@noble/ciphers`). + - Un head de 16 MiB tarda de 10 a 40 s en la página, en el hilo principal (Go tarda la mitad): `open()` en un worker. + - Menores: el `TypeError` sin sumidero llega tras los pasos 3 a 8 con un `Blob`; `tempfile.remove()` marca borrado antes de lograrlo; `measureFiles` en cada tecla con 65 535 ficheros; un bundle `.app` no avisa (igual que la CLI). + - Subido el 01-10 por la noche, con permiso del autor: la rama `v0.10` de `App`, y `main` y `v0.11` de `datekeys-go`. + 6. La entrega 2 abre la versión siguiente del spec, y la 3 espera al documento «Servicio de sellado DateKeys v1». En esa versión entra también la **llave de palabras** que pidió el autor el 01-10: palabras que elige la persona y abren la cápsula en lugar de la `.dkk`, ya hechas en la página y en la CLI (apartado «Retomar aquí»). Además, el 01-10 el autor pidió que `/inspect` pueda pedir la firma a drand: ya lo hace, con un botón (`2ec7102`), lo que cambia la decisión 4 del plan de la fase 2. Para otra revisión externa, el artefacto hay que volver a publicarlo desde el diseño nuevo. + +**Hecho el 30-09 por la noche: el formato 3 en Go.** Rama `v0.10` de `datekeys-go`, subida con el tag `spec-v0.10` en `cc35d2c`, un commit o varios por paso del plan: +- `631d09c`, el spec con la regla de invisibles; `6fba1dd`, paso 1, `internal/pathrule` con las tablas de Unicode 18.0.0 y best-fit generadas y su `TablesDigest`; `72e86b8`, paso 2, el códec de `BODY`, `security` y el head. +- `7249ef4`, paso 3, el lector: `capsule.Sink`, `ErrSinkRequired` justo tras el paso 2, el paso 17 en subpasos con su precedencia, y lecturas de `BODY` que crecen con los bytes recibidos (§57). +- `8955c0f`, paso 4, el escritor `capsule.EncryptFiles`, que lee cada fichero dos veces; `Encrypt` solo escribe el formato 2 con `EncryptOptions.TestVectors`. +- `a0de80f`, paso 5, el CLI: `encrypt -in` con ficheros y carpetas, `-comment`, `-author` y `-no-mtime`; `decrypt -out CARPETA` con `os.Root`; la presentación de §29.7, con el ancho del terminal pedido por `syscall`, sin dependencias nuevas. +- Paso 6, datos de prueba: `3c39336` (`SpecVersion` 0.10 y `ERR_HEAD_INVALID`), `e070f89` (las nueve fixtures), `db862d5` (`paths.json`, `path_fold.json`, `head_schema.json`, `security.json` y el control de versión 3 en `cbor.json`) y `18eb3c3` (las mutaciones: 209 casos, 169 del §64, tres de los cuales se abren con su veredicto). +- `20f9959`, paso 7, la documentación; `735885c`, una corrección del CLI: una carpeta de salida sin su carpeta padre falla antes de pedir el release; `6fa2b54`, paso 8, tres objetivos de fuzzing nuevos (`FuzzDecodeHead`, `FuzzEvaluateSecurity`, `FuzzCheckPath`) y el SHA-256 del spec en `spec/README.md`. +- Verificación: `go test ./...` y `scripts/check.sh 60s` limpios, cobertura de `capsule` 93,1 %; la prueba en vivo contra Quicknet abrió cápsulas de formato 3 de las dos políticas; los tres objetivos nuevos, cerca de un millón de ejecuciones cada uno, sin fallos. +- Para el autor, sin urgencia: + - un cambio editorial en el texto aprobado: §67 decía «Serán … (por implementar)» de las fixtures del formato 3, y ahora dice «Son …». El SHA-256 de `spec/README.md` es el del texto con ese cambio; + - el corpus de mutaciones pasa de 168 KB a 706 KB. 476 KB son el caso de 65 536 carpetas implícitas que pide el §64, cuyo head mide 235 KB; + - los textos del CLI que el spec no fija son de la referencia: la cabecera «Ficheros escritos en CARPETA (N):», los avisos de nombres peligrosos y los mensajes del escritor. Los que fija, los veredictos y las dos etiquetas, van literales. +- Para `datekeys-ts`: + - hecho: el generador escribe el módulo TypeScript con la bandera `-ts` (`13910b3`, en `main` de `datekeys-go`, un commit por delante de `origin/main` y sin subir), y el digest recalculado en TypeScript coincide con `TablesDigest`; + - `testdata` cambia entero de `"spec"`, y añade nueve fixtures, cuatro ficheros de vectores, `mutations.json` con 209 casos (`version changed` pone ahora `VERSION` 4, y hay casos con `verdicts`) y el diferencial con 5 110; + - los textos de las reglas de rutas y de texto deben coincidir byte a byte: `paths.json` y `head_schema.json` los traen en `result` y `detail`. +- Herramientas: en esta máquina los heredocs de Bash rompen apóstrofos y barras invertidas, y la herramienta Write convierte `\uXXXX` en caracteres literales. Funciona escribir los cambios como scripts de Python en el scratchpad. + +**Conclusiones de la conversación, sin decisión pendiente:** +- El protocolo no contempla un sello de tiempo de creación (§5, §55.1). Si se quiere, lo recomendado es un sello RFC 3161 u OpenTimestamps sobre el SHA-256 del `.dkc` completo, guardado aparte. +- Un fichero único `.dk` con `.dkc` y `.dkk` juntos no conviene: con `time_and_key` equivaldría a `time_only`. Ya se envía un solo fichero con `time_only` o con destinatarios `age1…`. +- `datekeys-ts` cerró `0.1.0` el 29-09 (`d577283`, tag `v0.1.0`), y la fase 3 va en `0.2.0-dev`. + +### 2.3 Depende del autor + +- Crear `security@datekeys.com` y, si se quiere, un `security.txt` en la web. Después, actualizar `SECURITY.md`, que hoy dice `info@activething.com`. +- Elegir la ruta pública del módulo Go (propuesta: `datekeys.com/go/datekeys`, en minúsculas) y el espejo público, que no puede ser GitHub (por ejemplo Codeberg). Publicar la página `go-import` en `datekeys.com`. Después: renombrar el módulo y poner el tag `v0.1.0` cuando `go get` funcione desde una máquina limpia. +- Decidir si `datekeys-ts` cierra `0.2.0`, ahora que la fase 3 está completa. + +### 2.4 Más adelante + +Release API sobre la librería, traducción del spec al inglés y revisión externa antes de la v1.0. Opcional: escribir en OPFS en trozos de 1 MiB, que ahorra un 10 % al cifrar ficheros grandes en la página (README de `datekeys-ts`, «Crear»). + +--- + +## 3. Reglas del proyecto + +Están en el [README](README.md#reglas) de este repo, que el `CLAUDE.md` de la raíz carga en cada sesión. + +--- + +## 4. Documentos + +- En este repo están los planes, la revisión del protocolo y los papeles de la v0.9. El [README](README.md#documentos) los lista. +- En `datekeys-go`: + - `spec/DateKeys_Protocol_Specification_v0.10.md`, cerrado con el tag `spec-v0.10`; `spec/DateKeys_Protocol_Specification_v0.9.md`, cerrado con el tag `spec-v0.9`; `spec/DateKeys_Protocol_Specification_v0.8.2.md`, `spec/datekeys.cddl` y `spec/README.md`; + - `testdata/README.md`, que documenta los ficheros compartidos para segundas implementaciones; + - `docs/traceability.md` y `CHANGELOG.md`. +- Las herramientas de verificación de las sesiones del 26 al 28-09 estaban en carpetas temporales y pueden haber desaparecido: el diferencial Go/TypeScript de `tsreview/` y las copias congeladas `dkgo-ref-`. Su descripción está en los mensajes de los commits de `datekeys-ts` y en su README. diff --git a/README.md b/README.md index 2414a3d..652a317 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Para retomar el trabajo, lee [HANDOFF.md](HANDOFF.md): el estado de cada repo, l | Documento | Contenido | |---|---| | [HANDOFF.md](HANDOFF.md) | Estado actual y trabajo pendiente | +| [HANDOFF_historial.md](HANDOFF_historial.md) | Lo que fue el handoff hasta el 6-10, sesión a sesión: por qué se decidió cada cosa y en qué commit quedó | | [PLAN_libreria_go.md](PLAN_libreria_go.md) | Plan de la librería Go, hitos M0 a M5 (hecho) | | [PLAN_codec_cbor_y_pagina_svelte.md](PLAN_codec_cbor_y_pagina_svelte.md) | v2: codec CBOR propio en Go y TypeScript, librería TypeScript y página `/inspect` (hecho) | | [PLAN_fase2_ibe_noble2.md](PLAN_fase2_ibe_noble2.md) | v2: fase 2, abrir cápsulas en el navegador (hecho) |