CI runs on pull_request, not on feature-branch pushes¶
Context¶
After pushing a feature branch, the post-push CI monitor searched for workflow runs on the pushed commit and found zero. The instinct is to suspect a broken push, a misconfigured workflow, or a queuing delay. None of those was true — the workflows are simply not configured to run on a branch push. Remote CI only started once a pull request was opened.
Guidance¶
opnDossier's CI is gated on pull_request and push to main. A push to a feature branch with no open PR triggers nothing. To exercise remote CI on a branch, open a PR — that fires ci.yml and security.yml against the head commit.
The local just ci-check recipe is the pre-push gate; remote CI is a PR-time gate. Running just ci-check locally before pushing is what validates a branch commit — not a remote run, because there is no remote run until the PR exists.
Trigger map for the workflows in .github/workflows/ (as of this writing):
| Workflow | Triggers on |
|---|---|
ci.yml |
push: main, pull_request |
security.yml |
push: main, pull_request, weekly schedule |
docs.yml |
push: main, pull_request (paths: docs/**, mkdocs.yml, requirements.txt, mise.toml, .github/workflows/docs.yml) |
go-deps.yml |
push: main |
scorecard.yml |
push: main, branch_protection_rule, schedule, workflow_dispatch |
release.yml |
push tags v*, workflow_dispatch |
sbom.yml |
schedule, workflow_dispatch |
copilot-setup-steps.yml |
workflow_dispatch, push and pull_request (paths: its own file only) |
Practical consequence: on a feature branch, only a PR (or merging to main) runs Actions — with one narrow exception: copilot-setup-steps.yml has an unrestricted push trigger filtered to its own file, so a branch push that edits that one workflow does fire it. Nothing else does.
Doc/metadata-only branches still get the full ci.yml + security.yml matrix once a PR is open, because neither has a path filter; a PR touching docs/** additionally fires docs.yml, which does.
Why This Matters¶
- The
github-action-monitorskill returning "0 runs for this commit" on a branch push is expected, not a failure. Reporting it as a CI failure would be wrong; reporting it as "CI passed" would be equally wrong — nothing ran. - It prevents wasted debugging: the absence of runs is a trigger-config fact, not a symptom of a bad push, auth problem, or Actions outage.
- It reinforces the project rule that
just ci-checkmust pass locally before pushing — it is the real gate for branch commits, and there is no remote substitute until PR time. (See AGENTS.md § "Runjust ci-checkBEFORE committing".)
When to Apply¶
- Immediately after
git pushof a feature branch, before concluding anything about CI health. - When the CI monitor reports no runs — check whether a PR exists before investigating the push.
- When deciding whether to open a PR: opening one is the action that starts remote CI, so open it (or keep the branch local) deliberately rather than waiting for runs that will never appear.
Examples¶
Finding zero runs on a fresh branch push is the normal state:
# After: git push -u origin chore/my-branch (no PR yet)
COMMIT=$(git rev-parse HEAD)
gh run list --branch chore/my-branch --limit 10 \
--json headSha,name,status \
--jq "[.[] | select(.headSha==\"$COMMIT\")] | length"
# => 0 ← expected; no PR means no pull_request trigger, and the
# push trigger only fires on main
Opening the PR is what starts CI:
gh pr create --base main --head chore/my-branch --title "..." --body-file body.md
# Now ci.yml + security.yml queue against the head commit:
gh run list --branch chore/my-branch --limit 10 \
--json name,status,event \
--jq '[.[] | select(.event=="pull_request") | {name,status}]'
# => CI: in_progress, Security: in_progress