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

382 lines
29 KiB
Markdown

<!-- markdownlint-disable MD024 -->
# 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: `AbortSignal` SHALL propagate through every buffered op on every scheme
`DriveStorageLikeAdapter` and `InstrumentedDriveAdapter` SHALL accept and forward `AbortSignal` on every buffered operation: `get`, `set`, `delete`, `exists`, `stat`, `list`, plus the streaming `createReadStream` and `createWriteStream`. A pre-aborted signal SHALL short-circuit any op to `DriveUriError(DRIVE_URI.ABORTED, …, { scheme, path: key })` BEFORE any `Drive` call. The signal forwarded to `Drive.{read,write,delete,stat,list}` SHALL be the same reference the caller supplied.
#### Scenario: pre-aborted signal short-circuits get without invoking Drive.read
- **WHEN** `adapter.get("x", AbortSignal.abort())` is called against any of the three plugins
- **THEN** the call rejects with `DriveUriError` whose `code === "DRIVE_URI.ABORTED"` AND the underlying `Drive.read` is NOT invoked
#### Scenario: live signal forwarded to Drive.write
- **WHEN** `adapter.set("x", bytes, liveSignal)` is called against the `drive://` plugin
- **THEN** `Drive.write` is invoked with `options.signal === liveSignal`
#### Scenario: signal threads through stat, list, exists, delete
- **WHEN** any of `adapter.stat`, `adapter.list`, `adapter.exists`, `adapter.delete` is invoked with a live signal
- **THEN** the corresponding `Drive.{stat,list,delete}` (or, for `exists`, the underlying probe) receives the same signal reference
**Verified by:** `src/adapter/drive-storage-like.test.ts::"propagates AbortSignal through every buffered op"` AND `src/adapter/drive-storage-like.test.ts::"short-circuits with DRIVE_URI.ABORTED on pre-aborted signal"` AND `src/plugins/drive/drive.streams.test.ts::"forwards live AbortSignal unchanged on every op"`
---
### Requirement: `drive://` SHALL support writes, removes, and write-streams via the resolver surface
The `drive` plugin's instrumented adapter SHALL delegate `set(key, value, signal?)` to `Drive.write(key, data, { signal })`, `delete(key, signal?)` to `Drive.delete(key, signal)`, and `createWriteStream(key, body, signal?)` to `Drive.createWriteStream(key, signal)` consuming `body` as a `ReadableStream<Uint8Array>`. Successful writes increment `drive_uri.writes_total{scheme:"drive", outcome:"success"}`; successful removes increment `drive_uri.deletes_total{scheme:"drive", outcome:"success"}`. The `AbortSignal` passed via `resolver.write` / `resolver.remove` SHALL be threaded through to the underlying `Drive` call.
#### 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` 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: write-stream pipes ReadableStream into Drive.createWriteStream
- **WHEN** `resolver.write("drive://primary/clip.mov", readableStreamOfChunks)` is called where the body is a `ReadableStream`
- **THEN** `Drive.createWriteStream` is invoked exactly once AND the assembled bytes equal the concatenation of the streamed chunks
**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.streams.test.ts::"createWriteStream pipes ReadableStream into Drive.createWriteStream"` 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 with opt-in advertise via `?advertise=true`
The `drive+mesh` plugin's instrumented adapter SHALL delegate `set`/`delete`/`createWriteStream` to the underlying `Drive` exactly as the `drive` scheme does. By default it SHALL NOT call any mesh advertise API; on every successful default-mode write the plugin SHALL emit a span event `drive_uri.mesh_write_local_only` carrying `{ scheme: "drive+mesh", path }`. When the URI carries `?advertise=true` AND `options.advertise: MeshAdvertiseHook` is wired, the plugin SHALL invoke `options.advertise.advertise(fileId, bitset, totalChunks, signal)` AFTER the local write resolves; hook rejection SHALL be re-wrapped as `DriveUriError(DRIVE_URI.MESH_PROPAGATION_TIMEOUT, …, { cause })`. When `?advertise=true` is present but `options.advertise` is absent, `parse` SHALL throw `DRIVE_URI.CAPABILITY_MISSING` with `reason: "advertise"` synchronously.
#### Scenario: default write persists locally without advertise
- **WHEN** `resolver.write("drive+mesh://swarmA/clip.mov", bytes)` is called against a mesh-configured `Drive` with a spy `MeshAdvertiseHook`
- **THEN** the call resolves with `void`, the bytes are persisted, and the spy records zero `advertise(...)` calls AND the span carries a `drive_uri.mesh_write_local_only` event
#### Scenario: `?advertise=true` invokes the hook exactly once
- **WHEN** `resolver.write("drive+mesh://swarmA/clip.mov?advertise=true", bytes)` is called
- **THEN** the spy records exactly one `advertise(fileId, bitset, totalChunks, signal)` call AFTER `Drive.write` resolves AND a `drive_uri:mesh_advertised` event fires on the `Drive.events` bus
#### Scenario: advertise rejection becomes MESH_PROPAGATION_TIMEOUT
- **WHEN** the hook's `advertise` rejects with `new Error("transport down")`
- **THEN** `resolver.write(...)` rejects with `DriveUriError` whose `code === "DRIVE_URI.MESH_PROPAGATION_TIMEOUT"` AND `cause.message === "transport down"`
#### Scenario: `?advertise=true` without a hook fails fast at construction
- **WHEN** the plugin is constructed without `options.advertise` AND `resolver.write("drive+mesh://swarmA/x?advertise=true", bytes)` is called
- **THEN** the `parse` step throws `DriveUriError` whose `code === "DRIVE_URI.CAPABILITY_MISSING"` AND `reason === "advertise"`
**Verified by:** `src/plugins/drive-mesh/drive-mesh.test.ts::"default write persists locally without advertise"` AND `src/plugins/drive-mesh/drive-mesh.test.ts::"?advertise=true invokes MeshAdvertiseHook exactly once"` AND `src/plugins/drive-mesh/drive-mesh.test.ts::"advertise rejection becomes MESH_PROPAGATION_TIMEOUT"` AND `src/plugins/drive-mesh/drive-mesh.test.ts::"?advertise=true without hook throws CAPABILITY_MISSING"` AND `tests/integration/drive-mesh-roundtrip-write.test.ts::"opt-in advertise produces a single outbound advertisement on a real Drive"`
---
### Requirement: `drive+template://` writes, removes, and write-streams SHALL be permanently rejected with `DRIVE_URI.TEMPLATE_READ_ONLY`
The `drive+template` plugin's instrumented adapter SHALL throw `DriveUriError(DRIVE_URI.TEMPLATE_READ_ONLY, …, { scheme: "drive+template", path: key, templateId })` on every `set`, `delete`, and `createWriteStream` call, before any delegation. Rejections SHALL increment `drive_uri.writes_total{scheme:"drive+template", outcome:"error"}` and `drive_uri.deletes_total{scheme:"drive+template", outcome:"error"}`. The error message SHALL state that template-backed drives require authority re-signing the URI resolver never holds.
#### Scenario: write 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"`, `templateId === "tplA"`
#### Scenario: remove 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: createWriteStream rejects with TEMPLATE_READ_ONLY
- **WHEN** the adapter's `createWriteStream("clip.mov", body)` is called
- **THEN** the call rejects with `DriveUriError` whose `code === "DRIVE_URI.TEMPLATE_READ_ONLY"` AND `Drive.createWriteStream` is NOT invoked
**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/plugins/drive-template/drive-template.test.ts::"createWriteStream rejects with DRIVE_URI.TEMPLATE_READ_ONLY"` AND `tests/integration/template-write-rejection.test.ts::"resolver.write and resolver.remove both reject on template-backed drive"`
---
### Requirement: Range reads `{ offset, length }` SHALL be supported on every `drive*://` scheme
The adapter's `createReadStream(key, options?: { offset?: number; length?: number; signal?: AbortSignal })` SHALL forward the range bag to `Drive.createReadStream(key, options)`. Every plugin's adapter SHALL advertise `capabilities.nativeRange === true` so `StorageUriResolver.open(uri, { offset, length, signal })` issues exactly one range-aware `createReadStream` call (no buffer-and-slice fallback). Over `drive+mesh://`, the chunks-plugin middleware downstream of `Drive` SHALL use the range to request only intersecting chunks via `ChunkRequest.specific` (when span ≤ 64) or `bitset` (span > 64). On invalid range, `Drive.createReadStream` throws `DRIVE.RANGE_INVALID`; the adapter SHALL re-throw the original error unchanged (it is a `SuaveplanError` and reaches the caller intact under the resolver pass-through rule).
#### Scenario: range slice is emitted exactly
- **WHEN** `resolver.open("drive://primary/file.bin", { offset: 1024, length: 4096, signal })` is called on a 200 KiB file
- **THEN** the returned stream emits exactly bytes `[1024, 5120)`
#### Scenario: zero-length range yields an immediately-closed stream
- **WHEN** `resolver.open("drive://primary/file.bin", { offset: 12345, length: 0 })` is called
- **THEN** the returned stream closes with zero enqueued bytes
#### Scenario: cross-boundary range still emits exactly
- **WHEN** the chunks-plugin chunkSize is 65536 and `resolver.open("drive+mesh://swarmA/clip.mov", { offset: 60_000, length: 10_000 })` is called
- **THEN** the returned stream emits exactly bytes `[60_000, 70_000)` AND `drive_uri.stream_chunks_fetched` records `2`
#### Scenario: invalid range surfaces DRIVE.RANGE_INVALID via pass-through
- **WHEN** `resolver.open("drive://primary/file.bin", { offset: -1 })` is called
- **THEN** the call rejects with a `SuaveplanError` whose `code === "DRIVE.RANGE_INVALID"`
#### Scenario: out-of-bounds range surfaces DRIVE.RANGE_OUT_OF_BOUNDS
- **WHEN** the file is 1024 bytes and `resolver.open("drive://primary/file.bin", { offset: 2048 })` is called
- **THEN** the call rejects with a `SuaveplanError` whose `code === "DRIVE.RANGE_OUT_OF_BOUNDS"`
**Verified by:** `src/adapter/drive-storage-like.test.ts::"createReadStream forwards { offset, length, signal } to Drive"` AND `src/plugins/drive/drive.streams.test.ts::"range slice is emitted exactly through plugin"` AND `src/plugins/drive/drive.streams.test.ts::"zero-length range closes the stream immediately"` AND `src/otel/otel.test.ts::"records stream_chunks_fetched with the in-range chunk count"` AND `tests/integration/drive-range-roundtrip.test.ts::"range read returns exactly [60_000, 70_000) on a real 200 KiB Drive file"`
---
### Requirement: `stat` SHALL return `StatResult` populated from `Drive.stat`
Every plugin's adapter SHALL implement `getMetadata(key, signal?): Promise<StatResult | undefined>` (per `StreamingStorageExtensions`) so `StorageUriResolver.stat(uri)` returns `StatResult { size, lastModified?, etag?, contentType? }`. The implementation SHALL read `Drive.stat(key, signal)` and map `DriveStats.size` → `StatResult.size`, `DriveStats.modifiedAt` (epoch ms) → `StatResult.lastModified` (`new Date(modifiedAt)`), and `DriveStats.checksum` → `StatResult.etag` when present. When `Drive.stat` returns `null`, the adapter SHALL resolve `undefined`. When `Drive.stat` rejects with a non-not-found cause, the adapter SHALL throw `DriveUriError(DRIVE_URI.STAT_UNAVAILABLE, …, { cause })`.
#### Scenario: stat returns StatResult for an existing key
- **WHEN** `resolver.stat("drive://primary/file.bin")` is called on a key the Drive reports as `{ size: 1024, modifiedAt: 1700000000000, checksum: "abc" }`
- **THEN** the call resolves with `{ size: 1024, lastModified: new Date(1700000000000), etag: "abc" }`
#### Scenario: stat returns undefined for a missing key
- **WHEN** `resolver.stat("drive://primary/missing")` is called and `Drive.stat` returns `null`
- **THEN** the call resolves with `undefined`
#### Scenario: stat failure becomes DRIVE_URI.STAT_UNAVAILABLE
- **WHEN** `Drive.stat` rejects with a non-not-found `SuaveplanError`
- **THEN** the call rejects with `DriveUriError` whose `code === "DRIVE_URI.STAT_UNAVAILABLE"` AND `cause` is the original error
**Verified by:** `src/adapter/drive-storage-like.test.ts::"getMetadata maps Drive.stat to StatResult"` AND `src/adapter/drive-storage-like.test.ts::"getMetadata returns undefined when Drive.stat is null"` AND `src/adapter/drive-storage-like.test.ts::"getMetadata wraps non-not-found Drive.stat failures as STAT_UNAVAILABLE"` AND `tests/integration/drive-stat-list-exists.test.ts::"resolver.stat returns populated StatResult on a real Drive"`
---
### Requirement: `exists` SHALL use a cheap presence path
Every plugin's adapter `exists(key, signal?)` SHALL first try `Drive.getPresence(key)`; when it returns `chunksPresent > 0`, the result is `true` without a `Drive.stat` round-trip. When `getPresence` reports `chunksPresent === 0 && chunksTotal === 0` (the file is not in the location index), the adapter SHALL fall back to `Drive.stat(key, signal) !== null`. The signal SHALL be honoured throughout.
#### Scenario: presence > 0 short-circuits to true
- **WHEN** `Drive.getPresence(key)` reports `{ chunksPresent: 3, chunksTotal: 5 }` and `resolver.exists("drive://primary/key")` is called
- **THEN** the call resolves `true` AND `Drive.stat` is NOT invoked
#### Scenario: presence empty falls back to stat
- **WHEN** `Drive.getPresence(key)` reports `{ chunksPresent: 0, chunksTotal: 0 }` and `Drive.stat(key)` returns a non-null result
- **THEN** the call resolves `true` AND `Drive.stat` is invoked exactly once
#### Scenario: stat null returns false
- **WHEN** presence is empty AND `Drive.stat(key)` returns `null`
- **THEN** the call resolves `false`
**Verified by:** `src/adapter/drive-storage-like.test.ts::"exists short-circuits true on presence > 0"` AND `src/adapter/drive-storage-like.test.ts::"exists falls back to stat when presence is empty"` AND `src/adapter/drive-storage-like.test.ts::"exists returns false when stat is null"`
---
### Requirement: `list` SHALL enumerate via `Drive.list` and re-serialise via `UriPlugin.build`
Every plugin's adapter `list({ prefix?, limit?, cursor?, signal? })` SHALL forward to `Drive.list(prefix, { signal, limit, cursor })` and return `{ keys, total, hasMore, continuationToken? }`. The plugin's `UriPlugin.build(key, meta)` SHALL re-serialise every returned key back into a fully-qualified URI that round-trips through `parse`. When the bound `Drive`'s default storage lacks `list`, the adapter SHALL throw `DriveUriError(DRIVE_URI.LIST_UNSUPPORTED, …, { scheme })`.
#### Scenario: list returns prefix-matching keys
- **WHEN** `resolver.list("drive://primary/folder/")` is called against a Drive with files `folder/a`, `folder/b`, `other/c`
- **THEN** the call resolves with `{ keys: ["folder/a", "folder/b"], hasMore: false, … }` (or equivalent re-serialised URIs per the resolver's contract)
#### Scenario: each listed key re-serialises through build
- **WHEN** the resolver re-serialises each key via `plugin.build(key, { driveId: "primary" })`
- **THEN** each result is a `drive://primary/<key>` URI that round-trips through `plugin.parse`
#### Scenario: list propagates AbortSignal
- **WHEN** `resolver.list("drive://primary/", { limit: 100 }, signal)` is called
- **THEN** `Drive.list` receives `options.signal === signal`
#### Scenario: list on a storage without list throws LIST_UNSUPPORTED
- **WHEN** the underlying storage lacks `list` AND `resolver.list("drive://primary/")` is called
- **THEN** the call rejects with `DriveUriError` whose `code === "DRIVE_URI.LIST_UNSUPPORTED"`
**Verified by:** `src/adapter/drive-storage-like.test.ts::"list forwards prefix, limit, cursor, signal to Drive.list"` AND `src/adapter/drive-storage-like.test.ts::"list throws LIST_UNSUPPORTED when storage lacks list"` AND `tests/integration/drive-stat-list-exists.test.ts::"resolver.list returns URIs that round-trip through resolver.read"`
---
### Requirement: Per-scheme query string options SHALL be parsed with a strict allow-list
Every plugin's `parse` SHALL parse `parts.query` via `parseQuery(query, scheme)`. The recognised key set per scheme:
| Scheme | Allowed keys |
|---------------------|----------------------------------------------------|
| `drive://` | `signal-timeout-ms` |
| `drive+mesh://` | `signal-timeout-ms`, `advertise` |
| `drive+template://` | `signal-timeout-ms`, `nonce` |
Unknown keys SHALL throw `DriveUriError(DRIVE_URI.INVALID_QUERY, …, { scheme, key, value })`. Malformed values (`?advertise=maybe`, `?signal-timeout-ms=-1`, `?signal-timeout-ms=NaN`) SHALL throw `DRIVE_URI.INVALID_QUERY` with the offending value. `?signal-timeout-ms=<int>` SHALL be honoured via `AbortSignal.timeout(ms)` linked to the caller's signal; elapse SHALL raise `DRIVE_URI.ABORTED` with `reason: "signal-timeout-ms"`. `?nonce=<hex>` on `drive+template://` SHALL be forwarded to `templateProvider.fetchTemplate(templateId, { nonce, signal })`.
#### Scenario: unknown query key throws INVALID_QUERY
- **WHEN** `resolver.read("drive://primary/x?foo=bar")` is called
- **THEN** the call rejects with `DriveUriError` whose `code === "DRIVE_URI.INVALID_QUERY"` AND `key === "foo"` AND `value === "bar"`
#### Scenario: malformed advertise value throws INVALID_QUERY
- **WHEN** `resolver.read("drive+mesh://swarmA/x?advertise=maybe")` is called
- **THEN** the call rejects with `DriveUriError` whose `code === "DRIVE_URI.INVALID_QUERY"` AND `key === "advertise"`
#### Scenario: signal-timeout-ms enforces the upper bound
- **WHEN** `resolver.read("drive://primary/slow?signal-timeout-ms=10")` is called against a `Drive.read` that never resolves
- **THEN** the call rejects with `DriveUriError` whose `code === "DRIVE_URI.ABORTED"` AND `reason === "signal-timeout-ms"` after ~10 ms
#### Scenario: nonce forwarded to templateProvider
- **WHEN** `resolver.read("drive+template://tplA/x?nonce=deadbeef")` is called
- **THEN** `templateProvider.fetchTemplate` is invoked exactly once with `templateId === "tplA"` and `options.nonce === "deadbeef"`
**Verified by:** `src/query/parse-query.test.ts::"rejects unknown query keys per scheme"` AND `src/query/parse-query.test.ts::"rejects malformed advertise and signal-timeout-ms values"` AND `src/plugins/drive/drive.test.ts::"signal-timeout-ms enforces an upper bound and surfaces ABORTED"` AND `src/plugins/drive-template/drive-template.test.ts::"forwards nonce query param to templateProvider.fetchTemplate"`
---
### Requirement: `DRIVE_URI_CODES` SHALL contain 14 distinct, frozen, reachable codes
The `DRIVE_URI_CODES` registry produced by `defineCodes("DRIVE_URI", [...] as const)` SHALL contain exactly: `INVALID_URI`, `DRIVE_ID_MISMATCH`, `TEMPLATE_NOT_AVAILABLE`, `TEMPLATE_INVALID`, `TEMPLATE_READ_ONLY`, `WRITE_UNSUPPORTED`, `CAPABILITY_MISSING`, `ABORTED`, `RANGE_INVALID`, `RANGE_OUT_OF_BOUNDS`, `MESH_PROPAGATION_TIMEOUT`, `STAT_UNAVAILABLE`, `LIST_UNSUPPORTED`, `INVALID_QUERY`. `Object.isFrozen(DRIVE_URI_CODES)` MUST remain `true`. Every code value MUST start with `DRIVE_URI.`. Every code MUST be reachable from at least one real call site in `src/` and MUST be exercised by at least one test (per CLAUDE.md §2c).
#### Scenario: registry contains the 14 expected codes
- **WHEN** `Object.keys(DRIVE_URI_CODES).length` is asserted
- **THEN** it equals `14` AND every value starts with `"DRIVE_URI."`
#### Scenario: every code is reachable from a real call site
- **WHEN** the registry-reachability test scans `src/` for each code's qualified string AND walks every test for an `expect(...).code === "DRIVE_URI.<X>"` assertion
- **THEN** every code maps to ≥1 source occurrence AND ≥1 test assertion
#### Scenario: WRITE_UNSUPPORTED is raised only by clear()
- **WHEN** the source grep restricts to `WRITE_UNSUPPORTED` usages
- **THEN** the sole non-registry occurrence is in `src/adapter/drive-storage-like.ts` inside `clear()`
**Verified by:** `src/error-codes/error-codes.test.ts::"registry contains exactly 14 codes, all DRIVE_URI.-prefixed and frozen"` AND `src/error-codes/error-codes.test.ts::"every DRIVE_URI.* code is reachable from a real call site"` AND `src/error-codes/error-codes.test.ts::"WRITE_UNSUPPORTED is raised only by DriveStorageLikeAdapter.clear"`
---
### Requirement: EventBus emission SHALL fire on every write and delete (success and failure)
When the wrapped `Drive.events: EventBusLike | undefined` is present, `InstrumentedDriveAdapter` SHALL emit `drive_uri:write` on every `set` outcome and `drive_uri:delete` on every `delete` outcome. Payload: `{ scheme, key, uri (redacted), outcome: "success" | "error", code?, durationMs, fileId?, range? }`. On successful `drive+mesh://` opt-in advertise, the adapter SHALL emit `drive_uri:mesh_advertised` with `{ scheme: "drive+mesh", fileId, totalChunks, durationMs }`. Absence of `Drive.events` is a silent no-op.
#### Scenario: write emits drive_uri:write on success
- **WHEN** `resolver.write("drive://primary/x", bytes)` succeeds against a `Drive` with a real `EventBusLike`
- **THEN** the bus receives one `drive_uri:write` event with `outcome === "success"`, `scheme === "drive"`, `key === "x"`, `uri === "drive://primary/x"` (no query), `durationMs` ≥ 0
#### Scenario: write emits drive_uri:write on failure
- **WHEN** `resolver.write("drive+template://tplA/x", bytes)` rejects
- **THEN** the bus receives one `drive_uri:write` event with `outcome === "error"` AND `code === "DRIVE_URI.TEMPLATE_READ_ONLY"`
#### Scenario: delete emits drive_uri:delete
- **WHEN** `resolver.remove("drive://primary/x")` is called against a `Drive` with a bus
- **THEN** the bus receives one `drive_uri:delete` event with `outcome === "success"`
#### Scenario: missing events bus is a no-op
- **WHEN** the wrapped `Drive` has `events === undefined` and any op runs
- **THEN** no event is emitted and the op succeeds normally
**Verified by:** `src/events/events.test.ts::"emits drive_uri:write on success"` AND `src/events/events.test.ts::"emits drive_uri:write on failure with code"` AND `src/events/events.test.ts::"emits drive_uri:delete on success"` AND `src/events/events.test.ts::"is a no-op when Drive.events is undefined"`
---
### Requirement: OpenTelemetry surface SHALL cover every op with backend identification, range, and redaction
Every plugin op SHALL emit a span on the `@suaveplan/drive-uri` tracer and record `drive_uri.op_duration_ms{op, scheme, outcome}`. Errors SHALL increment `drive_uri.errors_total{scheme, code}`. The `drive.uri` span attribute SHALL exclude any URI query string AND any URI fragment. On `createReadStream` calls with a range, the span SHALL carry `drive.uri.range = "{offset}-{end}"` AND `drive_uri.stream_chunks_fetched{scheme}` SHALL record the chunk count actually pulled. On `drive+mesh://` writes, the span SHALL carry `drive.uri.has_advertise = "true" | "false"` reflecting the `?advertise` opt-in. The `drive+template` plugin SHALL increment `drive_uri.template_hydrations_total{outcome}` exactly once per first-use template.
#### Scenario: range attribute set iff range is supplied
- **WHEN** `resolver.open("drive://primary/x", { offset: 100, length: 50 })` succeeds AND a sibling `resolver.open("drive://primary/x")` call without range succeeds
- **THEN** the first span carries `drive.uri.range === "100-150"` AND the second span has no `drive.uri.range` attribute
#### Scenario: stream_chunks_fetched records pulled count
- **WHEN** a range read pulls 2 chunks
- **THEN** `drive_uri.stream_chunks_fetched{scheme}` records `2`
#### Scenario: query and fragment stripped from span attribute
- **WHEN** `resolver.read("drive+mesh://swarmA/path?advertise=true#frag")` is called
- **THEN** the emitted span's `drive.uri` attribute equals `"drive+mesh://swarmA/path"` (no `?`, no `#`)
#### Scenario: has_advertise reflects opt-in
- **WHEN** `resolver.write("drive+mesh://swarmA/x?advertise=true", bytes)` succeeds
- **THEN** the span carries `drive.uri.has_advertise === "true"`
**Verified by:** `src/otel/otel.test.ts::"sets drive.uri.range only when range is supplied"` AND `src/otel/otel.test.ts::"records drive_uri.stream_chunks_fetched per range read"` AND `src/otel/otel.test.ts::"strips query and fragment from drive.uri span attribute"` AND `src/otel/otel.test.ts::"sets drive.uri.has_advertise on mesh writes"`
---
### Requirement: `runUriPluginConformance` SHALL pass the full op matrix for all three plugins
The conformance harness re-exported from `@suaveplan/storage-uri` SHALL be re-run against each of the three plugins covering `read`, `write`, `delete`, `stat`, `list`, `exists`, range read, and parse/build round-trips. Expected outcomes:
- `drive://` and `drive+mesh://` complete the full cycle.
- `drive+template://` passes read/stat/list/exists/range; `set`/`delete`/`createWriteStream` reject with `DRIVE_URI.TEMPLATE_READ_ONLY` (not `WRITE_UNSUPPORTED`).
- The mesh-advertise spy hook records zero calls when `?advertise` is omitted, exactly one call when `?advertise=true` is supplied.
#### Scenario: drive plugin full matrix passes
- **WHEN** `runUriPluginConformance(driveUriPlugin({ drive, driveId: "primary" }), driveFixtures)` is invoked with the full matrix
- **THEN** every assertion (read/write/delete/stat/list/exists/range/round-trip) passes without throwing
#### Scenario: drive+mesh plugin full matrix passes with advertise opt-in behaviour
- **WHEN** the harness exercises the mesh plugin with both `?advertise`-absent and `?advertise=true` writes
- **THEN** the absent-case advertise count is `0`, the opt-in case advertise count is `1`, and all read/write/delete/stat/list/exists assertions pass
#### Scenario: drive+template plugin rejects writes with TEMPLATE_READ_ONLY
- **WHEN** the harness exercises the template plugin's write/delete/writeStream cases
- **THEN** every such call rejects with `DRIVE_URI.TEMPLATE_READ_ONLY` (never `WRITE_UNSUPPORTED`)
**Verified by:** `src/conformance/conformance.test.ts::"drive plugin satisfies the full op matrix"` AND `src/conformance/conformance.test.ts::"drive+mesh plugin satisfies the full op matrix with advertise opt-in"` AND `src/conformance/conformance.test.ts::"drive+template plugin rejects writes 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` 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 `clear()` continue to function. 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`
- **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"`
<!-- markdownlint-enable MD024 -->