Assay-Runner CI Lane Contract¶
Internal Phase 2A reference. This page classifies when ordinary continuous CI is enough and when the delegated Linux/eBPF runner lane is required.
Assay-Runner has two proof classes:
- Continuous CI: hosted or ordinary repository checks that must stay fast, broadly available, and safe for pull requests.
- Delegated CI: the manual
Runner Spike Delegatedworkflow on[self-hosted, linux, assay-bpf-runner], used when a change can only be proven on the dedicated Linux/eBPF host.
The delegated lane is intentionally workflow_dispatch only. Do not add a pull-request, push, or schedule trigger to make the lane automatic. The host is dedicated and destructive cleanup is part of the contract.
Decision Table¶
| Change type | Continuous CI | Delegated CI | Required before merge? |
|---|---|---|---|
| Docs-only change outside runner acceptance, runbook, artifact contracts, or CI lane docs | yes | no | no |
| Docs-only change to runner acceptance, runbook, artifact contracts, fixture contract, or CI lane docs | yes | no | no, unless it changes acceptance criteria |
| Non-runner crate change with no monitor, policy, SDK fixture, cgroup, workflow, or evidence artifact impact | yes | no | no |
| Runner artifact schema, field set, note format, or artifact determinism semantics | yes | yes | yes |
| Runner telemetry-versus-evidence filter behavior | yes | yes | yes |
assay-monitor ring-buffer reader, BPF event decode, drop accounting, or capture stats | yes | yes | yes |
crates/assay-monitor/** or crates/assay-ebpf/** | yes | yes | yes |
| eBPF build image, build command, or loader/attach path | yes | yes | yes |
| Runner cgroup placement, domain-root resolution, or process spawn discipline | yes | yes | yes |
| Policy correlation, policy event normalization, or policy-to-kernel coherence rule | yes | yes | yes |
OpenAI Agents fixture dependency, SDK event normalization, SDK version assertion, or tool_call_id binding | yes | yes | yes |
Gemini Python google-genai fixture dependency, SDK event normalization, SDK version assertion, cassette content, or tool_call_id binding | yes | yes | yes |
| Acceptance fixture behavior or control paths | yes | yes | case-by-case; required when observed evidence can change |
Delegated workflow, runner labels, cleanup, checkout, sudo environment, preflight, or scripts/ci/runner-spike-*.sh | yes | yes | yes |
@openai/agents, zod, or fixture package-lock.json bump | yes | yes | yes |
aya, aya-ebpf, aya-log-ebpf, or BPF/runtime dependency bump | yes | yes | yes |
Workspace dependency bump that can affect assay-runner-spike, assay-monitor, assay-ebpf, assay-cli, policy correlation, or runner fixtures | yes | yes | yes |
| Delegated runbook wording that only clarifies existing behavior | yes | no | no |
| Follow-up issue text, planning notes, or extraction-roadmap prose | yes | no | no |
Required Delegated Gate¶
When delegated CI is required, choose the narrowest gate that proves the changed layer:
| Touched surface | Minimum delegated gate |
|---|---|
| Kernel fixture control path or kernel-only acceptance assertion | kernel-only |
| Policy capture or policy-to-kernel coherence | kernel-policy |
OpenAI Agents SDK fixture, SDK event schema, SDK version assertion, or tool_call_id binding | openai-agents-kernel-policy |
Gemini Python google-genai fixture, SDK event schema, SDK version assertion, cassette content, or tool_call_id binding | all (no narrower Gemini-specific gate exists in v0; a narrower gate is a separate coordinated decision per #1307) |
Delegated hidden-write semantic-gap expansion, proof-pack collector changes, crates/assay-monitor/**, crates/assay-ebpf/**, crates/assay-xtask/**, eBPF build/attach path, cgroup placement, telemetry filter, cross-layer archive, artifact schema, correlation report, workflow/security model, runner scripts, BPF/runtime dependency bump, or final release/acceptance proof | all |
If a change touches multiple surfaces, run the highest required gate. If the right gate is ambiguous, default to all.
Use build_ebpf=true for delegated proof unless the workflow has been explicitly extended to restore a deterministic prebuilt eBPF object after cleanup and checkout.
Merge Discipline¶
- Run ordinary continuous CI for every PR.
- For runner-impacting changes, dispatch the minimum delegated gate after the PR branch contains the final candidate commit.
- Record the workflow run URL, commit SHA, selected gate, and result in the PR body or a PR comment.
- Do not treat a delegated skip as success. In the delegated lane, exit
40means the runner contract has drifted. - Do not bypass required repository checks for runner-impacting changes.
If a runner-impacting PR cannot get a delegated run because the host is unavailable, leave the PR open. Merge only docs-only or clearly non-runner-impacting changes without delegated proof.
The Assay-Runner Lane Check / lane-check workflow provides the machine-visible path classification and delegated proof check for this contract. To make the contract hard-blocking, repository branch protection must mark that check as required.
The executable path mapping lives in scripts/ci/assay_runner_lane_check.py and must mirror the decision table on this page. Changes to this contract and changes to the classifier must land in the same PR; the helper's --self-test is the drift canary for the known runner-impacting surfaces.
Dependabot PRs follow the same proof rules, but need maintainer action because Dependabot cannot dispatch the delegated lane or record proof itself. See the Runner Dependabot lane flow for the required maintainer steps. Do not auto-dispatch the self-hosted delegated workflow from Dependabot PRs without a separate security design review.
Ring-buffer drop diagnostics remain a separate follow-up tracked in https://github.com/Rul1an/assay/issues/1271; that issue must not weaken the ringbuf_drops=0 delegated acceptance rule.
Boundary Rule¶
The delegated lane proves the Linux/eBPF runner boundary, not macOS, Windows, live LLM calls, production load, or a distributed runner fleet. Platform expansion requires a separate platform spike with its own kill criteria and CI lane contract.