Current Verified State (2026-06-06)
This issue was originally filed for two Memory Core defects:
StorageRouter.injectQueryReRanker() crashed when ChromaDB query results were empty, malformed, or failed during embedding.
SessionService.findSessionsToSummarize() selected the current in-process session for summarization when the summary was missing.
Those original defects are already resolved by merged PR #9960 (merged 2026-04-13). Current source confirms:
ai/services/memory-core/managers/StorageRouter.mjs wraps Pass 1 semantic retrieval in try/catch, logs fallback, and reads searchResult?.ids?.[0].
ai/services/memory-core/SessionService.mjs excludes sessionId === this.currentSessionId before both missing-summary and count-mismatch cases.
test/playwright/unit/ai/services/memory-core/QueryReRanker.spec.mjs covers the defensive re-ranker path and in-process active-session exclusion.
The remaining live bug is narrower: periodic child-process summarization can still select sessions that are active in another harness or MCP process, because the child process has no request-bound session context for those externally active sessions.
Problem
The orchestrator summary task runs ai/scripts/lifecycle/summarize-sessions.mjs as a spawned child process:
ai/daemons/orchestrator/TaskDefinitions.mjs points the summary task at summarize-sessions.mjs.
summarize-sessions.mjs initializes Memory_SessionService in the child process and calls summarizeSessions({ includeAll: false }).
findSessionsToSummarize() excludes only this.currentSessionId, which resolves to RequestContextService.getSessionId() || this._legacySessionId.
In the spawned child path, this.currentSessionId is the child process's local legacy/request session, not the session IDs currently accumulating memories in other live harnesses. A periodic sweep can therefore see memory-count drift for an active external session and re-summarize it repeatedly before that session has actually ended.
Impact:
- incomplete mid-flight summaries can be written for still-running sessions;
- LLM summarization tokens are spent on active sessions rather than completed work;
- future agents may retrieve stale or partial summaries while the raw memory stream is still growing.
Accepted Scope
Define and implement a cross-process active-session predicate for periodic drift-detection summarization.
This ticket is about automatic periodic sweeps. Explicit/manual summarization of a named sessionId must remain allowed when deliberately requested.
Contract Ledger
| Surface |
Contract |
SessionService.findSessionsToSummarize(includeAll = false) |
Must exclude sessions that are active in another harness/process, not only the child process currentSessionId. The predicate must be source-backed and testable. |
SessionService.summarizeSessions({ includeAll, sessionId }) |
Explicit sessionId summarization remains intentional and may summarize the active session when the caller names it directly. The cross-process skip applies only to drift-detection candidate selection. |
ai/scripts/lifecycle/summarize-sessions.mjs |
Periodic child-process summarization must use the same skip predicate before broad drift summarization. Pending explicit jobs may still drain through their existing explicit-session path. |
SummarizationJobs / resume state |
Do not finalize or mark a still-active session as completed merely because a periodic child processed it. Preserve resume_session semantics and cross-check the pending-aware summarization barrier from #11676. |
| Observability |
Logs or returned summaries should make it clear when a drift candidate was skipped because it is externally active. |
| Tests |
Add focused coverage for a no-request-context child-process shape where a session is active elsewhere, plus a counter-test proving explicit summarizeSessions({ sessionId }) still works. |
Acceptance Criteria
Out of Scope
- Re-implementing the original StorageRouter re-ranker crash fix from PR #9960.
- Re-implementing the in-process
currentSessionId exclusion from PR #9960.
- Replacing the summarization job coordinator or
SummarizationJobs schema wholesale.
- Changing summary visibility / tenant filtering semantics.
- Running broad full-suite summarization or closing historical sessions manually.
Verification Anchors
- Merged original fix: PR #9960.
- Current revalidation comment: https://github.com/neomjs/neo/issues/9959#issuecomment-4636388490
- Relevant source:
ai/services/memory-core/managers/StorageRouter.mjs
ai/services/memory-core/SessionService.mjs
ai/scripts/lifecycle/summarize-sessions.mjs
ai/daemons/orchestrator/TaskDefinitions.mjs
test/playwright/unit/ai/services/memory-core/QueryReRanker.spec.mjs
Origin Session IDs:
- Original issue:
598f1a53-952e-4356-8c6f-ada3e71b6152
- 2026-05-27 revalidation:
6ca1b510-51c3-4fac-aa39-a0fd6941318c
Current Verified State (2026-06-06)
This issue was originally filed for two Memory Core defects:
StorageRouter.injectQueryReRanker()crashed when ChromaDB query results were empty, malformed, or failed during embedding.SessionService.findSessionsToSummarize()selected the current in-process session for summarization when the summary was missing.Those original defects are already resolved by merged PR #9960 (merged 2026-04-13). Current source confirms:
ai/services/memory-core/managers/StorageRouter.mjswraps Pass 1 semantic retrieval intry/catch, logs fallback, and readssearchResult?.ids?.[0].ai/services/memory-core/SessionService.mjsexcludessessionId === this.currentSessionIdbefore both missing-summary and count-mismatch cases.test/playwright/unit/ai/services/memory-core/QueryReRanker.spec.mjscovers the defensive re-ranker path and in-process active-session exclusion.The remaining live bug is narrower: periodic child-process summarization can still select sessions that are active in another harness or MCP process, because the child process has no request-bound session context for those externally active sessions.
Problem
The orchestrator summary task runs
ai/scripts/lifecycle/summarize-sessions.mjsas a spawned child process:ai/daemons/orchestrator/TaskDefinitions.mjspoints thesummarytask atsummarize-sessions.mjs.summarize-sessions.mjsinitializesMemory_SessionServicein the child process and callssummarizeSessions({ includeAll: false }).findSessionsToSummarize()excludes onlythis.currentSessionId, which resolves toRequestContextService.getSessionId() || this._legacySessionId.In the spawned child path,
this.currentSessionIdis the child process's local legacy/request session, not the session IDs currently accumulating memories in other live harnesses. A periodic sweep can therefore see memory-count drift for an active external session and re-summarize it repeatedly before that session has actually ended.Impact:
Accepted Scope
Define and implement a cross-process active-session predicate for periodic drift-detection summarization.
This ticket is about automatic periodic sweeps. Explicit/manual summarization of a named
sessionIdmust remain allowed when deliberately requested.Contract Ledger
SessionService.findSessionsToSummarize(includeAll = false)currentSessionId. The predicate must be source-backed and testable.SessionService.summarizeSessions({ includeAll, sessionId })sessionIdsummarization remains intentional and may summarize the active session when the caller names it directly. The cross-process skip applies only to drift-detection candidate selection.ai/scripts/lifecycle/summarize-sessions.mjsSummarizationJobs/ resume stateresume_sessionsemantics and cross-check the pending-aware summarization barrier from #11676.summarizeSessions({ sessionId })still works.Acceptance Criteria
currentSessionId.summarizeSessions({ sessionId })semantics are preserved.Out of Scope
currentSessionIdexclusion from PR #9960.SummarizationJobsschema wholesale.Verification Anchors
ai/services/memory-core/managers/StorageRouter.mjsai/services/memory-core/SessionService.mjsai/scripts/lifecycle/summarize-sessions.mjsai/daemons/orchestrator/TaskDefinitions.mjstest/playwright/unit/ai/services/memory-core/QueryReRanker.spec.mjsOrigin Session IDs:
598f1a53-952e-4356-8c6f-ada3e71b61526ca1b510-51c3-4fac-aa39-a0fd6941318c