Skip to content

ci: move parked device replay suites to a dispatch-only workflow (#1781 A1) - #1794

Open
thymikee wants to merge 1 commit into
mainfrom
ci/1781-a1-park-full-tier
Open

ci: move parked device replay suites to a dispatch-only workflow (#1781 A1)#1794
thymikee wants to merge 1 commit into
mainfrom
ci/1781-a1-park-full-tier

Conversation

@thymikee

@thymikee thymikee commented Aug 17, 2026

Copy link
Copy Markdown
Member

Summary

#1781 A1 fallback. Replay Nightly has failed every scheduled run since 2026-07-24. Two jobs are responsible and neither has an owner:

  • Android Full Emulator Suite — dies inside full:lifecycle-system, a scenario that had never executed end to end. Diagnosis and a validated fix for it (and for full:observability-artifacts) are in test(android): restore full-tier lifecycle and observability scenarios (#1781 A1) #1793; even with that, the last scenario full:fixture-replays still fails on a replay fixture whose scroll canary is authored for a taller device than the pixel_7 profile the lane pins.
  • iOS Replay Suite — fails on varying steps; not diagnosed here.

Both jobs move, byte-for-byte, into .github/workflows/replays-manual.yml, which has no schedule:. The parser fuzz lane keeps its nightly schedule in replays-nightly.yml and is untouched; the macOS job is already gone (#1787). Nothing about how the suites run changes — dispatch them with:

gh workflow run replays-manual.yml --ref <branch>

Why a separate file rather than if: github.event_name == 'workflow_dispatch'

The first revision of this PR used a job-level if:. It would have parked the jobs and lied about it: workflowLanes() (scripts/gate/workflows.ts) computes qualifying = 'pull_request' in on || 'schedule' in on once per workflow file and never reads job-level if:. So pnpm check:gate-manifest kept printing

gate manifest: ok — 48 checks wired across 32 lanes, 1 declared unprovable.

while replay-android, replay-ios, and replay-ios-device — declared only in those two jobs — no longer ran on any schedule. That is exactly the failure the manifest exists to catch: "a check that silently loses its owner looks exactly like a green build" (docs/agents/testing.md). A separate workflow_dispatch-only file is what the existing file-level model already reads correctly.

What that exposed, and how it is declared

With the jobs moved, the audit reports the truth:

check "replay-ios" is not declared by any pull_request/schedule lane: script:test:replay:ios.
check "replay-ios-device" is not declared by any pull_request/schedule lane: script:test:replay:ios-device.

These are declared in scripts/gate/declarations.ts as a new MANUAL_ONLY_OWNERS record rather than being folded into UNPROVABLE_OWNERS, because the two facts are opposites:

  • UNPROVABLE_OWNERS claims "the suite runs; this loader cannot see it" — which stopped being true for replay-android the moment its lane stopped running automatically, so its stale prose moved with it. UNPROVABLE_OWNERS is now empty, with a comment saying why.
  • MANUAL_ONLY_OWNERS says "nothing runs this until someone dispatches it", with the reason and the exit condition per entry.

check:gate-manifest now reports:

gate manifest: ok — 46 checks wired across 32 lanes, manual-only: replay-android, replay-ios, replay-ios-device.

Named, not counted — the ids read like a list of things nothing runs, where "3 manual-only" would read like a tally.

Two tests pin the new path (pnpm check:gate-manifest:test, 30/30):

  • a workflow_dispatch-only lane owns nothing, however many gates it declares — plants a dispatch-only workflow declaring replay-ios and asserts the gate is read but the lane is non-qualifying.
  • every manual-only declaration names a registered check no qualifying lane owns — the ratchet in the other direction: putting a lane back on a schedule without deleting its exemption fails the suite (verified by planting layering in the record: the test goes red).

docs/agents/testing.md no longer calls the iOS full tier "the scheduled/manual nightly workflow"; it names Replay Manual, states that the three checks run only on dispatch, and points at the declaration.

Validation

pnpm check:tooling passes (format, lint, typecheck, layering, depgraph, gate-manifest + its tests, production-exports, tmpdir-leaks, mcp-metadata, build, bundle-owner-files, package). The moved job bodies are byte-identical to the originals — only the job ids changed (nightly-android/nightly-iosmanual-android/manual-ios); job names, steps, pins, env, and artifact names are unchanged.

Notes for whoever picks these up

Exit condition

Move the two jobs back into replays-nightly.yml and delete their MANUAL_ONLY_OWNERS entries once a dispatch run is green. The audit test fails if the entries outlive the parking, so this cannot quietly become permanent.

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 2.26 MB 2.26 MB 0 B
JS gzip 744.4 kB 744.4 kB 0 B
npm tarball 863.7 kB 863.7 kB 0 B
npm unpacked 3.01 MB 3.01 MB 0 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 27.8 ms 27.8 ms -0.0 ms
CLI --help 66.2 ms 66.2 ms +0.0 ms

Top changed chunks: no changes in the largest emitted chunks.

… A1)

Both full-tier device jobs have failed every scheduled run since 2026-07-24: the
Android suite inside full-tier scenarios that had never executed end to end, the
iOS suite on varying steps. They move to .github/workflows/replays-manual.yml,
which has no `schedule:`, so the schedule stops emitting a guaranteed failure while
the suites stay runnable on demand.

A job-level `if: github.event_name == 'workflow_dispatch'` would have looked the
same and lied: `workflowLanes()` decides `qualifying` per workflow FILE and never
reads job-level `if:`, so the manifest kept reporting replay-android, replay-ios,
and replay-ios-device as scheduled-lane owners — the silent-owner-loss failure the
manifest exists to catch. A separate file is what the file-level model already
reads correctly.

Those three checks now have no pull_request/schedule owner, so they are declared as
MANUAL_ONLY_OWNERS rather than folded into UNPROVABLE_OWNERS, whose claim ("it runs,
this loader cannot see it") is no longer true for replay-android. check:gate-manifest
drops from 48 to 46 wired checks and names the three on every run. Two tests pin it:
a dispatch-only lane is non-qualifying however many gates it declares, and every
manual-only declaration must name a registered check that no qualifying lane owns, so
a re-scheduled lane cannot keep a stale exemption.
@thymikee
thymikee force-pushed the ci/1781-a1-park-full-tier branch from a6e8c6c to 2198ff5 Compare August 17, 2026 17:59
@thymikee thymikee changed the title ci: park full-tier nightly device jobs on manual dispatch (#1781 A1) ci: move parked device replay suites to a dispatch-only workflow (#1781 A1) Aug 17, 2026
@thymikee

Copy link
Copy Markdown
Member Author

P1: MANUAL_ONLY_OWNERS is currently only a negative allowlist. The new test proves each entry is registered and has no qualifying owner, but it never proves a workflow_dispatch lane still declares and can run that check. Deleting a parked manual job, or its run-gate step, would therefore leave check:gate-manifest green and continue to print the check as manual-only: parked coverage has silently become deleted coverage.

Please derive/attest each manual-only declaration from a dispatch-only lane and add a regression that deleting its declaration fails. Android needs an explicit attestation too: replay-android remains inside the opaque third-party action, so the existing loader cannot supply it by itself.

The loss of scheduled replay coverage itself matches #1781 A1 (manual means off). The current Bundle Size and CodeQL failures are GitHub 503 infrastructure failures; the wording/count issue in the manifest output is non-blocking.

@thymikee
thymikee marked this pull request as ready for review August 17, 2026 18:50
@thymikee

Copy link
Copy Markdown
Member Author

CI status on this head: 25 pass, 2 fail. Both failures are Analyze (java-kotlin) and Analyze (javascript-typescript) from the GitHub outage this PR was opened during — the logs contain only Encountered an error while trying to determine feature enablement: HttpError: No server is currently available…, never a finding, and that CodeQL run reports cannot be rerun; This workflow run cannot be retried. Bundle Size failed the same way (Failed to update PR comment: 503) and passes on re-run, as does every other job. The next push, or a maintainer re-run once GitHub finishes recovering, will clear the two Analyze rows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant