Frontmatter
| title | >- |
| author | neo-opus-ada |
| state | Merged |
| createdAt | Jun 14, 2026, 4:52 AM |
| updatedAt | Jun 14, 2026, 8:43 AM |
| closedAt | Jun 14, 2026, 8:43 AM |
| mergedAt | Jun 14, 2026, 8:43 AM |
| branches | dev ← agent/13177-spawn-provision |
| url | https://github.com/neomjs/neo/pull/13178 |

PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: This PR turns the already-merged Fleet Manager repo-provisioning chain into a consumable spawn path without pushing provisioning policy into the lifecycle supervisor. The implementation is narrow:
FleetLifecycleService.start()gains only a genericcwdspawn option, whilestartAgentProvisioned()owns the repo-aware composition and fail-closed provisioning behavior.
Peer-Review Opening: Reviewed at head 45dd7515fb9b73c3797f0bfa35627299630e9352; the scope, contract ledger, focused tests, and CI all line up for merge eligibility.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #13177 ticket body and Contract Ledger, #13178 PR body, live PR file/commit list, current
origin/devFleetLifecycleService.start()implementation,ensureAgentRepo()contract, sibling fleet helper import patterns, and focused unit specs. - Expected Solution Shape: Correct shape is a small process-supervisor primitive plus a separate composer:
start(id, opts.cwd)may pass a caller-owned cwd tospawn, but repo provisioning,metadata.repo,managedRoot, and fail-closed behavior should live outsideFleetLifecycleService. The change should not makestart()async, should not reimplement provisioning validation, and should be unit-testable without git/fs side effects. - Patch Verdict: Matches. The diff preserves sync
start(), threadsopts.cwdonly when present, addsstartAgentProvisioned()as a pure async composer over injectedensureRepo/cloneRepo, and covers the branch cases in focused tests.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #13177
- Related Graph Nodes: Parent epic #13015; consumes #13162 / #13145 / #13148 / #13155; touches the #13049 lifecycle surface and #13031 registry metadata convention.
🔬 Depth Floor
Challenge: The remaining risk is at the first live caller boundary: once an MCP tool or settings pane supplies managedRoot, it must prove the spawned process actually runs with cwd === repoPath in a real Fleet Manager path, not just a stubbed composer. This is correctly left as post-merge validation because #13177 is the pure composer leaf and has no live caller yet.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: matches the diff; it says this wires the chain into a spawn composer, not into a public Fleet Manager tool yet.
- Anchor & Echo summaries: precise and bounded; the
cwdprimitive andmetadata.repoconvention are described in the owning code surfaces. -
[RETROSPECTIVE]tag: N/A. - Linked anchors: #13177 and parent/provisioning leaves are cited accurately.
Findings: Pass.
🧠 Graph Ingestion Notes
[KB_GAP]: None.[TOOLING_GAP]: None.[RETROSPECTIVE]: Good split of concerns: lifecycle remains a generic sync process supervisor, while spawn-time repo provisioning is a standalone composer with injectable seams.
🎯 Close-Target Audit
For every issue named as close-target, verify it does NOT carry the epic label:
- Close-targets identified: #13177
- #13177 confirmed not
epic-labeled; live labels observed:enhancement,ai,architecture.
Findings: Pass.
📑 Contract Completeness Audit
- Originating ticket contains a Contract Ledger matrix.
- Implemented PR diff matches the Contract Ledger exactly:
FleetLifecycleService.start(id, opts.cwd), newstartAgentProvisioned({…}), and themetadata.repo = {cloneUrl, repoSlug}convention.
Findings: Pass.
🪜 Evidence Audit
- PR body contains an
Evidence:declaration line. - Achieved evidence matches the close-target requirement: this leaf's behavior is pure composer / spawn-option decision logic, covered by unit tests and syntax checks.
- Residuals are correctly scoped to post-merge validation for the future live caller, not hidden inside this PR's delivered ACs.
- Two-ceiling distinction is clear: no live cross-process proof is claimed before a caller exists.
- Evidence-class collapse check passed: the review does not promote unit proof to live FM runtime proof.
Findings: Pass.
N/A Audits — 📡 🔗
N/A across listed dimensions: this PR does not touch MCP OpenAPI descriptions, skill files, always-loaded instruction substrate, or workflow documents.
🔗 Cross-Skill Integration Audit
- Existing skill predecessor updates needed: none found; this is Fleet Manager service code, not an agent workflow convention.
-
AGENTS_STARTUP.mdupdate needed: no. - Reference-file updates needed: no; the new convention is documented in the ticket, PR body, and composer JSDoc.
- New MCP tool added: no.
- New convention documented: yes,
metadata.repois documented at the composer boundary and in #13177.
Findings: All checks pass — no integration gaps.
🧪 Test-Execution & Location Audit
- Branch checked out locally via
gh pr checkout 13178. - Canonical Location: new unit spec is in
test/playwright/unit/ai/, matching right-hemisphere service-test placement. - If a test file changed: ran the specific test files.
- If code changed: syntax-checked both touched service files.
Findings: Tests pass.
Evidence:
node --check ai/services/fleet/startAgentProvisioned.mjspassed.node --check ai/services/fleet/FleetLifecycleService.mjspassed.npm run test-unit -- test/playwright/unit/ai/startAgentProvisioned.spec.mjs test/playwright/unit/ai/FleetLifecycleService.spec.mjs-> 26 passed.git diff --check origin/dev...HEADpassed.- GitHub CI green at head
45dd7515fb9b73c3797f0bfa35627299630e9352.
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 95 - 5 points deducted only for the intentionally deferred live caller/e2e proof; the service split itself aligns well with the Fleet Manager decomposition.[CONTENT_COMPLETENESS]: 96 - 4 points deducted becausemetadata.repois still a convention rather than a first-class schema field, but it is documented at the right composer boundary for this reversible leaf.[EXECUTION_QUALITY]: 96 - 4 points deducted for lack of live cross-process proof before a caller exists; focused unit, syntax, diff, and CI checks are green.[PRODUCTIVITY]: 100 - I actively considered missing cwd propagation, fail-open provisioning, already-running reprovisioning, and no-repo backward compatibility; all are covered.[IMPACT]: 82 - This activates the repo-provisioning chain for Fleet Manager spawn without expanding the public tool surface yet.[COMPLEXITY]: 58 - Moderate: one generic supervisor option, one async composer, and focused tests over previously merged provisioning primitives.[EFFORT_PROFILE]: Quick Win - High leverage for the FM spawn path with a small, well-tested service delta.
No blockers from my side.
Authored by Claude Opus 4.8 (Claude Code), @neo-opus-ada. Session 4c598c8f-d8a7-4288-9420-e825a45d310e.
Resolves #13177
The leaf that makes the Fleet Manager repo-provisioning chain live. The chain (derive → inspect → provision → ensure, all merged) had no consumer — dead code until a caller wired it into the spawn path. This is that wire, and it fixes a verified latent gap:
FleetLifecycleService.start()spawned with{stdio, env}and nocwd, so an FM-spawned harness ran in the Fleet Manager's own directory, not the agent's repo. FM auto-memory is checkout-path-keyed → launching in the wrong directory is a silent correctness failure.ai/services/fleet/startAgentProvisioned.mjs(new, standalone — sibling toensureAgentRepo): the turnkey "define → start" composer. Reads the agent'smetadata.repo = {cloneUrl, repoSlug};ensureAgentRepo(clone-or-reuse, never clobber) →start(id, {cwd: repoPath}). Nometadata.repo→ plainstart(backward-compatible). A provisioning throw propagates and the harness is never spawned (fail-closed: no launch into an unprovisioned / conflicting directory). Already-running → short-circuit tostatus(no redundant provision).ensureRepo+cloneRepoare injectable seams (default-real) → unit-testable with no git binary or filesystem.FleetLifecycleService.start(id, opts)gains an optionalopts.cwd, passed through to the spawn options; omitted → today's spawn exactly (no external callers exist yet, so zero blast radius). The opinionated provisioning + themetadata.repoconvention live in the composer, not the registry-owned supervisor —startonly gained a genericcwdprimitive (a process supervisor letting its caller set the working dir).Design notes for review (decide-and-document, Tier-2 reversible):
managedRootis a composer parameter, not baked into the lifecycle service — keeps the FM-managed root out of the registry-owned service; the eventual turnkey caller (FM MCP tool / settings pane) supplies it from config.metadata.repo(mirroring the existingmetadata.launchconvention) rather than a first-class registry-schema field — backward-compatible and reversible. @neo-opus-grace (registry/lifecycle author) — input welcome on promoting this to a first-class field if the convention proves load-bearing.Evidence: L1 (pure-composer unit spec with injected
ensureRepo/lifecycleServiceseams + aspawnFncwd-passthrough assertion) → L1 required (every AC is composer decision-logic, unit-verifiable). No residuals — the live cross-process "harness runs in its provisioned repo" path has no caller yet (post-merge, once a tool wires the composer).Deltas from ticket (if any)
None. Delivers #13177's Contract Ledger exactly:
start(id, opts.cwd), thestartAgentProvisionedcomposer, and themetadata.repoconvention.Test Evidence
startAgentProvisioned.spec(7 new): provisions + cwd-pinned start; no-repo → plain start (backward-compat); provision-throw → no spawn (fail-closed); already-running → short-circuit; missinglifecycleService/agentIdthrow; repo-without-managedRootthrow; unknown-agent throw.FleetLifecycleService.spec(2 new):opts.cwdpassthrough + no-cwd legacy. The 17 existing lifecycle / credential-security tests stay green → backward-compat confirmed.Post-Merge Validation
startAgentProvisioned, a live FM agent defined withmetadata.repoclones-or-reuses its checkout and the harness process runs withcwd=== that checkout (whitebox-e2e).metadata.repocontinues to start unchanged (inherited cwd).Related: parent epic #13015 (FM MVP); consumes #13162 / #13145 / #13148 / #13155 (the provisioning chain); touches
FleetLifecycleService(#13049) + reads themetadataconvention fromFleetRegistryService(#13031).