Repository navigation
ci(lint): every job in lint.yml carries a timeout-minutes derived from its measured duration - #21064
Merged
objectstack-fleet[bot] merged 2 commits intoOct 1, 2026
Conversation
Five of the six jobs in the Lint & Type Check workflow declared no timeout-minutes, so a step that stops producing output ran to GitHub's 360-minute default. Lint & Repo Gates is the longest required check in every merge-queue group; the queue's 60-minute check-response window removes such an entry with no failing check and no triage comment while the hung job keeps a runner for hours. Walls, from the measured p50 / p99 / max of the 100 most recent completed runs (2026-10-01T00:23Z to 03:24Z): Lint & Repo Gates 60, Type Check workspace 30, consumer gates 20, debt ledger 15, source gates 10; the TypeScript Type Check aggregate keeps its 10. Each new line carries its measurement and the derivation rule in a comment. No job name, step, needs or concurrency block changes. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PGMD6TRDaZY8Ubyo7Ukm66
The lint job's timeout clock starts when a runner picks the job up, which is after the merge queue's 60-minute check-response window has opened, so a wall equal to that window lets the queue remove a hung entry before the check turns cancelled. At 55 the cancelled check and its "exceeded the maximum execution time" annotation land first, and the removal is attributable to a visible failing check; 55 still leaves 22 minutes (1.7x) over the measured maximum of 32.7. The derivation rule's floor becomes a flat 10 minutes, the floor every value in the file meets, and the sentence that listed the jobs sitting under the former maximum-plus-10 clause is dropped. The four type-check lane values are unchanged. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PGMD6TRDaZY8Ubyo7Ukm66
objectstack-fleet
Bot
deleted the
claude/issue-21050-lint-yml-job-timeouts
branch
October 1, 2026 05:18
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 #21050
Clause-②: no
What changed
.github/workflows/lint.ymlgains fivetimeout-minuteskeys, each under a comment carrying its measurement and the derivation rule. Nothing else moves: no jobname:, step,needs:,if:,permissions:orconcurrency:changes. The diff against d1f8ce8 is 62 insertions, 0 deletions, in five hunks, each directly under a job'sruns-on:line (two commits: 5e6d90c, then 51f3743 for the ruled patch round).name:, byte-identical)timeout-minutesbeforelintLint & Repo Gates(required)typecheck-workspaceType Check · workspacetypecheck-consumersType Check · consumer gatestypecheck-debtType Check · debt ledgertypecheck-source-gatesType Check · source gatestypecheckTypeScript Type Check(required)Measurement (the card's, transcribed into the comments): the 100 most recent completed
lint.ymlruns, 2026-10-01T00:23Z to 03:24Z, 96 runs read, 525 successful job rows, jobstarted_attocompleted_atfrom the jobs API. Rule: about 2x the measured maximum, rounded to a 5-minute grain, never below 10 minutes, never above the merge queue's 60-minutecheck_response_timeout_minutes. Forlintthe window binds rather than 2x, and the wall sits below it, at 55, leaving 22 minutes (1.7x) over the measured maximum. Thelintcomment carries the full reasoning; the four lane comments are short and point at it.Why
Lint & Repo Gatesis the longest required check in every merge-queue group, and nothing in this workflow bounds a step that stops producing output: no step runs underscripts/run-with-stall-guard.mjs, so the job timeout is the only wall these jobs can have, and five of six declared none. A silent step would hold the jobin_progressuntil GitHub's 360-minute default, while the queue (ruleset 12119582) gives up on the entry at 60 minutes with no failing check to read and noMerge Queue Triagecomment, and the hung job keeps a runner for up to five more hours.What GitHub does at the wall: documented, plus one reading on this repository
No local test can drive a job timeout. GitHub documents that a job exceeding
timeout-minutesis cancelled. One reading on this repository agrees, read this session from the jobs and check-runs APIs: in run 36803445860 (CI,merge_group), jobTest Core (1/6), stopped by its 45-minute wall, hasconclusion: cancelledand afailure-level annotation readingThe job has exceeded the maximum execution time of 45m0s. For the four type-check lanes, acancelledlane fails the requiredTypeScript Type Checkaggregate (its verdict step fails on anything butsuccess). Forlint,cancelledis the conclusion of the required context itself.Ruleset 12119582, read this session:
merge_queue.check_response_timeout_minutes: 60, and its required contexts includeLint & Repo GatesandTypeScript Type Check.Verification (head 51f3743, base d1f8ce8)
timeout-minutes, plus the top-level keys and the job order) is identical before and after except for the fivetimeout-minutesvalues.actionlintis not on the PATH; nothing was installed.git grep -c 'run-with-stall-guard' -- .github/workflows/lint.ymlanswers 1, not 0. The hit is prose in theStall-guard self-teststep's comment, and no step runs under the guard.pnpm check:stall-guard-budgetexits 0: 39 workflow files, 65 jobs, 730 steps, 10 guard-wrapped steps, none of them in this file.node scripts/check-ci-filter-parity.mjs(and its--self-test),node scripts/check-required-contexts.mjs(7 required contexts pinned across 3 workflows) andnode scripts/ci/select-shard-timings-run.mjs --self-testall exit 0 on this diff.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, with no paths, derived the change set from git against merge base d1f8ce8 and printed 44 commands. 43 exit 0, includingpnpm check:pm-dispatch-gates(1976 cases, 680 s).pnpm check:type-check-debtexits 3, PREREQUISITE NOT MET: its--re-measurehalf needs the built package closure, so it is NOT MEASURED locally, and CI runs it in theType Check · debt ledgerlane. Its--self-testhalf passed, andpnpm check:type-check-coverage, which reads this file, exits 0.--ranreconciliation: 44 accounted, 43 run, 1 NOT-MEASURED, 0 UNRUN. 15 of the 44 are--self-test-only commands that judge their own script, not this diff.pnpm check:doc-authoring,pnpm check:nul-bytes,pnpm check:pm-skill-id-lint,node scripts/check-issue-citations.mjs(no citations added),pnpm check:stall-guard,pnpm check:pm-governed-prose,pnpm check:route-ledger-census,pnpm check:select-shard-packages,node scripts/measure-test-shard-timings.mjs --self-test,node scripts/pr-labels.mjs --self-test.pnpm check:doc-authoring,pnpm check:pm-skill-id-lint,node scripts/check-issue-citations.mjs,pnpm check:nul-bytes,node scripts/check-ci-filter-parity.mjs,node scripts/check-required-contexts.mjsandpnpm check:stall-guard-budgetall exit 0. The file parses under PyYAML and js-yaml. The structural fingerprint against d1f8ce8 differs only in the five addedtimeout-minutesvalues (55/10/30/15/20), and the aggregate's 10 is unchanged.Acceptance notes
lintcomment on the seat's ruling.cancelled. On the seat's ruling thelintwall is 55. Thecancelledcheck and its annotation land before the queue's window closes whenever pickup takes under five minutes, so the removal is attributable to a visible failing check. 55 leaves 22 minutes (1.7x) over the measured maximum of 32.7.CIworkflow only (workflow_run,workflows: [CI]), notLint & Type Check, and fires onfailureonly. A timed-out lint job gets no triage comment either way. Its header scopes it to "every red merge_group CI run", so this is its declared scope, not a defect. Noted, not filed; carrier: none.Stall-guard budget invariantstep in thelintjob, but it sits intypecheck-source-gates. That has no effect on this change.skip-changesetapplies:.github/workflows/publishes nothing, so no changeset was created and the seat applies the label.Generated by Claude Code