# Capability Spec Delta: storage-uri (fix-storage-uri-error-passthrough) **Package**: `@suaveplan/storage-uri` **Status**: PROPOSED > Every requirement carries a `**Verified by:**` line at authoring time. This delta MODIFIES two requirements from `add-storage-uri` (still in `openspec/changes/`, not yet archived). ## MODIFIED Requirements ### Requirement: Adapter error re-wrapping Errors thrown by the underlying adapter SHALL be inspected before re-wrap. Any throwable that is an instance of `SuaveplanError` (the runtime carrier for `defineCodes`-based error namespaces) SHALL be re-thrown unchanged — the resolver MUST NOT wrap a namespaced error inside its own envelope. Throwables that are NOT `SuaveplanError` instances (plain `Error`, foreign objects, strings) SHALL be wrapped in `StorageUriError` with `code === "STORAGE_URI.ADAPTER_ERROR"`, the original preserved as `cause`, and `uri` + `scheme` discriminants populated. This includes `StorageUriError` itself (which `extends SuaveplanError`) — the pre-existing pass-through is preserved as a special case of the new rule. #### Scenario: arbitrary non-Suaveplan throwable is re-wrapped as ADAPTER_ERROR - **WHEN** `read("file:///a")` is called and `adapter.get` throws `new Error("disk fault")` - **THEN** the rejection is a `StorageUriError` with `code === "STORAGE_URI.ADAPTER_ERROR"`, `cause.message === "disk fault"`, `uri === "file:///a"`, and `scheme === "file"` #### Scenario: SuaveplanError subclass passes through with its original code - **WHEN** `read("drive://primary/x")` is called and `adapter.get` throws `new DriveUriError("DRIVE_ID_MISMATCH", { uri, expected, actual })` (a `SuaveplanError` subclass with `code === "DRIVE_URI.DRIVE_ID_MISMATCH"`) - **THEN** the rejection is that same `DriveUriError` instance, `err.code === "DRIVE_URI.DRIVE_ID_MISMATCH"`, and the resolver does NOT wrap it inside a `StorageUriError` #### Scenario: existing StorageUriError is re-thrown unchanged - **WHEN** the adapter (via a nested resolver) throws `new StorageUriError("NOT_FOUND", ...)` - **THEN** the same instance is propagated; no re-wrap occurs **Verified by:** `src/resolver/resolver.test.ts::"wraps non-SuaveplanError throwables as ADAPTER_ERROR"` AND `src/resolver/resolver.test.ts::"passes through thrown SuaveplanError subclasses unchanged"` AND `src/resolver/resolver.test.ts::"re-throws StorageUriError unchanged"` --- ### Requirement: Streaming writes with buffered fallback The `write(uri, body, signal?)` method SHALL accept `Uint8Array` or `ReadableStream` for `body`. When the underlying adapter exposes `createWriteStream`, the resolver SHALL forward it. When the adapter exposes only `set`, the resolver SHALL drain the stream into a single `Uint8Array`, call `set` once, and SHALL increment `storage_uri.buffered_write_total{scheme}`. When `adapter.set` throws, the resolver SHALL apply the same pass-through rule as `Adapter error re-wrapping` (above): `SuaveplanError` subclasses SHALL pass through unchanged with their original code; non-`SuaveplanError` throwables SHALL be wrapped as `StorageUriError` with `code === "STORAGE_URI.WRITE_UNSUPPORTED"` and the original preserved as `cause`. #### Scenario: Uint8Array body is forwarded directly - **WHEN** `write("file:///a.bin", new Uint8Array([1,2,3]))` is called - **THEN** `adapter.set` is invoked exactly once with the exact byte array #### Scenario: stream body is drained into a single set call - **WHEN** `write("file:///a.bin", stream)` is called where `stream` yields three chunks - **THEN** `adapter.set` is invoked exactly once with the concatenated bytes; `buffered_write_total{scheme:"file"}` is incremented by 1 #### Scenario: non-Suaveplan throw on set wraps as WRITE_UNSUPPORTED - **WHEN** `write("memory://x/y", bytes)` is called against a plugin whose `adapter.set` throws `new Error("read only mount")` - **THEN** the call rejects with `StorageUriError` having `code === "STORAGE_URI.WRITE_UNSUPPORTED"` and `cause.message === "read only mount"` #### Scenario: SuaveplanError on set passes through with its original code - **WHEN** `write("drive://primary/x", bytes)` is called against a plugin whose `adapter.set` throws `new DriveUriError("WRITE_UNSUPPORTED", { uri, scheme: "drive" })` - **THEN** the rejection is that same `DriveUriError` instance, `err.code === "DRIVE_URI.WRITE_UNSUPPORTED"`, and the resolver does NOT re-wrap it as `STORAGE_URI.WRITE_UNSUPPORTED` **Verified by:** `src/resolver/resolver.writes.test.ts::"forwards Uint8Array body directly to adapter.set"` AND `src/resolver/resolver.writes.test.ts::"drains ReadableStream into single set call"` AND `src/resolver/resolver.writes.test.ts::"wraps non-Suaveplan throw on set as WRITE_UNSUPPORTED"` AND `src/resolver/resolver.writes.test.ts::"passes through thrown SuaveplanError subclasses on write"`