# Drive — Capability Spec ## DRIVE-01 — Drive consumes `AbstractStorage` directly `Drive` MUST accept any concrete `AbstractStorage` from `@suaveplan/storage` as its storage substrate. There MUST NOT be a separate `StorageAdapter` shim. Drive MUST narrow capabilities through a `DriveStorage` view that extends `AbstractStorage` with `id: string` and optional lifecycle hooks. **Verified by:** `src/drive/drive.spec-conformance.test.ts`::"accepts MemoryStorage as DriveStorage" ## DRIVE-02 — `initialize()` is idempotent and ownership-tracking `Drive.initialize()` MUST be idempotent. For each registered storage, drive MUST call `storage.connect?.()` ONLY when `storage.isConnected?.() !== true`, and MUST record those storages in an internal `connectedByMe: WeakSet`. Connection failures MUST surface as `DriveError(DRIVE.STORAGE_CONNECT_FAILED, { cause })`. **Verified by:** `src/drive/drive.spec-conformance.test.ts`::"calls connect only when not already connected" AND `src/drive/drive.spec-conformance.test.ts`::"surfaces connect failure as STORAGE_CONNECT_FAILED" ## DRIVE-03 — `dispose()` is idempotent and ownership-respecting `Drive.dispose()` MUST be idempotent. Drive MUST only close storages in `connectedByMe`; storages pre-connected by the caller MUST be left open. After `dispose()`, the drive transitions to a terminal disposed state. **Verified by:** `src/drive/drive.spec-conformance.test.ts`::"closes only storages connected by drive" AND `src/drive/drive.spec-conformance.test.ts`::"does not close pre-connected storage" ## DRIVE-04 — Operations after `dispose()` throw Any file operation invoked on a disposed drive (`read`, `write`, `delete`, `stat`, `list`, `createReadStream`, `createWriteStream`) MUST throw `DriveError(DRIVE.DISPOSED)`. Operations invoked before `initialize()` MUST throw `DriveError(DRIVE.NOT_INITIALIZED)`. **Verified by:** `src/drive/drive.spec-conformance.test.ts`::"read throws DISPOSED after dispose" AND `src/drive/drive.spec-conformance.test.ts`::"read throws NOT_INITIALIZED before initialize" ## DRIVE-05 — Error-code registry is namespaced and frozen `DRIVE_CODES` MUST be declared via `defineCodes("DRIVE", [...])` from `@suaveplan/error`. `Object.isFrozen(DRIVE_CODES)` MUST be `true`. Every code value MUST start with `DRIVE.`. `DriveError` MUST extend `SuaveplanError`. **Verified by:** `src/error-codes.spec-conformance.test.ts`::"Object.isFrozen(DRIVE_CODES) is true" AND `src/error-codes.spec-conformance.test.ts`::"every code value starts with DRIVE." ## DRIVE-06 — Plugin middleware order `drive.use(plugin)` and `drive.useMiddleware(mw)` MUST install in registration order. Middleware chains for `read`, `write`, `delete`, `stat`, `list` MUST execute outer-first on the request path and outer-last on the response path. `plugin.dispose()` MUST be called in reverse-registration order on `Drive.dispose()`. Plugin install/dispose throws MUST surface as `DriveError(DRIVE.PLUGIN_FAILED, { cause })`. **Verified by:** `src/plugins/registry.spec-conformance.test.ts`::"middleware executes outer-first request, outer-last response" AND `src/plugins/registry.spec-conformance.test.ts`::"dispose calls plugins in reverse registration order" AND `src/plugins/registry.spec-conformance.test.ts`::"plugin install throw surfaces as PLUGIN_FAILED" ## DRIVE-07 — Capability fallbacks for streams `drive.createReadStream(path)` MUST use `storage.createReadStream` when `storage.capabilities?.nativeStreams === true`, otherwise MUST fall back to the inherited `AbstractStorage.defaultCreateReadStream`. Same rule for `createWriteStream`. **Verified by:** `src/file-operations/streams.spec-conformance.test.ts`::"createReadStream uses native stream when nativeStreams=true" AND `src/file-operations/streams.spec-conformance.test.ts`::"createReadStream falls back when nativeStreams=false" ## DRIVE-08 — Generic storage typing `Drive` MUST narrow `TStorageMap` through `drive.use(id, storage)` so that `drive.getStorage(id)` returns `TStorageMap[K]` exactly (no widening to the base `DriveStorage`). Calls with an unknown id MUST be a TypeScript error. **Verified by:** `src/drive/drive.spec-conformance.test.ts`::"getStorage returns narrowed type" (type-level) ## DRIVE-09 — Constructor overloads `new Drive()`, `new Drive(storage)`, `new Drive(storage, options)`, and `new Drive({ defaultStorage, plugins, ... })` MUST all be valid. The bare-storage form MUST be observably equivalent to passing `{ defaultStorage: storage }` and MUST register the storage under id `"default"`. **Verified by:** `src/drive/drive.spec-conformance.test.ts`::"new Drive() is valid" AND `src/drive/drive.spec-conformance.test.ts`::"new Drive(storage) registers as default"