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

7.3 KiB

Tasks: complete-drive

All tasks land in packages/drive/drive/. Follow CLAUDE.md ### Quality and openspec/AGENTS.md §13 pre-ship gates. Coverage gate is 100/100/100/100.

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. Audit & spec lock-in

  • 1.1 Snapshot current public surface — bunx turbo build --filter=@suaveplan/drive then grep dist/index.d.ts for the exported symbol list; paste into design.md ## Today's surface.
  • 1.2 Confirm sibling-change scope boundaries with complete-drive-uri (URI/locator owner) and complete-types-drive-promotion (cross-package types owner) — no duplicate requirements.

2. Error-code registry

  • 2.1 Extend src/error-codes.ts DRIVE_CODES with COPY_FAILED, MOVE_FAILED, WATCH_FAILED, QUOTA_EXCEEDED, OPERATION_ABORTED, STORAGE_READONLY (keeps defineCodes("DRIVE", [...]) frozen).
  • 2.2 Update src/error-codes.md and the conformance test src/error-codes.spec-conformance.test.ts to assert the wider set.

3. Op surface widening

  • 3.1 Add DeleteOptions, StatOptions, ReadStreamOptions, WriteStreamOptions to src/types/drive.types.ts; export them from src/index.ts.
  • 3.2 Add overload signatures on Drive.delete/Drive.stat/Drive.createReadStream/Drive.createWriteStream accepting the options bundle (positional signal? kept as a second overload for one minor cycle).
  • 3.3 Implement range-read in src/file-operations/streams.ts using storage.createReadStream({ offset, length }) when capabilities.rangeReads === true, else slice in the default fallback.

4. Copy / move

  • 4.1 New module src/file-operations/copy.ts + .md: middleware-wrapped copy; uses storage.copy? when available, else read-then-write; emits drive:copy:before/drive:copy:after. Errors surface as DriveError(DRIVE.COPY_FAILED, { cause }).
  • 4.2 New module src/file-operations/move.ts + .md: same shape; uses storage.move? (rename), else copy + delete with rollback on failure; emits drive:move:before/drive:move:after. Errors surface as DriveError(DRIVE.MOVE_FAILED, { cause }).
  • 4.3 Wire Drive.copy(src, dst, opts?) and Drive.move(src, dst, opts?) through PluginRegistry.runMiddleware. Add copy?/move? slots to DriveMiddleware.

5. List typing

  • 5.1 Replace Promise<unknown> return on Drive.list with Promise<DriveListPage> where DriveListPage = { entries: DriveEntry[]; cursor?: string }.
  • 5.2 Add Drive.scan(prefix?, opts?): AsyncIterable<DriveEntry> that auto-paginates and respects signal.

6. Watch

  • 6.1 New module src/file-operations/watch.ts + .md: Drive.watch(path, opts?) returns { events: AsyncIterable<DriveChangeEvent>; unsubscribe(): void }. Backed by the injected EventBusLike. Falls back to a per-drive in-memory bus when none injected (drive-local fan-out only).
  • 6.2 Emitters on write/delete/copy/move publish DriveChangeEvent to bus topic drive:change:<path>.

7. Plugin lifecycle

  • 7.1 Extend PluginRegistry with unload(name), list(), find(name) and an ordered handle map keyed by plugin.name.
  • 7.2 Expose Drive.unloadPlugin(name), Drive.listPlugins(), Drive.findPlugin(name) on the class. Unload is idempotent; unknown name throws DriveError(DRIVE.PLUGIN_FAILED, ...).
  • 7.3 Document install/unload ordering invariants in src/plugins/registry.md.

8. Quota / usage

  • 8.1 New module src/observability/usage.ts + .md: Drive.usage(): Promise<DriveUsage> aggregating per-storage byte counts via storage.usage?() when available, else by summing stat().size over scan(). Cached for options.usageCacheMs (default 5s).
  • 8.2 New module src/observability/quota.ts + .md: Drive.setQuota({ soft?, hard? }). On every write/copy/move, post-op usage() check; emit drive:quota:warning on soft trip and throw DriveError(DRIVE.QUOTA_EXCEEDED) on hard.

9. Sharing-integration hook

  • 9.1 In src/types/drive.types.ts add DriveShareLike interface (share(path, audience): Promise<ShareHandle>, revoke(handle): Promise<void>, listShares(path?): Promise<ShareHandle[]>). Drive owns the interface; concrete impl lives in drive-sharing.
  • 9.2 Add options.shareHook?: DriveShareLike to DriveOptions; expose Drive.share/Drive.revoke/Drive.listShares that delegate to the hook or throw DriveError(DRIVE.PLUGIN_FAILED, "no share hook").

10. Hydration progress events

  • 10.1 In src/drive/hydrate-from.ts, alongside the existing onProgress callback, publish drive:hydrate:progress events to the EventBus when injected. Add drive:hydrate:complete and drive:hydrate:aborted.
  • 10.2 Update hydrate-from.md examples + add a watch-the-bus advanced example.

11. OTEL spans

  • 11.1 Wrap each public op (read, write, delete, stat, list, scan, copy, move, watch, hydrateFrom, usage) in a span named drive.<op> with attributes drive.path, drive.storage.id, drive.bytes where applicable. Use @opentelemetry/api directly; no-op when no exporter registered.

12. Tests

  • 12.1 Per-feature unit tests (.test.ts) for every new module.
  • 12.2 Extend drive.spec-conformance.test.ts with scenarios for every new requirement (one scenario per **Verified by:** line in the spec delta).
  • 12.3 fast-check property tests: copy(a,b);read(b) === read(a), move invariant (after) !exists(a) && exists(b), usage() monotonicity across N writes, watch delivers every change.
  • 12.4 Verify bunx turbo test:coverage --filter=@suaveplan/drive reports 100/100/100/100 (istanbul). No c8 ignore.

13. Docs

  • 13.1 Sibling .md for every new .ts, ≥200 words, basic + advanced examples (CLAUDE.md ### Documentation).
  • 13.2 Update packages/drive/drive/README.md Modules section with every new feature.
  • 13.3 Refresh src/drive/drive.md to list the widened surface and the new option fields.

14. Pre-ship gate

  • 14.1 bunx turbo lint typecheck test --filter=@suaveplan/drive green.
  • 14.2 bunx turbo test:coverage --filter=@suaveplan/drive 100%.
  • 14.3 bunx turbo build --filter=@suaveplan/drive green.
  • 14.4 Banned-pattern + barrel-shape + test-runner-import scans clean (AGENTS §13 steps 4, 4a, 4b).
  • 14.5 Dependent sweep: bunx turbo test --filter=...@suaveplan/drive green.
  • 14.6 bun scripts/folder-reorg/generate-manifest.ts + bun scripts/generate-missing.ts; refresh STATUS.md / SUMMARY.md; bunx markdownlint-cli2 --fix.

15. Archive

  • 15.1 Fold specs/drive/spec.md into openspec/specs/drive/spec.md.
  • 15.2 Move openspec/changes/complete-drive/ → openspec/archive/<yyyy-mm-dd>-complete-drive/.