LearnNewsExamplesServices
Frontmatter
id16554
titleFive orchestrator lanes have no owner: both roles decline them
stateClosed
labels
bugaiarchitecture
assigneesneo-opus-ada
createdAtAug 5, 2026, 4:42 PM
updatedAtAug 5, 2026, 7:05 PM
githubUrlhttps://github.com/neomjs/neo/issues/16554
authorneo-opus-ada
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 5, 2026, 7:05 PM

Five orchestrator lanes have no owner: both roles decline them

Closed Backlog/active-chunk-13 bugaiarchitecture
neo-opus-ada
neo-opus-ada commented on Aug 5, 2026, 4:42 PM

Context

Found by @neo-opus-vega from the live host-edge runtime state and handed to me as orchestrator surface; the enablement half is measured here. Both halves are first-hand.

The Knowledge Base holds 0 documents. Per ADR-0027 (:112, :117, :189) that is by design outside the autonomous recovery target set, because "Knowledge Base rebuilds from source" — so kbSync is the KB's sanctioned recovery path. It has never run.

The Problem

Five lanes are declined by the container plane on the grounds that host-edge owns them, and declined by the host-edge profile on the grounds that host-edge does not own them. Both statements are internally coherent. Together they leave the lanes with no owner, and every health surface reads green.

Container orchestrator, on every boot:

[Orchestrator] Not running 5 lane(s) this role does not own — host-edge owns
githubWorkflowSync, kbSync, primary-dev-sync, swarm-heartbeat, temporal-summary.
This process does not verify that the owning role is live.

ai/deploy/hostEdgeProfile.mjs:107-117, under the literal comment "Host-edge-class lanes this topology does not elect for the host edge:"

NEO_ORCHESTRATOR_GITHUB_WORKFLOW_SYNC_ENABLED: 'false',
NEO_ORCHESTRATOR_KB_SYNC_ENABLED             : 'false',
NEO_ORCHESTRATOR_PRIMARY_DEV_SYNC_ENABLED    : 'false',
NEO_ORCHESTRATOR_SWARM_HEARTBEAT_ENABLED     : 'false',
NEO_ORCHESTRATOR_TEMPORAL_SUMMARY_ENABLED    : 'false'

Five for five, exactly — the same lanes on both sides.

Observed consequence, host-edge orchestrator-state.json (measured by @neo-opus-vega, host-edge live at PID 99868, up 2d 4h): all five report lastRunAt = NEVER. Only lms has ever run — and lms is the one flag the same profile sets 'true' at :100, which is the positive control that the field is written at all and that the profile's declarations are what decide.

registry.mjs:93 reads state.kbSync?.lastRunAt ?? 0, so NEVER means due-immediately. This is not a not-yet-due artefact.

A live owner running none of its lanes is worse than a dead one. A dead host-edge would fail a liveness probe. A live one running nothing satisfies every check, and the container's warning naming it as owner reads as reassurance.

The Architectural Reality

#16166 ("Split host-edge and container orchestrator task authority", closed) created this topology, and its own AC-3 is the invariant now violated:

"The combined host-edge + container-plane matrix has exactly one owner for every required lane; duplicates and gaps fail before work starts."

and its Fix section:

"Add a startup/preflight receipt that reports the resolved owner of every task and rejects an incomplete or double-owned required lane before either supervisor begins work."

The reject half is what is missing. The two halves are derived from different substrates and nothing reconciles them:

  • ai/daemons/orchestrator/Orchestrator.mjs:1125-1150buildDisabledLaneAnnouncement maps each declined lane through resolveAuthorityClassOwner({authorityClass}). The owner is derived from the lane's authority class, a static classification. Its JSDoc is explicit and correct about its own boundary (:1116-1121): "it does NOT claim the owning role is running" — a graphless host edge cannot probe the container plane, so honesty was chosen over a guess.
  • ai/deploy/hostEdgeProfile.mjs:92-118buildHostEdgeEnv is a hand-written env fragment declaring which lanes host-edge elects. Its own JSDoc (:78-81) calls this the "lane closure" and says "stating the closure makes the elected lane set legible in one place."

Both are well-documented and each is right about itself. Neither reads the other. The class table says "host-edge's class"; the profile says "not elected here". The announcement is a statement, not a check — the gap is named in prose at the exact moment it opens, and then both supervisors start anyway.

ai/daemons/orchestrator/scheduling/registry.mjs:93 — the due-computation that makes NEVER mean due-immediately, so the lanes are not merely idle; they are permanently due and never offered.

The Fix

Make the reconciliation mechanical rather than editorial, per #16166's undelivered half.

  1. Derive the host-edge lane closure from the same authority classification the container uses (resolveAuthorityClassOwner), instead of a hand-maintained parallel env fragment. A lane classified host-edge-owned must be enabled by the host-edge profile by construction, not by a second author agreeing.
  2. Where a declared owner declines a lane, that is an unowned required lane and must fail at boot, not log. The honest-boundary reasoning in Orchestrator.mjs:1116-1121 stays intact: this check does not require probing the other plane, only comparing two local declarations.
  3. Decide and record the disposition of each of the five. kbSync self-evidently needs an owner. The other four (githubWorkflowSync, primary-dev-sync, swarm-heartbeat, temporal-summary) may be intentionally retired — if so, they must be removed from the classification rather than left orphaned, because an orphan is indistinguishable from a gap.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback / Error Semantics Docs Evidence
buildHostEdgeEnv lane closure (hostEdgeProfile.mjs:92) #16166 AC-3, over the hand-written fragment derived from the authority classification a lane the classification assigns host-edge cannot be absent from the closure the two lists agree by construction, asserted on a generated closure
buildDisabledLaneAnnouncement (Orchestrator.mjs:1125) existing unchanged — its stated boundary is correct n/a its existing specs still pass
boot with an unowned required lane this ticket refuses names the lane and both declining roles; no silent start a fixture where both roles decline one lane fails boot
lastRunAt = NEVER on an owned lane registry.mjs:93 unchanged — due-immediately is correct n/a untouched

Decision Record impact

aligned-with ADR 0027 — this ticket does not change the KB's exclusion from autonomous recovery; it restores the re-ingestion path that exclusion assumes exists. Also depends-on the authority model established by #16166.

Acceptance Criteria

  • The host-edge lane closure is derived from the same authority classification the container reads; a spec fails if the two disagree for any lane.
  • A lane declined by every role fails boot with a message naming the lane and both declining roles — proven by a fixture, not by inspection.
  • kbSync has exactly one owner, and a boot on that role shows it scheduled.
  • The other four lanes each have a recorded disposition: owned, or removed from the classification. No lane is left classified-but-unelected.
  • buildDisabledLaneAnnouncement's existing behaviour and its honest-boundary JSDoc are unchanged.
  • Post-merge only: kbSync lastRunAt advances on the owning role, read from that role's state file rather than from a health surface.

Out of Scope

  • Refilling the corpus. #16549 / #16550 own restore; this ticket owns the lane that would keep it fresh. They compound: a corpus restored while this holds arrives stale.
  • The container restart loop (#16546, merged as PR #16547) and its deploy. Different producer, different consumer — that feeds tenant repos into the KB, this feeds the Neo repo. Neither substitutes for the other.
  • #16551 (tenant sync backoff). Same service family, unrelated defect.
  • Whether host-edge should exist as a role. The split is #16166's settled decision; this ticket completes it rather than reopening it.

Avoided Traps

  • Reading the container's warning as reassurance. "host-edge owns kbSync" is a true statement about a class table and says nothing about whether host-edge runs it. The line even says so. It was read as coverage for 2d 4h.
  • Asserting the enablement branch from the symptom. @neo-opus-vega left this branch explicitly open — "enables.kbSync false versus the scheduling pipeline not running on host-edge at all" — rather than inferring it from five NEVERs. The profile read settles it; the five-for-five correspondence plus lms: 'true' running is the discriminator, and neither is available from the symptom alone.
  • Fixing buildDisabledLaneAnnouncement. It is correct and its boundary is deliberate. The defect is that nothing compares its output against the other role's declaration.
  • A census instead of a predicate. Enumerating today's five lanes in a doc or a test fixture would go stale the first time a lane is added. The check has to be a derivation, so a new lane is classified as a side effect of existing.

Related

#16166 (closed — created this split; its AC-3 is the invariant violated here) · #16549, #16550 (KB corpus restore — compounding, not causal) · #16546 / PR #16547 (tenant-repo ingestion; different producer) · #16551 (tenant sync backoff) · #15798 (local runtime parity, open) · ADR-0027 (KB outside the autonomous recovery target set).

Structure Map gate: no file is created or relocated. Owning folders cited in place: ai/daemons/orchestrator/ (announcement + registry), ai/deploy/ (profile fragment).

Live latest-open sweep: checked the latest 20 open issues by creation time at 2026-08-05T14:41Z — no equivalent found. A2A in-flight claim sweep over the 12 most recent messages at 14:41Z — the only claim on this scope is my own broadcast at 14:39Z, following @neo-opus-vega's explicit handover at 14:35Z. Local mirror grep over resources/content/issues/ surfaced #16166/#16210/#16230 (all closed prior art) and #16167/#15798 (open, adjacent topology work, neither owning this gap). Semantic KB sweep unavailable — the Knowledge Base holds 0 documents, which is the condition this ticket exists to fix.

Origin Session ID: eeacb603-97f1-4241-9b2f-3a542cab6d2c

Retrieval Hint: query_raw_memories("host-edge container-plane lane ownership contradiction kbSync never ran five lanes no owner authority class versus profile closure")

Retrieval Hint: the discriminating probe is ai/deploy/hostEdgeProfile.mjs:107-117 read against the container's Not running N lane(s) this role does not own boot line — the same five names on both sides is the whole finding.

tobiu referenced in commit 37e5f54 - "fix(ai): the corpus lanes move to the plane that can run them (#16554) (#16556) on Aug 5, 2026, 7:05 PM
tobiu closed this issue on Aug 5, 2026, 7:05 PM