5.5 KiB
Capability Spec Delta: drive-uri (fix-storage-uri-error-passthrough)
Package: @suaveplan/drive-uri
Status: PROPOSED
Every requirement carries a
**Verified by:**line at authoring time. This delta MODIFIES five scenarios across three requirements fromadd-drive-uri(still inopenspec/changes/, not yet archived). The**Note —** revisited infix-storage-uri-error-passthrough...annotation at the top of the drive-uriadd-drive-uridelta is also retired by this change. (The companion**Note —** buffered-read signal threadingannotation stays, sinceadd-signal-to-storage-likehas not landed.)
MODIFIED Requirements
Requirement: drive:// plugin parses authority as driveId and delegates to Drive.read
The driveUriPlugin(options) factory SHALL return a UriPlugin with scheme === "drive". Its parse SHALL extract the URI authority as driveId and the remainder as a slash-prefix-trimmed key. The returned plugin SHALL forward key to the consumer-supplied Drive via Drive.read(key, { signal }) (or Drive.createReadStream on open()). The plugin SHALL throw DRIVE_URI.DRIVE_ID_MISMATCH when the URI's driveId does not equal the driveId declared in options.
The StorageUriResolver SHALL surface this throw directly per the pass-through rule (see fix-storage-uri-error-passthrough spec delta for storage-uri).
Scenario: URI dispatches to Drive.read
- WHEN
resolver.read("drive://primary/folder/file.bin")is called and the resolver holdsdriveUriPlugin({ drive, driveId: "primary" }) - THEN
drive.read("folder/file.bin", { signal })is invoked exactly once and its return value is the resolver's result
Scenario: driveId mismatch surfaces DRIVE_URI.DRIVE_ID_MISMATCH directly
- WHEN
resolver.read("drive://other/x")is called and the plugin is configured withdriveId: "primary" - THEN the call rejects with
DriveUriErrorhavingcode === "DRIVE_URI.DRIVE_ID_MISMATCH",uri === "drive://other/x",expected === "primary",actual === "other"(the resolver passes theDriveUriErrorthrough unchanged per the storage-uri pass-through rule; noSTORAGE_URI.*envelope is added)
Scenario: build round-trips driveId and key
- WHEN
plugin.build("folder/file.bin", { driveId: "primary" })is called - THEN the returned string equals
"drive://primary/folder/file.bin"
Verified by: src/plugins/drive/drive.test.ts::"dispatches a drive:// URI to Drive.read" AND src/plugins/drive/drive.test.ts::"throws DRIVE_ID_MISMATCH when URI driveId differs from configured driveId" AND src/plugins/drive/drive.test.ts::"build round-trips driveId and key into a drive:// URI"
Requirement: Template fetch and hydration failures map to distinct DRIVE_URI codes
When options.templateProvider.fetchTemplate rejects, the plugin SHALL re-wrap the rejection as DRIVE_URI.TEMPLATE_NOT_AVAILABLE with the original error preserved on cause. When Drive.hydrateFrom rejects (any DTP_* code), the plugin SHALL re-wrap the rejection as DRIVE_URI.TEMPLATE_INVALID with the original on cause. The two failures MUST NOT be conflated — operator response differs (network/availability vs. integrity).
The StorageUriResolver SHALL surface both DriveUriErrors directly per the pass-through rule.
Scenario: fetchTemplate rejection becomes TEMPLATE_NOT_AVAILABLE
- WHEN
resolver.read("drive+template://templA/x")is called andtemplateProvider.fetchTemplaterejects withnew Error("404") - THEN the call rejects with
DriveUriErrorhavingcode === "DRIVE_URI.TEMPLATE_NOT_AVAILABLE"ANDcause.message === "404"
Scenario: hydrateFrom rejection becomes TEMPLATE_INVALID
- WHEN
resolver.read("drive+template://templA/x")is called anddrive.hydrateFromrejects with aSuaveplanErrorcarryingcode === "DTP.TEMPLATE_EXPIRED" - THEN the call rejects with
DriveUriErrorhavingcode === "DRIVE_URI.TEMPLATE_INVALID"ANDcause.code === "DTP.TEMPLATE_EXPIRED"
Verified by: src/plugins/drive-template/drive-template.test.ts::"wraps fetchTemplate rejection as TEMPLATE_NOT_AVAILABLE" AND src/plugins/drive-template/drive-template.test.ts::"wraps hydrateFrom rejection as TEMPLATE_INVALID"
Requirement: Writes via drive:// schemes are rejected
The three plugins SHALL reject set (write) calls with DRIVE_URI.WRITE_UNSUPPORTED. The rejection SHALL carry the original URI and scheme on the error so operators can see misuse rate via drive_uri.writes_total{scheme, outcome: "error"}.
The StorageUriResolver SHALL surface this throw directly per the pass-through rule — err.code === "DRIVE_URI.WRITE_UNSUPPORTED" reaches the caller without a STORAGE_URI.WRITE_UNSUPPORTED envelope.
Scenario: write against drive:// rejects with DRIVE_URI.WRITE_UNSUPPORTED
- WHEN
resolver.write("drive://primary/x", new Uint8Array([1, 2, 3]))is called - THEN the call rejects with
DriveUriErrorhavingcode === "DRIVE_URI.WRITE_UNSUPPORTED",uri === "drive://primary/x",scheme === "drive"
Scenario: writes_total counter increments on the rejection
- WHEN
resolver.write("drive+mesh://swarmA/x", bytes)is called - THEN
drive_uri.writes_total{scheme: "drive+mesh", outcome: "error"}is incremented by 1
Verified by: src/plugins/drive/drive.test.ts::"rejects writes with DRIVE_URI.WRITE_UNSUPPORTED" AND src/otel/otel.test.ts::"increments writes_total on rejected writes"