ci: derive a job ceiling for lint, bundle-analysis and release (objectui#7270) - #7957
Merged
Merged
Conversation
…tui#7270)
Three jobs declared no job-level `timeout-minutes`, so their only backstop
was GitHub's 360-minute default. Two of them are required contexts, and this
repository has twice had a transient fault converted into a `cancelled` check
by a job ceiling (objectui#5304, objectui#6577) — a verdict the merge queue
cannot tell from `failure`.
Each ceiling is derived from that job's own measured run distribution, never
inherited from `ci.yml` (objectui#7048 fences that), and the derivation is
recorded beside the key: window, sample size, min/median/p95/max, and the rule.
- `lint.yml::lint` 25 (n=300, max 7m14s)
- `performance-budget.yml::bundle-analysis` 25 (n=300, max 5m23s)
- `changeset-release.yml::release` 40 (n=25, max 7m15s, plus the
900-second wait cap the job declares for itself)
`workflow-cache-save-bound.test.ts` gains a pin so removing a key or raising
one of these ceilings is no longer invisible.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013uAaxiwgYDybsTNV9xwa1M
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
baozhoutao
marked this pull request as ready for review
September 6, 2026 04:39
This was referenced Sep 6, 2026
baozhoutao
deleted the
claude/issue-7270-job-timeouts-derived-per-job
branch
September 6, 2026 05:05
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7270
Three jobs declared no job-level
timeout-minutes, so their only backstop was GitHub's documented 360-minute default. Two of them are required contexts. This PR gives each of the three a ceiling derived from that job's own measured run distribution, and records the derivation beside the key.The card asked for exactly one ruling — accept 360, or derive a number. The ruling taken here is derive, per job. Grounds are the card's own: this repository has twice had a transient fault converted into a
cancelledcheck by a job ceiling (objectui#5304, objectui#6577), andcancelledis a verdict the merge queue cannot tell fromfailure.The derivations
Per-job wall clock from the Actions jobs endpoint (
completed_atminusstarted_at— the job's own clock, never the run's total). Successful runs only.lint.yml::lintperformance-budget.yml::bundle-analysischangeset-release.yml::releaseRule: ceiling is the smallest round number that is at or above both
3 x maxandmax + 15min. ⛔ Nothing is inherited fromci.yml's 10/15/20/30/40 — objectui#7048 fences exactly that, and two of the three landing on 25 is arithmetic, not a shared constant.Why
releaseis 40 and not 25. Its honest slowest run is not the slowest run in its sample. The job's first step,Wait for older release runs to finish, declaresMAX_WAIT_SECONDS: '900'for itself, so a contended release may legitimately spend 15 minutes waiting before doing any work. None of the 25 sampled runs was contended, so that quarter-hour appears nowhere in the distribution and has to be added rather than measured. Ceiling = 15min (the declared cap at face value — it is already hard and fail-open, so multiplying it only buys slack for a clock that cannot overrun) +3 xmeasured max work (21.8min) = 36.8min, rounded to 40. The plain rule would have given 25, leaving a legitimately contended release (15min + 7m15s = 22m15s) inside 12% of its own ceiling — a ceiling under the job's honest slowest run, which is the mirror hazard.Two measured corrections to the card
changeset-release.ymlhas two unbounded jobs, not one.lane(uncached) sits aboverelease(cached). The card named onlyrelease; the dispatch's file surface covers only it.laneis left alone and recorded in objectui#7956 with the five other uncached jobs that declare no ceiling.performance-budget.ymldoes not subscribemerge_group. It subscribespushandpull_requestonly, and 300 sampled runs contain zeromerge_groupruns. SoBundle Analysiscannot hold the merge queue the wayLintcan — what six hours costs there is the pull request and the runner, not a shared serial queue. The exposure is real on its own, so the ceiling still derives; the note is in the workflow so nobody reuses theLintstakes argument there by mistake.Both are stated in the workflow comments, not just here.
The pin
scripts/__tests__/workflow-cache-save-bound.test.tsgains one assertion covering the three jobs in both directions: the key missing (the job silently returns to 360) and the number raised above what was derived (objectui#7048's fence). It is the closest existing workflow-shape test — it already parses every workflow's jobs and already reads job-leveltimeout-minutes— so no new file. Its header prose said "the three jobs here that declare notimeout-minutesat all"; that sentence is now false, and is updated in the same commit.Ablation, on the committed tree: deleting the job-level
timeout-minutes: 25fromlint.yml(verified on disk — anchor count 1 before, 0 after, step-leveltimeout-minutes: 5untouched at count 1) turns the run red with1 failed | 8 passed, naminglint.yml :: job `lint`. Restored withgit checkout HEAD --, byte-identical: blob414d8c0a28b877cc2c164a4946428a3764dddc2cbefore and after,git diff HEADempty.Gates
Run at
248b057ef, verdict lines quoted from the tools themselves:pnpm exec vitest run scripts/—Test Files 107 passed (107),Tests 3221 passed (3221)pnpm type-check:scripts— exit 0pnpm lint:root— exit 0 (32 problems (0 errors, 32 warnings), all pre-existing; none in a changed file)pnpm check:control-bytes—OK (scanned 6412 tracked text file(s); skipped 85 binary)node scripts/check-changeset-presence.mjs—No source or published contract of a released package changed in this range, so no changeset is owed.Workflow files and a test publish nothing.node scripts/check-governed-queue-guard.mjs --teston all four paths —NOT GOVERNED — 4 path(s) checked against 5 governed surface(s); none matched.Not done here
timeout-minutestouched. The5values are objectui#7269's and say DERIVED FOR THIS SITE.ci.ymlorlive-e2e.yml, and no existing ceiling anywhere raised or lowered.Generated by Claude Code