Skip to content

refactor: Delete Dead Code From the Four Audit Targets (#170) #12

refactor: Delete Dead Code From the Four Audit Targets (#170)

refactor: Delete Dead Code From the Four Audit Targets (#170) #12

Workflow file for this run

name: Drivers
# Compile gate for the two native drivers under drivers/ — the only automated
# verification they have. Before this workflow existed, nothing in
# .github/workflows/ mentioned gradle, xcodebuild, Kotlin or Swift: a bad edit
# to the 48 native files was caught by a dead device in someone's manual
# session, not by a failing check.
#
# COMPILE ONLY — deliberately no test execution:
# - drivers/android/app/src/androidTest/ IS the driver (24 of 25 Kotlin
# files). Its single @Test starts a gRPC server and blocks forever, and
# there are zero assertions in the whole tree, so `connectedAndroidTest`
# has nothing to report and would never terminate.
# - drivers/ios has no unit-test target at all.
# The gate therefore proves the native code compiles and links. It does NOT
# prove a tap lands in the right place — that still needs a manual device
# session. Treat "drivers is green" as "it builds", nothing more.
#
# This workflow is ADDITIVE and must stay that way: ci.yml's job graph and its
# `test` job name are a contract with repo ruleset 14531661 (the required
# status check). No job in THIS file may be named `test` — a same-named check
# from this workflow would be indistinguishable from the required one.
#
# Unlike ci.yml, this workflow DOES carry a `concurrency:` block — see the block
# below `on:` for the full reasoning. The short version: ci.yml's
# no-cancellation rule is load-bearing because `test` is the required check, and
# a cancelled run at a PR tip reads exactly like a clean one to the merge gate.
# Nothing in THIS file is required by ruleset 14531661, so no merge gate consults
# it. The PENDING-eviction footgun ci.yml records is still real, which is exactly
# why the group key below is run-id-scoped on push to main.
on:
# Both triggers carry the SAME `paths` list, duplicated verbatim. That is a
# deliberate choice, not a forced one: GitHub Actions HAS supported YAML
# anchors/aliases since 2025-09-18, so a `&anchor`/`*alias` pair would parse.
# Two short adjacent literal lists are kept because they are trivially eyeball-
# and diff-verifiable, and anchor support specifically inside the `on:` trigger
# block is not something this change verified. Keep the two lists byte-identical.
#
# A `paths` filter means the workflow does not run AT ALL when nothing
# matching changed: the check is absent, not green. That is safe here and
# would NOT be on ci.yml — ruleset 14531661 requires exactly one context,
# `test`, which resolves to ci.yml's job, so the two jobs below are additive
# and block no merge by their absence. Never copy this filter to ci.yml
# without also adding an always-runs sentinel job.
#
# Why each entry earns its place:
# - drivers/** — both native trees, their gradle files, the gradle wrapper,
# the Xcode project, and the committed generated Swift under
# drivers/ios/finalrun-ios-test/Generated/.
# - proto/** — load-bearing and easy to miss.
# drivers/android/app/build.gradle.kts:104 adds the repo-root `proto`
# directory as a protobuf source dir, so the Android driver compiles
# proto/finalrun/driver.proto from source on every build. A proto edit can
# break the Kotlin compile with no file under drivers/ changing at all.
# - the two build scripts — each job's single `run:` step is one of them, so
# a change to either changes what this gate actually does.
# - this workflow file — so a change to the gate is verified by the gate.
# resources/android/ and resources/ios/ are deliberately ABSENT: they are the
# build scripts' output staging directories, not build inputs.
pull_request:
branches: [main]
paths:
- 'drivers/**'
- 'proto/**'
- 'scripts/build-drivers-android.sh'
- 'scripts/build-drivers-ios.sh'
- '.github/workflows/drivers.yml'
# Filtering `push` too is intentional: a merge whose diff touches no driver
# path cannot break either native build, and a merge that does touch one still
# matches the filter and still runs the post-merge net.
push:
branches: [main]
# Keep byte-identical to the pull_request list above.
paths:
- 'drivers/**'
- 'proto/**'
- 'scripts/build-drivers-android.sh'
- 'scripts/build-drivers-ios.sh'
- '.github/workflows/drivers.yml'
# Supersede in-flight PR runs; never queue or evict a main run.
#
# On a pull_request the group is the PR ref, so a newer push cancels the run
# the previous push started — the measured waste this closes is PR #167's
# three pushes, ~200 billable minutes for one informative verdict. A cancelled
# `drivers` run is safe to trade away in a way a cancelled `ci` run is not:
# ruleset 14531661 requires only ci.yml's `test` context, so no merge gate
# consults this workflow, and the commit a cancellation skipped is by
# definition no longer the tip.
#
# On a push to main the group key is the run id, which is unique per run — so
# every main run is alone in its group and behaves exactly as it does today:
# not cancelled, and never queued behind or evicted by another. A bare
# `group: drivers-${{ github.ref }}` would NOT be equivalent: GitHub cancels an
# existing PENDING run whenever a newer run queues into the same group on the
# default `queue: single` (cancel-in-progress governs only the in-progress
# run), so two rapid merges would silently cost the middle one its verdict.
# See docs/memory/ci/pr-quality-gate.md for the long form of that footgun.
concurrency:
group: drivers-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
# Debug + androidTest APK pair, both required: the driver lives under
# app/src/androidTest/, so it ships as an instrumentation-test APK and a
# release build produces artifacts that cannot host it.
android:
runs-on: ubuntu-latest
# Job level, not step level, so checkout and toolchain setup are inside the
# bound. Worst `android` run observed across five recorded runs: 2m36s
# (57s, 58s, 2m20s, 2m33s, 2m36s), so 15 leaves ~5.8x headroom for a cold
# gradle cache and runner-image variance. It replaces GitHub's 360-minute
# default: a wedged job now costs 15 Linux-rate minutes, not 360.
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
# AGP 8.1.4 (drivers/android/build.gradle.kts) requires JDK 17.
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
cache: gradle
cache-dependency-path: |
drivers/android/gradle/wrapper/gradle-wrapper.properties
drivers/android/**/*.gradle.kts
# The same script `npm run build:drivers:android` runs. Invoked directly
# so the gate needs no Node toolchain, and NOT reimplemented here: the
# gradle task list and the APK staging paths live in one place.
- name: Build the Android driver (assembleDebug + assembleDebugAndroidTest)
run: ./scripts/build-drivers-android.sh
# Requires a macOS runner (xcodebuild). release.yml already provisions a
# windows-latest runner, so a second runner OS is established precedent.
ios:
runs-on: macos-latest
# Worst `ios` run observed across five recorded runs: 9m20s (5m36s, 5m57s,
# 6m57s, 7m28s, 9m20s — the longest being the push-to-main run), so 25
# leaves ~2.7x headroom. Deliberately the tighter bound RELATIVE to its
# worst run, because macos-latest bills at 10x: a hung xcodebuild now costs
# 250 billable minutes instead of the ~3,600 the 360-minute default allows.
# A spurious timeout is a red job a re-run clears — visible and
# self-correcting — which beats a cap so generous it defeats its purpose.
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
# The same script `npm run build:drivers:ios` runs. It uses
# `build-for-testing`, not plain `build`: build-for-testing is what emits
# the finalrun-ios-test-Runner.app the script asserts on, and a plain
# build would pass while producing artifacts that cannot host the driver.
- name: Build the iOS driver (build-for-testing)
run: ./scripts/build-drivers-ios.sh