diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,21 @@
 
 ## [Unreleased]
 
+## [0.8] - 2019-08-10
+### Added
+- Associated type `ReplicatedAsObject.Rep`
+- Function `correct`
+
+### Changed
+- Renamed `ObjectState` to `ObjectFrame`.
+- Simplified `Error` type
+- Type `StateChunk` is split into two new:
+  - `StateChunk` is tagged on Haskell-type-level with its RDT
+  - `WireStateChunk` has RDT as a field, isomorphic to the old `StateChunk`
+
+### Removed
+- Method `ReplicatedAsObject.objectOpType`
+
 ## [0.7] - 2019-07-26
 ### Added
 - Instance `ReplicaClock WriterT`.
@@ -115,9 +130,10 @@
   - RON-Schema
   - RON-Schema TemplateHaskell code generator
 
-[Unreleased]: https://github.com/ff-notes/ron/compare/v0.7...HEAD
-[0.7]: https://github.com/ff-notes/ron/compare/v0.6...v0.7
-[0.6]: https://github.com/ff-notes/ron/compare/v0.5...v0.6
+[Unreleased]: https://github.com/ff-notes/ron/compare/ron-0.8...HEAD
+[0.8]: https://github.com/ff-notes/ron/compare/ron-0.7...ron-0.8
+[0.7]: https://github.com/ff-notes/ron/compare/ron-0.6...ron-0.7
+[0.6]: https://github.com/ff-notes/ron/compare/v0.5...ron-0.6
 [0.5]: https://github.com/ff-notes/ron/compare/v0.4...v0.5
 [0.4]: https://github.com/ff-notes/ron/compare/v0.3...v0.4
 [0.3]: https://github.com/ff-notes/ron/compare/v0.2...v0.3
diff --git a/lib/Attoparsec/Extra.hs b/lib/Attoparsec/Extra.hs
--- a/lib/Attoparsec/Extra.hs
+++ b/lib/Attoparsec/Extra.hs
@@ -1,18 +1,18 @@
 {-# LANGUAGE OverloadedStrings #-}
 
-module Attoparsec.Extra
-    ( module Attoparsec
-    , char
-    , endOfInputEx
-    , isSuccessful
-    , label
-    , parseOnlyL
-    , takeL
-    , definiteDouble
-    , withInputSize
-    , (??)
-    , (<+>)
-    ) where
+module Attoparsec.Extra (
+    module Attoparsec,
+    char,
+    endOfInputEx,
+    isSuccessful,
+    label,
+    parseOnlyL,
+    takeL,
+    definiteDouble,
+    withInputSize,
+    (??),
+    (<+>),
+) where
 
 import           RON.Prelude
 
diff --git a/lib/Data/ZigZag.hs b/lib/Data/ZigZag.hs
--- a/lib/Data/ZigZag.hs
+++ b/lib/Data/ZigZag.hs
@@ -1,9 +1,9 @@
 -- Copyright (c) 2016, Pasqualino `Titto` Assini
 
-module Data.ZigZag
-    ( zzEncode
-    , zzDecode64
-    ) where
+module Data.ZigZag (
+    zzEncode,
+    zzDecode64,
+) where
 
 import           RON.Prelude
 
diff --git a/lib/RON/Base64.hs b/lib/RON/Base64.hs
--- a/lib/RON/Base64.hs
+++ b/lib/RON/Base64.hs
@@ -3,24 +3,24 @@
 {-# LANGUAGE OverloadedStrings #-}
 
 -- | RON version of Base64 encoding
-module RON.Base64
-    ( alphabet
-    , decode
-    , decode60
-    , decode60base32
-    , decode64
-    , decode64base32
-    , decodeLetter
-    , decodeLetter4
-    , encode
-    , encode60
-    , encode60short
-    , encode64
-    , encode64base32short
-    , encodeLetter
-    , encodeLetter4
-    , isLetter
-    ) where
+module RON.Base64 (
+    alphabet,
+    decode,
+    decode60,
+    decode60base32,
+    decode64,
+    decode64base32,
+    decodeLetter,
+    decodeLetter4,
+    encode,
+    encode60,
+    encode60short,
+    encode64,
+    encode64base32short,
+    encodeLetter,
+    encodeLetter4,
+    isLetter,
+) where
 
 import           RON.Prelude
 
@@ -203,11 +203,10 @@
 
 -- | Encode a 60-bit number to a Base64 string
 encode60 :: Word60 -> ByteString
-encode60 w = BS.pack $
-    map (encodeLetter . leastSignificant6)
-        [ (safeCast w `shiftR` (6 * i)) .&. 0b111111 :: Word64
-        | i <- [9, 8 .. 0]
-        ]
+encode60 w = BS.pack
+    [ encodeLetter $ leastSignificant6 (safeCast w `shiftR` (6 * i) :: Word64)
+    | i <- [9, 8 .. 0]
+    ]
 
 -- | Encode a 60-bit number to a Base64 string, dropping trailing zeroes
 encode60short :: Word60 -> ByteString
diff --git a/lib/RON/Binary/Parse.hs b/lib/RON/Binary/Parse.hs
--- a/lib/RON/Binary/Parse.hs
+++ b/lib/RON/Binary/Parse.hs
@@ -30,8 +30,9 @@
 import           RON.Types (Atom (AFloat, AInteger, AString, AUuid),
                             ClosedOp (..), Op (..),
                             OpTerm (TClosed, THeader, TQuery, TReduced),
-                            UUID (UUID), WireChunk (Closed, Query, Value),
-                            WireFrame, WireReducedChunk (..))
+                            Payload, UUID (UUID),
+                            WireChunk (Closed, Query, Value), WireFrame,
+                            WireReducedChunk (..))
 import           RON.Util (ByteStringL)
 import           RON.Util.Word (safeCast)
 
@@ -186,7 +187,7 @@
         _  -> fail "expected uuid of size 16"
 
 -- | 'Parser' for a payload (sequence of atoms)
-parsePayload :: Parser [Atom]
+parsePayload :: Parser Payload
 parsePayload = label "payload" $ many atom
 
 -- | 'Parser' for an atom
diff --git a/lib/RON/Error.hs b/lib/RON/Error.hs
--- a/lib/RON/Error.hs
+++ b/lib/RON/Error.hs
@@ -1,10 +1,10 @@
 {-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE DeriveAnyClass #-}
 {-# LANGUAGE FlexibleContexts #-}
 
 module RON.Error (
     Error (..),
     MonadE,
+    correct,
     errorContext,
     liftEither,
     liftEitherString,
@@ -17,18 +17,25 @@
 
 import           Data.String (IsString, fromString)
 
-data Error
-    = Error        Text [Error]
-    | ErrorContext Text  Error
-    deriving (Exception, Eq, Show)
+data Error = Error Text [Error]
+    deriving (Eq, Show)
+{-  TODO(2019-08-09, cblp)
+    data Error = Error
+        { context :: [Text]
+        , desc    :: Text
+        , reasons :: [Error]
+        }
+-}
 
+instance Exception Error
+
 instance IsString Error where
     fromString s = Error (fromString s) []
 
 type MonadE = MonadError Error
 
 errorContext :: MonadE m => Text -> m a -> m a
-errorContext ctx action = action `catchError` (throwError . ErrorContext ctx)
+errorContext ctx action = action `catchError` \e -> throwError $ Error ctx [e]
 
 liftMaybe :: MonadE m => Text -> Maybe a -> m a
 liftMaybe msg = maybe (throwErrorText msg) pure
@@ -41,3 +48,10 @@
 
 throwErrorString :: (MonadError e m, IsString e) => String -> m a
 throwErrorString = throwError . fromString
+
+correct :: MonadError e m => a -> m a -> m a
+correct def action =
+    action
+    `catchError` \_e ->
+        -- TODO(2019-08-06, cblp) $logWarnSH e
+        pure def
diff --git a/lib/RON/Event.hs b/lib/RON/Event.hs
--- a/lib/RON/Event.hs
+++ b/lib/RON/Event.hs
@@ -6,30 +6,30 @@
 {-# LANGUAGE PatternSynonyms #-}
 {-# LANGUAGE RecordWildCards #-}
 
-module RON.Event
-    ( CalendarTime (..)
-    , CalendarEvent (..)
-    , EpochEvent (..)
-    , EpochTime
-    , Event (..)
-    , LocalTime (..)
-    , Naming (..)
-    , ReplicaClock (..)
-    , ReplicaId (..)
-    , advanceToUuid
-    , applicationSpecific
-    , decodeEvent
-    , encodeEvent
-    , fromCalendarEvent
-    , fromEpochEvent
-    , getEvent
-    , getEventUuid
-    , getEventUuids
-    , mkCalendarDate
-    , mkCalendarDateTime
-    , mkCalendarDateTimeNano
-    , toEpochEvent
-    ) where
+module RON.Event (
+    CalendarTime (..),
+    CalendarEvent (..),
+    EpochEvent (..),
+    EpochTime,
+    Event (..),
+    LocalTime (..),
+    Naming (..),
+    ReplicaClock (..),
+    ReplicaId (..),
+    advanceToUuid,
+    applicationSpecific,
+    decodeEvent,
+    encodeEvent,
+    fromCalendarEvent,
+    fromEpochEvent,
+    getEvent,
+    getEventUuid,
+    getEventUuids,
+    mkCalendarDate,
+    mkCalendarDateTime,
+    mkCalendarDateTimeNano,
+    toEpochEvent,
+) where
 
 import           RON.Prelude
 
diff --git a/lib/RON/Event/Simulation.hs b/lib/RON/Event/Simulation.hs
--- a/lib/RON/Event/Simulation.hs
+++ b/lib/RON/Event/Simulation.hs
@@ -4,16 +4,16 @@
 -- | Lamport clock network simulation.
 -- 'ReplicaSim' provides 'Replica' and 'Clock' instances,
 -- replicas may interchange data while they are connected in a 'NetworkSim'.
-module RON.Event.Simulation
-    ( NetworkSim
-    , NetworkSimT
-    , ReplicaSim
-    , ReplicaSimT
-    , runNetworkSim
-    , runNetworkSimT
-    , runReplicaSim
-    , runReplicaSimT
-    ) where
+module RON.Event.Simulation (
+    NetworkSim,
+    NetworkSimT,
+    ReplicaSim,
+    ReplicaSimT,
+    runNetworkSim,
+    runNetworkSimT,
+    runReplicaSim,
+    runReplicaSimT,
+) where
 
 import           RON.Prelude
 
@@ -53,7 +53,7 @@
                 t0orig = HM.lookupDefault (ls60 0) rid replicaStates
                 ReplicaId _ r = rid
                 randomLeap =
-                    ls60 . fromIntegral $ hash (t0orig, n, r) `mod` 0x100000000
+                    ls60 . fromIntegral $ hash (t0orig, n, r) `mod` 0x10000
                 t0 = t0orig `word60add` randomLeap
                 t1 = t0 `word60add` n
                 in ((t0, t1), HM.insert rid t1 replicaStates)
diff --git a/lib/RON/Prelude.hs b/lib/RON/Prelude.hs
--- a/lib/RON/Prelude.hs
+++ b/lib/RON/Prelude.hs
@@ -7,7 +7,12 @@
     headMay,
     lastDef,
     maximumDef,
+    maximumMay,
+    maximumMayOn,
     maxOn,
+    minimumDef,
+    minimumMay,
+    minimumMayOn,
     minOn,
     note,
     replicateM2,
@@ -25,8 +30,9 @@
 import           Control.Exception as X (Exception, catch, evaluate, throwIO)
 import           Control.Monad as X (Monad, filterM, guard, unless, void, when,
                                      (<=<), (=<<), (>=>), (>>), (>>=))
-import           Control.Monad.Except as X (ExceptT, MonadError, catchError,
-                                            liftEither, runExceptT, throwError)
+import           Control.Monad.Except as X (ExceptT (ExceptT), MonadError,
+                                            catchError, liftEither, runExceptT,
+                                            throwError)
 import           Control.Monad.Fail as X (MonadFail, fail)
 import           Control.Monad.IO.Class as X (MonadIO, liftIO)
 import           Control.Monad.Reader as X (MonadReader, ReaderT (ReaderT), ask,
@@ -48,8 +54,8 @@
 import           Data.Either as X (Either (Left, Right), either)
 import           Data.Eq as X (Eq, (/=), (==))
 import           Data.Foldable as X (Foldable, and, asum, fold, foldMap, foldl',
-                                     foldr, for_, length, minimumBy, null, or,
-                                     toList, traverse_)
+                                     foldr, for_, length, null, or, toList,
+                                     traverse_)
 import           Data.Function as X (const, flip, id, on, ($), (.))
 import           Data.Functor as X (Functor, fmap, ($>), (<$), (<$>), (<&>))
 import           Data.Functor.Identity as X (Identity)
@@ -92,12 +98,13 @@
                                 (^), (^^))
 import           GHC.Stack as X (HasCallStack)
 import           System.IO as X (FilePath, IO)
+import           Text.Read as X (readMaybe)
 import           Text.Show as X (Show)
 
 --------------------------------------------------------------------------------
 
 import qualified Data.Foldable
-import           Data.List (last, maximum)
+import           Data.List (last, maximum, maximumBy, minimum, minimumBy)
 import           Data.String (IsString, fromString)
 import qualified Text.Show
 
@@ -123,8 +130,23 @@
 maximumDef :: Ord a => a -> [a] -> a
 maximumDef def = list' def maximum
 
+maximumMay :: Ord a => [a] -> Maybe a
+maximumMay = list' Nothing (Just . maximum)
+
+maximumMayOn :: Ord b => (a -> b) -> [a] -> Maybe a
+maximumMayOn key = list' Nothing (Just . maximumBy (comparing key))
+
 maxOn :: Ord b => (a -> b) -> a -> a -> a
 maxOn f x y = if f x < f y then y else x
+
+minimumDef :: Ord a => a -> [a] -> a
+minimumDef def = list' def minimum
+
+minimumMay :: Ord a => [a] -> Maybe a
+minimumMay = list' Nothing (Just . minimum)
+
+minimumMayOn :: Ord b => (a -> b) -> [a] -> Maybe a
+minimumMayOn key = list' Nothing (Just . minimumBy (comparing key))
 
 minOn :: Ord b => (a -> b) -> a -> a -> a
 minOn f x y = if f x < f y then x else y
diff --git a/lib/RON/Text.hs b/lib/RON/Text.hs
--- a/lib/RON/Text.hs
+++ b/lib/RON/Text.hs
@@ -1,14 +1,14 @@
 -- | RON-Text wire format
-module RON.Text
-    ( parseObject
-    , parseStateFrame
-    , parseWireFrame
-    , parseWireFrames
-    , serializeObject
-    , serializeStateFrame
-    , serializeWireFrame
-    , serializeWireFrames
-    ) where
+module RON.Text (
+    parseObject,
+    parseStateFrame,
+    parseWireFrame,
+    parseWireFrames,
+    serializeObject,
+    serializeStateFrame,
+    serializeWireFrame,
+    serializeWireFrames,
+) where
 
 import           RON.Text.Parse (parseObject, parseStateFrame, parseWireFrame,
                                  parseWireFrames)
diff --git a/lib/RON/Text/Parse.hs b/lib/RON/Text/Parse.hs
--- a/lib/RON/Text/Parse.hs
+++ b/lib/RON/Text/Parse.hs
@@ -7,24 +7,24 @@
 {-# LANGUAGE RecordWildCards #-}
 
 -- | RON-Text parsing
-module RON.Text.Parse
-    ( parseAtom
-    , parseObject
-    , parseOp
-    , parseStateFrame
-    , parseString
-    , parseUuid
-    , parseUuidKey
-    , parseUuidAtom
-    , parseWireFrame
-    , parseWireFrames
-    ) where
+module RON.Text.Parse (
+    parseAtom,
+    parseObject,
+    parseOp,
+    parseStateFrame,
+    parseString,
+    parseUuid,
+    parseUuidKey,
+    parseUuidAtom,
+    parseWireFrame,
+    parseWireFrames,
+) where
 
 import           RON.Prelude hiding (takeWhile)
 
-import           Attoparsec.Extra (Parser, char, endOfInputEx, isSuccessful,
-                                   label, manyTill, parseOnlyL, satisfy,
-                                   definiteDouble, (<+>), (??))
+import           Attoparsec.Extra (Parser, char, definiteDouble, endOfInputEx,
+                                   isSuccessful, label, manyTill, parseOnlyL,
+                                   satisfy, (<+>), (??))
 import qualified Data.Aeson as Json
 import           Data.Attoparsec.ByteString (takeWhile1)
 import           Data.Attoparsec.ByteString.Char8 (anyChar, decimal, double,
@@ -37,11 +37,11 @@
 
 import qualified RON.Base64 as Base64
 import           RON.Types (Atom (AFloat, AInteger, AString, AUuid),
-                            ClosedOp (..), ObjectState (ObjectState), Op (..),
+                            ClosedOp (..), ObjectFrame (ObjectFrame), Op (..),
                             OpTerm (TClosed, THeader, TQuery, TReduced),
-                            StateChunk (..), StateFrame, UUID (UUID),
+                            Payload, StateFrame, UUID (UUID),
                             WireChunk (Closed, Query, Value), WireFrame,
-                            WireReducedChunk (..))
+                            WireReducedChunk (..), WireStateChunk (..))
 import           RON.Util (ByteStringL)
 import           RON.Util.Word (Word2, Word4, Word60, b00, b0000, b01, b10, b11,
                                 ls60, safeCast)
@@ -314,7 +314,7 @@
         '-' -> pure b11
         _   -> fail "not a UUID-version"
 
-payloadP :: UUID -> Parser [Atom]
+payloadP :: UUID -> Parser Payload
 payloadP = label "payload" . go
   where
     go prevUuid = do
@@ -400,20 +400,19 @@
 parseStateFrame = parseWireFrame >=> findObjects
 
 -- | Parse a state frame as an object
-parseObject :: UUID -> ByteStringL -> Either String (ObjectState a)
-parseObject oid bytes = ObjectState oid <$> parseStateFrame bytes
+parseObject :: UUID -> ByteStringL -> Either String (ObjectFrame a)
+parseObject oid bytes = ObjectFrame oid <$> parseStateFrame bytes
 
 -- | Extract object states from a common frame
 findObjects :: WireFrame -> Either String StateFrame
 findObjects = fmap Map.fromList . traverse loadBody where
     loadBody = \case
-        Value WireReducedChunk{..} -> do
-            let ClosedOp{reducerId, objectId, op} = wrcHeader
-            let Op{opId} = op
-            let stateVersion = opId
-            let stateBody = wrcBody
-            let stateType = reducerId
-            pure (objectId, StateChunk{..})
+        Value WireReducedChunk{wrcHeader, wrcBody} -> do
+            let ClosedOp{reducerId, objectId} = wrcHeader
+            pure
+                ( objectId
+                , WireStateChunk{stateType = reducerId, stateBody = wrcBody}
+                )
         _ -> Left "expected reduced chunk"
 
 opZero :: ClosedOp
diff --git a/lib/RON/Text/Serialize.hs b/lib/RON/Text/Serialize.hs
--- a/lib/RON/Text/Serialize.hs
+++ b/lib/RON/Text/Serialize.hs
@@ -6,16 +6,16 @@
 {-# LANGUAGE RecordWildCards #-}
 
 -- | RON-Text serialization
-module RON.Text.Serialize
-    ( serializeAtom
-    , serializeObject
-    , serializeRawOp
-    , serializeStateFrame
-    , serializeString
-    , serializeUuid
-    , serializeWireFrame
-    , serializeWireFrames
-    ) where
+module RON.Text.Serialize (
+    serializeAtom,
+    serializeObject,
+    serializeRawOp,
+    serializeStateFrame,
+    serializeString,
+    serializeUuid,
+    serializeWireFrame,
+    serializeWireFrames,
+) where
 
 import           RON.Prelude
 
@@ -29,10 +29,10 @@
 import           RON.Text.Serialize.UUID (serializeUuid, serializeUuidAtom,
                                           serializeUuidKey)
 import           RON.Types (Atom (AFloat, AInteger, AString, AUuid),
-                            ClosedOp (..), ObjectState (..), Op (..),
-                            StateChunk (..), StateFrame,
-                            WireChunk (Closed, Query, Value), WireFrame,
-                            WireReducedChunk (..))
+                            ClosedOp (..), ObjectFrame (..), Op (..), Payload,
+                            StateFrame, WireChunk (Closed, Query, Value),
+                            WireFrame, WireReducedChunk (..),
+                            WireStateChunk (..))
 import           RON.Util (ByteStringL)
 import           RON.UUID (UUID, zero)
 
@@ -170,29 +170,24 @@
 -- | Serialize a payload in stream context
 serializePayload
     :: UUID  -- ^ previous UUID (default is 'zero')
-    -> [Atom]
+    -> Payload
     -> ByteStringL
 serializePayload prev =
     BSLC.unwords . (`evalState` prev) . traverse serializeAtomZip
 
 -- | Serialize a state frame
 serializeStateFrame :: StateFrame -> ByteStringL
-serializeStateFrame =
-    serializeWireFrame . map wrapChunk . sortOn (stateType . snd) . Map.assocs
-    -- TODO(2019-01-28, cblp) remove sortOn type
-  where
-    wrapChunk (objectId, StateChunk{..}) = Value WireReducedChunk{..}
-      where
-        wrcHeader = ClosedOp
-            { reducerId = stateType
-            , objectId
-            , op = Op{opId = stateVersion, refId = zero, payload = []}
-            }
-        wrcBody = stateBody
+serializeStateFrame = serializeWireFrame . map wrapChunk . Map.assocs where
+    wrapChunk (objectId, WireStateChunk{stateType, stateBody}) =
+        Value
+            WireReducedChunk
+                { wrcHeader = opZero{reducerId = stateType, objectId}
+                , wrcBody = stateBody
+                }
 
 -- | Serialize an object. Return object id that must be stored separately.
-serializeObject :: ObjectState a -> (UUID, ByteStringL)
-serializeObject (ObjectState oid frame) = (oid, serializeStateFrame frame)
+serializeObject :: ObjectFrame a -> (UUID, ByteStringL)
+serializeObject (ObjectFrame oid frame) = (oid, serializeStateFrame frame)
 
 opZero :: ClosedOp
 opZero = ClosedOp
diff --git a/lib/RON/Text/Serialize/UUID.hs b/lib/RON/Text/Serialize/UUID.hs
--- a/lib/RON/Text/Serialize/UUID.hs
+++ b/lib/RON/Text/Serialize/UUID.hs
@@ -5,11 +5,11 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ViewPatterns #-}
 
-module RON.Text.Serialize.UUID
-    ( serializeUuid
-    , serializeUuidAtom
-    , serializeUuidKey
-    ) where
+module RON.Text.Serialize.UUID (
+    serializeUuid,
+    serializeUuidAtom,
+    serializeUuidKey,
+) where
 
 import           RON.Prelude
 
@@ -17,6 +17,7 @@
 import qualified Data.ByteString as BS
 import qualified Data.ByteString.Char8 as BSC
 import qualified Data.ByteString.Lazy as BSL
+import           Data.Foldable (minimumBy)
 
 import qualified RON.Base64 as Base64
 import           RON.Util (ByteStringL)
@@ -125,5 +126,6 @@
 serializeUuidGeneric :: UUID -> ByteString
 serializeUuidGeneric (UUID x y) = Base64.encode64 x <> Base64.encode64 y
 
+-- | XXX Partial for lists!
 minimumByLength :: Foldable f => f ByteString -> ByteString
 minimumByLength = minimumBy $ comparing BS.length
diff --git a/lib/RON/Types.hs b/lib/RON/Types.hs
--- a/lib/RON/Types.hs
+++ b/lib/RON/Types.hs
@@ -10,27 +10,30 @@
 
 -- | RON model types
 module RON.Types (
-    pattern AckP,
-    pattern AnnotationDerivedP,
-    pattern AnnotationP,
-    pattern CreateP,
-    pattern DeleteP,
-    pattern RegularP,
-    pattern UndeleteP,
     Atom (..),
     ClosedOp (..),
     Object (..),
-    ObjectState (..),
+    ObjectFrame (..),
     Op (..),
-    OpPattern (..),
     OpTerm (..),
+    Payload,
     StateChunk (..),
     StateFrame,
     UUID (..),
     WireChunk (..),
     WireFrame,
     WireReducedChunk (..),
+    WireStateChunk (..),
+    -- * Op patterns
+    OpPattern (..),
     opPattern,
+    pattern AckP,
+    pattern AnnotationDerivedP,
+    pattern AnnotationP,
+    pattern CreateP,
+    pattern DeleteP,
+    pattern RegularP,
+    pattern UndeleteP,
 ) where
 
 import           RON.Prelude
@@ -58,13 +61,15 @@
     }
     deriving (Data, Eq, Generic)
 
+type Payload = [Atom]
+
 -- | Open op (operation)
 data Op = Op
-    { opId      :: UUID
+    { opId :: UUID
         -- ^ event id (usually timestamp)
-    , refId     :: UUID
+    , refId :: UUID
         -- ^ reference to other op; actual semantics depends on the type
-    , payload :: [Atom]
+    , payload :: Payload
         -- ^ payload
     }
     deriving (Data, Eq, Generic, Hashable, Show)
@@ -104,16 +109,20 @@
     deriving (Eq, Show)
 
 -- | Reduced chunk representing an object state (i. e. high-level value)
-data StateChunk = StateChunk
-    { stateType    :: UUID
-    , stateVersion :: UUID
-    , stateBody    :: [Op]
+data WireStateChunk = WireStateChunk
+    { stateType :: UUID
+    , stateBody :: [Op]
     }
     deriving (Eq, Show)
 
--- | Frame containing only state chunks
-type StateFrame = Map UUID StateChunk
+-- | Type-tagged version of 'WireStateChunk'
+newtype StateChunk a = StateChunk [Op]
 
+-- | Frame containing only state chunks.
+-- Must contain one main object and any number of other objects that are part of
+-- the main one.
+type StateFrame = Map UUID WireStateChunk
+
 -- | Reference to an object
 newtype Object a = Object UUID
     deriving (Eq)
@@ -127,7 +136,7 @@
             . showsPrec 11 b
 
 -- | Object accompanied with a frame
-data ObjectState a = ObjectState{uuid :: UUID, frame :: StateFrame}
+data ObjectFrame a = ObjectFrame{uuid :: UUID, frame :: StateFrame}
     deriving (Eq, Show)
 
 data OpPattern =
diff --git a/lib/RON/UUID.hs b/lib/RON/UUID.hs
--- a/lib/RON/UUID.hs
+++ b/lib/RON/UUID.hs
@@ -8,25 +8,25 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ViewPatterns #-}
 
-module RON.UUID
-    ( UUID (..)
-    , UuidFields (..)
-    , build
-    , buildX
-    , buildY
-    , split
-    , succValue
-    , zero
-    , pattern Zero
+module RON.UUID (
+    UUID (..),
+    UuidFields (..),
+    build,
+    buildX,
+    buildY,
+    split,
+    succValue,
+    zero,
+    pattern Zero,
     -- * Name
-    , getName
-    , liftName
-    , mkName
-    , mkScopedName
+    getName,
+    liftName,
+    mkName,
+    mkScopedName,
     -- * Base32 encoding, suitable for file names
-    , decodeBase32
-    , encodeBase32
-    ) where
+    decodeBase32,
+    encodeBase32,
+) where
 
 import           RON.Prelude
 
diff --git a/lib/RON/Util/Word.hs b/lib/RON/Util/Word.hs
--- a/lib/RON/Util/Word.hs
+++ b/lib/RON/Util/Word.hs
@@ -4,48 +4,47 @@
 {-# LANGUAGE PatternSynonyms #-}
 {-# LANGUAGE TypeApplications #-}
 
-module RON.Util.Word
-    (
+module RON.Util.Word (
     -- * Word2
-      Word2
-    , b00, b01, b10, b11
-    , pattern B00, pattern B01, pattern B10, pattern B11
-    , leastSignificant2
+    Word2,
+    b00, b01, b10, b11,
+    pattern B00, pattern B01, pattern B10, pattern B11,
+    leastSignificant2,
     -- * Word4
-    , Word4
-    , b0000, b0001, b0010, b0011, b0100, b0101, b0110, b0111
-    , b1000, b1001, b1010, b1011, b1100, b1101, b1110, b1111
-    , pattern B0000
-    , leastSignificant4
+    Word4,
+    b0000, b0001, b0010, b0011, b0100, b0101, b0110, b0111,
+    b1000, b1001, b1010, b1011, b1100, b1101, b1110, b1111,
+    pattern B0000,
+    leastSignificant4,
     -- * Word6
-    , Word6 (..)
-    , leastSignificant6
-    , ls6
+    Word6 (..),
+    leastSignificant6,
+    ls6,
     -- * Word8
-    , Word8
+    Word8,
     -- * Word12
-    , Word12
-    , leastSignificant12
-    , ls12
+    Word12,
+    leastSignificant12,
+    ls12,
     -- * Word16
-    , Word16
+    Word16,
     -- * Word24
-    , Word24
-    , leastSignificant24
-    , ls24
+    Word24,
+    leastSignificant24,
+    ls24,
     -- * Word32
-    , Word32
+    Word32,
     -- * Word60
-    , Word60
-    , leastSignificant60
-    , ls60
-    , toWord60
-    , word60add
+    Word60,
+    leastSignificant60,
+    ls60,
+    toWord60,
+    word60add,
     -- * Word64
-    , Word64
+    Word64,
     -- * SafeCast
-    , SafeCast (..)
-    ) where
+    SafeCast (..),
+) where
 
 import           RON.Prelude
 
diff --git a/ron.cabal b/ron.cabal
--- a/ron.cabal
+++ b/ron.cabal
@@ -1,7 +1,7 @@
 cabal-version:  2.2
 
 name:           ron
-version:        0.7
+version:        0.8
 
 bug-reports:    https://github.com/ff-notes/ron/issues
 category:       Distributed Systems, Protocol, Database
