koala73/worldmonitor · error · TypeError
Physical divergence composite does not match its member read
Error message
Physical divergence composite does not match its member readings
What it means
validateStoredComposite() recomputes the expected composite (state, reason, index) from the snapshot's member readings and compares it with the stored composite fields. Any mismatch — wrong/missing reason string, a reason inconsistent with the actual state, or divergent state/reason/index values — throws this TypeError. It guarantees a stored composite is never presented unless it is exactly derivable from its readings.
Source
Thrown at server/_shared/physical-divergence-snapshot.ts:374
}
function validateStoredComposite(
value: unknown,
readings: PhysicalDivergenceRawReading[],
): void {
const raw = object(value);
methodology(raw.methodologyVersion);
canonicalWeights(raw.weights);
const expected = buildPhysicalStressComposite(readings);
const actualState = state(raw.state);
const actualIndex = nullableFinite(raw.index);
if (
!string(raw.reason)
|| !isPhysicalDivergenceStoredCompositeReason(actualState, raw.reason)
|| actualState !== expected.state
|| raw.reason !== expected.reason
|| actualIndex !== expected.index
) throw new TypeError('Physical divergence composite does not match its member readings');
}
function applyFreshness(
readings: PhysicalDivergenceRawReading[],
nowMs: number,
): PhysicalDivergenceRawReading[] {
if (!Number.isFinite(nowMs)) throw new TypeError('Physical divergence evaluation clock is invalid');
return readings.map((entry) => {
if (entry.state !== 'ok' && entry.state !== 'insufficient_history') return entry;
const staleReason = physicalDivergenceStaleReason({
physicalAsOf: entry.physicalAsOf,
paperAsOf: entry.paperAsOf,
fxAsOf: entry.provenance.fxAsOf,
}, nowMs);
if (!staleReason) return entry;
return {
...entry,
state: physicalDivergenceStateForFreshnessReason(staleReason),View on GitHub (pinned to 9361220cc0)
Solutions
- Purge the stale snapshot cache entry and let getPhysicalDivergenceIndex rebuild it from fresh readings so composite and readings are computed together atomically.
- Ensure the writer updates readings and composite in one atomic write (same Redis transaction/key version).
- If a methodology bump caused this, bump PHYSICAL_DIVERGENCE_METHODOLOGY_VERSION and invalidate all snapshots written under the old version.
- Verify serialization preserves the exact index value (no lossy rounding) between compute and store.
Example fix
// before (partial write)
cache.set(key, { ...snapshot, readings: newReadings }); // composite now stale
// after
cache.set(key, recomputeCompositeAndWrite(newReadings)); // composite + readings atomic Defensive patterns
Strategy: validation
Validate before calling
const recomputed = computeComposite(readings); // same code path as the writer
if (recomputed.state !== stored.state || recomputed.reason !== stored.reason || recomputed.index !== stored.index) {
throw new Error('stored composite diverges from member readings; regenerate before use');
} Type guard
null
Try / catch
try {
const snapshot = normalizePhysicalDivergenceSnapshot(stored, Date.now());
} catch (err) {
if (err instanceof TypeError && err.message.includes('does not match its member readings')) {
stored = await rebuildSnapshotFromReadings(); // discard stale composite
} else throw err;
} Prevention
- Persist readings and their composite atomically in a single write.
- Invalidate the whole snapshot key when any member reading changes.
- Bump and check methodologyVersion on every composite write.
- Avoid lossy rounding of index values during serialization.
When it happens
Trigger: Normalizing a stored physical-divergence snapshot where the persisted composite was computed under an older methodology, the readings were updated without recomputing the composite, or the stored index/reason/state drifted from what the readings imply (float/rounding drift included).
Common situations: Partial cache writes (readings updated, composite stale); methodology-version bump without cache invalidation; hand-patched cache entries; serialization rounding of the index value.
Related errors
- Physical divergence composite repeats a metal weight
- Physical divergence snapshot has an invalid envelope
- Physical divergence evaluation clock is invalid
- failed to build coverage snapshot
- failed to build overview snapshot
AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01).
Data as JSON: /api/errors/98885814472e5640.
Report an issue: GitHub.