From 020c6714e70845feb9988568603265816439a334 Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Sun, 13 Sep 2026 00:29:33 +0300 Subject: [PATCH] docs: the disclose policy, and what else 2.18.0 changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three rules landed upstream with nowhere to point: the tool prints Docs: https://commit-check.com/rules/#cc014 and the anchor did not exist. - rules.md gains ai-disclosure (CC014), ai-co-author (CC015) and ai-signoff (CC016), each with the policy that asks for it — the kernel, Fedora and FluxCD for Assisted-by, the ASF for Generated-by, pip and Requests for no AI co-author, the DCO for the sign-off. CC013 is rewritten: it now catches the disclosure trailers too, and its error text changed. - The policy guide gains "Asking for disclosure instead": the three conditions, the correction a failure carries, choosing the trailers and the value format, and warn = ["ai_disclosure"] for projects that appreciate disclosure without demanding it. Its forbid sample was a stale transcript and is re-run. - configuration.md documents ai_disclosure_trailers and ai_disclosure_pattern in all three forms. - troubleshoot.md gains an exit-codes section. Exit code 2 ships in this release and the site had nowhere that said what it means. - The changelog covers the whole release, not just the AI work: the measurements in a failure, hyperlinked spec names, anchored branch names, the narrowed CC001 exemption, exit code 2, and inherit_from failures on stderr. Every transcript on these pages was produced by running the command against the merged code. The install pins say v2.18.0, which is not published yet, so test_pinned_revisions_match_the_released_version is red until it is. --- docs/changelog.md | 72 ++++++++++++++++++ docs/configuration.md | 10 ++- docs/example.md | 2 +- docs/guides/policies.md | 154 +++++++++++++++++++++++++++++++++----- docs/guides/pre-commit.md | 4 +- docs/rules.md | 138 +++++++++++++++++++++++++++++++--- docs/troubleshoot.md | 24 ++++++ 7 files changed, 369 insertions(+), 35 deletions(-) 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