Skip to content

chore(ci): gate formatting and PR titles - #4

Merged
Yigtwxx merged 2 commits into
mainfrom
chore/ci-formatting-and-pr-title-gates
Sep 7, 2026
Merged

Yigtwxx merged 2 commits into
mainfrom
chore/ci-formatting-and-pr-title-gates

Conversation

@Yigtwxx

@Yigtwxx Yigtwxx commented Sep 7, 2026

Copy link
Copy Markdown
Owner

What and why

Three gates the contributing rules already describe, none of which anything
enforced.

ruff check and ruff format disagree about different things — the first about
what the code does, the second about how it reads — and only the first was
wired up. The frontend had the same hole for a different reason: next lint is
eslint, which says nothing about formatting, so the format:check script and
the .prettierrc beside it had sat unused since the frontend was created. Nine
files had drifted to whichever indentation their author's editor produced;
chore(frontend): reformat the files prettier had never been run on fixes them
in a separate commit so 285 lines of reindentation do not bury a 49-line
workflow change. Every hunk in it is whitespace.

The PR title check is new. A squash merge writes the title into history, which
makes it the subject line this repository's 72-character Conventional Commits
rule actually applies to — gating the branch commits instead would check text
that gets discarded on merge. The accepted types are the six the convention
lists rather than the wider Conventional Commits vocabulary, so widening the set
stays a visible edit here rather than something that happens by accident.

The title is read through an environment variable rather than a ${{ }}
interpolation into the script. On a public repository the title is
attacker-controlled, and substituting it directly would run whatever a PR author
put after a semicolon.

How it was verified

  • cd backend && ruff check . && python -m compileall -q -x "venv|data" . && pytest && ruff format --check .
  • cd frontend && npm run lint && npm run typecheck && npm test && npm run build

Beyond the checklist:

  • npm run format:check and ruff format --check . — the two new gates — pass
    on this branch, so neither arrives red.
  • python scripts/build_agent_skill.py --check and
    python scripts/build_repo_facts.py --check still pass; the reformat touched
    package.json but no generated figure moved.
  • The title script was extracted from the workflow and run against a table of
    titles: the five valid shapes above pass (including feat!: and a bare
    docs:), and Update stuff, feature(ui): …, a capitalised description, a
    trailing period, a 98-character subject and a bare feat(ui): each fail with
    the message naming the specific rule.
  • Both currently open PRs (chore(backend): remove the RLS workaround SQL from the backend root #1, feat(frontend): render the not-advice caveat on model output surfaces #3) pass the new title gate, so this does not
    block work already in flight.
  • Shell injection was tested directly: feat(ui): x; rm -rf / is accepted as a
    well-formed title and nothing executes, which is the point of the env: block.

Screenshots

Not applicable — no UI change. The nine reformatted files render identically;
the diff is indentation only.

Configuration

Nothing here applies.

Notes for the reviewer

No secret-scanning job, deliberately. GitHub's own secret scanning and push
protection are already enabled on this repository, and security_and_analysis
reports both enabled. A second scanner would add a way for the two to
disagree without adding coverage.

This branch push ran no CI. ci.yml listens on push: main and
pull_request: main, so nothing fired until this PR opened. The gates are green
locally; this PR is the first time they run on a runner, and pr-title is
running against its own definition.

Left out on purpose, both worth their own PR:

  • concurrency on the workflow, to cancel superseded runs. Five jobs on every
    push gets expensive as PR volume grows, but it is a different concern from
    what is gated.
  • Dependabot security updates are currently disabled.

The one judgement call I would push back on if you disagree: restricting types
to the six in the convention means a CI-only change has to be chore, not ci.
That is what this PR did.

🤖 Generated with Claude Code

https://claude.ai/code/session_01B455UiUbbGqda87ZFc9wjb

Yigtwxx and others added 2 commits September 7, 2026 10:28
The repository has carried a prettier config and a `format:check` script
since the frontend was created, but nothing in CI ever ran them, so nine
files kept whichever indentation their author's editor produced. All the
changes here are whitespace: four-space indentation collapsed to the two
the config asks for. Doing it in its own commit keeps the gate that
follows readable, because 285 lines of reindentation would otherwise bury
a nine-line workflow change.

`test-results/` and `playwright-report/` join .prettierignore for a
different reason. Both are gitignored, so CI never sees them, but a local
Playwright run leaves them behind and `format:check` then fails on a
machine where the gate would have passed — which is the fastest way to
teach someone the gate is unreliable and should be skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B455UiUbbGqda87ZFc9wjb
Three gates the contributing rules already describe but nothing enforced.

`ruff check` and `ruff format` disagree about different things — the first
about what the code does, the second about how it reads — and only the
first was wired up. The frontend had the same hole for a different reason:
`next lint` is eslint, which says nothing about formatting, so the
`format:check` script sat unused. Both pass on the current tree, so
neither gate arrives red.

The PR title check is new. A squash merge writes the title into history,
which makes it the subject line the repository's 72-character
Conventional Commits rule actually applies to; gating the branch commits
instead would check text that gets discarded. The accepted types are the
six in the contributing convention rather than the wider Conventional
Commits vocabulary, so widening it stays a visible edit here.

The title is read through an environment variable rather than a `${{ }}`
interpolation. On a public repository the title is attacker-controlled,
and substituting it into the script would run whatever a PR author put
after a semicolon.

No secret-scanning job: GitHub's own scanning and push protection are
enabled on this repository, and a second scanner would only add a way for
the two to disagree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B455UiUbbGqda87ZFc9wjb
@Yigtwxx
Yigtwxx merged commit 737c074 into main Sep 7, 2026
6 checks passed
@Yigtwxx
Yigtwxx deleted the chore/ci-formatting-and-pr-title-gates branch September 7, 2026 07:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant