Skip to content

docs: restructure contribution guidelines around authorship vs composition#217

Draft
d-v-b wants to merge 28 commits into
mainfrom
update-ai-policy
Draft

docs: restructure contribution guidelines around authorship vs composition#217
d-v-b wants to merge 28 commits into
mainfrom
update-ai-policy

Conversation

@d-v-b

@d-v-b d-v-b commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Preface

I drafted some changes to our contribution policy with the goal of producing something that would cover AI contributions as a logical consequence of some more basic rules about humans and tools. Then I had claude expand on that draft, after doing a survey of the contribution policies of a lot of different open source projects. My personal goals are:

  • ensuring that we can safely use powerful tools like AI
  • ensuring that good actors can easily follow project rules
  • ensuring that reviewer / contributor time is well spent.

I think the end result is pretty good. Our new guidelines distinguish accountability from authorship: only a human can be accountable, but tools can be authors. The guidelines clarify that machine-written text is unwelcome in review comments, but generally acceptable when clearly annotated as machine-written text, and when the accountable human has demonstrated ownership over it.

Summary

🤖 AI-generated text below, from Claude Code (claude-opus-4.8). Not yet reviewed by a human. 🤖

This follows from the discussion on zarr-developers#4132, where @maxrjones objected that the PR description was not human-written and that the change was out of scope, and where we converged on a narrower rule than the one the contributing guide then carried. Rather than patch that rule, this reorganizes the guidelines around the distinction the discussion surfaced.

The framework. Two different things are true of any contribution: someone is accountable for it, and someone composed it. Accountability can never be delegated to a tool. Composition can, if disclosed. Every rule now follows from that split, which is why the separate ## AI-assisted contributions section is gone — its rules are consequences of the general guidelines, which apply equally to contributors, core developers, and agents. There is no core-developer carve-out.

What changes in substance. The guide previously said "do not paste AI-generated text as comments or review responses." Labeled machine-composed text is now permitted, subject to three limits:

  • A pull request opens with a sentence the author wrote. This is @maxrjones' minimum bar, and the part a tool cannot produce without the human having thought about the change.
  • Review responses must be in the author's own words. A reviewer asking a question is asking you.
  • Endorsing machine-composed text means having trimmed it, not merely read it. Reading padding does not spare the reviewer from it.

The guide also explains why Dependabot is exempt from the human-sentence rule and an agent is not: a bot's identity fully supplies its motivation, an agent's does not.

What else it adds. A Write commit messages for the reader section, which is what @maxrjones said he cared most about and which the guide did not mention at all; the Assisted-by: trailer, noting that it certifies nothing here since this project has no DCO; and a statement that an agent should not open a pull request nobody asked for.

Relationship to zarr-developers#4041

This branch merges @maxrjones' docs/agents (zarr-developers#4041) wholesale, preserving his eight commits and authorship. Either zarr-developers#4041 lands first and this rebases, or this supersedes it — needs a decision, and it is why the PR is a draft.

Merging the two exposed a contradiction. His AGENTS.md opened by pointing at "docs/contributing.md, especially the AI-assisted contributions section" — the section this PR deletes — and restated the rule this PR changes ("PR descriptions / review responses must be in the human's own words"). Landed independently, the repo would have shipped an agent-facing file citing a nonexistent section and asserting the opposite of the policy. That paragraph now points at ## Contribution guidelines and carries only the short imperative rules that bind an agent directly. The rest of his file — pure mechanics — is untouched, which is the shape the evidence supports.

Where this sits relative to other projects

I surveyed ~25 projects' AI policies, verifying every quote against a primary source. Full write-up: https://gist.github.com/d-v-b/d56c653d52b5acca7ebc37ba0534ded6

Our position on machine-composed PR prose is a minority one, deliberately. NumPy, SciPy, scikit-learn, and xarray all ban it outright; xarray's wording is what our old text was adapted from. CPython requires no disclosure at all, and Fedora actively encourages AI prose for contributors writing in a second language. Expect this line to be argued about. The strongest defense of it is that a ban on machine-composed prose is really a proxy for effort — it catches the contributor who pasted an unread summary — and that a label recording whether a human read and cut the text measures that directly, instead of by inference. The honest cost: a ban binds bad-faith contributors and an attestation does not. That trade is worth making for a project whose contributors are few and repeat, and would not be for one drowning in anonymous drive-bys.

Three findings shaped the draft:

  • The label records whether a human read the text, not just which tool composed it — two variants, after apache/airflow's AGENTS.md (Drafted-by: … (no human review before posting) vs … reviewed by @handle before posting). Provenance alone tells a reviewer little; review state tells them where to look.
  • Endorsing text means editing it, after ghostty's AI_POLICY.md"reviewed and edited by a human… AI is very good at being overly verbose and including noise that distracts from the main point." Ghostty also supplies the framing now opening Attribute your sources: posting unread text at the boundary where a person meets your work shifts the burden of validating it onto them, which is a discourtesy rather than a procedural violation. Not adopted from Ghostty: its maintainer exemption (contrary to what this branch exists to settle) and its public denouncement list (calibrated for a flood of drive-bys we do not have).
  • The Assisted-by: trailer follows the Linux kernel, which mandates it and forbids AI Signed-off-by. Kubernetes bans that exact trailer, because AI cannot sign a CLA. Both reason from a signing instrument; zarr-python has neither a DCO nor a CLA, so ours is attribution and nothing more. The guide says so.

Policy prose belongs in contributing.md, not AGENTS.md. arXiv:2601.20404 (ICSE'26) found agents obey direct mechanical instructions but are unreliable on judgment calls, and that LLM-generated context files made outcomes worse; SciPy's maintainers reached the same conclusion and kept theirs to non-inferable mechanics. So AGENTS.md points at the contributing guide as authoritative and adds only short imperatives, as Airflow and pandas do. The real enforcement is the PR template checkbox.

Verification

  • tests/test_docs.py — 57 passed, 2 skipped (the usual cupy/GPU and nonexistent-module skips)
  • mkdocs build --strict — clean
  • prek — clean (codespell, trailing-whitespace, mypy, sp-repo-review)
  • Rendered site inspected: both label variants render inside code blocks, no dangling in-page anchors, and the PR template's #contribution-guidelines target resolves

Along the way this picked up zarr-developers#4132's own corrections to contributing.md (site/ build dir, serve URL, zarr.__version__ is an attribute not a property), which the branch predated and would otherwise have reverted.

Open questions

  • docs: add AGENTS.md for AI-assisted development zarr-developers/zarr-python#4041: supersede, or rebase after it lands?
  • Disclosure: the guide requires labeling (mark the block, name the tool, say if you read it) but not a blanket "did you use AI at all" declaration. NumPy rejects PRs lacking one; Ghostty requires one; Astropy deliberately requires none. This sits with Astropy, now stated on purpose rather than by omission. Reasonable to reverse.
  • changes/4140.doc.md is named for a guessed PR number. Rename if this lands as something else.

TODO

  • Add unit tests and/or doctests in docstrings — n/a, docs only
  • Add docstrings and API docs for any new/modified user-facing classes and functions — n/a
  • New/modified features documented in docs/user-guide/*.md — n/a
  • Changes documented as a new file in changes/
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

dependabot Bot and others added 28 commits May 31, 2026 19:28
…#176)

Bumps the actions group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [prefix-dev/setup-pixi](https://github.com/prefix-dev/setup-pixi) | `0.9.5` | `0.9.6` |
| [codecov/codecov-action](https://github.com/codecov/codecov-action) | `6.0.0` | `6.0.1` |
| [github/issue-metrics](https://github.com/github/issue-metrics) | `4.2.2` | `4.2.7` |
| [j178/prek-action](https://github.com/j178/prek-action) | `2.0.3` | `2.0.4` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `7.0.0` | `7.0.1` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `7.0.0` | `8.0.1` |
| [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) | `1.13.0` | `1.14.0` |
| [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) | `0.5.3` | `0.5.6` |



Updates `prefix-dev/setup-pixi` from 0.9.5 to 0.9.6
- [Release notes](https://github.com/prefix-dev/setup-pixi/releases)
- [Commits](prefix-dev/setup-pixi@1b2de7f...5185adf)

Updates `codecov/codecov-action` from 6.0.0 to 6.0.1
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](codecov/codecov-action@57e3a13...e79a696)

Updates `github/issue-metrics` from 4.2.2 to 4.2.7
- [Release notes](https://github.com/github/issue-metrics/releases)
- [Commits](github-community-projects/issue-metrics@c9e9838...1e38d5e)

Updates `j178/prek-action` from 2.0.3 to 2.0.4
- [Release notes](https://github.com/j178/prek-action/releases)
- [Commits](j178/prek-action@6ad8027...bdca6f1)

Updates `actions/upload-artifact` from 7.0.0 to 7.0.1
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v7...043fb46)

Updates `actions/download-artifact` from 7.0.0 to 8.0.1
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](actions/download-artifact@v7...3e5f45b)

Updates `pypa/gh-action-pypi-publish` from 1.13.0 to 1.14.0
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](pypa/gh-action-pypi-publish@v1.13.0...cef2210)

Updates `zizmorcore/zizmor-action` from 0.5.3 to 0.5.6
- [Release notes](https://github.com/zizmorcore/zizmor-action/releases)
- [Commits](zizmorcore/zizmor-action@b1d7e1f...5f14fd0)

---
updated-dependencies:
- dependency-name: prefix-dev/setup-pixi
  dependency-version: 0.9.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: codecov/codecov-action
  dependency-version: 6.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: github/issue-metrics
  dependency-version: 4.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: j178/prek-action
  dependency-version: 2.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: actions/download-artifact
  dependency-version: 8.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: pypa/gh-action-pypi-publish
  dependency-version: 1.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: zizmorcore/zizmor-action
  dependency-version: 0.5.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
…ition

Separate accountability (never delegable to a tool) from composition
(delegable, if disclosed), and derive the AI policy from that split
rather than maintaining a parallel AI-specific section.

Machine-composed text is now permitted where labeled, provided a
pull request opens with a sentence the author wrote themselves.
Review responses must still be in the author's own words.

Assisted-by: ClaudeCode:claude-opus-4.8
Correct the squash-merge description: a single-commit PR takes its
subject from the commit, not the PR title.

Assisted-by: ClaudeCode:claude-opus-4.8
Max's AGENTS.md referenced the "AI-assisted contributions" section
that this branch removes, and restated the old rule requiring PR
descriptions to be in the human's own words. Point it at the
Contribution guidelines section instead, and give agents the short
imperative rules that bind them directly, rather than duplicating
policy prose that agents follow unreliably.

Also, from a survey of comparable projects:

- Labels now record whether a human read the text before it was
  posted, not just which tool composed it (after apache/airflow).
  Provenance alone doesn't tell a reviewer what they need to know.
- State that an agent should not open a PR nobody asked for.
- Say that labeling, not blanket disclosure, is the obligation.
- Document the `Assisted-by:` trailer (after the Linux kernel), and
  note it certifies nothing here since we have no DCO.

Assisted-by: ClaudeCode:claude-opus-4.8
Two borrowings from ghostty's AI_POLICY.md, which frames this better
than anyone else surveyed.

Its rule is "reviewed _and edited_ by a human", with the reason that
"AI is very good at being overly verbose and including noise that
distracts from the main point." Our label asked only whether a human
had read the text. Reading it does not spare the reviewer the padding;
cutting it does. Endorsing machine-composed text now means having
trimmed it, and AGENTS.md tells agents to write less.

Also open the section by naming the harm the way ghostty does: posting
unread text at the boundary where a person meets your work shifts the
burden of validating it onto them. That is a discourtesy, not a
procedural violation, and saying so is more persuasive than a rule.

Deliberately not adopted: ghostty's maintainer exemption (contrary to
what this branch exists to settle) and its public denouncement list
(calibrated for a flood of anonymous drive-bys we do not have).

Assisted-by: ClaudeCode:claude-opus-4.8
The rule said a pull request opens with a sentence the author wrote,
but never said an agent must not supply one. An agent drafting a
sentence for its operator to paste satisfies the letter and defeats
the purpose: the sentence is evidence that a human thought about the
change, and evidence you were handed is not evidence.

State it in contributing.md, which is authoritative, and restate it as
an imperative in AGENTS.md and in the template's Summary prompt. Keep
the phrasing tool-neutral -- the rule binds any agent, not one vendor.

Assisted-by: ClaudeCode:claude-opus-4.8
@d-v-b

d-v-b commented Jul 10, 2026

Copy link
Copy Markdown
Owner Author

@maxrjones i'd appreciate your eyes when you have time. this PR brings in your commits that add AGENTS.md etc and apply changes to our contribution policy on top of them. If you are OK with that process (a thumbs-up indication is enough), then I will move this as a PR against zarr-python itself, and we can hash out content-based discussions there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants