# Borrador v0.16: decisiones para el autor *7 de octubre de 2026. El borrador está en la rama `v0.16` de `datekeys-go` (`2c29625`), en `spec/DateKeys_Protocol_Specification_v0.16.md`. Recoge la revisión de Astra de la v0.15, con la dirección acordada tras su segunda y su tercera respuesta: cinco hallazgos, todos comprobados contra el texto y el código. Todavía no hay código: `SpecVersion` sigue en 0.15, y el anexo que escribe la CLI es el de la v0.15.* > **Nota del 7-10 por la noche.** El autor pidió implementarla («ponte con la implementación de la 0.16»), y se tomó como aprobación de las ocho decisiones con su recomendación. Está implementada en Go (`7e3b810` a `3fd0e93`), TypeScript (`f79d8e2`, `59d7607`) y Dart (`290d97e`, `0609e9e`), con los tres gates en verde. Falta cerrarla con su tag. La licencia quedó decidida: CC BY-ND 4.0, también en la cabecera del anexo (`70d907b`). Si apruebas lo que sigue tal como está, basta con decir «apruebo el borrador». Después se implementa en Go, con sus vectores, y se lleva a TypeScript y a Dart. La versión se cierra con su tag cuando las tres pasen. ## Lo que hace el borrador 1. **El sello sin `accuracy`** (§29.7, §29.11). Un sello válido solo acredita que es anterior a la fecha de apertura (S4) si su token lleva `accuracy` y t + precisión < round_time. Sin `accuracy` da S5, y S5 cambia de texto: «No acredita que se sellara antes de la fecha de apertura: ‹motivo›.» Hay tres motivos, que se comprueban en este orden: - «se selló después de esa fecha o demasiado cerca de ella»; - «el sello no dice la precisión que exige su política», si la política del token es la BTSP de ETSI (0.4.0.2023.1.1), que obliga a llevar `accuracy`; - «el sello no dice su precisión», en los demás casos. En F6, la línea de un firmante cuyo sello no lleva `accuracy` dice «sin acreditar que fuera antes de la fecha de apertura» y el motivo. El texto anterior de S5, «Sellado después de la fecha de apertura», era falso para un sello anterior a la fecha cuya precisión llegaba a ella. 2. **La llave de palabras en el anexo** (§79.7, nueva). El anexo trae la derivación entera: P, la sal, PBKDF2 con 600 000 iteraciones y dos vectores. La normalización va en dos niveles: - **Sin tablas**, exacta para el texto que dan las listas de DateKeys: ASCII; á, é, í, ó, ú, ü y ñ con sus mayúsculas; y las marcas de U+0300 a U+036F. Se quitan las marcas, cada letra con tilde pasa a su letra base, A a Z pasan a minúsculas y se parte por los espacios. - **Completa** para cualquier otro texto: NFD, quitar las marcas, minúscula simple y partir por los espacios. Usa `UnicodeData.txt` de Unicode 18.0.0, que el anexo nombra por su SHA-256 y su dirección en unicode.org. El segundo vector, «Ñandú», dos espacios, «PINGÜINO», un tabulador y «camión árbol Éter ola», da la misma llave que «nandu pinguino camion arbol eter ola» y que el mismo texto con las tildes escritas como marcas sueltas. La v0.16 renumera El contenido como 79.8 y Lo que el anexo no comprueba como 79.9. 3. **El último bloque de `age`** (79.5). «El último más corto» pasa a «el último puede ser más corto, o estar completo». Con 65 536 bytes de plaintext hay un solo bloque, completo y marcado como último. `scripts/recovery` ya lo hacía bien, pero ningún fixture lo comprobaba. 4. **Las evidencias de la firma con certificado** (§29.10, §62.1 reglas 21 y 22). El escritor SHOULD guardar: - la cadena de cada firmante, sin su raíz; - la de la autoridad de cada sello, sin su raíz; - las respuestas OCSP. Así se sustituye el «podar a un certificado por firmante» de la v0.15. Si algo no cabe, el escritor MUST decir qué deja fuera y SHOULD ofrecer exportarlo. Nunca deja fuera una firma, el certificado de un firmante ni su sello. §29.10 ya no promete la respuesta OCSP: promete lo que la cápsula conserva. 5. **El JSON de drand, estricto** (§47.1): - ningún objeto repite un nombre; - los nombres se comparan exactos tras decodificar sus escapes; - un sustituto suelto hace el JSON mal formado; - `round` es un entero sin signo de 1 a 2⁵³ − 1, sin fracción ni exponente. Lo demás es `ERR_RELEASE_INVALID`. Hoy las tres implementaciones leen como `encoding/json` de Go: el último de dos nombres repetidos gana, y `ROUND` vale como `round`. Comprobado: `{"round":1000,"ROUND":1001,…}` da la ronda 1001 en Go, y 1000 en un lector con `JSON.parse` o con el `json` de Python. 6. **Erratas.** - §1 junta en una línea la Release API, la Release Cache y el objeto release. - La lista de §74 acaba en punto. - §77 añade ETSI EN 319 421 y 319 422. - §79 nombra las interfaces de `drand/kyber`, que `scripts/recovery` también importa. - La cabecera ya no dice «prevista» de la implementación de referencia. No cambia ningún formato. Cambian dos veredictos, el del sello sin `accuracy` y el de algunos JSON de drand, y §70 y §76 lo registran. ## Decisiones 1. **El sello sin `accuracy` acredita como S5, sin margen ni tabla de políticas.** Es lo que pidió Astra: ningún margen fijo vale para toda TSA, y la precisión de una política solo la sabe quien la conoce. Una tabla de políticas con su precisión, para dar S4 a un sello sin `accuracy`, queda en §74 como trabajo futuro: habría que mantenerla en el spec y en las tres implementaciones. - Recomendación: aprobar. 2. **Un motivo propio para un token BTSP sin `accuracy`.** Cuesta comparar un OID, y dice algo útil: que la autoridad incumple su propia política, y no solo que el sello no basta. Las cláusulas están comprobadas en los textos de ETSI: EN 319 421 V1.3.1, §5.1 (1 s o mejor), §5.2 (el OID), TIS-7.7.1-01 (el perfil de EN 319 422) y TIS-7.7.2-03; y EN 319 422 V1.1.1, §5.2.2 («the accuracy field shall be present»). - Recomendación: aprobar. 3. **El escritor MUST avisar de un sello sin `accuracy`** (regla 19) y SHOULD ofrecer pedirlo a otra autoridad. No lo rechaza: el sello sigue probando que la firma existía en t. Hoy ningún escritor pide sellos, ni la CLI ni `/create`, así que la regla no cambia ningún código. - Recomendación: aprobar. 4. **La receta sin tablas.** Cubre las letras de las dos listas, el español y el inglés de la EFF, y cualquier ASCII. Una letra de fuera, como la ç catalana o la ß, ya necesita las tablas. Ampliarla a todo Latin-1 es posible, pero alarga el anexo con casos que las listas no dan. - Recomendación: aprobar como está. 5. **Sin paquete de recuperación en el spec.** Astra proponía nombrar en el anexo un paquete de recuperación por su versión, su SHA-256 y el SHA-256 de cada fichero. El borrador nombra solo `UnicodeData.txt` por su SHA-256. Sirve cualquier copia que lo cumpla, y unicode.org conserva todas sus versiones. Un paquete tiene dos problemas: - el anexo no puede dar el SHA-256 de un paquete que lo contiene; - necesita un sitio público donde alojarlo, y hoy no hay ninguno: el Gitea no es nuestro. Cuando haya sitio, el paquete puede llevar `UnicodeData.txt`, el código de `scripts/recovery` y las listas, y el anexo lo nombraría sin contenerse a sí mismo. - Recomendación: aprobar sin paquete, y añadirlo a §74 cuando haya sitio público. 6. **Las evidencias, SHOULD guardar y MUST decir lo que falta.** No es un MUST guardar las cadenas, porque pueden no caber ni en 64 KiB con varios firmantes. Los veredictos del lector no cambian: un certificado de más no decide nada. Ningún escritor firma hoy con certificados. - Recomendación: aprobar. La medida del área (§74, §75 punto 13) incluirá las cadenas sin la raíz. 7. **La ronda del JSON de drand, de 1 a 2⁵³ − 1**, como en el objeto release. La ronda 0 y las mayores pasan de `ERR_ROUND_MISMATCH` a `ERR_RELEASE_INVALID`. Así el JSON y el objeto tienen el mismo rango. - Recomendación: aprobar. 8. **Los vectores de los sellos.** En `security_cms.json`, once de los trece casos que dan S4 llevan un token sin `accuracy`, porque el generador no la escribe si es 0. Con la v0.16 darían S5, y algunos dejarían de probar lo que dicen. Por ejemplo, «an authority named with 50 spaces» prueba cómo se muestra el nombre de la autoridad, y S5 no lo muestra. La propuesta: - regenerar esos casos con una `accuracy` de 1 s, para que sigan en S4; - añadir los casos sin `accuracy` de §64: años antes de la fecha, de la política BTSP, después de la fecha y en `alg` 2; - añadir uno con una `accuracy` de 0 segundos. Los fixtures no cambian: `format3_sealed` y `format3_signed_cms` ya llevan `accuracy`. - Recomendación: aprobar. ## Lo que queda para después - **La revisión externa.** Su paquete sigue en la v0.15. Al cerrar la v0.16 se le añade este cambio, que responde a una revisión. - **La licencia del anexo.** Decidida el 7-10: el spec es CC BY-ND 4.0, y la cabecera del anexo lo dice (`70d907b`). ## Al aprobar - `SpecVersion` 0.16, el SHA-256 en `spec/README.md`, el anexo regenerado con `DATEKEYS_WRITE_ANNEX=1`, el tag `spec-v0.16` y `main`. - En Go: - los veredictos y textos del sello; - el lector estricto del JSON de drand; - `scripts/recovery` con las palabras; - el fixture con un último bloque completo; - los vectores nuevos. - TypeScript y Dart siguen a Go con los vectores sincronizados. En TypeScript, la guarda exige una prueba para cada fichero nuevo de `testdata`.