---
name: backlog-reconciliation
description: "Tie every open tracker row to the actual source tree and find the rows the board is lying about. Classifies each open row as shipped-under-a-different-commit, built-but-one-step-from-live, genuinely open, or referencing a commit that no longer resolves. READ-ONLY — it surfaces and classifies, a human closes. Reach for it after a multi-lane sprint or when the open count feels wrong."
---

# Backlog Reconciliation

## The one idea

**A board is a claim about the source tree, and claims get reconciled.**

An open row asserts that something is not built. That assertion was true when
it was written, and nothing checks it afterwards. Rows close when someone
remembers to close them, which means the board's error is not random — it is
**directional**. It over-reports open work, always, and the drift grows fastest
in exactly the weeks when the most shipped.

The reconciliation is the same move an accountant makes against a bank
statement: take the ledger, take the ground truth, tie each line to evidence,
and produce a list of the differences. The board is the ledger. The source
tree and its history are the statement. The output is not a cleanup — it is
the list of rows whose stated position does not match the evidence.

> **Do not ask the board what is open. Ask the tree, and diff.**

## When to reach for this

- **After any multi-lane sprint.** Parallel lanes are where the drift is
  manufactured: one lane's build satisfies another lane's row, and neither
  lane knows. Nobody closes a row they did not open.
- **When the open count feels wrong.** That feeling is usually right, and it
  is usually right in the over-reporting direction.
- **When a row looks stale-open** — old, untouched, still open. That is
  precisely the shape of a row that shipped under a subject line nobody
  connected to it.
- **Before any planning session that uses the open count as an input.**
  Planning against an inflated board buys work that already exists.

Not a weekly ritual. Reach for it on the trigger, not the calendar — a
reconciliation with nothing to find is how the practice earns a reputation for
being ceremony.

## The anatomy — the moves that make it work

1. **Bind by evidence, never by subject line.** A commit whose message names a
   row is the easy case and the rare one. The hard case — and the whole value
   — is a row satisfied by a commit that never mentions it. Bind on what the
   row *asked for*: the file that had to change, the function that had to
   exist, the behaviour that had to be observable. *Why:* subject-line matching
   only ever re-finds the rows somebody already remembered to link, which are
   the rows least likely to be wrong.

2. **Read the tree, not the history alone.** History says a change was made;
   the tree says what is there now. A row can be satisfied by code that was
   later reverted, and can be satisfied by code that arrived with no commit
   naming it at all. Check both, and where they disagree, say so — that
   disagreement is itself a finding.

3. **Four classes, and every open row gets exactly one.** The classes are the
   product; a reconciliation that returns prose returns nothing actionable:

   | Class | What it means | What the human does |
   |---|---|---|
   | **SHIPPED-ELSEWHERE** | The row's ask exists in the tree, delivered under a commit that never named it | Close it, citing the evidence |
   | **ONE-STEP-FROM-LIVE** | Built, present, and gated behind one remaining action — a flag, a promotion, a human yes | Take the step, or say why not |
   | **GENUINELY-OPEN** | No evidence in the tree; the row is telling the truth | Leave it |
   | **DANGLING-REF** | The row cites a commit, file, or artifact that no longer resolves | Investigate — this is the class that hides a revert |

4. **ONE-STEP-FROM-LIVE is the class worth building the whole pass for.** It is
   finished work sitting behind a switch nobody flipped, and it will never
   surface on its own: the builder considers it done, the board considers it
   open, and both are locally correct. It is also, reliably, the cheapest
   value in the entire backlog.

5. **DANGLING-REF is where the real defect hides.** A row pointing at
   something that no longer resolves means either the record is wrong or the
   work was undone. Both matter, and they are indistinguishable from the row
   alone. Never auto-close this class — it is the one that most looks like
   housekeeping and most often is not.

6. **Cite evidence per row, or do not classify it.** Every non-open
   classification carries the specific thing that justifies it — the path, the
   symbol, the observable behaviour. *Why:* a human is going to close rows
   based on this, and a classification they cannot check in ten seconds is one
   they must either take on faith or redo. Both defeat the purpose.

7. **Report what you could not decide.** An UNDECIDABLE list is a legitimate
   and valuable output. Rows whose ask is too vague to bind against anything
   are themselves a finding — that is a row that can never be honestly closed,
   and rewriting it is the fix.

## The law: it is READ-ONLY

**It surfaces and classifies. A human closes.**

Nothing about this pass mutates the board. Not the obvious ones, not the ones
with overwhelming evidence, not the "just tidying" ones. Three reasons, and
the third is the one that matters:

- The evidence can be right and the conclusion wrong. A row's ask can be
  satisfied in the tree by something built for a different purpose.
- Closing is a statement about intent, and intent is not in the source tree.
- **An auto-closing reconciler destroys its own evidence.** Once it closes the
  rows, the next run has nothing to compare against, and nobody can audit
  whether the last run was any good. A read-only pass can be run twice and
  produce the same answer, which is the only reason to believe it at all.

## Template (skeleton)

```
RECONCILIATION — <date> · board at <version/ref> · tree at <ref>
Open rows in: <n>          Classified: <n>          Undecidable: <n>

SHIPPED-ELSEWHERE        (close these, evidence attached)
  <row> — asked for <ask>
          evidence: <path / symbol / observable behaviour>
          delivered under: <the change that satisfied it, which never named it>

ONE-STEP-FROM-LIVE       (the cheapest value on the board)
  <row> — built and present at <evidence>
          remaining step: <the flag / promotion / human yes>
          owner: <who can take it>

GENUINELY-OPEN           (count only — the board is right about these)
  <n> rows

DANGLING-REF             (investigate; never auto-close)
  <row> — cites <ref>, which does not resolve
          reading: <record is stale> | <work was undone> | <cannot tell>

UNDECIDABLE
  <row> — the ask cannot be bound to anything checkable. Rewrite it.

NET: the board reports <n> open; the tree supports <n>. Over-report: <n>.
```

## Anti-patterns — the reconciliation that misleads

- **Matching on subject lines** → you re-find only the links someone already
  made, and report a clean board.
- **Closing rows as you go** → you destroy the evidence that would let anyone
  check your work, and the next run has no baseline.
- **Auto-closing DANGLING-REF** → a revert gets filed as housekeeping and the
  regression ships twice.
- **Classifying without citing** → the human has to redo the pass to trust it.
- **A prose summary instead of four classes** → nothing is actionable; the
  board is unchanged next week.
- **Running it on a schedule** → it becomes ceremony, and a pass with nothing
  to find teaches everyone to skip the pass that would have found something.
- **Reporting only the over-report** → under-reporting exists too, and a row
  that was closed on work that got reverted is the more dangerous direction.

## Provenance

Built after a sprint whose board reported a comfortable amount of open work
and whose tree said otherwise: several rows had been satisfied by commits from
a different lane, and one row that everyone believed shipped was pointing at
code that had been reverted a week earlier. The four classes are the shapes
that pass actually found. The read-only law was added immediately after —
the first version closed what it was confident about, and there was then no
way to tell whether it had been right.
