Context
@tobiu (prio-0, on #14234's merge): "state providers are reactive. healing scripts can MUTATE configs at run-time. if you still STORE state provider leaves inside const values, they are stale. this can block self healing. the goal of ADR 19 is to USE AiConfig directly at consumer level." #14234 (the #14231 AiConfig pass) moved MemoryService's config constants into a new aiConfig.memoryService section but captured them as MODULE-LEVEL consts — a stale snapshot a runtime healing-mutation never reaches.
The Problem
The v13.1 self-heal pipeline does setData on AiConfig at runtime to recover (e.g., a recovery actuator adjusting a timeout / retry budget under contention). A module-level const MINI_SUMMARY_TIMEOUT_MS = aiConfig.memoryService.miniSummaryTimeoutMs; is read ONCE at module-load → frozen → the healing-mutation is invisible to it → blocks self-healing. ADR-0019 §2: "READ resolved leaves AT THE USE SITE." B2's "alias only if used 3+ times in one scope" is a FUNCTION-LOCAL alias (re-read per call), NOT a module-level capture (the misread that produced #14234's shape).
The Architectural Reality
8 module-level captures in ai/services/memory-core/MemoryService.mjs:21-78: miniSummaryTimeoutMs, miniSummaryBackfillMaxRunMs, miniSummaryBackfillFreshReserve, chromaFetchTimeoutMs, graphProjectionMaxAttempts, graphProjectionRetryBaseMs, graphProjectionRetryMaxMs, graphProjectionDrainIntervalMs. Use sites: listMemories default-param (:900), backfillMiniSummaries (:1627/:1637/:1662/:1663/:1706), _scheduleMemoryGraphProjection (:590/:600/:601/:606), _startGraphProjectionDrainLoop (:681).
The Fix
Delete the 8 module-level const-defs; read aiConfig.memoryService.* at the use site — inline for 1-2 uses; a function-local alias (re-read per call) for 3+ in one method (graphProjectionMaxAttempts ×3 in _scheduleMemoryGraphProjection); the listMemories default-param chromaTimeoutMs = aiConfig.memoryService.chromaFetchTimeoutMs is use-site (re-evaluated per call). Behavior-preserving (same resolved values).
Decision Record impact
aligned-with ADR-0019 — the use-site read-gate; corrects a B2 misread (module-load capture of a reactive leaf).
Acceptance Criteria
Out of Scope
- Other repo-wide module-load captures (
QueryService/DatabaseService neoRootDir, the github-workflow syncers' issueSync/pullRequest, analyzeNlTelemetry paths) — a separate systemic sweep; those are boot-static paths / sync-config with lower self-heal relevance. File separately if warranted.
Related
#14234 (the PR that introduced the captures), #14231 (the AiConfig pass), #14193 (de-dup epic, same file), ADR-0019 (the use-site read-gate).
Origin Session ID: f4bc5569-9c5f-477b-a810-7fb084867d6a
Authored by Ada (@neo-opus-ada · Claude Opus 4.8, Claude Code).
Context
@tobiu (prio-0, on #14234's merge): "state providers are reactive. healing scripts can MUTATE configs at run-time. if you still STORE state provider leaves inside const values, they are stale. this can block self healing. the goal of ADR 19 is to USE AiConfig directly at consumer level." #14234 (the #14231 AiConfig pass) moved MemoryService's config constants into a new
aiConfig.memoryServicesection but captured them as MODULE-LEVEL consts — a stale snapshot a runtime healing-mutation never reaches.The Problem
The v13.1 self-heal pipeline does
setDataonAiConfigat runtime to recover (e.g., a recovery actuator adjusting a timeout / retry budget under contention). A module-levelconst MINI_SUMMARY_TIMEOUT_MS = aiConfig.memoryService.miniSummaryTimeoutMs;is read ONCE at module-load → frozen → the healing-mutation is invisible to it → blocks self-healing. ADR-0019 §2: "READ resolved leaves AT THE USE SITE." B2's "alias only if used 3+ times in one scope" is a FUNCTION-LOCAL alias (re-read per call), NOT a module-level capture (the misread that produced #14234's shape).The Architectural Reality
8 module-level captures in
ai/services/memory-core/MemoryService.mjs:21-78:miniSummaryTimeoutMs,miniSummaryBackfillMaxRunMs,miniSummaryBackfillFreshReserve,chromaFetchTimeoutMs,graphProjectionMaxAttempts,graphProjectionRetryBaseMs,graphProjectionRetryMaxMs,graphProjectionDrainIntervalMs. Use sites:listMemoriesdefault-param (:900),backfillMiniSummaries(:1627/:1637/:1662/:1663/:1706),_scheduleMemoryGraphProjection(:590/:600/:601/:606),_startGraphProjectionDrainLoop(:681).The Fix
Delete the 8 module-level const-defs; read
aiConfig.memoryService.*at the use site — inline for 1-2 uses; a function-local alias (re-read per call) for 3+ in one method (graphProjectionMaxAttempts×3 in_scheduleMemoryGraphProjection); thelistMemoriesdefault-paramchromaTimeoutMs = aiConfig.memoryService.chromaFetchTimeoutMsis use-site (re-evaluated per call). Behavior-preserving (same resolved values).Decision Record impact
aligned-withADR-0019 — the use-site read-gate; corrects a B2 misread (module-load capture of a reactive leaf).Acceptance Criteria
const X = aiConfig.memoryService.*inMemoryService.mjs.aiConfig.memoryService.*at the use site (inline, or a function-local alias re-read per call) — a runtimesetDatais reflected.Out of Scope
QueryService/DatabaseServiceneoRootDir, the github-workflow syncers'issueSync/pullRequest,analyzeNlTelemetrypaths) — a separate systemic sweep; those are boot-static paths / sync-config with lower self-heal relevance. File separately if warranted.Related
#14234 (the PR that introduced the captures), #14231 (the AiConfig pass), #14193 (de-dup epic, same file), ADR-0019 (the use-site read-gate).
Origin Session ID: f4bc5569-9c5f-477b-a810-7fb084867d6a
Authored by Ada (@neo-opus-ada · Claude Opus 4.8, Claude Code).