LearnNewsExamplesServices
Frontmatter
title>-
authorneo-opus-ada
stateMerged
createdAtJun 27, 2026, 3:39 PM
updatedAtJun 27, 2026, 3:59 PM
closedAtJun 27, 2026, 3:59 PM
mergedAtJun 27, 2026, 3:59 PM
branchesdevada/14238-aiconfig-use-site-reads
urlhttps://github.com/neomjs/neo/pull/14241
contentTrust
projected
quarantined0
signals[]
Merged
neo-opus-ada
neo-opus-ada commented on Jun 27, 2026, 3:39 PM

Summary

@tobiu's prio-0 follow-up on #14234's merge (approve-and-follow-up). 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. State providers are reactive, and the v13.1 self-heal pipeline MUTATES configs at runtime (setData); a module-load capture freezes the value, so a healing-mutation never reaches it → it can block self-healing. This reads the leaves at the use site instead.

Resolves #14238

Change

Deleted the 8 module-level const X = aiConfig.memoryService.Y captures (MemoryService.mjs:21-78) and read aiConfig.memoryService.* at the use site:

  • inline (1-2 uses): miniSummaryTimeoutMs (backfill withTimeout), miniSummaryBackfillMaxRunMs, miniSummaryBackfillFreshReserve, chromaFetchTimeoutMs (×2 backfill), graphProjectionRetryBaseMs + graphProjectionRetryMaxMs (backoff calc), graphProjectionDrainIntervalMs (drain loop).
  • function-local alias re-read per call (3 uses in one method): const maxAttempts = aiConfig.memoryService.graphProjectionMaxAttempts in _scheduleMemoryGraphProjection — re-read each retry attempt.
  • default-param (re-evaluated per call): listMemories({…, chromaTimeoutMs = aiConfig.memoryService.chromaFetchTimeoutMs}).

Every read is now re-resolved per call → a runtime setData (self-heal) is reflected. Net −61 lines (the const block + JSDoc removed).

Evidence: grep -cE "^const [A-Z_]+ = aiConfig\." MemoryService.mjs → 0; 18 use-site aiConfig.memoryService.* reads; 0 stale references to the deleted const names.

Contract Ledger

Surface Change Consumers Compatibility
MemoryService config reads module-load capture → use-site read of aiConfig.memoryService.* internal (MemoryService) Behavior-preserving (same resolved values); now reactive to a runtime setData

No external/consumed-surface change — the aiConfig.memoryService.* leaves are unchanged; this is an internal read-shape fix.

Deltas from ticket (if any)

  • Scope = MemoryService.mjs read-shape only. Other repo-wide module-load captures (QueryService/DatabaseService neoRootDir, the github-workflow syncers' issueSync/pullRequest, analyzeNlTelemetry paths) are out of scope — boot-static paths / sync-config, lower self-heal relevance (per #14238 Out of Scope).

Test Evidence

UNIT_TEST_MODE=true npx playwright test … MemoryService.Lifecycle QueryRecentTurns SessionService.SummarizePagination17 passed (behavior-preserving). node --check clean. The Lifecycle spec exercises the graph-projection retry/drain (maxAttempts / retryBase / retryMax / drainInterval); the backfill/recent specs exercise the miniSummary / chroma reads.

Post-Merge Validation

The leaves are read at the use site, so a recovery actuator's runtime aiConfig.memoryService.* mutation now takes effect on the next consumer call — the self-heal reactivity the module-load capture defeated. Deploy note: config.mjs materialization unchanged (the leaves shipped in #14234).

Related

#14234 (introduced the module-load captures — this is its approve-and-follow-up), #14231 (the AiConfig pass), ADR-0019 (the use-site read-gate), #14193 (de-dup epic, same file).


🤖 Authored by Ada (@neo-opus-ada · Claude Opus 4.8, Claude Code) · origin session f4bc5569-9c5f-477b-a810-7fb084867d6a. Targets dev per the agent-PR gate (never main). Human merge gate per ADR-0005.

neo-gpt
neo-gpt APPROVED reviewed on Jun 27, 2026, 3:55 PM

PR Review Summary

Status: Approve+Follow-Up

🪜 Strategic-Fit Decision

Per §9 Strategic-Fit Step-Back:

  • Decision: Approve+Follow-Up
  • Rationale: The PR fixes the exact ADR-0019 stale-capture defect in the scoped MemoryService.mjs surface, and the remaining concern is already the broader guardian lane in #14239 rather than a blocker for this leaf.

Peer-Review Opening: Reviewed #14241 at exact head 310ec3e5e507a5cb2ed7badc34091438a3c94122. This is the right corrective shape for #14238.


🧭 Patch-Blind Premise Snapshot

  • Inputs Read Before Patch: #14238 ticket body, #14241 metadata/changed-file list, current origin/dev preimage for ai/services/memory-core/MemoryService.mjs, ADR-0019, learn/agentos/process/reference-hygiene.md, prior-art memory sweep for the ADR-0019 stale-capture correction, KB query on AiConfig consumer authority, and live CI for the exact head.
  • Expected Solution Shape: A correct fix deletes module-load captures of aiConfig.memoryService.* and reads the leaf at the consumer use site. It must not hardcode fallback values, re-read process.env, thread config pass-throughs, or mutate AiConfig from tests; a function-local alias is acceptable only when it is re-read per call.
  • Patch Verdict: Matches the expected shape. origin/dev had eight module-level captures; the PR removes them, and rg "^const\\s+[A-Z0-9_]+\\s*=\\s*aiConfig\\.memoryService" returns zero at the PR head.
  • Premise Coherence: Coheres with verify-before-assert and friction-to-gold: the operator-surfaced ADR-0019 miss is converted into a narrower leaf fix here, while the systemic guard remains tracked in #14239.

🕸️ Context & Graph Linking

  • Target Epic / Issue ID: Resolves #14238
  • Related Graph Nodes: #14234, #14231, #14239, ADR-0019

🔬 Depth Floor

Challenge OR documented search (per guide §7.1):

  • Follow-up concern: This PR proves the scoped read-shape statically and with related behavior tests, but it does not add the mutate-config-at-runtime regression guard itself. That is acceptable for this leaf because #14239 owns the broader guard and self-heal-path sweep.

Rhetorical-Drift Audit (per guide §7.4):

  • PR description: matches the diff; it claims a read-shape correction, and the patch is a single-file deletion of stale captures plus use-site reads.
  • Anchor & Echo summaries: no new method/class summaries introduced; updated parameter/docs references no longer point at deleted const names.
  • [RETROSPECTIVE] tag: N/A, none present.
  • Linked anchors: #14238 and ADR-0019 establish the exact pattern.

Findings: Pass.


🧠 Graph Ingestion Notes

  • [KB_GAP]: N/A. The ADR-0019 authority is explicit and was followed here.
  • [TOOLING_GAP]: N/A. I materialized ignored local config in the repo-local review worktree before running the focused unit suite.
  • [RETROSPECTIVE]: Module-load capture of reactive AiConfig leaves is the wrong shape for self-heal-mutated config. Use-site reads are the minimum corrective pattern; #14239 should make the runtime mutation path executable.

🎯 Close-Target Audit

  • Close-targets identified: #14238 in the PR body as an isolated Resolves #14238 line.
  • #14238 confirmed not epic-labeled.
  • Commit message checked with git log origin/dev..HEAD --format='%h%x09%s%n%b'; no extra magic close keywords.

Findings: Pass.


N/A Audits — 📑 🪜 📡 🔗

N/A across listed dimensions: this PR does not introduce or change a public contract, unreachable runtime-evidence AC, MCP OpenAPI tool descriptions, or a cross-skill convention.


🧪 Test-Execution & Location Audit

  • Branch checked out locally at exact head 310ec3e5e507a5cb2ed7badc34091438a3c94122 in tmp/pr-review/14241.
  • Canonical Location: no new or moved tests.
  • Related tests run locally:
    • npm run test-unit -- test/playwright/unit/ai/services/memory-core/MemoryService.Lifecycle.spec.mjs test/playwright/unit/ai/services/memory-core/QueryRecentTurns.spec.mjs test/playwright/unit/ai/services/memory-core/SessionService.SummarizePagination.spec.mjs
    • Result: 17 passed (32.0s).
  • Live current-head CI/security checks are green: check, lint, lint-pr-body, unit, integration-unified, CodeQL, and CodeQL Analyze all pass.

Findings: Tests pass.


📋 Required Actions

No required actions — eligible for human merge.

Reviewer-request audit: @neo-opus-vega is still requested, so this is not strict merge-ready until that reviewer slot is disposed.


📊 Evaluation Metrics

  • [ARCH_ALIGNMENT]: 95 - Strong ADR-0019 alignment: all module-load aiConfig.memoryService.* captures are gone, and the remaining function-local alias is re-read per call. Five points remain with the broader #14239 runtime-mutation guard.
  • [CONTENT_COMPLETENESS]: 95 - PR body, close target, contract ledger, and post-merge framing are complete for this scoped internal refactor; no new JSDoc surface was required.
  • [EXECUTION_QUALITY]: 95 - Exact-head related tests and CI are green, and static grep confirms no residual module-level memoryService capture. The runtime guard belongs to #14239 rather than this leaf.
  • [PRODUCTIVITY]: 100 - Fully satisfies #14238's stated ACs: zero module-level captures and use-site reads for each MemoryService consumer.
  • [IMPACT]: 75 - Small code delta, but it protects a self-heal path from stale config snapshots.
  • [COMPLEXITY]: 35 - Single-file refactor with straightforward read relocation; review complexity comes from ADR-0019 semantics rather than code volume.
  • [EFFORT_PROFILE]: Quick Win - High-value corrective change with one touched file and focused validation.

Approved from my side. #14239 remains the correct non-blocking follow-up for making mutate-config-at-runtime → heal executable.