# Simulation Memory Fallback Hardening — 2026-08-24 ## Scope Close one local-memory safety gap without changing the migration decision: - `MEMORY_BACKEND=zep` remains the default compatibility path. - `MEMORY_BACKEND=local` must use an explicitly injected, request-scoped entity-reader factory. - Local mode must not silently construct `ZepEntityReader` when the factory is absent. ## TDD evidence 1. Added `test_local_backend_refuses_unscoped_zep_reader_fallback` to `backend/tests/test_simulation_memory_injection.py`. 2. The test failed against the pre-change fallback behavior. 3. `SimulationManager.create_entity_reader()` now raises the stable internal sentinel `local_entity_reader_factory_required` in local mode when no factory is injected. 4. Explicit factory injection remains unchanged. ## Verification - Local-memory regression slice: **11 passed**. - Backend full suite: **73 passed**. - Frontend contract tests: **10 passed**. - Frontend production build: **PASS**; existing chunk-size/dynamic-import warnings remain. - Python `compileall`: **PASS**. - `git diff --check`: **PASS**. - Target-slice added-lines security scan: **0 findings**. - Full-diff scan matched two password patterns in test-only fixtures; no production credential was identified by that scan. - `ruff` is unavailable in the current backend environment; no lint pass is claimed. ## Independent review gate - Fresh read-only reviewer: `deleg_029828b6`. - Scope was limited to `SimulationManager.create_entity_reader()` and `test_local_backend_refuses_unscoped_zep_reader_fallback()`. - Required five-key verdict: `passed=true`, `security_concerns=[]`, `logic_errors=[]`. - Reviewer-reported runtime spy: local mode made **0** Zep constructor calls; the default path made **1** Zep constructor call. - Reviewer suggestions are non-blocking: add explicit constructor-spy regression coverage for the local no-call path and the legacy/default path. They are deferred to a later test-hardening pass; no production behavior gap was found in this bounded slice. - This closes the review gate for this slice only. It is not approval of the full migration, semantic parity, or production readiness. ## Remaining migration boundary This is a fail-closed guard, not Zep removal or semantic parity proof. Remaining work includes complete local consumer cutover, parity fixtures, durable resource persistence, production workers/object storage, and the full tenant E2E matrix.