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

   JMeter has no rule for disclosing AI tooling in a commit, and the gap shows 
in `master`. Sixteen commits since March 2026 name a tool in a trailer, in two 
capitalizations of the key and four spellings of the model:
   
   ```
   Co-Authored-By: Claude Opus 4.8 <[email protected]>                (8 
commits)
   Co-authored-by: Claude Opus 4.8 <[email protected]>                (3)
   Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>   (2)
   Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>   (2)
   Generated-by: Claude Opus 4.8                                          (1)
   ```
   
   ## Why
   
   Fifteen of those use `Co-authored-by:`, and in this same history that 
trailer also carries nine human names. One field is doing two different jobs, 
and nothing in the message distinguishes them: git and GitHub read every name 
there as an author of the commit, so a tool listed there makes a claim about 
authorship rather than a note about tooling.
   
   The line arrives 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. That is 
also why the spelling drifts: the model name comes from whichever build wrote 
the commit.
   
   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). 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 
kernel's first RFC proposed `Co-developed-by` and changed to `Assisted-by` 
before merging.
   
   ## What
   
   `AGENTS.md` gains a `## Commit messages` section holding one sentence:
   
   > Always end commit messages, including drafts, with `Assisted-by: <tool> 
(<model-id>)`, never `Co-Authored-By:`. Keep existing trailers and add yours 
when amending someone else's commit.
   
   The heading is deliberately broader than the rule: further commit message 
conventions belong under it rather than in a section of their own.
   
   That is the whole change, and the brevity is deliberate. Every sentence in 
this file is read by an agent and changes what it writes, so the file carries 
the wording the matrix below actually tested and nothing else. Drafts of this 
change that surrounded the rule with rationale measurably changed agent output: 
a paragraph offering `Generated-by:` as a second tier moved agents onto 
`Generated-by:` for a one-word typo fix. The reasoning therefore lives in this 
pull request, where it informs reviewers without steering tools.
   
   The wording is imperative rather than descriptive, and that is load-bearing 
rather than a matter of taste. An agent arrives with its own harness 
instruction to sign commits `Co-Authored-By:`, and a descriptive line loses to 
it.
   
   The human contributor remains the author and remains responsible for the 
change under the ICLA. That is why the rule forbids `Co-Authored-By:` for a 
tool rather than merely preferring `Assisted-by:`, and it needs no restating in 
`AGENTS.md`, since the trailer the file mandates already carries it.
   
   `Generated-by:` is deliberately left out, beyond the steering problem above: 
making the narrow label reachable for routine work defeats the distinction it 
exists to draw. A second tier is worth having, but its trigger needs wording an 
agent does not read as covering ordinary edits, and that wording needs its own 
run through the matrix. That is a follow-up, not a blocker for this one.
   
   ## 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. That is the axis this repository's history drifts on today.
   - 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 7 matters here in particular: this 
repository's history already carries fifteen `Co-Authored-By:` tool lines for 
an agent to imitate, and the matrix above was measured on pristine repositories.
   
   ## Scope
   
   Documentation only; no code, no build change.
   
   This brings JMeter in line with guidance that already exists rather than 
inventing a policy for it. The ASF asks contributors to name the tooling in the 
commit message; the choice of `Assisted-by:` over `Co-authored-by:` is where 
the projects listed above have landed, and the ASF page predates agentic 
tooling and names only `Generated-by:`. What is left for JMeter to decide is 
the exact wording, which is what this diff is.
   
   The same change is open for Calcite as 
[apache/calcite#5230](https://github.com/apache/calcite/pull/5230), with the 
same sentence.
   
   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