fix(ci): prevent concurrent pnpm refresh during mobile typechecks (#24776)

* fix(ci): run mobile typechecks without concurrent dependency refresh

* test(ci): check effective Linux E2E package list

* test(ci): preserve the mobile production compiler barrier

---------

Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example>
This commit is contained in:
Neil
2026-10-02 21:52:36 -07:00
committed by GitHub
co-authored by Orca Integration Recovery
parent b032867021
commit 77ad467ebb
4 changed files with 59 additions and 5 deletions
+3 -3
View File
@@ -114,11 +114,11 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
# pnpm entrypoints can auto-install; finish each before the next mutates node_modules.
# Call installed tools so pnpm's dependency refresh cannot race between checks.
- name: Typecheck
id: production-types
background: true
run: pnpm typecheck
run: node node_modules/typescript/bin/tsc --noEmit
- wait: production-types
@@ -127,7 +127,7 @@ jobs:
# drifted. This fails when a test file that checks today stops checking, when a test leaves
# the program, and on @ts-nocheck; the baseline may only shrink.
- name: Typecheck tests (ratchet)
run: pnpm run check:tests-typecheck
run: node scripts/check-tests-typecheck-ratchet.mjs
# This includes the bridged replay of the whole recording corpus, which used to be a second
# step of its own behind RPC_FOUNDATION_BRIDGE=1. A gate nobody can forget to set is the point:
@@ -0,0 +1,42 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
import { parse } from 'yaml'
const workflow = parse(readFileSync('.github/workflows/mobile.yml', 'utf8'))
const packageJson = JSON.parse(readFileSync('mobile/package.json', 'utf8'))
const job = workflow.jobs.verify
const steps = job.steps
describe('mobile verification command ownership', () => {
it('runs the declared checks through installed tools without a script-time install', () => {
const production = steps.find((step) => step.name === 'Typecheck')
const tests = steps.find((step) => step.name === 'Typecheck tests (ratchet)')
expect(packageJson.scripts.typecheck).toMatch(/^tsc\b/)
expect(production.run).toBe(`node node_modules/typescript/bin/${packageJson.scripts.typecheck}`)
expect(tests.run).toBe(packageJson.scripts['check:tests-typecheck'])
expect(tests.run).toMatch(/^node\s/)
expect(job.defaults.run['working-directory']).toBe('mobile')
for (const name of ['typecheck', 'check:tests-typecheck']) {
expect(packageJson.scripts[`pre${name}`]).toBeUndefined()
expect(packageJson.scripts[`post${name}`]).toBeUndefined()
}
})
it('finishes installation and joins production types before checking test types', () => {
const installIndex = steps.findIndex((step) => step.name === 'Install dependencies')
const productionIndex = steps.findIndex((step) => step.name === 'Typecheck')
const ratchetIndex = steps.findIndex((step) => step.name === 'Typecheck tests (ratchet)')
const waitIndex = steps.findIndex((step) => step.wait === steps[productionIndex].id)
const testIndex = steps.findIndex((step) => step.name === 'Test')
expect(steps[installIndex].run).toBe('pnpm install --frozen-lockfile')
expect(steps[installIndex].background ?? false).toBe(false)
expect(installIndex).toBeLessThan(productionIndex)
expect(steps[productionIndex].background).toBe(true)
expect(productionIndex).toBeLessThan(ratchetIndex)
expect(waitIndex).toBeGreaterThan(productionIndex)
expect(waitIndex).toBeLessThan(ratchetIndex)
expect(ratchetIndex).toBeLessThan(testIndex)
})
})
+4 -2
View File
@@ -1,4 +1,5 @@
import { DEDICATED_E2E_SPECS } from './ci-e2e-job-selection.mjs'
import { linuxInstallPackageList } from './pr-e2e-linux-packages.test-fixture.mjs'
import { existsSync, readdirSync, readFileSync } from 'node:fs'
import { join, resolve } from 'node:path'
import { parse as parseJsonc } from 'jsonc-parser'
@@ -20,6 +21,7 @@ import {
const projectDir = resolve(import.meta.dirname, '../..')
const prWorkflow = parseYaml(readFileSync(join(projectDir, '.github/workflows/pr.yml'), 'utf8'))
const e2eWorkflow = parseYaml(readFileSync(join(projectDir, '.github/workflows/e2e.yml'), 'utf8'))
const reliabilityManifest = parseJsonc(
readFileSync(join(projectDir, 'config/reliability-gates.jsonc'), 'utf8')
)
@@ -218,7 +220,7 @@ describe('PR E2E gate contract', () => {
const installStep = e2eWorkflow.jobs[jobName].steps.find((step) =>
step.name.startsWith('Install native build')
)
expect(installStep.env.ORCA_E2E_APT_PACKAGES.split(/\s+/), jobName).toContain('zsh')
expect(linuxInstallPackageList(installStep, jobName), jobName).toMatch(/\bzsh\b/)
}
})
@@ -308,7 +310,7 @@ describe('PR E2E gate contract', () => {
const changedInstall = e2eWorkflow.jobs['changed-e2e'].steps.find((step) =>
step.name.startsWith('Install native build')
)
expect(changedInstall.env.ORCA_E2E_APT_PACKAGES.split(/\s+/)).toContain('openssh-client')
expect(linuxInstallPackageList(changedInstall, 'changed-e2e')).toMatch(/\bopenssh-client\b/)
})
it('routes direct-SSH workspace and tab restore from its unnamed source seams', () => {
@@ -0,0 +1,10 @@
import { expect } from 'vitest'
export function linuxInstallPackageList(step, jobName) {
const packages = step.env?.ORCA_E2E_APT_PACKAGES
if (packages !== undefined) {
expect(step.run, jobName).toContain('read -r -a packages <<< "$ORCA_E2E_APT_PACKAGES"')
expect(step.run, jobName).toContain('sudo apt-get install -y "${packages[@]}"')
}
return packages ?? step.run
}