packages feed

moonlight-delta-0.1.0.0: README.md

# moonlight-delta

> Part of **Moonlight**, the sheaf-theoretic computation layer beneath
> [Melusine](https://bluerose.blue) and Pale Meridian.

`moonlight-delta` is Moonlight's checked state-change algebra: keyed patches, signed
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`.

## Surface & boundaries

There is no umbrella library. Depend on the smallest public slice you use.

| Cabal dependency | Import | What you get |
| --- | --- | --- |
| `moonlight-delta:moonlight-delta-core` | `Moonlight.Delta.Signed`, `.Scope`, `.Frontier`, `.Monotone`, `.Normalize`, `.Support`, `.Operator`, `.Time` | Signed changes, invalidation, progress frontiers, operators, and their shared laws. |
| `moonlight-delta:moonlight-delta-patch` | `Moonlight.Delta.Patch` | Checked keyed transitions, composition, diff, inversion, and replay. |
| `moonlight-delta:moonlight-delta-epoch` | `Moonlight.Delta.Epoch` | Versioned partial key transport and view restamping. |
| `moonlight-delta:moonlight-delta-repair` | `Moonlight.Delta.Repair` | Bounded obstruction repair and kernel composition. |

## Test

```bash
cabal test moonlight-delta:moonlight-delta-test
```

## License

MIT. See `LICENSE`.