LearnNewsExamplesServices
Frontmatter
id13672
titleHarden the session-summary churn-gate timestamp edges (future-skew + unparseable-ts)
stateClosed
labels
bugaimodel-experience
assigneesneo-opus-vega
createdAtJun 20, 2026, 11:26 PM
updatedAtJun 20, 2026, 11:46 PM
githubUrlhttps://github.com/neomjs/neo/issues/13672
authorneo-opus-vega
commentsCount0
parentIssue13647
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 20, 2026, 11:46 PM

Harden the session-summary churn-gate timestamp edges (future-skew + unparseable-ts)

Closed v13.1.0/archive-v13-1-0-chunk-4 bugaimodel-experience
neo-opus-vega
neo-opus-vega commented on Jun 20, 2026, 11:26 PM

Context

Carved from #13647 (parent; epic #13624; the gate itself is #13637's churn-gate, delivered by #13645) so the delivering PR has an honest close-target. The churn-gate in findSessionsToSummarize (ai/services/memory-core/SessionService.mjs) has two timestamp edge-cases, flagged by @neo-opus-ada in the #13645 review.

Live latest-open sweep: checked the latest 12 open issues at ~2026-06-20T21:20Z — no equivalent found.

The Problem

  • Future-skew (correctness bug): the gate skips a session while (nowMs - lastActivity) < churnCooldownMs. A clock-drifted memory (plausible across multi-machine / multi-tenant deployments) yields lastActivity > nowMs → the difference is negative → always < cooldown → the session is gated forever and never summarized (lost summarization).
  • Unparseable timestamp: an unparseable/missing timestamp resolves to lastActivity = 0 (falsy) → it bypasses the gate and stays eligible. That is the correct fail-open, but it was undocumented.

The Architectural Reality

findSessionsToSummarize builds per-session lastActivity via resolveGraphTimestampMs (returns null for unparseable). The churn-gate compares nowMs - lastActivity against swarmHeartbeat.idleThresholdMs.

The Fix

  • Add an idleMs >= 0 guard so a future-skewed timestamp is treated as eligible (summarize once) rather than perpetually gated.
  • Document the unparseable-ts fail-open (lastActivity = 0 → bypass).

Decision Record impact

none — pure correctness hardening of the existing gate; no config/API change.

Acceptance Criteria

  • A future-skewed session (lastActivity > now) is eligible, not perpetually gated.
  • The unparseable-ts fail-open is documented.
  • Unit tests (future-skew eligible; unparseable fails open) in SessionService.ChurnCooldown.spec.mjs.

Out of Scope

  • The marker archived-filter (#13667 / PR #13668).
  • The 45 projection-lag + the axis-3 archival.

Related

Parent: #13647. Epic: #13624. The gate: #13637 (delivered by #13645).

Origin Session ID: c4fcedd0-c449-4f8c-b368-e3ac0c0509ff Retrieval Hint: "findSessionsToSummarize churn-gate future-skew idleMs guard unparseable timestamp fail-open #13647"