From af87fdc7128a175a4ae1520392eff48e98b338ec Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 14 Aug 2026 15:04:41 +1000 Subject: [PATCH 1/8] QEP-5: Code of AI Use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds QEP-5 as a Draft: a Code of AI Use for QuantEcon contributions — AI assistance welcome, a human submits and owns the work, and meaningful AI involvement is disclosed with a machine-readable marker rather than a narrative. Policy only, by design. The contributor registry and pull-request gate explored in the discussion (QuantEcon/qeps#12) are deliberately out of scope: the norms bind whether or not anyone attests to them, and volume is handled by GitHub's native controls. If a registry proves necessary it is a later amendment or a QEP of its own. Co-Authored-By: Claude Opus 5 (1M context) --- qeps/qep-0005-code-of-ai-use.md | 212 ++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 qeps/qep-0005-code-of-ai-use.md diff --git a/qeps/qep-0005-code-of-ai-use.md b/qeps/qep-0005-code-of-ai-use.md new file mode 100644 index 0000000..6e7e4aa --- /dev/null +++ b/qeps/qep-0005-code-of-ai-use.md @@ -0,0 +1,212 @@ +--- +qep: 5 +title: Code of AI Use +author: "@mmcky" +status: Draft +type: standard +created: 2026-08-14 +discussion: https://github.com/QuantEcon/qeps/issues/12 +--- + +# QEP-5: Code of AI Use + +| | | +| -------------- | ---------------------------------------------------------------- | +| **QEP** | 5 | +| **Title** | Code of AI Use | +| **Author** | @mmcky | +| **Status** | Draft | +| **Type** | standard | +| **Created** | 2026-08-14 | +| **Discussion** | [QuantEcon/qeps#12](https://github.com/QuantEcon/qeps/issues/12) | + +## Summary + +This QEP adopts a **Code of AI Use** for QuantEcon: AI-assisted contributions +are welcome, a human must submit and own them, and meaningful AI involvement +must be disclosed with a machine-readable marker. It is policy, not +infrastructure — the norms bind every contributor from acceptance, and the +volume problem they sit alongside is handled with GitHub's own native controls +rather than with anything we build. This answers a **cost** problem rather than +a safety one: maintainer review attention is the scarce resource here, and an +unattended submission spends it with nobody on the other end. A contributor +registry and a pull-request gate were drafted and are deliberately **not** part +of this decision; if the native controls prove insufficient, that is a later +amendment or a separate QEP. + +## Motivation + +An audit of the 18 open pull requests on `QuantEcon.py` (2026-08-14) found that +**11–12 involve AI authorship, and most carry no disclosure**. Eight have +explicit machine-readable attribution — bot accounts, Copilot co-author +trailers, maintainer pull requests with Claude trailers, and one exemplary +disclosed-and-human-reviewed submission. Three more carry strong agent +fingerprints with nothing declared, including two competing agent-written fixes +for the same issue filed on the same day by different first-time authors, and +one whose description presents a test run that stopped at 47% when the agent's +session ended as if it were validation. + +The pattern reads as issue-crawling automation rather than individual +experimentation: first-time authors converging on freshly filed structured +issues within days, echoing our issue text verbatim, and in two cases colliding +on the same issue. The costs are already concrete — duplicated review effort, CI +minutes spent on unverifiable claims, and no way to tell which pull-request +author will still be present to answer review comments. Review attention is the +binding constraint on this project, and the volume rises with agent capability. + +GitHub's native controls address **volume, not norms**. A repository can +[restrict pull requests][pr-access] to collaborators or turn them off entirely +(February 2026); an organisation can cap how many concurrent open pull requests +a user without write access may have ([August 2026][pr-limits]); and +[interaction limits][limits] throttle everything at once for up to six months. +Between them these can hold back a single runaway account without any custom +infrastructure, and that is the right first move. What none of them supplies is +a statement of what we expect from an AI-assisted contribution, or any basis for +asking a contributor to put one right. That is what this QEP provides. + +[limits]: https://docs.github.com/en/communities/moderating-comments-and-conversations/limiting-interactions-in-your-repository +[pr-access]: https://github.blog/changelog/2026-02-13-new-repository-settings-for-configuring-pull-request-access/ +[pr-limits]: https://github.blog/changelog/2026-08-06-set-pull-request-limits-at-the-organization-level/ + +## Proposal + +### 1. The Code of AI Use + +AI-assisted contributions are welcome at QuantEcon; our maintainers use these +tools daily and in the open. In exchange, every contributor accepts six norms: + +1. **A human submits.** Unattended agents and automated pipelines must not open + pull requests or crawl our issue tracker for work. A human chooses the task, + reviews the result, and submits it under their own account. Where a tool + pipeline generates the change, the human operating it is the contributor and + owns what it files — which is also how organisation-operated automation + qualifies (below). +2. **Disclose.** If AI tools meaningfully contributed to the code, tests, or + text of a pull request, say so — tick the disclosure box in the pull-request + template and leave one machine-readable trailer naming the tool, such as + `Co-Authored-By: `, which Claude Code and Copilot already emit + automatically. The disclosure is a **marker, not a narrative**. +3. **Own it.** You are the author: you can explain what the change does, you + answer review yourself — not an agent — and you carry the result. Reading + every line is the default way to earn that. **In code, tests can stand in for + it:** where a change is covered by tests that genuinely exercise the changed + behaviour, the tests do the verifying, and line-by-line reading of the + implementation is not expected. The burden moves rather than disappears — the + tests are then what you must have read and be able to explain. Prose, + mathematics, and exposition have no such substitute, because no test tells you + an argument is wrong. Submitting output nobody has vouched for shifts your + work onto volunteer maintainers. +4. **Verify before you claim.** Only state that tests pass, coverage rose, or + benchmarks improved if you ran them to completion. Partial runs are fine to + submit, described as what they are. +5. **Don't duplicate or farm.** Check for an existing open pull request before + starting on an issue, and don't mass-submit generated pull requests across + repositories to build a contribution record. The idea behind issues labelled as + `good first issue` is they are good candidates for humans to learn the codebase. +6. **Put it right.** We assume good faith and expect the occasional violation. + If something here is missed, a maintainer will say so and point at the fix — + please amend the pull request. Repeated or deliberate lapses may lead to + *Enforcement* (see below). + +These norms exist so that AI tools raise the quality of QuantEcon rather than +the cost of maintaining it. They bind **every** contributor, maintainers +included, and they bind from acceptance — like the Code of Conduct, this is +project policy rather than a contract only signatories are held to. + +**Organisation-operated automation is not an external contribution.** QuantEcon +runs its own scheduled maintenance — dependency bots, link checkers, build and +warning sweeps, and maintenance agents that open pull requests across +repositories. That is QuantEcon acting on its own repositories, not contributing +to them, and norm 1 does not prohibit it. The accountability rule is applied +rather than waived: such automation has a **named maintainer who owns its output +and answers for it**, it is **declared** — recorded somewhere public, not +self-asserted in a pull-request description — and it carries +[QEP-2](qep-0002-standard-github-labels.md)'s `automated` label so its output +stays distinguishable from human triage at a glance. Disclosure (norm 2) is +satisfied structurally by that label and the bot account rather than by a +trailer; norms 3 and 4 bind the operating maintainer exactly as they would for +work submitted by hand. Automation meeting none of those conditions is an +unattended agent, whoever built it. + +### 2. Enforcement + +The first response to any lapse is a **rectification comment**: a maintainer +points at the Code and asks the contributor to amend the PR. + +Beyond that, maintainers use judgement. The responses available, roughly in +order, are closing the pull request without further review and, at the far end, +GitHub's own organisation block, which can be set to expire on its own rather +than run indefinitely. Blocking is blunt by design — it also stops the person +filing issues and commenting — so it is the step to be slowest to take. + +The point is to keep the review queue worth reading, not to punish. Every step +short of the last is undone by the contributor simply fixing the problem. + +### 3. What this is not + +- **Not a ban on AI-assisted contributions.** QuantEcon maintainers use Claude + and Copilot openly, including delegated agent pull requests. A blanket ban + would cover our own workflow. +- **Not a CLA.** The Code covers conduct and disclosure only — no copyright + assignment, no licence grant, and no Developer Certificate of Origin line. +- **Not a contributor registry or a pull-request gate.** Both were drafted and + set aside. The norms above bind whether or not anyone attests to them, so a + registry would notify rather than bind; and a gate puts a bot comment on a + newcomer's *first* contribution, which is the worst possible moment to + introduce friction. Should one prove necessary later, it is an amendment to + this QEP or a QEP of its own, covering the maintenance and procedures a + registry needs — and two constraints from the design work carry over to it: + whatever records a contributor's standing must be **public and auditable**, so + that removing someone is a reviewable act rather than a private one, and no + mechanism may **check out or execute pull-request code** while holding + repository write permissions. + +## Alternatives considered + +- **Do nothing.** Volume rises with agent capability, and review attention is + precisely what this project is short of. The audit is a snapshot of a trend, + not a one-off. +- **A contributor registry with a pull-request gate.** A public whitelist of + logins who have attested to the Code, plus an action holding pull requests + from unregistered external authors until they register. Drafted in full and + set aside for now. Against it: the norms bind regardless of attestation, so + the registry notifies rather than binds; the friction lands on a newcomer's + first contribution; and it is standing infrastructure running with repository + write permissions. The native controls cost nothing and address the + single-account case immediately. Revisit on evidence, not on this audit. +- **Restricting pull requests to collaborators**, or turning them off entirely + ([available since February 2026][pr-access]). Native and free, but binary: + there is no tier between "anyone" and "write access", so it closes the + community pipeline — GSoC participants, students, one-off domain experts — + that produces some of our best contributions. +- **Interaction limits.** Native, but temporary (≤6 months), manually renewed, + and all-or-nothing — they silence the bug reports and questions we want from + the same people. +- **A structured `AI-Usage:` narrative on every pull request** — a free-text line + describing what the tool did and what the human verified, following the one + disclosed submission in the audit. Rejected as cost without signal: a reviewer + cannot verify the claim, norms 3 and 4 already bind the contributor to + vouching for the work and to not overstating what was run, and a mandatory + prose field in every description degrades into boilerplate that reads like + disclosure while carrying nothing. A greppable marker serves the audit; the + norms do the rest. Reversible by amendment if reviewers find the marker alone + leaves them guessing. + +## Adoption + +Acceptance fixes the Code of AI Use as QuantEcon policy. It binds from that +point, like the Code of Conduct — without anyone signing anything, and without +anything being built. + +One obligation follows for a repository adopting it: **the disclosure path must +be visible where contributions are made.** That means a disclosure checkbox in +the pull-request template, the trailer convention documented in +`CONTRIBUTING.md`, and a link to this policy from the structured issue templates +that agents are already consuming — the same text several of them echoed back to +us verbatim. A norm nobody encounters is not a norm. + +The Code is applied by maintainers reading pull requests. It adds no automation +of its own, and it assumes GitHub's native volume controls — org-level +[pull-request limits][pr-limits] in particular — are already in use. Those need +no QEP to enable, tune, or turn off, and this Code stands whether or not they +are. From d8df01528932942f0459505b85087f1a75f9bc1f Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 10 Sep 2026 14:24:44 +1000 Subject: [PATCH 2/8] QEP-5: revise from the 2026-09-09 feedback round Norm 1 binds a human in the loop rather than human attendance; norm 2 names a hand-added Assisted-by: trailer; norm 3's test carve-out is bounded to changes a test could fail; norm 5 adopts the good-first-issue reservation with the label as the fence; enforcement gains a merge-on-merits path. Motivation records the QuantEcon.py#923 confirmation, Alternatives adds the LLVM, QEMU, and detect-versus-ask entries, and a Disclosure section closes the document. Rebased onto main; the README index row is dropped since the index is now generated after merge. Assisted-by: Claude Code Co-Authored-By: Claude Fable 5.1 --- qeps/qep-0005-code-of-ai-use.md | 181 ++++++++++++++++++++++---------- 1 file changed, 127 insertions(+), 54 deletions(-) diff --git a/qeps/qep-0005-code-of-ai-use.md b/qeps/qep-0005-code-of-ai-use.md index 6e7e4aa..18d5765 100644 --- a/qeps/qep-0005-code-of-ai-use.md +++ b/qeps/qep-0005-code-of-ai-use.md @@ -23,16 +23,18 @@ discussion: https://github.com/QuantEcon/qeps/issues/12 ## Summary This QEP adopts a **Code of AI Use** for QuantEcon: AI-assisted contributions -are welcome, a human must submit and own them, and meaningful AI involvement -must be disclosed with a machine-readable marker. It is policy, not -infrastructure — the norms bind every contributor from acceptance, and the -volume problem they sit alongside is handled with GitHub's own native controls -rather than with anything we build. This answers a **cost** problem rather than -a safety one: maintainer review attention is the scarce resource here, and an -unattended submission spends it with nobody on the other end. A contributor -registry and a pull-request gate were drafted and are deliberately **not** part -of this decision; if the native controls prove insufficient, that is a later -amendment or a separate QEP. +are welcome, a human must be in the loop — choosing the task, reading the +result, submitting it, and answering review on it — and meaningful AI +involvement must be disclosed with a machine-readable marker. It is policy, not +infrastructure: the norms bind every contributor from acceptance, and the volume +problem they sit alongside is handled with GitHub's own native controls rather +than with anything we build. The problem it answers is **cost**, not safety. +Maintainer review attention is the scarce resource here, and a submission nobody +has read before asking us to read it is an *extractive contribution* — one that +costs more to review than it returns to the project. A contributor registry and +a pull-request gate were drafted and are deliberately **not** part of this +decision; if the native controls prove insufficient, that is a later amendment +or a separate QEP. ## Motivation @@ -46,13 +48,20 @@ for the same issue filed on the same day by different first-time authors, and one whose description presents a test run that stopped at 47% when the agent's session ended as if it were validation. -The pattern reads as issue-crawling automation rather than individual -experimentation: first-time authors converging on freshly filed structured -issues within days, echoing our issue text verbatim, and in two cases colliding -on the same issue. The costs are already concrete — duplicated review effort, CI -minutes spent on unverifiable claims, and no way to tell which pull-request -author will still be present to answer review comments. Review attention is the -binding constraint on this project, and the volume rises with agent capability. +The pattern read as issue-crawling automation rather than individual +experimentation — first-time authors converging on freshly filed issues within +days, echoing our issue text verbatim, twice colliding on the same one — and a +contributor has since confirmed it. Asked whether AI was involved, the author of +a lint cleanup merged on 2026-09-09 +([QuantEcon.py#923](https://github.com/QuantEcon/QuantEcon.py/pull/923)) +disclosed within the hour that an autonomous agent on a cron schedule had read +the issue, written the patch, run the validation, and drafted the description. +The change was correct and merged; but it carried no marker, since the runtime +emits no AI trailer and nobody added one, and nothing told a reviewer whether +anyone would answer review. The costs are already concrete: duplicated review +effort, CI minutes spent on unverifiable claims, and review comments written to +authors who may never read them. Review attention is the binding constraint on +this project, and the volume rises with agent capability. GitHub's native controls address **volume, not norms**. A repository can [restrict pull requests][pr-access] to collaborators or turn them off entirely @@ -75,43 +84,61 @@ asking a contributor to put one right. That is what this QEP provides. AI-assisted contributions are welcome at QuantEcon; our maintainers use these tools daily and in the open. In exchange, every contributor accepts six norms: -1. **A human submits.** Unattended agents and automated pipelines must not open - pull requests or crawl our issue tracker for work. A human chooses the task, - reviews the result, and submits it under their own account. Where a tool - pipeline generates the change, the human operating it is the contributor and - owns what it files — which is also how organisation-operated automation - qualifies (below). +1. **A human is in the loop.** A human chooses the task, reads the result before + asking anyone else to, submits it under their own account, and answers review + on it. Where a tool pipeline produces the change, the human operating it is + the contributor and owns what it files. Delegating work to an agent is fine. + A pipeline that files and vanishes is not, and neither is an agent that acts + in our repositories — opening, commenting, reviewing — without a person + approving what it does. Whether a human was at the keyboard when the pull + request opened does not matter; whether one owns it and is present for review + does. 2. **Disclose.** If AI tools meaningfully contributed to the code, tests, or text of a pull request, say so — tick the disclosure box in the pull-request - template and leave one machine-readable trailer naming the tool, such as - `Co-Authored-By: `, which Claude Code and Copilot already emit - automatically. The disclosure is a **marker, not a narrative**. + template and add one machine-readable trailer naming the tool, + `Assisted-by: `, to the commit message or the pull-request description. + Add it yourself; do not rely on the tool. A `Co-Authored-By:` trailer that a + tool emits on its own (Claude Code and Copilot do) also serves as the marker, + but an in-house or third-party pipeline emits nothing, so for those the + trailer exists only if its operator writes it. The disclosure is a **marker, + not a narrative**. 3. **Own it.** You are the author: you can explain what the change does, you - answer review yourself — not an agent — and you carry the result. Reading - every line is the default way to earn that. **In code, tests can stand in for - it:** where a change is covered by tests that genuinely exercise the changed - behaviour, the tests do the verifying, and line-by-line reading of the - implementation is not expected. The burden moves rather than disappears — the - tests are then what you must have read and be able to explain. Prose, - mathematics, and exposition have no such substitute, because no test tells you - an argument is wrong. Submitting output nobody has vouched for shifts your - work onto volunteer maintainers. + answer review yourself — not by passing a reviewer's comments to an agent — + and you carry the result. Reading every line is the default way to earn that. + **In code, tests can stand in for it, narrowly:** where a change is covered by + tests that would fail if the change were wrong, the tests do the verifying, + and line-by-line reading of the implementation is not expected. The burden + moves rather than disappears — the tests are then what you must have read and + be able to explain. The substitution stops where no test can fail: a deletion, + a refactor that preserves behaviour, or a change the issue asked you to judge + site by site is verified by reading it, or not at all. Prose, mathematics, and + exposition have no substitute either, because no test tells you an argument is + wrong. Submitting output nobody has vouched for shifts your work onto + volunteer maintainers. 4. **Verify before you claim.** Only state that tests pass, coverage rose, or benchmarks improved if you ran them to completion. Partial runs are fine to submit, described as what they are. -5. **Don't duplicate or farm.** Check for an existing open pull request before +5. **Don't crawl, duplicate, or farm.** Do not run automation that crawls our + issue tracker for work. Check for an existing open pull request before starting on an issue, and don't mass-submit generated pull requests across - repositories to build a contribution record. The idea behind issues labelled as - `good first issue` is they are good candidates for humans to learn the codebase. -6. **Put it right.** We assume good faith and expect the occasional violation. - If something here is missed, a maintainer will say so and point at the fix — - please amend the pull request. Repeated or deliberate lapses may lead to + repositories to build a contribution record. Issues labelled + [`good first issue`](qep-0002-standard-github-labels.md) are reserved for + people learning the codebase by hand: **do not use AI tools to fix them**, + whether you are a newcomer or not. The label is the fence — a maintainer who + wants any issue kept for hands-on learning labels it so. +6. **Put it right.** We assume good faith and expect the occasional lapse. If + something here is missed, a maintainer will say so and point at the fix — + please amend the pull request, or, where it has already merged, carry the + point into your next one. Repeated or deliberate lapses may lead to *Enforcement* (see below). These norms exist so that AI tools raise the quality of QuantEcon rather than the cost of maintaining it. They bind **every** contributor, maintainers included, and they bind from acceptance — like the Code of Conduct, this is -project policy rather than a contract only signatories are held to. +project policy rather than a contract only signatories are held to. They cover +anything a contributor asks a maintainer to read: pull requests first, but also +issues, review comments, and proposals — an AI-drafted bug report nobody has +checked costs the same attention as an AI-drafted patch. **Organisation-operated automation is not an external contribution.** QuantEcon runs its own scheduled maintenance — dependency bots, link checkers, build and @@ -119,11 +146,11 @@ warning sweeps, and maintenance agents that open pull requests across repositories. That is QuantEcon acting on its own repositories, not contributing to them, and norm 1 does not prohibit it. The accountability rule is applied rather than waived: such automation has a **named maintainer who owns its output -and answers for it**, it is **declared** — recorded somewhere public, not -self-asserted in a pull-request description — and it carries -[QEP-2](qep-0002-standard-github-labels.md)'s `automated` label so its output -stays distinguishable from human triage at a glance. Disclosure (norm 2) is -satisfied structurally by that label and the bot account rather than by a +and answers for it**, it is **declared** — recorded in a public register of the +organisation's automation, not self-asserted in a pull-request description — and +it carries [QEP-2](qep-0002-standard-github-labels.md)'s `automated` label so its +output stays distinguishable from human triage at a glance. Disclosure (norm 2) +is satisfied structurally by that label and the bot account rather than by a trailer; norms 3 and 4 bind the operating maintainer exactly as they would for work submitted by hand. Automation meeting none of those conditions is an unattended agent, whoever built it. @@ -131,7 +158,14 @@ unattended agent, whoever built it. ### 2. Enforcement The first response to any lapse is a **rectification comment**: a maintainer -points at the Code and asks the contributor to amend the PR. +points at the Code and asks the contributor to amend the pull request. + +A lapse does not decide the merits. Where the work is correct and in scope, a +maintainer may merge it and still record the lapse — a comment stating what the +Code expects next time. That comment is the rectification step for a pull +request that has already merged, and it counts toward *repeated* if the lapse +recurs. Closing correct work on process alone costs the project the work and the +contributor's goodwill, and is not the default. Beyond that, maintainers use judgement. The responses available, roughly in order, are closing the pull request without further review and, at the far end, @@ -166,6 +200,18 @@ short of the last is undone by the contributor simply fixing the problem. - **Do nothing.** Volume rises with agent capability, and review attention is precisely what this project is short of. The audit is a snapshot of a trend, not a one-off. +- **Adopt LLVM's [AI Tool Use Policy][llvm] as written.** The closest prior art, + and this Code borrows from it: the binding test (a human in the loop, not a + human at the keyboard), the hand-added `Assisted-by:` trailer, the + `good first issue` reservation, and the name *extractive contribution* for the + cost the whole policy exists to control. Not adopted wholesale because LLVM + bans any agent that acts in its repositories without per-action human + approval, which would cover the scheduled maintenance automation and delegated + agent pull requests QuantEcon runs itself. The organisation-automation + paragraph above is where the two policies part. +- **Decline AI-generated contributions on provenance grounds**, as + [QEMU][qemu] does under its Developer Certificate of Origin, or ban the tools + outright as Gentoo has. Defensible positions that would cover our own workflow. - **A contributor registry with a pull-request gate.** A public whitelist of logins who have attested to the Code, plus an action holding pull requests from unregistered external authors until they register. Drafted in full and @@ -174,6 +220,14 @@ short of the last is undone by the contributor simply fixing the problem. first contribution; and it is standing infrastructure running with repository write permissions. The native controls cost nothing and address the single-account case immediately. Revisit on evidence, not on this audit. +- **Detecting agents rather than asking.** Any mechanism keyed on recognising + agent output — fingerprints in the description, style in the diff — is weak + and getting weaker. In the one case tested, the diff carried no signal at all: + the issue enumerated every site, so a human working from the list produces the + same patch, and only the prose gave it away. Against that, a single neutral + question on the thread produced full, voluntary disclosure within the hour. + The Code therefore rests on maintainers reading pull requests and asking, and + on a disclosure path the contributor can see, not on identifying agents. - **Restricting pull requests to collaborators**, or turning them off entirely ([available since February 2026][pr-access]). Native and free, but binary: there is no tier between "anyone" and "write access", so it closes the @@ -192,21 +246,40 @@ short of the last is undone by the contributor simply fixing the problem. norms do the rest. Reversible by amendment if reviewers find the marker alone leaves them guessing. +[llvm]: https://llvm.org/docs/AIToolPolicy.html +[qemu]: https://www.qemu.org/docs/master/devel/code-provenance.html + ## Adoption Acceptance fixes the Code of AI Use as QuantEcon policy. It binds from that point, like the Code of Conduct — without anyone signing anything, and without anything being built. -One obligation follows for a repository adopting it: **the disclosure path must -be visible where contributions are made.** That means a disclosure checkbox in -the pull-request template, the trailer convention documented in -`CONTRIBUTING.md`, and a link to this policy from the structured issue templates -that agents are already consuming — the same text several of them echoed back to -us verbatim. A norm nobody encounters is not a norm. +Two obligations follow for a repository adopting it. + +**The disclosure path must be visible where contributions are made.** That means +a disclosure checkbox in the pull-request template, the `Assisted-by:` trailer +documented in `CONTRIBUTING.md` alongside the tool-emitted `Co-Authored-By:` +form it also accepts, and a link to this policy from the structured issue +templates that agents are already consuming — the same text several of them +echoed back to us verbatim. A norm nobody encounters is not a norm. + +**The `good first issue` label is applied deliberately.** Under norm 5 it now +reserves an issue for hands-on work as well as advertising it, so it goes only +on issues that meet [QEP-2](qep-0002-standard-github-labels.md)'s criteria for +it, and a maintainer who wants an audit or tech-debt issue kept for learning +labels it rather than assuming the reservation. The Code is applied by maintainers reading pull requests. It adds no automation of its own, and it assumes GitHub's native volume controls — org-level [pull-request limits][pr-limits] in particular — are already in use. Those need no QEP to enable, tune, or turn off, and this Code stands whether or not they are. + +## Disclosure + +This QEP was drafted with AI assistance, under the norms it sets out. Claude, +via Claude Code, produced text under the author's direction; the author read, +revised, and owns every line, and answers review on it. + +`Assisted-by: Claude Code` From e1d04b36f0aa5126b306b1c913c9346e46a2021d Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 11 Sep 2026 14:25:19 +1000 Subject: [PATCH 3/8] QEP-5: the Code in brief, three visibility channels, and the QEP-2 amendment Revised from jstac's comment of 2026-09-10 on the PR. - Add "The Code in brief": six one-sentence imperatives in a marker-fenced, normative block above the full norms, for verbatim reuse in contributor files and agent instructions. The full norms govern where they differ. - Adoption now names three channels, since no single place reaches everyone: the checkbox pair in the pull-request template (MicroPython's form, where the second box attests ownership), the Code in brief in the file agents read from a checkout, and a comment-only neutral ask on pull requests from outside the organisation. The no-automation claim narrows to "nothing that gates or decides". - Norm 2 lets the tool add the trailer, with the responsibility staying human. Alternatives cites Yang, He, and Zhou (2026) on agents ignoring rules they are not handed and never refusing to contribute under a ban. - Add "Amendments to QEP-2": the good-first-issue row's when-to-use cell carries the norm-5 reservation; applied at landing as QEP-2 v1. Assisted-by: Claude Code Co-Authored-By: Claude Fable 5.1 --- qeps/qep-0005-code-of-ai-use.md | 135 +++++++++++++++++++++++++++----- 1 file changed, 116 insertions(+), 19 deletions(-) diff --git a/qeps/qep-0005-code-of-ai-use.md b/qeps/qep-0005-code-of-ai-use.md index 18d5765..d7b0556 100644 --- a/qeps/qep-0005-code-of-ai-use.md +++ b/qeps/qep-0005-code-of-ai-use.md @@ -28,7 +28,10 @@ result, submitting it, and answering review on it — and meaningful AI involvement must be disclosed with a machine-readable marker. It is policy, not infrastructure: the norms bind every contributor from acceptance, and the volume problem they sit alongside is handled with GitHub's own native controls rather -than with anything we build. The problem it answers is **cost**, not safety. +than with anything we build. What a repository does build is visibility: the +Code is put in front of contributors and the tools they run, through the three +channels set out under *Adoption*. The problem it answers is **cost**, not +safety. Maintainer review attention is the scarce resource here, and a submission nobody has read before asking us to read it is an *extractive contribution* — one that costs more to review than it returns to the project. A contributor registry and @@ -82,7 +85,40 @@ asking a contributor to put one right. That is what this QEP provides. ### 1. The Code of AI Use AI-assisted contributions are welcome at QuantEcon; our maintainers use these -tools daily and in the open. In exchange, every contributor accepts six norms: +tools daily and in the open. In exchange, every contributor accepts six norms. + +**In brief.** The block below is the Code's copyable form. It is what a +repository's contributor files and agent instructions carry, verbatim, and it is +normative: a change to it is a substantive amendment of this QEP. Where it and +the full norms that follow differ, the full norms govern. + + +> [!IMPORTANT] +> **QuantEcon's Code of AI Use** +> ([QEP-5](https://github.com/QuantEcon/qeps/blob/main/qeps/qep-0005-code-of-ai-use.md)). +> AI-assisted contributions are welcome. In exchange: +> +> 1. **A human is in the loop.** Choose the task, read the result before asking +> anyone else to, submit it under your own account, and answer review on it +> yourself. +> 2. **Disclose.** If AI tools meaningfully contributed to the code, tests, or +> text, tick the disclosure box and add `Assisted-by: ` to the commit +> message or the pull-request description. +> 3. **Own it.** Be able to explain the change and answer review on it: read +> every line, or read the tests that would fail if it were wrong. +> 4. **Verify before you claim.** Say tests pass, coverage rose, or benchmarks +> improved only if you ran them to completion. +> 5. **Don't crawl, duplicate, or farm.** No automation that crawls our issue +> tracker; check for an existing pull request before starting; never +> mass-submit; and do not use AI tools on issues labelled `good first issue`. +> 6. **Put it right.** If a maintainer points at a lapse, amend the pull +> request, or carry the point into your next one. +> +> This covers anything you ask a maintainer to read: pull requests, issues, +> review comments, and proposals. + + +**In full.** 1. **A human is in the loop.** A human chooses the task, reads the result before asking anyone else to, submits it under their own account, and answers review @@ -97,10 +133,12 @@ tools daily and in the open. In exchange, every contributor accepts six norms: text of a pull request, say so — tick the disclosure box in the pull-request template and add one machine-readable trailer naming the tool, `Assisted-by: `, to the commit message or the pull-request description. - Add it yourself; do not rely on the tool. A `Co-Authored-By:` trailer that a - tool emits on its own (Claude Code and Copilot do) also serves as the marker, - but an in-house or third-party pipeline emits nothing, so for those the - trailer exists only if its operator writes it. The disclosure is a **marker, + Add it yourself, or have your tool add it — repositories put the Code in + front of agents for exactly that reason — but check that it is there: the + trailer is your responsibility, not the tool's. A `Co-Authored-By:` trailer + that a tool emits on its own (Claude Code and Copilot do) also serves as the + marker, but an in-house or third-party pipeline emits nothing, so for those + the trailer exists only if its operator writes it or instructs it. The disclosure is a **marker, not a narrative**. 3. **Own it.** You are the author: you can explain what the change does, you answer review yourself — not by passing a reviewer's comments to an agent — @@ -185,9 +223,11 @@ short of the last is undone by the contributor simply fixing the problem. assignment, no licence grant, and no Developer Certificate of Origin line. - **Not a contributor registry or a pull-request gate.** Both were drafted and set aside. The norms above bind whether or not anyone attests to them, so a - registry would notify rather than bind; and a gate puts a bot comment on a - newcomer's *first* contribution, which is the worst possible moment to - introduce friction. Should one prove necessary later, it is an amendment to + registry would notify rather than bind; and a gate holds a newcomer's + *first* contribution behind a registration step, which is the worst possible + moment to introduce friction. A comment that asks and holds nothing is a + different thing, and *Adoption* calls for one. Should a gate prove necessary + later, it is an amendment to this QEP or a QEP of its own, covering the maintenance and procedures a registry needs — and two constraints from the design work carry over to it: whatever records a contributor's standing must be **public and auditable**, so @@ -211,7 +251,11 @@ short of the last is undone by the contributor simply fixing the problem. paragraph above is where the two policies part. - **Decline AI-generated contributions on provenance grounds**, as [QEMU][qemu] does under its Developer Certificate of Origin, or ban the tools - outright as Gentoo has. Defensible positions that would cover our own workflow. + outright as Gentoo has. Defensible positions that would cover our own + workflow. There is also evidence a ban would not reach its target: a 2026 + study of coding agents working in open-source repositories found they never + refused to contribute to a repository that bans AI, under any condition + tested ([Yang, He, and Zhou][agents-study]). - **A contributor registry with a pull-request gate.** A public whitelist of logins who have attested to the Code, plus an action holding pull requests from unregistered external authors until they register. Drafted in full and @@ -227,7 +271,11 @@ short of the last is undone by the contributor simply fixing the problem. same patch, and only the prose gave it away. Against that, a single neutral question on the thread produced full, voluntary disclosure within the hour. The Code therefore rests on maintainers reading pull requests and asking, and - on a disclosure path the contributor can see, not on identifying agents. + on a disclosure path the contributor can see, not on identifying agents. The + same [study][agents-study] found that agents almost never fetch a + repository's contribution rules on their own, and do disclose once the rule + is put in front of them — which is why *Adoption* puts the Code in the file + agents read, not only where people look. - **Restricting pull requests to collaborators**, or turning them off entirely ([available since February 2026][pr-access]). Native and free, but binary: there is no tier between "anyone" and "write access", so it closes the @@ -246,6 +294,7 @@ short of the last is undone by the contributor simply fixing the problem. norms do the rest. Reversible by amendment if reviewers find the marker alone leaves them guessing. +[agents-study]: https://arxiv.org/abs/2607.26819 [llvm]: https://llvm.org/docs/AIToolPolicy.html [qemu]: https://www.qemu.org/docs/master/devel/code-provenance.html @@ -257,12 +306,39 @@ anything being built. Two obligations follow for a repository adopting it. -**The disclosure path must be visible where contributions are made.** That means -a disclosure checkbox in the pull-request template, the `Assisted-by:` trailer -documented in `CONTRIBUTING.md` alongside the tool-emitted `Co-Authored-By:` -form it also accepts, and a link to this policy from the structured issue -templates that agents are already consuming — the same text several of them -echoed back to us verbatim. A norm nobody encounters is not a norm. +**The disclosure path must be visible where contributions are made — to +contributors and to the tools they run.** No single place reaches everyone. A +pull-request template reaches a person opening a pull request in the web +interface and nobody else; an agent working from a checkout reads the +repository's agent-instruction file and nothing else; a pipeline that opens +pull requests through the API sees neither. A repository adopting the Code +therefore provides three things. + +- **A disclosure checkbox pair in the pull-request template**, in this form, + where the second box is an ownership attestation (norm 3) and not only a + disclosure: + + > - [ ] I did not use generative AI tools when creating this pull request. + > - [ ] I used generative AI tools when creating this pull request, and a + > human has checked the work and is responsible for the code and the + > description above. + + Alongside it, `CONTRIBUTING.md` documents the `Assisted-by:` trailer and the + tool-emitted `Co-Authored-By:` form it also accepts, and the structured issue + templates link to this policy — the same text several agents echoed back to + us verbatim. +- **The Code in brief in the file agents read from a checkout** (`AGENTS.md`, + by current convention), verbatim from the block above, so that the tool adds + the trailer rather than the contributor remembering to. +- **A neutral ask on pull requests the template did not reach.** A comment on + each pull request from outside the organisation, posted once, that links to + this Code and asks the author to paste the checkbox pair into their + description and tick one. It reaches a pull request however it was opened, + and it is the ask that produced full disclosure within the hour in the one + case tested. It holds nothing, decides nothing, skips the organisation's own + automation, and never checks out or executes the pull request's code. + +A norm nobody encounters is not a norm. **The `good first issue` label is applied deliberately.** Under norm 5 it now reserves an issue for hands-on work as well as advertising it, so it goes only @@ -270,12 +346,33 @@ on issues that meet [QEP-2](qep-0002-standard-github-labels.md)'s criteria for it, and a maintainer who wants an audit or tech-debt issue kept for learning labels it rather than assuming the reservation. -The Code is applied by maintainers reading pull requests. It adds no automation -of its own, and it assumes GitHub's native volume controls — org-level +The Code is applied by maintainers reading pull requests. The only automation +it asks for is the comment above, which asks and never decides; enforcement +stays human. It assumes GitHub's native volume controls — org-level [pull-request limits][pr-limits] in particular — are already in use. Those need no QEP to enable, tune, or turn off, and this Code stands whether or not they are. +## Amendments to QEP-2 + +Norm 5 gives `good first issue` a meaning that +[QEP-2](qep-0002-standard-github-labels.md)'s label table does not carry. At +acceptance the edit below is applied to QEP-2 as a substantive amendment — its +first, so its `version` moves to 1 and a **Version** row is added to its header +table. The yml appendix is unchanged: the label's name, colour, and description +do not move. + +In the label table, the **When to use** cell of the `good first issue` row +changes from + +> Only when genuinely self-contained with clear acceptance criteria + +to + +> Only when genuinely self-contained with clear acceptance criteria. Under +> [QEP-5](qep-0005-code-of-ai-use.md) the label also reserves the issue for +> hands-on work — AI tools are not to be used on it — so apply it deliberately + ## Disclosure This QEP was drafted with AI assistance, under the norms it sets out. Claude, From 8824139f9bbfcd3f3a8466c5c75031ab8fa911fb Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 11 Sep 2026 14:37:41 +1000 Subject: [PATCH 4/8] QEP-5: one disclosure line replaces the checkbox pair Norm 2 now asks for a single machine-readable line in every pull request: `Assisted-by: ()` where AI tools meaningfully contributed, or `Assisted-by: none` where they did not. The template carries the empty line with both forms and a fixed attestation sentence beside it; the checkbox pair is gone. The neutral ask on external pull requests fires only where the description carries no such line, and asks for the line plus a reply confirming a human has read the pull request. Assisted-by: Claude Code (Claude Fable 5.1) Co-Authored-By: Claude Fable 5.1 --- qeps/qep-0005-code-of-ai-use.md | 75 +++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/qeps/qep-0005-code-of-ai-use.md b/qeps/qep-0005-code-of-ai-use.md index d7b0556..1caf8c5 100644 --- a/qeps/qep-0005-code-of-ai-use.md +++ b/qeps/qep-0005-code-of-ai-use.md @@ -101,9 +101,10 @@ the full norms that follow differ, the full norms govern. > 1. **A human is in the loop.** Choose the task, read the result before asking > anyone else to, submit it under your own account, and answer review on it > yourself. -> 2. **Disclose.** If AI tools meaningfully contributed to the code, tests, or -> text, tick the disclosure box and add `Assisted-by: ` to the commit -> message or the pull-request description. +> 2. **Disclose.** Put one line in the pull-request description or a commit +> message: `Assisted-by: ()` where AI tools meaningfully +> contributed to the code, tests, or text, or `Assisted-by: none` where they +> did not. > 3. **Own it.** Be able to explain the change and answer review on it: read > every line, or read the tests that would fail if it were wrong. > 4. **Verify before you claim.** Say tests pass, coverage rose, or benchmarks @@ -129,17 +130,21 @@ the full norms that follow differ, the full norms govern. approving what it does. Whether a human was at the keyboard when the pull request opened does not matter; whether one owns it and is present for review does. -2. **Disclose.** If AI tools meaningfully contributed to the code, tests, or - text of a pull request, say so — tick the disclosure box in the pull-request - template and add one machine-readable trailer naming the tool, - `Assisted-by: `, to the commit message or the pull-request description. - Add it yourself, or have your tool add it — repositories put the Code in - front of agents for exactly that reason — but check that it is there: the - trailer is your responsibility, not the tool's. A `Co-Authored-By:` trailer - that a tool emits on its own (Claude Code and Copilot do) also serves as the - marker, but an in-house or third-party pipeline emits nothing, so for those - the trailer exists only if its operator writes it or instructs it. The disclosure is a **marker, - not a narrative**. +2. **Disclose.** Every pull request carries one machine-readable line, in the + pull-request description or a commit message. Where AI tools meaningfully + contributed to the code, tests, or text, it names them: + `Assisted-by: ()` — the harness first, the model in + parentheses, one line per tool, as in `Assisted-by: Claude Code (Claude + Fable 5.1)`. Where they did not, it says so: `Assisted-by: none`. The + explicit negative exists because silence is ambiguous — forgotten, or + unassisted — and a reviewer should not have to guess which. Add the line + yourself, or have your tool add it — repositories put the Code in front of + agents for exactly that reason — but check that it is there: the line is + your responsibility, not the tool's. A `Co-Authored-By:` trailer that a tool + emits on its own (Claude Code and Copilot do) also serves as the marker, but + an in-house or third-party pipeline emits nothing, so for those the line + exists only if its operator writes it or instructs it. The disclosure is a + **marker, not a narrative**: it names what was used, not what it did. 3. **Own it.** You are the author: you can explain what the change does, you answer review yourself — not by passing a reviewer's comments to an agent — and you carry the result. Reading every line is the default way to earn that. @@ -314,26 +319,34 @@ repository's agent-instruction file and nothing else; a pipeline that opens pull requests through the API sees neither. A repository adopting the Code therefore provides three things. -- **A disclosure checkbox pair in the pull-request template**, in this form, - where the second box is an ownership attestation (norm 3) and not only a - disclosure: - - > - [ ] I did not use generative AI tools when creating this pull request. - > - [ ] I used generative AI tools when creating this pull request, and a - > human has checked the work and is responsible for the code and the - > description above. - - Alongside it, `CONTRIBUTING.md` documents the `Assisted-by:` trailer and the - tool-emitted `Co-Authored-By:` form it also accepts, and the structured issue - templates link to this policy — the same text several agents echoed back to - us verbatim. +- **The disclosure line in the pull-request template.** The template carries + an empty `Assisted-by:` line for the author to complete, with the two forms + and one fixed sentence of attestation explained beside it: + + ```markdown + + Assisted-by: + ``` + + The attestation is a fixed sentence rather than a box to tick: norm 3 binds + whether or not anyone ticks anything, and the template's job is to make sure + the author has seen it. Alongside it, `CONTRIBUTING.md` documents the line + and the tool-emitted `Co-Authored-By:` form it also accepts, and the + structured issue templates link to this policy — the same text several + agents echoed back to us verbatim. - **The Code in brief in the file agents read from a checkout** (`AGENTS.md`, by current convention), verbatim from the block above, so that the tool adds the trailer rather than the contributor remembering to. - **A neutral ask on pull requests the template did not reach.** A comment on - each pull request from outside the organisation, posted once, that links to - this Code and asks the author to paste the checkbox pair into their - description and tick one. It reaches a pull request however it was opened, + each pull request from outside the organisation whose description carries no + `Assisted-by:` line, posted once, that links to this Code and asks the author + for two things: add the line to their description, and confirm in a reply + that a human has read the pull request and answers for it. Where the template + did its job the comment never fires. It reaches a pull request however it was + opened, and it is the ask that produced full disclosure within the hour in the one case tested. It holds nothing, decides nothing, skips the organisation's own automation, and never checks out or executes the pull request's code. @@ -379,4 +392,4 @@ This QEP was drafted with AI assistance, under the norms it sets out. Claude, via Claude Code, produced text under the author's direction; the author read, revised, and owns every line, and answers review on it. -`Assisted-by: Claude Code` +`Assisted-by: Claude Code (Claude Fable 5.1)` From 78db9dd6e81af9b6c339b3b2e3050b29d37be2d3 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 11 Sep 2026 14:39:55 +1000 Subject: [PATCH 5/8] QEP-5: the template attestation echoes norm 1 Assisted-by: Claude Code (Claude Fable 5.1) Co-Authored-By: Claude Fable 5.1 --- qeps/qep-0005-code-of-ai-use.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qeps/qep-0005-code-of-ai-use.md b/qeps/qep-0005-code-of-ai-use.md index 1caf8c5..feee3fd 100644 --- a/qeps/qep-0005-code-of-ai-use.md +++ b/qeps/qep-0005-code-of-ai-use.md @@ -327,7 +327,8 @@ therefore provides three things. + Opening this pull request confirms a human chose the task, read the + result, and will answer review on it. --> Assisted-by: ``` From 695e685409797220f4592ac8d81753e0db1959e0 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 11 Sep 2026 14:41:53 +1000 Subject: [PATCH 6/8] =?UTF-8?q?QEP-5:=20final=20read=20=E2=80=94=20align?= =?UTF-8?q?=20wording=20with=20the=20single=20disclosure=20line?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: Claude Code (Claude Fable 5.1) Co-Authored-By: Claude Fable 5.1 --- qeps/qep-0005-code-of-ai-use.md | 42 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/qeps/qep-0005-code-of-ai-use.md b/qeps/qep-0005-code-of-ai-use.md index feee3fd..6670acd 100644 --- a/qeps/qep-0005-code-of-ai-use.md +++ b/qeps/qep-0005-code-of-ai-use.md @@ -24,15 +24,14 @@ discussion: https://github.com/QuantEcon/qeps/issues/12 This QEP adopts a **Code of AI Use** for QuantEcon: AI-assisted contributions are welcome, a human must be in the loop — choosing the task, reading the -result, submitting it, and answering review on it — and meaningful AI -involvement must be disclosed with a machine-readable marker. It is policy, not +result, submitting it, and answering review on it — and every pull request +states its AI involvement in one machine-readable line. It is policy, not infrastructure: the norms bind every contributor from acceptance, and the volume problem they sit alongside is handled with GitHub's own native controls rather than with anything we build. What a repository does build is visibility: the Code is put in front of contributors and the tools they run, through the three channels set out under *Adoption*. The problem it answers is **cost**, not -safety. -Maintainer review attention is the scarce resource here, and a submission nobody +safety. Maintainer review attention is the scarce resource here, and a submission nobody has read before asking us to read it is an *extractive contribution* — one that costs more to review than it returns to the project. A contributor registry and a pull-request gate were drafted and are deliberately **not** part of this @@ -130,8 +129,8 @@ the full norms that follow differ, the full norms govern. approving what it does. Whether a human was at the keyboard when the pull request opened does not matter; whether one owns it and is present for review does. -2. **Disclose.** Every pull request carries one machine-readable line, in the - pull-request description or a commit message. Where AI tools meaningfully +2. **Disclose.** Every pull request carries a machine-readable `Assisted-by:` + line, in the pull-request description or a commit message. Where AI tools meaningfully contributed to the code, tests, or text, it names them: `Assisted-by: ()` — the harness first, the model in parentheses, one line per tool, as in `Assisted-by: Claude Code (Claude @@ -193,8 +192,8 @@ and answers for it**, it is **declared** — recorded in a public register of th organisation's automation, not self-asserted in a pull-request description — and it carries [QEP-2](qep-0002-standard-github-labels.md)'s `automated` label so its output stays distinguishable from human triage at a glance. Disclosure (norm 2) -is satisfied structurally by that label and the bot account rather than by a -trailer; norms 3 and 4 bind the operating maintainer exactly as they would for +is satisfied structurally by that label and the bot account rather than by the +line; norms 3 and 4 bind the operating maintainer exactly as they would for work submitted by hand. Automation meeting none of those conditions is an unattended agent, whoever built it. @@ -232,9 +231,9 @@ short of the last is undone by the contributor simply fixing the problem. *first* contribution behind a registration step, which is the worst possible moment to introduce friction. A comment that asks and holds nothing is a different thing, and *Adoption* calls for one. Should a gate prove necessary - later, it is an amendment to - this QEP or a QEP of its own, covering the maintenance and procedures a - registry needs — and two constraints from the design work carry over to it: + later, it is an amendment to this QEP or a QEP of its own, covering the + maintenance and procedures a registry needs — and two constraints from the + design work carry over to it: whatever records a contributor's standing must be **public and auditable**, so that removing someone is a reviewable act rather than a private one, and no mechanism may **check out or execute pull-request code** while holding @@ -247,8 +246,8 @@ short of the last is undone by the contributor simply fixing the problem. not a one-off. - **Adopt LLVM's [AI Tool Use Policy][llvm] as written.** The closest prior art, and this Code borrows from it: the binding test (a human in the loop, not a - human at the keyboard), the hand-added `Assisted-by:` trailer, the - `good first issue` reservation, and the name *extractive contribution* for the + human at the keyboard), the hand-added `Assisted-by:` trailer (extended here + with the model and an explicit `none`), the `good first issue` reservation, and the name *extractive contribution* for the cost the whole policy exists to control. Not adopted wholesale because LLVM bans any agent that acts in its repositories without per-action human approval, which would cover the scheduled maintenance automation and delegated @@ -306,8 +305,8 @@ short of the last is undone by the contributor simply fixing the problem. ## Adoption Acceptance fixes the Code of AI Use as QuantEcon policy. It binds from that -point, like the Code of Conduct — without anyone signing anything, and without -anything being built. +point, like the Code of Conduct — without anyone signing anything. What a +repository builds is the visibility below, not enforcement. Two obligations follow for a repository adopting it. @@ -340,16 +339,15 @@ therefore provides three things. agents echoed back to us verbatim. - **The Code in brief in the file agents read from a checkout** (`AGENTS.md`, by current convention), verbatim from the block above, so that the tool adds - the trailer rather than the contributor remembering to. + the line rather than the contributor remembering to. - **A neutral ask on pull requests the template did not reach.** A comment on each pull request from outside the organisation whose description carries no `Assisted-by:` line, posted once, that links to this Code and asks the author for two things: add the line to their description, and confirm in a reply - that a human has read the pull request and answers for it. Where the template - did its job the comment never fires. It reaches a pull request however it was - opened, - and it is the ask that produced full disclosure within the hour in the one - case tested. It holds nothing, decides nothing, skips the organisation's own + that a human chose the task, read the result, and will answer review on it. + Where the template did its job the comment never fires. It reaches a pull + request however it was opened, and it is the ask that produced full + disclosure within the hour in the one case tested. It holds nothing, decides nothing, skips the organisation's own automation, and never checks out or executes the pull request's code. A norm nobody encounters is not a norm. @@ -361,7 +359,7 @@ it, and a maintainer who wants an audit or tech-debt issue kept for learning labels it rather than assuming the reservation. The Code is applied by maintainers reading pull requests. The only automation -it asks for is the comment above, which asks and never decides; enforcement +it calls for is the comment above, which asks and never decides; enforcement stays human. It assumes GitHub's native volume controls — org-level [pull-request limits][pr-limits] in particular — are already in use. Those need no QEP to enable, tune, or turn off, and this Code stands whether or not they From 990bddaa23fbf327b200fbe42bb4eb12bb7625f9 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 11 Sep 2026 14:42:29 +1000 Subject: [PATCH 7/8] QEP-5: rewrap four joined lines Assisted-by: Claude Code (Claude Fable 5.1) Co-Authored-By: Claude Fable 5.1 --- qeps/qep-0005-code-of-ai-use.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/qeps/qep-0005-code-of-ai-use.md b/qeps/qep-0005-code-of-ai-use.md index 6670acd..b823086 100644 --- a/qeps/qep-0005-code-of-ai-use.md +++ b/qeps/qep-0005-code-of-ai-use.md @@ -31,7 +31,8 @@ problem they sit alongside is handled with GitHub's own native controls rather than with anything we build. What a repository does build is visibility: the Code is put in front of contributors and the tools they run, through the three channels set out under *Adoption*. The problem it answers is **cost**, not -safety. Maintainer review attention is the scarce resource here, and a submission nobody +safety. Maintainer review attention is the scarce resource here, and a +submission nobody has read before asking us to read it is an *extractive contribution* — one that costs more to review than it returns to the project. A contributor registry and a pull-request gate were drafted and are deliberately **not** part of this @@ -130,7 +131,8 @@ the full norms that follow differ, the full norms govern. request opened does not matter; whether one owns it and is present for review does. 2. **Disclose.** Every pull request carries a machine-readable `Assisted-by:` - line, in the pull-request description or a commit message. Where AI tools meaningfully + line, in the pull-request description or a commit message. Where AI tools + meaningfully contributed to the code, tests, or text, it names them: `Assisted-by: ()` — the harness first, the model in parentheses, one line per tool, as in `Assisted-by: Claude Code (Claude @@ -247,7 +249,8 @@ short of the last is undone by the contributor simply fixing the problem. - **Adopt LLVM's [AI Tool Use Policy][llvm] as written.** The closest prior art, and this Code borrows from it: the binding test (a human in the loop, not a human at the keyboard), the hand-added `Assisted-by:` trailer (extended here - with the model and an explicit `none`), the `good first issue` reservation, and the name *extractive contribution* for the + with the model and an explicit `none`), the `good first issue` reservation, + and the name *extractive contribution* for the cost the whole policy exists to control. Not adopted wholesale because LLVM bans any agent that acts in its repositories without per-action human approval, which would cover the scheduled maintenance automation and delegated @@ -347,7 +350,8 @@ therefore provides three things. that a human chose the task, read the result, and will answer review on it. Where the template did its job the comment never fires. It reaches a pull request however it was opened, and it is the ask that produced full - disclosure within the hour in the one case tested. It holds nothing, decides nothing, skips the organisation's own + disclosure within the hour in the one case tested. It holds nothing, decides + nothing, skips the organisation's own automation, and never checks out or executes the pull request's code. A norm nobody encounters is not a norm. From 4e42c443614f8ae82d3868a9aae80a1a662b96c6 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 11 Sep 2026 14:42:48 +1000 Subject: [PATCH 8/8] QEP-5: reflow four paragraphs Assisted-by: Claude Code (Claude Fable 5.1) Co-Authored-By: Claude Fable 5.1 --- qeps/qep-0005-code-of-ai-use.md | 66 +++++++++++++++++---------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/qeps/qep-0005-code-of-ai-use.md b/qeps/qep-0005-code-of-ai-use.md index b823086..0b274dd 100644 --- a/qeps/qep-0005-code-of-ai-use.md +++ b/qeps/qep-0005-code-of-ai-use.md @@ -32,12 +32,12 @@ than with anything we build. What a repository does build is visibility: the Code is put in front of contributors and the tools they run, through the three channels set out under *Adoption*. The problem it answers is **cost**, not safety. Maintainer review attention is the scarce resource here, and a -submission nobody -has read before asking us to read it is an *extractive contribution* — one that -costs more to review than it returns to the project. A contributor registry and -a pull-request gate were drafted and are deliberately **not** part of this -decision; if the native controls prove insufficient, that is a later amendment -or a separate QEP. +submission nobody has read before asking us to read it is an *extractive +contribution* — one that costs more to review than it returns to the project. A +contributor registry and a pull-request gate were drafted and are deliberately +**not** part of this decision; if the native controls prove insufficient, that +is a later amendment or a separate QEP. + ## Motivation @@ -132,20 +132,20 @@ the full norms that follow differ, the full norms govern. does. 2. **Disclose.** Every pull request carries a machine-readable `Assisted-by:` line, in the pull-request description or a commit message. Where AI tools - meaningfully - contributed to the code, tests, or text, it names them: + meaningfully contributed to the code, tests, or text, it names them: `Assisted-by: ()` — the harness first, the model in - parentheses, one line per tool, as in `Assisted-by: Claude Code (Claude - Fable 5.1)`. Where they did not, it says so: `Assisted-by: none`. The - explicit negative exists because silence is ambiguous — forgotten, or - unassisted — and a reviewer should not have to guess which. Add the line - yourself, or have your tool add it — repositories put the Code in front of - agents for exactly that reason — but check that it is there: the line is - your responsibility, not the tool's. A `Co-Authored-By:` trailer that a tool - emits on its own (Claude Code and Copilot do) also serves as the marker, but - an in-house or third-party pipeline emits nothing, so for those the line - exists only if its operator writes it or instructs it. The disclosure is a - **marker, not a narrative**: it names what was used, not what it did. + parentheses, one line per tool, as in `Assisted-by: Claude Code (Claude Fable + 5.1)`. Where they did not, it says so: `Assisted-by: none`. The explicit + negative exists because silence is ambiguous — forgotten, or unassisted — and + a reviewer should not have to guess which. Add the line yourself, or have + your tool add it — repositories put the Code in front of agents for exactly + that reason — but check that it is there: the line is your responsibility, + not the tool's. A `Co-Authored-By:` trailer that a tool emits on its own + (Claude Code and Copilot do) also serves as the marker, but an in-house or + third-party pipeline emits nothing, so for those the line exists only if its + operator writes it or instructs it. The disclosure is a **marker, not a + narrative**: it names what was used, not what it did. + 3. **Own it.** You are the author: you can explain what the change does, you answer review yourself — not by passing a reviewer's comments to an agent — and you carry the result. Reading every line is the default way to earn that. @@ -250,12 +250,13 @@ short of the last is undone by the contributor simply fixing the problem. and this Code borrows from it: the binding test (a human in the loop, not a human at the keyboard), the hand-added `Assisted-by:` trailer (extended here with the model and an explicit `none`), the `good first issue` reservation, - and the name *extractive contribution* for the - cost the whole policy exists to control. Not adopted wholesale because LLVM - bans any agent that acts in its repositories without per-action human - approval, which would cover the scheduled maintenance automation and delegated - agent pull requests QuantEcon runs itself. The organisation-automation - paragraph above is where the two policies part. + and the name *extractive contribution* for the cost the whole policy exists to + control. Not adopted wholesale because LLVM bans any agent that acts in its + repositories without per-action human approval, which would cover the + scheduled maintenance automation and delegated agent pull requests QuantEcon + runs itself. The organisation-automation paragraph above is where the two + policies part. + - **Decline AI-generated contributions on provenance grounds**, as [QEMU][qemu] does under its Developer Certificate of Origin, or ban the tools outright as Gentoo has. Defensible positions that would cover our own @@ -346,13 +347,14 @@ therefore provides three things. - **A neutral ask on pull requests the template did not reach.** A comment on each pull request from outside the organisation whose description carries no `Assisted-by:` line, posted once, that links to this Code and asks the author - for two things: add the line to their description, and confirm in a reply - that a human chose the task, read the result, and will answer review on it. - Where the template did its job the comment never fires. It reaches a pull - request however it was opened, and it is the ask that produced full - disclosure within the hour in the one case tested. It holds nothing, decides - nothing, skips the organisation's own - automation, and never checks out or executes the pull request's code. + for two things: add the line to their description, and confirm in a reply that + a human chose the task, read the result, and will answer review on it. Where + the template did its job the comment never fires. It reaches a pull request + however it was opened, and it is the ask that produced full disclosure within + the hour in the one case tested. It holds nothing, decides nothing, skips the + organisation's own automation, and never checks out or executes the pull + request's code. + A norm nobody encounters is not a norm.