Skip to main content

Branching

The integration branch is develop, which is also the repository’s default branch. main is the release branch — only develop → main integration PRs land there, and a human performs that step. Verify before opening a PR:
develop being ahead of main is the expected state. Because develop is the default branch, scheduled workflows run the develop copy of their files. For the same reason, the PR watchdog never auto-merges a PR that touches .github/workflows/ — a human clicks merge on those.

Commit messages

Conventional commits:

Working attitude

Ship work that would clear the bar of a careful senior reviewer.
When you split a file, every input, mutation, side effect and accessibility hook that existed before must exist after — even the ones that were already broken. If you find a pre-existing bug while refactoring, fix it in the same PR and say so in the description. Never silently propagate it.
Walk every JSX block, form schema and payload serialiser side by side with the pre-change version. For every field in the schema ask: is it rendered? is it serialised? is it seeded? Missing one is the silent-data-loss bug.
A fix without a test is a fix that reverts on the next refactor. Keep the test on the failure mode, not the implementation.
Treat each new finding as a signal that the original work missed a checkpoint, not as a fresh task.

Self-review checklist

Before opening or updating a PR, walk your own diff: Security
  • Auth first, then permission, in every handler.
  • Ownership verified on every HTTP verb in the file.
  • No unvalidated redirect target; no token in a Location: header or query string.
  • No interpolation into GraphQL, shell commands or raw SQL.
  • timingSafeEqual for token comparison.
  • Security fixes carry the attack, 401 and 403 tests.
Sibling-path completeness — the most repeated finding
  • grep for every sibling call site of what you changed and fix each.
  • Pin structural twins with a same-shape test.
Code quality
  • No console.* in src/; no empty catch blocks.
  • No any, @ts-ignore, or silencing casts.
  • All user-facing strings in de + en + fr.
  • No magic numbers, dead code, duplicate JSDoc or stale comments.
  • Functions under 80 lines.
Database
  • Schema change has exactly one matching migration; no duplicate.
  • Conditional $transaction uses the interactive callback form.
  • Every JSON.parse() is wrapped.
Tests and i18n — as above.

The PR test plan

The ## Test plan section lists only the checks you ran locally, with their results.
Do not list CI Quality Gate or Bot review on this PR as test-plan items. Both run automatically and are reported elsewhere; an unchecked checkbox for them is noise. The test plan ends at the last local check.

The automated review loop

After every push to an open PR, a bot review posts a severity table (🔴 Must Fix / 🟡 Should Fix / 🟢 Nit). When the summary reports non-zero 🔴 or 🟡, an auto-fix job rebases, applies fixes, runs the full gate, and pushes — which re-triggers the review. The loop is capped at three rounds; when the cap is hit it posts a stuck summary and a human takes over. Integration PRs (develop → main) are excluded — every commit in them was already reviewed on its feature PR.

What you still own

  • Round-1 quality. The auto-fix loop is a safety net for what the checklist missed, not a substitute for it.
  • 🟢 Nits get fixed too. “Non-blocking” describes the merge gate, not your obligation. The only acceptable way to skip a nit is a reply explaining why it is factually wrong or would make the code worse.
  • Stuck PRs. A round-3 finding usually signals an architectural call the auto-fixer cannot make. Fix it by hand and the loop resumes, or escalate.
  • Tests for every fix, including the ones the auto-fixer wrote.

Documentation

Documentation lives in docs/, and this site is docs/site/. Update the relevant operations playbook in the same PR as any production change that affects operations. See The docs site for how to run and deploy it.