LearnNewsExamplesServices
Frontmatter
id16347
titleBind the fleet wake-state seams to the containerized plane
stateClosed
labels
enhancementaiarchitecture
assigneesneo-fable-clio
createdAtAug 2, 2026, 2:31 PM
updatedAtAug 2, 2026, 6:09 PM
githubUrlhttps://github.com/neomjs/neo/issues/16347
authorneo-fable-clio
commentsCount0
parentIssue13015
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 2, 2026, 6:09 PM

Bind the fleet wake-state seams to the containerized plane

Closed Backlog/active-chunk-12 enhancementaiarchitecture
neo-fable-clio
neo-fable-clio commented on Aug 2, 2026, 2:31 PM

Context

Lane A of the FM-week co-plan (#14560, lane-map comment) reconnects the Fleet cockpit's read/write seams to the dockerized Agent OS plane. Leaf 1 (#16324, PR #16329, merged at a0e6c8f — commit a0e6c0… see PR) moved the mailbox, compose, and catch-up seams onto an identity-verified persistent MCP client (ai/services/fleet/planeMailboxClient.mjs) against the containerized Memory Core, with a fail-closed boot decision in the entrypoint. This leaf migrates the remaining S2 wake-state observation seams, which still read pre-hard-cut host truths.

Live latest-open sweep: checked latest 20 open issues at 2026-08-02T12:29:35Z; no equivalent found. Adjacent-not-duplicate: #16331 / PR #16340 (wake-status semantics convergence across readers — orthogonal axis: status interpretation vs. which truth store is opened; merge-order coordination flagged A2A). A2A in-flight claim sweep (last ~60 min): claims cover #16336, #16343, #15252-R2, #16331 — no overlap with this scope.

The Problem

Post-hard-cut, the wake-state axes wired at ai/services/fleet/devFleetServer.mjs:132-136 measure a plane that no longer exists on the host:

  1. Subscription axis: readActiveWakeSubscriptionIdentities opens the host GraphService SQLite. The live WAKE_SUBSCRIPTION rows are written by the containerized Memory Core into the container plane volume — the host graph holds pre-cut relic rows (the class the wake-manifest builder deliberately skips). This is the same split-brain-read defect class leaf 1 removed for the mailbox seams.
  2. Daemon-liveness axis: pidFilePath points at the legacy local wake daemon's PID file under the memory-core wakeDaemon.dataDir. No such process runs post-cut (verified: ps finds no daemons/wake/daemon.mjs; delivery is now container-Memory-Core leg 1 → signed host receiver leg 2, per ADR 0019 §10.7). A missing PID file is OBSERVED not-running by the adapter's contract → alive: false.
  3. Terminal-receipt axis: deliveryFailureFilePath reads the same retired daemon's receipt file.

Composed through resolveAgentWakeState's truth table, host-relic-active identities render suppressed (intent on + "delivery off") and genuinely-subscribed post-cut identities render off. The cockpit's wake column currently fabricates a fleet-wide blind-switch incident and hides real subscriptions — exactly the failure class the fail-honest taxonomy exists to prevent, produced by stale wiring rather than a broken adapter.

The Architectural Reality

  • ai/services/fleet/fleetWakeStateAdapter.mjs — already seam-shaped: injected readers, entrypoint-owned config resolution, capability envelope, row-local honest degradation. The taxonomy and truth table need no change.
  • ai/services/fleet/readActiveWakeSubscriptionIdentities.mjs:43-59 — durable host-SQLite ACTIVE scan; correct for a host plane, split-brain against the containerized one. Its module doc already names why the fleet read is deliberately NOT the caller-owner management API.
  • ai/services/memory-core/WakeSubscriptionService.mjs (manage_wake_subscription) — every action derives its owner from RequestContextService; list filters to the caller and returns full subscription rows ({id, ...props}) for that owner. The plane surface today cannot answer "which identities hold an active subscription" for a fleet-scoped observer, and full rows would over-disclose if it did.
  • ai/services/fleet/planeMailboxClient.mjs — leaf 1's identity-verified client already exposes the generic proven-session callTool(name, args) (the catch-up seam rides it, devFleetServer.mjs:198-204).
  • Admission precedent: the mailbox-mirror read (leaf 1) — a fleet-wide read admitted by the Memory Core's own permission-grant machinery, decided plane-side, attributed to the verified boot viewer.
  • ADR 0019 §10.7 — wake delivery disposition: container Memory Core owns heartbeat/coalescing; the signed host receiver is the final mile; the Shape-C local daemon is a pre-cleanup relic.

The Fix

Memory-Core side (the truth owner):

  • Add a fleet-scope observation read to the wake-subscription surface: deduplicated holder identity strings only for ACTIVE subscriptions — deliberately not full rows (owner rows carry endpoint/config/key-adjacent material a roster read has no business seeing). Durable-first SQL mirroring the established ACTIVE-scan shape.
  • Admission: the who_is_online telemetry class (resolved 2026-08-02 against the registered permission kinds, as this body reserved): PermissionService's model is strictly pairwise grantee→owner edges (CAN_READ_INBOX_OF shape) with AGENT:* structurally always-true as a target — a fleet-scoped resource fits neither, and per-seat N-grants would turn missing grants into roster holes (a new fabrication class). The truth-owning service already exposes an authenticated-caller fleet-telemetry read: who_is_online IS WakeSubscriptionService.whoIsOnline. The fleet-identities read is its narrow sibling — same service, same authenticated-caller gate, and strictly less disclosure than the host-side fleet scan has always had (identities only, no rows). Any plane-side refusal (unauthenticated/unadmitted caller) still degrades honestly in the adapter.
  • Surface shape (resolved): a new fleet-identities action on the existing manage_wake_subscription tool — no new MCP tool (#16217 bloat discipline, handler-census friendly), no change to who_is_online's DTO. #16320 note: clients with pinned pre-change schemas may not see the new action value until reconnect; the FM plane client connects fresh per boot, and server-side validation governs.

Fleet side:

  • devFleetServer.mjs: in plane mode, FleetManager.wakeStateOptions.listActiveSubscriptionIdentities binds to the plane read through the verified client, replacing the host-graph scan; the host-graph scan remains the in-process-mode binding (correct for a host plane). The boot log names the wake-seam plane decision (mirror of leaf 1's witness line).
  • Plane mode wires no Shape-C PID/receipt path (they measure a retired daemon). The delivery-liveness axis binds to what the plane can actually vouch for (healthcheck/heartbeat surface if exposed — V-B-A at implementation), else stays honestly unknown with a named reason. No fabricated on, no fabricated suppressed.
  • fleetWakeStateAdapter.mjs gains only what that binding needs (an injectable delivery-liveness seam beside the PID-file path) — additive, truth table unchanged.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
manage_wake_subscription fleet-identities action ai/services/memory-core/WakeSubscriptionService.mjs (sibling of whoIsOnline) identities-only ACTIVE scan, authenticated-caller telemetry class (who_is_online precedent), riding the converged status policy (PR #16340) plane refusal of any kind → adapter's honest unknown tool description + service JSDoc unit specs: refusal × identities-only shape × policy-module consumption
FleetManager.wakeStateOptions binding ai/services/fleet/devFleetServer.mjs:132 (boot entrypoint, leaf-1 plane decision) plane mode → plane-backed bulk reader + plane-vouched liveness; in-process mode → existing host bindings reader throw → adapter's row-local honest unknown (existing contract) entrypoint module doc, step-5 extension boot log witness naming the wake-seam plane
fleetWakeStateAdapter options ai/services/fleet/fleetWakeStateAdapter.mjs additive injectable delivery-liveness seam seam absent → current PID-file behavior adapter JSDoc existing specs stay green + new seam specs

Decision Record impact: aligned-with ADR 0019 (§10.7 wake-delivery disposition; any config touch stays leaf-read-at-use-site clean). No new ADR.

Acceptance Criteria

  • Plane mode: the wake snapshot's subscription axis reads the containerized plane's ACTIVE rows through the identity-verified client; the host GraphService is not opened for it.
  • The plane read returns holder identities only; no subscription row properties cross the boundary.
  • Refused plane caller (unauthenticated/unadmitted): the adapter degrades that axis honestly (unknown with reason), never an empty-fleet fabrication.
  • The MC-side read consumes the converged status policy module (PR #16340), never a re-inlined status interpretation; every status-idiom edit is label-classified first (the three-label lookalike trap).
  • Plane mode wires no Shape-C PID/receipt path; delivery-liveness is plane-vouched or honestly unknown with a named reason — no suppressed fabricated from the retired daemon's absence.
  • In-process mode bindings unchanged; existing adapter specs stay green.
  • Boot log names the wake-seam plane decision.
  • Unit specs cover admission grant/refusal, identities-only shape, plane-mode wiring, and honest-degrade rows.
  • Live-plane receipt: post-merge, against a plane rebuilt at/past the implementing commit (deployment-lane dependency, D#16304: running containers lag dev; spec-level witnesses gate the PR, the live witness follows the rebuild).

Out of Scope

  • Throttle axis: FleetManager.throttleStateOptions was never wired anywhere (the adapter documents that no platform throttle truth source exists yet) — nothing to migrate.
  • Host receiver observability and wake-election policy (S2 read-projection over turn presence) — separate lanes (#16310-adjacent).
  • Retiring the Shape-C daemon code itself (hard-cut cleanup owns deletion).
  • Cockpit UI changes (#14560 design lane).
  • Status-semantics convergence across wake readers — that is #16331 / PR #16340 (Ada); this ticket only changes WHICH store the fleet's plane-mode read opens.

Avoided Traps

  • Reading the container SQLite volume from the host process: bypasses the MCP tool contract and tenant admission — the exact authority-model violation the plane exists to end.
  • Exposing the fleet scan as full rows through the caller-owner list action: the owner-scoped verb and the fleet telemetry read have different disclosure contracts; identities-only enumeration matches the established who_is_online telemetry surface, full rows never cross fleet-wide.
  • A per-seat pairwise grant model (CAN_OBSERVE_WAKE_OF): consistent-looking with the permission model, but a missing grant would render as a roster hole — a new fabrication class — and every seat onboarding would carry a silent grant obligation.
  • Returning full subscription rows fleet-wide: over-discloses endpoint/config/key-adjacent material to a read that needs identity strings.
  • Treating "plane MCP answers" as delivery-lane liveness: presence/reachability and wake-route health are independent signals; MCP reachability must not be inferred into on.

Related

#13015 (parent epic) · #16324 / PR #16329 (leaf 1: pattern + client) · #16331 / PR #16340 (status semantics, merge-order coordination) · #16310 (wake boot-arming, receiver side) · #16320 (pinned tool schemas) · #14560 (cockpit epic) · D#16304 (merged code vs. running containers)

Origin Session ID: 5892cb00-bb3f-467b-9346-81c509834503

Retrieval Hint: query_raw_memories("fleet wake-state plane migration split-brain subscription scan"); commit anchor: leaf 1 merge (PR #16329).

tobiu referenced in commit 015699a - "feat: fleet wake-state seams ride the containerized plane (#16347) (#16368) on Aug 2, 2026, 6:09 PM
tobiu closed this issue on Aug 2, 2026, 6:09 PM