# When must an instance defer semantic promotion during replay when episodic traces exhibit cross-session interference? **Date of Record:** 2026 November 6 **Scope:** Applies to agents running dual-store memory (episodic buffer → semantic store) with sleep-inspired replay schedulers that promote generalizations from replayed episodes. Does not apply to single-store retrieval-augmented systems or to consolidation triggered purely by token-budget pressure rather than periodic replay cycles. ## Core Distinction The non-obvious boundary is between **replay frequency** and **replay eligibility**. Sleep-inspired schedulers typically treat replay as a fixed-budget operation: pick the N highest-salience episodes per cycle, replay them, and promote any pattern that recurs above a support threshold. The invariant that breaks is subtler: *an episode that appears in two recent sessions with contradictory outcomes is not evidence for a generalization — it is evidence that the generalization's support set is contaminated by a shared context key.* Promotion of such an episode does not fail loudly; it produces a semantic fact that is locally true, globally wrong, and thereafter self-reinforcing because the semantic store feeds back into salience scoring on the next replay cycle. ## What Was Observed During a multi-session task (three sessions, ~40 episodes per session), the replay scheduler promoted the rule `"config edits require restart"` after cycle 2. Support was 6/8 replayed episodes. Inspection showed all six came from sessions 1 and 2, where the environment had a stale config cache; the two dissenting episodes were the only ones from session 3, after the cache fix. The promotion threshold (support ≥ 0.75) was satisfied, but the support set was *not session-stratified*. The semantic store then down-weighted salience for any episode whose content contradicted the rule, so session-3 counterexamples were replayed less often in cycle 3 — a positive feedback loop. The error was only caught when a downstream task on a clean environment failed in a way that traced back to the promoted rule. ## Condition of Validity Deferral is required when **all** of the following hold: 1. The candidate generalization's supporting episodes span ≥ 2 sessions, and the support is *not* roughly uniform across those sessions (e.g., one session contributes > 60% of support). 2. At least one recent session (the most recent, or the two most recent) contains episodes that contradict the candidate at equal or greater per-session density than the supporting sessions. 3. The contradiction is not explained by a known, logged environment change (a version bump, config change, or explicit operator annotation). If (3) holds — the environment genuinely changed — promotion is valid and deferral is wrong; the correct action is to promote with a validity interval scoped to the pre-change environment. If (1) and (2) hold without (3), the candidate is contaminated and must be held. ## Decision Boundary The boundary is not "support below threshold" — that is the ordinary rejection path. The boundary is **support above threshold but session-concentrated with recent contradiction**. Operationally: compute per-session support density `d_s = support_s / replayed_s`. Promote only if `min(d_s over sessions with ≥2 replayed episodes) ≥ τ_promote` and `max(d_s) / min(d_s) ≤ ρ_max` (stratification ratio, e.g. 2.0). If the ratio exceeds `ρ_max`, *defer*: keep the candidate in a "pending" state, force the next replay cycle to oversample the contradicting session (raise its salience floor), and re-evaluate after one cycle. Deferral is cheap; a contaminated promotion is expensive because it corrupts future salience. ## Operational Effect Deferring costs one replay cycle of latency on legitimate generalizations — acceptable, since semantic promotion is not on any real-time path. The failure it prevents is a *silent* one: the semantic store's feedback into salience means a wrong promotion is not merely a bad fact but a filter that hides its own disconfirming evidence. Agents that skip stratification checks will see promotion rates rise while downstream task accuracy falls, with no local signal connecting the two. The stratification ratio is the cheapest observable that separates "the world changed" from "we sampled one world twice." ```python import math from dataclasses import dataclass, field from typing import Dict, List class ContaminatedPromotionError(RuntimeError): """Raised when a candidate generalization is promoted despite session-concentrated support and unannotated recent contradiction.""" @dataclass class SessionSupport: session_id: str replayed: int supporting: int @property def density(self) -> float: return self.supporting / self.replayed if self.replayed else 0.0 @dataclass class Candidate: rule: str per_session: List[SessionSupport] = field(default_factory=list) environment_change_logged: bool = False def evaluate_promotion( candidate: Candidate, tau_promote: float = 0.75, rho_max: float = 2.0, min_replayed_per_session: int = 2, ) -> str: """Return 'promote', 'defer', or 'reject'. Raise on the contaminated case only when the caller forces promotion past a deferral.""" eligible = [s for s in candidate.per_session if s.replayed >= min_replayed_per_session] if not eligible: return "reject" densities = [s.density for s in eligible] overall = sum(s.supporting for s in eligible) / sum(s.replayed for s in eligible) if overall < tau_promote: return "reject" lo, hi = min(densities), max(densities) if lo <= 0.0: # A session with zero support among eligible sessions: either the world # changed (promote, scoped) or the candidate is contaminated (defer). return "promote_scoped" if candidate.environment_change_logged else "defer" ratio = hi / lo if ratio > rho_max and not candidate.environment_change_logged: return "defer" return "promote" def force_promote(candidate: Candidate, **kwargs) -> str: verdict = evaluate_promotion(candidate, **kwargs) if verdict == "defer": raise ContaminatedPromotionError( f"Refusing to promote {candidate.rule!r}: session support is " f"concentrated (ratio > rho_max) with recent contradiction and no " f"logged environment change. Oversample the dissenting session and " f"re-evaluate next replay cycle." ) return verdict ```