Production set tracker — every discovery production, on one screen

Every Bates batch becomes a production record with recipient, date, Bates range, and the EXACT version hash of every doc delivered. Closes the discovery production loop.

Updated 2026-05-26

/productions answers the question every partner asks: "what did we produce on Jan 15 to opposing counsel, and which docs did we hold back?"

**The flow:**

1. Build your privilege log on /privilege-log v2 (classify what to withhold). 2. Redact partially-privileged docs at /doc/[id]/redact (burn black rectangles into a new immutable version). 3. Stamp Bates onto the production set at /bates-stamp. 4. From the Bates result table, click **Record as production** — type a production name, recipient, matter ref, optional notes, click Record. Kodori inserts a production record + per-doc rows capturing the EXACT version hash of every doc that was just stamped. 5. The production lands on /productions. Click into it to see the document set with per-doc Bates BEG/END + page count + version hash.

**Why version-hash capture matters.** A later re-stamp on the same doc creates a NEW version. Without version-hash capture, "what did we produce?" would point at the latest version — which isn't what was delivered. Productions store the version hash that existed when the production was recorded, so the produced-bytes story stays accurate forever. If the doc's current version differs from the produced one, the table shows an "archived" badge so reviewers know they're looking at the produced bytes.

**Production fields:**

- *name* — short label ("Production Set 1", "Rolling production — first wave") - *recipient* — who got it ("Opposing counsel — Jones & Smith LLP", "Court — ECF filing", "Government — DOJ Antitrust Division") - *matter ref* — case caption / number ("Smith v. Acme — 24-cv-1234") - *Bates range* — overall BEG / END across the production - *privilegeLogSourceKind / privilegeLogSourceId* — pointer to the privilege log used (collection or saved search), so a future audit can reconstruct the withheld vs. produced split

**Audit chain.** Each production fires `production.recorded` on the hash-chained audit log with the document count, recipient, Bates range, and privilege-log source. Webhook subscribers can react — common pattern: post to a Slack channel when a production is recorded so the matter team gets notified.

**Programmable.** `recordProduction` is an MCP tool — automations can record productions on a trigger ("when these N docs are stamped, record a production with recipient X"). External MCP clients (Claude Desktop, Cursor, Kodokyo) call the same tool. The /api/v1 REST surface exposes the same shape.

**Production set diff.** Open /productions/diff (or click "Diff with another production →" on any production detail page) to compare two production sets side-by-side. Three sections: only-in-A (amber), in-both (neutral), only-in-B (emerald). Per-row Bates ranges from each side surface so you can verify "did we re-produce X with the same Bates range?" or "was this doc dropped between rolling sets?" In-both rows flag versionChanged when the same documentId was produced with different versionHashes (re-stamped or re-redacted) — usually intentional but worth verifying against the privilege log. Useful for FRCP rolling-production hygiene + opposing-counsel sanity checks.

**Search + matter filter.** Firms with 30+ productions can't scroll-find. /productions has a search input filtering across name + recipient + matterRef + bates prefix + bates range (substring, case-insensitive) and a matter dropdown auto-populated from distinct matterRefs. URL-state captured so filter combinations are bookmarkable. "Showing N of M" counter when filters are applied.

**Manifest CSV export.** Click "Download manifest CSV ↓" on /productions/[id] to get the standard ediscovery deliverable opposing counsel expects alongside the production share-link. The CSV streams one row per produced doc with documentId, batesBeg, batesEnd, pageCount, displayName, mimeType, sensitivityLabel, and the EXACT versionHash captured at production-recording time (NOT the current version — re-stamps and post-production redactions never silently change what the manifest says was delivered). Header preamble carries production name + matter ref + recipient + produced-at + Bates range + doc count, formatted as `#`-prefixed lines that ediscovery vendors' ingestion scripts (Concordance, Relativity, etc.) detect and skip. Sorted by Bates ranges (asc) so the manifest tracks the produced page sequence.

**Coming next:** matter binder export (one-click compile a production into a single bookmarked PDF for delivery); public share links (tokenized read-only URLs so opposing counsel gets a link, not an account).