Parent: #14
Registry prerequisite: #5
Problem
server/_shared/redis.ts is the shared cache primitive for server handlers. The distributed coordinator cannot rely on the old URL-encoded SET write path for larger JSON payloads, and it cannot safely use runRedisPipeline() for lock scripting because pipeline normalization assumes a simple key-at-index-1 command shape.
Scope
- add generated server-side cache-fill policy projection from
registry/datasets.ts
- validate
cacheFill invariants during registry:generate
- move
setCachedJson() to a dedicated body-command Redis path
- add miss-only distributed coordination in
server/_shared/redis.ts
- derive lock keys from the final prefixed Redis key
- use token-safe unlock from the start
- add structured outcome logging in the shared helper
- keep behavior unchanged when no generated policy exists or Redis coordination is unavailable
Out of scope
- expanding the allowlist beyond the first two shared keys
- migrating unrelated ad hoc locks in handler-specific code
- introducing a metrics backend beyond structured logs
Invariants
- mandatory cache recheck after lock acquisition
- followers poll the data key, not the lock key
waitMs < leaseMs
pollMinMs > 0
pollMaxMs >= pollMinMs
pollMaxMs < waitMs
- Redis lock errors degrade to legacy local singleflight behavior
Expected files
registry/datasets.ts
scripts/generate-dataset-registry.ts
scripts/check-dataset-registry.mjs
server/_shared/_generated/cache-fill-registry.ts
server/_shared/redis.ts
- fake Redis / shared cache tests
Validation
npm run registry:generate
npm run registry:check
node --test tests/redis-caching.test.mjs
npm run typecheck
npm run typecheck:api
npm run test:data
Parent: #14
Registry prerequisite: #5
Problem
server/_shared/redis.tsis the shared cache primitive for server handlers. The distributed coordinator cannot rely on the old URL-encodedSETwrite path for larger JSON payloads, and it cannot safely userunRedisPipeline()for lock scripting because pipeline normalization assumes a simple key-at-index-1 command shape.Scope
registry/datasets.tscacheFillinvariants duringregistry:generatesetCachedJson()to a dedicated body-command Redis pathserver/_shared/redis.tsOut of scope
Invariants
waitMs < leaseMspollMinMs > 0pollMaxMs >= pollMinMspollMaxMs < waitMsExpected files
registry/datasets.tsscripts/generate-dataset-registry.tsscripts/check-dataset-registry.mjsserver/_shared/_generated/cache-fill-registry.tsserver/_shared/redis.tsValidation
npm run registry:generatenpm run registry:checknode --test tests/redis-caching.test.mjsnpm run typechecknpm run typecheck:apinpm run test:data