fix(e2e): retain workspace packages in rolling app copies (#18982)

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A rolling deployment must preserve running native agents and their
work.
> - The source test lane starts separate copies of the compiled app.
> - The development Runner entry imports source from the workspace
packages directory.
> - That directory was absent from each copied app, so its supervisor
could not start.
> - This pull request preserves the package link beside the existing CLI
link.
> - The test lane can then exercise real controller replacement.

## Linked Issues or Issue Description

**What happened?**

The source rolling-deployment supervisor failed with a missing Runner
module before starting a paid agent. The copied app had its compiled
server, dependencies and CLI link, but lacked the workspace package path
used by the development Runner entry.

**Expected behavior**

The copied app resolves its development dependencies and reaches
controller replacement.

**Steps to reproduce**

1. Build the server and UI from source with the development Runner
entry.
2. Run `tests/runner-e2e/controller-replacement-smoke.ts` with
disposable PostgreSQL and S3.
3. The old copy fails to resolve the Runner package. The fixed copy
completes the supervisor smoke.

No duplicate PR or issue was found in the exact-path search. This is a
test-harness fix within the existing rolling-deployment lane.

## What Changed

- Link the checkout's `packages/` directory into each copied source app.
- Document the shared dependency links and the limits of source-lane
evidence.

## Verification

- The missing-module failure was reproduced before the link was added.
- The same supervisor smoke passed after the fix and confirmed cleanup.
- The ten-check non-agent rolling smoke passed with disposable
PostgreSQL and S3.
- A fresh strict Codex rolling browser case passed. It kept the same
running process, native session and sandbox lease, acquired a new
controller generation, finalized the workspace, and continued from the
saved project.
- An earlier paid attempt failed the strict tool oracle because the
agent's own soak script omitted the argument delimiter for
hyphen-prefixed input. That failure remains recorded; the verifier and
task contract were unchanged for the passing attempt.
- Server TypeScript compilation passed in the source test checkout. Full
repository typecheck, tests and build are required in CI for this clean
PR head; they have not been repeated locally in this dependency-free
checkout.

- Exact head `d8addaa7723af5a013489e5bb6331dd1021dc6be`: all CI checks
passed or were intentionally skipped; Greptile 5/5 with no review
threads. Earlier cancelled jobs and the old recovery-fixture failure
remain retained; rebasing onto its existing master fix passed cleanly.

## Risks

Low production risk: only source test setup and its documentation
change. Each compiled app still has a separate cache and home. Its
workspace dependencies are shared, so this does not qualify a released
container or Railway deployment.

## Model Used

OpenAI Codex, exact model ID `gpt-6.1-sol`, with reasoning, tool use and
code execution. The host does not expose the 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 OR (b) described the
issue in-PR following the relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
ticket id or instance-derived details
- [x] I have run tests locally and they pass, with the earlier material
failure retained above
- [x] I have added or updated tests where applicable: the existing
supervisor and live rolling browser lane exercise this path
- [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>
This commit is contained in:
DottaandPaperclip authored and GitHub committed 2026-11-04 11:56:13 -06:00
1 parent edb9d29942
commit 8f06bd4e17
2 files changed
+5 -2

No files matched your search

+4 -2
View File
@@ -187,8 +187,10 @@ pnpm test:e2e:runner -- --id rolling-web-deployment.runner-codex.daytona.recover
```
This source lane requires a complete server/UI build and disposable S3 and
Postgres. Each controller has an independent compiled build and cache; shared
workspace dependencies mean it is not released-container or Railway evidence.
Postgres. Each controller has an independent compiled build and cache. The copied
app retains the checkout's `cli/` and `packages/` dependency links, including the
development Runner vendor entry. Shared workspace dependencies mean this is
not released-container or Railway evidence.
The read-only recovery observer captures the live predecessor's identity just
before handoff, then requires a new controller generation, authenticated Runner
attachment, and new canonical events for the original execution. No fixture
@@ -48,6 +48,7 @@ export async function startRollingDeploymentProcess(input: {
// This lane uses workspace dependencies, whose exports include TypeScript.
// Preserve the normal development plugin loader beside each compiled copy.
await symlink(path.join(input.repositoryRoot, "cli"), path.join(home, "app/cli"));
await symlink(path.join(input.repositoryRoot, "packages"), path.join(home, "app/packages"));
await writeFile(path.join(appRoot, "package.json"), '{"type":"module"}');
for (const omittedAsset of input.browser.omitAssets ?? []) {
if (!/^[A-Za-z0-9_.-]+\.js$/.test(omittedAsset)) throw new Error("Unsafe omitted asset fixture");