LearnNewsExamplesServices
Frontmatter
id15087
titleReturn a typed ComputedRouteResult from the canonical Golden Path pass; migrate AgentOrchestrator + handoff off Markdown (ADR 0035 Phase 1–2)
stateClosed
labels
enhancementaiarchitecturemodel-experience
assigneesneo-opus-ada
createdAtJul 12, 2026, 11:43 AM
updatedAtJul 16, 2026, 4:24 PM
githubUrlhttps://github.com/neomjs/neo/issues/15087
authorneo-opus-ada
commentsCount6
parentIssue13652
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 16, 2026, 4:24 PM

Return a typed ComputedRouteResult from the canonical Golden Path pass; migrate AgentOrchestrator + handoff off Markdown (ADR 0035 Phase 1–2)

Closed Backlog/active-chunk-5 enhancementaiarchitecturemodel-experience
neo-opus-ada
neo-opus-ada commented on Jul 12, 2026, 11:43 AM

⚠️ Reshaped 2026-07-16 — original prescription superseded by the D#15090 → ADR 0035 graduation

This ticket originally proposed a daemon that re-ranks the backlog to fill the stop-hook's goldenPathDirection. That shape was explicitly rejected by the D#15090 convergence (no second scorer; no new re-ranking daemon; no fabricated non-empty route) and the ticket was parked [ARCHITECTURE_DEFERRED_TO_D#15090]. D#15090 has since graduated (→ Epic #15100 + ADR 0035, merged/logically-Accepted per ADR 0005).

Under the graduated contract, #15087 is the typed-route consumer leaf (ADR 0035 §8). This body is reshaped to the ADR §5 first leaf-family — "Typed route + consumer migration" (ADR 0035 §2.11 Phases 1–2) — retaining parent #13652 and native-linked under #15100 as a dependency edge. The hook-projection reader cutover (Phase 4) is carved out to a follow-on leaf gated on the Phase-3 Memory-Core projection writer, so this lane is buildable without the writer.

Scope-boundary note (open to @neo-gpt, ADR author): §8 names #15087 "stop-hook producer/typed-route consumer." I read that as this Phase 1+2 typed-route leaf (the ADR §5 first leaf-family maps 1:1), with the hook-reader as a separate downstream leaf. If you intended #15087 as the hook-reader only, the typed-route content splits to a new leaf — cheap; flag and I adjust. The convergence history (Vega/Emmy/Euclid/Grace comments below) is preserved and now durably owned by ADR 0035.


Context

GoldenPathSynthesizer runs the one canonical Golden Path scoring pass, but it renders the result to Markdown (## Computed Golden Path) and returns only status/counts — the selected route stays method-local. Every downstream consumer then reparses that Markdown to recover the route:

  • AgentOrchestrator.parseGoldenPath() (ai/agent/AgentOrchestrator.mjs:86–113) regex-matches ## Computed Golden Path and re-extracts issue-<n> + description rows from sandman_handoff.md.
  • The stop-hook path reads an unprovenanced goldenPathDirection array with no producer version, source manifest, freshness, or channel semantics.

ADR 0035 §1 names this exactly: "GoldenPathSynthesizer … writes sandman_handoff.md and returns only status/counts; the selected route remains method-local. AgentOrchestrator.parseGoldenPath() reparses the rendered Markdown with regular expressions." Markdown-as-route-authority is the live wound behind the fixture-row and empty-route failures.

The Problem

There is no typed carrier for the canonical route. Because the only machine-readable form is rendered prose:

  • consumers cannot distinguish empty vs missing vs stale vs degraded — all collapse to "no rows found";
  • current-focus-substitution is invisible (a renderer can't signal it in prose a regex will read back);
  • route identity (routeVersion, sourceManifestHash, sourceWatermark) is unrecoverable, so a consumer cannot cache or cite the exact pass it saw;
  • every new consumer (hook projection, Fleet read) is pressured to grow its own parser or re-score.

Intended Solution Shape

Make the canonical pass return the typed ComputedRouteResult (ADR 0035 §2.2) before any renderer runs, and migrate the machine consumers onto the typed object. Markdown (sandman_handoff.md) remains a downstream human-readable render, never the machine contract (§2.2 invariant 6).

{
    schemaVersion: 'computed-route.v1',
    status,            // fresh | empty | missing | stale | degraded  (independent of item count)
    capturedAt, sourceWatermark, expiresAt, routeVersion, sourceManifestHash,
    provenance: { producer: 'GoldenPathSynthesizer', runId, algorithmVersion, citations: [] },
    freshness:  { status, checkedAt, expiresAt },
    route:      { kind /* computed-ranked | current-focus-substitution | none */, items: [{id, title, score, rank, citations: []}] },
    advisoryFallback: { kind: 'declared-intent', status, items: [{id, title, citations: []}] },
    citations: [], notAuthority: true
}

The Architectural Reality

  • Producer: ai/services/graph/GoldenPathSynthesizer.mjs (~`:1241builds the## Computed Golden PathMarkdown) + its routing helperai/services/graph/computedGoldenPathRouting.mjs` (the extracted routing-decision surface). The typed object is assembled here, from the same scoring the Markdown renders — no second scoring pass.
  • Consumer 1 — handoff renderer: consumes the typed object and renders the identical human section (parity), so sandman_handoff.md output is unchanged for humans while its authority moves to the typed object.
  • Consumer 2 — AgentOrchestrator: parseGoldenPath() is replaced by direct consumption of the typed ComputedRouteResult (or the same producer-stamped envelope, §2.2 invariant 5). The regex authority is deleted, not left as a dual path.
  • Structural pre-flight: any new .mjs (e.g. a computedRouteResult contract/factory helper) runs structural-pre-flight; the natural home is alongside computedGoldenPathRouting.mjs under ai/services/graph/ (sibling-lift, no novel directory).

The Fix (ADR 0035 §2.11 Phases 1–2)

  1. Phase 1 — typed route. The canonical pass returns ComputedRouteResult. route.items is the only executable slot; advisoryFallback.items (declared-intent) is context that can never turn status: empty into a routed result (§2.2 invariant 1). current-focus-substitution is set explicitly by the pass, never inferred by a renderer (invariant 2). status/freshness/coverage are independent of item count (invariant 3). Handoff renderer consumes the object at parity.
  2. Phase 2 — direct consumer. AgentOrchestrator consumes the typed object directly and deletes parseGoldenPath(). No indefinite regex/typed dual path.

Contract Ledger

Surface Source of authority Behavior Fallback Evidence
New ComputedRouteResult (computed-route.v1) ADR 0035 §2.2 Canonical pass returns the typed object with honest status/freshness/route-identity missing/degraded/stale/empty are distinct + never normalized to empty Schema test per status; route/advisory separation; current-focus substitution
GoldenPathSynthesizer Markdown render ADR 0035 §2.2 inv.6 Downstream human render only; derived from the typed object Render parity with the pre-change section Handoff-parity test
AgentOrchestrator.parseGoldenPath() ai/agent/AgentOrchestrator.mjs:86 Deleted; replaced by typed-object consumption Missing/degraded typed route → deterministic no-route (no regex fallback) AgentOrchestrator no-Markdown-parse test; advisory-non-executable test
Route identity {routeVersion, sourceManifestHash, sourceWatermark} ADR 0035 §2.2 inv.4 Consumers may cite/cache; may not recompute One-pass/one-version identity test

Decision Record

Authority: ADR 0035 (§2.1 owner table, §2.2 ComputedRouteResult, §2.11 Phases 1–2, §5 "Typed route + consumer migration" evidence row). Composes ADR 0033 (one additive advisory route authority) and ADR 0028; supersedes none. Graduated from Discussion #15090 (Cycle-7). No new ADR required.

Acceptance Criteria (derived from ADR 0035 §5, not Discussion archaeology)

  • The canonical Golden Path pass returns a computed-route.v1 ComputedRouteResult; scoring executes once and the Markdown section is rendered from it.
  • Schema tests cover every status (fresh | empty | missing | stale | degraded); missing/degraded is never normalized to empty.
  • route.items vs advisoryFallback.items separation is enforced: advisory can never make status: empty executable.
  • current-focus-substitution is emitted explicitly by the pass and asserted; a renderer cannot manufacture it.
  • Route identity {routeVersion, sourceManifestHash, sourceWatermark} is stamped and one-pass/one-version stable.
  • Handoff-render parity: the human ## Computed Golden Path section output is unchanged (or intentionally-diffed with a recorded rationale).
  • AgentOrchestrator consumes the typed object directly; parseGoldenPath() Markdown-regex authority is removed; a test proves no Markdown parse remains on the route path.
  • Inference/route unavailable preserves deterministic coverage and marks the route channel honestly; advisory stays visibly non-executable.
  • Cross-family review challenges the typed contract + handoff parity + the AgentOrchestrator cutover before merge.

Out of Scope (separate #15100 leaves)

  • Hook-projection reader cutover (ADR §2.11 Phase 4 / §5 "Claude/Codex readers") — follow-on leaf; gated on the Phase-3 Memory-Core projection writer. This ticket does not touch laneStateStopHook.mjs.
  • Memory-Core projection broker/writer (Phase 3, §2.6) — separate leaf.
  • Lifecycle-frontier producer (§2.3) — separate leaf.
  • Legacy lifecycle-state.json / goldenPathDirection quarantine removal (Phase 5, §2.11) — sequenced after reader cutover.
  • Any softening of the stop-hook's turn-end refusal (the retracted anti-pattern #15001/#14580/#13822/PR #15082).

Avoided Traps

  • Second scorer / re-ranking daemon (this ticket's own rejected original): the typed object is a projection of the one canonical pass, not a new score.
  • Dual Markdown+typed authority: parseGoldenPath() is deleted, not left as a fallback — indefinite dual authority is forbidden (ADR §2.11 Phase 2).
  • Empty-route fabrication: honest empty/degraded/missing is preserved; advisory context never fills an empty route.
  • Renderer-manufactured current-focus: the pass owns that signal.

Related

  • Epic: #15100 (dependency edge; not reparented — stays under #13652)
  • Parent: #13652
  • Authority: ADR 0035 §2.2 / §2.11 / §5
  • Graduated from: Discussion #15090 (Cycle-7)
  • Downstream consumers of the typed route: the hook-reader cutover leaf (to be filed), #14961 (freshness reader)
  • Historical Bird Views (separate): #14435 (merged), #15088 (closed)
tobiu referenced in commit cf3d2e3 - "feat(graph): typed computed-route.v1 + consumer migration off Markdown (#15087) (#15231) on Jul 16, 2026, 4:24 PM
tobiu closed this issue on Jul 16, 2026, 4:24 PM