diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Changelog
 
+## 0.1.0.2 - 2026-07-22
+
+- Documentation: each public front door — `Moonlight.Delta.Patch`,
+  `Moonlight.Delta.Signed`, `.Scope`, `.Frontier`, `.Epoch`, and
+  `Moonlight.Delta.Repair` — now carries a module-header overview and a worked
+  recipe. The README is reduced to a dependency and front-door map.
+
 ## 0.1.0.1 - 2026-07-21
 
 - DeltaHash protocol v3 (`deltaHashEncodingVersion`) replaces v2. Merkle leaves
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -7,205 +7,10 @@
 multiplicities, invalidation scopes, frontiers, epochs, monotone operators, and bounded
 repair. Operations return typed incompatibilities where a transition cannot be applied.
 
-## Main idea
-
-A `CellPatch value` records both endpoints of one keyed transition: absent to absent,
-absent to present, present to absent, or present to present. Build cells with
-`assertAbsent`, `insert`, `delete`, `replace`, or `cellFromEndpoints`. `apply` checks
-the before endpoint, and `compose` checks that adjacent endpoints connect.
-
-Use patches for concurrent updates, retries, synchronization, authorization-sensitive
-changes, and reconciliation.
-
-## Use
-
-```haskell
-import Data.Map.Strict (Map)
-import Data.Map.Strict qualified as Map
-import Moonlight.Delta.Patch qualified as Patch
-
-changeTitle :: Patch.Patch Int String
-changeTitle = Patch.singleton 7 (Patch.replace "Draft" "Published")
-
-committed
-  :: Either (Patch.ApplyError Int String) (Map Int String)
-committed = Patch.apply changeTitle (Map.singleton 7 "Draft")
-```
-
-## Cookbook
-
-### Compose and replay patches
-
-`compose newer older` collapses two connected transitions. `replay` applies a
-chronological sequence and reports the failing index.
-
-```haskell
-import Data.Map.Strict (Map)
-import Data.Map.Strict qualified as Map
-import Moonlight.Delta.Patch qualified as Patch
-
-draft, reviewed, published :: Map Int String
-draft = Map.singleton 7 "Draft"
-reviewed = Map.singleton 7 "Review"
-published = Map.singleton 7 "Published"
-
-draftToReview, reviewToPublished :: Patch.Patch Int String
-draftToReview = Patch.diff draft reviewed
-reviewToPublished = Patch.diff reviewed published
-
-publication
-  :: Either (Patch.ComposeError Int String) (Patch.Patch Int String)
-publication = Patch.compose reviewToPublished draftToReview
-
-replayed
-  :: Either (Patch.ReplayError Int String) (Map Int String)
-replayed = Patch.replay [draftToReview, reviewToPublished] draft
-
-history
-  :: Either (Patch.ComposeError Int String) (Patch.Patch Int String)
-history =
-  Patch.recordMany
-    [ (7, Patch.replace "Draft" "Review")
-    , (7, Patch.replace "Review" "Published")
-    ]
-```
-
-Use `invert` to reverse a patch. Repeated temporal keys belong in `recordMany`;
-`fromList` instead means authoritative, last-wins rows.
-
-### Apply signed multiplicities
-
-`Signed` stores integer changes while the state retains non-negative multiplicities.
-
-```haskell
-import Data.Map.Strict (Map)
-import Data.Map.Strict qualified as Map
-import Moonlight.Delta.Signed qualified as Signed
-
-inventory :: Map String Signed.Multiplicity
-inventory = Map.singleton "rose" (Signed.Multiplicity 2)
-
-sale :: Signed.Signed String
-sale = Signed.signedFromList [("rose", -1), ("lily", 2)]
-
-afterSale
-  :: Either
-       (Signed.SignedApplyError String)
-       (Map String Signed.Multiplicity)
-afterSale = Signed.applySignedToMap sale inventory
-```
-
-An underflow returns `SignedMultiplicityUnderflow`; a zero result removes the row.
-Combine changes with `combineSigned` and reverse one with `negateSigned`.
-
-### Bound invalidation with a scope
-
-`Scope` distinguishes no invalidation, a finite dirty set, and global invalidation.
-
-```haskell
-import Data.Set (Set)
-import Data.Set qualified as Set
-import Moonlight.Delta.Scope qualified as Scope
-
-dirtyPages :: Scope.Scope (Set Int)
-dirtyPages = Scope.dirtyScope (Set.fromList [2, 7])
-
-visibleDirtyPages :: Scope.Scope (Set Int)
-visibleDirtyPages = Scope.restrictScope (Set.singleton 7) dirtyPages
-```
-
-`scopeKeys` returns `Nothing` for `fullScope`.
-
-### Track two-axis progress
-
-`ProductFrontier2` canonicalizes a two-dimensional progress skyline by removing
-dominated points.
-
-```haskell
-import Moonlight.Delta.Frontier qualified as Frontier
-
-progress :: Frontier.ProductFrontier2 Int Int
-progress = Frontier.mkProductFrontier2 [(0, 3), (1, 2), (2, 1), (3, 0)]
-
-covered :: Bool
-covered = Frontier.productFrontier2Contains (2, 2) progress
-```
-
-Use `mkFrontier` or `mkUpperFrontier` for a general `PartialOrder`.
-
-### Transport keys across an epoch
-
-An `EpochDelta` checks a partial transport between versioned key universes. A query is
-partitioned into transported, retired, and unknown keys.
-
-```haskell
-import Data.IntMap.Strict (IntMap)
-import Data.IntMap.Strict qualified as IntMap
-import Data.IntSet (IntSet)
-import Data.IntSet qualified as IntSet
-import Moonlight.Delta.Epoch qualified as Epoch
-
-source, target :: Epoch.Endpoint IntSet
-source = Epoch.Endpoint Epoch.initialVersion (IntSet.fromList [10, 20])
-target =
-  Epoch.Endpoint
-    (Epoch.nextVersion Epoch.initialVersion)
-    (IntSet.fromList [11, 30])
-
-advance
-  :: Either
-       (Epoch.DeltaViolation Int)
-       (Epoch.EpochDelta (IntMap Int) IntSet)
-advance =
-  Epoch.epochDelta
-    source
-    target
-    (IntMap.singleton 10 11)
-    (IntSet.singleton 20)
-    (IntSet.singleton 10)
-
-query
-  :: Either (Epoch.DeltaViolation Int) (Epoch.Transport (IntMap Int) IntSet)
-query =
-  fmap
-    (\deltaValue -> Epoch.transportKeys deltaValue (IntSet.fromList [10, 20, 99]))
-    advance
-```
-
-Invalid versions, universes, transports, retirements, or changed keys return a
-`DeltaViolation`. Here `query` partitions `10 -> 11`, retired `20`, and unknown `99`;
-changed key `10` and fresh key `30` determine the dirty target set.
-
-### Run bounded repair
-
-A repair `Kernel` checks obstructions, turns repairable ones into corrections, and
-applies those corrections under explicit fuel.
-
-```haskell
-import Data.List.NonEmpty (NonEmpty ((:|)))
-import Moonlight.Delta.Repair qualified as Repair
-
-data TooSmall = TooSmall Int
-data Increment = Increment
-
-incrementKernel :: Int -> Repair.Kernel Int TooSmall Increment
-incrementKernel target =
-  Repair.Kernel
-    { Repair.check = \state ->
-        if state >= target
-          then Repair.StepConverged state
-          else Repair.StepObstructed state (TooSmall target :| [])
-    , Repair.residuate = \_ -> Just Increment
-    , Repair.applyKernelCorrection = \state Increment -> state + 1
-    }
-
-repaired :: Repair.Result Int TooSmall
-repaired = Repair.boundedRepair (incrementKernel 2) (Repair.Config 4) 0
-```
-
-The result is `ResultConverged 2 2`; the other terminal cases are `ResultStuck` and
-`ResultBudgetExhausted`. Compose kernels with `sequenceRepair`, `productRepair`, or
-`focusRepair`.
+Each public front door — `Moonlight.Delta.Patch`, `Moonlight.Delta.Signed`,
+`.Scope`, `.Frontier`, `.Epoch`, and `Moonlight.Delta.Repair` — carries its own
+overview and a worked recipe in its module header; there is no umbrella. The
+table below maps each dependency to its front door.
 
 ## Surface & boundaries
 
diff --git a/moonlight-delta.cabal b/moonlight-delta.cabal
--- a/moonlight-delta.cabal
+++ b/moonlight-delta.cabal
@@ -1,6 +1,6 @@
 cabal-version:       3.0
 name:                moonlight-delta
-version:             0.1.0.1
+version:             0.1.0.2
 synopsis:            Boundary-aware delta calculus for Moonlight.
 description:         Categorical and state-change delta vocabulary layered over moonlight-core.
 license:             MIT
diff --git a/src-core/Moonlight/Delta/Frontier.hs b/src-core/Moonlight/Delta/Frontier.hs
--- a/src-core/Moonlight/Delta/Frontier.hs
+++ b/src-core/Moonlight/Delta/Frontier.hs
@@ -1,6 +1,20 @@
 {-# LANGUAGE DerivingStrategies #-}
 
--- | Antichain frontiers over partial orders (lower, upper, and two-dimensional product variants), answering containment queries.
+{-|
+Antichain frontiers over partial orders: lower, upper, and two-dimensional
+product variants, answering containment queries. @ProductFrontier2@
+canonicalizes a two-dimensional progress skyline by removing dominated points.
+
+> import Moonlight.Delta.Frontier qualified as Frontier
+>
+> progress :: Frontier.ProductFrontier2 Int Int
+> progress = Frontier.mkProductFrontier2 [(0, 3), (1, 2), (2, 1), (3, 0)]
+>
+> covered :: Bool
+> covered = Frontier.productFrontier2Contains (2, 2) progress
+
+Use @mkFrontier@ or @mkUpperFrontier@ for a general @PartialOrder@.
+-}
 module Moonlight.Delta.Frontier
   ( Frontier,
     UpperFrontier,
diff --git a/src-core/Moonlight/Delta/Scope.hs b/src-core/Moonlight/Delta/Scope.hs
--- a/src-core/Moonlight/Delta/Scope.hs
+++ b/src-core/Moonlight/Delta/Scope.hs
@@ -3,7 +3,22 @@
 {-# LANGUAGE StandaloneKindSignatures #-}
 {-# LANGUAGE TypeFamilies #-}
 
--- | Dirty-scope tracking with one type-indexed notion of emptiness.
+{-|
+Dirty-scope tracking with one type-indexed notion of emptiness. A @Scope@
+distinguishes no invalidation, a finite dirty set, and global invalidation.
+
+> import Data.Set (Set)
+> import Data.Set qualified as Set
+> import Moonlight.Delta.Scope qualified as Scope
+>
+> dirtyPages :: Scope.Scope (Set Int)
+> dirtyPages = Scope.dirtyScope (Set.fromList [2, 7])
+>
+> visibleDirtyPages :: Scope.Scope (Set Int)
+> visibleDirtyPages = Scope.restrictScope (Set.singleton 7) dirtyPages
+
+@scopeKeys@ returns @Nothing@ for @fullScope@.
+-}
 module Moonlight.Delta.Scope
   ( ScopeCarrier (..),
     Scope,
diff --git a/src-core/Moonlight/Delta/Signed.hs b/src-core/Moonlight/Delta/Signed.hs
--- a/src-core/Moonlight/Delta/Signed.hs
+++ b/src-core/Moonlight/Delta/Signed.hs
@@ -2,7 +2,28 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeFamilies #-}
 
--- | Integer-signed multiplicities and their changes: states stay non-negative, deltas carry sign, application is checked ('SignedApplyError').
+{-|
+Integer-signed multiplicities and their changes: states stay non-negative,
+deltas carry sign, application is checked. A @Signed@ stores integer changes
+while the state retains non-negative @Multiplicity@ values.
+
+> import Data.Map.Strict (Map)
+> import Data.Map.Strict qualified as Map
+> import Moonlight.Delta.Signed qualified as Signed
+>
+> inventory :: Map String Signed.Multiplicity
+> inventory = Map.singleton "rose" (Signed.Multiplicity 2)
+>
+> sale :: Signed.Signed String
+> sale = Signed.signedFromList [("rose", -1), ("lily", 2)]
+>
+> afterSale
+>   :: Either (Signed.SignedApplyError String) (Map String Signed.Multiplicity)
+> afterSale = Signed.applySignedToMap sale inventory
+
+An underflow returns @SignedMultiplicityUnderflow@; a zero result removes the
+row. Combine changes with @combineSigned@ and reverse one with @negateSigned@.
+-}
 module Moonlight.Delta.Signed
   ( Multiplicity (..),
     MultiplicityChange (..),
diff --git a/src-epoch/Moonlight/Delta/Epoch.hs b/src-epoch/Moonlight/Delta/Epoch.hs
--- a/src-epoch/Moonlight/Delta/Epoch.hs
+++ b/src-epoch/Moonlight/Delta/Epoch.hs
@@ -1,14 +1,45 @@
--- | The epoch calculus: version-anchored key transport between endpoint
--- snapshots.
---
--- 'Version' is an opaque, unbounded epoch counter. An 'Endpoint' pairs a
--- version with the result-key universe observed at that instant. An
--- 'EpochDelta' is an abstract partial transport: source keys either descend to
--- target keys or retire, and the carrier owns its target-side dirty set.
---
--- 'ContextProjectionDelta' is the bounded join-semilattice of dirty-key
--- pairs; its 'Data.Semigroup.Semigroup'/'Data.Monoid.Monoid' structure is
--- the seam consumed upstream and is preserved verbatim.
+{-|
+The epoch calculus: version-anchored key transport between endpoint snapshots.
+
+@Version@ is an opaque, unbounded epoch counter. An @Endpoint@ pairs a version
+with the result-key universe observed at that instant. An @EpochDelta@ is an
+abstract partial transport: source keys either descend to target keys or retire,
+and the carrier owns its target-side dirty set. @ContextProjectionDelta@ is the
+bounded join-semilattice of dirty-key pairs; its @Semigroup@ and @Monoid@
+structure (from "Data.Semigroup" and "Data.Monoid") is the seam consumed
+upstream and is preserved verbatim.
+
+A query against an @EpochDelta@ is partitioned into transported, retired, and
+unknown keys.
+
+> import Data.IntMap.Strict (IntMap)
+> import Data.IntMap.Strict qualified as IntMap
+> import Data.IntSet (IntSet)
+> import Data.IntSet qualified as IntSet
+> import Moonlight.Delta.Epoch qualified as Epoch
+>
+> source, target :: Epoch.Endpoint IntSet
+> source = Epoch.Endpoint Epoch.initialVersion (IntSet.fromList [10, 20])
+> target =
+>   Epoch.Endpoint
+>     (Epoch.nextVersion Epoch.initialVersion)
+>     (IntSet.fromList [11, 30])
+>
+> advance
+>   :: Either (Epoch.DeltaViolation Int) (Epoch.EpochDelta (IntMap Int) IntSet)
+> advance =
+>   Epoch.epochDelta source target
+>     (IntMap.singleton 10 11) (IntSet.singleton 20) (IntSet.singleton 10)
+>
+> query
+>   :: Either (Epoch.DeltaViolation Int) (Epoch.Transport (IntMap Int) IntSet)
+> query =
+>   fmap (\d -> Epoch.transportKeys d (IntSet.fromList [10, 20, 99])) advance
+
+Invalid versions, universes, transports, retirements, or changed keys return a
+@DeltaViolation@. Here @query@ partitions @10 -> 11@, retired @20@, and unknown
+@99@; changed key @10@ and fresh key @30@ determine the dirty target set.
+-}
 module Moonlight.Delta.Epoch
   ( Version,
     initialVersion,
diff --git a/src-patch-public/Moonlight/Delta/Patch.hs b/src-patch-public/Moonlight/Delta/Patch.hs
--- a/src-patch-public/Moonlight/Delta/Patch.hs
+++ b/src-patch-public/Moonlight/Delta/Patch.hs
@@ -1,3 +1,43 @@
+{-|
+Checked keyed transitions. A @CellPatch value@ records both endpoints of one
+keyed change — absent→absent, absent→present, present→absent, or
+present→present. Build cells with @assertAbsent@, @insert@, @delete@, @replace@,
+or @cellFromEndpoints@; @apply@ checks the before endpoint and @compose@ checks
+that adjacent endpoints connect. Use patches for concurrent updates, retries,
+synchronization, authorization-sensitive changes, and reconciliation.
+
+/Apply a patch./
+
+> import Data.Map.Strict (Map)
+> import Data.Map.Strict qualified as Map
+> import Moonlight.Delta.Patch qualified as Patch
+>
+> changeTitle :: Patch.Patch Int String
+> changeTitle = Patch.singleton 7 (Patch.replace "Draft" "Published")
+>
+> committed :: Either (Patch.ApplyError Int String) (Map Int String)
+> committed = Patch.apply changeTitle (Map.singleton 7 "Draft")
+
+/Compose and replay./ @compose newer older@ collapses two connected transitions;
+@replay@ applies a chronological sequence and reports the failing index. @invert@
+reverses a patch. Repeated temporal keys belong in @recordMany@; @fromList@ means
+authoritative, last-wins rows.
+
+> draft, reviewed, published :: Map Int String
+> draft = Map.singleton 7 "Draft"
+> reviewed = Map.singleton 7 "Review"
+> published = Map.singleton 7 "Published"
+>
+> draftToReview, reviewToPublished :: Patch.Patch Int String
+> draftToReview = Patch.diff draft reviewed
+> reviewToPublished = Patch.diff reviewed published
+>
+> publication :: Either (Patch.ComposeError Int String) (Patch.Patch Int String)
+> publication = Patch.compose reviewToPublished draftToReview
+>
+> replayed :: Either (Patch.ReplayError Int String) (Map Int String)
+> replayed = Patch.replay [draftToReview, reviewToPublished] draft
+-}
 module Moonlight.Delta.Patch
   ( CellPatch,
     PatchKey,
diff --git a/src-repair/Moonlight/Delta/Repair.hs b/src-repair/Moonlight/Delta/Repair.hs
--- a/src-repair/Moonlight/Delta/Repair.hs
+++ b/src-repair/Moonlight/Delta/Repair.hs
@@ -1,5 +1,34 @@
 {-# LANGUAGE DerivingStrategies #-}
 
+{-|
+Bounded obstruction repair. A repair @Kernel@ checks obstructions, turns
+repairable ones into corrections, and applies those corrections under explicit
+fuel. The terminal cases are @ResultConverged@, @ResultStuck@, and
+@ResultBudgetExhausted@.
+
+> import Data.List.NonEmpty (NonEmpty ((:|)))
+> import Moonlight.Delta.Repair qualified as Repair
+>
+> data TooSmall = TooSmall Int
+> data Increment = Increment
+>
+> incrementKernel :: Int -> Repair.Kernel Int TooSmall Increment
+> incrementKernel target =
+>   Repair.Kernel
+>     { Repair.check = \state ->
+>         if state >= target
+>           then Repair.StepConverged state
+>           else Repair.StepObstructed state (TooSmall target :| [])
+>     , Repair.residuate = \_ -> Just Increment
+>     , Repair.applyKernelCorrection = \state Increment -> state + 1
+>     }
+>
+> repaired :: Repair.Result Int TooSmall
+> repaired = Repair.boundedRepair (incrementKernel 2) (Repair.Config 4) 0
+
+The result is @ResultConverged 2 2@. Compose kernels with @sequenceRepair@,
+@productRepair@, or @focusRepair@.
+-}
 module Moonlight.Delta.Repair
   ( Kernel (..),
     Step (..),
