LearnNewsExamplesServices
Frontmatter
id14889
titleWire Fleet cockpit lifecycle intents to honest provider state
stateOpen
labels
enhancementdeveloper-experienceaiarchitecture
assigneesneo-gpt
createdAt12:55 PM
updatedAt12:55 PM
githubUrlhttps://github.com/neomjs/neo/issues/14889
authorneo-gpt
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]

Wire Fleet cockpit lifecycle intents to honest provider state

Open Backlog/active-chunk-4 enhancementdeveloper-experienceaiarchitecture
neo-gpt
neo-gpt commented on 12:55 PM

Context

Vega's B4 work on the Fleet cockpit controls is now blocked on a concrete back-signal contract. The accepted contract on #14611 says the control surface emits lifecycleIntent {action, agentId} / {action, scope: 'fleet'}, and the C2 adapter writes honest round-trip state onto the per-card provider fields that B4 renders.

This ticket exists because the consumed Lane-C proofs are already closed (#14563 and #14595), while #14611 is assigned to Vega for the UI/control-cluster half. The adapter side needs its own close target before Euclid edits tracked code.

The Problem

A Fleet cockpit control must not render optimistic success. When a per-card start/stop/restart intent is accepted, rejected, denied, or times out, the card provider must carry the current in-flight action and any terminal non-success reason so the UI can render pending/rejected/unauthorized/timeout honestly.

Current dev does not have that cockpit adapter seam:

  • apps/agentos/view/FleetSettingsPanel.mjs has the older keeper-view runLifecycleAction() path calling globalThis.AgentOS.fleet.registryBridge.<verb>(agentId) and reflecting state through AgentDefinitions.
  • apps/agentos/view/fleet/AgentCard.mjs exposes the per-card stateProvider as the single binding surface, but it has no pendingAction / controlReason fields on dev.
  • apps/agentos/view/fleet/fleetCardFactory.mjs serializes provider data into the card blueprint, so provider fields are the right adapter surface for B4 to render.
  • A repo search for pendingAction, controlReason, and lifecycleIntent found no existing implementation on dev.

The Architectural Reality

  • #14611 owns the B4 UI/control-cluster rendering: verb buttons, pending/rejected/unauthorized/timeout presentation, and unit/NL proof of the rendered state machine.
  • This ticket owns the C2 adapter side: consume B4's lifecycleIntent, call the existing Fleet registry bridge methods, and write the accepted provider fields back to the matching per-card provider.
  • The transport path already exists: src/ai/fleet/fleetWireMethods.mjs, src/ai/fleet/createFleetRegistryBridge.mjs, ai/services/fleet/FleetControlBridge.mjs, and ai/services/fleet/dispatchFleetRequest.mjs are the registry/wire boundary. This ticket must not create a bespoke control channel.
  • The accepted B4/C2 contract is recorded on #14611: pendingAction: String|null and controlReason: {action, kind, reason}|null, with C2 clearing stale controlReason when a new accepted intent enters pending.

The Fix

Add the Fleet cockpit lifecycle-intent adapter that:

  1. Maps per-card lifecycleIntent actions (start, stop, restart) to the existing generated registry bridge methods (startAgent, stopAgent, restartAgent).
  2. Sets pendingAction on the target card provider when the adapter accepts an intent.
  3. Clears stale controlReason when a new accepted intent enters pending.
  4. Clears pendingAction on settle/reject/deny/timeout.
  5. Writes controlReason for terminal non-success states using {action, kind, reason} with kind in rejected|unauthorized|timeout.
  6. Fails closed if the registry bridge is unavailable, without inventing success and without exposing PAT/credential data.

Implementation should reuse the current Agent OS / fleet bridge seams and add focused unit coverage for the adapter state transitions. If the live B4 branch has not landed yet, expose the adapter through a small testable helper or controller seam that B4 can call without coupling the UI to transport details.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
lifecycleIntent adapter #14611 contract comment consumes {action, agentId} and maps to existing registry bridge method unsupported action -> controlReason.kind='rejected', no bridge call JSDoc / PR body unit covers action mapping and unsupported action
pendingAction provider field #14611 B4/C2 contract set when intent is accepted; clear on settle/reject/deny/timeout no accepted intent -> remains null JSDoc / provider field summary unit covers pending lifecycle
controlReason provider field #14611 B4/C2 contract set terminal non-success reason; clear on new accepted pending and successful settle no failure -> null JSDoc / provider field summary unit covers rejected/unauthorized/timeout and stale-clear
Registry bridge calls FLEET_WIRE_METHODS / createFleetRegistryBridge use generated startAgent / stopAgent / restartAgent methods only missing bridge -> fail closed, no optimistic success existing bridge docs + adapter JSDoc unit verifies no bespoke bridge path
Secret boundary Fleet Registry / Accounts credential model adapter sends agent id + operation only secret-shaped payload throws/fails test test assertion unit verifies no PAT/credential fields in calls

Decision Record impact

Aligned with ADR-0020 Agent Harness and the Agent OS one-harness-app direction. No ADR amendment expected.

Acceptance Criteria

  • A testable adapter/controller seam consumes per-card lifecycleIntent and calls the existing registry bridge method for start, stop, and restart.
  • pendingAction is set on accepted intent and cleared on settle/reject/deny/timeout.
  • controlReason uses {action, kind, reason} for rejected, unauthorized, and timeout, and stale reasons clear when a new accepted intent enters pending.
  • Missing bridge or unsupported action fails closed without optimistic success.
  • The bridge call payload is operation + agent id only; no PAT/credential-shaped fields are sent or stored.
  • Focused unit coverage proves success, rejected, unauthorized/missing-bridge, timeout, and stale-reason-clear behavior. Do not run default npx playwright test.

Out of Scope

  • B4 visual rendering, buttons, SCSS, and per-card control-cluster layout; those remain #14611.
  • New Fleet wire methods or lifecycle service verbs.
  • Fleet-level morning-start / whole-fleet orchestration beyond preserving the accepted {action, scope: 'fleet'} contract for a later leaf.
  • Wake-toggle implementation (#14537).
  • Full Neural-Link round-trip proof unless it naturally composes from #14611 after B4 lands.

Avoided Traps

  • No optimistic UI success before the bridge settles.
  • No event-only hidden channel that B4 cannot bind through the card provider.
  • No duplicate resurrection of the already-closed #14563 / #14595 tickets.
  • No secret or PAT payload crossing into the Body during lifecycle controls.

Related

Parent #14560 · consumes #14611 contract · follows closed #14563 / #14595 · related #14537.

Live latest-open sweep: checked latest 20 open issues immediately before creation on 2026-07-06; no equivalent C2 provider-field adapter ticket found. A2A in-flight sweep: checked latest 30 all-state messages immediately before creation; Vega owns B4 #14611, and no competing C2 adapter claim exists. Local exact sweep: searched issue/discussion resources plus apps, src, ai, and test for pendingAction, controlReason, lifecycleIntent, and provider-field terms; no implementation ticket or code seam found beyond #14611's B4 contract. Memory Core sweep: query_raw_memories and query_summaries for Fleet cockpit lifecycleIntent/provider fields returned no duplicate. Structure-map gate: ran npm run --silent ai:structure-map -- --files --loc; owning precedent is apps/agentos/view/fleet/ for card provider data plus ai/services/fleet / src/ai/fleet for bridge boundaries.

Origin Session ID: e0af78f0-80e9-485d-ae00-654ce902178d Retrieval Hint: "Fleet cockpit lifecycleIntent pendingAction controlReason provider field C2 adapter #14611"