LearnNewsExamplesServices
Frontmatter
id13179
titleFleet Manager: observe fleet repo provisioning state (inspectFleetRepos)
stateClosed
labels
enhancementaiarchitecture
assigneesneo-opus-ada
createdAtJun 14, 2026, 5:14 AM
updatedAtJun 14, 2026, 8:44 AM
githubUrlhttps://github.com/neomjs/neo/issues/13179
authorneo-opus-ada
commentsCount0
parentIssue13015
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 14, 2026, 8:44 AM

Fleet Manager: observe fleet repo provisioning state (inspectFleetRepos)

Closed v13.1.0/archive-v13-1-0-chunk-2 enhancementaiarchitecture
neo-opus-ada
neo-opus-ada commented on Jun 14, 2026, 5:14 AM

Context

The Fleet Manager MVP epic (#13015) is "define, start, observe the agent fleet." Define (the settings pane #13058) and start (lifecycle #13049 + spawn-time repo provisioning #13177) are built. Observe is half-built: FleetLifecycleService reports process state (status / listRunning), but nothing reports repo state. After #13177 each agent provisions its working repo at spawn — yet there is no fleet-wide read of whether each agent's repo is actually present, a valid checkout, conflicted, or not configured at all.

The Problem

Operating the fleet means knowing, per agent: is its working repo provisioned? Is the checkout healthy or is the path occupied by a conflicting / foreign occupant? Is the agent even wired to a repo yet? Today that requires manually deriving each path and stat-ing it. The settings pane (#13058) and the operator need a single read to render fleet repo health — the repo dimension of the "observe" pillar, the read-side mirror of #13177's provision-side.

The Architectural Reality

  • ai/services/fleet/inspectAgentRepo.mjs — classifies one repo's on-disk state read-only: {exists, isCheckout, state, provisioningAction}.
  • ai/services/fleet/deriveAgentRepoPath.mjs — the stable {managedRoot, agentId, repoSlug} → checkout path.
  • FleetRegistryService.listAgents() — enumerates agent definitions, secret-stripped via toPublic (keeps id + the free-form metadata, so metadata.repo = {cloneUrl, repoSlug} survives).
  • Nothing composes these into a fleet-wide repo view. That aggregator is this ticket.

The Fix

  • ai/services/fleet/inspectFleetRepos.mjs (new, standalone — sibling to ensureAgentRepo): inspectFleetRepos({registry, managedRoot, inspect = inspectAgentRepo}) → maps registry.listAgents() to a per-agent repo-status array. For an agent with metadata.repo.repoSlug: derive the path → inspect({repoPath}){agentId, configured: true, repoSlug, repoPath, exists, isCheckout, state, provisioningAction}. For an agent without repo coordinates: {agentId, configured: false, …} with a state: 'unconfigured' marker — observability surfaces the whole fleet, never silently omitting un-wired agents. Read-only; inspect is an injectable seam (default-real) so the aggregation is unit-testable without the filesystem. managedRoot is a parameter (consistent with ensureAgentRepo / startAgentProvisioned), supplied by the eventual caller from FM config.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
inspectFleetRepos({registry, managedRoot, inspect}) (new) this ticket per-agent repo status over registry.listAgents() unconfigured agents reported, not omitted module JSDoc + spec inspectAgentRepo / deriveAgentRepoPath / listAgents verified on origin/dev
registry.listAgents() (consumed) FleetRegistryService read the agent set incl. metadata.repo existing JSDoc toPublic keeps ...rest incl. metadata (verified)

Decision Record impact

none — aligned-with the #13015 MVP decomposition (the "observe" pillar's repo dimension).

Acceptance Criteria

  • inspectFleetRepos returns one status entry per agent from registry.listAgents().
  • A repo-configured agent's entry carries the derived repoPath + the inspect classification (configured: true).
  • An agent with no metadata.repo is reported with configured: false + state: 'unconfigured' (not omitted).
  • missing registry / managedRoot each throw a clear error.
  • The inspect seam is honored (injected stub drives the per-agent classification — no filesystem in the unit spec).
  • Unit spec at test/playwright/unit/ai/inspectFleetRepos.spec.mjs, green via the custom unit config; node --check.

Out of Scope

  • The live caller / settings-pane wire that consumes this read (a later integration leaf; supplies managedRoot from FM config).
  • Any mutation / provisioning (read-only — provisioning is #13177's startAgentProvisioned).
  • Process / liveness observability (already exists: status / listRunning).
  • Deep git-health probes beyond inspectAgentRepo's occupant classification.

Related

  • Parent epic: #13015 (FM MVP — define, start, observe). The read-side mirror of #13177 (provision-side).
  • Consumes: #13148 (inspectAgentRepo), #13145 (deriveAgentRepoPath); reads metadata.repo (the #13177 convention).
  • Consumer-to-be: the settings pane (#13058).

Live latest-open sweep: checked the live tracker + in-flight A2A claims immediately before filing; no equivalent (the only active claim is an unrelated marathon-benchmark lane).

Authored by Claude Opus 4.8 (Claude Code), @neo-opus-ada. Origin Session ID: 4c598c8f-d8a7-4288-9420-e825a45d310e Retrieval Hint: "Fleet Manager observe fleet repo status inspectFleetRepos listAgents"