@ -15,18 +15,18 @@ Sirve para retomar sin contexto previo, sea una persona o una sesión de Claude.
| Repo | Rama y commit | Tags | Qué es |
|---|---|---|---|
| `datekeys-go` | `v0.15` en `92e7154`; `main` en `fe50885` | `spec-v0.15` en `fe50885`, y los de las versiones anteriores | Spec v0.15 aprobada, implementación de referencia, `testdata` compartido; `c49c67c` añade las palabras al azar, `27a75ee` el alfabeto de cada lista y la fuerza de las palabras, `96d8992` arregla `TestGenerate`, `e671032` añade la lista inglesa de la EFF y `92e7154` los dados |
| `App` (`datekeys-ts`) | `v0.10` en `f5044e3`; `main` en `7650418` | `v0.4.0` en `7650418`, `v0.3.0`, `v0.2.0`, `v0.1.0` | Librería TypeScript `0.5.0-dev`, de la spec 0.15, y páginas `/inspect` y `/create`, con las palabras al azar; la última publicada es la 0.4.0 |
| `datekeys-dart` | `v0.15` en `00f4ad4` | ninguno | Librería Dart completa, de la spec 0.15, con las palabras al azar; las ramas `v0.11` a `v0.14` se quedan atrás |
| `datekeys-go` | `v0.15` en `6158be2`; `main` en `fe50885` | `spec-v0.15` en `fe50885`, y los de las versiones anteriores | Spec v0.15 aprobada, implementación de referencia, `testdata` compartido; `c49c67c` añade las palabras al azar, `27a75ee` el alfabeto de cada lista y la fuerza de las palabras, `96d8992` arregla `TestGenerate`, `e671032` añade la lista inglesa de la EFF, `92e7154` los dados y `aefc8f6` lo que dice el SDK al sellar |
| `App` (`datekeys-ts`) | `v0.10` en `e8b5d35`; `main` en `7650418` | `v0.4.0` en `7650418`, `v0.3.0`, `v0.2.0`, `v0.1.0` | Librería TypeScript `0.5.0-dev`, de la spec 0.15, y páginas `/inspect` y `/create`, con las palabras al azar; la última publicada es la 0.4.0 |
| `datekeys-dart` | `v0.15` en `e2296b0` | ninguno | Librería Dart completa, de la spec 0.15, con las palabras al azar; las ramas `v0.11` a `v0.14` se quedan atrás |
| `docs` | `main` | — | Este repo |
| `web` | `main` en `f2b8a38` | — | Landing de datekeys.com, sin remoto |
- **Spec:** la v0.15 está aprobada desde el 7-10, con SHA-256 `45105e693be4187af4dd30f4d254402612587b6427c746f5d29f07a541c1e3f3`. Es la recuperación a largo plazo: el objeto release, los archivos y servicios de caché que guardan todas las rondas, el release en la mano en el paso 9.c (opción B: no se compara con el reloj) y el anexo de recuperación del §79. No cambia ningún formato de `.dkc` ni de `.dkk`. No hay ningún borrador abierto. Las versiones aprobadas y sus SHA-256 están en `datekeys-go/spec/README.md`.
- **El fichero `.dkr` se descartó** antes de aprobar (7-10). El autor no lo había aprobado conscientemente, y no tiene sentido: al crear la cápsula no hay release que guardar, y cuando llega la ronda la cápsula ya se abre. El objeto release no tiene extensión propia; sale de un archivo o de un servicio de caché. El §76 lo registra.
- **Las tres implementaciones** coinciden en todos los vectores compartidos de `datekeys-go/testdata` en `fe50885`, 142 ficheros, los mismos que en `92e7154`, de donde TypeScript y Dart copian hoy `testdata` y `wordlists`. Gates el 7-10:
- Go: `scripts/check.sh` entero en `fe50885`, con el anexo de recuperación abriendo fixtures sin código de DateKeys, y `scripts/fuzz.sh 20s` en `fe50885` con sus 27 objetivos, sin fallos; `scripts/check.sh` entero otra vez en `27a75ee`, `96d8992`, `e671032` y `92e7154`;
- TypeScript: `npm run verify` en `f5044e3`, con 8 127 pruebas;
- Dart: `tool/check.sh` en `00f4ad4`, con 2 243 pruebas en la VM y 712 en Node.
- **Las tres implementaciones** coinciden en todos los vectores compartidos de `datekeys-go/testdata` en `fe50885`, 142 ficheros, los mismos que en `aefc8f6`, de donde TypeScript y Dart copian hoy `testdata`, `wordlists` y `annex`. Gates el 7-10:
- Go: `scripts/check.sh` entero en `fe50885`, con el anexo de recuperación abriendo fixtures sin código de DateKeys, y `scripts/fuzz.sh 20s` en `fe50885` con sus 27 objetivos, sin fallos; `scripts/check.sh` entero otra vez en `27a75ee`, `96d8992`, `e671032`, `92e7154`, `aefc8f6` y `6158be2`;
- TypeScript: `npm run verify` en `728c3bb`, con 8 132 pruebas;
- Dart: `tool/check.sh` en `e2296b0`, con 2 250 pruebas en la VM y 716 en Node.
- **Palabras al azar (7-10, después de cerrar la v0.15):** es el SHOULD de §38.1 de ofrecer palabras generadas; no cambia ningún formato ni la derivación.
- Go: `c49c67c` añade `wordkey.Generate`, `List` y `CheckList`, y `datekeys encrypt -new-words FICHERO [-dic es] [-word-count 7]`. `27a75ee` hace que `CheckList(lang, words)` compruebe cada palabra contra el alfabeto de su idioma, que da el código y no la lista (para `es`, de la `a` a la `z`, `á`, `é`, `í`, `ó`, `ú`, `ü` y `ñ`, en minúscula y NFC): una letra cirílica que parece latina, una mayúscula, una cifra o el retorno de carro de un fichero CRLF dejarían la cápsula sin abrir. También añade `Bits`, la fuerza de lo sorteado, que `encrypt` muestra (90 bits para 7 de 7 776). `scripts/check.sh` pasa entero en los dos.
- TypeScript (`0.5.0-dev`, de `012cd74` a `4057607`): `scripts/sync-testdata.mjs` copia del mismo commit de Go `wordkey/lists` en `wordlists/`, con su `SOURCE.json` (`testdata` y `wordlists` en `27a75ee`, cuyo `testdata` es el del tag). `wordlist.ts` hace lo de Go, con sus textos: `readWordList` solo acepta una lista con el SHA-256 fijado para su idioma, `checkWordList`, `generateWords` y `wordBits`. `/create` ofrece palabras al azar por defecto tras una casilla, con su fuerza y «Otras palabras», y deja escribir las propias con el aviso de que son más débiles; `licenses.txt` lleva la licencia de la lista. `npm run verify` pasa con 8 119 pruebas, y el flujo se comprobó en el navegador sobre el build de producción.
@ -37,16 +37,31 @@ Sirve para retomar sin contexto previo, sea una persona o una sesión de Claude.
- **La lista inglesa** (7-10 por la tarde, con permiso del autor): `wordkey/lists/en.txt` es la lista grande de la EFF (Joseph Bonneau, 2016), 7 776 palabras, CC BY 4.0 según la política de copyright de eff.org, en su orden y sin los números de los dados, así que la posición de cada palabra sigue dando su número. `-dic` la toma por defecto, como decidió el autor. El alfabeto de `en` es de la `a` a la `z` y el guion ASCII de sus cuatro palabras compuestas (`drop-down`, `felt-tip`, `t-shirt` y `yo-yo`), para no quitar ninguna ni romper su numeración. Go `e671032`, TypeScript `13df99b` (la página sigue ofreciendo solo la española, y `check-build.mjs` exige que publique solo esa) y Dart `bf0f3d3`, con sus vectores regenerados con Go.
- **Los dados** (7-10 por la tarde, decisión del autor «sí, hazlo así»): para quien no se fía del azar del ordenador, cinco dados por palabra dan un número del 11111 al 66666, la posición de la palabra en la lista (7 776 = 6⁵), con el primer dado como cifra más significativa. Go `92e7154`: `wordkey.DiceNumber`, `DiceWord`, `DiceWords` (al menos 6 números y ninguna palabra repetida, que se vuelve a tirar) y `DiceList`, la lista numerada como la publica la EFF (la de `en` es su fichero byte a byte, SHA-256 `addd3553…903e`; la de `es`, `611f779a…fddb`, en `wordkey/lists/README.md`); `encrypt -dice TEXT` y `-dice-file FILE`, que muestran las palabras (las que abren la cápsula, no los números), y `datekeys wordlist [-dic LISTA]`, que escribe la lista numerada y su SHA-256. TypeScript `f5044e3`: lo mismo en `wordlist.ts`, y en `/create` la opción «Con dados» entre «Al azar» y «Las elijo yo», que convierte los números en palabras a medida que se escriben, avisa de un número que no vale o de una palabra repetida y ofrece la lista numerada para imprimirla, con su SHA-256. Comprobado en el navegador sobre el build de producción: la lista descargada tiene el SHA-256 de Go y la cápsula se crea con las palabras de los dados. Dart `00f4ad4`, de un agente Opus revisado contra Go: lo mismo en `wordlist.dart`, con vectores de Go de los dados (`DiceWords` con cada punto de código de los planos 0, 1 y 14 entre dos números, entre otros).
- La lista española, `wordkey/lists/es.txt` (7 776 palabras, SHA-256 `ff77b487…34fe`), es un **borrador sin revisar**, CC BY-SA 4.0, sacado de las frecuencias de subtítulos de FrequencyWords filtradas con el diccionario de LibreOffice; el método está en `wordkey/lists/README.md` y el script en [wordlists/build_es.py](wordlists/build_es.py). Cumple el alfabeto tal cual.
- **Lo que dice el SDK oficial al sellar (7-10 por la tarde):** los SHOULD de la v0.14 y la v0.15 que no cumplían ni la CLI ni `/create`.
- **El anexo junto a la cápsula** (§62.1, regla 27): `annex/recovery.md` en `datekeys-go`, el §79 del spec bajo un título con su versión y el SHA-256 de su texto, igual para toda cápsula. `datekeys.RecoveryAnnex` lo incrusta y `TestRecoveryAnnex` exige que sea el §79 del spec de `SpecVersion`: al aprobar una versión nueva se regenera con `DATEKEYS_WRITE_ANNEX=1 go test -run TestRecoveryAnnex .`. `encrypt` lo escribe como `FICHERO.dkc.recuperacion.txt` (`-no-recovery` lo evita), y `/create` lo ofrece para descargar con ese nombre. TypeScript y Dart lo copian de Go en `annex/`, como las listas.
- **Qué hará falta para abrirla** (regla 26): `encrypt` y `/create` lo dicen al sellar: el `.dkc`, una credencial si es `time_and_key`, y el release de su ronda, que tendrá que guardar un archivo o un servicio de caché si drand ya no lo sirve (§50). El aviso local opcional para `round_time` (MAY) no se ha hecho.
- **`time_and_key` para horizontes largos** (§7.6): a más de un año y con `time_only`, la CLI y `/create` la recomiendan.
- **Las palabras propias** (§38.1): `/create` y la ayuda de la CLI dicen que no bastan para algo valioso y que no se use una contraseña de otro sitio, porque pasada la fecha la cápsula permite probarla.
- **El estado del perfil** (§71): `profile.Status`/`StatusOf` en Go, `profileStatusOf` en TypeScript, con la tabla de los perfiles fijados que trae cada versión, porque el registro firmado no existe: Quicknet, activo. Con un perfil que no esté activo no se escribe ninguna cápsula, y `decrypt`, `inspect` e `/inspect` avisan si el de una cápsula está comprometido.
- Go `aefc8f6` y `6158be2`, TypeScript `728c3bb` y `e8b5d35`, Dart `8eed96f` y `e2296b0` (de un agente Opus revisado contra Go: el anexo es una constante generada, `lib/src/recovery_annex.g.dart`, que escribe `tool/recovery_annex_copy.dart` tras cada sincronización que cambie `annex/`).
- Pendiente menor: el anexo es texto del spec, con licencia CC BY 4.0 (`spec/README.md`), pero ni su cabecera ni el README de Go lo dicen.
- **La revisión externa:** el paquete de [revision_externa/](revision_externa/NOTA_PARA_EL_AUTOR.md) está al día con la v0.15. Su nota dice qué decidió el autor y qué falta: elegir revisor, alcance y presupuesto, el NDA, los bundles y el envío.
---
## Qué queda
La recuperación a largo plazo quedó hecha con la v0.15, y las palabras al azar en las tres librerías y en `/create` (7-10). **Para empezar mañana**, lo que depende del autor en ellas: la revisión de la lista española por alguien que hable español, o rehacerla con el corpus de Leipzig cuando su web vuelva (el 7-10 por la tarde seguía caída). Sin eso, lo siguiente es el segundo punto de «Librerías y clientes»: las recomendaciones de la v0.14 y la v0.15 al SDK oficial.
La recuperación a largo plazo quedó hecha con la v0.15, y las palabras al azar en las tres librerías y en `/create` (7-10). **Para empezar mañana**, lo que depende del autor en ellas: la revisión de la lista española por alguien que hable español, o rehacerla con el corpus de Leipzig cuando su web vuelva (el 7-10 por la tarde seguía caída). Sin eso, lo siguiente de «Librerías y clientes» es la página web cuando se publique (§59) o el localizador en las páginas.
### Protocolo
0. **La revisión de Astra de la v0.15 (7-10), para la v0.16.** Cinco hallazgos, todos comprobados y aceptados; la v0.15 no cambia. Tras su segunda respuesta, la dirección es:
- **Sello sin `accuracy`** (§29.11): S4 solo con una cota de precisión conocida, la del token o la de una política de TSA que el lector tenga identificada (p. ej. una tabla de OID de políticas con su cota, que habría que fijar y mantener en el spec); sin ella el sello verifica pero no acredita anterioridad. Se descarta el margen fijo que propuso Claude: ningún margen finito es conservador para toda TSA. S5 pasa a «No acredita que se sellara antes de la fecha de apertura».
- **Anexo y llave de palabras** (§79.6): el anexo incluirá la derivación de §38.1 (normalización, PBKDF2 con su sal y sus rondas, vector), con una receta exacta para un subconjunto explícito y comprobado (los alfabetos de las listas de DateKeys) y, para el resto, las tablas de Unicode 18.0.0 conservadas junto a la documentación (quizá un paquete de recuperación publicado una vez, con su SHA-256). `scripts/recovery` abrirá con palabras, con casos que ejerciten la normalización.
- **Último bloque de `age`** (§79.5): «el último puede ser más corto», y un vector con un último bloque completo. `scripts/recovery` ya lo hace bien.
- **Evidencias de la firma con certificado** (§29.10, regla 21): guardar la cadena sin la raíz y las respuestas OCSP cuando quepan; si no caben, el escritor dice qué deja fuera, también de la TSA y de los intermedios, y permite exportarlo; §29.10 promete solo lo conservado. Ligado a la medida del área (punto 3).
- **JSON de drand** (§47.1): regla estricta, con vectores: nombres exactos tras decodificar sus escapes (`"\u0072ound"` es `round`), un nombre repetido es `ERR_RELEASE_INVALID`, la ronda un entero sin fracción ni exponente. Hoy Go y TypeScript leen como `encoding/json`: el último gana y los nombres no distinguen mayúsculas.
- Pendiente del autor: aprobar esta dirección y cuándo abrir la v0.16 (antes o después del informe de la revisión externa).
1. **La revisión externa.** El paquete está listo; lo que falta es del autor. Al recibir el informe, se abre la versión siguiente con sus hallazgos, el párrafo de idioma y precedencia del final del §1, las etiquetas del §76 que hoy llaman independientes a revisiones de IA, y el registro de la revisión (§75, punto 10). Todo eso lo aprobó el autor el 6-10; ver [revision_externa/precedence_and_language.md](revision_externa/precedence_and_language.md).
Con ellos, dos retoques editoriales que el texto no puede llevar tras su tag: los de K17 del paquete (la cabecera «prevista», el §1 con la Release API y la Release Cache, el punto y coma del §74), y el §79, que nombra solo `drand/kyber-bls12381` cuando `scripts/recovery` usa también las interfaces de `drand/kyber`.
2. **Un archivo o servicio de caché de releases** (§50). El protocolo ya lo admite y las librerías leen un archivo local, pero nadie aloja uno todavía. Es decisión del autor: dónde, quién lo mantiene y si DateKeys ofrece el suyo.
@ -62,10 +77,7 @@ La recuperación a largo plazo quedó hecha con la v0.15, y las palabras al azar
- los dados protegen de un generador trucado, no de una app que se quede con las palabras: eso solo lo cubre una app auditable (§59);
- el servicio `words.datekeys.com`, cuando haya sitio propio: ver las decisiones;
- quizá el alfabeto por idioma como regla del SDK en la versión siguiente del spec (§38.1). El riesgo de fondo es la app misma, que puede cambiar el generador: §59, builds reproducibles y releases firmadas.
- **Las recomendaciones de la v0.14 y la v0.15 al SDK oficial**, que no aplican ni `/create` ni la CLI de Go:
- recomendar `time_and_key` para horizontes largos (§7.6);
- avisar del estado de un perfil (§71);
- explicar al crear cómo se abrirá la cápsula dentro de veinte años: el anexo de recuperación (§79) y los archivos de releases (§50).
- **Lo que queda de las recomendaciones al SDK:** el aviso local para `round_time` (§62.1, regla 26, MAY).
- **La página web, cuando se publique** (§59): builds reproducibles con sus hashes, Subresource Integrity y un cliente sin conexión.
- **El localizador en las páginas:** las tres librerías lo tienen, pero `/create` no crea sobres e `/inspect` no descarga el resto.
- **Go no tiene ninguna release del módulo**; la primera, cuando haya un repo accesible desde fuera para `go get`. govulncheck avisa de GO-2026-6443 en grpc, que el código no alcanza: subir grpc cuando salga la 1.85.0.