Deleted for posterity
On 2 October a merged Kubernetes design document was reverted out of the tree — 2,020 lines removed — because a maintainer concluded it had been written with undisclosed AI assistance. The project reserves a status for proposals that are kept as historical documents, and has nowhere in the repository to put the fact that decided this one.
The argumentKubernetes requires AI disclosure in the pull request description and forbids the commit trailer that would carry it, so when provenance decided the fate of a merged design document, the only way the record could express doubt was to delete it.
On 2 October a pull request landed in the Kubernetes enhancements repository with a diff stat of plus nothing, minus 2,020. It removed three files: a production-readiness stub, a metadata file, and a design document describing how the StatefulSet controller would be integrated with the project's new Workload APIs. The document had been merged two days earlier, on 30 September, five weeks after it was opened and after four reviewers had been through it.
The reason recorded in the thread is that the document was written with undisclosed help from a generative model. The maintainer who called for the revert wrote that they had "left multiple objections against this particular document, and request a thorough rewrite," citing undisclosed AI usage, and that a fresh start would give every reader a better starting ground. The enhancement was moved out of the v1.38 milestone and into v1.39. A second reviewer, pohly, asked the question worth sitting with: "Why revert? Wouldn't it be better to keep the proposal for posterity in the tree" — with, they suggested, a status such as deferred, rejected or withdrawn.
That question quotes the process at the project. Kubernetes keeps its design history in a directory of enhancement proposals, and the document that defines that process, KEP-0000, lists seven states a proposal can be in. One of them is rejected, and its definition contains a promise: "The approvers and authors have decided that this KEP is not moving forward. The KEP is kept around as a historical document." The repository's own README explains why anyone should bother with the ceremony at all — so that contributors can "find a structured historical record," a "well curated set of clear proposals," explicitly inspired by IETF RFCs, Python PEPs and Rust RFCs.
That machinery was working perfectly three days earlier. On 30 September, a proposal to add webhook hosting to the cloud controller manager, filed in May 2021, was moved to withdrawn. Its metadata file still sits in the tree, carrying three added links: the umbrella issue, the original implementation pull request, and a recording of the SIG meeting where the decision was taken. Five years of a dead idea, preserved with a pointer to the conversation that killed it. That is what a decision record is supposed to do, and it costs almost nothing to do it.
So the question is not whether Kubernetes knows how to retire a proposal gracefully. It demonstrably does. The question is why, for this document, the graceful options were unavailable — and the answer is that the fact which decided its fate is the one fact the project has decided not to keep.
The Kubernetes contributor guide is unambiguous on both halves of that. Using a model to help write a contribution "is acceptable, but as the author, you are responsible for understanding every change." If you do, "you must disclose this in the description of your PR" — the guide even supplies the sentence. And then: "Listing AI tooling as a co-author, co-signing commits using an AI tool, or using the assisted-by, co-developed or similar commit trailer is not allowed."
Read those two sentences as an architect reads a schema, and the shape is clear. The disclosure is mandatory in a GitHub text box: mutable, attached to a pull request rather than to a file, and not part of the repository at all. It is prohibited in the commit message: immutable, attached to the change itself, surviving a clone, greppable in git log a decade later. One field travels with the artefact forever. The other is a comment on a web page that happens to be adjacent to it. The project requires the fact in the second place and forbids it in the first.
The proposal's own metadata has no room for it either. The KEP template defines fields for title, number, authors, owning and participating SIGs, reviewers, approvers, creation date, see-also, replaces, superseded-by, target stage, milestones, feature gates and metrics. Nothing describes how the text was produced. Which means that when a maintainer concluded, after the merge, that they could not vouch for how 2,020 lines had come to exist, the options were: leave it in place with status implementable; mark it rejected and thereby keep it, by the project's own definition, "as a historical document"; or delete it. The vocabulary had no way to say this document may not be what it appears to be. Deleting it was the only available sentence.
It matters that this was not a drive-by. The proposal was opened on 25 August as a draft, marked ready on 31 August, and reviewed hard. An automated reviewer flagged internal contradictions on day one: beta criteria describing drain-and-recreate scaling where another section specified an in-place update, and a claim repeated in one place that conflicted with an earlier one. A maintainer wrote on 2 September that "there are a few inconsistencies but overall the KEP is looking really solid." Another raised rolling-update semantics in September and called it "an important item to solve in alpha." The approving review on 29 September said "the rest can be addressed in a follow up." A day later, after the merge, came the objection that broke it open: StatefulSet rollouts are controller-driven in a way Deployments are not, so — "if this is not solved why is this merged?" and "this topic should be solved at alpha!"
Nothing in that sequence required a theory about authorship. The document's defect was legible in the document: it specified two incompatible scaling behaviours and left the core semantics of the controller it proposed to change unresolved while collecting approvals. What provenance supplied, afterwards, was an explanation for why reading it had felt like that. And once the explanation is provenance rather than content, the record has nothing to say, because the record only holds content.
The Linux kernel reached the opposite conclusion about the same trailer in the same year. Its guidelines for tool-generated content ask contributors to "be transparent about the origin of content in cover letters and changelogs," and the transparency it describes is granular: which tools were used, the input to them, the prompts themselves or a summary of them for longer sessions, which portions of the content were affected, and how the result was tested. Its companion document on coding assistants is firm about the limit — "AI agents MUST NOT add Signed-off-by tags. Only humans can legally certify the Developer Certificate of Origin" — and then specifies the tag that Kubernetes bans: "Contributions should include an Assisted-by tag," formatted Assisted-by: LLM [TOOL1] [TOOL2]. The kernel's maintainers are told they may treat such a contribution normally, reject it outright, review it with extra scrutiny, review it at lower priority, or ask the submitter to explain how the tool was trained. They can do that because the fact is in front of them, in the changelog, permanently.
The case for the Kubernetes rule is real and should be stated at full strength. A trailer that credits a machine corrupts the thing trailers are for: the chain of human sign-off that makes someone answerable. And deletion was arguably the kind choice. An archive is not free — a rejected proposal stays precisely so that it can be cited, so that the next person does not re-argue a settled trade-off. Keeping 2,020 lines of analysis that nobody will defend, in the directory the project advertises as its structured historical record, imports a liability into the one place engineers are told to trust. The contributor guide already says that if an author "cannot explain why a change was made, the PR will be closed," which is the same judgement in another form: an artefact nobody can account for is worse than no artefact. The tracking issue stayed open, the work moved to the next release, and the proposal's own author opened the revert. As dispositions go, that is honest.
But the choice was forced by an absence, not reached by judgement. What the record needed was never a boolean. It was the kernel's shape: which sections were generated, from what prompting, what the human verified. With that in the commit, provenance becomes a property of the document, and the maintainer's options widen — mark it rejected, record the reason beside it, keep the analysis with its warning label attached, let the next author see both the proposal and what was wrong with how it arrived. Without it, the only way a repository can express a doubt about a document is to stop containing the document.
The cost is quiet and it compounds. What remains in the tree now is the tracking issue — open, milestone cleared, pointing at a pull request whose files no longer exist. An engineer who finds it in 2029 will learn that a design was proposed and reverted, and will reconstruct why from a thread, if the thread is still there. As the volume of plausible proposals rises, the archive will hold only the ones somebody could vouch for, and the record of what a project declined — the most useful part of any decision history, because rejections are where the reasons live — will thin out exactly as the reasons get harder to establish.
Every architecture practice that keeps decision records is standing in the same place and mostly has not noticed. The ADR template has fields for context, decision, consequences, status, date and deciders. It has none for how the text was produced, because until recently the question was answered by the existence of the text. A record whose provenance cannot be established does not merely lose authority. It becomes something the next team has to re-derive, which is the precise opposite of what it was written for.
Kubernetes keeps its proposals so that nobody has to argue the same thing twice. The one durable promise in that arrangement is that a proposal which failed is kept as a historical document. The first time a maintainer could not say how one had been written, that promise was the thing that could not be honoured.
What this is argued from
Reporting and primary material the piece rests on, dated at the time of writing. The interpretation is mine; the facts belong to these.
- Revert "KEP-6277: Add KEP for integrating Workload APIs with StatefulSet" (#6451)
- KEP-6277: Add KEP for integrating Workload APIs with StatefulSet (#6298)
- KEP-0000, the Kubernetes Enhancement Proposal process
- Kubernetes Enhancement Proposals, repository README
- Pull Requests — AI Guidance, Kubernetes contributor guide
- Kernel Guidelines for Tool-Generated Content
- AI Coding Assistants
- KEP-2699: Add webhook hosting to CCM, kep.yaml
- WAS: Integrate Statefulset controller with Workload APIs (#6277)
Editorials on this site are written to be argued with. If you think the reading is wrong, it probably is in some particular way, and that is the useful part.