Files
PaperClipAI/server
DottaandPaperclip 2a2071340d refactor(server): extract heartbeat runtime selection (#15746)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Heartbeat execution prepares a runtime, dispatches work, and records
the result.
> - Earlier refactors separated workspace services, scheduling, and
completion.
> - The executor still builds native inputs and records runtime
selection inline.
> - This preparation must preserve admitted inputs and serialize with
Stop.
> - This pull request moves that phase into a typed runtime-selection
module.
> - Reviewers can inspect runtime preparation separately from dispatch
and cleanup.

## Linked Issues or Issue Description

Refs: #15732.

**What existing behavior does this improve?**

Maintainability of heartbeat runtime preparation and selection.

**Subsystem affected**

server/ — orchestration services.

**Current behavior**

The main heartbeat service has 8,128 lines. `executeRun` builds or
restores native inputs, selects sessions and sandbox lifecycle, and
records native or legacy selection inline.

**Proposed behavior**

Move this phase into
`server/src/services/heartbeat/runtime-selection.ts`. The executor calls
`selectHeartbeatRuntime` at the existing boundary and receives an
explicit selection result. The main file becomes 7,275 lines, a
reduction of 853 lines.

**Reason and benefit**

This gives runtime selection its own typed boundary and direct tests. It
preserves existing decisions, database transactions, and cleanup
ordering.

**Breaking changes**

None intended. All public heartbeat exports remain available.

## What Changed

- Move native input assembly, completion contract selection, checkpoint
lookup, runtime persistence, and native workspace-sync preparation into
`selectHeartbeatRuntime`.
- Preserve the row lock and controller lease check that serialize native
selection with cancellation.
- Report lifecycle and ownership changes to the executor immediately,
including when a later preparation step throws.
- Move sandbox lifecycle and model fallback helpers with compatible
public re-exports.
- Add 12 database-backed boundary tests. Update the existing
session-recovery source test and developer guide.

## Verification

- Structural AST comparison against current `master` confirms the
784-line selection block, moved helpers, and remaining service bodies
are unchanged after normalizing boundary callbacks. All 140 public
exports are preserved.
- On final head `2eddaa485f`, all 12 new database-backed tests and 83
existing lifecycle, selection, fallback-warning, and session regression
tests pass (95 total).
- Five executor integration cases passed before the rebase. Their
final-head rerun could not start because the local checkout was removed
during verification; no assertions ran in that last attempt.
- `pnpm -r typecheck` and `pnpm build` both pass on final head.
- Local verification limitations: the full `pnpm test:run` was
attempted, then stopped after database/process startup timeouts in
concurrent local runs. Two unchanged optional real-runner session cases
timed out on the initial run and one isolated retry; they were excluded
from the 95-test focused run. CI also skips those two binary-dependent
cases.
- All CI gates pass on final head `2eddaa485f`: typecheck, build,
general and serialized tests, runner checks, E2E, and canary dry run.
- Greptile reviewed final head at 5/5 with no actionable findings.

## Risks

This boundary controls native admission and cleanup ownership. Losing an
update after a later exception could change resource cleanup. Immediate
callbacks preserve those updates. Tests cover Stop races, lost
controller leases, immutable admitted inputs, competing runtime
selection, and workspace-sync failures. The change adds no schema or API
behavior.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, code editing, and command
execution. The session does not expose the exact model variant or
context window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (95 focused tests on final
head; broader local limitations documented above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-10 07:31:15 -05:00
..