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.

132 lines
11 KiB

# Plan: formato 3 en `datekeys-ts` (spec v0.10, entrega 1)
*30 de septiembre de 2026. Implementa en `datekeys-ts`, rama `v0.10`, lo que la referencia Go ya hace con el tag `spec-v0.10` (`cc35d2c`): leer y escribir cápsulas de formato 3, en la librería y en las páginas. Fuentes: el spec v0.10, [spec_v0.10/formato3_diseno.md](spec_v0.10/formato3_diseno.md), cuyas decisiones de la página ya aprobó el autor (apartados 3 y 5, decisiones 8 a 11 del apartado 9), y el código Go de `capsule/format3.go`, `open3.go`, `encrypt3.go` e `internal/pathrule`.*
## Reglas de trabajo
- Cada paso va en su commit, o en varios, sobre la rama `v0.10`, y cada commit deja `npm run verify` en verde. `main` no se toca mientras el autor no decida si cierra `0.2.0` (§2.3 del handoff).
- Nada se sube sin la autorización del autor.
- Sin dependencias nuevas: las tablas Unicode las genera `datekeys-go` (`pathrule/gen -ts`), y el ZIP y el CRC-32 son código propio.
- `testdata` solo llega de `datekeys-go`, con `scripts/sync-testdata.mjs` y el tag `spec-v0.10`.
- Los textos de error siguen los de Go byte a byte, también los de las reglas de rutas y de texto, y las líneas de los veredictos en español.
- `src/lib/dkc` sigue a la referencia Go. Lo que solo tiene la página va en `src/lib/inspector`: el ZIP, el CRC-32 y el sumidero en OPFS.
- Los módulos nuevos se cubren al 100 %, como los de las fases 2 y 3 (`vitest.config.ts`).
## Pasos
| Paso | Contenido | Resultado |
|---|---|---|
| 0 | Tablas: el generador de `datekeys-go` escribe `src/lib/dkc/pathrule-tables.ts` | Hecho el 30-09: `datekeys-go` `13910b3`, sin subir. El digest recalculado en TypeScript coincide con `TablesDigest` |
| 1 | `pathrule.ts`: NFD, pliegue, clave de R7, de R1 a R10 con R4b, R6b, R6c y R9, y las reglas de texto de §29.6 | Hecho el 30-09: los casos de las pruebas Go con sus textos, y cobertura del 100 % |
| 2 | Códec del formato 3, sin tocar la trama: `BODY`, `security` y head, y `ERR_HEAD_INVALID` | Hecho el 30-09, `d9a9cf5`: los casos de las pruebas Go, con los textos de Go sacados de la referencia |
| 3 | Lector y `testdata` en `spec-v0.10`: `VERSION` 3, control de versión 3, paso 17 en subpasos, sumidero y lectura hasta EOF | Hecho el 30-09, `b176ad2`: los 209 casos del corpus con el texto exacto de Go, congelado en `testing/mutation-texts.json` |
| 4 | Escritor: `encryptFiles`, en dos fases y con dos lecturas; `encrypt` solo para vectores | Hecho el 30-09, de `3daa1f7` a `2efc8bc`: los cinco fixtures de `EncryptFiles` byte a byte, los textos de Go, `/create` en formato 3 con un fichero, y Go abre seis cápsulas de formato 3 de TypeScript |
| 5 | ZIP de la página y su sumidero en OPFS | Hecho el 30-09, `36096a9` y `ee82f43`: `ZipSink` con escrituras posicionadas, y `archive/zip` de Go lee las muestras, 65 535 entradas incluidas |
| 6 | Página `/inspect`: veredictos, autor, comentario, rutas y descargas | Hecho el 30-09, `651178a`: un fichero suelto o un ZIP en OPFS, con la descarga de cada fichero; en Chromium, el ZIP de `format3_tree` con sus CRC-32 parcheados y el borrado del temporal |
| 7 | Página `/create`: ficheros y carpetas, rutas editables, exclusiones, comentario, autor y mtime | Hecho el 30-09, `7dc88ef`: el tamaño exacto antes de escribir, y `datekeys decrypt` de Go y `/inspect` abren una cápsula de seis ficheros escrita por la página |
| 8 | Documentación, verificación y revisión adversarial | README, CHANGELOG, `npm run verify` y una revisión adversarial del lector, del escritor y de las páginas |
### Paso 1. Reglas de rutas y de texto
- `pathrule-tables.ts` es código generado: no se edita a mano. Se regenera con `go run ./internal/pathrule/gen -data .cache -go internal/pathrule/tables.go -ts ../App/src/lib/dkc/pathrule-tables.ts` desde `datekeys-go`, y una prueba recalcula su digest.
- `pathrule.ts` no usa `normalize`, `toLowerCase`, `localeCompare`, `Intl` ni las clases `\p{...}`, porque su versión de Unicode cambia con el motor. Los límites cuentan bytes de UTF-8, con el `utf8Length` de `bytes.ts`.
- `index.ts` no lo reexporta: sus tablas pesan 136 KB y se cargan bajo demanda, con el lector y con el formulario de `/create` (pasos 6 y 7).
### Paso 2. Códec
- Módulos por esquema, como `header.ts` y `control.ts`: `body.ts` (la trama de §29.2, `AREA_LEN`, `SECURITY_LEN` y `HEAD_LEN`, y el área rellena de ceros), `security.ts` (el mapa exterior, la firma y el sello, los veredictos X, F0, F1, S0, S1 y S2 con sus textos, y el codificador) y `head.ts` (capas 2 a 4 del head, R1 y R8 en la capa 3, y la capa 4 con `ERR_HEAD_INVALID`).
- `ERR_HEAD_INVALID` en `errors.ts`, que pasa a 19 códigos, y su glosa en `format.ts`.
- El objeto de extensiones `HEAD_CBOR` en `extension.ts`, con sus claves 6 y 7.
- Pruebas: los casos de `format3_test.go` con sus bytes y sus textos. Los vectores de `head_schema.json` y `security.json` llegan en el paso 3.
### Paso 3. Lector y datos de prueba
- `npm run testdata:sync -- --commit spec-v0.10`, `SPEC_VERSION` 0.10, y la autocomprobación del arnés con `want 0.10`.
- Trama: `FORMAT_3`, y `isFormat` acepta de 1 a 3. El control de versión 3 tiene las claves del de versión 2. `accessSlots` da 16 en los formatos 2 y 3, y el relleno vale para los dos.
- `open`:
- Gana `OpenOptions.sink`: `begin(head)`, `create(i)` con un `WritableStream`, `commit()` y `abort()`. Tiene la semántica del `Sink` de Go: nada se presenta como válido antes de `commit`.
- Sin sumidero, un formato 3 rechaza con un `TypeError` justo tras el paso 2, antes de pedir nada, como `ErrSinkRequired`.
- El paso 17 va en los subpasos 17.1 a 17.8, con la precedencia de Go:
- Un fallo de `age`, o una longitud distinta de P, prevalece.
- Si no, manda el primer subpaso que falle.
- Los códigos distintos de `ERR_INTEGRITY` solo se dan tras leer `PAYLOAD_AGE` hasta EOF.
- `Opened` gana `head`, `verdicts`, `areaLen` y `unusableHeadExtensions`.
- `inspect` acepta el formato 3 en los pasos 1 a 8, y su vista JSON coincide con la de Go.
- Un sumidero en memoria en `opener.ts`, para los fixtures y para contenidos de hasta 64 MiB. Hasta el paso 6, la página inspecciona el formato 3 y, al abrirlo, dice que aún no entrega ficheros.
- Pruebas:
- `fixtures.test.ts` con los formatos 1, 2 y 3.
- `open.test.ts`: cada fixture abre, con el SHA-256 de `BODY` y el de cada fichero.
- `mutations.json`: 209 casos, con la clave `verdicts` y los casos `ok`, desde memoria y desde un `Blob`, con un sumidero que debe acabar abortado.
- `inspect_differential.json`: 5 110 casos sobre 14 bases.
- `cbor.json` con el control de versión 3; `head_schema.json`, `security.json`, `paths.json` y `path_fold.json`.
- `ibe-vectors.json`, regenerado con `scripts/ibe-go-vectors.go` para los nueve fixtures nuevos.
- Los textos de error de los 209 casos quedan congelados desde Go, con un script, en `testing/`, igual que `capsule-vectors.json`. En la v0.9 se compararon una sola vez, fuera del repositorio.
- `check-build.mjs` añade a los secretos de fixture que no pueden publicarse el head, la sal, el comentario, los ficheros y `BODY`.
### Paso 4. Escritor
- `encryptFiles(files, opts)`:
- Cada fichero trae `path`, `size`, `mtime` opcional (en milisegundos, como `File.lastModified`) y una forma de leerlo dos veces: un `Blob` o `open()`.
- Las opciones ganan `comment`, `author` y las extensiones del head.
- Primera fase:
- Rutas y textos con las reglas del lector: CR LF y un CR suelto pasan a LF en el comentario.
- La mtime con la regla 16 de §62.1.
- L medido con un head de sal y hashes a cero.
- `|HEAD|` de 16 MiB como máximo, y L como máximo L_MAX.
- La primera pasada de SHA-256, en piezas de 64 KiB.
- Segunda fase:
- La sal y `HEAD_CBOR`, el control de versión 3 y el `SECURITY_CBOR` vacío.
- La autodecodificación de los tres CBOR (MUST).
- La segunda pasada, que aborta si un fichero cambió de tamaño o de SHA-256, con el texto de Go.
- El `.dkk`.
- `capsuleLength3` en `lengths.ts`: el tamaño exacto antes de escribir, para la página.
- `encrypt` escribe el formato 2 solo con `testVectors`, con el texto de Go. La página deja de usarlo en el paso 7.
- Interoperabilidad:
- `scripts/capsule-ts-samples.mjs` gana muestras del formato 3, y `scripts/capsule-go-verdicts.go` las abre con `capsule.Open` y un sumidero.
- `capsule-vectors.json` se regenera.
- Con sorteos fijos, las secciones deterministas coinciden con las de los fixtures `format3_*`.
### Paso 5. ZIP y sumidero de la página
- Hechos y cubiertos al 100 %:
- `crc32.ts`.
- `zip.ts`: entradas almacenadas, nombres UTF-8 con el bit 11, sin descriptores de datos ni entradas de carpeta, el CRC-32 parcheado en la cabecera local, fechas DOS en UTC entre 1980 y 2107, el campo NTFS 0x000A, que manda, el 0x5455 cuando cabe en 32 bits con signo, y ZIP64 por tamaño, posición o número de entradas.
- `zipsink.ts`, un sumidero sobre un solo fichero de OPFS:
- Un único fichero de un segmento se escribe tal cual.
- En otro caso va el ZIP, con las cabeceras escritas por adelantado, el CRC-32 con escrituras posicionadas y el directorio central en `commit`.
- Cada fichero se ofrece como un trozo (`slice`) del de OPFS.
- `tempfile.ts` gana la escritura posicionada.
- Interoperabilidad:
- Un script escribe ZIP con TypeScript: nombres no ASCII, mtime ausente o fuera de rango, ficheros vacíos y 65 535 entradas.
- `archive/zip` de Go los lee, y el resultado queda congelado en `testing/zip-vectors.json`.
- La entrada de 4 GiB solo se prueba en la disposición: el fichero entero no cabe en una prueba.
### Paso 6. Página `/inspect`
- Primero los veredictos, en sus líneas de §29.7, y después el autor declarado y el comentario, con el prefijo de la regla.
- Las rutas, en `<bdi dir=auto>` y con los invisibles escapados.
- Avisos según la clave de R7: `.lnk`, `.url`, `.library-ms`, `.searchConnector-ms`, `desktop.ini`, `.git`, ejecutables y un `-` inicial.
- Descargas:
- Un único fichero de un segmento se descarga con su nombre, pasado por `safeFileName`.
- Un único fichero dentro de una carpeta se descarga primero, y el ZIP después (decisión 8).
- Con varios ficheros, el ZIP se llama `<primer segmento común>.zip`, o `<nombre del .dkc>.zip`, y cada fichero tiene su descarga.
- El espacio de OPFS se comprueba dos veces: con el contenido cifrado antes de empezar, como en el formato 2, y con la longitud exacta del ZIP al leer el head, antes de escribir nada.
- `check-build.mjs` comprueba que las tablas de `pathrule` no entran en la primera carga de ninguna página.
### Paso 7. Página `/create`
- Ficheros y carpetas, con `multiple`, `webkitdirectory` y arrastrar y soltar.
- Rutas editables, validadas con `pathrule` a medida que se escriben.
- Exclusiones tachadas, que se pueden reactivar: `.DS_Store`, `Thumbs.db`, `desktop.ini`, `._*` y `__MACOSX/`.
- Comentario, autor declarado, y una casilla de mtime marcada por defecto.
- Las dos fases del escritor, con el progreso de las dos pasadas.
- El tamaño exacto del `.dkc` y la comprobación de la cuota antes de escribir.
- `creator.ts` sigue inspeccionando la cápsula escrita y exige el tamaño y la ronda del plan.
### Paso 8. Documentación, verificación y revisión
- README: versiones, módulos, páginas, vectores, dependencias y `testdata`. CHANGELOG: bajo «sin publicar»; el número de versión lo decide el autor.
- `npm run verify` y `npm run testdata:check`.
- Revisión adversarial de las páginas, del lector y del escritor, con subagentes, como en la fase 3.
- Actualizar el handoff.

Powered by TurnKey Linux.