Index

A Pull Request Is a Review Narrative, Not a Template

Most pull-request templates start with good intentions and end as paperwork.

They ask for a summary, testing instructions, screenshots, a ticket, a risk assessment, a deployment plan, a rollback plan, and twelve checkboxes. A small change answers half of them with “not applicable.” A large change fills them with links. The template is complete, yet the reviewer still has to reverse engineer the actual decision from the diff.

The failure is not Markdown. It is treating the presence of headings as proof that communication happened.

A pull request has one job: make an integration decision reviewable. It should tell another engineer what the repository will become, why that change is necessary, how the proposed design produces it, why that design was selected, what could go wrong, and what evidence supports the claims.

That makes a pull request a small changelog with a different audience and a different tense. A changelog tells consumers what shipped. A pull request tells reviewers what would ship if they accept the proposal.

The missing layer in development history

We already ask different artifacts to preserve different kinds of truth:

Project Profile
Intent Commits
atomic implementation intent
Intent Pull Requests
integration rationale and review evidence
Intent Changesets
release decision across implementation boundaries
Intent Changelog
consumer-facing release history
Release Manifest
evidence of what was published

A commit cannot explain a whole branch without becoming dishonest about its atomic scope. A changeset should not become a design review. A changelog should not narrate implementation trade-offs that consumers do not need. An issue usually describes desired work before the implementation reveals its real constraints.

The pull request owns the integration-level explanation.

A title is a promise about the merged state

Weak titles describe activity:

DEVELOP-241
update auth files
address feedback
fix tests

They may identify a work item, but they do not identify a result. Once the branch is merged, the activity is irrelevant. The repository state is what survives.

A useful title describes that state:

feat(apps/gateway/auth): bind service tokens to audiences

The type says what kind of integrated change this is. The scope identifies the primary application and context. The description says what becomes true.

This matters even when a project does not squash. Search results, release automation, review lists, notifications, and incident archaeology all reuse the title. When a project does squash, the title may become durable Git history and must meet the same standard as a commit header.

The body should answer the reviewer’s real questions

The useful questions are semantic, not templating questions.

What becomes true?

Describe behavior after integration. “Refactored the token validator” says what the author did. “Tokens are rejected when their audience does not match the receiving application” says what the system does.

Why is this necessary?

Preserve the reason locally. A ticket link can supply detail, but links rot, permissions change, and issue descriptions often preserve the request rather than the final understanding.

How does the design achieve it?

Explain the mechanism at reviewer altitude. Name the boundary where the rule is enforced, the data that flows through it, compatibility behavior, and failure mode. Do not list every changed file; the diff already does that perfectly.

Why this design?

The most valuable context is often the context code cannot retain. Why validate at the shared boundary instead of four applications? Why migrate lazily instead of rewriting the table? Why accept temporary duplication? Why was an apparently simpler alternative rejected?

This does not require a miniature architecture decision record for every pull request. One honest sentence can preserve the decisive constraint.

What does it affect?

In a monorepo, “auth” is not a release boundary. The pull request should name every application or package and, when relevant, its release stream. The same implementation may be major for the gateway, patch for the worker, and absent from the worker’s long-term-support stream.

Applying the largest impact everywhere is easy automation and false history.

What evidence supports it?

“Tests pass” is not enough. Which tests? Against which revision? Did a command run, did CI report it, was it skipped, or was the required environment unavailable?

Five states cover the truth without euphemism:

  • passed: the check ran successfully;
  • failed: it ran and failed;
  • skipped: it could have run but deliberately did not;
  • unavailable: this environment could not run it; and
  • not applicable: it does not test this change, with a reason.

Lint does not prove compilation. A focused unit test does not prove the full suite. Ten thousand generated lines do not prove high compatibility impact. A one-line authorization change can be major.

Ready is a semantic state

A draft pull request is allowed to be uncertain. That is why it is a draft. Missing migration judgment or an unresolved rollout decision should be visible, not replaced with plausible prose.

Ready for review means the current proposal is explained completely enough to evaluate. The body should change when the branch changes. It is not a diary of attempt one, review feedback, attempt two, and a final cleanup. Review comments can preserve the conversation; the body preserves its current conclusion.

Merged means the explanation matches what entered the base. Closed means it did not enter the base. Those are different historical claims.

A compact body is usually enough

The Intent Pull Requests Specification defines semantic fields and a canonical portable record. A readable rendering can remain small:

## What

Bind service tokens to the application that receives them.

## Why

Prevent credentials issued for one service from being replayed elsewhere.

## Approach

Validate audiences at the shared authentication boundary so every service
uses the same rule.

### Trade-offs

Existing clients must add an audience before upgrading.

## Impact

- `apps/gateway@stable`: major; add the gateway audience claim

## Verification

- **unit-tests — passed:** `go test ./...`, CI run 481
- **production-smoke — unavailable:** pull-request CI has no production access

A tiny documentation correction may need three paragraphs instead. The goal is not to populate every heading. The goal is to leave no material review question hidden behind an empty section or N/A.

AI makes the labor cheaper and the guessing riskier

AI is unusually good at the tedious part: reading a complete branch diff, condensing repeated changes, finding affected packages, organizing verification output, and drafting concise prose. That makes richer pull-request context economically reasonable.

It is also unusually good at turning missing evidence into fluent fiction.

An agent can infer a convincing rationale that nobody chose, call a risk negligible because the diff is short, report tests as passed because a README mentions them, or obey a prompt hidden inside a fixture. Review comments and issue descriptions are no safer than source code; all are untrusted evidence.

An AI author should receive:

  1. trusted caller instructions;
  2. the exact base and head revisions;
  3. the complete diff and commits between them;
  4. the exact Project Profile;
  5. verified decision sources; and
  6. the revision associated with every verification result.

It must not invent rationale, impact, migration, risk, rollout, provenance, or review conclusions. When evidence cannot answer a required question, the right output is NEEDS_INPUT, not a polished guess.

Put freshness in CI

ACK implements the portable protocol without requiring GitHub, GitLab, or another forge. The commands below are verified against ACK main as of 21 July 2026:

ack profile validate .ack/ack.yaml
ack pull-request check \
  --profile .ack/ack.yaml \
  .ack/pull-requests/bind-service-token-audiences.yaml
ack pull-request verify \
  --profile .ack/ack.yaml \
  --repo . \
  --head HEAD \
  .ack/pull-requests/bind-service-token-audiences.yaml

check validates the narrative, lifecycle, targets, migrations, disclosure, and evidence shape. verify proves that the recorded base is an ancestor of the selected head, that the record still describes that head, and that linked release decisions do not contradict its targets. A later push makes the evidence revision stale and closes the gate until the record is reviewed again.

Creating a remote pull request is a separate authorized action. The core tool does not need forge credentials to decide whether the review artifact is coherent.

The complete workflow preserves judgment once

The six specifications are not six forms to fill in. They keep distinct decisions at the point where evidence is strongest:

  • commits preserve atomic implementation intent;
  • pull requests preserve integration reasoning and review evidence;
  • changesets preserve release decisions spanning implementation boundaries;
  • changelog records preserve consumer-facing history;
  • manifests preserve publication evidence; and
  • the Project Profile gives all of them the same names and routing rules.

The payoff is not more YAML. It is less archaeology, less release-day prose generation, fewer confident guesses, and review context that survives the platform where the conversation happened.