Previous commit 34e0e34 over-corrected by skipping commitlint on every
next → main promotion PR, hiding a future class of CC violations sneaking
through admin-bypass direct pushes.
Properly:
- commitlint workflow back to skipping ONLY sync PRs (head_ref=main).
Promotion PRs (head=next, base=main) lint the full aggregate again.
- commitlint.config.mjs grows an ignores predicate for the one
historical commit (888977d) whose 'merge:' prefix isn't a CC type.
That commit landed via admin bypass before stricter branch protection
was in place. Acknowledged + scoped opt-out, not a relaxed rule.
Follow-up needed: tighten branch protection on main + next to disallow
admin bypass so this class of leak can't happen again.
Phase D entry slice. Two pieces, both meta-CI:
1. **dependabot.yml** — adds the two missing ecosystems
(`docker` for `deploy/docker` and `docker/test-sshd`) on top of
the existing npm / gomod / github-actions configs. The deploy
container ships to anyone running the turn-key sshd compose
stack; the test-sshd container backs every integration CI run.
Without docker entries, base-image CVEs in alpine + openssh-
server would have to be noticed by hand. Both new entries:
weekly Monday 09:00 JST (matching existing schedules), open-PR
cap 3, labels `dependencies` + `build`/`ci`. No grouping —
docker bumps are individually noteworthy.
2. **commitlint workflow + config** — turns the existing-by-hand
Conventional Commits convention into a hard PR gate. Lints the
PR's full commit range (`base..head`), not just the squash-
merge title, so a typo in commit #3 of a 5-commit PR fails fast
instead of leaking into history.
Repo-specific tweaks vs `@commitlint/config-conventional`:
- `subject-case: [0]` — repo history mixes cases
(`Phase C.M3 — …`); standard config rejects anything but
lower-case subjects.
- `header-max-length: 144` — standard cap is 100, but the
repo's `feat(plugin): Phase C.M10 — perf-bench off the PR
critical path … (0.4.48)` style commits push up to ~120.
144 gives the existing style room to breathe without
inviting actual essays.
- `type-enum` — explicit allow-list collected from the
existing history (`build / chore / ci / docs / feat / fix
/ perf / refactor / revert / style / test`) plus `release`
for any future release-on-merge auto-commits.
- `scope-empty: [0]` — scopes are free-form (plugin /
server / proto / deploy / ci / etc); don't restrict via
`scope-enum` because new scopes appear naturally.
Triggers on PRs only (not pushes to main): main is squash-
merged from PRs whose commits already passed; running on every
push to main would be redundant and would re-fire on the merge
commit which has its own (also Conventional) format.
Permissions: `contents: read` + `pull-requests: read` (no
write — commitlint just reads the commit range).
Verification:
- `npx vitest run` — 37 files / 501 tests still green (no source
surface change).
- `npx tsc --noEmit -p tsconfig.json` — clean.
- Locally inspected last ~50 commits on main against
`commitlint --extends @commitlint/config-conventional` — none
exceed the 144-char header cap or use a type outside the
enum-list.
- Dependabot YAML parses against the v2 schema (verified by
matching the existing entries' shape).
- Live behaviour requires merge to surface — the next PR will be
the first to see commitlint on its own commits, and Dependabot's
next Monday run is the first chance to see the docker bumps.
manifest/package/versions bumped 0.4.48 → 0.4.49.
Roadmap context: Phase D-α (meta-CI integration, this) → D-β
(Logger JSONL, F20) → D-γ (Error toast taxonomy, F18) → D-δ
(daemon sha256 + cosign + security.yml, F23/F24).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>