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

7.0 KiB

Tasks — add-drive-plugin-cache

Every checkbox MUST reflect work actually done in this change.

1. Spec authoring

  • 1.1 Read openspec/specs/drive/spec.md and confirm DrivePlugin / DriveMiddleware shape
  • 1.2 Read openspec/specs/cache/spec.md and confirm AbstractCache<T> contract
  • 1.3 Read openspec/archive/2026-05-16-add-cache-storage-redis-backends/ for the cache-family conventions
  • 1.4 Read openspec/AGENTS.md §0c, §2b, §6a, §7, §11, §13
  • 1.5 Read packages/drive/drive/src/types/drive.types.ts to confirm MiddlewareContext and MiddlewareNext<T> signatures
  • 1.6 Draft proposal.md, design.md, tasks.md, specs/drive-plugin-cache/spec.md
  • 1.7 Every requirement in the spec delta carries a **Verified by:** line naming concrete planned it(...) titles
  • 1.8 Build the numbered Requirement/Scenario implementation checklist (§0c step 6) — 12 requirements, 29 scenarios

2. Scaffolding

  • 2.1 Create packages/drive/drive-plugin-cache/ mirroring packages/drive/drive-uri/ conventions
  • 2.2 Write package.json v0.0.0, "sideEffects": false, subpath exports for every feature module
  • 2.3 Wire deps: @suaveplan/error, @suaveplan/drive, @suaveplan/cache, @suaveplan/types, @opentelemetry/api, tslib (all workspace:^ / catalog:)
  • 2.4 Wire devDeps: @suaveplan/testing, @suaveplan/storage, @suaveplan/storage-file, @suaveplan/cache-storage, @vitest/coverage-istanbul, fast-check, typescript, vite, vite-plugin-dts, vitest
  • 2.5 Write tsconfig.json, tsconfig.lib.json, vite.config.ts, vitest.config.ts (via createTestConfig)
  • 2.6 Write tests/setup/polyfills.ts and README.md skeleton

3. Implementation

  • 3.1 src/error-codes/error-codes.ts — defineCodes("DRIVE_CACHE", ["INVALID_OPTIONS", "CACHE_TOO_LARGE", "INSTALL_FAILED"] as const), DriveCacheError class, path?/namespace? discriminants
  • 3.2 src/types/options.types.ts — DriveCacheOptions, DriveCacheHandle, DriveCacheStats interfaces (no inline shapes per §11)
  • 3.3 src/handle/handle.ts — createHandle(cache, stats), exposes getStats() / invalidate(path) / clear() / cache
  • 3.4 src/middleware/middleware.ts — read(ctx, next) with hit short-circuit, miss + populate, shouldCache gate
  • 3.5 src/middleware/middleware.invalidation.ts — write(ctx, next) and delete(ctx, next) post-success invalidation, invalidateOnWrite/invalidateOnDelete toggles
  • 3.6 src/middleware/middleware.signal.ts — AbortSignal short-circuit helper used by all three intercepts
  • 3.7 src/otel/otel.ts — meter + tracer wiring, counter hits/misses/populations/invalidations/errors, histogram entry_bytes, span attribute helpers
  • 3.8 src/plugin/plugin.ts — driveCachePlugin(options): DrivePlugin<DriveCacheHandle> factory with construction-time INVALID_OPTIONS check
  • 3.9 src/index.ts — explicit named re-exports per §6a

4. Tests (every it(...) carries { timeout: 5000 }, 30000 for async integration)

  • 4.1 src/error-codes/error-codes.test.ts — every code reachable from a real call site, discriminants populated
  • 4.2 src/plugin/plugin.test.ts — install registers middleware, install returns handle with same cache reference, INVALID_OPTIONS on missing cache, INVALID_OPTIONS on malformed cache
  • 4.3 src/middleware/middleware.test.ts — hit short-circuits, custom namespace used in key, miss populates, shouldCache gate, default 16 MiB ceiling, stat/list passthrough, cache.get rejection falls through, cache.set rejection swallowed
  • 4.4 src/middleware/middleware.invalidation.test.ts — write invalidates post-success, write failure does not invalidate, invalidateOnWrite:false skips, delete symmetric, delete failure does not invalidate, cache.delete rejection swallowed
  • 4.5 src/middleware/middleware.signal.test.ts — pre-aborted signal skips cache work, live signal forwarded to cache.get/set/delete
  • 4.6 src/handle/handle.test.ts — getStats monotonic, invalidate deletes one entry, clear clears cache
  • 4.7 src/otel/otel.test.ts — hit/miss/populate/invalidate/error counters increment, entry_bytes histogram observed on populations, errors_total carries op label, span outcome attribute populated
  • 4.8 tests/integration/with-memory-cache.test.ts — real Drive + real MemoryCache: write bytes, read twice, assert hits === 1 on second read
  • 4.9 tests/integration/with-storage-cache.test.ts — real Drive + real StorageCache over real storage-file FileStorage: cache survives plugin reinstall (disk-backed)
  • 4.10 tests/integration/with-namespaced-caches.test.ts — two plugin instances with distinct namespaces share one AbstractCache reference but do not see each other's entries
  • 4.11 No imports from vitest or bun:test in test files — all via @suaveplan/testing/runner (rule 11)
  • 4.12 No vi.mock / jest.mock; all dependencies are real per CLAUDE.md rule 2

5. Documentation

  • 5.1 Sibling .md for every implementation .ts (≥200 words, basic + advanced examples, full API reference)
  • 5.2 README.md links every module under ## Modules
  • 5.3 README documents the five composition recipes from design.md (memory / OPFS / file / Redis / wrap() stale-while-revalidate)
  • 5.4 README documents the shouldCache / maxEntryBytes defaults and the rationale (16 MiB matches drive-mesh-protocol's frame ceiling)

6. Gates

  • 6.1 bun run check
  • 6.2 bunx turbo lint typecheck test --filter=@suaveplan/drive-plugin-cache
  • 6.3 bunx turbo test:coverage --filter=@suaveplan/drive-plugin-cache — 100/100/100/100 Istanbul
  • 6.4 bunx turbo build --filter=@suaveplan/drive-plugin-cache
  • 6.5 bun scripts/lint/check-test-runner-imports.ts (rule 11)
  • 6.6 Tier-purity grep — grep -rnE "from ['\"](node:|bun:)" packages/drive/drive-plugin-cache/src/ returns empty
  • 6.7 Banned-pattern scan returns empty (§2)
  • 6.8 Missing-.md scan returns empty (§4)
  • 6.9 Non-root export * scan returns empty (§6a)
  • 6.10 Bare-version scan returns empty (§1)
  • 6.11 Folder-naming scan (§10) — children under plugins/, middleware/, handle/ do not include the parent's singular/plural form as a suffix
  • 6.12 Spec-reconciliation gate — every ### Requirement is implemented; every **Verified by:** test name exists verbatim (§13 step 0)

7. Manifest & archival

  • 7.1 Add package to MANIFEST.md via bun scripts/folder-reorg/generate-manifest.ts
  • 7.2 Update STATUS.md (genesis-original — add to "Completed" once shipped)
  • 7.3 Update SUMMARY.md with the one-paragraph description
  • 7.4 bunx markdownlint-cli2 --fix on touched docs
  • 7.5 Fold specs/drive-plugin-cache/spec.md into openspec/specs/drive-plugin-cache/spec.md
  • 7.6 Move openspec/changes/add-drive-plugin-cache/ → openspec/archive/<yyyy-mm-dd>-add-drive-plugin-cache/