feat(forecast): Phase 2 simulation package read path#2219
Merged
Conversation
…ckage RPC + Redis existence key)
- writeSimulationPackage now writes forecast:simulation-package:latest to Redis after
successful R2 write, containing { runId, pkgKey, schemaVersion, theaterCount, generatedAt }
with TTL matching TRACE_REDIS_TTL_SECONDS (60 days)
- New getSimulationPackage RPC handler reads Redis key, returns pointer metadata without
requiring an R2 fetch (zero R2 cost for existence check)
- Wired into ForecastServiceHandler and server/gateway.ts cache tier (medium)
- Proto: GetSimulationPackage RPC + get_simulation_package.proto message definitions
- api/health.js: simulationPackageLatest added to STANDALONE_KEYS + ON_DEMAND_KEYS
- Tests: SIMULATION_PACKAGE_LATEST_KEY constant + writeSimulationPackage null-guard test
Closes todo #17 (Phase 2 prerequisites for MiroFish integration)
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
… runId mismatch - Add `error` field to GetSimulationPackageResponse: populated with "redis_unavailable" on Redis errors so callers can distinguish a healthy not-found (found=false, error="") from a Redis failure (found=false, error="redis_unavailable"). Adds console.warn on error. - Add `note` field: populated when req.runId is supplied but does not match the latest package's runId, signalling that per-run filtering is not yet active (Phase 3). - Add proto comment on run_id: "Currently ignored; reserved for Phase 3" - Add milliseconds annotation to generated_at description. - Simplify handler: extract NOT_FOUND constant, remove SimulationPackagePointer interface, remove || '' / || 0 guards on guaranteed-present fields. - Regenerate all buf-generated files. Fixes todos #18 (runId silently ignored) and #19 (error indistinguishable from not-found). Also resolves todos #22 (simplifications) and #23 (OpenAPI required fields / generatedAt unit annotation).
…th deep-run update frequency)
…no-cache not-found
Three P1 regressions caught in external review:
1. Key prefix bug: getCachedJson() applies preview:<sha>: prefix in non-production
environments, but writeSimulationPackage writes the raw key via a direct Redis
command. In preview/dev the RPC always returned found:false even when the package
existed. Fix: new getRawJson() in redis.ts always uses the unprefixed key AND throws
on failure instead of swallowing errors.
2. redis_unavailable unreachable: getCachedJson swallows fetch failures and missing-
credentials by returning null, so the catch block for redis_unavailable was dead
code. getRawJson() throws on HTTP errors and missing credentials, making the
error: "redis_unavailable" contract actually reachable.
3. Negative-cache stampede: slow tier caches every 200 GET. A request before any deep
run wrote a package returned { found:false } which the CDN cached for up to 1h,
breaking post-run discovery. Fix: markNoCacheResponse() on both not-found and
error paths so they are served fresh on every request.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 2 of the WorldMonitor → MiroFish bridge. Phase 1 (PR #2204) delivered the simulation package write path. This PR delivers the read path so MiroFish (or any LLM scenario-analysis workflow) can discover and consume the package at runtime.
writeSimulationPackagenow writesforecast:simulation-package:latestto Redis after a successful R2 write, with{ runId, pkgKey, schemaVersion, theaterCount, generatedAt }and 60-day TTL. Zero R2 cost for existence checks.getSimulationPackageRPC: New GET endpoint/api/forecast/v1/get-simulation-packagethat reads the Redis key and returns the pointer metadata. Returnsfound: falsewhen no package has been written yet (e.g. before the first deep forecast run).GetSimulationPackageRPC +get_simulation_package.protomessage definitions.make generaterun to regenerate client/server types and OpenAPI spec.medium(same asget-forecasts).simulationPackageLatestadded toSTANDALONE_KEYS+ON_DEMAND_KEYSinapi/health.js(WARN not CRIT when absent, since it only exists after the first deep run).SIMULATION_PACKAGE_LATEST_KEYconstant validation +writeSimulationPackagenull-guard (returns null without R2 credentials). 2296 tests pass.Closes todo #17.
Test plan
npm run typecheckcleanforecast:simulation-package:latestappears in Redis with correct shapeGET /api/forecast/v1/get-simulation-packagereturns{ found: false }when key absent, correct pointer when presentPost-Deploy Monitoring & Validation
forecast:simulation-package:latestRedis key after next deep forecast runGET /api/forecast/v1/get-simulation-packageshould returnfound: truewithpkgKeymatching the R2 pathfound: falseafter a known successful deep run indicates Redis write failed silently inwriteSimulationPackage