PR-E2 (ADR 0008 §6.5): self-hosted Mac M4 GitHub Actions integration workflow#57
Merged
FluffyAIcode merged 1 commit intoJun 2, 2026
Conversation
5 tasks
…tion workflow
Closes the loop on automated GA gating. After PR-N1..N4 retired all
verifier-protocol test doubles from the Linux gate, the integration
suite (tests/integration/) became the binding correctness gate for
runtime modules \u2014 inference_engine.session.coordinator,
inference_engine.session.generator,
inference_engine.scheduler.scheduler,
inference_engine.server.{app,engine,tokenizer,streaming}, and
kakeya.{client,session}. Until this PR, that suite ran manually
via scripts/review_pr_*_on_mac.sh; PR-E2 wires it into CI on every
PR labelled needs-mac-m4.
Three artifacts ship:
.github/workflows/integration.yaml +136 lines
Self-hosted runner workflow targeting [self-hosted, macOS,
ARM64, kakeya-mac-m4]. Triggers on PR events when the
needs-mac-m4 label is present, plus on workflow_dispatch
for manual re-runs. Steps:
1. Checkout (full history).
2. Verify host shape (chip, memory, python version).
3. Verify Qwen/Qwen3-0.6B is in HF cache (HF_HUB_OFFLINE=1
at test time \u2014 no downloads in CI; cache miss fails
fast with a clear pre-warm command).
4. pip install -e . + pytest dependencies (warm pip cache
keeps this <30 s).
5. pytest -m integration tests/integration/ \u2014 expected
runtime 60-120 s on M4 with warm cache. 90-min timeout
is a safety margin, not the operating point.
6. Upload JUnit XML artifact.
7. On failure, inline the test names + first-line error
messages into the Action log so triage doesn't require
downloading the artifact.
Concurrency: cancel-in-progress per PR, so a new push
supersedes the previous run.
.github/workflows/auto-label-mac.yaml +89 lines
pull_request_target workflow that auto-applies (or removes)
the needs-mac-m4 label based on which paths the PR touches.
Trigger paths:
inference_engine/ \u2014 runtime, scheduler, session, server
sdks/ \u2014 Python + TypeScript SDK
proto/ \u2014 wire contract
tests/integration/ \u2014 the integration suite itself
kv_cache_proposer/ \u2014 verifier + decoder
Doc-only or CI-only PRs are NOT labelled \u2014 they skip the
integration gate entirely, saving runner time. The label is
automatically dropped if a subsequent push removes all
verifier-dependent edits.
docs/ops/mac-m4-runner-setup.md +137 lines
Operator runbook for the self-hosted runner: hardware
requirements (24 GB minimum, ~50 GB free disk), runner
registration with the kakeya-mac-m4 label, HF cache
pre-warm command (Qwen3-0.6B), Python toolchain setup,
runtime expectations, cache hygiene cron, runner upgrade
procedure, and failure triage steps.
CI workflow split rationale
---------------------------
The pre-existing .github/workflows/ci.yaml stays as the Linux gate
(verifier-independent, runs on github-hosted ubuntu-latest, fires
on every PR). PR-E2 adds integration.yaml as a SEPARATE workflow
because:
1. Self-hosted runners are slow / few; doc-only PRs shouldn't
touch them.
2. The integration gate is intentionally OPT-IN by label; ci.yaml
is non-optional.
3. Failure semantics differ: Linux gate failure blocks merge
unconditionally; Mac M4 gate failure surfaces a structured
report but the merge decision is a human one until v0.3.0
final ships.
Together the two workflows form the post-cleanup gating model:
- Linux gate (ci.yaml):
verifier-independent code; 100% coverage; every PR.
- Mac M4 gate (integration.yaml):
verifier-dependent code; binding GA gate; PRs touching
runtime / SDK / proto / integration tests.
Stack
-----
PR-E2 is branched off main, independent of the cleanup PRs (#49,
#50, #51, #52, #53, #54, #55, #56). The workflow doesn't fail at
launch even before PR-E1 lands; it just won't find any tests
under tests/integration/ until that PR is merged. Recommended
merge order: cleanup PRs first (so the workflow has tests to
run), then PR-E2.
Per ADR 0008 \u00a79
----------------
PR-E2 ships ONLY workflow YAML + a runbook \u2014 no Python source
changes. No Mac M4 evidence required for this PR (the workflow
itself becomes the Mac M4 evidence machinery for ALL future PRs).
Co-authored-by: FluffyAIcode <FluffyAIcode@users.noreply.github.com>
60b18bb to
a0397c9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Closes the loop on automated GA gating. After PR-N1..N4 retired all verifier-protocol test doubles from the Linux gate, the integration suite (
tests/integration/) became the binding correctness gate for runtime modules —inference_engine.session.coordinator,inference_engine.session.generator,inference_engine.scheduler.scheduler,inference_engine.server.{app,engine,tokenizer,streaming},kakeya.{client,session}. Until this PR, that suite ran manually viascripts/review_pr_*_on_mac.sh; PR-E2 wires it into CI on every PR labelledneeds-mac-m4.What ships
.github/workflows/integration.yamlpip install -e .→pytest -m integration→ upload JUnit + inline failure summary.github/workflows/auto-label-mac.yamlpull_request_targetworkflow that auto-appliesneeds-mac-m4when a PR touchesinference_engine/,sdks/,proto/,tests/integration/, orkv_cache_proposer/; auto-removes it if a subsequent push drops all verifier-dependent editsdocs/ops/mac-m4-runner-setup.mdkakeya-mac-m4label, HF cache pre-warm command, Python toolchain setup, runtime expectations, cache hygiene cron, runner upgrade procedure, failure triageWorkflow details
integration.yaml[self-hosted, macOS, ARM64, kakeya-mac-m4]opened/synchronize/reopened/labeled+workflow_dispatch. Conditional onneeds-mac-m4label being present.HF_HUB_OFFLINE=1enforcement (cache miss fails fast with a clear pre-warm command).auto-label-mac.yamlubuntu-latest(no self-hosted overhead).opened/synchronize/reopened.Two-tier gating model post PR-E2
ci.yamlintegration.yamlneeds-mac-m4(auto-applied)Failure semantics differ:
Operator runbook highlights
The
docs/ops/mac-m4-runner-setup.mdis the source of truth for the runner. Key one-time setup:kakeya-mac-m4label (in addition to the defaultself-hosted, macOS, ARM64).Stack
PR-E2 is branched off
main, independent of the cleanup PRs. The workflow doesn't fail at launch even before PR-E1 lands; it just won't find any tests undertests/integration/until that PR is merged. Recommended merge order:main.Per ADR 0008 §9
This PR ships only workflow YAML + a runbook — no Python source changes. No Mac M4 evidence required for this PR; the workflow itself becomes the Mac M4 evidence machinery for ALL future PRs.
Reviewer checklist
python3 -c "import yaml; yaml.safe_load(...)").auto-label-mac.yamlpermission scope ispull-requests: writeand trigger ispull_request_target(required for PRs from forks to gain the label).integration.yamlruns-onincludeskakeya-mac-m4(operator must add this label when registering the runner per the runbook).HF_HUB_OFFLINE=1constraint at test time.