docs/19-ci-and-pull-requests.md
CI and pull requests
Use this procedure when publishing a change, handling review comments, recovering failed checks or merging a PR. Local proof follows agent development and workflow commands; this guide covers the GitHub state.
CI events and checks
ci.yml runs on PR opened/synchronize/reopened, pushes to main and explicit manual dispatch. Contribution branch pushes and tags do not automatically run CI. Opening or updating a PR tests GitHub's proposed merge checkout; pushing main verifies the resulting main revision. There are no path filters or draft skips.
| Job | Result required before merge |
|---|---|
workflow-lint | actionlint 1.7.12 validates all GitHub Actions workflows |
rust | Shared scripts/verify.sh full, including server QA, isolated GTK and benchmark |
minimum-rust | Rust 1.92 checks the workspace and all targets with the lockfile |
The verification artifact contains summary.json, logs and screenshots even
when full verification fails. Read the failed step's log and inspect renders as
appropriate. Lint checks configuration; it does not prove event scheduling or
replace application verification. The exact ubuntu-26.04 label in
actionlint.yaml supplements the linter's older list;
it does not select a self-hosted runner or suppress other diagnostics.
Concurrency groups use workflow, event and PR number or full ref. Different PRs
with equal fork branch names cannot cancel each other. A newer run in the same
group cancels the older run. PR, main-push and manual runs have distinct groups.
Tokens have contents: read; checkout does not persist credentials.
After this workflow is on main, explicitly verify an unopened branch with:
| 1 | gh workflow run ci.yml --ref BRANCH |
Manual dispatch needs a workflow on the default branch. Fork contributions can require GitHub approval before running. Conflicting PRs need conflict resolution before GitHub can run their merge checkout. Repository rulesets are separate settings; these files define the checks and do not configure merge enforcement.
Prepare and publish
- Complete the selected feature's tasks, independent review and local full
verification. Stage final source before full; check fresh delivery proof with
scripts/agent.sh check --phase delivery --feature FULL-SLUG --evidence RUN. - Use the PR template. Describe concrete
behavior and link the spec. Record the verified revision, actual commands,
artifact, findings, limitations and rollback implications.
not runandpendingare valid results; they do not mean passed. - Push and create the PR. When using gh, write the exact description to a file
and pass
--body-file. Register the PR with the orchestrator when it supports PR linking. This applies to every layer in a stack.
Review, recover and merge
Capture the current head and base before assessing comments or checks. Keep both values throughout the review and merge:
sh1 reviewed_refs=$(gh pr view NUMBER --json headRefOid,baseRefOid --jq '[.headRefOid, .baseRefOid] | join(" ")') || exit 1 2 read -r reviewed_head reviewed_base <<< "$reviewed_refs" Inspect conversation comments, review submissions and inline threads, including replies and resolved state. Use
gh-address-commentswhen available. Evaluate each finding against source and project requirements; fix valid defects and record the reason for rejecting a suggestion. A bot's generic threshold does not become a project requirement. A reviewer out of quota has not approved.Inspect the PR's check runs and workflow run identity. Confirm the head and base still equal
reviewed_headandreviewed_base; a change requires restarting the assessment. Usegh pr view NUMBER --json headRefOid,baseRefOid,statusCheckRollup,reviewsandgh run view RUN_ID --json event,headSha,status,conclusion,jobs. Require the latest PR run's three jobs to pass for the reviewed head. An old cancelled push run alongside a passing replacement is not an outstanding defect. A cancelled latest run, pending/failed check or unavailable log is not passing proof. Confirm the checked merge usedreviewed_base; if main advances, update and verify the proposed merge again.For failed GitHub Actions checks, use
gh-fix-ciwhen available. Read the log, reproduce the failure, form a diagnosis and make a bounded correction. Rerun only after examining the cause; repeated failure needs new evidence. Use existing session authorization for fixes and publishing. External reviewer outages or quotas are reported as limitations, not solved by retrying code.After source changes, review the delta, stage final content and refresh local full/delivery proof. Push, then inspect CI and new comments for the new head. Finish pending reviews before claiming they are clear. Prefer orchestrator PR watching to a polling loop while waiting.
Merge only when authorized by the user/task and all latest checks and review decisions are settled. Recheck both revisions immediately before merging and preserve the reviewed head in the merge request:
sh1 current_refs=$(gh pr view NUMBER --json headRefOid,baseRefOid --jq '[.headRefOid, .baseRefOid] | join(" ")') || exit 1 2 if [ "$current_refs" != "$reviewed_refs" ]; then 3 echo 'PR head or base changed; review and verify again.' >&2 4 exit 1 5 fi 6 gh pr merge NUMBER --squash --match-head-commit "$reviewed_head" Capture both revisions before assessing checks and comments, not after them.
--match-head-commitatomically guards only the head. The base recheck detects changes observed before the merge request; it cannot prevent a concurrent base update after that check. Strict up-to-date branch protection or a merge queue is needed for server-enforced base freshness. Do not bypass checks with admin flags. Existing merge authorization persists; ask only if it was never provided.Confirm merged state and merge commit. Stop orchestrator watching when handing work back. Start follow-up changes from updated main in a separate branch.