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:
Maps per-card lifecycleIntent actions (start, stop, restart) to the existing generated registry bridge methods (startAgent, stopAgent, restartAgent).
Sets pendingAction on the target card provider when the adapter accepts an intent.
Clears stale controlReason when a new accepted intent enters pending.
Clears pendingAction on settle/reject/deny/timeout.
Writes controlReason for terminal non-success states using {action, kind, reason} with kind in rejected|unauthorized|timeout.
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.
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.
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.
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 (
#14563and#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
devdoes not have that cockpit adapter seam:apps/agentos/view/FleetSettingsPanel.mjshas the older keeper-viewrunLifecycleAction()path callingglobalThis.AgentOS.fleet.registryBridge.<verb>(agentId)and reflecting state throughAgentDefinitions.apps/agentos/view/fleet/AgentCard.mjsexposes the per-cardstateProvideras the single binding surface, but it has nopendingAction/controlReasonfields ondev.apps/agentos/view/fleet/fleetCardFactory.mjsserializes provider data into the card blueprint, so provider fields are the right adapter surface for B4 to render.pendingAction,controlReason, andlifecycleIntentfound no existing implementation ondev.The Architectural Reality
lifecycleIntent, call the existing Fleet registry bridge methods, and write the accepted provider fields back to the matching per-card provider.src/ai/fleet/fleetWireMethods.mjs,src/ai/fleet/createFleetRegistryBridge.mjs,ai/services/fleet/FleetControlBridge.mjs, andai/services/fleet/dispatchFleetRequest.mjsare the registry/wire boundary. This ticket must not create a bespoke control channel.pendingAction: String|nullandcontrolReason: {action, kind, reason}|null, with C2 clearing stalecontrolReasonwhen a new accepted intent enters pending.The Fix
Add the Fleet cockpit lifecycle-intent adapter that:
lifecycleIntentactions (start,stop,restart) to the existing generated registry bridge methods (startAgent,stopAgent,restartAgent).pendingActionon the target card provider when the adapter accepts an intent.controlReasonwhen a new accepted intent enters pending.pendingActionon settle/reject/deny/timeout.controlReasonfor terminal non-success states using{action, kind, reason}withkindinrejected|unauthorized|timeout.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
lifecycleIntentadapter{action, agentId}and maps to existing registry bridge methodcontrolReason.kind='rejected', no bridge callpendingActionprovider fieldnullcontrolReasonprovider fieldnullFLEET_WIRE_METHODS/createFleetRegistryBridgestartAgent/stopAgent/restartAgentmethods onlyDecision Record impact
Aligned with ADR-0020 Agent Harness and the Agent OS one-harness-app direction. No ADR amendment expected.
Acceptance Criteria
lifecycleIntentand calls the existing registry bridge method forstart,stop, andrestart.pendingActionis set on accepted intent and cleared on settle/reject/deny/timeout.controlReasonuses{action, kind, reason}forrejected,unauthorized, andtimeout, and stale reasons clear when a new accepted intent enters pending.npx playwright test.Out of Scope
{action, scope: 'fleet'}contract for a later leaf.Avoided Traps
#14563/#14595tickets.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, andtestforpendingAction,controlReason,lifecycleIntent, and provider-field terms; no implementation ticket or code seam found beyond #14611's B4 contract. Memory Core sweep:query_raw_memoriesandquery_summariesfor Fleet cockpit lifecycleIntent/provider fields returned no duplicate. Structure-map gate: rannpm run --silent ai:structure-map -- --files --loc; owning precedent isapps/agentos/view/fleet/for card provider data plusai/services/fleet/src/ai/fleetfor bridge boundaries.Origin Session ID: e0af78f0-80e9-485d-ae00-654ce902178d Retrieval Hint: "Fleet cockpit lifecycleIntent pendingAction controlReason provider field C2 adapter #14611"