Files
2026-05-27 23:29:53 +01:00

5.6 KiB
Raw Permalink Blame History

Drive Plugin Chunks — Spec Delta (drive-plugin-chunks-port)

ADDED Requirements

CHUNKS-FORMAT-V1-01 — Chunk binary layout is byte-exact

A version 0x0001 chunk MUST be the byte concatenation metadata(100) ‖ sig(64) ‖ ciphertext(payloadLen), total 164 + payloadLen bytes, big-endian throughout. Field offsets within metadata MUST be exactly: version 0–2, fileId 2–34, chunkId 34–38, totalChunks 38–42, fileSize 42–50, chunkSize 50–54, payloadLen 54–58, flags 58–60, nonce 60–84, aeadTag 84–100. sig occupies 100–164. Ciphertext starts at 164.

Verified by: src/codec/chunk.spec-conformance.test.ts (CHUNKS-FORMAT-V1-01).

CHUNKS-FORMAT-V1-02 — flags reserved in v1

flags MUST be 0x0000 for v1. Receivers MUST reject chunks with non-zero flags via ChunksError(CHUNKS.FLAGS_RESERVED_NONZERO) before any further parse work.

Verified by: src/codec/chunk.spec-conformance.test.ts (CHUNKS-FORMAT-V1-02).

CHUNKS-FORMAT-V1-03 — Payload length invariants

For non-final chunks (chunkId < totalChunks - 1), payloadLen MUST equal chunkSize - 164. For the final chunk, payloadLen MUST equal fileSize - chunkId * (chunkSize - 164). Mismatches MUST be rejected via ChunksError(CHUNKS.PAYLOAD_LEN_INVALID) before sig verification.

Verified by: src/codec/chunk.spec-conformance.test.ts (CHUNKS-FORMAT-V1-03).

CHUNKS-SIG-01 — Signature covers metadata plus ciphertext

sig MUST be ed25519_sign(serverPrivKey, metadata[0..100] ‖ ciphertext[0..payloadLen]). Verification MUST be performed before AEAD decryption. Any mutation to any signed byte MUST cause sig verification to fail with ChunksError(CHUNKS.SIG_INVALID).

Verified by: src/pipeline/sign-chunk.spec-conformance.test.ts (CHUNKS-SIG-01).

CHUNKS-INVARIANT-01 — Store-as-is

Plugin MUST persist received chunks byte-identical to receipt. No re-signing, no re-encryption, no metadata rewrites. The bytes returned by chunkStore.get(fileId, chunkId) MUST equal the bytes accepted by chunks.putChunk(rawBytes) for that chunk.

Verified by: src/plugin.spec-conformance.test.ts (CHUNKS-INVARIANT-01).

CHUNKS-VERIFY-01 — Sig-verify gate on receipt

chunks.putChunk(rawBytes) MUST run, in order: structural parse → flags check → payload-length invariant → ed25519 sig verification → persist. Any failure aborts persistence and returns the appropriate ChunksError code without writing to storage.

Verified by: src/plugin.spec-conformance.test.ts (CHUNKS-VERIFY-01).

CHUNKS-READ-01 — Read middleware reassembles via streaming

When a fileId is registered for path, drive.read(path) MUST return a ReadableStream<Uint8Array> that yields plaintext by iterating chunk 0..N-1, sig-verifying each, AEAD-decrypting, and enqueueing only the first payloadLen bytes of each chunk's plaintext. The full file MUST NOT be materialised in memory.

Verified by: src/plugin.spec-conformance.test.ts (CHUNKS-READ-01).

CHUNKS-LAYOUT-SPARSE-01 — Sparse-file layout

In sparse-file mode, the plugin MUST pre-allocate a single storage object of length (totalChunks - 1) * chunkSize + (164 + lastPayloadLen) after manifest load. Each chunk MUST be written via storage.setPartial(fileKey, chunkId * chunkSize, rawBytes). A separate BitSet at bitmap:<fileId> MUST track landed chunks. The plugin MUST require storage.capabilities.partialWrites === true and throw ChunksError(CHUNKS.LAYOUT_INCOMPATIBLE) otherwise.

Verified by: src/layout/sparse-file.spec-conformance.test.ts (CHUNKS-LAYOUT-SPARSE-01).

CHUNKS-LAYOUT-KEYS-01 — Chunk-keys layout

In chunk-keys mode, each chunk MUST be stored as its own object at key chunks/<fileId>/<chunkId>. hasChunks(fileId) MUST be derivable from key existence (storage.exists). No bitmap object is required.

Verified by: src/layout/chunk-keys.spec-conformance.test.ts (CHUNKS-LAYOUT-KEYS-01).

CHUNKS-LAYOUT-AUTO-01 — Auto layout selection

In auto mode (default), the plugin MUST pick sparse-file when storage.capabilities.partialWrites === true, otherwise MUST pick chunk-keys. The selected layout MUST be observable via chunks.layout.

Verified by: src/layout/auto.spec-conformance.test.ts (CHUNKS-LAYOUT-AUTO-01).

CHUNKS-MANIFEST-01 — Manifest format and signature

The manifest MUST be a Zod-validated object with fields version, fileId, fileSize, chunkSize, totalChunks, encryption: { algo, fileKeyWrapped, baseNonce }, chunks: [{ chunkId, hash, payloadLen }], and sig. sig MUST be ed25519_sign(serverPrivKey, canonical_serialize(manifest_without_sig)). Load failures (parse, schema, sig) MUST throw ChunksError(CHUNKS.MANIFEST_INVALID).

Verified by: src/manifest/load.spec-conformance.test.ts (CHUNKS-MANIFEST-01).

CHUNKS-MANIFEST-02 — Manifest distribution strategy

Default strategy MUST be manifest-as-chunk: the manifest is itself a server-signed object stored at storage key manifest:<fileId>. server-only strategy MUST be opt-in via manifestSource: "server-only"; in that mode loadManifest(fileId) fetches via an injected fetch against the configured server URL.

Verified by: src/manifest/load.spec-conformance.test.ts (CHUNKS-MANIFEST-02).

CHUNKS-CODES-01 — Error registry namespaced and frozen

CHUNKS_CODES MUST be declared via defineCodes("CHUNKS", [...]). Object.isFrozen(CHUNKS_CODES) MUST be true. Every code value MUST start with CHUNKS.. ChunksError MUST extend SuaveplanError<ChunksErrorCode>.

Verified by: src/error-codes.spec-conformance.test.ts (CHUNKS-CODES-01).