Commit Graph
2 Commits
Author SHA1 Message Date
Nicky LeachandClaude Opus 5.5 97953e9b59 fix(ci): repair the weekly test-weight refresh and extend it to e2e and Runner lanes (#19650)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Contributors wait for PR CI before merge, so CI wall-clock time sets
the pace of work
> - CI test shards are balanced with per-file durations that a weekly
workflow refreshes
> - The weekly refresh has failed since 2026-11-02, and the e2e weights
have not been measured since 2026-09-15. Today e2e shards 3 and 6 take
7.0–7.7 minutes of tests, and shard 1 takes 4.3 minutes
> - A single file can also grow until it sets the time of its shard, and
nothing tells us about it
> - This pull request repairs the refresh, extends it to the e2e and
Runner package lanes, and warns about test files over 180 seconds
> - The benefit is balanced shards that stay balanced, and early notice
of oversized test files

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The weekly refresh of the test-duration weights that balance CI shards.

**Subsystem affected**

CI: `scripts/ci/refresh-test-durations.mjs`,
`.github/workflows/ci-test-durations.yml`, and the Vitest and Playwright
CI reporters.

**Current behavior**

- The 2026-11-02 refresh (run 41408033686) failed. `gh api …/logs` now
refuses output that contains terminal escape sequences.
- Most successful `cloud-readiness.yml` master runs are admission-only
and have no server jobs. The script took the newest 2 runs, so it would
fail with "No server timing jobs found" on most weeks.
- The e2e weights (`scripts/e2e-shard-durations.json`) have no refresh
and are from 2026-09-15.
- No signal tells us when one test file becomes too slow.

**Proposed behavior**

The refresh runs again, selects master runs that ran the server jobs,
refreshes the e2e and Runner package-lane weights from merged PRs, and
lists oversized files. CI writes a warning for each test file over 180
seconds.

**Reason and benefit**

Unbalanced shards add minutes to every PR. The current e2e weights put
472 seconds on the slowest shard. The new weights put about 300 seconds
on each shard.

**Breaking changes**

None. Weights change only shard placement, never which tests run.

## What Changed

- Add `scripts/ci/gh-api.mjs`. It always passes
`--allow-escape-sequences`, retries without the flag when an older `gh`
does not know it, and strips ANSI codes from logs.
- `scripts/ci/refresh-test-durations.mjs`:
- scans up to 50 master runs and uses the 2 newest that ran the server
jobs;
- adds the `--dry-run`, `--pr-body=<path>` and
`--lanes=server,e2e,runner` options;
- validates every lane before it writes a file. If a merged-PR lane has
fewer than 2 valid runs, it keeps the current weights and writes a
warning.
- Add `scripts/ci/pr-run-durations.mjs`. It uses the final passing
`pr.yml` run of each merged PR, and it validates:
  - the PR is merged into `master`;
  - the merge commit is in the checkout;
  - the run's head SHA is the PR's final head SHA;
  - every shard of the run succeeded.

  It parses Playwright per-spec times and Runner per-file times.
- Add `scripts/ci/oversized-test-files.mjs` (Vitest) and
`scripts/ci/oversized-test-files-playwright.mjs` (Playwright). In GitHub
Actions they write a `::warning` for each test file over
`PAPERCLIP_CI_OVERSIZED_TEST_FILE_SECONDS` (default 180). They never
fail a job. The root and Runner Vitest configs and the e2e Playwright
config load them.
- `scripts/ci/test-timing-reporter.mjs`: move the per-file duration
calculation into an exported `moduleDurationMs()` helper. The behavior
does not change.
- `.github/workflows/ci-test-durations.yml` and
`.github/ci-duration-pr.md`:
  - the bot PR can also update the e2e and Runner manifests;
  - the PR body lists oversized files;
  - the verify step also runs the new tests and the e2e shard tests.
- Refresh `scripts/e2e-shard-durations.json`: 56 of 56 specs measured
(before: 30), from merged PRs #19613, #19191 and #19176. The file now
uses the shared schema with `sources` and `coverage`.

## Verification

- `node --test scripts/ci/test-selection-pr-timings.test.mjs
scripts/ci/test-selection-timings.test.mjs
scripts/__tests__/e2e-shard.test.mjs`: 32/32 pass. These include the e2e
shard balance check with the new weights.
- `node scripts/ci/refresh-test-durations.mjs --dry-run` against real
GitHub data, all lanes:

| Manifest | Measured | Sources |
| --- | --- | --- |
| `general-server-shard-durations.json` | 1488/1534 files | master runs
42296943853, 42294279748 |
| `serialized-shard-durations.json` | 167/167 files | the same two runs
|
| `e2e-shard-durations.json` | 56/56 specs | PR runs 42296374365,
42297700476, 42296994179 |
| Runner `vitest-lane-durations.json` | 310/311 files | the same three
PR runs |

- e2e placement over 8 shards, with the new medians as the real costs:
  - with the old weights, the slowest shard has 472 seconds;
  - with the new weights, every shard has about 300 seconds.
- The dry run lists 12 files over 180 seconds. The largest is
`server/src/services/workspace-recovery.test.ts`, at 636 seconds.
- In this PR, only the e2e weight file changes. The weekly run refreshes
the server weights. The Runner manifest is added by #19646.

## Risks

- The `--allow-escape-sequences` path ran only in unit tests. The local
`gh` did not support the flag, so the real dry run used the fallback.
The next weekly run is the first real test of the flag.
- The changes to the bot-PR shell steps did not run in Actions yet.
- The e2e weights come from 3 PR runs. Real shard times vary more than
the estimate.
- This PR and #19637 both edit the `reporters` lists in
`vitest.config.ts` and `packages/paperclip-runner/vitest.config.ts`. The
second PR to merge needs a small merge resolution.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use and
code execution. A Claude sub-agent wrote the change, and the parent
session reviewed it.

## 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

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 15:50:02 -08:00
DottaandPaperclip e40de0c9e8 perf(ci): refresh test weights and narrow graph dependencies (#18464)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Contributors need fast, reliable CI feedback.
> - Diff-aware CI selects test files and partitions them into runner
jobs.
> - Stale cost estimates put several slow suites on the same runner.
Broad imports also couple small tests to large modules.
> - This PR refreshes test costs, runs independent graph discovery in
parallel, and narrows three dependency boundaries.
> - Selection safeguards and CODEOWNER-only AWS routing stay in force.

## Linked Issues or Issue Description

Refs #18398. This follows the audit of [PR #18427's verification
run](https://github.com/paperclipai/paperclip/actions/runs/41169978784).

The audit found 403 selected general-server files without timing
weights. Three suites measured at 232s, 122s and 116s shared one shard
because each received a roughly 2s fallback weight. Local graph
discovery across four projects took 43.7s serially and 21.7s with two
workers. A reverse-order repeat took 37.7s serially and 22.6s with two
workers. Both comparisons produced identical selection results. This is
a local measurement, not a claim about production CI speed.

## What Changed

- Refresh general-server costs for 1,285 of 1,309 current files and
serialized costs for all 163 files from two successful protected-master
Cloud readiness runs. Retain prior costs for unmeasured files, including
dedicated chat and native-runner suites.
- Record passing server file costs, including collection, setup and
environment preparation. A weekly hosted workflow validates trusted
source runs and opens a timing-only PR. It tests shard coverage, pauses
while a refresh PR is open, and never merges automatically.
- Discover at most two project graphs concurrently in isolated,
heap-limited Node processes. Cache repeated inventory reads within one
selection. Worker errors and timeouts retain the full task plan.
- Fetch only the merge commit and parents for the selector. A real
shallow-clone regression proves the complete diff still includes more
than 300 files, renames and deletions.
- Share the identical log viewer and run details between both
AgentDetail pages. The viewer test imports the shared implementation and
runs each of its 13 distinct cases once.
- Extract the pure API error class while preserving the API client's
public exports. Import delivery work signals through their existing
narrow DB export.

## Verification

- PASS: `pnpm -r typecheck` and `pnpm build`.
- PASS: 284 CI selection, timing, shallow-diff, sharding and routing
tests.
- PASS: 74 further cache, routing and graph-proof tests.
- PASS: 94 targeted UI assertions across the viewer, run invocation, API
errors/client and progress helpers. All 76 assertions in the 12 server
suites made independently selectable also pass.
- PASS: `pnpm check:token-gates`, module-boundary checks, YAML parsing
and `git diff --check`.
- PASS: [Full PR CI and required `ci / verify`
aggregate](https://github.com/paperclipai/paperclip/actions/runs/41206683345),
including all 12 general-server shards, all nine serialized shards,
workspace groups, chat suites, Runner lanes and build checks.
- PASS: [GitHub hosted real-workspace selector and cache/routing
qualification](https://github.com/paperclipai/paperclip/actions/runs/41206683205).
- PASS: Both Greptile and Paperclip reviews are 5/5 with no actionable
findings or inline comments on `7dc65c51b8`. The PR has no merge
conflicts.
- PASS: The production refresh parser accepted all 107 structured
file-cost records from a real successful server CI job, including
setup/loading cost.
- Local `pnpm test:run` completed all six chat shards successfully. The
duplicate monolithic local run was stopped after the complete remote
suite passed; it was not completed locally.

The focused log-viewer command improved from 18.84s (26 duplicate
variant cases) to 8.49s (all 13 distinct behavior cases). The dependency
audit confirms 12 server files and the API-error test no longer need
conservative always-run retention. Repartitioning the audited PR with
the new costs changes the slowest shard from 810s to 591s of summed
historical test execution (1,124 of 1,142 files measured). This is a
workload simulation, not measured new CI wall time.

## Risks

- Two graph processes use more peak memory. Each has a 2 GiB heap limit
and a three-minute timeout. Any failure preserves the original task
plan. Real workspace qualification runs in GitHub CI.
- Historical logs contain test/hook costs only. New reporter records add
loading/setup costs after merge. The manifests identify measurement
coverage and source runs. These weights change placement, never
permission to skip tests.
- Runner load adds timing noise. The refresh uses medians and requires
at least 90% measurement coverage in each lane.
- GitHub may require approval to run checks on a PR created with
`GITHUB_TOKEN`. Refreshes remain reviewable and do not merge themselves.
- The shared viewer is a mechanical extraction. Both pages retain their
existing exports, and the behavior assertions remain covered. AWS runner
authorization is unchanged.

## Model Used

OpenAI Codex, GPT-6, with repository inspection, reasoning, code
execution and GitHub tools. The exact deployment ID and context-window
size were 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 references)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (focused checks and six
chat shards; complete suite passed in CI as detailed 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-31 11:05:12 -05:00