LearnNewsExamplesServices
Frontmatter
id12655
titleSandman handoff: cap sections (GP 10, others 5) + bare issue refs
stateClosed
labels
bugaiperformancemodel-experience
assigneesneo-opus-grace
createdAtJun 6, 2026, 10:54 PM
updatedAtJun 6, 2026, 11:39 PM
githubUrlhttps://github.com/neomjs/neo/issues/12655
authorneo-opus-grace
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 6, 2026, 11:39 PM

Sandman handoff: cap sections (GP 10, others 5) + bare issue refs

Closed v13.0.0/archive-v13-0-0-chunk-16 bugaiperformancemodel-experience
neo-opus-grace
neo-opus-grace commented on Jun 6, 2026, 10:54 PM

Context

Operator-flagged this session (2026-06-06): the Sandman strategic-priming handoff (resources/content/sandman_handoff.md, generated by GoldenPathSynthesizer and parsed by ai/agent/AgentOrchestrator.mjs into every headless agent's context) has bloated into a token drain. Two compounding issues: oversized per-section render limits and full GitHub-URL hyperlinks on every issue/PR row.

Live latest-open sweep: checked latest 20 open issues 2026-06-06; no equivalent found (#10275 is the closed Silent-Threads feature itself; #10120 is a different Golden-Path concern).

The Problem

The handoff is always-injected priming content — every row costs every primed agent tokens that compete with reasoning budget. Current state:

  • Section limits too high vs the 5-row convention: goldenPathStaleAssignmentRenderLimit = 20, goldenPathSilentThreadRenderLimit = 10. Shipped oversized via the Silent-Threads (#12603) + Stale-Assignments (#12125) sections. (Note: slice(0, undefined) returns the entire array, so a stale local config.mjs lacking these leaves renders genuinely unbounded — the worst case for a budget control.)
  • Full URL hyperlinks: [#N](https://github.com/neomjs/neo/issues/N) per issue row + [title](url) per PR row — ~73 full URLs in a representative handoff. The bare #N is sufficient (agents resolve repo context); the URL is pure token waste.
  • Golden Path itself under-rendered: the main priority list is hardcoded to 5; it is the one section that warrants more depth (top 10).

The Architectural Reality

  • Render limits are AiConfig leaves in ai/mcp/server/memory-core/config.template.mjs (goldenPathStaleAssignmentRenderLimit ~L227, goldenPathSilentThreadRenderLimit ~L244, goldenPathRecentOpenPrRenderLimit ~L249 already 5).
  • ai/services/graph/GoldenPathSynthesizer.mjs: issueRef ternaries (~L399, ~L644) emit the URL form; PR rows (~L697, ~L1174) use [title](url); the Golden-Path main list hardcodes .slice(0, 5) (~L879).
  • Consumer: AgentOrchestrator.mjs parses the handoff into a headless agent loop → fewer/shorter rows = direct per-agent token savings.

The Fix

  1. config.template.mjs (memory-core): goldenPathStaleAssignmentRenderLimit 20 → 5; goldenPathSilentThreadRenderLimit 10 → 5; add goldenPathTopNodeRenderLimit = 10 (env NEO_GOLDEN_PATH_TOP_NODE_RENDER_LIMIT).
  2. GoldenPathSynthesizer.mjs: Golden-Path main .slice(0, 5).slice(0, aiConfig.goldenPathTopNodeRenderLimit); issueRef → bare `#${candidate.number}` (both sites); PR rows → drop the (url) hyperlink, keep PR #N + title.
  3. No defensive ?? <n> on the leaf reads — the SSOT leaf is authoritative.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Evidence
goldenPathStaleAssignmentRenderLimit this ticket / operator default 20 → 5 env override unchanged GoldenPathSynthesizer spec
goldenPathSilentThreadRenderLimit this ticket / operator default 10 → 5 env override unchanged spec
goldenPathTopNodeRenderLimit (NEW) this ticket / operator default 10; Golden-Path main cap env NEO_GOLDEN_PATH_TOP_NODE_RENDER_LIMIT spec
GoldenPathSynthesizer issue/PR row format this ticket / operator bare #N / PR #N (no hyperlink) n/a rendered-handoff diff

Decision Record impact

aligned-with ADR 0019 (AiConfig reactive Provider SSOT — read resolved leaves at use site, no defensive re-reads).

Acceptance Criteria

  • goldenPathStaleAssignmentRenderLimit default = 5; goldenPathSilentThreadRenderLimit default = 5.
  • goldenPathTopNodeRenderLimit leaf added (default 10); Golden-Path main renders up to 10.
  • All issue rows render bare #N (no [#N](url)); all PR rows drop the URL hyperlink (title kept).
  • No defensive ?? <n> fallback added on the leaf reads.
  • GoldenPathSynthesizer unit tests pass; a regenerated handoff shows ≤5 Stale-Assignment + ≤5 Silent-Thread rows, ≤10 Golden-Path rows, and zero https://github.com/ URLs.

Out of Scope

  • The #12612 idle-out wake-digest cycle-state enrichment (separate lane — same golden-path/graph content, but the daemon digest path, not the handoff render).
  • The Silent-Threads / Stale-Assignments selection logic (thresholds, scoring) — render caps + format only.
  • The operator's local config.mjs overlay (gitignored; updated out-of-band).

Avoided Traps

  • Don't add a ?? 5 defensive fallback on the leaf read — that's the B3 AiConfig-defense antipattern removed in #12461. A missing leaf is a config-regen problem, not a render-time guard.
  • Don't hardcode the Golden-Path cap — make it a leaf, consistent with its 3 sibling render-limit leaves.
  • Don't strip issue/PR titles — the token waste is the URL, not the human-readable title.

Related

  • #12603 (silent threads, limit 10) + #12125 (stale assignments, limit 20) — introduced the oversized sections.
  • #12612 — sibling idle-out wake-digest re-scope (separate lane).

Origin Session ID: 4c567b8a-c0ac-447a-901b-5369ed4449d5

Handoff Retrieval Hint: "golden path sandman handoff render limit caps bare issue refs token bloat"

tobiu referenced in commit 9527703 - "fix(ai): cap Sandman handoff sections (GP 10/others 5) + bare issue refs (#12655) (#12656) on Jun 6, 2026, 11:39 PM
tobiu closed this issue on Jun 6, 2026, 11:39 PM