[PR #5652] [MERGED] perf(ci): keep fast built shards under ten minutes #7015

Closed
opened 2026-11-01 21:44:44 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/5652
Author: @morluto
Created: 10/20/2026
Status: ✅ Merged
Merged: 10/20/2026
Merged by: @morluto

Base: main ← Head: cursor/ci-shard-budget-82da


📝 Commits (6)

  • 1b1ef06 test(acceptance): split competing loader ownership across files
  • 70cb99a perf(ci): run eight fast built shards under a ten-minute budget
  • 5538c11 fix(ci): keep each scheduled file on one worker lane
  • 2d7b6e6 docs(testing): separate the shard budget from workflow time
  • 94fbf85 docs(testing): match fast shard count to lane scheduling
  • b4239e0 fix(ci): seed split loader durations from pre-split history

📊 Changes

9 files changed (+775 additions, -464 deletions)

View changed files

📝 .github/workflows/ci.yml (+5 -3)
📝 docs/testing.md (+43 -17)
➕ tests/acceptance/applications/javascriptLiteralLoaderOwnership.ts (+401 -0)
➕ tests/acceptance/applications/javascriptLiteralLoaderOwnershipEarly.test.ts (+29 -0)
➕ tests/acceptance/applications/javascriptLiteralLoaderOwnershipLate.test.ts (+18 -0)
➕ tests/acceptance/applications/javascriptLiteralLoaderOwnershipMiddle.test.ts (+18 -0)
📝 tests/acceptance/applications/javascriptLiteralPercentPaths.test.ts (+0 -385)
📝 tests/boundary/filesystem/ciTestSequencer.test.ts (+102 -19)
📝 tests/ciTestSequencer.ts (+159 -40)

📄 Description

Summary

Fast built Vitest shards were still about 15 minutes because one file took 578 seconds and five shards with two workers cannot schedule the built suite under ten minutes. This PR splits that loader matrix, schedules each file onto one worker lane, and runs eight fast built shards. The ten-minute target is the uncontended built shard job. Classification, build, and the portable-test merge are measured separately.

Rebased onto main 0add6a5aa after #5634. The fast/deep static split stays. The IDA retryable expectation stays main's: an unchanged invalid request is not retryable.

No linked issue. This continues the requested CI wall-time work on a new branch, separate from #5634, #5655, and #5658.

Problem and expected behavior

On 2026-10-20, run 39451548945 spent 925 seconds in its slowest built shard job (shard 4/5) and 874 seconds in built Vitest on shard 1/5. File timings from that run contain 7944 seconds of built module time. javascriptLiteralPercentPaths.test.ts alone was 578 seconds.

process-boundary stays serial and runs after the parallel projects (groupOrder 1, resolved maxWorkers 1). Dividing a parallel file by its worker count removes that file's own floor and can pack it onto a serial tail.

Published timings still name that one path. Without a bridge, the shortened file would keep the 578-second weight and the three new files would get only the suite median.

node_modules is 674 MiB. Shipping it between jobs would move more bytes than the 9-second npm ci. The existing npm download cache remains the setup cache.

Change and scope

  • Split the competing-loader matrix into three acceptance files. Every CLI and stdio MCP case is still asserted. The files share one helper.
  • Fast CI runs eight built shards after the build, plus the existing source job. Full qualification stays six covered shards.
  • The history sequencer places each file whole on one lane. Peers overlap only inside a sequence group, up to that group's resolved worker count. Later groups add their makespan.
  • Until history records one of the three new loader files, the sequencer shares the old path's duration by the pre-split case counts: 54/192 for the remaining file and 46/192 for each new file. A later artifact that names any new file is used as published.
  • docs/testing.md records the shard-job budget, that history bridge, and the measured classification, build, and merge that sit outside the shard job.

Not in this change: child-workflow concurrency (those lanes must keep the caller's group), and caching node_modules. Four local workers only improved a six-file sample from 96–101 seconds to 71–73 seconds, and a single file still occupies one worker, so the cap stays two. process-boundary is not made parallel; host sampling still shares one lane.

Follow the contribution scope. Not applicable: no new provider, target execution, injection, mutation, or protection recovery.

Contract and boundary impact

  • Semantic owner and earliest changed stage: CI test scheduling and acceptance test file layout. No product behavior change.
  • Contribution scope fit and linked maintainer decision: CI orchestration and test harness only. Not applicable.
  • CLI and MCP/tool-catalog contract: none. The same CLI and MCP cases still run.
  • Provider, bridge, target-format, or platform compatibility: none.
  • Evidence, artifact, provenance, or reconstruction contract: none.
  • Target selection, authority, upstream behavior, and cleanup details (if applicable): not applicable.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact (CI generates and validates ignored catalogs and skills/; edit authored instructions in .agents/skills/reverse-engineer-anything/ and never commit build outputs): none.

Expected effects: none of the target-interaction effects below. This changes CI scheduling and test file layout only.

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated: loader cases moved, not dropped; a partition test checks the three groups cover the name list once. Sequencer tests keep a 300-second file whole on a two-worker lane, add a serial file after a parallel file (160 seconds), and place one 100-second parallel file alone while two 60-second serial files share the other shard. A history test divides 192000 ms into 54000 and three times 46000, and leaves the map unchanged once any new path is present. ciFeedback merges one source blob and eight built blobs.
  • Base reproduction or other evidence: run 39451548945. Classification 15 seconds, build 49 seconds, portable-test merge 29 seconds, shard 1/5 setup 25 seconds around 874 seconds of built Vitest, slowest shard job 925 seconds. Lane schedule of that built inventory: five shards peak at 820 seconds of tests; six at 684 seconds. After splitting the 578-second file by case count (54 remain, 46 in each of three files), eight shards peak at 513 seconds of tests, about 538 seconds with the measured shard setup. Adding classification, build, and merge makes about 631 seconds of uncontended critical path. On this PR's pre-rebase run 39475793479, the one finished successful shard (5/8) spent 463 seconds in Vitest and 488 seconds for the job. Fail-fast then cancelled the rest. The red lanes matched main: IDA retryable and spawn E2BIG.
  • User-visible CLI/MCP output (if applicable): none.
  • Remaining proof gaps: hosted wall time for a complete eight-shard matrix on this head is not measured yet. The file schedule under-reads the five-shard run's hosted Vitest. Queue time can grow because each fast code PR starts three more shard jobs. Full qualification is still six covered shards. The 399-second loader-review file is still one file. The history bridge retires when a published artifact names one of the new loader files.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npm run check:ci:fast after the history seed — succeeded in 15.9 seconds (typecheck, lint:built, format:check).
  • npx vitest run tests/boundary/filesystem/ciTestSequencer.test.ts — 7 passed in 640ms (Node 24.18.0).
  • After the rebase onto 0add6a5aa, before this seed: npm run check:ci:fast succeeded in 48 seconds, and sequencer plus ciFeedback tests passed 13 tests in 5.1 seconds.
  • Earlier, before the rebase: npx vitest run on the three loader files, javascriptLiteralPercentPaths.test.ts, ciFeedback, and ciTestSequencer — 206 passed in 200.6 seconds.
  • Local worker sample, six acceptance/CLI files, 96 tests each run, all passed: two workers 96.3s and 100.8s; four workers 70.7s and 72.7s.
  • Lane probe during vitest --shard=1/2: process-boundary resolved maxWorkers=1; boundary resolved maxWorkers=2.

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: not run. This change does not select those lanes.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: not applicable.

Author readiness

Human owner: @morluto

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.
Open in Web Open in Cursor 

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/5652 **Author:** [@morluto](https://github.com/morluto) **Created:** 10/20/2026 **Status:** ✅ Merged **Merged:** 10/20/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `cursor/ci-shard-budget-82da` --- ### 📝 Commits (6) - [`1b1ef06`](https://github.com/morluto/rea/commit/1b1ef069a37e7e01bcef8f254dc9172bef0361e4) test(acceptance): split competing loader ownership across files - [`70cb99a`](https://github.com/morluto/rea/commit/70cb99aec36399bf6869ce75f98efe6690e0e254) perf(ci): run eight fast built shards under a ten-minute budget - [`5538c11`](https://github.com/morluto/rea/commit/5538c113f13f2e2635ff0dd955befd0b56e6e547) fix(ci): keep each scheduled file on one worker lane - [`2d7b6e6`](https://github.com/morluto/rea/commit/2d7b6e61641aa3cbdcca2af08b0c292c8edcbab7) docs(testing): separate the shard budget from workflow time - [`94fbf85`](https://github.com/morluto/rea/commit/94fbf859a8e29fed990718204fc9d4a7e8b2db42) docs(testing): match fast shard count to lane scheduling - [`b4239e0`](https://github.com/morluto/rea/commit/b4239e07d5c9a894432feef6884d282850377a99) fix(ci): seed split loader durations from pre-split history ### 📊 Changes **9 files changed** (+775 additions, -464 deletions) <details> <summary>View changed files</summary> 📝 `.github/workflows/ci.yml` (+5 -3) 📝 `docs/testing.md` (+43 -17) ➕ `tests/acceptance/applications/javascriptLiteralLoaderOwnership.ts` (+401 -0) ➕ `tests/acceptance/applications/javascriptLiteralLoaderOwnershipEarly.test.ts` (+29 -0) ➕ `tests/acceptance/applications/javascriptLiteralLoaderOwnershipLate.test.ts` (+18 -0) ➕ `tests/acceptance/applications/javascriptLiteralLoaderOwnershipMiddle.test.ts` (+18 -0) 📝 `tests/acceptance/applications/javascriptLiteralPercentPaths.test.ts` (+0 -385) 📝 `tests/boundary/filesystem/ciTestSequencer.test.ts` (+102 -19) 📝 `tests/ciTestSequencer.ts` (+159 -40) </details> ### 📄 Description <!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## Summary Fast built Vitest shards were still about 15 minutes because one file took 578 seconds and five shards with two workers cannot schedule the built suite under ten minutes. This PR splits that loader matrix, schedules each file onto one worker lane, and runs eight fast built shards. The ten-minute target is the uncontended built shard job. Classification, build, and the portable-test merge are measured separately. Rebased onto main `0add6a5aa` after #5634. The fast/deep static split stays. The IDA retryable expectation stays main's: an unchanged invalid request is not retryable. No linked issue. This continues the requested CI wall-time work on a new branch, separate from #5634, #5655, and #5658. ## Problem and expected behavior On 2026-10-20, run `39451548945` spent 925 seconds in its slowest built shard job (shard 4/5) and 874 seconds in built Vitest on shard 1/5. File timings from that run contain 7944 seconds of built module time. `javascriptLiteralPercentPaths.test.ts` alone was 578 seconds. `process-boundary` stays serial and runs after the parallel projects (`groupOrder` 1, resolved `maxWorkers` 1). Dividing a parallel file by its worker count removes that file's own floor and can pack it onto a serial tail. Published timings still name that one path. Without a bridge, the shortened file would keep the 578-second weight and the three new files would get only the suite median. `node_modules` is 674 MiB. Shipping it between jobs would move more bytes than the 9-second `npm ci`. The existing npm download cache remains the setup cache. ## Change and scope - Split the competing-loader matrix into three acceptance files. Every CLI and stdio MCP case is still asserted. The files share one helper. - Fast CI runs eight built shards after the build, plus the existing source job. Full qualification stays six covered shards. - The history sequencer places each file whole on one lane. Peers overlap only inside a sequence group, up to that group's resolved worker count. Later groups add their makespan. - Until history records one of the three new loader files, the sequencer shares the old path's duration by the pre-split case counts: 54/192 for the remaining file and 46/192 for each new file. A later artifact that names any new file is used as published. - `docs/testing.md` records the shard-job budget, that history bridge, and the measured classification, build, and merge that sit outside the shard job. Not in this change: child-workflow concurrency (those lanes must keep the caller's group), and caching `node_modules`. Four local workers only improved a six-file sample from 96–101 seconds to 71–73 seconds, and a single file still occupies one worker, so the cap stays two. `process-boundary` is not made parallel; host sampling still shares one lane. Follow the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope). Not applicable: no new provider, target execution, injection, mutation, or protection recovery. ## Contract and boundary impact - Semantic owner and earliest changed stage: CI test scheduling and acceptance test file layout. No product behavior change. - Contribution scope fit and linked maintainer decision: CI orchestration and test harness only. Not applicable. - CLI and MCP/tool-catalog contract: none. The same CLI and MCP cases still run. - Provider, bridge, target-format, or platform compatibility: none. - Evidence, artifact, provenance, or reconstruction contract: none. - Target selection, authority, upstream behavior, and cleanup details (if applicable): not applicable. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact (CI generates and validates ignored catalogs and `skills/`; edit authored instructions in `.agents/skills/reverse-engineer-anything/` and never commit build outputs): none. Expected effects: none of the target-interaction effects below. This changes CI scheduling and test file layout only. - [ ] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: loader cases moved, not dropped; a partition test checks the three groups cover the name list once. Sequencer tests keep a 300-second file whole on a two-worker lane, add a serial file after a parallel file (160 seconds), and place one 100-second parallel file alone while two 60-second serial files share the other shard. A history test divides 192000 ms into 54000 and three times 46000, and leaves the map unchanged once any new path is present. `ciFeedback` merges one source blob and eight built blobs. - Base reproduction or other evidence: run `39451548945`. Classification 15 seconds, build 49 seconds, portable-test merge 29 seconds, shard 1/5 setup 25 seconds around 874 seconds of built Vitest, slowest shard job 925 seconds. Lane schedule of that built inventory: five shards peak at 820 seconds of tests; six at 684 seconds. After splitting the 578-second file by case count (54 remain, 46 in each of three files), eight shards peak at 513 seconds of tests, about 538 seconds with the measured shard setup. Adding classification, build, and merge makes about 631 seconds of uncontended critical path. On this PR's pre-rebase run `39475793479`, the one finished successful shard (5/8) spent 463 seconds in Vitest and 488 seconds for the job. Fail-fast then cancelled the rest. The red lanes matched main: IDA `retryable` and `spawn E2BIG`. - User-visible CLI/MCP output (if applicable): none. - Remaining proof gaps: hosted wall time for a complete eight-shard matrix on this head is not measured yet. The file schedule under-reads the five-shard run's hosted Vitest. Queue time can grow because each fast code PR starts three more shard jobs. Full qualification is still six covered shards. The 399-second loader-review file is still one file. The history bridge retires when a published artifact names one of the new loader files. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npm run check:ci:fast` after the history seed — succeeded in 15.9 seconds (typecheck, lint:built, format:check). - `npx vitest run tests/boundary/filesystem/ciTestSequencer.test.ts` — 7 passed in 640ms (Node 24.18.0). - After the rebase onto `0add6a5aa`, before this seed: `npm run check:ci:fast` succeeded in 48 seconds, and sequencer plus `ciFeedback` tests passed 13 tests in 5.1 seconds. - Earlier, before the rebase: `npx vitest run` on the three loader files, `javascriptLiteralPercentPaths.test.ts`, `ciFeedback`, and `ciTestSequencer` — 206 passed in 200.6 seconds. - Local worker sample, six acceptance/CLI files, 96 tests each run, all passed: two workers 96.3s and 100.8s; four workers 70.7s and 72.7s. - Lane probe during `vitest --shard=1/2`: `process-boundary` resolved `maxWorkers=1`; `boundary` resolved `maxWorkers=2`. ## Compatibility, safety, and release - Breaking changes or migration steps: none. - Real Hopper/Ghidra, browser, or OS coverage: not run. This change does not select those lanes. - Package or release metadata impact: none. - Security, privacy, process, or containment review: not applicable. ## Author readiness Human owner: @morluto - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [ ] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-f85d7d37-0a4b-5e62-9992-2a20ade282da?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-f85d7d37-0a4b-5e62-9992-2a20ade282da&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-01 21:44:44 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#7015
No description provided.