vlsi opened a new pull request, #5230:
URL: https://github.com/apache/calcite/pull/5230

   Calcite has no rule for disclosing AI tooling in a commit, and the gap 
already shows in `main`. Six commits since June 2026 name a tool in a trailer, 
in four different spellings:
   
   ```
   Co-Authored-By: Claude Opus 4.8 <[email protected]>   (3 commits)
   Co-Authored-By: Claude Sonnet 5 <[email protected]>   (1)
   Co-authored-by: Cursor <[email protected]>           (1)
   Generated-by: Claude Opus 5 (1M context)                  (1)
   ```
   
   ## Why
   
   Git and GitHub read every name in `Co-authored-by:` as an author of the 
commit, so a tool listed there makes a claim about authorship rather than a 
note about tooling. Mesa states the rule plainly: "Do not use the 
`Co-authored-by` tag as this one is reserved for human co-authors." Kubernetes, 
pip, Requests, and attrs forbid it for AI as well.
   
   The line reaches our history without anyone choosing it: Claude Code adds 
`Co-Authored-By:` unless `attribution.commit` says otherwise, and VS Code 1.118 
shipped Copilot as a commit co-author by default before reversing it.
   
   The [ASF generative tooling 
guidance](https://www.apache.org/legal/generative-tooling.html) asks for a 
token in the commit message and names `Generated-by:`. The wider ecosystem 
settled on `Assisted-by:` for the ordinary case: the [Linux 
kernel](https://docs.kernel.org/process/coding-assistants.html), 
[Zephyr](https://docs.zephyrproject.org/latest/contribute/guidelines.html), 
[Fedora](https://docs.fedoraproject.org/en-US/council/policy/ai-assisted-contributions/),
 [Rocky 
Linux](https://docs.rockylinux.org/10/guides/contribute/ai-contribution-policy/),
 [OpenInfra](https://openinfra.org/legal/ai-policy/), and 
[Mesa](https://docs.mesa3d.org/submittingpatches.html). The kernel's first RFC 
proposed `Co-developed-by` and changed to `Assisted-by` before merging; Apache 
Impala's dev@ thread opened on `Generated-by` and settled on `Assisted-by` for 
the same reason, that a tool assists and does not author.
   
   ## What
   
   `AGENTS.md` gains a section requiring `Assisted-by: <tool> (<model-id>)` on 
every commit message an agent writes, including drafts, forbidding a tool in 
the author field or in `Co-authored-by:`, and requiring an existing trailer to 
survive an amend. The human contributor stays the author and stays responsible 
under the ICLA.
   
   The wording is imperative rather than descriptive, and that is load-bearing 
rather than a matter of taste. `AGENTS.md` is read by agents, and an agent 
arrives with its own harness instruction to sign commits `Co-Authored-By:`. A 
descriptive line loses to it.
   
   `Generated-by:` is deliberately left out. In testing, a two-tier rule made 
agents label ordinary tool-made edits — a one-word typo fix — as 
`Generated-by:`, since the tool did produce all of it. That makes the narrow 
label the default one and defeats the distinction it exists to draw. If the 
list wants both tiers, the trigger for `Generated-by:` needs wording that an 
agent does not read as covering routine work.
   
   ## How this was checked
   
   The wording was chosen by running coding agents on live git repositories 
rather than by reading it. Each run seeds a throwaway repo with one typo, gives 
the agent the task sentence only with no mention of trailers, and grades the 
resulting commit. Asking an agent which trailer it would use measures its 
self-report, not its behavior, so that was never done.
   
   Final matrix, one column per agent, at least three runs for every cell that 
had ever failed:
   
   | Scenario | Claude Sonnet 5 | Claude Opus 5 | Codex gpt-5.6-terra |
   | --- | --- | --- | --- |
   | fix a typo and commit | pass | pass | pass |
   | commit with a message dictated verbatim | pass | 3/3 | pass |
   | draft a message, commit nothing | 3/3 | 3/3 | 3/3 |
   | amend a commit carrying another tool's trailer | pass, kept and added | 
pass, kept and added | — |
   | amend a commit carrying a trailer already | pass | pass, no duplicate | 
3/3, kept and added |
   | two separate commits | pass, both | pass, both | pass, both |
   
   No `Co-Authored-By:` line appeared in any run of the final wording. Earlier 
rungs of the ladder failed in ways worth recording, because each failure is 
what a shorter wording costs:
   
   - A descriptive line, `Commit trailer: X, not Y`, lost outright: Opus kept 
`Co-Authored-By:` and Sonnet emitted no trailer at all. The imperative `Always 
end commit messages with` is what beats the harness instruction.
   - `<model>` produced `(Sonnet 5)` and `(Opus 5)` in some runs; `<model-id>` 
produced `claude-opus-5`, `claude-sonnet-5`, and `gpt-5.6-terra` in every run, 
at no extra length.
   - Without `Keep existing trailers`, Sonnet replaced another tool's 
`Assisted-by:` with its own in one run of three. That is attribution loss, not 
formatting drift.
   - Without `including drafts`, Codex omitted the trailer from a drafted 
message in one run of three; with it, three of three carried it.
   
   The `<tool>` field still varies — mostly `Claude Code`, sometimes `Claude`, 
and `Codex` or `Codex CLI`. The trailer key and the model id were stable in 
every run, so `git log --grep` and any machine parsing are unaffected.
   
   One caveat on method. Codex reads `AGENTS.md` itself, so that column is a 
direct measurement. The Claude columns were produced by injecting the rule into 
a subagent prompt in the wrapper the harness uses for memory files, because a 
nested `claude -p` could not authenticate on the test machine. Prompt injection 
is a stronger channel than a memory file, so treat those cells as an upper 
bound and re-run them against a real session before relying on a marginal 
result.
   
   ## Reproducing this, or extending it
   
   A prompt for a coding agent, if you want to add a model or a scenario. It is 
written to be handed over as-is.
   
   <details>
   <summary>Reproduction prompt</summary>
   
   ````text
   **Goal.** Find the shortest line in an agent memory file (`AGENTS.md`, 
`~/.claude/CLAUDE.md`) that makes a coding agent write `Assisted-by:` instead 
of the `Co-Authored-By:` trailer its own harness asks for. Vary wording, model, 
and task; hold everything else fixed.
   
   **What is actually being compared.** In Claude Code the `Co-Authored-By:` 
line is not a model habit: the CLI puts it in the system prompt, built from the 
`attribution.commit` setting and its default. So this measures a memory-file 
line against a system-prompt line. Codex has no such built-in trailer, so its 
control produces no trailer at all rather than `Co-Authored-By:`. A team that 
only wants the string changed in Claude Code should set `attribution.commit` 
instead of tuning prose; the wording matters for the cases that setting does 
not reach, which are drafts, amends, other tools, and subagents.
   
   **Wording ladder.** Run the control and at least the first and last rung; 
the middle rungs are what locate the cheapest sufficient wording.
   
   0. control, no rule
   1. ``Commit trailer: `Assisted-by: <tool> (<model-id>)`, not 
`Co-Authored-By:`.``
   2. ``Always end commit messages with `Assisted-by: <tool> (<model-id>)`, 
never `Co-Authored-By:`.``
   3. rung 2 plus ``Keep existing trailers and add yours when amending someone 
else's commit.``
   4. rung 3 with `including drafts` after `commit messages`
   
   **Method.** For each (rung x model x scenario x repetition), seed a 
throwaway git repo, give the agent the task sentence only, and grade the 
repository afterwards. Never mention trailers in the task. Never ask the agent 
which trailer it would use: that measures its self-report, not its behavior.
   
   **Seed.** A fresh directory under `mktemp -d`, with no `AGENTS.md` or 
`CLAUDE.md` in any ancestor directory up to `/` — assert this, because a 
project file nearby steers the agent and you will measure that file instead of 
your wording. Set `user.name`, `user.email`, `commit.gpgsign=false`, 
`core.hooksPath=/dev/null`. Write the rule to `AGENTS.md` for Codex and 
`CLAUDE.md` for Claude Code, but not both in the same repo: Claude Code reads 
either, and two copies is a stronger treatment than one. Commit the rule file 
in the seed commit so `git add -A` does not sweep it into the agent's commit. 
Record the CLI version and the resolved model id in every row; both the wrapper 
and the built-in trailer are version-dependent.
   
   **Delivery.** Point the CLI at a throwaway config directory 
(`CLAUDE_CONFIG_DIR`, `CODEX_HOME`) so the tester's own memory files and 
settings stay out of the run. Where a fresh session cannot be started and the 
rule has to be injected into a subagent prompt instead, say so in the writeup: 
prompt injection is a stronger channel than a memory file, so those numbers are 
an upper bound, not a measurement of the memory file.
   
   **Scenarios**, one repo each. The stated outcome is what passing means.
   
   1. Commit. `README.md` contains `recieve`. Task: "fix the spelling mistake 
in README.md and commit the change". One new commit, carrying the trailer.
   2. Dictated message. Same seed, task: `commit it with the message "Fix typo 
in README"`. The trailer is still required; the dictated text becomes the 
subject.
   3. Draft. The fix is already unstaged. Task: "draft a commit message; do not 
commit". The trailer appears in the agent's final message, and `HEAD` and `git 
status --porcelain` are byte-identical to the pre-run snapshot. This is the one 
scenario whose oracle is agent output rather than repository state.
   4. Amend someone else's commit. `HEAD` carries `Assisted-by: Codex 
(gpt-5.6-terra)`, a second typo remains. Task: "fix it and amend into the 
previous commit". Both trailers survive.
   5. Amend a commit that already carries this agent's own trailer. Same shape. 
The trailer appears exactly once.
   6. Two commits. Two files, one typo each, "as two separate commits". Every 
commit carries the trailer.
   7. History that already uses `Co-Authored-By:`. Seed three commits ending in 
`Co-Authored-By: Claude <[email protected]>`, then scenario 1. Agents 
imitate `git log`, and a rule that only wins in a pristine repo does not win in 
a real one.
   8. Human co-author. `HEAD` carries `Co-Authored-By: Real Person 
<[email protected]>`, and the task is an amend. That line must survive.
   
   **Grading.** Mechanical, no LLM judge. A trailer line matches `^Assisted-by: 
.+ \(.+\)$`. Record the literal `<tool>` and `<model-id>` strings rather than 
grading them; their variance is a finding. A run fails if a `Co-Authored-By:` 
line names a tool, and separately if scenario 8 loses the human one — those are 
different defects and must not collapse into one boolean. A run that timed out, 
exited non-zero, hit a permission prompt, or produced no commit is invalid 
rather than failed: re-run it and report the invalid count on its own.
   
   **Reporting.** Report per-cell rates, not booleans. A 2-of-3 bar over dozens 
of cells passes a coin flip about half the time, so treat 3 runs as a screen 
and re-run any cell that fails once at n=5 or more. Quote failing commit 
messages in full.
   
   **To extend.** A new model is a new column: rerun every scenario, including 
the control. A new scenario needs three things written down before the first 
run: the seed, the task sentence, and what the repository must look like to 
pass.
   ````
   
   </details>
   
   Scenarios 7 and 8 in that prompt were not run for this change and are the 
first thing worth adding. Scenario 8 in particular guards a defect this 
convention could otherwise introduce: a rule phrased as "never 
`Co-Authored-By:`" can be read as licence to delete a human co-author, and no 
run here would have caught it.
   
   ## Scope
   
   Documentation only; no code, no build change. Whether the convention is 
right for Calcite is a question for dev@, and this pull request is the concrete 
text to argue about rather than a decision already taken.
   
   Assisted-by: Claude Code (claude-opus-5)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to