You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

547 lines
56 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Handoff DateKeys, 26 de septiembre de 2026 (actualizado el 6 de octubre: las etapas 2 a 5 de Dart, hechas)
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 a 5 de Dart
Corrió en Opus 5.5, del 5 al 6 de octubre. 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 y, a petición del autor, las etapas 4 y 5 de Dart:
- **Repos:** comprobados; estaban como dice la lista.
- **Dart, etapas 2 y 3**, en paralelo: la 2 en `v0.11` y la 3 en un worktree, integrada encima.
- **`datekeys-go`:** el generador de las tablas de Unicode escribe también una librería de Dart (`internal/pathrule/gen -dart`). Es `c531e93` en `v0.12`, subido con permiso del autor. La salida de TypeScript y `tables.go` no cambian.
- **Dart, etapa 4**, en tres partes: 4a, las rutas, los textos y la llave de palabras; 4b, los formatos; 4c, el head, la nota, la inspección y la apertura de los formatos 1 a 3.
- **Dart, etapa 5**, en tres partes:
- 5a, el lector CMS, ECDSA y RSA;
- 5b, `testdata` en la v0.12, los compromisos, `SECURITY_CBOR`, `alg` 1 y los veredictos;
- 5c, `alg` 2 y `seal_type` 2 en los veredictos.
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. Las revisiones están en [PLAN_dart.md](PLAN_dart.md), al final.
**Estado al cerrar:**
- `datekeys-dart`: rama `v0.11` en `a14a3b8`, limpia, solo en local, sin remoto. El gate pasa con 1 572 pruebas en la VM y 332 en Node.
- La librería Dart ya inspecciona y abre cápsulas de los formatos 1 a 3, también grandes y en streaming, con todas sus credenciales, y evalúa la firma y el sello como Go.
- `testdata` está en `c531e93`, el borrador v0.12 sin aprobar; `specVersion` sigue en 0.11.
- `datekeys-go`: `v0.12` en `c531e93`, subida. `App` no se tocó.
- G: tiene 26 GB libres desde el 5-10, porque el autor liberó unos 24 GB.
**Siguiente:**
1. **Dart, etapa 6:** el escritor, con el formato 3, el área de 32 KiB, `time_only` y `time_and_key`, la llave de palabras y la nota pública. Antes conviene decidir cómo se cifra el stanza tlock sin que el tiempo de `BigInt` revele sigma y r (README de `datekeys-dart`).
2. **Dart, etapa 7:** el localizador y el sobre, y las claves de autor `dkauthor1…` con su fichero cifrado con scrypt.
3. 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.
4. **Medir en un móvil de gama media,** cuando haya app: BLS12-381, PBKDF2, scrypt y la apertura.
5. **Un posible fallo de dart2js en Dart 3.13,** que encontró el agente de la 4c: un objeto que llega al campo de otro a través de `c ? null : objeto` puede perder sus escrituras. Está documentado en el README de `datekeys-dart`. Reportarlo al equipo de Dart sería publicar fuera: solo con permiso del autor.
## 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-<commit>`. Su descripción está en los mensajes de los commits de `datekeys-ts` y en su README.

Powered by TurnKey Linux.