Files
suaveplan/openspec/archive/2026-05-16-add-cache-storage-redis-backends/INVENTORY.md
2026-05-27 23:29:53 +01:00

3.6 KiB

Spec-First Inventory — add-cache-storage-redis-backends

Per openspec/AGENTS.md §0c step 6 + AGENTS.md §2b. Implementation may not begin until this exists.

cache-storage — Requirements

R1. StorageCache extends AbstractCache

  • R1.S1 instance is instanceof AbstractCache and has the full AbstractCacheShape
  • R1.S2 inherited wrap caches the loader result on a miss

R2. 32-byte fixed-width metadata header

  • R2.S1 header.encode → header.decode round-trips every field
  • R2.S2 decodeHeader throws ENTRY_CORRUPT on bytes shorter than HEADER_BYTES

R3. TTL expiration is lazy on read

  • R3.S1 get returns undefined and deletes when entry has expired
  • R3.S2 entry with no ttl never expires

R4. ENTRY_CORRUPT on short blob from storage

  • R4.S1 short blob surfaces as ENTRY_CORRUPT with error.key === originalKey

R5. Codec decouples T from byte storage

  • R5.S1 JsonCodec round-trips structured value
  • R5.S2 JsonCodec.decode throws CODEC_ERROR on malformed bytes
  • R5.S3 IdentityCodec encode/decode preserves bytes

R6. CACHE_STORAGE error registry

  • R6.S1 every CACHE_STORAGE_* code reachable

R7. Module augmentation registers "storage" provider

  • R7.S1 hasCacheProvider("storage") true after import
  • R7.S2 createCache("storage", ...) returns a StorageCache

R8. Namespacing prefixes every stored key

  • R8.S1 namespace prefixes keys before delegating to storage

R9. Lifecycle events emitted when EventBusLike provided

  • R9.S1 emits hit on get after set
  • R9.S2 emits miss on get of unknown key

R10. Stats counters via getStats

  • R10.S1 hitRate computes hits / (hits + misses)

R11. Tier purity — universal

  • R11.S1 src contains no node:/bun: imports

cache-storage — error-code reachability (R6)

  • ENTRY_CORRUPT — short blob OR decodeHeader on undersized buffer
  • CODEC_ERROR — JsonCodec.decode malformed bytes
  • BACKEND_ERROR — underlying storage throws non-cache error → wrapped
  • KEY_TOO_LONG — set with key longer than max allowed
  • VALUE_TOO_LARGE — set with value larger than max allowed

cache-redis — Requirements

R1. RedisCache extends AbstractCache

  • R1.S1 instance is instanceof AbstractCache with full shape

R2. RedisLike interface

  • R2.S1 FakeRedis stub satisfies the interface
  • R2.S2 cache round-trips set→get against FakeRedis

R3. Native TTL via SET ... EX

  • R3.S1 positive ttl invokes SET with EX seconds
  • R3.S2 zero default ttl invokes SET without EX

R4. INVALID_TTL on negative ttl

  • R4.S1 negative ttl rejected with INVALID_TTL

R5. clear() refuses when no namespace

  • R5.S1 clear without namespace throws COMMAND_FAILED
  • R5.S2 clear with namespace deletes only namespaced keys

R6. CACHE_REDIS error registry

  • R6.S1 every CACHE_REDIS_* code reachable

R7. Codec layer shared with cache-storage

  • R7.S1 JsonCodec emits UTF-8 string into redis.set
  • R7.S2 IdentityCodec emits base64 round-trip

R8. Module augmentation registers "redis" provider

  • R8.S1 hasCacheProvider("redis") true after import
  • R8.S2 createCache("redis", ...) returns a RedisCache

R9. getStats client-side counters

  • R9.S1 reports hits/misses/hitRate, size 0

R10. Tier — server

  • R10.S1 src contains no node:/bun: imports

cache-redis — error-code reachability (R6)

  • CONNECTION_FAILED — wrap RedisLike error during set/get
  • COMMAND_FAILED — clear() without namespace
  • CODEC_ERROR — codec decode failure during get
  • KEY_TOO_LONG — set with oversized key
  • INVALID_TTL — negative ttl in set