CI/CD must pass before merge — ABSOLUTE rule, all Corone projects
No PR merges with failing CI. Every CI job must be green. No bypass. No exceptions.
User (r_goto) directive 2026-05-04, hardened after CRV-46 firefight regressed Curva’s CD bypass.
Scope
Applies to every repo under COCONRobotics-Corp org and every Corone-Inc account project hosted on this VPS or anywhere else:
| Project | Repo | Branch model |
|---|---|---|
| Curva | COCONRobotics-Corp/Curva | develop (with user/corone-CRV-XX-… PRs) |
| Pasukuru FE | COCONRobotics-Corp/pasukuru-fe | TBD |
| Pasukuru BE | COCONRobotics-Corp/pasukuru-be | TBD |
| Corone Monster | COCONRobotics-Corp/corone-monster | main + corone-ryo + corone-julian |
| Kokorozashi | (Xserver static) | manual deploy |
| Passkuru LP | (Xserver static) | manual deploy |
| Future Corone projects | TBD | inherits this rule |
Plus Da Vinci (DVG) — but that’s NO-TOUCH read-only, no merges happen via this agent anyway. Rule still applies if/when ever lifted.
The hard rule (verbatim)
Every CI/CD test job must show GREEN before any PR can be merged.
If even one job is red/failed/cancelled, MERGE IS FORBIDDEN regardless of:
- Who requested the merge
- How urgent the fix is
- Whether the failing job is “unrelated”
- Whether it works locally
- Whether CI is “just being flaky”
- Whether the user explicitly says “merge it anyway”
If user requests merge while CI is red → respond:
PR has N red CI jobs. Cannot merge. Fix CI first.
Then either auto-fix the red jobs or surface them to the user for direction.
Pre-merge checklist (every PR, every project)
Run through this before acting on any merge request:
[ ] All CI jobs status == "success"
(not "pending", not "failure", not "cancelled", not "skipped-but-should-have-run")
[ ] Branch up-to-date with target (no behind-by-N)
[ ] PR body has Jira ID
[ ] Workspace attribution in PR body or Jira comment
("Requested by Ryo" or "Requested by Julian")
[ ] No secrets in commit diff
[ ] Explicit human approval THIS specific commit SHA
(Ryo/eduson510 OR Julian/time7676 — both valid signoff)
If any box unchecked → merge blocked.
To check CI status fast:
gh pr checks <PR_NUMBER>Returns table with pass / fail / pending per job.
Required infrastructure (every Corone repo)
For this rule to be enforceable, every Corone repo MUST have:
- Branch protection on default branch (and any deploy-target branch like
develop,staging):- Require status checks before merge
- Require branches to be up to date before merging
- Required status checks: ALL CI jobs that run on PRs must be selected
- CI workflow triggered on
pushandpull_requestto all deploy-target branches. - CD workflow that either:
- Runs only on
workflow_runafter CI succeeds, OR - Has a
ci-gatejob that usesgh apito verify CI green for the same SHA before deploy proceeds (CRV-54 pattern, see.github/workflows/cd.ymlin COCONRobotics-Corp/Curva).
- Runs only on
- No
workflow_dispatchon deploy workflows withoutci-gate. - No
[skip ci]/--skip-ci/--no-verifyon commits to deploy-target branches.
If any of these are missing → file a ticket like CRV-54 and harden before any further feature work.
CRV-54 reference pattern (for future Corone repos)
The cd.yml ci-gate job from Curva (COCONRobotics-Corp/Curva PR #1045):
on:
workflow_run:
workflows: [CI]
branches: [main, develop]
types: [completed]
workflow_dispatch:
inputs:
reason:
description: "Why dispatch manually? (audit trail)"
required: true
type: string
jobs:
ci-gate:
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
steps:
- name: Verify CI passed for SHA ${{ github.sha }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
RUN_JSON=$(gh api -H "Accept: application/vnd.github+json" \
"/repos/${REPO}/actions/workflows/ci.yml/runs?head_sha=${SHA}&per_page=1" \
--jq '.workflow_runs[0] // empty')
if [ -z "$RUN_JSON" ]; then
echo "::error::No CI run found for SHA $SHA"
exit 1
fi
STATUS=$(echo "$RUN_JSON" | jq -r '.status')
CONCLUSION=$(echo "$RUN_JSON" | jq -r '.conclusion')
if [ "$STATUS" != "completed" ] || [ "$CONCLUSION" != "success" ]; then
echo "::error::CI did not succeed for SHA $SHA"
exit 1
fi
build-and-deploy:
needs: [ci-gate]
if: |
always() &&
(
(github.event_name == 'workflow_run' && !contains(fromJSON('["failure", "cancelled"]'), github.event.workflow_run.conclusion)) ||
(github.event_name == 'workflow_dispatch' && needs.ci-gate.result == 'success')
)
# ... rest of deploy ...Use this pattern in any new deploy workflow on any Corone repo.
Anti-patterns (FORBIDDEN)
- ❌ “Just merge it, the test failure is unrelated.” → NO. Fix the test or open a tracking ticket and explicitly approve the deviation, with sign-off recorded.
- ❌ “It worked locally, CI is just slow/flaky.” → NO. Flakiness is a separate ticket. Re-run CI to green; do not merge red.
- ❌ “We need to ship this hotfix now, CI takes too long.” → NO. Use the ci-gate-aware emergency workflow with documented reason input. Never bypass.
- ❌ “I’ll merge and fix CI in the next commit.” → NO. Develop branch must always be deployable.
- ❌ “Lint is just style, doesn’t matter.” → NO. Lint is a hard gate. Style errors signal process failures (review skipped, hooks bypassed).
- ❌ Adding
[skip ci]to deploy commits. → Forbidden by branch protection if configured correctly. - ❌ Using GitHub admin override to merge. → Forbidden except for the single exception path below.
Single exception path
GitHub repository admin override is allowed ONLY when ALL of the following are true:
- Documented in an incident ticket within 24 hours of the override.
- Explicit
r_gotosign-off (either Ryo/eduson510 or Julian/time7676 persona). - Reason matches: “production down, CI infrastructure broken, customer impact”.
- A follow-up ticket exists to root-cause + harden CI within 7 days.
That’s it. Single, narrow, audited path. Anything else → forbidden.
How this rule was hardened (CRV-54 history)
- 2026-05-03 → 2026-05-04: CRV-46 emergency redis pecl + EB recovery work on Curva.
- During CRV-46, PR #1027 added unconditional
workflow_dispatchtocd.yml. Eight manual production deploys ran through it on 2026-05-04. CI was also returning false-greens becausepaths-filterexcluded.ebextensions/,.platform/,.github/workflows/, etc. - 2026-05-04: CRV-54 created (Julian persona scoping ticket).
- 2026-05-04: PR #1045 opened (Ryo + Julian commits) — restored mandatory CI gate, expanded paths-filter, version unification, action upgrades, ci-light deletion, eb-ops consolidation, package audit, README documenting hard rule + anti-patterns.
- 2026-05-04: After PR #1045 lint fixes (commits
0e7e7ba+3513baa), user (r_goto) made this an absolute rule for ALL Corone projects, not just Curva.
Cross-references
- Memory:
corone-cicd-must-pass-before-merge-absolute(canonical persistent record) - Memory:
crv-54-pr-1045-cicd-hardening(origin PR, ci-gate pattern) - Memory:
curva-merge-approval-personas(Ryo OR Julian both valid signoff) - Memory:
absolute-jira-id-comment-attribution-corone-keb(companion rule on git push workflow) - File:
/var/www/CLAUDE.md(global CLAUDE prompt — has a section pointing here) - File:
/var/www/corone.monster/CLAUDE.mdand/var/www/kebahagiaan.corone.monster/CLAUDE.md(per-workspace cross-refs) - File:
.github/workflows/README.mdin COCONRobotics-Corp/Curva (concrete reference implementation)