From f53c203f2b9ec3fbcf0f52d8ff04d6fa7c399c68 Mon Sep 17 00:00:00 2001 From: Val Alexander <68980965+BunsDev@users.noreply.github.com> Date: Mon, 10 Aug 2026 06:25:19 -0500 Subject: [PATCH 1/4] ci: take Windows off the pull_request fan-out; require seven contexts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every pull request scheduled 19 jobs, three of them Windows. On 2026-08-10 the repository held 39 queued Actions runs with ZERO in progress, the oldest stuck since 2026-07-18, while GitHub Actions was globally operational and a hosted runner completed an unrelated job mid-stall. The queue, not the suite, was the blocker: every required check on every open PR sat pending indefinitely. macOS was already pulled from these matrices for exactly this reason. Windows now follows it, for the same reason: - `conformance` and `sidecar-runtime` matrices are ubuntu-only on pull_request and ubuntu+windows on every other event. - `windows-native` skips on pull_request. `main` keeps identical platform coverage — all three Windows legs run in full on push to `main`, and `release.yml` still builds the Windows MSI. Only the per-PR fan-out shrinks, by three jobs billed at 2x. Two consequences had to be handled together, because either one alone wedges every PR: - `sidecar-runtime-required` failed unless `windows-native` reported `success`. It now accepts `skipped` on pull_request ONLY, and still hard-fails a skip on any other event — that is the event whose coverage the rollup guarantees. Both rollups are already `if: always()`, so they keep reporting. - Branch protection required `Cross-environment (windows-latest)` and `Sidecar runtime (windows-latest)`. Those contexts no longer report on a pull request, and a required context that never reports is precisely the BLOCKED-with-nothing-failing wedge documented in CLAUDE.md. Protection drops to the seven contexts that always report; the two `*-required` rollups stay required, so Windows still gates `main`. `scripts/ci-recovery-workflow.test.mjs` pins the new shape. Its exact-string SHA-guard assertion becomes structural: a job may narrow itself further, but only by ANDing onto the guard, and a top-level `||` in the suffix is rejected so the head-moved protection cannot be weakened. Verified by mutation — reverting the PR skip, letting the rollup accept a skip on any event, and swapping the `&&` for `||` each fail a distinct assertion. Follows the approved release-candidate CI design (docs/superpowers/specs/2026-08-05-release-candidate-ci-design.md, cave-7kix8), which reduces enforcement further to a single `PR checks` context once the release-candidate promotion gate exists. --- .agents/skills/branch-to-merge/SKILL.md | 16 ++++-- .github/workflows/ci.yml | 50 ++++++++++++++--- CLAUDE.md | 8 ++- scripts/branch-to-merge-contract.test.mjs | 2 +- scripts/ci-recovery-workflow.test.mjs | 68 ++++++++++++++++++++++- scripts/dependency-policy.test.mjs | 6 +- 6 files changed, 127 insertions(+), 23 deletions(-) diff --git a/.agents/skills/branch-to-merge/SKILL.md b/.agents/skills/branch-to-merge/SKILL.md index 7169e644d5..0b032d5347 100644 --- a/.agents/skills/branch-to-merge/SKILL.md +++ b/.agents/skills/branch-to-merge/SKILL.md @@ -8,7 +8,7 @@ description: Use when finishing work on a Coven Cave branch and landing it on pr Take a finished branch to a merged commit on `main` without ever writing to `main` directly and without destroying another session's work. -`main` in this repository is protected: pull request required, nine required +`main` in this repository is protected: pull request required, seven required status checks, no force-push, no deletion. A pull request is the **only** path an agent may use. This skill is the Cave-specific replacement for generic "finish a branch" workflows that offer a local merge into the base @@ -202,7 +202,7 @@ count. ## Phase 5: Checks and review -Nine required checks must pass: +Seven required checks must pass: ```bash expected_head=$(git rev-parse HEAD) @@ -215,10 +215,8 @@ gh pr view <#> --json headRefOid,mergeable,mergeStateStatus,statusCheckRollup - `Rust check` - `E2E (Playwright)` - `Cross-environment (ubuntu-latest)` -- `Cross-environment (windows-latest)` - `Cross-environment required` - `Sidecar runtime (ubuntu-latest)` -- `Sidecar runtime (windows-latest)` - `Sidecar runtime required` CodeQL is retired, and code scanning is fully off — nothing scans in its place. @@ -226,7 +224,15 @@ If a required context never reports, the PR sits `BLOCKED` with nothing failing. Before and after the watch, require `headRefOid` to equal `$expected_head` and each listed context to be complete and successful. A pass tied to an earlier SHA, or a pending, cancelled, stale, missing, or failed context, is incomplete; -do not merge until the exact current head has all nine passes. +do not merge until the exact current head has all seven passes. + +Windows no longer runs on pull requests, so there is no +`Cross-environment (windows-latest)` or `Sidecar runtime (windows-latest)` +context to wait for. Windows still gates `main`: the two `*-required` rollups +stay required, and the Windows legs run in full on push to `main` and on +release. Do not re-add the windows contexts to protection without first +re-adding the jobs to the pull_request path — a required context that never +reports is the classic `BLOCKED`-with-nothing-failing wedge. The `E2E (Playwright)` leg runs daemon-less (`COVEN_CAVE_E2E=1`), so e2e specs must dismiss onboarding and mock APIs via `page.route(...)` rather than expect a diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 45ba1ceeac..66712a4f98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -332,7 +332,21 @@ jobs: # exhausting the org Actions limit and queuing indefinitely, stalling # every required check. macOS is still covered by the release pipeline # (release.yml). Restore macos-latest here once macOS budget is sorted. - os: [ubuntu-latest, windows-latest] + # + # Windows now follows macOS off the pull_request path, for the same + # failure and one measurement: on 2026-08-10 the repository held 39 + # queued runs with ZERO in progress, the oldest stuck since 2026-07-18, + # while GitHub Actions was globally operational and a hosted runner + # completed an unrelated job mid-stall. The queue, not the suite, was + # the blocker — so every required check on every open PR sat pending. + # + # Windows bills at 2x and was three of the fifteen PR-time jobs. It + # still runs in full on push to main and on release, so `main` keeps + # identical platform coverage; only the per-PR fan-out shrinks. The + # windows-latest leg is deliberately dropped from branch protection in + # the same change — a required context that never reports is exactly + # how a PR ends up BLOCKED with nothing failing (see CLAUDE.md). + os: ${{ github.event_name == 'pull_request' && fromJSON('["ubuntu-latest"]') || fromJSON('["ubuntu-latest","windows-latest"]') }} runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 @@ -364,7 +378,7 @@ jobs: echo "::error::Cross-environment matrix result: ${{ needs.conformance.result }}" exit 1 fi - echo "Cross-environment matrix passed on ubuntu-latest and windows-latest." + echo "Cross-environment matrix passed on every leg scheduled for this event." sidecar-runtime: name: Sidecar runtime (${{ matrix.os }}) @@ -376,7 +390,10 @@ jobs: matrix: # macOS removed from PR CI (see conformance matrix note). Release # pipeline still exercises macOS. Restore once macOS budget is sorted. - os: [ubuntu-latest, windows-latest] + # Windows likewise runs on push/main and release only — same queue + # saturation, and this is the slowest Windows leg of the three + # (timeout-minutes: 40 against conformance's 15). + os: ${{ github.event_name == 'pull_request' && fromJSON('["ubuntu-latest"]') || fromJSON('["ubuntu-latest","windows-latest"]') }} runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 @@ -431,7 +448,11 @@ jobs: # edit for this job to be able to fail a PR. windows-native: name: Windows native tests - if: github.event_name != 'workflow_dispatch' || github.sha == inputs.expected_sha + # Windows runs on push/main and release only (see the conformance matrix + # note). `sidecar-runtime-required` below treats a `skipped` result here as + # acceptable, so a pull_request still gets a reporting rollup rather than a + # rollup that fails on the absence of a job it deliberately did not run. + if: (github.event_name != 'workflow_dispatch' || github.sha == inputs.expected_sha) && github.event_name != 'pull_request' runs-on: windows-latest # Hung steps stall required checks for the 6h default (cave-whm5); ~3x p95 (observed ~2.5min incl. cold cargo build). timeout-minutes: 20 @@ -561,20 +582,31 @@ jobs: # without adding a context to branch protection. Both results are # reported before exiting so one red job does not mask the other. - name: Require every sidecar runtime matrix leg + env: + EVENT: ${{ github.event_name }} + SIDECAR_RESULT: ${{ needs.sidecar-runtime.result }} + WINDOWS_RESULT: ${{ needs.windows-native.result }} run: | failed=0 - if [ "${{ needs.sidecar-runtime.result }}" != "success" ]; then - echo "::error::Sidecar runtime matrix result: ${{ needs.sidecar-runtime.result }}" + if [ "$SIDECAR_RESULT" != "success" ]; then + echo "::error::Sidecar runtime matrix result: $SIDECAR_RESULT" failed=1 fi - if [ "${{ needs.windows-native.result }}" != "success" ]; then - echo "::error::Windows native tests result: ${{ needs.windows-native.result }}" + # Windows native tests do not run on pull_request (they cost a 2x + # runner and the queue could not absorb them; see the conformance + # matrix note). A `skipped` result is therefore expected THERE AND + # ONLY THERE — on push/main a skip is still a hard failure, because + # that is the event whose coverage this rollup exists to guarantee. + if [ "$WINDOWS_RESULT" = "skipped" ] && [ "$EVENT" = "pull_request" ]; then + echo "Windows native tests skipped on pull_request by design; they gate push to main." + elif [ "$WINDOWS_RESULT" != "success" ]; then + echo "::error::Windows native tests result: $WINDOWS_RESULT" failed=1 fi if [ "$failed" -ne 0 ]; then exit 1 fi - echo "Sidecar runtime matrix passed on ubuntu-latest and windows-latest, and Windows native tests passed." + echo "Sidecar runtime matrix passed on every leg scheduled for this event." # ── iOS ───────────────────────────────────────────────────────────────────── # The Swift app is compiled NOWHERE in CI. Verified across every workflow: diff --git a/CLAUDE.md b/CLAUDE.md index f4c3088148..61720fc3cd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -24,7 +24,9 @@ yours. Use a PR. **Current settings** (verified live; `gh api repos/OpenCoven/coven-cave/branches/main/protection`): - PR required before merging — **0 approvals** (you can self-merge once checks pass; no second human needed for solo work). -- Required status checks — **all NINE** must pass (widened 2026-08-01 from five): `Frontend build`, `Rust check`, `E2E (Playwright)`, `Cross-environment (ubuntu-latest)`, `Cross-environment (windows-latest)`, `Cross-environment required`, `Sidecar runtime (ubuntu-latest)`, `Sidecar runtime (windows-latest)`, `Sidecar runtime required`. The four matrix legs were added alongside their `*-required` rollups. The rollups already fail unless `needs..result == 'success'`, so this is defense in depth rather than a gap being closed — it removes the dependency on those aggregation scripts staying correct. Classic branch protection is the active enforcement layer. Ruleset `19123333` lists the same nine checks but is currently disabled, so it does not provide a second gate. Only `ci.yml` runs on `pull_request` and no job carries a skippable `if:`, which is why requiring the legs is safe — a required context that never reports is what leaves a PR stuck `BLOCKED` with nothing failing. **`CodeQL` is retired** (2026-07-31): the ruleset's `code_scanning` rule went first, then the required context in classic branch protection, and now the workflow itself. Code scanning is fully off — GitHub default setup is `not-configured`, so nothing scans in its place. If you ever see a PR stuck `BLOCKED` with `mergeable: MERGEABLE`, no failing check and every conversation resolved, check two things: a required context that no longer reports (compare `gh api repos/OpenCoven/coven-cave/branches/main/protection --jq .required_status_checks.contexts` against the checks the PR actually runs), and `required_signatures` (see the signatures bullet below — it produced exactly this symptom on three PRs and is now off). The `E2E (Playwright)` job runs daemon-less (`COVEN_CAVE_E2E=1`), so e2e specs must be self-contained — dismiss onboarding (`cave:onboarding:dismissed=1`) and drive surfaces via `page.route(...)` API mocks rather than a live daemon. +- Required status checks — **all SEVEN** must pass (widened 2026-08-01 from five to nine, narrowed 2026-08-10 to seven when Windows left the pull_request path): `Frontend build`, `Rust check`, `E2E (Playwright)`, `Cross-environment (ubuntu-latest)`, `Cross-environment required`, `Sidecar runtime (ubuntu-latest)`, `Sidecar runtime required`. The two ubuntu matrix legs are required alongside their `*-required` rollups. The rollups already fail unless the legs they aggregate succeeded, so this is defense in depth rather than a gap being closed — it removes the dependency on those aggregation scripts staying correct. Classic branch protection is the active enforcement layer. Ruleset `19123333` is currently disabled, so it does not provide a second gate. Only `ci.yml` runs on `pull_request`. + + ⚠️ **Only require a context that always reports on a pull request.** The two `(windows-latest)` legs were required until 2026-08-10; they were dropped in the same change that took Windows off the `pull_request` path, because a required context that never reports is precisely what leaves a PR stuck `BLOCKED` with nothing failing. Windows still gates `main` — `conformance`, `sidecar-runtime`, and `windows-native` all run in full on push to `main`, and `release.yml` builds the Windows MSI — but on a pull request `windows-native` is deliberately skipped and the conformance/sidecar matrices are ubuntu-only. `Sidecar runtime required` therefore accepts a `skipped` `windows-native` **on `pull_request` only**, and still hard-fails a skip on any other event. `scripts/ci-recovery-workflow.test.mjs` pins all of that, so re-adding a windows context to protection without first re-adding the jobs will fail the suite before it can wedge a PR. **`CodeQL` is retired** (2026-07-31): the ruleset's `code_scanning` rule went first, then the required context in classic branch protection, and now the workflow itself. Code scanning is fully off — GitHub default setup is `not-configured`, so nothing scans in its place. If you ever see a PR stuck `BLOCKED` with `mergeable: MERGEABLE`, no failing check and every conversation resolved, check two things: a required context that no longer reports (compare `gh api repos/OpenCoven/coven-cave/branches/main/protection --jq .required_status_checks.contexts` against the checks the PR actually runs), and `required_signatures` (see the signatures bullet below — it produced exactly this symptom on three PRs and is now off). The `E2E (Playwright)` job runs daemon-less (`COVEN_CAVE_E2E=1`), so e2e specs must be self-contained — dismiss onboarding (`cave:onboarding:dismissed=1`) and drive surfaces via `page.route(...)` API mocks rather than a live daemon. A separate scheduled workflow detects GitHub event-delivery gaps: after a 15-minute grace period from the PR's latest update it dispatches a fresh @@ -50,7 +52,7 @@ yours. Use a PR. Prefer this fresh dispatch to rerunning a queued run with zero jobs: there is no job to rerun, and the stalled run can remain queued. Recovery does not - bypass branch protection; all nine required contexts still have to report and + bypass branch protection; all seven required contexts still have to report and pass on the exact PR head. - Review conversations are **no longer required to be resolved** (`required_conversation_resolution` was turned OFF on 2026-08-01, at the @@ -136,7 +138,7 @@ yours. Use a PR. If you believe it should change, say so to the owner and leave it alone. Nothing here changes how **agents** land work. Every rule below still binds - us: work on a branch, open a PR, wait for the nine required checks. The + us: work on a branch, open a PR, wait for the seven required checks. The `--admin` flag `gh` dangles at you on a blocked merge is still not the fix — fix the actual blocker. - Force-pushes and deletion of `main` are blocked. `allow_deletions = false` diff --git a/scripts/branch-to-merge-contract.test.mjs b/scripts/branch-to-merge-contract.test.mjs index ca66354e8a..1222e2164e 100644 --- a/scripts/branch-to-merge-contract.test.mjs +++ b/scripts/branch-to-merge-contract.test.mjs @@ -28,7 +28,7 @@ function backticked(source) { function documentedChecks() { const bullet = - /- Required status checks — \*\*all ([A-Z]+)\*\* must pass[^:]*:(.*?)\. The four matrix legs/s.exec( + /- Required status checks — \*\*all ([A-Z]+)\*\* must pass[^:]*:(.*?)\. The two ubuntu matrix legs/s.exec( claude, ); assert.ok(bullet, "CLAUDE.md no longer states the required status checks in the expected shape"); diff --git a/scripts/ci-recovery-workflow.test.mjs b/scripts/ci-recovery-workflow.test.mjs index 5c04ef133f..1aedd7d4b1 100644 --- a/scripts/ci-recovery-workflow.test.mjs +++ b/scripts/ci-recovery-workflow.test.mjs @@ -55,6 +55,31 @@ assert.equal( "ci-${{ github.event.pull_request.head.sha || inputs.expected_sha || github.sha }}", "late pull_request delivery and its recovery dispatch must share one concurrency key", ); +const SHA_GUARD = "github.event_name != 'workflow_dispatch' || github.sha == inputs.expected_sha"; + +// Every job must refuse a recovery dispatch whose branch head has moved. A job +// may narrow itself further (for example, skipping on pull_request to keep a +// paid runner off the PR fan-out), but only by ANDing extra conditions onto the +// guard. A top-level `||` in the suffix could re-admit a stale dispatch, so the +// shape is pinned rather than merely searched for. +function assertShaGuarded(jobName, condition) { + assert.equal(typeof condition, "string", `${jobName} must declare an if: condition`); + if (condition === SHA_GUARD) { + return; + } + const prefix = `(${SHA_GUARD}) && `; + assert.ok( + condition.startsWith(prefix), + `${jobName} must not run a recovery dispatch after the branch head moves`, + ); + const suffix = condition.slice(prefix.length); + assert.ok(suffix.length > 0, `${jobName} must not AND the guard against an empty condition`); + assert.ok( + !suffix.includes("||"), + `${jobName} must not weaken the head-moved guard with a top-level disjunction`, + ); +} + for (const jobName of [ "frontend-static", "frontend-tests", @@ -65,11 +90,48 @@ for (const jobName of [ "sidecar-runtime", "windows-native", ]) { + assertShaGuarded(jobName, ciWorkflow.jobs[jobName].if); +} + +// Paid-runner fan-out policy: Windows is billed at 2x and the shared Actions +// queue could not absorb three Windows legs per pull request. Windows coverage +// moves to push/main and release. These assertions exist so the reduction +// cannot be silently undone, and so the rollup below cannot be "fixed" by +// accepting a skip on the very event whose coverage it guarantees. +const PR_ONLY_UBUNTU = + "${{ github.event_name == 'pull_request' && fromJSON('[\"ubuntu-latest\"]')" + + " || fromJSON('[\"ubuntu-latest\",\"windows-latest\"]') }}"; +for (const jobName of ["conformance", "sidecar-runtime"]) { assert.equal( - ciWorkflow.jobs[jobName].if, - "github.event_name != 'workflow_dispatch' || github.sha == inputs.expected_sha", - `${jobName} must not run a recovery dispatch after the branch head moves`, + ciWorkflow.jobs[jobName].strategy.matrix.os, + PR_ONLY_UBUNTU, + `${jobName} must run ubuntu-only on pull_request and ubuntu+windows elsewhere`, ); } +assert.ok( + ciWorkflow.jobs["windows-native"].if.includes("github.event_name != 'pull_request'"), + "windows-native must stay off the pull_request fan-out", +); + +const sidecarRollup = ciWorkflow.jobs["sidecar-runtime-required"]; +assert.deepEqual( + sidecarRollup.needs, + ["sidecar-runtime", "windows-native"], + "the sidecar rollup must still depend on the Windows legs it reports for", +); +const sidecarGate = sidecarRollup.steps.find( + (step) => step.name === "Require every sidecar runtime matrix leg", +); +assert.ok(sidecarGate, "the sidecar rollup must gate on its matrix legs"); +assert.match( + sidecarGate.run, + /"\$WINDOWS_RESULT" = "skipped" \] && \[ "\$EVENT" = "pull_request"/, + "a skipped windows-native is acceptable on pull_request only", +); +assert.match( + sidecarGate.run, + /elif \[ "\$WINDOWS_RESULT" != "success" \]/, + "any other windows-native result, on any other event, must fail the rollup", +); console.log("ci-recovery-workflow.test.mjs: ok"); diff --git a/scripts/dependency-policy.test.mjs b/scripts/dependency-policy.test.mjs index 45c9a1d041..e0802513ca 100644 --- a/scripts/dependency-policy.test.mjs +++ b/scripts/dependency-policy.test.mjs @@ -52,8 +52,10 @@ assert.equal( // under the other version's JS → native/JS ABI mismatch → on win32 `format()` // returns a table with no `heif`, so `sharp/dist/utility.cjs` throws at load and // the avatar route 500s. macOS/Linux tolerate the mismatch, so ONLY the -// `Sidecar runtime (windows-latest)` CI leg catches it. This guard fails fast in -// the required Frontend-build check instead. Fix a divergence by aligning `sharp` +// `Sidecar runtime (windows-latest)` CI leg catches it — and since 2026-08-10 that +// leg runs on push to `main` and on release, NOT on pull requests. So this guard is +// now the only pre-merge signal for the skew; it fails fast in the required +// Frontend-build check. Fix a divergence by aligning `sharp` // to next's pin, or by adding `pnpm.overrides.sharp` so next's transitive copy is // forced to the same version. (PR #2263 dug out this root cause.) const lockfile = parse(await readFile(new URL("../pnpm-lock.yaml", import.meta.url), "utf8")); From 0a6e0932b3259b3faefe32f406cc593b9a9d5aa0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Aug 2026 11:41:05 +0000 Subject: [PATCH 2/4] fix(ios): handle .credentialFailure(_) in ConnectionView switch to fix non-exhaustive switch compile error Co-authored-by: BunsDev <68980965+BunsDev@users.noreply.github.com> --- apps/ios/CovenCave/CovenCave/Views/ConnectionView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ios/CovenCave/CovenCave/Views/ConnectionView.swift b/apps/ios/CovenCave/CovenCave/Views/ConnectionView.swift index 7938703029..23eb465bb5 100644 --- a/apps/ios/CovenCave/CovenCave/Views/ConnectionView.swift +++ b/apps/ios/CovenCave/CovenCave/Views/ConnectionView.swift @@ -390,7 +390,7 @@ struct ConnectionView: View { switch outcome { case .found(let url): liveCheck = .found(port: url.port) - case .unauthorized: + case .unauthorized, .credentialFailure(_): liveCheck = .pairingRequired case .unreachable(let failure): liveCheck = .failed(failure) From ac6b6658c2fc0c8beb1fbf79b1321f73bfa56619 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Aug 2026 12:42:28 +0000 Subject: [PATCH 3/4] test: address PR review wording fixes Co-authored-by: BunsDev <68980965+BunsDev@users.noreply.github.com> --- scripts/ci-recovery-workflow.test.mjs | 6 +++--- scripts/dependency-policy.test.mjs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/ci-recovery-workflow.test.mjs b/scripts/ci-recovery-workflow.test.mjs index 1aedd7d4b1..1429cd0bad 100644 --- a/scripts/ci-recovery-workflow.test.mjs +++ b/scripts/ci-recovery-workflow.test.mjs @@ -60,8 +60,8 @@ const SHA_GUARD = "github.event_name != 'workflow_dispatch' || github.sha == inp // Every job must refuse a recovery dispatch whose branch head has moved. A job // may narrow itself further (for example, skipping on pull_request to keep a // paid runner off the PR fan-out), but only by ANDing extra conditions onto the -// guard. A top-level `||` in the suffix could re-admit a stale dispatch, so the -// shape is pinned rather than merely searched for. +// guard. Any `||` in the suffix could re-admit a stale dispatch, so the shape is +// pinned rather than merely searched for. function assertShaGuarded(jobName, condition) { assert.equal(typeof condition, "string", `${jobName} must declare an if: condition`); if (condition === SHA_GUARD) { @@ -76,7 +76,7 @@ function assertShaGuarded(jobName, condition) { assert.ok(suffix.length > 0, `${jobName} must not AND the guard against an empty condition`); assert.ok( !suffix.includes("||"), - `${jobName} must not weaken the head-moved guard with a top-level disjunction`, + `${jobName} must not weaken the head-moved guard with any disjunction in the suffix`, ); } diff --git a/scripts/dependency-policy.test.mjs b/scripts/dependency-policy.test.mjs index e0802513ca..426b8590cc 100644 --- a/scripts/dependency-policy.test.mjs +++ b/scripts/dependency-policy.test.mjs @@ -55,7 +55,7 @@ assert.equal( // `Sidecar runtime (windows-latest)` CI leg catches it — and since 2026-08-10 that // leg runs on push to `main` and on release, NOT on pull requests. So this guard is // now the only pre-merge signal for the skew; it fails fast in the required -// Frontend-build check. Fix a divergence by aligning `sharp` +// Frontend build check. Fix a divergence by aligning `sharp` // to next's pin, or by adding `pnpm.overrides.sharp` so next's transitive copy is // forced to the same version. (PR #2263 dug out this root cause.) const lockfile = parse(await readFile(new URL("../pnpm-lock.yaml", import.meta.url), "utf8")); From 89fe2bf3ca2a94571acc68c51ce1102999f526a0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Aug 2026 12:43:49 +0000 Subject: [PATCH 4/4] test: clarify sha guard failure message Co-authored-by: BunsDev <68980965+BunsDev@users.noreply.github.com> --- scripts/ci-recovery-workflow.test.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci-recovery-workflow.test.mjs b/scripts/ci-recovery-workflow.test.mjs index 1429cd0bad..316ea54593 100644 --- a/scripts/ci-recovery-workflow.test.mjs +++ b/scripts/ci-recovery-workflow.test.mjs @@ -70,7 +70,7 @@ function assertShaGuarded(jobName, condition) { const prefix = `(${SHA_GUARD}) && `; assert.ok( condition.startsWith(prefix), - `${jobName} must not run a recovery dispatch after the branch head moves`, + `${jobName} if: condition must start with the SHA guard prefix before adding extra conditions`, ); const suffix = condition.slice(prefix.length); assert.ok(suffix.length > 0, `${jobName} must not AND the guard against an empty condition`);