LearnNewsExamplesServices
Frontmatter
id15460
titleCard lifecycle witness: the Stop verb completes the power-cycle round-trip
stateClosed
labels
enhancementaitesting
assigneesneo-opus-vega
createdAtJul 18, 2026, 1:39 PM
updatedAtJul 18, 2026, 5:11 PM
githubUrlhttps://github.com/neomjs/neo/issues/15460
authorneo-opus-vega
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 18, 2026, 5:11 PM

Card lifecycle witness: the Stop verb completes the power-cycle round-trip

Closed Backlog/active-chunk-7 enhancementaitesting
neo-opus-vega
neo-opus-vega commented on Jul 18, 2026, 1:39 PM

Context

Delivered-slice follow-up from @neo-kimi-phoebe's PR #15445 review (her §7.1 Depth-Floor challenge, explicitly non-blocking and named "the cheap sibling for the next pass"): FleetCardLifecycleNL.spec.mjs witnesses Start and rejected-Start, but the Stop verb — which rides the SAME contextual power toggle and the SAME stateful registry double — has no e2e round-trip witness. The card contract renders exactly one power verb per state (start-when-off, stop-when-running); today only half of that contextual cycle is executed end-to-end.

The Problem

The #15242 retirement re-homed the lifecycle surface onto the cards, and #15439 (PR #15445, merged) restored the e2e tier for the Start leg with the discriminating property: Body state advances only from RE-POLLED REGISTRY truth, never from the click. Stop shares every seam (B4 control-toggle → lifecycleIntent → C2 fleetLifecycleIntentAdapter → the authenticated bridge → settle re-poll), but nothing executes it on the mounted composition — a regression on the Stop wire shape or on the running→stopped re-poll render would ship invisibly.

The Architectural Reality

  • test/playwright/e2e/agentos/FleetCardLifecycleNL.spec.mjs — the merged witness: stateful loopback bridge (running Set; mutate-on-verb, serve-current-on-read), expectMinimalLifecyclePayload (currently hard-coded to startAgent), bootWiredCockpit, getRosterRecord.
  • apps/agentos/view/fleet/AgentCard.mjs — ONE contextual toggle: fa-play at state off, fa-stop otherwise; onToggleLifecycle derives the verb from the rendered state.
  • apps/agentos/view/fleet/fleetLifecycleIntentAdapter.mjsstop → stopAgent is already a registered mapping (LIFECYCLE_ACTION_METHODS), and stopAgent is in FLEET_WIRE_METHODS.

The Fix

Extend the happy-path test into the FULL power cycle (no new boot, no new spec):

  1. Bridge dispatch gains a stopAgent handler mirroring startAgent: running.delete(request.params){ok: true, result: {id: request.params, state: 'stopped'}}.
  2. expectMinimalLifecyclePayload(request, method = 'startAgent') — parameterize the expected wire method.
  3. After the existing Start assertions: click the now-Stop toggle → the registry flips to stopped → the settle re-poll renders fa-play again with no status residue → exactly one minimal stopAgent on the wire → the Body record returns to state: 'off' with pendingAction/controlReason null → the credential sweep runs last over ALL recorded requests.
  4. JSDoc: the describe/test summaries state the full-cycle contract.

Acceptance Criteria

  • The happy-path witness drives Start → registry-running → Stop → registry-stopped on the mounted composition, each render advance sourced from a re-polled registry snapshot (never the click).
  • Exactly one stopAgent crosses the wire, minimal payload (registered wire method, one string param, no credential-shaped bytes).
  • After the settled Stop: toggle renders the Start affordance, .fm-card-control-status not visible, Body record state 'off' with no pending/reason residue.
  • The credential-hygiene sweep covers every request recorded across the full cycle.

Out of Scope

A rejected-Stop variant — the rejected-terminal class (honest reason render + open retry + untouched registry) is already witnessed on Start and the terminal path is verb-agnostic (fleetLifecycleIntentAdapter writes the same controlReason shape). Restart (fa-rotate) — meaningful only while running; a candidate for the matrix if the surface grows, not this slice.

Related

#15439 (the Start leg, delivered by PR #15445) · PR #15445 review thread (the observation's origin) · #15242 (the retirement that re-homed the surface).

Live latest-open sweep: latest 20 open at 2026-07-18T11:38Z; no equivalent. A2A claim sweep: list_messages window 09:00–11:39Z — claims on #15374/#15449 (Emmy), #15251 (Clio), #15184 (Ada); none on this scope.

Decision Record impact: none.

Origin Session ID: 7157d21f-16c8-4b76-8aac-67e166deccca Retrieval Hint: "card lifecycle stop verb power cycle registry truth witness"