ci: give package boundary validation its measured job budget

Hosted four-CPU runs spend about 19 minutes preparing SDK artifacts and
compiling all 126 plugin packages with two compiler children. Three runs
hit the 20-minute job deadline: one completed compile and canary but timed
out during the job lifecycle, while two lost receipt or canary coverage.

Give only the extension-package-boundary row 30 minutes for the complete
flow, including setup and cleanup. Preserve the other additional-check
rows at 20 minutes, full selection, compiler concurrency, receipt guards,
negative canary, runner routes, and caches.

Validated the executable timeout guard against the original failure and
neighboring hosted budgets; workflow/static checks and independent review
cover the scoped correction. No new hosted runtime success is claimed.
This commit is contained in:
Peter Steinberger 2026-09-29 15:37:58 -07:00
parent 3ff1d44783
commit 5e5e50e842
No known key found for this signature in database
4 changed files with 38 additions and 1 deletions

View file

@ -305,6 +305,12 @@ These are intentionally guarded by the `ci-workflow-guards`,
class-vCPU-minutes (1.17% of that broad run). Include that allowance with
Node packing costs until native proof measures the new duration. No jobs,
registrations, permissions, compiler checks, or hosted eligibility are added.
The package-boundary row has a 30-minute whole-job budget: three hosted
four-CPU attempts hit the former 20-minute limit, with about 19 minutes in
SDK preparation and 126 compiles before final validation/canary/cleanup.
One completed both compile and canary but still exceeded the job deadline.
Other additional-check groups retain 20 minutes; compiler concurrency,
complete inventory, receipt guards, canary, and routing remain unchanged.
- Current fast plugin/channel contract families each share one checkout/setup.
Their two weighted process envelopes run sequentially with unchanged include
lists and package commands; channel invocations retain four project slots and

View file

@ -5395,7 +5395,8 @@ jobs:
needs: [preflight]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check_additional == 'true' }}
runs-on: ${{ (github.event_name == 'workflow_dispatch' && startsWith(inputs.dispatch_id, 'full-release-validation-') && vars.OPENCLAW_RELEASE_RUNNER_GROUP || '') != '' && fromJSON(format('{{"group":{0},"labels":{1}}}', toJSON((github.event_name == 'workflow_dispatch' && startsWith(inputs.dispatch_id, 'full-release-validation-') && vars.OPENCLAW_RELEASE_RUNNER_GROUP || '')), toJSON((contains(fromJSON('["hybrid","runson"]'), (needs.preflight.outputs.ci_qualification == 'true' && (github.run_attempt == 1 && needs.preflight.outputs.qualification_runner_backend || 'github') || vars.OPENCLAW_CI_RUNNER_BACKEND)) && github.run_attempt == 1 && needs.preflight.outputs.hybrid_hosted_checks == 'true' && (matrix.group == 'extension-package-boundary' || matrix.group == 'runtime-topology-architecture')) && 'ubuntu-24.04' || (needs.preflight.outputs.ci_qualification == 'true' && (github.run_attempt == 1 && needs.preflight.outputs.qualification_runner_backend || 'github') || vars.OPENCLAW_CI_RUNNER_BACKEND) == 'github' && 'ubuntu-24.04' || (contains(fromJSON('["hybrid","runson"]'), (needs.preflight.outputs.ci_qualification == 'true' && (github.run_attempt == 1 && needs.preflight.outputs.qualification_runner_backend || 'github') || vars.OPENCLAW_CI_RUNNER_BACKEND)) && (github.run_attempt > 1 || (matrix.group != 'extension-package-boundary' && matrix.group != 'runtime-topology-architecture' && matrix.group != 'plugin-sdk-api-diff'))) && 'ubuntu-24.04' || ((github.event_name == 'workflow_dispatch' && ((needs.preflight.outputs.node_runner_backend != 'runson' && needs.preflight.outputs.ci_qualification != 'true') || github.run_attempt != 1)) || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && github.run_attempt > 1)) && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || contains(fromJSON('["OWNER","MEMBER","COLLABORATOR","CONTRIBUTOR"]'), github.event.pull_request.author_association)) && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04')))) || ((contains(fromJSON('["hybrid","runson"]'), (needs.preflight.outputs.ci_qualification == 'true' && (github.run_attempt == 1 && needs.preflight.outputs.qualification_runner_backend || 'github') || vars.OPENCLAW_CI_RUNNER_BACKEND)) && github.run_attempt == 1 && needs.preflight.outputs.hybrid_hosted_checks == 'true' && (matrix.group == 'extension-package-boundary' || matrix.group == 'runtime-topology-architecture')) && 'ubuntu-24.04' || (needs.preflight.outputs.ci_qualification == 'true' && (github.run_attempt == 1 && needs.preflight.outputs.qualification_runner_backend || 'github') || vars.OPENCLAW_CI_RUNNER_BACKEND) == 'github' && 'ubuntu-24.04' || (contains(fromJSON('["hybrid","runson"]'), (needs.preflight.outputs.ci_qualification == 'true' && (github.run_attempt == 1 && needs.preflight.outputs.qualification_runner_backend || 'github') || vars.OPENCLAW_CI_RUNNER_BACKEND)) && (github.run_attempt > 1 || (matrix.group != 'extension-package-boundary' && matrix.group != 'runtime-topology-architecture' && matrix.group != 'plugin-sdk-api-diff'))) && 'ubuntu-24.04' || ((github.event_name == 'workflow_dispatch' && ((needs.preflight.outputs.node_runner_backend != 'runson' && needs.preflight.outputs.ci_qualification != 'true') || github.run_attempt != 1)) || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && github.run_attempt > 1)) && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (github.event_name != 'pull_request' || contains(fromJSON('["OWNER","MEMBER","COLLABORATOR","CONTRIBUTOR"]'), github.event.pull_request.author_association)) && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04')) }}
timeout-minutes: 20
# Full cold package validation exceeds 20 minutes on four-CPU hosted runners.
timeout-minutes: ${{ matrix.group == 'extension-package-boundary' && 30 || 20 }}
strategy:
fail-fast: false
max-parallel: 12

View file

@ -62,6 +62,13 @@ Full GitHub and hybrid type checks run the five core stripes independently, reta
Additional checks start directly after preflight. Known full compiler selections skip discovery while retaining the core graph boundary in an existing required owner; see [pipeline ordering](/ci/pipeline#fail-fast-order).
The extension package boundary row has a 30-minute job budget for SDK preparation,
all selected plugin compiles, input-receipt validation, the required negative
canary, and cleanup. Hosted four-CPU runs spent about 19 minutes in the compile
command alone; one completed compile and canary but exceeded the former
20-minute whole-job deadline. Other additional-check rows retain 20 minutes.
This changes no compiler concurrency, coverage, runner routing, or cache guards.
Core lint discovers separate source and UI TypeScript projects, retaining shared ambient declarations and imported dependencies. The source project also includes `src/**/*.test-support.cjs`; unrelated JavaScript files are not added as roots. See [local checks](/ci/local-proof#local-equivalents).
Runtime topology checks inherit the existing [Go memory defaults](/ci/local-proof#local-equivalents), with caller overrides and the full architecture check sequence retained.

View file

@ -2366,6 +2366,29 @@ require("node:fs").writeFileSync("scheduler-baseline", process.env.OPENCLAW_UPGR
}
});
it("keeps the full extension package boundary in its own job budget", () => {
const timeout = readCiWorkflow().jobs["check-additional-shard"]["timeout-minutes"];
for (const [group, expected] of [
["extension-package-boundary", 30],
["runtime-topology-architecture", 20],
["plugin-sdk-api-diff", 20],
["boundaries", 20],
[undefined, 20],
] as const) {
expect(
typeof timeout === "number"
? timeout
: evaluateWorkflowExpression(timeout, {
eventName: "pull_request",
repository: "openclaw/openclaw",
runAttempt: 2,
matrix: { group },
}),
group ?? "default additional check",
).toBe(expected);
}
});
it("resolves the pull request base and changed files from the shallow security checkout", () => {
const securitySteps = readCiWorkflow().jobs["security-fast"].steps as WorkflowStep[];
const checkoutIndex = securitySteps.findIndex((step) => step.name === "Checkout");