# Handoff DateKeys, 26 de septiembre de 2026 (actualizado al cerrar la sesión del 5 de octubre: Go y TypeScript al día con el borrador v0.12, y las etapas 0 y 1 de Dart) 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. **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. --- ## La segunda sesión del 5 de octubre: etapas 2 y 3 de Dart Corrió en Opus 5.5. Se abrió en `App` y a los pocos minutos pasó a la raíz con la herramienta de carpetas de la app, sin cerrarse. Hizo los puntos 1 a 4 de la lista de abajo: - **Repos:** comprobados; estaban como dice la lista. - **Dart, etapa 2:** hecha y revisada, commits `0c21f55` a `82fa714`. - **Dart, etapa 3:** el autor pidió adelantarla, y se hizo en paralelo con la 2, en un worktree aparte. Está revisada e integrada encima de la 2, commits `cdd1c89` a `b81bdfa`. El worktree y su rama ya están borrados. Las revisiones de las dos etapas están en [PLAN_dart.md](PLAN_dart.md), al final; ninguna encontró fallos. **Estado al cerrar:** - `datekeys-dart`: rama `v0.11` en `b81bdfa`, limpia, solo en local. El gate pasa, con 367 pruebas en la VM, más una aplazada, y 113 en Node. - `datekeys-go` y `App` no se tocaron. - G: tiene 26 GB libres desde el 5-10, porque el autor liberó unos 24 GB. **Siguiente:** 1. **Dart, etapa 5**, pedida por el autor el 5-10 («sigue con la etapa 5»). Está en marcha. La etapa 4 está completa: 4a, 4b y 4c hechas, revisadas e integradas en `v0.11`, hasta `8e0e993`. La salida `-dart` del generador de tablas está en `c531e93` de `datekeys-go`, subido. La etapa 5 se reparte en 5a, 5b y 5c, descritas en [PLAN_dart.md](PLAN_dart.md), al final. La 5a y la 5b ya están hechas, revisadas e integradas en `v0.11`, hasta `6ba6893`. Con la 5b, `testdata` pasó a `c531e93`, el borrador v0.12. La 5c corre en la copia principal. Si la sesión se cierra a medias: 1. mira qué commits hay en `v0.11` después de `6ba6893`; 2. revísalos; 3. pasa el gate; 4. si quedó a medias, relanza la 5c con el esquema de [PLAN_dart.md](PLAN_dart.md). 2. Lo que sigue abierto de la lista de abajo: - 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; - las observaciones sin decisión. 3. Medir BLS12-381, PBKDF2 y scrypt en un móvil de gama media, cuando haya app. ## Retomar aquí (al cerrar la sesión del 5 de octubre) **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. - `testdata` no tiene vectores compartidos de la llave de palabras. El §64 de la v0.11 los pide, y solo están en las pruebas de Go (`wordkey.TestKeyVector`). TypeScript y Dart los van a necesitar. - 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.