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

14 KiB

Tasks — complete-drive-uri

Every checkbox MUST reflect work actually done in this change. Walk every ### Requirement and #### Scenario in specs/drive-uri/spec.md AND specs/drive/spec.md before declaring done (§12a).

0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Spec authoring

  • 1.1 Read openspec/AGENTS.md §0c, §2b, §2c, §6a, §7, §11, §13, §13a, §14
  • 1.2 Read openspec/archive/2026-05-16-add-drive-uri/proposal.md, _superseded-narrow-deferrals-2026-05-17/{add-drive-uri-writes,add-drive-range-reads}/{proposal,design}.md
  • 1.3 Read openspec/specs/drive-uri/spec.md and openspec/specs/drive/spec.md
  • 1.4 Confirm Drive.{read,write,delete,stat,list,createReadStream,createWriteStream,hydrateFrom,getKeyStatus,getPresence} surface; DriveStorage.capabilities flag pattern; StreamingStorageExtensions shape; MeshDrive.{advertise,unadvertise} shape; ChunkRequest union; parseUri query/fragment shape
  • 1.5 Draft proposal.md + design.md + tasks.md + spec deltas
  • 1.6 Build the numbered Requirement / Scenario implementation checklist (per §0c step 6)
  • 1.7 openspec validate complete-drive-uri --strict exits 0

2. @suaveplan/drive — range overload + new codes

  • 2.1 src/types/drive.types.ts — add RangeReadOptions { offset?, length?, signal? }; extend DriveStorage with capabilities.nativeRange?: boolean and an extended createReadStream?(path, options?: { offset?, length?, signal? }) signature
  • 2.2 src/error-codes.ts — add RANGE_INVALID, RANGE_OUT_OF_BOUNDS to DRIVE_CODES (registry grows 11 → 13)
  • 2.3 src/error-codes.spec-conformance.test.ts — extend frozen-registry and every-code-starts-with-DRIVE. checks
  • 2.4 src/file-operations/streams.range.ts — pure slicing transform sliceStream(stream, offset, length) honouring signal
  • 2.5 src/file-operations/streams.range.md — sibling doc
  • 2.6 src/file-operations/streams.ts — overload createReadStream(storage, path, signal?) AND createReadStream(storage, path, options: RangeReadOptions); runtime instanceof AbortSignal discriminator; synchronous validation → DRIVE.RANGE_INVALID; nativeRange → forward { offset, length }; otherwise wrap in sliceStream
  • 2.7 src/file-operations/streams.md — update docs
  • 2.8 src/file-operations/streams.range.test.ts — boundary table: fully inside one chunk, spans boundary, aligned multi-chunk, tail-to-EOF, zero-length, whole-file, abort mid-stream
  • 2.9 src/drive/drive.ts — createReadStream overload signatures forwarded to streams.ts; middleware context carries range?: { offset, length? }
  • 2.10 src/drive/drive.test.ts — overload-compat (bare signal still works), options form, DRIVE.RANGE_INVALID synchronous throw, DRIVE.RANGE_OUT_OF_BOUNDS (size-known) synchronous throw

3. @suaveplan/drive-uri — error registry + types

  • 3.1 src/error-codes/error-codes.ts — extend DRIVE_URI_CODES to 14 codes: TEMPLATE_READ_ONLY, RANGE_INVALID, RANGE_OUT_OF_BOUNDS, MESH_PROPAGATION_TIMEOUT, STAT_UNAVAILABLE, LIST_UNSUPPORTED, INVALID_QUERY added to the existing 7
  • 3.2 src/error-codes/error-codes.ts — extend DriveUriErrorOptions with range?: { offset: number; length?: number }, fileId?: string, key?: string, value?: string
  • 3.3 src/error-codes/error-codes.md — describe every code, its call site, and the narrowed role of WRITE_UNSUPPORTED
  • 3.4 src/error-codes/error-codes.test.ts — exhaustive registry shape (14 codes, every code starts with DRIVE_URI., Object.isFrozen holds), DriveUriError discriminants all surface, cause preserved across re-wraps
  • 3.5 src/types/plugin-options.types.ts — add MeshAdvertiseHook { advertise(fileId, bitset, totalChunks, signal?), unadvertise(fileId, signal?) }; widen TemplateProvider.fetchTemplate(templateId, options?: { nonce?, signal? }) (preserve back-compat by making the second arg optional); add ?advertise?: MeshAdvertiseHook to DriveMeshUriPluginOptions
  • 3.6 src/types/plugin-options.types.md — update

4. @suaveplan/drive-uri — query parsing

  • 4.1 src/query/parse-query.ts — parseQuery(query: string | undefined, scheme: string): ParsedQuery returning { signalTimeoutMs?, advertise?, nonce? }; unknown keys throw DRIVE_URI.INVALID_QUERY
  • 4.2 src/query/parse-query.md — sibling doc
  • 4.3 src/query/parse-query.test.ts — per-scheme allow-list, unknown keys, malformed values (?advertise=maybe, ?signal-timeout-ms=-1), empty/missing query

5. @suaveplan/drive-uri — events

  • 5.1 src/events/events.ts — typed topic constants DRIVE_URI_TOPICS = { write: "drive_uri:write", delete: "drive_uri:delete", meshAdvertised: "drive_uri:mesh_advertised" } as const; emit(events, topic, payload) no-op when events is undefined
  • 5.2 src/events/events.md — sibling doc
  • 5.3 src/events/events.test.ts — emission against a real EventBusLike fixture; no-op when bus absent

6. @suaveplan/drive-uri — adapter widening

  • 6.1 src/adapter/drive-storage-like.ts — widen get/set/delete/exists/stat/list to accept and forward AbortSignal; add getMetadata(key, signal?): Promise<StatResult | undefined> mapping Drive.stat → StatResult; add createWriteStream(key, body, signal?): Promise<void> consuming ReadableStream<Uint8Array> and piping into Drive.createWriteStream; widen createReadStream to accept { offset?, length?, signal? }; advertise capabilities = { nativeRange: true, nativeStreams: true }
  • 6.2 src/adapter/drive-storage-like.md — update for every new method and signature
  • 6.3 src/adapter/drive-storage-like.test.ts — get/set/delete/exists/stat/list all propagate signal; pre-aborted signal short-circuits; getMetadata returns StatResult shape; createWriteStream round-trips; createReadStream({ offset, length }) forwards; clear() still rejects WRITE_UNSUPPORTED; list returns the expected re-serialisable keys

7. @suaveplan/drive-uri — InstrumentedDriveAdapter per-scheme dispatch

  • 7.1 src/plugins/drive/drive.streams.ts — replace unconditional set rejection with per-scheme dispatch: drive/drive+mesh → super.set(key, value, signal); drive+template → throw DRIVE_URI.TEMPLATE_READ_ONLY. Same for delete and createWriteStream
  • 7.2 src/plugins/drive/drive.streams.ts — pre-aborted signal on every op → throw DRIVE_URI.ABORTED
  • 7.3 src/plugins/drive/drive.streams.ts — range pass-through on createReadStream; OTel drive.uri.range = "{offset}-{end}" span attribute when present
  • 7.4 src/plugins/drive/drive.streams.ts — emit drive_uri:write / drive_uri:delete events via events/events.ts on every success and every failure
  • 7.5 src/plugins/drive/drive.streams.ts — narrow WRITE_UNSUPPORTED to DriveStorageLikeAdapter.clear() only (preserve constant for clear call site)
  • 7.6 src/plugins/drive/drive.streams.md — update
  • 7.7 src/plugins/drive/drive.streams.test.ts — pre-aborted abort short-circuits per op; range round-trip; write-stream round-trip; event emission asserted via real bus fixture

8. @suaveplan/drive-uri — drive:// plugin

  • 8.1 src/plugins/drive/drive.ts — invoke parseQuery(parts.query, "drive") and propagate signal-timeout-ms; reject ?advertise and ?nonce with DRIVE_URI.INVALID_QUERY
  • 8.2 src/plugins/drive/drive.test.ts — full op matrix: read/write/delete/stat/list/exists; AbortSignal threading; pre-aborted abort; ?signal-timeout-ms honoured; ?advertise rejected; DRIVE_ID_MISMATCH preserved; INVALID_URI for malformed inputs

9. @suaveplan/drive-uri — drive+mesh:// plugin

  • 9.1 src/plugins/drive-mesh/drive-mesh.ts — invoke parseQuery(parts.query, "drive+mesh"); honour ?advertise=true|false; on true requires options.advertise hook else throws DRIVE_URI.CAPABILITY_MISSING (reason: advertise) synchronously at parse
  • 9.2 src/plugins/drive-mesh/drive-mesh.ts — after a successful write under ?advertise=true, invoke options.advertise.advertise(fileId, bitset, totalChunks, signal); rejection → wrap as DRIVE_URI.MESH_PROPAGATION_TIMEOUT; on success emit drive_uri:mesh_advertised
  • 9.3 src/plugins/drive-mesh/drive-mesh.ts — without ?advertise, emit drive_uri.mesh_write_local_only span event on every successful write
  • 9.4 src/plugins/drive-mesh/drive-mesh.md — update for opt-in flow + redaction policy
  • 9.5 src/plugins/drive-mesh/drive-mesh.test.ts — default = no advertise (spy asserts zero calls + local-only span event); ?advertise=true → exactly one advertise call; MeshAdvertiseHook rejection → MESH_PROPAGATION_TIMEOUT; absence of hook with ?advertise=true → CAPABILITY_MISSING; full op matrix

10. @suaveplan/drive-uri — drive+template:// plugin

  • 10.1 src/plugins/drive-template/drive-template.ts — invoke parseQuery(parts.query, "drive+template"); forward ?nonce=… to templateProvider.fetchTemplate(templateId, { nonce, signal })
  • 10.2 src/plugins/drive-template/drive-template.ts — set/delete/createWriteStream throw DRIVE_URI.TEMPLATE_READ_ONLY synchronously, carrying { scheme, path: key, templateId }
  • 10.3 src/plugins/drive-template/drive-template.md — update
  • 10.4 src/plugins/drive-template/drive-template.test.ts — full read-side op matrix post-hydrate; nonce forwarding; write/delete/writeStream all reject TEMPLATE_READ_ONLY; existing hydration behaviour preserved (memoised, concurrent-share, NOT_AVAILABLE, INVALID)

11. @suaveplan/drive-uri — OTel

  • 11.1 src/otel/otel.ts — add drive_uri.stream_chunks_fetched histogram; setter for drive.uri.range and drive.uri.has_advertise span attributes; extend redactUri to also strip the fragment
  • 11.2 src/otel/otel.md — update
  • 11.3 src/otel/otel.test.ts — every counter/histogram fires per op; range attribute present iff range supplied; advertise attribute on mesh writes; redaction holds for ? and #

12. @suaveplan/drive-uri — conformance

  • 12.1 src/conformance/conformance.test.ts — re-run runUriPluginConformance with full read/write/delete/stat/list/exists/range matrices for all three plugins. Fixtures: 3 valid URIs + 6 invalid + build round-trip + range round-trip per scheme; drive/drive+mesh pass full cycle; drive+template rejects writes with TEMPLATE_READ_ONLY

13. Integration tests (no mocks per CLAUDE.md rule 2)

  • 13.1 tests/integration/drive-roundtrip-write.test.ts — real local-storage Drive; resolver.write then resolver.read; assert equality
  • 13.2 tests/integration/drive-mesh-roundtrip-write.test.ts — mesh-configured Drive with a real advertise hook implementation; default = no advertise; ?advertise=true → exactly one advertise observed
  • 13.3 tests/integration/template-write-rejection.test.ts — wired template-backed Drive; resolver.write and resolver.remove both reject TEMPLATE_READ_ONLY
  • 13.4 tests/integration/drive-range-roundtrip.test.ts — write 200 KiB file via local Drive; resolver.open("drive://…", { offset: 60_000, length: 10_000, signal }) returns exactly bytes [60 000, 70 000)
  • 13.5 tests/integration/drive-stat-list-exists.test.ts — full read-side matrix on a real Drive: resolver.stat → StatResult, resolver.exists → boolean, resolver.list → URIs that round-trip through resolver.read

14. Migration audit

  • 14.1 grep -rln "DRIVE_URI.WRITE_UNSUPPORTED" packages/ | grep -v "/dist/\|/coverage/\|/drive-uri/" — every hit reviewed; non-matching consumers re-routed onto TEMPLATE_READ_ONLY / RANGE_* / MESH_PROPAGATION_TIMEOUT where appropriate
  • 14.2 Update README.md Features + Modules sections to reflect full surface

15. Pre-publish gate (§13)

  • 15.1 Spec reconciliation — walk every ### Requirement and #### Scenario in specs/drive-uri/spec.md AND specs/drive/spec.md; confirm every **Verified by:** test name exists verbatim
  • 15.2 bunx turbo lint typecheck test --filter=@suaveplan/drive --filter=@suaveplan/drive-uri — green
  • 15.3 bunx turbo test:coverage --filter=@suaveplan/drive --filter=@suaveplan/drive-uri — 100/100/100/100 on touched modules
  • 15.4 bunx turbo build --filter=@suaveplan/drive --filter=@suaveplan/drive-uri — green
  • 15.5 Banned-pattern, barrel, test-runner-import, missing-.md, README, bare-version, subpath-export, security scans — all clean
  • 15.6 Dependent sweep: bunx turbo test --filter=...@suaveplan/drive — green

16. Root-doc refresh (§13b)

  • 16.1 bun scripts/folder-reorg/generate-manifest.ts — refresh MANIFEST.md
  • 16.2 bun scripts/generate-missing.ts — refresh MISSING.yml
  • 16.3 Update STATUS.md / SUMMARY.md paragraphs for drive-uri and drive to reflect full surface
  • 16.4 bunx markdownlint-cli2 --fix over touched docs

17. Archival (§14)

  • 17.1 Fold specs/drive-uri/spec.md delta into openspec/specs/drive-uri/spec.md
  • 17.2 Fold specs/drive/spec.md delta into openspec/specs/drive/spec.md
  • 17.3 Move openspec/changes/complete-drive-uri/ → openspec/archive/<yyyy-mm-dd>-complete-drive-uri/
  • 17.4 Delete openspec/changes/_superseded-narrow-deferrals-2026-05-17/ (research already folded into this change's archive)