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

8.8 KiB

Capability Spec Delta: drive (drive)

Package: @suaveplan/drive Status: PROPOSED

Every requirement below carries a **Verified by:** line at authoring time. The named tests are planned; they MUST exist and pass verbatim before this delta is folded into openspec/specs/drive/spec.md.

ADDED Requirements

Requirement: Drive.createReadStream accepts a range-options bag

Drive.createReadStream SHALL be overloaded to accept either a bare AbortSignal (existing form) or a RangeReadOptions bag with optional offset, length, and signal. The bare-signal form MUST continue to return a whole-file stream. When the options form is passed, the drive MUST forward { offset, length, signal } through the plugin middleware chain via the middleware context's range field. The implementation MUST runtime-discriminate via instanceof AbortSignal.

Scenario: bare signal still returns whole-file stream

  • WHEN drive.createReadStream("file.bin", abortSignal) is called on a 200 KiB file
  • THEN the returned stream emits the entire 200 KiB payload and respects abortSignal for cancellation

Scenario: options form forwards offset and length

  • WHEN drive.createReadStream("file.bin", { offset: 1024, length: 4096 }) is called
  • THEN the middleware context carries range = { offset: 1024, length: 4096 } and the returned stream emits exactly bytes [1024, 5120) of the source

Scenario: zero-length range yields an empty stream

  • WHEN drive.createReadStream("file.bin", { offset: 12345, length: 0 }) is called
  • THEN the returned stream closes immediately with zero enqueued bytes

Verified by: src/drive/drive.test.ts::"createReadStream(path, signal) preserves whole-file behaviour" AND src/drive/drive.test.ts::"createReadStream(path, { offset, length }) emits exactly the requested slice" AND src/drive/drive.test.ts::"createReadStream(path, { length: 0 }) returns an immediately closed stream"


Requirement: Invalid range options throw DRIVE.RANGE_INVALID synchronously

Drive.createReadStream(path, options) SHALL validate options.offset and options.length synchronously before constructing the ReadableStream. Either field, when present, MUST be a finite non-negative integer (Number.isInteger(x) && x >= 0 && Number.isFinite(x)). On violation, the method MUST throw DriveError(DRIVE.RANGE_INVALID, ...) BEFORE returning. The error's context SHALL include the offending field name and value.

Scenario: negative offset throws synchronously

  • WHEN drive.createReadStream("file.bin", { offset: -1 }) is called
  • THEN the call throws DriveError with code === "DRIVE.RANGE_INVALID" and context.field === "offset", and no ReadableStream is created

Scenario: non-integer length throws synchronously

  • WHEN drive.createReadStream("file.bin", { length: 1.5 }) is called
  • THEN the call throws DriveError with code === "DRIVE.RANGE_INVALID" and context.field === "length"

Scenario: NaN / Infinity rejected

  • WHEN drive.createReadStream("file.bin", { offset: Number.NaN }) is called OR drive.createReadStream("file.bin", { length: Number.POSITIVE_INFINITY }) is called
  • THEN each call throws DriveError(DRIVE.RANGE_INVALID, ...) synchronously

Verified by: src/drive/drive.test.ts::"createReadStream throws RANGE_INVALID for negative offset" AND src/drive/drive.test.ts::"createReadStream throws RANGE_INVALID for non-integer length" AND src/drive/drive.test.ts::"createReadStream throws RANGE_INVALID for NaN or Infinity"


Requirement: Out-of-bounds range surfaces DRIVE.RANGE_OUT_OF_BOUNDS

When the underlying source exposes a known size at stream-start (via the chunks-plugin manifest, a storage stat, or a nativeRange-capable storage that reports size), Drive.createReadStream MUST raise DriveError(DRIVE.RANGE_OUT_OF_BOUNDS, ...) synchronously for offset > size or offset + length > size. When size is unknown at start-time, the stream MUST accept the request, emit available bytes, and on close MUST surface DRIVE.RANGE_OUT_OF_BOUNDS via controller.error if the byte count emitted is less than the requested length. The error MUST carry the originating CHUNKS.RANGE_OUT_OF_BOUNDS (when applicable) as cause.

Scenario: offset past EOF rejected synchronously when size is known

  • WHEN the underlying file is 1024 bytes and drive.createReadStream("file.bin", { offset: 2048 }) is called via a chunks-plugin-mediated path
  • THEN the call throws DriveError(DRIVE.RANGE_OUT_OF_BOUNDS, ...) synchronously with cause carrying CHUNKS.RANGE_OUT_OF_BOUNDS

Scenario: offset+length past EOF rejected synchronously when size is known

  • WHEN the file is 1024 bytes and drive.createReadStream("file.bin", { offset: 900, length: 500 }) is called via the chunks plugin
  • THEN the call throws DriveError(DRIVE.RANGE_OUT_OF_BOUNDS, ...) synchronously

Scenario: short-fall on stream end when size was unknown at start

  • WHEN the storage cannot report size, drive.createReadStream("file.bin", { offset: 0, length: 10_000 }) is called, and the source closes after 4000 bytes
  • THEN the stream errors with DriveError(DRIVE.RANGE_OUT_OF_BOUNDS, ...) and context.emittedBytes === 4000

Verified by: src/drive/drive.test.ts::"createReadStream throws RANGE_OUT_OF_BOUNDS when offset exceeds known size" AND src/drive/drive.test.ts::"createReadStream throws RANGE_OUT_OF_BOUNDS when offset+length exceeds known size" AND src/file-operations/streams.range.test.ts::"stream errors with RANGE_OUT_OF_BOUNDS on short-fall when size is unknown"


Requirement: nativeRange storage capability is honoured

DriveStorage SHALL accept an optional capabilities.nativeRange?: boolean flag. When true, Drive.createReadStream(path, { offset, length, signal }) MUST forward { offset, length } to storage.createReadStream directly. When false (or absent), the drive MUST wrap the storage stream in a slicing transform that drops bytes before offset and stops emitting after length bytes. Both paths MUST produce identical observable output.

Scenario: storage with nativeRange receives offset/length

  • WHEN storage.capabilities.nativeRange === true and drive.createReadStream("file.bin", { offset: 1024, length: 4096 }) is invoked
  • THEN storage.createReadStream is called exactly once with { offset: 1024, length: 4096, signal } and no slicing transform is interposed

Scenario: storage without nativeRange is wrapped in slicing transform

  • WHEN storage.capabilities?.nativeRange is undefined or false and the same call is made
  • THEN storage.createReadStream is called with { signal } only, and the returned stream is wrapped so the consumer observes exactly bytes [1024, 5120)

Verified by: src/file-operations/streams.range.test.ts::"nativeRange storage receives offset and length directly" AND src/file-operations/streams.range.test.ts::"non-nativeRange storage is wrapped in a slicing transform"


Requirement: Range cancellation propagates via AbortSignal

Drive.createReadStream(path, options) MUST propagate options.signal (or the bare signal in the back-compat form) through the chunks-plugin / mesh / storage pull chain. On abort, in-flight chunk fetches MUST be cancelled, the stream MUST close with controller.error(AbortError), and (over drive+mesh://) the mesh transport MUST emit a cd:error envelope with code: "ABORTED".

Scenario: mid-stream abort cancels chunk fetches

  • WHEN drive.createReadStream("file.bin", { offset: 0, length: 1_048_576, signal }) is called and signal.abort() is invoked after the first chunk emits
  • THEN the stream closes with an AbortError, no further chunks are fetched, and the chunks-plugin loop exits at the next throwIfAborted checkpoint

Verified by: src/file-operations/streams.range.test.ts::"abort mid-range stream cancels in-flight chunk fetches"


Requirement: DRIVE_CODES registry adds RANGE_INVALID and RANGE_OUT_OF_BOUNDS

DRIVE_CODES SHALL include "RANGE_INVALID" and "RANGE_OUT_OF_BOUNDS" declared via the existing defineCodes("DRIVE", [...] as const) call. Object.isFrozen(DRIVE_CODES) MUST remain true. Every code value MUST start with DRIVE..

Scenario: registry exposes the new codes

  • WHEN the test imports DRIVE_CODES from @suaveplan/drive
  • THEN DRIVE_CODES.RANGE_INVALID === "DRIVE.RANGE_INVALID" AND DRIVE_CODES.RANGE_OUT_OF_BOUNDS === "DRIVE.RANGE_OUT_OF_BOUNDS" AND Object.isFrozen(DRIVE_CODES) === true

Verified by: src/error-codes.spec-conformance.test.ts::"DRIVE_CODES exposes RANGE_INVALID and RANGE_OUT_OF_BOUNDS" AND src/error-codes.spec-conformance.test.ts::"Object.isFrozen(DRIVE_CODES) is true"