Skip to content

Preserve dispatch-failed agents for reaper handoff#264

Merged
kjgbot merged 1 commit into
mainfrom
factory-sdk-v2fix11b-sb-impl2
Jun 12, 2026
Merged

Preserve dispatch-failed agents for reaper handoff#264
kjgbot merged 1 commit into
mainfrom
factory-sdk-v2fix11b-sb-impl2

Conversation

@kjgbot

@kjgbot kjgbot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Persist dispatch-failed spawned agents from a spawn-local capture into the durable factory reaper registry.
  • Preserve those handoff entries across #batch.abandon(...), loop heartbeat rewrites, and stop-time registry rewrites so the external fleet factory reap-orphans pass can still resolve and reap them.
  • Add V0 regressions for writeback failure handoff, abandon/stop-time registry erasure, reaper consumption with protected PID exclusion, pre-spawn failure no-op, and unresolved PID loud reporting.

Verification

  • npx vitest run packages/factory-sdk
  • npx tsc --noEmit

V1 Required

V0 proves the dispatch-failure path writes and preserves the durable handoff, and that the reaper consumes matching name-only entries with protected PIDs honored. It cannot prove the live failure-path end to end. fv2 V1 is mandatory: induce a real post-spawn writeback failure, confirm the abandoned pair is present in the durable registry, then confirm the running external reaper consumes that handoff and kills the whole tree with zero survivors while broker 68009 remains alive.

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds dispatch-failure handoff tracking to the factory orchestrator, persisting orphaned agent spawn metadata into the durable in-flight reaper registry when dispatch fails. The factory collects spawned agents before dispatch execution, persists them on failure, and clears them on success or issue completion. The reaper later reads and consumes these handoffs to release stranded processes.

Changes

Dispatch-Failure Handoff Tracking and Reaper Registry Persistence

Layer / File(s) Summary
Handoff type definition and dispatch-level collection
packages/factory-sdk/src/orchestrator/factory.ts, packages/factory-sdk/src/orchestrator/factory.test.ts
Introduces RegistryHandoffAgent type for issue+agent metadata, adds #dispatchFailureReaperHandoffs map to track handoff state by issue/agent name, creates stable keying and agent cloning helpers, and collects spawned agents with tracked state during dispatch for later persistence if dispatch fails.
Factory handoff lifecycle: persistence, registry, and cleanup
packages/factory-sdk/src/orchestrator/factory.ts, packages/factory-sdk/src/orchestrator/factory.test.ts
Clears handoffs on dispatch success and persists them on failure; extends #writeInFlightRegistry() to serialize handoff agents into the in-flight registry file with termination roots and PID resolution; clears stale handoffs when issues complete. Regression tests verify handoffs survive writeback failures, persist through registry rewrites at stop time, and are cleared once issues successfully complete.
Reaper handoff consumption and edge cases
packages/factory-sdk/src/orchestrator/factory.test.ts
Tests reaper behavior consuming handoffs from the in-flight registry: confirms name-only agents are reaped via discovered child processes and protected broker PIDs are skipped; verifies dispatch failures before spawn do not create orphan handoffs; ensures reaper reports unresolved handoff PIDs as skipped rather than treating them as resolved.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • AgentWorkforce/pear#253: Both PRs extend the factory's durable in-flight registry sidecar used by the orphan reaper—this PR adds dispatch-failure "handoff" entries to the registry that the reaper/reap-orphans flow will later read.
  • AgentWorkforce/pear#263: This PR extends FactoryLoop's #writeInFlightRegistry() to persist dispatch-failure handoff agents into the durable in-flight registry that the related PR reworks for PID/termination-aware release.
  • AgentWorkforce/pear#248: Both PRs modify packages/factory-sdk/src/orchestrator/factory.ts in the factory loop's dispatch failure path, but only this PR additionally persists dispatch-failure handoffs into the in-flight reaper registry for later reaping.

Poem

🐇 Handoffs hop into the durable registry,
When dispatch falters, we've got memory!
The reaper reads and reaps with care,
Protected PIDs and orphans bare. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Preserve dispatch-failed agents for reaper handoff' directly and clearly summarizes the main feature being added: persisting failed dispatch agents for the reaper to handle.
Description check ✅ Passed The description is well-related to the changeset, explaining the dispatch-failure reaper handoff tracking, persistence across rewrites, and V0 regression tests that are implemented in the modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch factory-sdk-v2fix11b-sb-impl2

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed due to a network error.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

agent-relay-code Bot added a commit that referenced this pull request Jun 12, 2026
@agent-relay-code

Copy link
Copy Markdown
Contributor

Found and fixed one real issue: dispatch-failure handoff entries could remain in memory after the same issue later succeeded/completed, causing stale agents to keep appearing in later registry writes. The fix clears those handoffs after successful dispatch and completion in factory.ts, factory.ts, and factory.ts. Added a regression test in factory.test.ts.

Addressed comments

  • gemini-code-assist[bot]: quota-limit warning only; no code finding to validate or fix.
  • coderabbitai[bot]: rate-limit/usage warning only; no code finding to validate or fix.

Advisory Notes

None.

Local validation

Passed locally:

  • npm run verify:mcp-resources-drift
  • npm run lint with 0 errors; existing warnings are outside touched files
  • npm run typecheck:web
  • npm run typecheck:node
  • npm test
  • npx vitest run
  • npm run build
  • npm run build:web
  • npx playwright test --config playwright.fidelity.config.ts
  • npx playwright test --config playwright.redraw.config.ts

I installed Playwright Chromium locally after the first browser run failed due to a missing executable, then reran the Playwright gates successfully. I did not run the macOS packaging smoke job in this Linux sandbox.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/factory-sdk/src/orchestrator/factory.test.ts`:
- Around line 966-969: Add a final explicit assertion after the existing
expectations in the V1 reaper test to verify process liveness: assert that no
killed entry has a nonzero signal except the protected broker PID 68009 and that
the set of alive PIDs equals exactly [68009]; specifically, add checks against
the killed array (e.g., ensure killed.every(e => e.pid === 68009 || e.signal ===
0)) and assert report.alive or an equivalent liveness source contains only
68009, referencing the existing symbols report, killed, and the protected pid
68009.

In `@packages/factory-sdk/src/orchestrator/factory.ts`:
- Around line 924-945: appendAgent currently persists agents with pids returned
from this.#terminationRoots without removing protected broker PIDs, which causes
reaper to skip name-based resolution; after obtaining const { pids } = await
this.#terminationRoots(agentName, tracked) filter out protected PIDs (e.g.,
using the existing protected-PID checker on the class such as
this.#isProtectedPid or a protectedPidSet) before building the processes array
and before pushing into agents so pids = pids.filter(pid =>
!this.#isProtectedPid(pid)); also filter processes to match the filtered pids
and ensure seenAgents/registryHandoffKey logic still applies so protected PIDs
are never persisted in agents.
- Around line 885-899: The catch block currently deletes all handoff keys for
handoffAgents which can remove pre-existing entries; change the code to track
which registry keys you actually added before calling `#writeInFlightRegistry`
(e.g., create a local array/set newKeys and push registryHandoffKey(agent.issue,
agent.name) when adding to this.#dispatchFailureReaperHandoffs inside the try),
and in the catch only delete those tracked newKeys instead of deleting every
handoff for handoffAgents; keep uses of
`#increment`('dispatchFailureReaperHandoffFailures') and the logging as-is.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ac57f142-7502-473b-a740-30671ffbeaa8

📥 Commits

Reviewing files that changed from the base of the PR and between 97ae199 and c77a088.

📒 Files selected for processing (2)
  • packages/factory-sdk/src/orchestrator/factory.test.ts
  • packages/factory-sdk/src/orchestrator/factory.ts

Comment on lines +966 to +969
expect(report.reaped.map((entry) => entry.pid)).toEqual([7_302, 7_303, 7_301])
expect(killed.some((entry) => entry.pid === 68_009 && entry.signal !== 0)).toBe(false)
expect(report.skipped).toContainEqual({ pid: 68_009, reason: 'protected pid' })
} finally {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add an explicit zero-survivor assertion for the V1 reaper scenario.

This test verifies kill/reap reporting but doesn’t assert final process liveness. Add a post-condition that only protected broker PID 68_009 remains alive.

🔧 Suggested fix
       expect(report.reaped.map((entry) => entry.pid)).toEqual([7_302, 7_303, 7_301])
       expect(killed.some((entry) => entry.pid === 68_009 && entry.signal !== 0)).toBe(false)
       expect(report.skipped).toContainEqual({ pid: 68_009, reason: 'protected pid' })
+      expect(alive).toEqual(new Set([68_009]))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
expect(report.reaped.map((entry) => entry.pid)).toEqual([7_302, 7_303, 7_301])
expect(killed.some((entry) => entry.pid === 68_009 && entry.signal !== 0)).toBe(false)
expect(report.skipped).toContainEqual({ pid: 68_009, reason: 'protected pid' })
} finally {
expect(report.reaped.map((entry) => entry.pid)).toEqual([7_302, 7_303, 7_301])
expect(killed.some((entry) => entry.pid === 68_009 && entry.signal !== 0)).toBe(false)
expect(report.skipped).toContainEqual({ pid: 68_009, reason: 'protected pid' })
expect(alive).toEqual(new Set([68_009]))
} finally {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/factory-sdk/src/orchestrator/factory.test.ts` around lines 966 -
969, Add a final explicit assertion after the existing expectations in the V1
reaper test to verify process liveness: assert that no killed entry has a
nonzero signal except the protected broker PID 68009 and that the set of alive
PIDs equals exactly [68009]; specifically, add checks against the killed array
(e.g., ensure killed.every(e => e.pid === 68009 || e.signal === 0)) and assert
report.alive or an equivalent liveness source contains only 68009, referencing
the existing symbols report, killed, and the protected pid 68009.

Comment on lines +885 to +899
try {
for (const agent of handoffAgents) {
this.#dispatchFailureReaperHandoffs.set(registryHandoffKey(agent.issue, agent.name), agent)
}
await this.#writeInFlightRegistry()
this.#increment('dispatchFailureReaperHandoffs')
this.#logger.warn?.('[factory] persisted dispatch-failed agents for orphan reaper', {
issue: record.issue,
agents: handoffAgents.map((agent) => agent.name).sort(),
})
} catch (error) {
this.#increment('dispatchFailureReaperHandoffFailures')
for (const agent of handoffAgents) {
this.#dispatchFailureReaperHandoffs.delete(registryHandoffKey(agent.issue, agent.name))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve prior handoff entries on persistence failure rollback.

Lines 897-899 always delete keys after a write failure. If the same issue/agent handoff was already persisted earlier, this drops that prior entry from memory and a subsequent registry rewrite can erase the durable handoff.

🔧 Suggested fix
   async `#persistDispatchFailureReaperHandoff`(record: InFlightIssue, handoffAgents: RegistryHandoffAgent[]): Promise<void> {
     if (record.dryRun || handoffAgents.length === 0) {
       return
     }

+    const previousByKey = new Map<string, RegistryHandoffAgent | undefined>()
     try {
       for (const agent of handoffAgents) {
-        this.#dispatchFailureReaperHandoffs.set(registryHandoffKey(agent.issue, agent.name), agent)
+        const key = registryHandoffKey(agent.issue, agent.name)
+        previousByKey.set(key, this.#dispatchFailureReaperHandoffs.get(key))
+        this.#dispatchFailureReaperHandoffs.set(key, agent)
       }
       await this.#writeInFlightRegistry()
       this.#increment('dispatchFailureReaperHandoffs')
       this.#logger.warn?.('[factory] persisted dispatch-failed agents for orphan reaper', {
         issue: record.issue,
         agents: handoffAgents.map((agent) => agent.name).sort(),
       })
     } catch (error) {
       this.#increment('dispatchFailureReaperHandoffFailures')
-      for (const agent of handoffAgents) {
-        this.#dispatchFailureReaperHandoffs.delete(registryHandoffKey(agent.issue, agent.name))
+      for (const [key, previous] of previousByKey) {
+        if (previous) {
+          this.#dispatchFailureReaperHandoffs.set(key, previous)
+        } else {
+          this.#dispatchFailureReaperHandoffs.delete(key)
+        }
       }
       this.#logger.error?.('[factory] failed to persist dispatch-failed agents for orphan reaper', {
         issue: record.issue,
         error,
       })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
for (const agent of handoffAgents) {
this.#dispatchFailureReaperHandoffs.set(registryHandoffKey(agent.issue, agent.name), agent)
}
await this.#writeInFlightRegistry()
this.#increment('dispatchFailureReaperHandoffs')
this.#logger.warn?.('[factory] persisted dispatch-failed agents for orphan reaper', {
issue: record.issue,
agents: handoffAgents.map((agent) => agent.name).sort(),
})
} catch (error) {
this.#increment('dispatchFailureReaperHandoffFailures')
for (const agent of handoffAgents) {
this.#dispatchFailureReaperHandoffs.delete(registryHandoffKey(agent.issue, agent.name))
}
async `#persistDispatchFailureReaperHandoff`(record: InFlightIssue, handoffAgents: RegistryHandoffAgent[]): Promise<void> {
if (record.dryRun || handoffAgents.length === 0) {
return
}
const previousByKey = new Map<string, RegistryHandoffAgent | undefined>()
try {
for (const agent of handoffAgents) {
const key = registryHandoffKey(agent.issue, agent.name)
previousByKey.set(key, this.#dispatchFailureReaperHandoffs.get(key))
this.#dispatchFailureReaperHandoffs.set(key, agent)
}
await this.#writeInFlightRegistry()
this.#increment('dispatchFailureReaperHandoffs')
this.#logger.warn?.('[factory] persisted dispatch-failed agents for orphan reaper', {
issue: record.issue,
agents: handoffAgents.map((agent) => agent.name).sort(),
})
} catch (error) {
this.#increment('dispatchFailureReaperHandoffFailures')
for (const [key, previous] of previousByKey) {
if (previous) {
this.#dispatchFailureReaperHandoffs.set(key, previous)
} else {
this.#dispatchFailureReaperHandoffs.delete(key)
}
}
this.#logger.error?.('[factory] failed to persist dispatch-failed agents for orphan reaper', {
issue: record.issue,
error,
})
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/factory-sdk/src/orchestrator/factory.ts` around lines 885 - 899, The
catch block currently deletes all handoff keys for handoffAgents which can
remove pre-existing entries; change the code to track which registry keys you
actually added before calling `#writeInFlightRegistry` (e.g., create a local
array/set newKeys and push registryHandoffKey(agent.issue, agent.name) when
adding to this.#dispatchFailureReaperHandoffs inside the try), and in the catch
only delete those tracked newKeys instead of deleting every handoff for
handoffAgents; keep uses of `#increment`('dispatchFailureReaperHandoffFailures')
and the logging as-is.

Comment on lines +924 to +945
const appendAgent = async (issue: IssueRef, agentName: string, tracked: TrackedAgent): Promise<void> => {
const key = registryHandoffKey(issue, agentName)
if (seenAgents.has(key)) {
return
}
seenAgents.add(key)
const { pids } = await this.#terminationRoots(agentName, tracked)
const processes = []
for (const pid of pids) {
const identity = await this.#processIdentityReader(pid)
if (identity && identity.cmdline.includes(agentName)) {
processes.push({ ...identity, agentName })
}
}
agents.push({
name: agentName,
role: tracked.spec.role,
issue,
sessionRef: tracked.sessionRef,
pids,
processes,
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Filter protected PIDs before persisting handoff registry agents.

Line 930 resolves roots without a protected-PID filter. If a protected broker PID is persisted, reaper treats the agent as already PID-resolved and skips name-based resolution, which can leave child orphan processes unreaped.

🔧 Suggested fix
   async `#writeInFlightRegistry`(
     path = this.#config.loop.registryPath,
     heartbeatPath = this.#config.loop.heartbeatPath,
     empty = false,
   ): Promise<void> {
     const updatedAtMs = this.#clock.now()
     const agents: FactoryInFlightRegistryAgent[] = []
     const seenAgents = new Set<string>()
+    const protectedPids = await this.#protectedPids()
+    const protectedPidSet = new Set(protectedPids)
     const appendAgent = async (issue: IssueRef, agentName: string, tracked: TrackedAgent): Promise<void> => {
       const key = registryHandoffKey(issue, agentName)
       if (seenAgents.has(key)) {
         return
       }
       seenAgents.add(key)
-      const { pids } = await this.#terminationRoots(agentName, tracked)
+      const { pids } = await this.#terminationRoots(agentName, tracked, protectedPids)
+      const persistedPids = pids.filter((pid) => !protectedPidSet.has(pid))
       const processes = []
-      for (const pid of pids) {
+      for (const pid of persistedPids) {
         const identity = await this.#processIdentityReader(pid)
         if (identity && identity.cmdline.includes(agentName)) {
           processes.push({ ...identity, agentName })
         }
       }
       agents.push({
         name: agentName,
         role: tracked.spec.role,
         issue,
         sessionRef: tracked.sessionRef,
-        pids,
+        pids: persistedPids,
         processes,
       })
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/factory-sdk/src/orchestrator/factory.ts` around lines 924 - 945,
appendAgent currently persists agents with pids returned from
this.#terminationRoots without removing protected broker PIDs, which causes
reaper to skip name-based resolution; after obtaining const { pids } = await
this.#terminationRoots(agentName, tracked) filter out protected PIDs (e.g.,
using the existing protected-PID checker on the class such as
this.#isProtectedPid or a protectedPidSet) before building the processes array
and before pushing into agents so pids = pids.filter(pid =>
!this.#isProtectedPid(pid)); also filter processes to match the filtered pids
and ensure seenAgents/registryHandoffKey logic still applies so protected PIDs
are never persisted in agents.

@agent-relay-code

Copy link
Copy Markdown
Contributor

Implemented fixes for the validated PR review findings.

Changed:

  • factory.ts: failed handoff persistence now restores prior in-memory handoffs instead of deleting pre-existing entries.
  • factory.ts: registry writes now resolve and filter protected PIDs before persisting agent PID/process entries.
  • factory.test.ts: added the explicit final liveness assertion that only the protected broker PID remains alive.

Addressed comments

  • gemini-code-assist[bot]: quota-limit warning only; no code finding to validate or fix.
  • coderabbitai[bot]: walkthrough/pre-merge comment plus ESLint tool network warning; no code change required. Local npm run lint passes with 0 errors.
  • coderabbitai[bot]: protected broker PIDs could be persisted and block name-based reaper resolution; fixed in factory.ts.
  • coderabbitai[bot]: failed handoff registry rewrite could delete pre-existing handoff entries; fixed in factory.ts.
  • coderabbitai[bot]: requested explicit liveness assertion in the reaper regression; fixed in factory.test.ts.
  • agent-relay-code[bot]: stale dispatch-failure handoffs after later success/completion; already present in the current checkout at factory.ts, factory.ts, with regression coverage at factory.test.ts.

Advisory Notes

None.

Local validation

Passed locally:

  • npm run verify:mcp-resources-drift
  • npm run lint
  • npm run typecheck:web
  • npm run typecheck:node
  • npm test
  • npx vitest run
  • npm run build
  • npm run build:web
  • npx playwright test --config playwright.fidelity.config.ts
  • npx playwright test --config playwright.redraw.config.ts

I did not run the macOS packaging job in this Linux sandbox.

@kjgbot kjgbot force-pushed the factory-sdk-v2fix11b-sb-impl2 branch from c77a088 to d5c2ae3 Compare June 12, 2026 23:52
@kjgbot kjgbot merged commit 764c235 into main Jun 12, 2026
8 checks passed
@kjgbot kjgbot deleted the factory-sdk-v2fix11b-sb-impl2 branch June 12, 2026 23:58
@agent-relay-code

Copy link
Copy Markdown
Contributor

Implemented the validated PR fixes.

Changed:

  • Preserved existing dispatch-failure handoff entries if registry persistence fails, instead of deleting/restoring the wrong map state: factory.ts
  • Filtered protected broker PIDs out before persisting registry agent pids/processes, while still passing protected PIDs into PID resolution: factory.ts
  • Added the requested explicit liveness assertion that only the protected broker PID remains alive after reaping: factory.test.ts

Addressed comments

  • gemini-code-assist[bot]: quota-limit warning only; no code finding to validate or fix.
  • coderabbitai[bot]: walkthrough/pre-merge summary plus ESLint tool network warning; no code finding. Local npm run lint completes with warnings only.
  • coderabbitai[bot]: protected broker PIDs could be persisted and block name-based reaper resolution; fixed in factory.ts.
  • coderabbitai[bot]: failed handoff persistence rollback could remove pre-existing handoff entries; fixed in factory.ts.
  • coderabbitai[bot]: requested explicit final liveness assertion in the reaper regression; fixed in factory.test.ts.
  • agent-relay-code[bot]: stale dispatch-failure handoffs after later success/completion; already present in current checkout at factory.ts and factory.ts, with regression coverage at factory.test.ts.

Advisory Notes

None.

Local validation

Passed locally:

  • npm ci
  • npm run verify:mcp-resources-drift
  • npm run lint
  • npm run typecheck:web
  • npm run typecheck:node
  • npm test
  • npx vitest run
  • npx vitest run packages/factory-sdk/src/orchestrator/factory.test.ts packages/factory-sdk/src/orchestrator/reaper.test.ts
  • npm run build
  • npm run build:web
  • npx playwright install --with-deps chromium
  • npx playwright test --config playwright.fidelity.config.ts
  • npx playwright test --config playwright.redraw.config.ts

I did not run the macOS packaging job in this Linux sandbox, and I did not verify GitHub-side mergeability/check status from here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant