Files
PaperClipAI/tests/e2e/workspace-bootstrap
DottaandPaperclip 37913e4907 refactor(heartbeat): extract run output recording (#15969)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Heartbeat runs stream adapter output and persist execution results.
> - Output recording currently sits inside the executor beside admission
and cleanup.
> - Log handles, sequence numbers, progress writes, and excerpt buffers
share one attempt lifetime.
> - This pull request moves that state and its callbacks into a
per-attempt recorder.
> - The executor keeps dispatch and finalization visible, while
finalization reads live output values.

## Linked Issues or Issue Description

**What existing behavior does this improve?**
Maintenance of heartbeat execution. This PR follows #15966, which is now
merged. The branch is rebased onto `master`; `git range-diff` confirms
that its extraction patch is unchanged.

**Current behavior**
`heartbeat.ts` has 4,740 lines and 195,258 bytes. It directly owns log
handles, excerpt buffers, output sequence numbers, progress flushes, and
adapter event callbacks.

**Proposed behavior**
`run-output.ts` owns the per-attempt recorder. The main file has 4,561
lines and 188,950 bytes; the recorder has 209 lines and 7,757 bytes.

**Reason and benefit**
Output state has one explicit lifetime and interface. The shared log
store and finalization policy retain their original owners. Related open
output work includes #12539 and #15524; this PR does not change
redaction policy.

**Breaking changes**
None intended. Public flush constants and log formatting exports remain
available from `heartbeat.ts`.

## What Changed

- Move log initialization, redaction, excerpts, progress persistence,
live delivery, and adapter callbacks into `createHeartbeatRunOutput`.
- Preserve the acquired log handle if later setup fails. Bind callbacks
to the execution-start run row.
- Pass live excerpt getters to success and failure completion so output
arriving during finalization remains visible.
- Add three real-database public-path tests. Extend browser acceptance
to inspect persisted worker stdout and output byte counts.
- Update the module map.

## Verification

- Before extraction: 23 tests pass, including all three new output
characterization cases.
- After extraction: 45 tests pass across output, log formatting, event
sequencing, and run completion. No skips.
- `pnpm -r typecheck` and `pnpm build` pass.
- Normalized syntax comparison confirms the moved bodies and
reconstructed executor match. Reviewed the factory ownership, callback
binding, getter wiring, and constant re-exports separately.
- Isolated browser acceptance: 2/2 pass, including persisted worker
stdout and matching final byte counts. The process worker completes
after recovery; persistent timeouts stop after three attempts. Both
terminal states survive reload.
- Hosted full-suite CI passes on
`d32c8fc40e72b9766bdd9e191d777e8dc554e3f2`; all 55 reported checks are
successful. Greptile is 5/5 with zero review threads.
- The initial chat shard timed out waiting for GitHub mention admission.
Its fixture mocks heartbeat wakeup and never calls the output recorder.
Both parameterized cases passed locally; the unchanged shard passed on
one rerun. No test or timeout changes.

- Merge preparation: all seven session-preparation and run-output
regression tests pass after rebasing onto `master`. Fresh full CI passes
for `60e2a49ce2879645a9f618a801e0ba0903ede161`: 55 successful checks and
two optional Storybook skips, including all eight browser shards,
typecheck, tests, and build. Greptile is 5/5 on this exact commit with
zero review threads.

## Risks

- A stale excerpt snapshot could lose output that arrives while
finalization awaits I/O. Passing-before/passing-after tests exercise
this for both successful and failed runs.
- Per-attempt state must not become service-wide. Each executor
constructs its own recorder and keeps the existing shared store.
- Browser acceptance uses a real process fixture and disposable data; it
makes no live provider calls.

## Model Used

OpenAI Codex, based on GPT-6, assisted with reasoning, code edits, tool
execution, and verification. The exact deployment model ID and
context-window size are not exposed in this session.

## 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
- [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-12 09:51:17 -05:00
..

Workspace bootstrap recovery acceptance

This opt-in suite uses a disposable loopback instance, real Git repositories, the real Git scan scheduler, durable retries, and the task UI. A deterministic process adapter verifies the prepared files and completes its task through the run-scoped API. It makes no model calls. The test Git executable injects a real timeout only when the test explicitly arms a marker inside its repository.

From a development worktree, start the foreground instance:

node cli/node_modules/tsx/dist/cli.mjs tests/e2e/workspace-bootstrap/launch.ts

The launcher creates an isolated test-drive, installs the Git shim, and sets a 10-second snapshot deadline after test-drive clears inherited configuration. Production's longer snapshot deadline would outlast the injected failure.

Set BOOTSTRAP_REAL_GIT to the absolute Git executable if it is not /usr/bin/git. Do not point this fixture at a normal development or production instance. The seeder checks the loopback host, trusted-local mode, and company name. It does not create tasks; each test creates its task through the UI.

Use the ready URL printed by test-drive:

WORKSPACE_BOOTSTRAP_TEST_URL=http://127.0.0.1:3100 \
pnpm exec playwright test --config tests/e2e/workspace-bootstrap/playwright.config.ts

The tests prove that one timeout schedules a retry and completes without manual Retry, that persistent timeouts stop after three total runs, and that the final state survives reload. Source edits remain intact and ignored private files are not copied. The worker also verifies that persisted task context contains the assignment, the full and compact prompt variants, and the description revision. Screenshots and failure traces go to test-results/workspace-bootstrap. Stop test-drive with Ctrl-C. Its disposable data directory remains for inspection.