# Capability Spec Delta: drive-uri (drive-uri) **Package**: `@suaveplan/drive-uri` **Status**: PROPOSED > Every requirement carries a `**Verified by:**` line at authoring time naming planned tests. ## ADDED Requirements ### Requirement: `drive://` SHALL support writes and removes via the resolver surface The `drive` plugin's instrumented adapter SHALL delegate `set(key, value, signal?)` to `Drive.write(path, data, { signal })` and `delete(key, signal?)` to `Drive.delete(path, signal)`. Successful writes SHALL increment `drive_uri.writes_total{scheme:"drive", outcome:"success"}`; successful removes SHALL increment `drive_uri.deletes_total{scheme:"drive", outcome:"success"}`. The `AbortSignal` passed to `resolver.write(uri, body, signal)` / `resolver.remove(uri, signal)` SHALL be threaded through to the underlying `Drive` call. A pre-aborted signal SHALL short-circuit to `DRIVE_URI.ABORTED` without invoking `Drive.write` / `Drive.delete`. #### Scenario: write round-trips via Drive.write - **WHEN** `resolver.write("drive://primary/clip.mov", bytes)` is called against a `drive` plugin bound to a real local-storage `Drive` - **THEN** the call resolves with `void`, the underlying `Drive` reports the path persisted, and `resolver.read("drive://primary/clip.mov")` returns `bytes` #### Scenario: remove delegates to Drive.delete - **WHEN** `resolver.remove("drive://primary/clip.mov")` is called after a successful write - **THEN** the call resolves with `true` and a subsequent `resolver.read(...)` rejects with `STORAGE_URI.NOT_FOUND` #### Scenario: AbortSignal threads through writes - **WHEN** a `resolver.write(...)` is invoked with an `AbortSignal` that aborts mid-call - **THEN** the call rejects with `DRIVE_URI.ABORTED` and any underlying `Drive.write` invocation observes the abort **Verified by:** `src/plugins/drive/drive.test.ts::"writes succeed and round-trip via Drive.write"` AND `src/plugins/drive/drive.test.ts::"removes delegate to Drive.delete and return its boolean"` AND `src/plugins/drive/drive.test.ts::"writes propagate AbortSignal to Drive.write"` AND `tests/integration/drive-roundtrip-write.test.ts::"resolver.write then resolver.read round-trips on a real Drive"` --- ### Requirement: `drive+mesh://` SHALL support writes/removes locally without triggering mesh re-advertisement The `drive+mesh` plugin's instrumented adapter SHALL delegate `set`/`delete` to the underlying `Drive` exactly as the `drive` scheme does. It SHALL NOT call `mesh.advertise(...)` or any equivalent gossip API; gossip propagation remains the consumer's responsibility. On every successful `drive+mesh://` write, the plugin SHALL emit a span event named `drive_uri.mesh_write_local_only` carrying `{ scheme: "drive+mesh", path }` so operators can audit that the contract holds. #### Scenario: write persists locally without auto-advertise - **WHEN** `resolver.write("drive+mesh://swarmA/clip.mov", bytes)` is called against a mesh-configured `Drive` with a spy transport - **THEN** the call resolves with `void`, the bytes are persisted via `Drive.write`, and the spy transport records zero `advertise(...)` calls #### Scenario: explicit consumer-side advertise still works - **WHEN** the consumer invokes `mesh.advertise(fileId, bitset, totalChunks)` after the write resolves - **THEN** the spy transport records one outbound advertisement #### Scenario: span event marks local-only write - **WHEN** any successful `drive+mesh://` write completes - **THEN** the active span carries an event `drive_uri.mesh_write_local_only` with attributes `{ scheme: "drive+mesh", path }` **Verified by:** `src/plugins/drive-mesh/drive-mesh.test.ts::"writes succeed without triggering mesh.advertise"` AND `src/plugins/drive-mesh/drive-mesh.test.ts::"writes emit drive_uri.mesh_write_local_only span event"` AND `tests/integration/drive-mesh-roundtrip-write.test.ts::"explicit mesh.advertise after write produces an outbound advertisement"` --- ### Requirement: `drive+template://` writes and removes SHALL be permanently rejected with `DRIVE_URI.TEMPLATE_READ_ONLY` The `drive+template` plugin's instrumented adapter SHALL throw a `DriveUriError` with `code === "DRIVE_URI.TEMPLATE_READ_ONLY"` on every `set` and `delete` call, before any delegation to `Drive`. The error SHALL carry `scheme: "drive+template"`, the offending `path`, and the `templateId` that was bound. The rejection SHALL increment `drive_uri.writes_total{scheme:"drive+template", outcome:"error"}` for writes and `drive_uri.deletes_total{scheme:"drive+template", outcome:"error"}` for removes. The error message SHALL state that template-backed drives require authority re-signing not held by the resolver. #### Scenario: write against drive+template:// rejects with TEMPLATE_READ_ONLY - **WHEN** `resolver.write("drive+template://tplA/clip.mov", bytes)` is called - **THEN** the call rejects with `DriveUriError` whose `code === "DRIVE_URI.TEMPLATE_READ_ONLY"`, `scheme === "drive+template"`, `path === "clip.mov"`, and `templateId === "tplA"` #### Scenario: remove against drive+template:// rejects with TEMPLATE_READ_ONLY - **WHEN** `resolver.remove("drive+template://tplA/clip.mov")` is called - **THEN** the call rejects with `DriveUriError` whose `code === "DRIVE_URI.TEMPLATE_READ_ONLY"` #### Scenario: rejection increments error counters - **WHEN** any `drive+template://` write rejection fires - **THEN** `drive_uri.writes_total{scheme:"drive+template", outcome:"error", code:"DRIVE_URI.TEMPLATE_READ_ONLY"}` increments by 1 **Verified by:** `src/plugins/drive-template/drive-template.test.ts::"writes reject with DRIVE_URI.TEMPLATE_READ_ONLY"` AND `src/plugins/drive-template/drive-template.test.ts::"removes reject with DRIVE_URI.TEMPLATE_READ_ONLY"` AND `src/otel/otel.test.ts::"increments writes_total{outcome:error,code:TEMPLATE_READ_ONLY} on template writes"` AND `tests/integration/template-write-rejection.test.ts::"resolver.write and resolver.remove both reject on template-backed drive"` --- ### Requirement: `DRIVE_URI_CODES` SHALL include `TEMPLATE_READ_ONLY` The `DRIVE_URI_CODES` registry produced by `defineCodes("DRIVE_URI", […])` SHALL include `TEMPLATE_READ_ONLY` as a distinct, fully-qualified `DRIVE_URI.TEMPLATE_READ_ONLY` code. The `DriveUriErrorCode` union SHALL include it. The code SHALL be reachable from real call sites (the `drive+template` adapter's `set` and `delete` overrides). #### Scenario: registry exposes TEMPLATE_READ_ONLY - **WHEN** `DRIVE_URI_CODES.TEMPLATE_READ_ONLY` is read - **THEN** the value is the string `"DRIVE_URI.TEMPLATE_READ_ONLY"` #### Scenario: registry remains size-stable elsewhere - **WHEN** the registry's key count is asserted - **THEN** it equals 8, comprising the original 7 plus `TEMPLATE_READ_ONLY` **Verified by:** `src/error-codes/error-codes.test.ts::"includes TEMPLATE_READ_ONLY and totals 8 codes"` --- ### Requirement: `runUriPluginConformance` writes suite SHALL pass for `drive`/`drive+mesh` and reject for `drive+template` The conformance harness re-exported from `@suaveplan/storage-uri` SHALL be re-run against each of the three plugins. The `drive` and `drive+mesh` plugins SHALL pass the full write/read/exists/list/remove cycle. The `drive+template` plugin SHALL continue to fail the write/remove portions of the suite, but with `DRIVE_URI.TEMPLATE_READ_ONLY` as the rejection code rather than `WRITE_UNSUPPORTED`. #### Scenario: conformance writes suite passes for drive - **WHEN** the harness is configured with a real-`Drive`-backed `drive` plugin and asked to exercise the writes suite - **THEN** every write/read round-trip assertion holds and no test is skipped #### Scenario: conformance writes suite passes for drive+mesh - **WHEN** the harness is configured with a mesh-configured `Drive`-backed `drive+mesh` plugin - **THEN** every write/read round-trip holds; no `advertise` is observed on the spy transport during the harness #### Scenario: conformance writes suite rejects drive+template with the new code - **WHEN** the harness is configured with a `drive+template` plugin and exercises any write/remove - **THEN** every such call rejects with `DRIVE_URI.TEMPLATE_READ_ONLY` **Verified by:** `src/conformance/conformance.test.ts::"writes suite passes for drive plugin"` AND `src/conformance/conformance.test.ts::"writes suite passes for drive+mesh plugin"` AND `src/conformance/conformance.test.ts::"writes suite rejects drive+template with TEMPLATE_READ_ONLY"` --- ## MODIFIED Requirements ### Requirement: `DRIVE_URI.WRITE_UNSUPPORTED` SHALL only be raised by `DriveStorageLikeAdapter.clear()` Previously the three plugins rejected every `set` (write) call with `DRIVE_URI.WRITE_UNSUPPORTED`. The code SHALL now be raised by exactly one call site: `DriveStorageLikeAdapter.clear()`, which intentionally refuses to wipe an entire Drive through the URI surface and points the caller at `Drive.delete(path)` (or `resolver.remove(uri)`). The code SHALL remain in `DRIVE_URI_CODES` so consumers that already assert on it for the `clear()` path continue to function unchanged. No other call site in `drive-uri` SHALL raise `WRITE_UNSUPPORTED`. #### Scenario: clear() still rejects with WRITE_UNSUPPORTED - **WHEN** any consumer invokes `adapter.clear()` on a `DriveStorageLikeAdapter` (directly or via an unusual resolver extension) - **THEN** the call rejects with `DriveUriError` whose `code === "DRIVE_URI.WRITE_UNSUPPORTED"` #### Scenario: set on drive:// no longer raises WRITE_UNSUPPORTED - **WHEN** `resolver.write("drive://primary/x", bytes)` is called against a real `Drive` - **THEN** the call resolves with `void` and no `DRIVE_URI.WRITE_UNSUPPORTED` is thrown anywhere in the call chain #### Scenario: set on drive+template:// raises TEMPLATE_READ_ONLY not WRITE_UNSUPPORTED - **WHEN** `resolver.write("drive+template://tplA/x", bytes)` is called - **THEN** the rejection's `code` is `DRIVE_URI.TEMPLATE_READ_ONLY`, never `DRIVE_URI.WRITE_UNSUPPORTED` **Verified by:** `src/adapter/drive-storage-like.test.ts::"clear() rejects with DRIVE_URI.WRITE_UNSUPPORTED"` AND `src/plugins/drive/drive.test.ts::"writes succeed and round-trip via Drive.write"` AND `src/plugins/drive-template/drive-template.test.ts::"writes reject with DRIVE_URI.TEMPLATE_READ_ONLY"`