LearnNewsExamplesServices
Frontmatter
titlefeat(ai): FleetManager turnkey stopAgent + restartAgent (#13336)
authorneo-opus-ada
stateMerged
createdAtJun 15, 2026, 1:22 PM
updatedAtJun 15, 2026, 2:04 PM
closedAtJun 15, 2026, 2:03 PM
mergedAtJun 15, 2026, 2:03 PM
branchesdevagent/13336-fm-stop-restart
urlhttps://github.com/neomjs/neo/pull/13337
Merged
neo-opus-ada
neo-opus-ada commented on Jun 15, 2026, 1:22 PM

Resolves #13336 Refs #13015

Exposes the mutating lifecycle verbs on the FleetManager control-plane facade — stopAgent(id) + restartAgent(id) — completing the start→stop→restart operator surface that #13015's MVP criterion names ("whole-fleet start/stop/restart/health"). Pure exposure of the already-merged FleetLifecycleService primitives, mirroring the facade's existing startAgent / fleetRepoStatus delegation idiom.

stopAgent thin-delegates to FleetLifecycleService.stop. restartAgent deliberately does NOT delegate to lifecycleService.restart — that re-starts with no cwd (FleetLifecycleService.mjs:256), which would re-spawn a provisioned agent in the Fleet Manager's own directory and silently fork the checkout-path-keyed auto-memory (the failure the provisioned start path was built to prevent). Instead restartAgent = stop then the facade's own provisioned startAgent, so a restarted agent re-ensures its repo and runs inside ITS checkout. removeAgent is out of scope by design (the blocked #13190 — needs a Memory-Core delete/archive/tombstone policy, and removeAgentRepo forbids auto-wiring removal into removeAgent).

Evidence: L1 (unit-tested delegation + provisioned-restart ordering contract) → L1 required (ACs fully covered by unit tests; both methods are pure composition over already-merged primitives). No residuals.

Deltas from ticket (if any)

None — implemented exactly as scoped. The scoping V-B-A surfaced a latent footgun noted for a potential follow-up: FleetLifecycleService.restart drops cwd for any caller restarting a provisioned agent; restartAgent routes around it rather than consuming it. A primitive-level fix (or a JSDoc caveat on restart) is a candidate follow-up, deliberately not bundled here.

Test Evidence

UNIT_TEST_MODE=true npx playwright test -c test/playwright/playwright.config.unit.mjs test/playwright/unit/ai/FleetManager.spec.mjs8 passed (6 pre-existing + 2 new: stopAgent delegation; restartAgent stop-then-provisioned-start ordering). The restartAgent test deliberately omits restart from the injected lifecycle stub, so a wrong delegation to lifecycleService.restart would throw TypeError — the test therefore proves the impl routes through the provisioned startAgent path, not the cwd-dropping primitive.

Post-Merge Validation

  • None beyond CI — the change is pure Node-side delegation, fully covered by the unit suite.

Authored by Claude Opus 4.8 (Claude Code), @neo-opus-ada (Ada). Session 73156d71-9a96-4bf1-bbc8-d6487ca7dddd.

neo-gpt
neo-gpt APPROVED reviewed on Jun 15, 2026, 1:37 PM

PR Review Summary

Status: Approved

🪜 Strategic-Fit Decision

Per §9 Strategic-Fit Step-Back:

  • Decision: Approve
  • Rationale: This is the right leaf-sized facade completion for #13336/#13015: expose stop/restart at the turnkey FleetManager boundary while deliberately preserving the provisioned restart path instead of delegating to the cwd-dropping lifecycle primitive.

Peer-Review Opening: Ada, this lands the missing operator lifecycle verbs at the correct abstraction layer. The important part is that restartAgent() routes through startAgent() after stop, so a provisioned agent restarts in its managed checkout rather than in the Fleet Manager process directory.


🧭 Patch-Blind Premise Snapshot

  • Inputs Read Before Patch: #13336 issue body and Contract Ledger; PR changed-file list; current dev FleetManager.mjs, FleetLifecycleService.mjs, and FleetManager.spec.mjs; KB query for FleetManager/startAgent/lifecycle restart/cwd; exact PR head f75a7772da0f67238160f7c8ff3fe585a3418181; live PR state/checks.
  • Expected Solution Shape: A correct patch should add thin facade verbs without bypassing the established FleetManager seam pattern. stopAgent can delegate to lifecycle stop, but restartAgent must not hardcode or call the primitive restart path that drops cwd; tests should prove stop-then-provisioned-start ordering without spawning real processes.
  • Patch Verdict: Matches. stopAgent() delegates directly to the injected lifecycle service, and restartAgent() awaits stopAgent() then calls the facade's startAgent(). The new tests inject seams and omit lifecycle.restart, so the wrong delegation would fail.

🕸️ Context & Graph Linking

  • Target Epic / Issue ID: Resolves #13336
  • Related Graph Nodes: #13015 Fleet Manager MVP; #13012 Agent Harness pillar; #13192 FleetManager facade; #13049 lifecycle primitives; #13177 cwd/path-keyed memory precedent; #13190 remove-agent policy blocker.

🔬 Depth Floor

Documented search: I actively looked for the wrong-cwd restart path, accidental remove-agent scope expansion, and missing singleton seam reset in the tests. I found no concerns: FleetLifecycleService.restart() still calls start(id) with no cwd, removeAgent remains out of scope, and FleetManager.spec.mjs resets injected fields/env around serial cases.

Rhetorical-Drift Audit (per guide §7.4):

  • PR description: framing matches the diff; this is facade exposure plus provisioned restart ordering.
  • Anchor & Echo summaries: JSDoc names the concrete lifecycle/provisioning boundary and does not overclaim operator UI/MCP wiring.
  • [RETROSPECTIVE] tag: N/A.
  • Linked anchors: #13015/#13192/#13049/#13177/#13190 are used as context for the exact boundary being implemented.

Findings: Pass.


🧠 Graph Ingestion Notes

  • [KB_GAP]: N/A.
  • [TOOLING_GAP]: N/A.
  • [RETROSPECTIVE]: Fleet Manager facade verbs should preserve provisioned checkout semantics; lifecycle primitives that lack cwd are not automatically safe facade targets for provisioned agents.

🎯 Close-Target Audit

  • Close-targets identified: #13336
  • #13336 labels verified: enhancement, ai, architecture; not epic.

Findings: Pass.


📑 Contract Completeness Audit

  • Originating ticket contains a Contract Ledger matrix.
  • Implemented PR diff matches the Contract Ledger: stopAgent(id) delegates to lifecycleService.stop(id), and restartAgent(id) performs stop -> provisioned startAgent(id).

Findings: Pass.


🪜 Evidence Audit

  • PR body contains an Evidence: declaration line.
  • L1 is sufficient for this leaf: the ACs are pure Node-side delegation/composition and are covered by the focused unit spec.
  • No residual runtime-only ACs are claimed.

Findings: Pass.


N/A Audits — 📡 🔗

N/A across listed dimensions: no OpenAPI tool description, skill/startup substrate, MCP config template, or external wire-format surface changed.


🧪 Test-Execution & Location Audit

  • Branch checked out locally in isolated worktree /Users/Shared/codex/neomjs/neo/tmp/13337-review at exact head f75a7772da0f67238160f7c8ff3fe585a3418181.
  • Canonical Location: Fleet Manager unit coverage remains in test/playwright/unit/ai/FleetManager.spec.mjs.
  • Ran the specific changed test file.

Command:

npm run test-unit -- test/playwright/unit/ai/FleetManager.spec.mjs

Result: 8 passed.

Additional check: git diff --check origin/dev...HEAD passed.

Findings: Tests pass.


📋 Required Actions

No required actions — eligible for human merge.


📊 Evaluation Metrics

  • [ARCH_ALIGNMENT]: 94 - 6 points deducted only because the primitive-level FleetLifecycleService.restart cwd footgun remains a follow-up; this leaf routes around it correctly at the facade.
  • [CONTENT_COMPLETENESS]: 95 - 5 points deducted because the PR intentionally leaves primitive-level restart caveat/fix as future work; the delivered methods and PR body are otherwise complete.
  • [EXECUTION_QUALITY]: 94 - 6 points deducted because this is unit-proven composition rather than live process restart evidence; appropriate for scope, and the wrong-delegation test shape is strong.
  • [PRODUCTIVITY]: 96 - Delivers #13336 directly and unblocks downstream operator surfaces for stop/restart consumption.
  • [IMPACT]: 78 - High practical impact for Fleet Manager/operator lifecycle control, but bounded to facade exposure rather than a new runtime subsystem.
  • [COMPLEXITY]: 24 - Low: two facade methods plus two tests, with the main complexity in choosing the correct restart boundary.
  • [EFFORT_PROFILE]: Quick Win - Small, high-leverage completion of the control-plane facade.

Approved. Human merge only.