ADR-0009: Batch staging review workflow

Status: Accepted Date: 2026-05-19

Context

AI must produce content faster than the user can review per-note, but full autopilot lets drift catch you weeks late. Need a workflow that gets bulk efficiency AND tight control.

Decision

Batch staging with two hard review gates.

Gate 1 — Ingestion review

When AI ingests a new resource:

  • AI shows: file count, heading structure, citation form sample
  • User confirms before AI produces any atomics from it
  • Prevents: ingesting a misformatted source and generating 50 broken-citation atomics downstream

Gate 2 — Batch review

For each work batch:

  1. AI processes a bounded chunk (e.g., one DP chapter)
  2. Output lands in /staging/{batch-id}/ — proposed notes + REVIEW.md
  3. User reviews in Obsidian or VS Code — edits, rejects, or accepts in place
  4. On approval, AI copies REVIEW.md to _meta/batch-reviews/{batch-id}.md, moves accepted files to final locations, updates Person/Glossary indexes, deletes the now-empty staging folder, and commits in one atomic operation. The REVIEW copy in _meta/batch-reviews/ plus git history of the staging commit together preserve the durable record — the live staging folder adds no signal once finalized.

Batch ID naming

Primary pattern: {resource-class}-{chapter-slug} (e.g., csg-01-03, br-07-methods-for-transitioning). Fallback for non-resource batches: short topic slug (e.g., worship-leader-grilling). Sequential batch-0## IDs are deprecated — they gave no signal about batch content without opening the file.

REVIEW.md

Every batch’s REVIEW.md includes:

  • Summary of what was added/changed
  • Tag requests (new tags AI wants to add, with justification)
  • Suspected duplicates AI couldn’t resolve
  • Proposed work section (see ADR-0014): open questions / proposed threads / stale wrestling
  • Cost report (script-mode only; see ADR-0011)

Variant: content-cleanup batches

Resource-ingestion batches (e.g., stage-2 PDF cleanup per ADR-0019) don’t produce atomics, so the standard Proposed-work / Tag-requests / Duplicates sections are not load-bearing. These batches use a content-cleanup REVIEW.md shape:

  • What changed — files created/modified, with paths
  • Heading map — sub-theme → sub-sub-theme → SMM-block layout produced
  • Cleanup decisions — heading re-leveling, OCR/footnote rewires, attribution-line normalization, judgment calls made (per the script-vs-AI split: AI handles judgment, flags rather than fixes when uncertain)
  • Flagged for human review — ambiguous passages AI deferred on rather than auto-fixed
  • Config diff — any quartz.config.ts / pre-commit hook changes the batch requires

If the batch produces atomics in addition to resource cleanup, append the standard Proposed-work / Tag-requests sections.

Pre-commit hook

A small Python script (~50 lines) enforces the AI hard rules from CONTEXT.md. AI cannot bypass — failed hook = failed commit = AI must fix and retry.

Alternatives considered

  • A. Full autopilot (no review gates): rejected — drift detected too late.
  • B. Per-note pre-commit review: rejected — every note = a conversation turn; slow, token-expensive, no chance to see notes in context of each other.
  • Review in chat instead of in Obsidian: rejected — chat review forces serial reading, loses spatial context. Obsidian/VS Code lets user see multiple drafts at once and catch duplicates.

Consequences

  • (+) Bulk efficiency with bounded review effort per sitting
  • (+) Spatial review (graph view, multi-file open) catches near-duplicates
  • (+) Pre-commit hook = drift insurance, hardcoded
  • (−) /staging/ adds folders to track during a batch, but they are deleted at finalize. Durable record = REVIEW.md copy in _meta/batch-reviews/{batch-id}.md + the staging commit in git history (e.g., git show <staging-commit> reproduces the exact proposals reviewed).
  • (−) Hook = a small piece of code to maintain (small price for the safety net)