Definition of Done — the user completes the job in a screen

Why this exists

On 2026-09-26 an audit of iec-ledger found months of work reported "done" that an accountant could not use: 48 vendor fields in the API schema and 11 in the form; bills with no vendor invoice number; reports with an export and no page; a Pay Bills screen that looped payments client-side. Every one of those PRs had green tests and merged. Nothing in the pipeline had asked whether the person the feature was for could do the job. This convention makes that the question, and a merge-gate hook asks it mechanically.

The rule

A change is done only when all of these hold:

  1. The user can complete the story in a screen. The issue's story ("As a <role>, I need to <do> so that <outcome>") was driven end to end in a browser against a running build of this change, by the agent or dev who built it. "API only, UI to follow" is a status, not done.
  2. Field parity. Every field the API accepts on a record is in the form, or is listed as intentionally hidden with a reason. Repos with forms carry a parity lint (iec-ledger: npm run lint:parity, a ratchet that fails only on new gaps).
  3. Reference behaviour cited. The PR names what the reference system does (for accounting: QuickBooks Online, Sage Intacct, NetSuite, Applied Epic/AMS360, Vertafore AIM, the accounting bible) and where this matches or deliberately differs.
  4. Evidence in the PR body under ## Walkthrough: the story, the screen steps driven, a Reference: line, and proof. Preferred proof is a tawa walkthrough page (asserted screenshots, public link); a screenshot/GIF or a docs/qa/issue-N-*.md execution log also counts.
  5. QA execution log for changes to routes, models, services, pages or components: a ## QA Execution section with real, dated output, or a changed docs/qa/issue-N-*.md. Mocked unit tests alone do not satisfy this.
  6. Vertical slice. One issue spans API and UI. A backend-only PR must link the UI issue opened in the same PR and say so.
  7. Honest completion. The final message names what was not done and why. A parent agent never reports a fan-out complete when a child failed or was rate-limited.

Escape hatch

DoD-exempt: <reason, 20+ characters> in the PR body. The gate allows the merge and surfaces the reason. For infrastructure, docs, and platform plumbing, not for "UI later". Docs-only PRs (only .md, docs/, .forgejo/) are exempt automatically.

The merge-gate hook

scripts/pr-merge-gate.sh in this repo is a Claude Code PreToolUse hook on any MCP tool named *git_pr_merge. It fetches the PR from Forgejo with the machine's stored git credential and denies the merge when the body lacks the sections above. Install on every machine that merges:

mkdir -p ~/.claude/hooks && cp scripts/pr-merge-gate.sh ~/.claude/hooks/ && chmod +x ~/.claude/hooks/pr-merge-gate.sh

Then add to ~/.claude/settings.json:

{ "hooks": { "PreToolUse": [ { "matcher": "mcp__.*git_pr_merge",
  "hooks": [ { "type": "command", "command": "~/.claude/hooks/pr-merge-gate.sh", "timeout": 45 } ] } ] } }

Decisions are appended to ~/.claude/hooks/pr-merge-gate.log. Test without merging:

echo '{"tool_input":{"repo":"iec-ledger","index":<pr>}}' | ~/.claude/hooks/pr-merge-gate.sh
DOD_GATE_TEST_BODY='## Walkthrough ...' bash -c 'echo ... | ~/.claude/hooks/pr-merge-gate.sh'

The strict QA-log requirement applies to insureco/iec-ledger, iec-ledger-ui and icap-portal; edit ledger_repos in the script to add a repo.

Issue and PR templates

Repos adopting this carry .forgejo/issue_template/{feature,bug}.md (story, screen-step acceptance criteria, Reference, API + UI checkboxes, out-of-scope) and .forgejo/pull_request_template.md (Walkthrough, QA Execution, Not done in this PR). Copy them from iec-ledger.

What this does not replace

  • The Agile workflow: issues first, PR-only main, self-merge when green. This convention defines what "green" must include.
  • The QA & regression discipline: dossiers, risk tiers, live E2E. This convention is the gate that makes the dossier non-optional for code that touches the user.
  • Walkthroughs: the preferred way to produce the evidence.

Common mistakes

  • Closing an issue when the schema landed and the form did not.
  • Reporting a report "built" when it has no page.
  • Modelling a business document as a bare GL transaction because the posting engine already existed.
  • Writing the Walkthrough from memory instead of from the browser.
  • Using DoD-exempt for "UI in a later PR".
  • Widening the parity baseline to make the lint pass.

Last updated: October 6, 2026