LearnNewsExamplesServices
Frontmatter
id15035
titleExpose Discussion sync exhaustion before temporal-summary enablement
stateOpen
labels
enhancementaitestingarchitecture
assigneesneo-gpt
createdAt2:17 PM
updatedAt2:33 PM
githubUrlhttps://github.com/neomjs/neo/issues/15035
authorneo-gpt
commentsCount0
parentIssue12679
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]

Expose Discussion sync exhaustion before temporal-summary enablement

Open Backlog/active-chunk-5 enhancementaitestingarchitecture
neo-gpt
neo-gpt commented on 2:17 PM

Context

The exact-head convergence review of PR #15016 found that the temporal-summary aggregation service is correctly reading the repo-tracked Discussion mirror, but the mirror producer cannot prove that each conversation is complete.

The live source path is:

DiscussionSyncerFETCH_DISCUSSIONS_FOR_SYNC / FETCH_SINGLE_DISCUSSION_FOR_SYNC → repo-tracked Markdown → TemporalSummaryAggregationService.fetchSandboxesGraduated().

At current dev, both bulk sync and force-refetch hard-cap nested connections at 50 comments and 20 replies. The GraphQL selections expose neither nested pageInfo nor totalCount, so the renderer cannot distinguish an exhausted conversation from a silently truncated one. A corpus census on 2026-07-11 found 92 synced Discussion files and a current maximum of 33 top-level comments, so no present mirror is known to cross the cap. The missing invariant is still a prerequisite for runtime enablement: absence of a graduation action must not become a confidently wrong numeric zero.

The terminal review also isolated one consumer-side completeness edge: extractGraduationActions currently toggles one Boolean for either backtick or tilde fences, so a mixed delimiter inside an open fence can expose a marker that is still code. Two stale temporalSummarySchema.mjs sentences also describe every re-fold as minting a new document, contradicting the implemented same-version deterministic overwrite. Because the lane remains disabled, these bounded residuals join this same pre-enablement gate instead of creating another author cycle.

The Problem

The temporal aggregation lane must count exact graduation author-actions by their event timestamps. Its owning service can parse the synced Markdown, but it cannot paginate GitHub or infer whether the upstream mirror stopped early.

Coupling the aggregation service to today's 50/20 constants would move the bug across the service boundary and turn cap equality into a brittle completeness heuristic. The sync producer must either exhaust nested comment/reply connections or emit explicit, structured incompleteness evidence. The consumer must fail closed when that evidence is absent or false.

The Architectural Reality

  • ai/services/github-workflow/sync/DiscussionSyncer.mjs:323-331 and :499-512 own bulk and force-refetch materialization and currently pass maxComments: 50 / maxReplies: 20.
  • ai/services/github-workflow/queries/discussionQueries.mjs:137-182 and :229-248 paginate only the outer Discussion list; nested comments/replies are bounded first: connections without exhaustion metadata.
  • ai/daemons/temporal-summary/TemporalSummaryAggregationService.mjs:176-204,323-352 is the downstream consumer. It must validate mirror completeness, not re-query GitHub.
  • The Agent OS structure map confirms these are existing owner surfaces; no new daemon, scheduler, or collection is needed.
  • ADR 0028 and the #14938 graduation-metric contract require complete-or-fail-closed evidence before temporal-summary runtime enablement.

The Fix

  1. Extend the Discussion sync query/result contract so nested comments and replies expose exhaustion state (pageInfo / totalCount) and can be fully fetched.
  2. Make both bulk sync and force-refetch converge on the same nested-pagination primitive before rendering Markdown.
  3. Persist a stable structured completeness signal in each Discussion artifact, e.g. conversationComplete: true only after both nested connections are exhausted. Include observed/total counts when useful for diagnosis.
  4. Teach TemporalSummaryAggregationService to reject incomplete or legacy-unknown Discussion evidence before folding sandboxesGraduated; never convert incompleteness into zero.
  5. Re-materialize existing Discussion artifacts before enabling the temporal-summary lane.
  6. Track the opening fence delimiter kind/length in extractGraduationActions; only a matching closer may end the fence. Add mixed backtick/tilde falsifiers.
  7. Align the remaining schema-level version JSDoc with the material-contract rule: same window+track+version keeps one deterministic id; only a material version bump mints a new append-only id.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
Discussion sync GraphQL result GitHub nested connection semantics + discussionQueries.mjs Expose and exhaust comment/reply pagination state Mark conversation incomplete; never imply exhaustion query JSDoc >50-comment and >20-reply fixtures
Synced Discussion frontmatter DiscussionSyncer#renderDiscussionMarkdown Carry explicit conversation-completeness evidence for bulk and refetch paths Missing/false means unknown/incomplete renderer JSDoc + sync guide serialized-artifact contract spec
fetchSandboxesGraduated source gate ADR 0028 + #14938 complete-or-fail-closed contract Fold only artifacts proven complete Reject the window/source; never emit a numeric zero service JSDoc incomplete/legacy artifact falsifiers
Temporal-summary enablement AiConfig.temporalSummary.aggregationEnabled Remain disabled until the completeness contract and artifact refresh land Disabled by default config/PR evidence exact-head integration witness

Decision Record impact

aligned-with ADR 0028; no amendment required. This ticket completes an existing evidence boundary at its owning sync layer.

Acceptance Criteria

  • Bulk Discussion sync exhausts or explicitly marks nested comment/reply connections incomplete.
  • Force-refetch uses the same completeness contract as bulk sync.
  • Synced Markdown persists structured completeness evidence without coupling consumers to numeric cap constants.
  • Temporal aggregation fails closed for incomplete or legacy-unknown Discussion artifacts.
  • Focused tests cover more than 50 top-level comments, more than 20 replies, mixed complete/incomplete discussions, and force-refetch parity.
  • Existing Discussion artifacts are re-synced or migrated before temporal-summary runtime enablement.
  • Mixed backtick/tilde fences cannot expose a graduation marker before a matching delimiter closes the block.
  • temporalSummarySchema.mjs consistently documents same-version overwrite versus material-version append-only minting.
  • aggregationEnabled remains false until this ticket lands and the refreshed corpus is verified.

Out of Scope

  • Changing graduation-action grammar beyond matching fence-state correctness.
  • PR/issue conversation pagination.
  • A second temporal-summary scheduler, collection, or live-GitHub read path.
  • UI work.

Avoided Traps

  • No cap-equality heuristic inside the aggregation consumer.
  • No silent fallback from unknown completeness to zero.
  • No separate bulk/refetch render contracts.
  • No micro-ticket split: query, sync artifact, consumer gate, and refresh form one end-to-end evidence lane.

Related

Parent epic: #12679
Related: #14938 · PR #15016
Historical nested-reply cost context: #12190

Live latest-open sweep: checked the latest 20 open issues, all-state GitHub search, repo issue/Discussion content, Knowledge Base tickets, and the latest 30 A2A messages at 2026-07-11T12:12Z; no equivalent active ticket or in-flight claim found.

Origin Session ID: de713f27-0e82-4960-b4c6-f281e0c36449

Retrieval Hint: "DiscussionSyncer nested comment reply exhaustion conversationComplete temporal summary fail closed"