Context
Operator V-B-A surfaced 2026-05-20: resources/content/discussions/**/discussion-*.md now carries closed / closedAt frontmatter after #11554 / #11573, but resources/content/sandman_handoff.md still ranked closed Discussions in the Computed Golden Path top 5.
This ticket exists because the producer-side sync fix is present, but the graph consumer still appears to ignore the new lifecycle state.
Duplicate sweep:
- #9809 added Discussion nodes to the Golden Path, but it predates discussion closed-state frontmatter and treated active Discussions as the target problem.
- #11554 synced
closed / closedAt to Discussion markdown.
- #11573 fixed metadata persistence / frontmatter integrity so the fields actually land in synced markdown.
- No existing ticket found for the downstream
IssueIngestor / Golden Path consumer still forcing Discussion nodes open.
The Problem
Closed Discussions are still represented in the Native Edge Graph as state: 'OPEN', so the Golden Path ranking can promote already-graduated / closed archaeological discussions as active next work.
Empirical sample from the current checkout:
<h1 class="neo-h1" data-record-id="4">resources/content/discussions/chunk-1/discussion-11168.md</h1>
closed: true
closedAt: '2026-05-11T00:19:55Z'
But Memory Core graph lookup currently reports:
{"id":"discussion-11168","type":"DISCUSSION","state":"OPEN"}
The same mismatch appears for discussion-10520 (closed: true on disk; graph node state OPEN). Both appeared in the Golden Path top 5 in the current sandman_handoff.md output.
The Architectural Reality
DiscussionSyncer now emits the lifecycle fields correctly:
ai/services/github-workflow/sync/DiscussionSyncer.mjs:242-250 writes closed and closedAt into frontmatter.
IssueIngestor is the graph projection surface for Discussions:
ai/daemons/services/IssueIngestor.mjs:265-349 reads resources/content/discussions and upserts DISCUSSION nodes.
IssueIngestor.mjs:308-315 currently hard-codes every Discussion node to state: 'OPEN' with the comment: Discussions are treated as perpetually open for semantic traversal.
GoldenPathSynthesizer then filters candidate nodes by open state:
ai/daemons/services/GoldenPathSynthesizer.mjs:190-202 selects only nodes whose $.properties.state or $.state is OPEN.
Therefore the sync layer carries the truth, but graph projection overwrites the lifecycle state before the ranking query sees it.
The Fix
Teach IssueIngestor.ingestDiscussionStates() to derive Discussion graph state from frontmatter:
meta.closed === true -> graph state: 'CLOSED' and properties.closed = true, properties.closedAt = meta.closedAt || null.
- otherwise -> graph
state: 'OPEN' and properties.closed = false, properties.closedAt = null.
- Preserve
category, updatedAt, and title behavior.
- Ensure the vector metadata for Discussions carries lifecycle metadata where useful (
closed, closedAt, type: 'DISCUSSION') so future graph/vector consumers do not re-derive from raw markdown.
- Add regression coverage that a closed Discussion markdown fixture does not become an OPEN graph candidate.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback / Edge Case |
Docs |
Evidence |
IssueIngestor.ingestDiscussionStates() graph node state |
Discussion frontmatter emitted by #11554 / #11573 |
Use closed to set DISCUSSION node state to OPEN or CLOSED |
Missing closed preserves legacy OPEN behavior but records closed: false |
JSDoc / inline comment replacing perpetual-open rationale |
Unit test with open + closed Discussion fixtures |
| Golden Path candidate set |
GoldenPathSynthesizer open-state filter |
Closed Discussion nodes are excluded from actionable top 5 |
Open Discussions still surface normally |
Test description / ticket refs |
Unit test or integration-style focused spec proves closed node is filtered |
sandman_handoff.md operator output |
Native Edge Graph + Golden Path ranking |
Closed archaeological Discussions no longer appear as current strategic recommendations |
Historical closed discussions remain searchable in KB / resources content |
Ticket body and PR body |
Manual post-fix runSandman or targeted synthesizer evidence |
Acceptance Criteria
Out of Scope
- Changing DiscussionSyncer. The producer-side frontmatter fields already exist.
- Removing closed Discussions from the Knowledge Base. Closed discussions remain valuable archaeological context.
- Closing currently open Discussions. This ticket only fixes graph projection and ranking.
- Broad IssueIngestor freshness/cadence changes. The two-stage sync-then-ingest cadence remains separate.
Avoided Traps
- Dropping closed Discussions entirely. Rejected: closed discussions still carry design archaeology and should remain searchable. They just should not rank as active Golden Path work.
- Changing GoldenPathSynthesizer to special-case IDs. Rejected: the ranking layer already has a state filter; the bug is that the graph projection lies about Discussion state.
- Reintroducing a
state enum into DiscussionSyncer. Rejected: GitHub Discussions expose closed / closedAt; the graph projection can translate that into the graph's OPEN / CLOSED state convention.
Related
- #9809 — original Discussion-to-Golden-Path ingestion.
- #11554 — sync
closed / closedAt to Discussion frontmatter.
- #11573 — post-merge verification gap and sync metadata persistence fix.
resources/content/sandman_handoff.md current Golden Path output.
Origin Session ID: d13c94dd-e721-4e28-ac9e-4d0b3c0f66de
Handoff Retrieval Hint: query_raw_memories("closed Discussions Golden Path IssueIngestor state OPEN sandman_handoff")
Context
Operator V-B-A surfaced 2026-05-20:
resources/content/discussions/**/discussion-*.mdnow carriesclosed/closedAtfrontmatter after #11554 / #11573, butresources/content/sandman_handoff.mdstill ranked closed Discussions in the Computed Golden Path top 5.This ticket exists because the producer-side sync fix is present, but the graph consumer still appears to ignore the new lifecycle state.
Duplicate sweep:
closed/closedAtto Discussion markdown.IssueIngestor/ Golden Path consumer still forcing Discussion nodes open.The Problem
Closed Discussions are still represented in the Native Edge Graph as
state: 'OPEN', so the Golden Path ranking can promote already-graduated / closed archaeological discussions as active next work.Empirical sample from the current checkout:
<h1 class="neo-h1" data-record-id="4">resources/content/discussions/chunk-1/discussion-11168.md</h1> closed: true closedAt: '2026-05-11T00:19:55Z'But Memory Core graph lookup currently reports:
{"id":"discussion-11168","type":"DISCUSSION","state":"OPEN"}The same mismatch appears for
discussion-10520(closed: trueon disk; graph node stateOPEN). Both appeared in the Golden Path top 5 in the currentsandman_handoff.mdoutput.The Architectural Reality
DiscussionSyncernow emits the lifecycle fields correctly:ai/services/github-workflow/sync/DiscussionSyncer.mjs:242-250writesclosedandclosedAtinto frontmatter.IssueIngestoris the graph projection surface for Discussions:ai/daemons/services/IssueIngestor.mjs:265-349readsresources/content/discussionsand upsertsDISCUSSIONnodes.IssueIngestor.mjs:308-315currently hard-codes every Discussion node tostate: 'OPEN'with the comment:Discussions are treated as perpetually open for semantic traversal.GoldenPathSynthesizerthen filters candidate nodes by open state:ai/daemons/services/GoldenPathSynthesizer.mjs:190-202selects only nodes whose$.properties.stateor$.stateisOPEN.Therefore the sync layer carries the truth, but graph projection overwrites the lifecycle state before the ranking query sees it.
The Fix
Teach
IssueIngestor.ingestDiscussionStates()to derive Discussion graph state from frontmatter:meta.closed === true-> graphstate: 'CLOSED'andproperties.closed = true,properties.closedAt = meta.closedAt || null.state: 'OPEN'andproperties.closed = false,properties.closedAt = null.category,updatedAt, and title behavior.closed,closedAt,type: 'DISCUSSION') so future graph/vector consumers do not re-derive from raw markdown.Contract Ledger Matrix
IssueIngestor.ingestDiscussionStates()graph node stateclosedto setDISCUSSIONnode state toOPENorCLOSEDclosedpreserves legacyOPENbehavior but recordsclosed: falseGoldenPathSynthesizeropen-state filtersandman_handoff.mdoperator outputrunSandmanor targeted synthesizer evidenceAcceptance Criteria
IssueIngestor.ingestDiscussionStates()mapsmeta.closed === truetostate: 'CLOSED'instead of hard-codedOPEN.closedandclosedAtso graph inspection exposes the lifecycle state.discussion-11168anddiscussion-10520are corrected after the next graph ingestion / Sandman run.Out of Scope
Avoided Traps
stateenum into DiscussionSyncer. Rejected: GitHub Discussions exposeclosed/closedAt; the graph projection can translate that into the graph'sOPEN/CLOSEDstate convention.Related
closed/closedAtto Discussion frontmatter.resources/content/sandman_handoff.mdcurrent Golden Path output.Origin Session ID: d13c94dd-e721-4e28-ac9e-4d0b3c0f66de Handoff Retrieval Hint:
query_raw_memories("closed Discussions Golden Path IssueIngestor state OPEN sandman_handoff")