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

5.2 KiB

Tasks: enterprise-server-cache-memory

Change ID: enterprise-server-cache-memory Package: @suaveplan/cache-memory Target path: server/data/cache-memory Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/logger


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. Scaffold

  • Create directory tree per proposal.md layout.
  • Write package.json at 0.1.0, "sideEffects": false, exports map for ".", adapter, and lru.
  • Add dependencies: @suaveplan/error workspace:^, @suaveplan/types workspace:^, @suaveplan/logger workspace:^, zod catalog:forms, @opentelemetry/api catalog:observability, tslib catalog:build.
  • Add devDependencies: vitest catalog:testing, @vitest/coverage-istanbul catalog:testing, fast-check catalog:testing, @suaveplan/testing workspace:^.
  • tsconfig.json extending library.json; vitest.config.ts using createTestConfig().
  • Scripts: lint, typecheck, test, test:coverage, build, docs:check.

2. Types and errors

  • Define MemoryCacheOptions, CacheStats, MemoryCacheOptionsSchema in src/types/cache-memory.types.ts.
  • Write cache-memory.types.md (≥200 words, both examples, API reference).
  • src/error-codes.ts: MemoryCacheErrorCode, metadata, registerMemoryCacheErrorCodes(), eager call.

3. LRU data structure

  • Implement src/lru/lru-cache/lru-cache.ts:
    • Doubly-linked list + Map, O(1) get/set/delete.
    • LruCache<V> with maxSize, get(k), set(k, v), delete(k), has(k), keys(), size.
    • On capacity exceeded: evict LRU (tail) entry; increment eviction counter.
    • No external deps.
  • Write lru-cache.test.ts: LRU ordering, capacity eviction, re-access promotes entry, delete middle node, size tracking.
  • Write lru-cache.md (≥200 words).

4. Memory cache adapter

  • Implement MemoryCacheAdapter in src/adapter/memory-cache-adapter/memory-cache-adapter.ts:
    • Owns an LruCache<{ value: Uint8Array; expiresAt?: number }>.
    • get(key): check expiry using clock.now() (or Date.now() when no clock); on expiry call delete(key) and return undefined; increment hit/miss counter.
    • set(key, value, ttlMs?): store entry with expiresAt = clock.now() + ttlMs when TTL supplied; evict if maxSize exceeded (handled by LRU internally).
    • delete(key): remove entry; return true if existed.
    • has(key): get + check expiry; return bool.
    • list(prefix?): iterate keys, skip expired, filter by prefix.
    • clear(): reset LRU; reset stats.
    • ttl(key): expiresAt - clock.now() or undefined.
    • size(): current entry count.
    • stats(): return CacheStats snapshot.
    • OTel: counter cache_memory.ops_total (operation, hit); histogram cache_memory.duration_ms.
  • Export createMemoryCacheAdapter(options?).
  • Write memory-cache-adapter.types.ts with internal types.
  • Write memory-cache-adapter.test.ts (≤500 lines): all CRUD, TTL expiry with FakeClock, LRU eviction order, stats accuracy, concurrent access (synchronous — no real concurrency needed), logger invocations.
  • Write memory-cache-adapter.md (≥200 words, simple + advanced, full API reference).

5. Property-based tests

  • Write tests/property.test.ts (≤500 lines, { timeout: 30000 } on each):
    • Get/set round-trip: for arbitrary keys + values, set then get returns the same bytes.
    • Delete removes: after set + delete, get returns undefined.
    • TTL expiry consistency: entries with ttlMs = 0 never returned on next get with advanced clock.
    • LRU ordering: inserting N+1 entries into a size-N cache results in the oldest-accessed entry being evicted.
    • Stats accuracy: hits + misses === total get calls for arbitrary call sequences.

6. OTel + docs

  • Counter cache_memory.ops_total; histogram cache_memory.duration_ms as specified.
  • All .md files per layout; root README.md with quick-start, FakeClock testing example, API table, deps table.

7. Verify and publish

  • bunx turbo lint --filter=@suaveplan/cache-memory — zero errors.
  • bunx turbo typecheck --filter=@suaveplan/cache-memory — zero errors.
  • bunx turbo test --filter=@suaveplan/cache-memory — all tests pass.
  • bunx turbo test:coverage --filter=@suaveplan/cache-memory — 100%.
  • Confirm "sideEffects": false set; no TODO/any/.skip in src/.
  • bun scripts/publish.ts --package @suaveplan/cache-memory.
  • Update CLAUDE.md; archive to openspec/archive/2026-04-24-enterprise-server-cache-memory/.