Ephemeris4 MIN READ13 / 31

Result Cache — High-Level Design

Scope decision: This standalone component is dropped from the binder package plan. The design below is historical context. Consumer applications own this responsibility; see the current package architecture.

Status: Draft for review · Part of: Astro Binder · Updated: 2026-10-24

The cache stores normalised provider results for an exact request, with the provenance that produced them. A hit returns the same canonical values without a provider call.

1. Purpose

Repeated position and transit workloads ask for the same instant and observer many times, yet recomputation costs a provider call and a normalisation pass. The cache removes that work:

  • exact key, so a hit is the same request;
  • canonical value, so a hit skips normalisation;
  • provenance travels with it, so cacheHit is the only difference;
  • an engine upgrade invalidates by construction, not cleanup.

2. Where it sits

calculation facade ──▶ result cache ── hit ──▶ stored canonical result + provenance
        │                    │ miss
        ▼                    ▼
provider router → adapter → normalizer ──▶ write-back
  • Upstream: the facade, with the router’s cache key.
  • Stores: canonical values plus provenance.
  • Never: chooses a provider, normalises, derives astrology, stores raw payloads.

3. Responsibilities

Component Owns Notes
Key contract Provider + full canonical request + engine version Instant never rounded
Lookup Read-through before a provider call No fuzzy or partial matching
Value contract Canonical result + provenance snapshot One provider per entry
Write-back Persist after normalisation succeeds Failures not cached
Retention Lifetime and eviction Fixed instants kept; evicted on upgrade
Metrics Hit ratio, latency, entry age No payload logging

4. Architecture

Result Cache — High-Level Design Reference design. The facade reads the cache before any provider call using a key built from the provider, the full canonical request and the engine version. A hit returns stored canonical values and their provenance with the cacheHit flag; a miss runs the router, adapter and normalizer, then writes the normalised result back. Entries are evicted when the engine version changes, and cache unavailability is treated as a miss rather than a failed calculation. Result Cache — High-Level Design Exact-request provider results reused with their provenance; a hit never re-derives or re-normalises. Calculation facade · request path Cache lookup before any provider call key = provider + request + engine Compute on miss route → adapter → normalizer one provider per response miss Result cache · managed data service Key contract provider · canonical request engine version · no rounding Read-through lookup exact key only stored canonical values Write-back + retention store on successful normalisation evict on engine upgrade request hit key on miss Provider router capability matrix select one provider Swiss + NASA adapters raw provider answer no canonical units Canonical normalizer one canonical result provenance stamped call raw write on success Why the key is exact The instant is never rounded. A new engine version is a new key, so old entries cannot answer. Cache trouble is a miss, not a failed calculation. dependency module entry / saved state boundary

Diagram: reference design, not deployed behaviour.

The cache sits beside the request path: when it cannot answer, the facade continues to the provider.

5. Rules

  1. Exact key only. Provider id, bodies, instant in UT, observer, zodiac, ayanamsa, frame, house system and flags all participate; the instant is never rounded.
  2. Engine version is identity. An upgrade changes the key; old entries cannot answer and are evicted.
  3. Store canonical output. Entries hold normalised values and provenance, not raw tables; a hit never re-normalises.
  4. One provider per entry. One provenance block, matching the one-provider-per-response rule.
  5. Success only. Provider errors, normalizer rejections and partial answers are never cached.
  6. A hit is transparent. Only cacheHit: true and the stored provenance differ.
  7. The cache is optional. Unavailability counts as a miss and never fails a calculation.
  8. Retention follows the workload. Fixed instants persist until an engine upgrade; later transit keys get a short lifetime.

6. Edge cases

Case Behaviour
Entry from an older engine Unreachable by the new key; evicted
Cache unavailable or erroring Treated as a miss; compute normally
Two identical misses at once Both compute; exact key makes the last write idempotent
Degraded answer Stored with degraded provenance; a hit never upgrades precision
Cache write fails after compute Response returned; miss counted
Houses and positions, same instant Separate entries; full request is the key
Very large body list Same rules; key length bounded by the request
Short-lived transit keys (later) TTL per workload, same value contract

7. Out of scope

  • Provider selection, fallback, breaker state (router).
  • Unit, frame, zodiac, precision rules (normalizer).
  • Response assembly, degradation policy (facade).
  • Provenance retention, audit queries (provenance store).
  • Drift validation and alerting.

8. Planned code

Piece Responsibility
cache/ResultCache Lookup, hit metadata, write-back
cache/CacheKey Exact key contract and validation
cache/CacheEntry Canonical values + provenance snapshot
cache/RetentionPolicy Lifetime, engine-version eviction, TTLs
cache/CacheMetrics Hit ratio, latency, entry age