<!-- ABOUTME: Changelog-first Conventional Commits policy for reader-friendly release notes. -->
<!-- ABOUTME: Groups each commit by releasable outcome instead of code layer or file type. -->
Conventional Commits
Invariants & Rules
- Smallest Releasable Vertical Slice: One commit is the smallest complete, independently reviewable outcome—not every change related to a broad feature or workstream. Include only the layers and artifacts required for that exact behavior.
- No Orphaned Generated Code: Generated clients/schemas must travel in the commit that triggered them.
- No Layer Scopes: Scopes describe capability/engineering concern—never code layers (
api, domain, persistence, blazor, client, dto are forbidden).
- Cross-Domain Precedence: When a feature spans domains, select the primary initiating capability (
registration).
- Reader-First Messages: Subjects state the concrete user/operator or engineering outcome in imperative mood, without decoding internal jargon. Bodies explain the problem and changed behavior before the mechanism. Apply reader-first writing to messages and PR descriptions; preserve exact identifiers, breaking-change instructions, and trailers.
- Breaking Work & Change-Id: Breaking changes require
! and BREAKING CHANGE: footer. Governed security/migration work requires its change fragment in docs/internal/releases/changes/ and matching Change-Id: CHG-... footer.
- Internal Nonbreaking Work: Commits of type
test, build, ci, refactor, style, or internal docs/fix must carry both Changelog: skip and non-empty Changelog-Reason: <reason>.
- Safe Staging: Never use blind
git add . on mixed trees. Explicitly name staged files per atomic commit. On a shared checkout, inspect the existing index first; never unstage another contributor's work. If unrelated paths are already staged, use an explicit path-limited commit only when you own the complete diff of every named file, then verify the resulting commit file list. A file containing another contributor's hunks is a blocker until ownership is separated or coordinated.
- Self-Sufficient Planned Contract: Planning writes exact metadata, commit paths, inspection commands,
git add, path-limited git commit, and post-commit verification in tasks.md. Pathspecs equal declared paths and the command encodes metadata/trailers. A truthful packet executes without loading this skill.
- Material-Divergence Override Gate: The executor loads this skill only when it will not use the planned packet due to user change, atomic split, material divergence, changed breaking/change-fragment classification, or factual invalidity. Before committing, record the reason and a complete metadata/path/command packet for every resulting commit. Style is insufficient.
- Execution Protocol: Show the proposed commit plan by default; execute stage-and-commit directly when explicitly instructed. An approved implementation-plan phase-close task is explicit instruction for the implementing agent to commit in the same session.
- History Invariants: Commit
B is the sole commit whose terminal footers are Changelog: skip and Changelog-Reason: release metadata commit. Never rewrite published history on develop or release lines.
- Oversized Commit Gate: A large dirty tree is evidence that more clustering is required, not permission for one umbrella commit. Split independent behaviors, refactors, tests, documentation, plans, cleanup, provider integrations, and operational changes even when they share a capability scope.
- Rare Large-Commit Exception: A commit may touch dozens or hundreds of files only when the same indivisible change necessarily applies across them—for example a mechanical repository-wide rename, generated artifacts from one source change, or one schema/migration regeneration whose files cannot build or remain truthful independently. State that necessity in the commit plan; “same feature,” “same workstream,” or “all currently dirty” is never sufficient.
Scope Registry
| Category | Allowed Scopes | Description |
|---|
| Public | events, registration, ticketing, discovery, notifications, privacy, access, storage, onboarding, federation, webhooks, localization, accessibility, self-hosting | User/operator capabilities (in release notes). |
| Engineering | ci, dependencies, architecture, database, observability, documentation, release, testing, build | Codebase health, build, testing, dev tooling. |
File Clustering (Atomic Slicing)
Sort dirty working trees using this priority order:
- Vertical Feature/Fix Slice: Domain + App + Persistence + UI + Generated Artifacts + Tests + Docs.
- Technical/Resilience Fix: Independent database execution strategies, retries, or middleware.
- Test Suite Hardening: Test fixtures, schema isolation (
current_schema()), characterization models.
- Build & Package Config: Central props (
Directory.Build.props), lockfiles, CI pipelines.
- Governance & Legal Docs:
CLA.md, CONTRIBUTING.md, README.md, ADRs (docs/internal/adr/*), durable findings (dev/_journal/*). (Note: Active task tracking in dev/active/* is gitignored local working memory and excluded from commits).
Then apply the atomicity gate:
- Describe each candidate commit in one benefit-led sentence.
- Remove every file not required to make that sentence true.
- Split files that implement another behavior, cleanup, plan, test-hardening effort, or operator concern.
- Keep generated outputs with their exact source change, but do not use generated files to absorb unrelated handwritten work.
- For an unusually large candidate, explain why splitting would create a broken build, orphan generated output, or a false intermediate contract. If no concrete break exists, split it.
File count is a warning signal, not the definition of atomicity. Small commits are the default; very large commits are exceptional and must be structurally indivisible.
Format & Non-Interactive CLI Recipes
type(scope): benefit-led subject
Explain the problem and what changes for the reader.
Then explain the relevant technical mechanism and constraints.
Changelog: skip
Changelog-Reason: concise explanation of why commit is excluded from public release notes
| Type | Meaning |
|---|
feat / fix / perf | User/operator capability, bugfix, or efficiency improvement |
revert / docs | Rollback with stated outcome, or documentation-only change |
test/build/ci/refactor/chore | Internal outcome (skipped from public release notes) |
CLI Recipe
Confirm git config --get core.hooksPath resolves to the repository .githooks
directory. If unset, use git config core.hooksPath .githooks; do not discard
an existing custom hook chain. The tracked commit-msg hook runs the native
preflight-commit command before Git records the commit. It validates the proposed
message and indexed Change-Id provenance with the policy used by range validation.
Never use --no-verify or override hooks to bypass this gate.
git status --short
git diff --cached --name-only
git add -- path/to/OwnedChange.cs path/to/OwnedChangeTests.cs
git commit --only -m "test(access): isolate committed cancellation observation" \
-m "Observe only keys created by this invocation." \
-m $'Changelog: skip\nChangelog-Reason: Internal test isolation correction.' \
-- path/to/OwnedChange.cs path/to/OwnedChangeTests.cs
git show --name-only --format=fuller HEAD
Use literal owned paths. Path-limited commits isolate files, not another contributor's hunks inside a shared file. Add the required changelog/breaking-change trailers for the classified change.
Use one -m argument for both skip declarations. Separate -m arguments introduce
blank paragraphs; native policy tolerates whitespace between terminal trailer
paragraphs, but keeps duplicates, conflicting values, missing reasons and breaking
metadata violations invalid. Ordinary body prose stops the terminal trailer scan.
For a saved proposed message, run the same gate explicitly before committing:
dotnet run --project eng/release/src/ISLAMU.ReleaseEngineering/ISLAMU.ReleaseEngineering.csproj \
--configuration Release -- preflight-commit /absolute/path/to/proposed-message.txt --target develop
Keep preflight-range --target develop --head HEAD as the final local/CI check;
successful hook validation does not replace complete-range validation.
Resources
Verification
git log --format='- %s' "$(git merge-base HEAD origin/develop)"..HEAD
- Apply the resource's readability check; confirm every skipped commit has both trailers and every breaking commit has its required footer. Readability never substitutes for release metadata.