diff --git a/docs/changelog.md b/docs/changelog.md index fb74801..ea808e3 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -11,6 +11,7 @@ below and to the page that documents the feature properly. | Version | What changed | Documented in | |---|---|---| +| [2.18.0](#v2180) | AI disclosure policy: three rules, and the correction written for you | [Policy guides](guides/policies.md#asking-for-disclosure-instead) · [CC014](rules.md#cc014) | | [2.17.0](#v2170) | Concrete corrections for mechanical slips; a `warn` level per rule | [Reading the JSON](example.md#reading-the-json) · [Report without enforcing](configuration.md#report-a-rule-without-enforcing-it) | | [2.16.0](#v2160) | Tag name validation, and file size, path and pattern policies | [CC401](rules.md#cc401) · [CC302–CC304](rules.md#push-rules) | | [2.15.1](#v2151) | Color and rule-ID links appear only where they render; `NO_COLOR` honoured | [Color and links](example.md#color-and-links) | @@ -28,6 +29,77 @@ below and to the page that documents the feature properly. | [2.5.0](#v250) | Organization-wide config with `inherit_from` | [Across an organization](guides/organization.md) | | [2.0.0](#v200) | Configuration moved from YAML to TOML — breaking | [Migrating from v1](migration.md) | +## v2.18.0 (2026-09-13) { #v2180 } + +### Added + +* **AI attribution gained a third policy, `"disclose"`** — for the projects + that welcome AI assistance and ask to be told about it. It turns on three + rules, one per condition, so any of them can be demoted to a warning while + the others keep enforcing: the assistance is disclosed with one of + `ai_disclosure_trailers` ([CC014](rules.md#cc014), default `Assisted-by` + and `Generated-by`), the tool is not credited as a co-author + ([CC015](rules.md#cc015)), and it did not sign off the commit + ([CC016](rules.md#cc016)) — a sign-off certifies the DCO, which only a + person can do. A failing check carries the correction: the vendor's + co-author line rewritten as the project's disclosure trailer, keeping the + name the tool gave itself. `ai_disclosure_pattern` asks for a particular + format, such as `agent/model`. The default stays `"ignore"`, and an + `ai_attribution` value that is none of the three is now a configuration + error rather than a silently disabled check. + See PR [#575](https://github.com/commit-check/commit-check/pull/575) and + [Asking for disclosure instead](guides/policies.md#asking-for-disclosure-instead). + +* **A failed check names the value it rejected, and by how much** — a long + subject reports `Subject is 96 characters; it must be at most 80 + characters` and how many to cut, a custom `message_pattern` is echoed back, + and the rejection banner says whether it was the commit, the branch, the + tag or the push that was rejected. + See PR [#571](https://github.com/commit-check/commit-check/pull/571). + +* **A specification named in an error links to it** on terminals that render + hyperlinks, so `Conventional Commits` and `Conventional Branch` are + clickable instead of trailing a URL. Piped output is unchanged. + See PR [#568](https://github.com/commit-check/commit-check/pull/568). + +### Changed + +* **`ai_attribution = "forbid"` now recognises the disclosure trailers too.** + `Assisted-by:` and `Generated-by:`, in the formats the Linux kernel, Fedora, + FluxCD and the ASF actually write them, are AI attribution like any other — + a project that forbids attribution was letting them through. + See PR [#575](https://github.com/commit-check/commit-check/pull/575) and + [CC013](rules.md#cc013). + +### Fixed + +* **[CC201](rules.md#cc201) anchors a branch name at both ends** — `main-backup`, + `master2` and `develop-x` passed as if they were `main`, `master` and + `develop`. They fail now. + See PR [#569](https://github.com/commit-check/commit-check/pull/569). + +* **[CC001](rules.md#cc001) exempts only the subjects git writes itself** — + `Merge `, `Revert "`, `fixup! `, `squash! ` and `amend! `. Author prose that + merely started that way, such as `Merged stuff` or `fixup!! nonsense`, was + exempt too. + See PR [#569](https://github.com/commit-check/commit-check/pull/569). + +* **A setting whose regex does not compile names the setting** and exits `2`, + the code for a broken configuration: `[commit] message_pattern is not a + valid regex: '^(unclosed'`. It used to surface as a bare Python error with + exit code `1`, the code a rejected commit gets. + See PR [#574](https://github.com/commit-check/commit-check/pull/574) and + [Exit codes](troubleshoot.md#exit-codes). + +* **A configuration error exits `2` and names the file it came from**, and + `--dry-run` runs the checks it was asked for instead of printing nothing + and exiting `0`. + See PR [#570](https://github.com/commit-check/commit-check/pull/570). + +* **An `inherit_from` that cannot be loaded says so on stderr** instead of + falling back to the local config in silence. The run still continues. + See PR [#569](https://github.com/commit-check/commit-check/pull/569). + ## v2.17.0 (2026-09-06) { #v2170 } ### Added diff --git a/docs/configuration.md b/docs/configuration.md index 475e7f8..001e7b8 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -192,7 +192,7 @@ allow_fixup_commits = true allow_wip_commits = false # changed: allowed by default require_body = false require_signed_off_by = false -ai_attribution = "forbid" # changed: "ignore" by default +ai_attribution = "disclose" # changed: "ignore" by default; see the AI policy guide # ignore_authors = [] # optional: bypass all commit checks for these authors [push] @@ -240,7 +240,7 @@ Used from a hook definition, with no config file anywhere in the repository: ```yaml title=".pre-commit-config.yaml" repos: - repo: https://github.com/commit-check/commit-check - rev: v2.17.0 + rev: v2.18.0 hooks: - id: check-message args: @@ -288,6 +288,8 @@ The full mapping between the three forms: | `require_rebase_target = "main"` | `CCHK_REQUIRE_REBASE_TARGET=main` | `--require-rebase-target=main` | | `allow_force_push = true` | `CCHK_ALLOW_FORCE_PUSH=true` | `--no-force-push` (sets `allow_force_push` to `false`) | | `ai_attribution = "forbid"` | `CCHK_AI_ATTRIBUTION=forbid` | `--ai-attribution=forbid` | +| `ai_disclosure_trailers = ["Assisted-by"]` | `CCHK_AI_DISCLOSURE_TRAILERS=Assisted-by` | `--ai-disclosure-trailers=Assisted-by` | +| `ai_disclosure_pattern = '^\S+/\S+$'` | `CCHK_AI_DISCLOSURE_PATTERN=^\S+/\S+$` | `--ai-disclosure-pattern='^\S+/\S+$'` | | `ignore_authors = ["bot"]` (in branch section) | `CCHK_BRANCH_IGNORE_AUTHORS=bot,user` | `--branch-ignore-authors=bot,user` | | `regex = "^v\\d+\\.\\d+\\.\\d+$"` (in tag section) | `CCHK_TAG_REGEX=^v\\d+\\.\\d+\\.\\d+$` | `--tag-regex=^v\\d+\\.\\d+\\.\\d+$` | | `max_size = "5MB"` (in files section) | `CCHK_FILES_MAX_SIZE=5MB` | `--files-max-size=5MB` | @@ -344,7 +346,9 @@ the same thing twice, so read the description rather than the cell: | commit | author_email_pattern | str | `^.+@.+$` | Custom regex for the author email check. When empty, the built-in default pattern is used. This option only takes effect when the author_email check is enabled (`-e` / `--author-email`). | | commit | author_name_pattern | str | "" (built-in default) | Custom regex for the author name check. When empty, the built-in default pattern is used (it is not disabled). This option only takes effect when the author_name check is enabled (`-n` / `--author-name`). | | commit | require_signed_off_by | bool | false | Require "Signed-off-by" line in the commit message footer. | -| commit | ai_attribution | str | "ignore" | AI attribution policy. `"forbid"` rejects any commit containing known AI tool signatures (Claude Code, Copilot, Codex, Gemini, Cursor, Devin, Aider, Windsurf, Tabby, and generic AI model patterns). `"ignore"` disables the check. This feature is a response to the industry-wide discussion on AI disclosure in open source (Linux kernel `Assisted-by:` trailer, CPython, VS Code, Apache, Fedora policies). | +| commit | ai_attribution | str | "ignore" | AI attribution policy. `"forbid"` rejects any commit carrying AI attribution — a co-author or sign-off line naming a known tool, a disclosure trailer, a vendor mark ([CC013](rules.md#cc013)). `"disclose"` accepts AI assistance that is disclosed with one of `ai_disclosure_trailers` ([CC014](rules.md#cc014)) and rejects the tool as a co-author ([CC015](rules.md#cc015)) or as a sign-off ([CC016](rules.md#cc016)). `"ignore"` disables the check. Any other value is a configuration error. | +| commit | ai_disclosure_trailers | list[str] | ["Assisted-by", "Generated-by"] | The trailers that disclose AI assistance under `"disclose"`. The first one is what a correction is written with. Listing `Co-authored-by` says the project accepts the tool as a co-author, and CC015 then passes. `Signed-off-by` is refused: only a person can certify the DCO. | +| commit | ai_disclosure_pattern | str | "" (any value) | A regex the disclosure trailer's value must match under `"disclose"`, e.g. `'^\S+/\S+$'` for an `agent/model` format. Empty accepts any value, but a trailer with no value at all is reported whatever the pattern is. | | branch | conventional_branch | bool | true | Enforce Conventional Branch specification. | | branch | allow_branch_types | list[str] | ["feature", "bugfix", "hotfix", "release", "chore", "feat", "fix", "build", "ci", "docs", "perf", "refactor", "style", "test", "ai", "claude", "codex", "copilot", "cursor", "dependabot", "renovate"] | Allowed branch types when `conventional_branch` is true. The default is a superset of the [Conventional Branch spec](https://conventionalbranch.org/): the spec types (`feature`, `bugfix`, `hotfix`, `release`, `chore`) plus the Conventional Commit types (`build`, `ci`, `docs`, `perf`, `refactor`, `style`, `test`), AI agent prefixes (`ai`, `claude`, `codex`, `copilot`, `cursor`) and bot prefixes (`dependabot`, `renovate`). For strict spec-only validation, set this option explicitly (e.g. `["feature", "bugfix", "hotfix", "release", "chore"]`). | | branch | allow_branch_names | list[str] | [] (empty list) | Additional standalone branch names allowed when conventional_branch is true (e.g., ["develop", "staging"]). By default, master, main, HEAD, and PR-* are always allowed. | diff --git a/docs/example.md b/docs/example.md index 2c211cb..b8cc155 100644 --- a/docs/example.md +++ b/docs/example.md @@ -131,7 +131,7 @@ pushed: ```yaml title=".pre-commit-config.yaml" repos: - repo: https://github.com/commit-check/commit-check - rev: v2.17.0 + rev: v2.18.0 hooks: - id: check-no-force-push stages: [pre-push] diff --git a/docs/guides/policies.md b/docs/guides/policies.md index 12849a4..4e3a6c4 100644 --- a/docs/guides/policies.md +++ b/docs/guides/policies.md @@ -91,16 +91,19 @@ ignore_authors = ["dependabot[bot]", "renovate[bot]"] ## AI attribution -AI coding tools add trailers to commit messages identifying themselves. Whether -that is welcome, required, or unacceptable is a decision each project makes for -itself — and the industry has landed in different places: +AI coding tools stamp their own trailers on the commits they help with. +Whether that is welcome, required or unacceptable is a decision each project +makes for itself, and the industry has landed in three places — which are the +three values `ai_attribution` takes: -- The **Linux kernel** added an `Assisted-by:` trailer, treating AI assistance - as something to disclose. -- **Some projects disallow AI-assisted contributions outright**, usually over - provenance and licensing. -- **Most projects have no stated position**, which means the question resurfaces - in every code review. +| `ai_attribution` | The project's position | Rules | +|---|---|---| +| `"ignore"` (default) | no stated position | — | +| `"forbid"` | no AI attribution in the history | [CC013](../rules.md#cc013) | +| `"disclose"` | AI is welcome, said out loud, and not credited as a person | [CC014](../rules.md#cc014)–[CC016](../rules.md#cc016) | + +Whichever you pick, the check reads what the message says. It cannot see +assistance that left no trace — see the note below. ### The default: no opinion @@ -122,26 +125,143 @@ ai_attribution = "forbid" Commits carrying a recognised AI signature now fail: ```text -CC013 ai-attribution check failed ==> feat: add caching layer -AI attribution policy violation -Suggest: This project forbids AI-assisted commits. Remove AI trailers and re-commit. +CC013 ai-attribution check failed ==> Claude Code +AI attribution is forbidden in this project — detected: Claude Code +Suggest: This project does not accept AI attribution in commit messages. Remove the AI trailer lines and re-commit. Docs: https://commit-check.com/rules/#cc013 ``` -Recognised signatures are trailers and co-author lines naming Claude Code, -GitHub Copilot, Codex, Gemini, Cursor, Devin, Aider, Windsurf and Tabby, plus -generic AI model patterns. +Recognised signatures are co-author and sign-off lines naming Claude Code, +GitHub Copilot, Codex, Gemini, Cursor, Devin, Aider, Windsurf and Tabby, the +disclosure trailers `Assisted-by:` and `Generated-by:`, vendor marks such as +`🤖 Generated with Claude Code`, and generic AI model names. This is the +position [Kubernetes](https://www.kubernetes.dev/docs/guide/pull-requests/) +takes — no AI trailers in the history, disclosure in the pull request +instead. !!! warning "This checks disclosure, not authorship" - CC013 reads commit metadata. It detects a commit that *says* it was - AI-assisted; it cannot detect one that was AI-assisted and did not say so. + These rules read commit metadata. They detect a commit that *says* it + was AI-assisted; they cannot detect one that was AI-assisted and did + not say so. Set against a policy of "no AI contributions", it is an honesty check on contributors who are already following the rules — not an enforcement mechanism against those who aren't. Be clear with yourself about which of those you are buying. +### Asking for disclosure instead + +Most projects that allow AI assistance ask to be told about it. The +[Linux kernel](https://docs.kernel.org/process/coding-assistants.html), +[Fedora](https://docs.fedoraproject.org/en-US/council/policy/ai-policy/) and +FluxCD want an `Assisted-by:` trailer; the +[Apache Software Foundation](https://www.apache.org/legal/generative-tooling.html) +recommends `Generated-by:`. The kernel adds a second rule: an AI agent must +never add a `Signed-off-by:` line, because only a person can certify the +[DCO](https://developercertificate.org/). + +```toml title="cchk.toml" +[commit] +ai_attribution = "disclose" +``` + +That turns on three rules, each about one of those conditions: + +| Rule | Asks that | +|---|---| +| [CC014](../rules.md#cc014) | the assistance is disclosed with an accepted trailer | +| [CC015](../rules.md#cc015) | the tool is not credited as a co-author | +| [CC016](../rules.md#cc016) | the tool did not sign off the commit | + +A commit that a vendor stamped and nobody disclosed fails the first two, and +the failure carries the disclosure already written: + +```text +CC014 ai-disclosure check failed ==> Co-Authored-By: Claude Opus 5 +AI assistance is not disclosed with Assisted-by or Generated-by — detected: Claude Code +Suggest: Disclose the tool with "Assisted-by: Claude Opus 5" +Docs: https://commit-check.com/rules/#cc014 + +CC015 ai-co-author check failed ==> Co-Authored-By: Claude Opus 5 +An AI tool is credited as a co-author: Claude Code +Suggest: Use "Assisted-by: Claude Opus 5" in place of the co-author line +Docs: https://commit-check.com/rules/#cc015 +``` + +Both carry the same correction in `--format json`: the co-author line rewritten +as the project's disclosure trailer, keeping the name the tool gave itself. + +```json +"fix": "feat: add caching layer\n\nAssisted-by: Claude Opus 5" +``` + +Once the tool is disclosed, CC015 asks only for the co-author line to go, and +a commit written the way the kernel asks passes all three: + +```bash +printf 'feat: add caching layer\n\nAssisted-by: LLM coccinelle sparse\nSigned-off-by: Jane Dev ' | commit-check -m +``` + +### Choosing the format + +`ai_disclosure_trailers` is the list of trailers that count as a disclosure, +and the first one is what a correction is written with: + +```toml title="cchk.toml" +[commit] +ai_attribution = "disclose" +ai_disclosure_trailers = ["Assisted-by"] # the kernel's, and nothing else +``` + +Listing `Co-authored-by` says the project accepts the tool as a co-author — +[pytest](https://github.com/pytest-dev/pytest/blob/main/CONTRIBUTING.rst) and +IREE do — and CC015 then passes. `Signed-off-by` is refused whatever else you +list, so CC016 cannot be configured away. + +`ai_disclosure_pattern` asks for a particular shape, such as FluxCD's +`agent/model`: + +```toml title="cchk.toml" +[commit] +ai_attribution = "disclose" +ai_disclosure_pattern = '^\S+/\S+$' +``` + +```text +CC014 ai-disclosure check failed ==> Assisted-by: Claude Code +The Assisted-by value does not match the required pattern: ^\S+/\S+$ +Suggest: Write the Assisted-by value so that it matches ^\S+/\S+$ (set by ai_disclosure_pattern in the [commit] config) +``` + +There is no correction for that one: which model, in which format, is not +something the tool should guess. + +### Disclosure that is appreciated, not required + +Some projects — [CPython](https://devguide.python.org/getting-started/generative-ai/) +among them — welcome disclosure without demanding it, while still refusing the +tool as a co-author. Put CC014 in the top-level `warn` list and the other two +keep enforcing: + +```toml title="cchk.toml" +warn = ["ai_disclosure"] + +[commit] +ai_attribution = "disclose" +``` + +```text +CC014 ai-disclosure check warning ==> 🤖 Generated with [Claude +AI assistance is not disclosed with Assisted-by or Generated-by — detected: Claude Code +Suggest: Disclose the tool with "Assisted-by: Claude Code" +Docs: https://commit-check.com/rules/#cc014 +This rule is set to warn in the config; it does not fail the run. +``` + +The run still passes. See +[Report a rule without enforcing it](../configuration.md#report-a-rule-without-enforcing-it). + ### Exempting automation Bots that legitimately carry AI trailers can be excluded: diff --git a/docs/guides/pre-commit.md b/docs/guides/pre-commit.md index 6cd9e30..3331593 100644 --- a/docs/guides/pre-commit.md +++ b/docs/guides/pre-commit.md @@ -8,7 +8,7 @@ Add Commit Check to `.pre-commit-config.yaml`: ```yaml title=".pre-commit-config.yaml" repos: - repo: https://github.com/commit-check/commit-check - rev: v2.17.0 + rev: v2.18.0 hooks: - id: check-message - id: check-branch @@ -55,7 +55,7 @@ Options can be passed as hook arguments, which keeps everything in one file: ```yaml title=".pre-commit-config.yaml" repos: - repo: https://github.com/commit-check/commit-check - rev: v2.17.0 + rev: v2.18.0 hooks: - id: check-message args: diff --git a/docs/rules.md b/docs/rules.md index d3a2a23..49511b5 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -91,6 +91,9 @@ Run with `-m` / `--message`. | [CC011](#cc011) | `require-body` | Commit body is required | `-m` | ⚪ Off | | [CC012](#cc012) | `require-signed-off-by` | Signed-off-by not found in latest commit | `-m` | ⚪ Off | | [CC013](#cc013) | `ai-attribution` | AI attribution policy violation | `-m` | ⚪ Off | +| [CC014](#cc014) | `ai-disclosure` | AI assistance is not disclosed with an accepted trailer | `-m` | ⚪ Off | +| [CC015](#cc015) | `ai-co-author` | An AI tool is credited as a co-author | `-m` | ⚪ Off | +| [CC016](#cc016) | `ai-signoff` | An AI tool signed off the commit | `-m` | ⚪ Off | @@ -532,25 +535,136 @@ git commit --amend --signoff **What it does** -Rejects commits carrying the signatures that AI coding tools add to commit -messages — trailers naming Claude Code, Copilot, Codex, Gemini, Cursor, Devin, -Aider, Windsurf, Tabby, and generic AI model patterns. +Rejects a commit whose message carries any AI attribution: a co-author or +sign-off line naming Claude Code, Copilot, Codex, Gemini, Cursor, Devin, +Aider, Windsurf or Tabby, a disclosure trailer such as `Assisted-by:` or +`Generated-by:`, a vendor's own mark such as `🤖 Generated with Claude Code`, +and generic AI model names. **Why is this bad?** -Whether AI-assisted commits are acceptable is a policy question, and projects -have landed on different answers: the Linux kernel added an `Assisted-by:` -trailer, while others disallow the practice outright. This rule exists for -projects that have made that decision and want it enforced mechanically rather -than relitigated in every code review. +Some projects want their history to carry no AI attribution at all — the +[Kubernetes contributor guide](https://www.kubernetes.dev/docs/guide/pull-requests/) +takes that position, asking for disclosure in the pull request instead. This +rule exists for projects that have made that decision and want it enforced +mechanically rather than relitigated in every review. -It is off by default, and the default policy is `"ignore"`. Enable it only if -your project has a stated position. +**Example** + +```text +CC013 ai-attribution check failed ==> Claude Code +AI attribution is forbidden in this project — detected: Claude Code +Suggest: This project does not accept AI attribution in commit messages. Remove the AI trailer lines and re-commit. +``` + +**Options** + +* `commit.ai_attribution` — `"forbid"` enables this rule. `"ignore"` (the + default) disables it; `"disclose"` replaces it with + [CC014](#cc014)–[CC016](#cc016). + +### ai-disclosure (CC014) { #cc014 } + +**What it does** + +Under `ai_attribution = "disclose"`, requires that a commit showing signs of +AI assistance discloses it with one of the project's trailers — by default +`Assisted-by:` or `Generated-by:`. A vendor's co-author line, an AI sign-off, +a `🤖 Generated with` mark, or a disclosure written with some other trailer +all count as signs; none of them counts as the disclosure. + +A trailer that is there but says nothing — no value, or a value that does not +match `ai_disclosure_pattern` — fails too. + +**Why is this bad?** + +A project that allows AI assistance and asks for it to be disclosed has an +honour-system rule until something checks it. The +[Linux kernel](https://docs.kernel.org/process/coding-assistants.html), +[Fedora](https://docs.fedoraproject.org/en-US/council/policy/ai-policy/) and +FluxCD ask for `Assisted-by:`; the +[Apache Software Foundation](https://www.apache.org/legal/generative-tooling.html) +recommends `Generated-by:`. The tools, meanwhile, stamp their own format on +the way out, so a contributor following the policy and one ignoring it produce +commits that look much the same. + +**Example** + +```text +CC014 ai-disclosure check failed ==> Co-Authored-By: Claude Opus 5 +AI assistance is not disclosed with Assisted-by or Generated-by — detected: Claude Code +Suggest: Disclose the tool with "Assisted-by: Claude Opus 5" +``` + +The suggestion keeps the name the tool gave itself, and `--format json` +carries the whole corrected message in `fix`. + +**Options** + +* `commit.ai_attribution` — set to `"disclose"` to enable this rule. +* `commit.ai_disclosure_trailers` — the trailers that count as a disclosure. + The first one is what a correction is written with. +* `commit.ai_disclosure_pattern` — a regex the disclosure's value must match, + for a project that wants a particular format. + +### ai-co-author (CC015) { #cc015 } + +**What it does** + +Under `ai_attribution = "disclose"`, rejects a commit that credits an AI tool +as a person: a `Co-authored-by:` or `Co-developed-by:` trailer naming a +recognised tool. + +**Why is this bad?** + +A co-author line is a claim about who wrote the change, and it travels: GitHub +counts co-authors as contributors, and a squash merge carries the line into +the default branch. Projects that welcome AI assistance still commonly draw +the line here — [pip](https://github.com/pypa/pip/blob/main/AI_POLICY.md), +`attrs` and Requests all say no AI in `Co-authored-by:` — because disclosure +and authorship are different claims. + +**Example** + +```text +CC015 ai-co-author check failed ==> Co-Authored-By: Claude Opus 5 +An AI tool is credited as a co-author: Claude Code +Suggest: Use "Assisted-by: Claude Opus 5" in place of the co-author line +``` + +**Options** + +* `commit.ai_attribution` — set to `"disclose"` to enable this rule. +* `commit.ai_disclosure_trailers` — listing `Co-authored-by` here says the + project accepts the tool as a co-author, and this rule then passes. + +### ai-signoff (CC016) { #cc016 } + +**What it does** + +Under `ai_attribution = "disclose"`, rejects a commit whose `Signed-off-by:` +trailer names an AI tool. + +**Why is this bad?** + +A sign-off is a legal certification — the +[Developer Certificate of Origin](https://developercertificate.org/) — and +only a person can make it. The Linux kernel's guidance says so outright: AI +agents must not add `Signed-off-by` tags, because they cannot certify the +DCO. No trailer list may name `Signed-off-by`, so this rule cannot be turned +off by accepting it as a disclosure. + +**Example** + +```text +CC016 ai-signoff check failed ==> Signed-off-by: Claude +An AI tool signed off the commit: Claude Code +Suggest: Remove the AI sign-off, then sign off yourself (git commit --signoff) +``` **Options** -* `commit.ai_attribution` — `"forbid"` enables this rule, `"ignore"` - (the default) disables it. +* `commit.ai_attribution` — set to `"disclose"` to enable this rule. ## Author rules diff --git a/docs/troubleshoot.md b/docs/troubleshoot.md index dd90640..32c2aab 100644 --- a/docs/troubleshoot.md +++ b/docs/troubleshoot.md @@ -98,6 +98,30 @@ commit-check --message --branch --author-name --author-email Each rule in the [rules reference](rules.md) lists the flag that activates it. +## The run failed, but nothing was checked { #exit-codes } + +A wrapper that treats every non-zero exit as a rejected commit cannot tell a +broken policy from a bad commit. Commit Check keeps them apart: + +| Exit code | Meaning | +|---|---| +| `0` | Every enforced check passed, or every check was skipped. | +| `1` | A check failed. This is a verdict on the commit. | +| `2` | The run could not start, so nothing was validated: bad usage, a `--rev` that does not resolve, a setting whose regex does not compile, or a config file that is missing, is not valid TOML, or names an unknown rule. | + +A configuration error names the file it came from: + +```text +Error: .github/cchk.toml: Expected ']' at the end of a table declaration (at line 1, column 8) +``` + +A setting that can also come from a flag or a `CCHK_*` variable names itself +instead, and echoes the value it could not use: + +```text +Error: [commit] message_pattern is not a valid regex: '^(unclosed' (missing ), unterminated subpattern at position 1) +``` + ## Something else If the failure does not match anything above, the JSON output shows exactly