Files
paperclip/packages/db/src/migrations/meta/_journal.json
T
Devin Foley 13551b2bac Add local environment lifecycle (#4297)
## Thinking Path

> - Paperclip orchestrates AI agents for zero-human companies.
> - Every heartbeat run needs a concrete place where the agent's adapter
process executes.
> - Today that execution location is implicitly the local machine, which
makes it hard to track, audit, and manage as a first-class runtime
concern.
> - The first step is to represent the current local execution path
explicitly without changing how users experience agent runs.
> - This pull request adds core Environment and Environment Lease
records, then routes existing local heartbeat execution through a
default `Local` environment.
> - The benefit is that local runs remain behavior-preserving while the
system now has durable environment identity, lease lifecycle tracking,
and activity records for execution placement.

## What Changed

- Added `environments` and `environment_leases` database tables, schema
exports, and migration `0065_environments.sql`.
- Added shared environment constants, TypeScript types, and validators
for environment drivers, statuses, lease policies, lease statuses, and
cleanup states.
- Added `environmentService` for listing, reading, creating, updating,
and ensuring company-scoped environments.
- Added environment lease lifecycle operations for acquire, metadata
update, single-lease release, and run-wide release.
- Updated heartbeat execution to lazily ensure a company-scoped default
`Local` environment before adapter execution.
- Updated heartbeat execution to acquire an ephemeral local environment
lease, write `paperclipEnvironment` into the run context snapshot, and
release active leases during run finalization.
- Added activity log events for environment lease acquisition and
release.
- Added tests for environment service behavior and the local heartbeat
environment lifecycle.
- Added a CI-follow-up heartbeat guard so deferred issue comment wakes
are promoted before automatic missing-comment retries, with focused
batching test coverage.

## Verification

Local verification run for this branch:

- `pnpm -r typecheck`
- `pnpm build`
- `pnpm exec vitest run server/src/__tests__/environment-service.test.ts
server/src/__tests__/heartbeat-local-environment.test.ts --pool=forks`

Additional reviewer/CI verification:

- Confirm `pnpm-lock.yaml` is not modified.
- Confirm `pnpm test:run` passes in CI.
- Confirm `PAPERCLIP_E2E_SKIP_LLM=true pnpm run test:e2e` passes in CI.
- Confirm a local heartbeat run creates one active `Local` environment
when needed, records one lease for the run, releases the lease when the
run finishes, and includes `paperclipEnvironment` in the run context
snapshot.

Screenshots: not applicable; this PR has no UI changes.

## Risks

- Migration risk: introduces two new tables and a new migration journal
entry. Review should verify company scoping, indexes, foreign keys, and
enum defaults are correct.
- Lifecycle risk: heartbeat finalization now releases environment leases
in addition to existing runtime cleanup. A finalization bug could leave
stale active leases or mark a failed run's lease incorrectly.
- Behavior-preservation risk: local adapter execution should remain
unchanged apart from environment bookkeeping. Review should pay
attention to the heartbeat path around context snapshot updates and
final cleanup ordering.
- Activity volume risk: each heartbeat run now logs lease acquisition
and release events, increasing activity log volume by two records per
run.

## Model Used

OpenAI GPT-5.4 via Codex CLI. Capabilities used: repository inspection,
TypeScript implementation review, local test/build execution, and
PR-description drafting.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots (N/A: no UI changes)
- [x] I have updated relevant documentation to reflect my changes (N/A:
no user-facing docs or commands changed)
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-22 20:07:41 -07:00

469 lines
9.5 KiB
JSON

{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1771300567463,
"tag": "0000_mature_masked_marvel",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1771349039633,
"tag": "0001_fast_northstar",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1771349403162,
"tag": "0002_big_zaladane",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1771456737635,
"tag": "0003_shallow_quentin_quire",
"breakpoints": true
},
{
"idx": 4,
"version": "7",
"when": 1771545600000,
"tag": "0004_issue_identifiers",
"breakpoints": true
},
{
"idx": 5,
"version": "7",
"when": 1771545601000,
"tag": "0005_chief_luke_cage",
"breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1771545602000,
"tag": "0006_overjoyed_mister_sinister",
"breakpoints": true
},
{
"idx": 7,
"version": "7",
"when": 1771545603000,
"tag": "0007_new_quentin_quire",
"breakpoints": true
},
{
"idx": 8,
"version": "7",
"when": 1771534160426,
"tag": "0008_amused_zzzax",
"breakpoints": true
},
{
"idx": 9,
"version": "7",
"when": 1771534211029,
"tag": "0009_fast_jackal",
"breakpoints": true
},
{
"idx": 10,
"version": "7",
"when": 1771605173513,
"tag": "0010_stale_justin_hammer",
"breakpoints": true
},
{
"idx": 11,
"version": "7",
"when": 1771616419708,
"tag": "0011_windy_corsair",
"breakpoints": true
},
{
"idx": 12,
"version": "7",
"when": 1771619674673,
"tag": "0012_perpetual_ser_duncan",
"breakpoints": true
},
{
"idx": 13,
"version": "7",
"when": 1771623691139,
"tag": "0013_dashing_wasp",
"breakpoints": true
},
{
"idx": 14,
"version": "7",
"when": 1771691806349,
"tag": "0014_many_mikhail_rasputin",
"breakpoints": true
},
{
"idx": 15,
"version": "7",
"when": 1771865100000,
"tag": "0015_project_color_archived",
"breakpoints": true
},
{
"idx": 16,
"version": "7",
"when": 1771955900000,
"tag": "0016_agent_icon",
"breakpoints": true
},
{
"idx": 17,
"version": "7",
"when": 1771883888199,
"tag": "0017_tiresome_gabe_jones",
"breakpoints": true
},
{
"idx": 18,
"version": "7",
"when": 1771897769629,
"tag": "0018_flat_sleepwalker",
"breakpoints": true
},
{
"idx": 19,
"version": "7",
"when": 1772029333401,
"tag": "0019_public_victor_mancha",
"breakpoints": true
},
{
"idx": 20,
"version": "7",
"when": 1772032176413,
"tag": "0020_white_anita_blake",
"breakpoints": true
},
{
"idx": 21,
"version": "7",
"when": 1772122471656,
"tag": "0021_chief_vindicator",
"breakpoints": true
},
{
"idx": 22,
"version": "7",
"when": 1772186400000,
"tag": "0022_company_brand_color",
"breakpoints": true
},
{
"idx": 23,
"version": "7",
"when": 1772139727599,
"tag": "0023_fair_lethal_legion",
"breakpoints": true
},
{
"idx": 24,
"version": "7",
"when": 1772806603601,
"tag": "0024_far_beast",
"breakpoints": true
},
{
"idx": 25,
"version": "7",
"when": 1772807461603,
"tag": "0025_nasty_salo",
"breakpoints": true
},
{
"idx": 26,
"version": "7",
"when": 1773089625430,
"tag": "0026_lying_pete_wisdom",
"breakpoints": true
},
{
"idx": 27,
"version": "7",
"when": 1773150731736,
"tag": "0027_tranquil_tenebrous",
"breakpoints": true
},
{
"idx": 28,
"version": "7",
"when": 1773432085646,
"tag": "0028_harsh_goliath",
"breakpoints": true
},
{
"idx": 29,
"version": "7",
"when": 1773417600000,
"tag": "0029_plugin_tables",
"breakpoints": true
},
{
"idx": 30,
"version": "7",
"when": 1773670925214,
"tag": "0030_rich_magneto",
"breakpoints": true
},
{
"idx": 31,
"version": "7",
"when": 1773511922713,
"tag": "0031_zippy_magma",
"breakpoints": true
},
{
"idx": 32,
"version": "7",
"when": 1773542934499,
"tag": "0032_pretty_doctor_octopus",
"breakpoints": true
},
{
"idx": 33,
"version": "7",
"when": 1773664961967,
"tag": "0033_shiny_black_tarantula",
"breakpoints": true
},
{
"idx": 34,
"version": "7",
"when": 1773697572188,
"tag": "0034_fat_dormammu",
"breakpoints": true
},
{
"idx": 35,
"version": "7",
"when": 1773698696169,
"tag": "0035_marvelous_satana",
"breakpoints": true
},
{
"idx": 36,
"version": "7",
"when": 1773756213455,
"tag": "0036_cheerful_nitro",
"breakpoints": true
},
{
"idx": 37,
"version": "7",
"when": 1773756922363,
"tag": "0037_friendly_eddie_brock",
"breakpoints": true
},
{
"idx": 38,
"version": "7",
"when": 1773931592563,
"tag": "0038_careless_iron_monger",
"breakpoints": true
},
{
"idx": 39,
"version": "7",
"when": 1773926116580,
"tag": "0039_fat_magneto",
"breakpoints": true
},
{
"idx": 40,
"version": "7",
"when": 1773927102783,
"tag": "0040_eager_shotgun",
"breakpoints": true
},
{
"idx": 41,
"version": "7",
"when": 1774011294562,
"tag": "0041_curly_maria_hill",
"breakpoints": true
},
{
"idx": 42,
"version": "7",
"when": 1774031825634,
"tag": "0042_spotty_the_renegades",
"breakpoints": true
},
{
"idx": 43,
"version": "7",
"when": 1774008910991,
"tag": "0043_reflective_captain_universe",
"breakpoints": true
},
{
"idx": 44,
"version": "7",
"when": 1774269579794,
"tag": "0044_illegal_toad",
"breakpoints": true
},
{
"idx": 45,
"version": "7",
"when": 1774530504348,
"tag": "0045_workable_shockwave",
"breakpoints": true
},
{
"idx": 46,
"version": "7",
"when": 1774960197878,
"tag": "0046_smooth_sentinels",
"breakpoints": true
},
{
"idx": 47,
"version": "7",
"when": 1775137972687,
"tag": "0047_overjoyed_groot",
"breakpoints": true
},
{
"idx": 48,
"version": "7",
"when": 1775145655557,
"tag": "0048_flashy_marrow",
"breakpoints": true
},
{
"idx": 49,
"version": "7",
"when": 1775349863293,
"tag": "0049_flawless_abomination",
"breakpoints": true
},
{
"idx": 50,
"version": "7",
"when": 1775487782768,
"tag": "0050_stiff_luckman",
"breakpoints": true
},
{
"idx": 51,
"version": "7",
"when": 1775524651831,
"tag": "0051_young_korg",
"breakpoints": true
},
{
"idx": 52,
"version": "7",
"when": 1775571715162,
"tag": "0052_mushy_trauma",
"breakpoints": true
},
{
"idx": 53,
"version": "7",
"when": 1775604018515,
"tag": "0053_sharp_wild_child",
"breakpoints": true
},
{
"idx": 54,
"version": "7",
"when": 1775750400000,
"tag": "0054_draft_routines",
"breakpoints": true
},
{
"idx": 55,
"version": "7",
"when": 1775825256196,
"tag": "0055_kind_weapon_omega",
"breakpoints": true
},
{
"idx": 56,
"version": "7",
"when": 1776084034244,
"tag": "0056_spooky_ultragirl",
"breakpoints": true
},
{
"idx": 57,
"version": "7",
"when": 1776309613598,
"tag": "0057_tidy_join_requests",
"breakpoints": true
},
{
"idx": 58,
"version": "7",
"when": 1776542245004,
"tag": "0058_wealthy_starbolt",
"breakpoints": true
},
{
"idx": 59,
"version": "7",
"when": 1776542246000,
"tag": "0059_plugin_database_namespaces",
"breakpoints": true
},
{
"idx": 60,
"version": "7",
"when": 1776717606743,
"tag": "0060_orange_annihilus",
"breakpoints": true
},
{
"idx": 61,
"version": "7",
"when": 1776785165389,
"tag": "0061_lively_thor_girl",
"breakpoints": true
},
{
"idx": 62,
"version": "7",
"when": 1776780000000,
"tag": "0062_routine_run_dispatch_fingerprint",
"breakpoints": true
},
{
"idx": 63,
"version": "7",
"when": 1776780001000,
"tag": "0063_issue_thread_interactions",
"breakpoints": true
},
{
"idx": 64,
"version": "7",
"when": 1776780002000,
"tag": "0064_issue_thread_interaction_idempotency",
"breakpoints": true
},
{
"idx": 65,
"version": "7",
"when": 1776903900000,
"tag": "0065_environments",
"breakpoints": true
}
]
}