ADR 0002 — The squash commit names no agent

  • Status: accepted
  • Scope: @putnami/sdd (agent-attribution-validate, a step of validate-workspace), and every workspace that sets options.sdd.agentAttribution

Context

A pull request merges by squash, and the squash commit is the only commit of the change that reaches the base branch. Its message is the pull request title and, when the repository squashes with it, the pull request body.

A coding agent, or the service that hosts it, can sign that message: a "Generated by" footer, a Co-Authored-By trailer for a model, a link to the agent's session. The agent's own settings do not cover every writer. A hosted service that opens the pull request for the agent writes its own footer, and an agent session that does not read the repository's settings writes its own trailer. Once the commit is on the base branch, only a history rewrite removes the signature, and a rewrite changes the ID of every later commit.

Some workspaces want no such signature in their history. Others want one. The choice belongs to the workspace.

Decision

  1. A step of validate-workspace reads the squash message. Every gate that runs validate runs it, on any runner, as it runs the breaking-marker step (ADR 0001).
  2. The workspace opts in. options.sdd.agentAttribution is "allow" or "forbid". Unset reads as "allow", and the step then passes with a note that says how to opt in. Any other value fails, so a typo does not turn the gate off.
  3. The message comes from PUTNAMI_PROPOSAL_MESSAGE. It is the variable the breaking-marker step reads, set by the runner the same way. An unset or blank variable passes with a note.
  4. Three forms fail, line by line. "Generated by" or "Generated with" followed by an agent's name; a Co-Authored-By trailer whose name or address is an agent's; a link to an agent's session, or the trailer that carries one. The agent names are one list in the engine, matched as whole words regardless of case. A failure names each line by its number and its form.
  5. Technical text passes. A path such as .claude/ or .agents/, a human co-author, and a generator that is not an agent are not signatures. A workspace that forbids attribution can still say that it is built with agents.
  6. The commits of the branch are not read. They never reach the base branch.
  7. The step is never served from cache. Its verdict reads an environment variable that the candidate cut does not hold.

Consequences

  • A pull request whose title or body names an agent fails the gate in a workspace that forbids it, on every runner that sets the variable.
  • An edit of the title or the body is checked at the next run of the gate. A runner that does not run the gate on such an edit leaves the edit unchecked until the next push.
  • The step checks the default squash message only. A person who rewrites the message in the merge dialog can still add a signature.
  • The list of agent names is closed. A new agent host is added to it in a release of @putnami/sdd.
  • A generator that shares its name with an agent, written right after "generated by", fails. The remedy is to reword the line.