docpack Docs
Ctrl K
DRAFT Ran green 15 days ago Edit this page

Backfill receipt fingerprints with docpack fingerprint

howto · 1 run (1 green) · last corrected 2026-10-29 · docs/run-docpack-fingerprint.md

Contents 5 sections · ~1,872 tokens whole page · every section is individually addressable
  1. 1 When to use it ~90
  2. 2 Run it ~577
  3. 3 What it reads, and why from git ~348
  4. 4 Options that matter ~145
  5. 5 Gotchas ~539

Token figures are estimates — chars/4 (estimate — docpack has no tokenizer). Section run receipts are not shown: docpack’s runs: ledger records a run against a PAGE, never a section, so a per-section outcome would be invented.

docpack fingerprint is the one-time migration behind the receipt rule. Every checked, corrected and success entry records a fingerprint of the page text it vouched for, and a verified page whose text no longer matches its newest one is amber ("edited since its last receipt"). Entries written before that have no fingerprint, so the badge reads them as unknown and a page edited after one is still green. This verb works out what each page said when its newest such entry was recorded, writes that down, and so makes the rule apply to the receipts you already have. See an edit needs a receipt for the rule itself.

1When to use it

Run it once when you upgrade a repo that already has a ledger, before you rely on docpack audit to catch edits that never got a receipt. Run the dry run first: it lists exactly which verified pages will start failing the audit gate, which is the finding. It is local only — it needs the repository's history — and it is not an MCP tool.

2Run it

bash
docpack --root pack fingerprint

The default is a dry run. This is a two-page repo where one page was edited after its receipt was committed:

output
fingerprint: dry run — nothing was written. 2 page(s) have a newest checked/corrected/success entry with no fingerprint.
  [differs] docs/deploy-notes.md (id deploy-notes, verified): checked 2026-10-02, recorded in commit 010391b42073 2026-10-16 "add pages with receipts"; fingerprint fdc639f2c2d157b7 — the body has changed since — WILL GO AMBER
  [matches] docs/rollback-notes.md (id rollback-notes, verified): checked 2026-10-02, recorded in commit 010391b42073 2026-10-16 "add pages with receipts"; fingerprint b0473ff6c2cacc60 — the body is unchanged since — stays green
fingerprint: 1 stay green · 1 differ (1 verified page(s) will go amber) · 0 skipped · 0 written
fingerprint: not considered: 0 already stamped · 0 with no checked/corrected/success entry · 0 retired (superseded or quarantined)
fingerprint: re-run with --write to record these. A page that goes amber is cleared by re-reading its changed text and logging
             `docpack log <id> --outcome checked|corrected --note "..."` (edit first, log last).

Each row names the page, the entry it read (outcome and date), the commit that recorded that entry, the fingerprint of the page as that commit had it, and whether that equals the page today. --write makes the same run, prints the same report with [written] on each row, and adds one line to each page; git diff on the first page then shows this and nothing else:

bash
docpack --root pack fingerprint --write
output
@@ -9,6 +9,7 @@ runs:
   - date: "2026-10-02"
     agent: claude
     outcome: checked
+    fingerprint: fdc639f2c2d157b7
     note: read every claim against the deploy script
 ---

That is the whole change to the page: one inserted line. The edited page now fails docpack audit (edited since its last receipt (2026-10-02, checked)), and the way back is the usual one — re-read what changed, then log a receipt for the text as it stands:

bash
docpack --root pack log deploy-notes --outcome checked --note "re-read the CI sentence against the deploy workflow; it holds"
output
logged checked run on docs/deploy-notes.md (run #2)

3What it reads, and why from git

For each page it takes the newest vouching entry: the last checked, corrected or success in the ledger since the last quarantine marker — the same entry the badge reads, chosen by the same function. If that entry already has a fingerprint the page is skipped. Otherwise it finds the entry's lines in the file, asks git blame which commit last touched them, and reads the page at that commit.

It anchors on the commit that recorded the entry, never on the entry's date:. A receipt's date can precede its merge commit by weeks (a pull request's receipts are dated when written, not when merged), and reading the page as it stood on the date would flag pages that had not been edited since they were reviewed. When the lines of one entry come from more than one commit (a note reworded later), the earliest wins: it is the commit that made the claim. Blame ignores whitespace-only changes, so a commit that only re-indented the ledger or normalized line endings does not become the recording commit. An entry that is not committed yet is anchored on the working tree: it vouches for the text in the working tree by definition, so it reports as matching.

The comparison is by fingerprint, so only wording counts: a later commit that changed the frontmatter, the line endings or the trailing whitespace but not the words leaves the page green.

4Options that matter

  • --write — record the fingerprints. Without it nothing is written, not a byte.
  • <id|path> ... — restrict the run to those pages; an unknown one is an error.
  • --json — emit the same report as an object: dry_run, rows (per page: path, id, status, run with its index, date and outcome, commit, commit_date, subject, anchor, fingerprint, current_fingerprint, verdict of matches, differs or skipped, reason, written) and a summary with the counts.
  • --root <dir> — the pack root, as for every verb.

5Gotchas

  • It only touches the newest vouching entry of each page. That is the only one the rule reads. Older entries stay unfingerprinted, and so do pages with no checked, corrected or success entry at all. It never changes status:, reviewed: or any other field, and never adds an entry.
  • The write is one inserted line, checked before it is saved. The result must parse, differ from the original in exactly that one field of that one entry, and give the original back byte for byte when the line is removed. A page the splice will not vouch for — CRLF line endings, a flow-style runs: [...] ledger, an entry whose lines do not decode to the entry they should be — is skipped and reported, left byte-identical, never reserialized.
  • Unresolvable anchors are skipped, not guessed. A page that is not in HEAD yet (new, or renamed and uncommitted — it has no history to anchor on, and stamping it from the working tree would call an old receipt matching whatever the body now says), a blame that cannot attribute the lines, a page with no readable frontmatter at the recording commit, or a shallow clone whose oldest commit is the only candidate each produce a [skipped] row with the reason. Commit the page and run it again. Fetch the full history (git fetch --unshallow) and run it again.
  • It refuses outside a git work tree. Stamping the current body would mark every receipt as matching and silently switch the rule off, so there is no fallback.
  • Run it again after it finishes and nothing is left to do. A stamped page is skipped, so --write is safe to repeat; the second run reports every page under "already stamped".
  • Included pages are skipped. A page whose text comes from a source: file (a README read in place) has a stub with an empty body in git, and the receipt vouched for the source's text, which this backfill does not trace. It gets a [skipped] row naming the source file; a receipt logged on it from now on is fingerprinted at write time.
  • Retired pages are not considered. A superseded or quarantined page makes no trust claim to check, so it is counted and skipped.
Run history
● 2026-10-29 · corrected · “(note withheld from the public build)”
● 2026-10-28 · reconciled · claude
● 2026-10-15 · corrected · claude · “(note withheld from the public build)”
● 2026-10-15 · success · claude