From 1d5e4199c8e0bc317ce52dbb2b6f09c028305db2 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Wed, 19 Aug 2026 17:24:58 +0800 Subject: [PATCH] fix(cic): address CI-split review - restore PR concurrency, fix comment migration, restore deleted spec block Per review on PR #2768: - Restore a concurrency block in ci.yml (cancel-in-progress: true) so a fresh PR push cancels the superseded run; GitHub has no default PR auto-cancel, so removing it would stack a second full 9-job run on every push. Update the ci-workflow.spec assertion accordingly. - Fix comment misplacements from the split boundary: ci.yml's all-checks-passed now carries its own branch-protection comment (the drill comment that was orphaned above it is gone), and ci-master.yml no longer ends with an orphaned all-checks-passed comment. - Restore the DeepSeek e2e workflow describe-block in ci-workflow.spec.ts that the rewrite had silently deleted (e2e.yml is unchanged). - serial-windows comment no longer claims non-blocking-for-PR/absent-from-needs since ci-master never listens to pull_request. - DSH_TELEMETRY_DISABLED safe-use comment restored in ci-master.yml env; split rationale (mi gray segments in PR check) documented in .github/AGENTS.md. Verification: ci-workflow.spec.ts 13/13, both workflows YAML-parse with correct concurrency, git diff --check clean. --- .github/AGENTS.md | 2 +- .github/workflows/ci-master.yml | 24 +++++++----------------- .github/workflows/ci.yml | 32 +++++++++++++++++++------------- scripts/ci-workflow.spec.ts | 23 ++++++++++++++++++++--- 4 files changed, 47 insertions(+), 34 deletions(-) diff --git a/.github/AGENTS.md b/.github/AGENTS.md index 08d3525f78..4efddc1bca 100644 --- a/.github/AGENTS.md +++ b/.github/AGENTS.md @@ -1,3 +1,3 @@ # AGENTS.md — GitHub Actions -Run jobs on Windows runners (`windows-*` labels) under native `pwsh`. The pull-request `windows` job is the deliberate exception: it runs Windows Node under Wine on hosted Linux and blocks `all checks passed`; `windows-native` runs automatically on `windows-2025` (or the self-hosted `[self-hosted, dsh-win-ci, windows]` pool under `DSH_CI_FAILOVER_WINDOWS=selfhosted`) but reports independently. `ci.yml` is pull-request-only; the master `serial-windows` standby, the Linux `serial-linux-selfhosted` standby, the `wine-apt-cache` seeder, and the two manual runner benchmarks live in `ci-master.yml` (master-push + `workflow_dispatch`). The master `serial-windows` standby continuously validates the self-hosted failover target — see the [failover runbook](../.agents/notes/implemented/process/2026-07-26-ci-failover-runbook.md). +Run jobs on Windows runners (`windows-*` labels) under native `pwsh`. The pull-request `windows` job is the deliberate exception: it runs Windows Node under Wine on hosted Linux and blocks `all checks passed`; `windows-native` runs automatically on `windows-2025` (or the self-hosted `[self-hosted, dsh-win-ci, windows]` pool under `DSH_CI_FAILOVER_WINDOWS=selfhosted`) but reports independently. `ci.yml` is pull-request-only; the master `serial-windows` standby, the Linux `serial-linux-selfhosted` standby, the `wine-apt-cache` seeder, and the two manual runner benchmarks live in `ci-master.yml` (master-push + `workflow_dispatch`). Because `ci-master.yml` does not listen to `pull_request`, those master-only jobs never appear in PR check panels (a job a workflow defines for a given event is listed and shows `skipped` when its `if` is false); keeping them in a separate workflow is what stops PR check circles from showing gray segments. The master `serial-windows` standby continuously validates the self-hosted failover target — see the [failover runbook](../.agents/notes/implemented/process/2026-07-26-ci-failover-runbook.md). diff --git a/.github/workflows/ci-master.yml b/.github/workflows/ci-master.yml index 05dc7cd636..d2df96fa4b 100644 --- a/.github/workflows/ci-master.yml +++ b/.github/workflows/ci-master.yml @@ -28,6 +28,8 @@ permissions: env: PRIMARY_NODE_VERSION: '24' + # CI runs must never report to the production telemetry endpoint baked + # into apps/cli/cordis.yml (AppCLIEntry disables the row when set). DSH_TELEMETRY_DISABLED: '1' jobs: @@ -143,11 +145,11 @@ jobs: # `windows` lane if the hosted pool degrades (the switch is setting the # writer-manageable DSH_CI_FAILOVER_WINDOWS variable — see the failover # runbook, no merge required). Push-triggered, so this lane always executes - # the base branch's own workflow definition. Non-blocking for pull requests; - # absent from all-checks-passed.needs by design — the required `windows` job - # owns the PR verdict. No cache steps because the VM's persistent pnpm store - # and tool caches make them redundant (and saving here would poison the - # hosted cache namespace with self-hosted paths). + # the base branch's own workflow definition. This workflow never listens to + # pull_request, so the drill does not appear in PR checks. No cache steps + # because the VM's persistent pnpm store and tool caches make them redundant + # (and saving here would poison the hosted cache namespace with self-hosted + # paths). serial-windows: if: github.event_name == 'push' && github.ref == 'refs/heads/master' name: serial / windows (self-hosted standby) @@ -393,15 +395,3 @@ jobs: env: DSH_GATE_CONCURRENCY: ${{ matrix.workers }} run: pnpm run check:ci:windows-blocking - - # Single stable required check for branch protection: require "all checks - # passed" instead of enumerating matrix legs whose names change as lanes and - # node versions evolve. Every blocking job in THIS workflow must be listed in - # `needs`. The required Wine job is listed as `windows`; `windows-native` is - # deliberately absent so its independent result never delays or changes this - # verdict. (`needs` cannot reach across workflow files; e2e.yml stays its own - # check.) - # `if: always()` is load-bearing: without it a failed dependency - # would SKIP this job, and GitHub counts a skipped required check as passing - # — so this job always runs and fails on any non-success result, including - # 'cancelled' and 'skipped'. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8746cf825b..d79953e9f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,8 +7,17 @@ permissions: env: PRIMARY_NODE_VERSION: '24' + # CI runs must never report to the production telemetry endpoint baked + # into apps/cli/cordis.yml (AppCLIEntry disables the row when set). DSH_TELEMETRY_DISABLED: '1' +# Cancel a superseded pull-request run on a new push so a fresh head does not +# queue a second full 9-job run behind a stale one (paid enterprise runners +# would otherwise stack with no auto-cancellation). +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: # Three enterprise jobs isolate coverage, static analysis, and the @@ -433,19 +442,16 @@ jobs: shell: pwsh run: pnpm run check:ci:windows-complete - # Hot-standby drill for the in-house self-hosted pool: every master move - # re-runs the complete unsharded aggregate on the persistent 64-core VM, - # continuously proving that environment can take over a required lane if - # the hosted pools degrade (the switch is then setting the writer-manageable - # DSH_CI_FAILOVER_LINUX variable — see the failover runbook, no merge required). - # Push-triggered, so this lane always executes the base branch's own - # workflow definition. (Under failover, pull_request jobs do reach these - # runners with the PR merge ref's workflow — the boundary there is - # repository membership: private, forking disabled, Dependabot excluded.) - # Non-blocking for - # pull requests; no cache steps because the VM's persistent pnpm store and - # tool caches make them redundant (and saving here would poison the hosted - # cache namespace with self-hosted paths). + # Single stable required check for branch protection: require "all checks + # passed" instead of enumerating matrix legs whose names change as lanes and + # node versions evolve. Every blocking job in THIS workflow must be listed in + # `needs`. The required Wine job is listed as `windows`; `windows-native` is + # deliberately absent so its independent result never delays or changes this + # verdict. + # `if: always()` is load-bearing: without it a failed dependency + # would SKIP this job, and GitHub counts a skipped required check as passing + # — so this job always runs and fails on any non-success result, including + # 'cancelled' and 'skipped'. all-checks-passed: name: all checks passed # This bookkeeping-only verdict must not depend on custom-pool diff --git a/scripts/ci-workflow.spec.ts b/scripts/ci-workflow.spec.ts index 3837a8ca23..1823c66bf0 100644 --- a/scripts/ci-workflow.spec.ts +++ b/scripts/ci-workflow.spec.ts @@ -129,9 +129,12 @@ describe('CI workflow', () => { // larger runners for 15 minutes in this same group on master. expect(workflow.concurrency['cancel-in-progress']).toBe("${{ github.event_name != 'push' }}") - // The PR-only ci.yml has no push-exemption concurrency; its jobs are - // cancel-on-supersede by the default PR cancel behavior and need no carve-out. - expect(prWorkflow.concurrency).toBeUndefined() + // The PR-only ci.yml still cancels a superseded run on a new push, so a + // fresh head does not stack a second full 9-job run behind a stale one. + // Unlike ci-master it has no push carve-out: every PR event supersedes. + expect(prWorkflow.concurrency).toMatchObject({ + 'cancel-in-progress': true, + }) // ci-master must not listen to pull_request: that is what keeps master-only // jobs out of the PR check panel. ci.yml is pull_request-only. @@ -217,6 +220,20 @@ describe('CI workflow', () => { }) }) +describe('DeepSeek e2e workflow', () => { + it('prepares bubblewrap from the pinned payload without a package transaction', () => { + const workflow = loadWorkflow('.github/workflows/e2e.yml') + const e2e = workflowJob(workflow, 'e2e') + if (!Array.isArray(e2e.steps)) throw new TypeError('DeepSeek e2e workflow must define steps') + + const steps = e2e.steps.filter(isRecord) + expect(steps.find(step => step.name === 'Prepare bubblewrap (unrestrict userns)')).toMatchObject({ + run: 'bash scripts/prepare-ci-bubblewrap.sh', + }) + expect(JSON.stringify(steps)).not.toContain('apt-get') + }) +}) + describe('E2B e2e workflow', () => { it('is manual-only and fails loud before running the focused live suite', () => { const workflow = loadWorkflow('.github/workflows/e2b-e2e.yml')