ci: restore hosted lane headroom

This commit is contained in:
Tianyi Cui
2026-07-21 21:28:49 +08:00
parent 7813dbcf0f
commit ca0c9a7c48
7 changed files with 36 additions and 27 deletions
@@ -16,7 +16,9 @@ The artifact boundary remains load-bearing. `publint`, `verify-node-next-types`,
[scripts/run-gates.ts](../../../../scripts/run-gates.ts) remains the common bounded scheduler, but GitHub supplies explicit shard names for the expensive gate families. [scripts/static-shards.ts](../../../../scripts/static-shards.ts) partitions static gates into foundation, API-contract, catalog, prose, documentation-projection, and documentation-build lanes and rejects a missing or duplicate gate assignment. Lint uses disjoint package-source, package-test, and repository-complement lanes; the complement still starts from `.` so a new top-level lint target cannot disappear between shards, and it owns the single cross-file duplication run. [scripts/coverage-shards.ts](../../../../scripts/coverage-shards.ts) assigns every workspace package to exactly one source-coverage lane; its test expands the live package tree, so a new package makes CI red until it has an owner. Each coverage lane includes only its owned source files, repeats the exhaustive companion topology test, and runs without a preceding build because the complete coverage suite passes from a tree with every generated `lib/` removed.
Snapshot replay uses two explicit multi-file lanes and two scenario partitions of the large ACP file. [scripts/snapshot-shards.ts](../../../../scripts/snapshot-shards.ts) owns that inventory, and its test discovers every file admitted by the snapshot config so a new file cannot land outside CI. Each snapshot job builds the shipped runtime while its Linux runner installs bubblewrap from the hosted image's existing package index, then runs only its assigned replay surface. CI explicitly retains the suite's bounded concurrency of five subprocesses instead of clamping it to the runner's two logical CPUs, because replay spends most of its time waiting on child protocol I/O. Fixture guards still inspect the complete ACP scenario table in every partition. Static, lint, coverage, and snapshot sharding changes only GitHub scheduling: the ordinary local package scripts still run their complete suites.
Snapshot replay uses one explicit multi-file lane and four scenario partitions of the large ACP file. [scripts/snapshot-shards.ts](../../../../scripts/snapshot-shards.ts) owns that inventory, and its test discovers every file admitted by the snapshot config so a new file cannot land outside CI. Each snapshot job builds the shipped runtime while its Linux runner installs bubblewrap from the hosted image's existing package index, then runs only its assigned replay surface. CI explicitly retains the suite's bounded concurrency of five subprocesses instead of clamping it to the runner's two logical CPUs, because replay spends most of its time waiting on child protocol I/O. Fixture guards still inspect the complete ACP scenario table in every partition. Static, lint, coverage, and snapshot sharding changes only GitHub scheduling: the ordinary local package scripts still run their complete suites.
Cold standalone documentation typechecking rebuilds the complete project-reference graph, so the API-contract lane now builds once and checks Markdown blocks against those declarations. The Linux documentation lane uses VitePress's MPA build to retain page rendering and dead-link validation inside the one-minute budget; the blocking Windows build also produces the normal production SPA, preserving the shipped-site check under its three-minute budget.
Artifacts use two lanes: one metadata lane for `publint`, NodeNext declarations, and compiled invariant loading, plus one built-bin smoke lane. Each lane produces its own build before its consumers. Repeating the short build costs runner minutes but avoids an upload/download dependency and keeps each job's critical path bounded.
+18 -13
View File
@@ -56,7 +56,7 @@ jobs:
command: pnpm run check:ci:static
gate_concurrency: '1'
static_shard: site-projection
- lane: static-site-build
- lane: static-site-mpa
command: pnpm run check:ci:static
gate_concurrency: '1'
static_shard: site-build
@@ -137,16 +137,10 @@ jobs:
gate_concurrency: '1'
coverage_max_workers: '4'
coverage_shard: capabilities
- lane: snapshot-support
- lane: snapshot-ordinary
command: pnpm run check:ci:snapshot
gate_concurrency: '1'
snapshot_lane: support
snapshot_max_concurrency: '5'
snapshot_prebuilt: '1'
- lane: snapshot-agents
command: pnpm run check:ci:snapshot
gate_concurrency: '1'
snapshot_lane: agents
snapshot_lane: ordinary
snapshot_max_concurrency: '5'
snapshot_prebuilt: '1'
- lane: snapshot-acp-1
@@ -161,6 +155,18 @@ jobs:
snapshot_lane: acp-2
snapshot_max_concurrency: '5'
snapshot_prebuilt: '1'
- lane: snapshot-acp-3
command: pnpm run check:ci:snapshot
gate_concurrency: '1'
snapshot_lane: acp-3
snapshot_max_concurrency: '5'
snapshot_prebuilt: '1'
- lane: snapshot-acp-4
command: pnpm run check:ci:snapshot
gate_concurrency: '1'
snapshot_lane: acp-4
snapshot_max_concurrency: '5'
snapshot_prebuilt: '1'
- lane: artifacts-metadata
command: pnpm run check:ci:artifacts
gate_concurrency: '3'
@@ -314,6 +320,9 @@ jobs:
- name: Build (tsc -b + tsdown)
run: pnpm run build
- name: Build documentation site (production SPA)
run: pnpm run docs:build
# Observational, non-blocking Windows static, lint, and artifact lanes. Coverage
# and snapshot stay Linux-only until their platform-specific runtime failures
# have dedicated support. Run the gates from native PowerShell: an MSYS parent
@@ -354,10 +363,6 @@ jobs:
command: pnpm run check:ci:static
gate_concurrency: '1'
static_shard: site-projection
- lane: static-site-build
command: pnpm run check:ci:static
gate_concurrency: '1'
static_shard: site-build
- lane: lint
command: pnpm run check:ci:lint
gate_concurrency: '1'
+1
View File
@@ -52,6 +52,7 @@
"verify-doc-budgets": "tsx scripts/verify-doc-budgets.ts",
"docs:dev": "pnpm --filter @deepseek-ai/website run dev",
"docs:build": "pnpm --filter @deepseek-ai/website run build",
"docs:build:mpa": "pnpm --filter @deepseek-ai/website exec vitepress build . --mpa",
"docs:preview": "pnpm --filter @deepseek-ai/website run preview",
"docs:check": "pnpm exec vitest run scripts/project-doc-site.spec.ts && pnpm run docs:build",
"website:dev": "pnpm run docs:dev",
+8 -2
View File
@@ -244,7 +244,12 @@ function ciStaticGates(): Gate[] {
pnpmScript('constraints', 'constraints'),
pnpmScript('package-invariants', 'verify-package-invariants', { label: 'package invariants' }),
pnpmScript('cordis-config', 'verify-cordis-config', { label: 'Cordis config' }),
...docSyncLeafGates(),
pnpmScript('build', 'build'),
...docSyncLeafGates({
docTypecheckNeeds: ['build'],
docTypecheckEnv: { DSH_DOC_TYPECHECK_USE_BUILD_OUTPUT: '1' },
docsBuildScript: 'docs:build:mpa',
}),
pnpmScript('module-graph', 'verify-module-graph', { label: 'module graph' }),
pnpmScript('knip', 'knip'),
]
@@ -366,6 +371,7 @@ function hygieneLeafGates(options: { artifactNeeds?: string[] } = {}): Gate[] {
function docSyncLeafGates(options: {
docTypecheckNeeds?: string[]
docTypecheckEnv?: Record<string, string | undefined>
docsBuildScript?: 'docs:build' | 'docs:build:mpa'
} = {}): Gate[] {
const docTypecheckOptions: Partial<Gate> = {}
if (options.docTypecheckNeeds !== undefined) docTypecheckOptions.needs = options.docTypecheckNeeds
@@ -396,7 +402,7 @@ function docSyncLeafGates(options: {
label: 'documentation projection',
}),
// Keep the VitePress build itself in one gate because projection rewrites website/.generated.
pnpmScript('docs-site-build', 'docs:build', { label: 'documentation build' }),
pnpmScript('docs-site-build', options.docsBuildScript ?? 'docs:build', { label: 'documentation build' }),
pnpmScript('package-readme-limitations', 'verify-package-readme-limitations', { label: 'package README limitations' }),
]
}
+2 -2
View File
@@ -26,10 +26,10 @@ describe('snapshot lanes', () => {
expect(new Set(ordinary).size).toBe(ordinary.length)
expect(acp.map(lane => lane.files)).toEqual(Array.from(
{ length: 2 },
{ length: 4 },
() => ['examples/acp-agent/tests/acp.snapshot.ts'],
))
expect(acp.map(lane => lane.scenarioShard)).toEqual(['1/2', '2/2'])
expect(acp.map(lane => lane.scenarioShard)).toEqual(['1/4', '2/4', '3/4', '4/4'])
expect([...ordinary, 'examples/acp-agent/tests/acp.snapshot.ts'].sort()).toEqual(discovered)
})
+3 -8
View File
@@ -13,25 +13,20 @@ export interface SnapshotLane {
/** Exhaustive file ownership plus scenario partitions for the large ACP suite. */
export const snapshotLanes: readonly SnapshotLane[] = [
{
name: 'support',
name: 'ordinary',
files: [
'packages/sdk/scripts/tests/config.snapshot.ts',
'packages/sdk/create-sdk/tests/create.snapshot.ts',
'packages/ui/tui/tests/tui.snapshot.ts',
],
},
{
name: 'agents',
files: [
'examples/tui-agent/tests/tui.snapshot.ts',
'examples/acp-agent/tests/goal.snapshot.ts',
'examples/headless-agent/tests/headless.snapshot.ts',
],
},
...Array.from({ length: 2 }, (_, offset) => ({
...Array.from({ length: 4 }, (_, offset) => ({
name: `acp-${offset + 1}`,
files: ['examples/acp-agent/tests/acp.snapshot.ts'],
scenarioShard: `${offset + 1}/2`,
scenarioShard: `${offset + 1}/4`,
})),
]
+1 -1
View File
@@ -23,7 +23,7 @@ export const staticShards = [
},
{
name: 'api-contracts',
gateIds: ['doc-typecheck', 'cordis-api', 'export-jsdoc', 'scoped-events', 'type-equivalence'],
gateIds: ['build', 'doc-typecheck', 'cordis-api', 'export-jsdoc', 'scoped-events', 'type-equivalence'],
},
{
name: 'catalogs',