diff --git a/asif.cabal b/asif.cabal
--- a/asif.cabal
+++ b/asif.cabal
@@ -1,145 +1,224 @@
-cabal-version:  2.2
-name:           asif
-version:        6.0.3
-description:    Library for creating and querying segmented feeds. Please see <https://github.com/arbor/asif#readme>
-synopsis:       Library for creating and querying segmented feeds
-category:       Services
-homepage:       https://github.com/arbor/asif#readme
-bug-reports:    https://github.com/arbor/asif/issues
-author:         Arbor Networks
-maintainer:     mayhem@arbor.net
-copyright:      Arbor Networks
-license:        MIT
-license-file:   LICENSE
-build-type:     Simple
-extra-source-files:
-    ChangeLog.md
-    README.md
+cabal-version: 2.2
 
+name:                   asif
+version:                6.0.4
+description:            Library for creating and querying segmented feeds. Please see <https://github.com/arbor/asif#readme>
+synopsis:               Library for creating and querying segmented feeds
+category:               Services
+homepage:               https://github.com/arbor/asif#readme
+bug-reports:            https://github.com/arbor/asif/issues
+author:                 Arbor Networks
+maintainer:             mayhem@arbor.net
+copyright:              Arbor Networks
+license:                MIT
+license-file:           LICENSE
+tested-with:            GHC == 8.8.1, GHC == 8.6.5, GHC == 8.4.4, GHC == 8.2.2
+build-type:             Simple
+extra-source-files:     ChangeLog.md
+                        README.md
+
 source-repository head
   type: git
   location: https://github.com/arbor/asif
 
-common common-deps
-  default-language:    Haskell2010
-  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -msse4.2
-  build-depends:
-      attoparsec
-    , base >=4.7 && <5
-    , binary
-    , bytestring
-    , conduit
-    , conduit-combinators
-    , conduit-extra
-    , containers
-    , cpu
-    , either
-    , exceptions
-    , foldl
-    , generic-lens
-    , hw-bits
-    , hw-ip >= 2.3.2.0
-    , lens
-    , network
-    , old-locale
-    , profunctors
-    , resourcet
-    , temporary-resourcet
-    , text
-    , thyme
-    , transformers
-    , vector
+common base                   { build-depends: base                 >= 4.7        && < 5      }
 
+common attoparsec             { build-depends: attoparsec           >= 0.13                   }
+common binary                 { build-depends: binary               >= 0.8                    }
+common bytestring             { build-depends: bytestring           >= 0.10                   }
+common conduit                { build-depends: conduit              >= 1.3                    }
+common conduit-combinators    { build-depends: conduit-combinators  >= 1.3                    }
+common conduit-extra          { build-depends: conduit-extra        >= 1.3                    }
+common containers             { build-depends: containers           >= 0.5                    }
+common cpu                    { build-depends: cpu                  >= 0.1                    }
+common directory              { build-depends: directory            >= 1.3                    }
+common doctest                { build-depends: doctest              >= 0.16.2     && < 0.17   }
+common doctest-discover       { build-depends: doctest-discover     >= 0.2        && < 0.3    }
+common either                 { build-depends: either               >= 5.0                    }
+common exceptions             { build-depends: exceptions           >= 0.10                   }
+common foldl                  { build-depends: foldl                >= 1.4                    }
+common generic-lens           { build-depends: generic-lens         >= 1.2.0.1                }
+common hedgehog               { build-depends: hedgehog             >= 1.0                    }
+common hspec                  { build-depends: hspec                >= 2.7                    }
+common hw-bits                { build-depends: hw-bits              >= 0.7                    }
+common hw-hspec-hedgehog      { build-depends: hw-hspec-hedgehog    >= 0.1                    }
+common hw-ip                  { build-depends: hw-ip                >= 2.3                    }
+common lens                   { build-depends: lens                 >= 4.18                   }
+common network                { build-depends: network              >= 2                      }
+common old-locale             { build-depends: old-locale           >= 1.0                    }
+common optparse-applicative   { build-depends: optparse-applicative >= 0.15                   }
+common profunctors            { build-depends: profunctors          >= 5.5                    }
+common resourcet              { build-depends: resourcet            >= 1.2.2                  }
+common temporary-resourcet    { build-depends: temporary-resourcet  >= 0.1                    }
+common text                   { build-depends: text                 >= 1.2                    }
+common thyme                  { build-depends: thyme                >= 0.3                    }
+common transformers           { build-depends: transformers         >= 0.5                    }
+common vector                 { build-depends: vector               >= 0.12                   }
 
+common config
+  ghc-options:          -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -msse4.2
+  default-language:     Haskell2010
+
+common asif
+  build-depends:        asif
+
 library
-  import: common-deps
-  exposed-modules:
-    Arbor.File.Format.Asif
-    Arbor.File.Format.Asif.ByIndex
-    Arbor.File.Format.Asif.ByteString
-    Arbor.File.Format.Asif.ByteString.Builder
-    Arbor.File.Format.Asif.ByteString.Lazy
-    Arbor.File.Format.Asif.Data.Ip
-    Arbor.File.Format.Asif.Data.Read
-    Arbor.File.Format.Asif.Extract
-    Arbor.File.Format.Asif.Format
-    Arbor.File.Format.Asif.Format.Text
-    Arbor.File.Format.Asif.Get
-    Arbor.File.Format.Asif.IO
-    Arbor.File.Format.Asif.Lookup
-    Arbor.File.Format.Asif.Segment
-    Arbor.File.Format.Asif.Type
-    Arbor.File.Format.Asif.Whatever
-    Arbor.File.Format.Asif.Write
-  other-modules:
-    Arbor.File.Format.Asif.Format.SegmentValue
-    Arbor.File.Format.Asif.Format.Type
-    Arbor.File.Format.Asif.List
-    Arbor.File.Format.Asif.Maybe
-    Arbor.File.Format.Asif.Text
-    Paths_asif
-  autogen-modules:
-    Paths_asif
-  hs-source-dirs:
-    src
-  default-extensions: BangPatterns FlexibleContexts FlexibleInstances GeneralizedNewtypeDeriving MultiParamTypeClasses OverloadedStrings TupleSections
-  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints
-  default-language: Haskell2010
+  import:               base, config
+                      , attoparsec
+                      , binary
+                      , bytestring
+                      , conduit
+                      , conduit-combinators
+                      , conduit-extra
+                      , containers
+                      , cpu
+                      , either
+                      , exceptions
+                      , foldl
+                      , generic-lens
+                      , hw-bits
+                      , hw-ip
+                      , lens
+                      , network
+                      , old-locale
+                      , profunctors
+                      , resourcet
+                      , temporary-resourcet
+                      , text
+                      , thyme
+                      , transformers
+                      , vector
+  exposed-modules:      Arbor.File.Format.Asif
+                        Arbor.File.Format.Asif.ByIndex
+                        Arbor.File.Format.Asif.ByteString
+                        Arbor.File.Format.Asif.ByteString.Builder
+                        Arbor.File.Format.Asif.ByteString.Lazy
+                        Arbor.File.Format.Asif.Data.Ip
+                        Arbor.File.Format.Asif.Data.Read
+                        Arbor.File.Format.Asif.Extract
+                        Arbor.File.Format.Asif.Format
+                        Arbor.File.Format.Asif.Format.Text
+                        Arbor.File.Format.Asif.Get
+                        Arbor.File.Format.Asif.IO
+                        Arbor.File.Format.Asif.Lookup
+                        Arbor.File.Format.Asif.Segment
+                        Arbor.File.Format.Asif.Type
+                        Arbor.File.Format.Asif.Whatever
+                        Arbor.File.Format.Asif.Write
+  other-modules:        Arbor.File.Format.Asif.Format.SegmentValue
+                        Arbor.File.Format.Asif.Format.Type
+                        Arbor.File.Format.Asif.List
+                        Arbor.File.Format.Asif.Maybe
+                        Arbor.File.Format.Asif.Text
+                        Paths_asif
+  autogen-modules:      Paths_asif
+  hs-source-dirs:       src
+  default-extensions:   BangPatterns FlexibleContexts FlexibleInstances GeneralizedNewtypeDeriving MultiParamTypeClasses OverloadedStrings TupleSections
+  ghc-options:          -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints
 
 executable asif
-  import: common-deps
-  main-is: Main.hs
-  other-modules:
-    App.Commands
-    App.Commands.Dump
-    App.Commands.DumpBitmap
-    App.Commands.DumpOnly
-    App.Commands.EncodeFiles
-    App.Commands.ExtractFiles
-    App.Commands.ExtractSegments
-    App.Commands.Ls
-    App.Commands.Options.Type
-    App.Dump
-    App.IO
-    Paths_asif
-  autogen-modules:
-    Paths_asif
-  hs-source-dirs:
-    app
-  default-extensions: BangPatterns FlexibleContexts FlexibleInstances GeneralizedNewtypeDeriving MultiParamTypeClasses OverloadedStrings TupleSections
-  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -threaded -rtsopts -O2 -msse4.2
-  build-depends:
-      asif
-    , directory
-    , optparse-applicative
-  default-language: Haskell2010
+  import:               base, config
+                      , asif
+                      , attoparsec
+                      , binary
+                      , bytestring
+                      , conduit
+                      , conduit-combinators
+                      , conduit-extra
+                      , containers
+                      , cpu
+                      , directory
+                      , either
+                      , exceptions
+                      , foldl
+                      , generic-lens
+                      , hw-bits
+                      , hw-ip
+                      , lens
+                      , network
+                      , old-locale
+                      , optparse-applicative
+                      , profunctors
+                      , resourcet
+                      , temporary-resourcet
+                      , text
+                      , thyme
+                      , transformers
+                      , vector
+  main-is:              Main.hs
+  other-modules:        App.Commands
+                        App.Commands.Dump
+                        App.Commands.DumpBitmap
+                        App.Commands.DumpOnly
+                        App.Commands.EncodeFiles
+                        App.Commands.ExtractFiles
+                        App.Commands.ExtractSegments
+                        App.Commands.Ls
+                        App.Commands.Options.Type
+                        App.Dump
+                        App.IO
+                        Paths_asif
+  autogen-modules:      Paths_asif
+  hs-source-dirs:       app
+  default-extensions:   BangPatterns FlexibleContexts FlexibleInstances GeneralizedNewtypeDeriving MultiParamTypeClasses OverloadedStrings TupleSections
+  ghc-options:          -threaded -rtsopts -O2
 
 test-suite asif-test
-  import: common-deps
-  type: exitcode-stdio-1.0
-  main-is: Spec.hs
-  build-tool-depends: hspec-discover:hspec-discover
-  other-modules:
-    Arbor.File.Format.Asif.ByteString.BuilderSpec
-    Arbor.File.Format.Asif.Data.IpSpec
-    Arbor.File.Format.Asif.ExtractSpec
-    Arbor.File.Format.Asif.Format.SegmentValueSpec
-    Arbor.File.Format.Asif.Format.TextSpec
-    Arbor.File.Format.Asif.WriteSpec
-    Arbor.File.Format.AsifSpec
-    Arbor.TestUtils
-    Gen.Feed
-    TestApp
-    Paths_asif
-  autogen-modules:
-    Paths_asif
-  hs-source-dirs:
-    test
-  default-extensions: BangPatterns FlexibleContexts FlexibleInstances GeneralizedNewtypeDeriving MultiParamTypeClasses OverloadedStrings TupleSections
-  ghc-options: -threaded -rtsopts -with-rtsopts=-N
-  build-depends:
-      asif
-    , hedgehog
-    , hspec
-    , hw-hspec-hedgehog
-  default-language: Haskell2010
+  import:               base, config
+                      , asif
+                      , attoparsec
+                      , binary
+                      , bytestring
+                      , conduit
+                      , conduit-combinators
+                      , conduit-extra
+                      , containers
+                      , cpu
+                      , either
+                      , exceptions
+                      , foldl
+                      , generic-lens
+                      , hedgehog
+                      , hspec
+                      , hw-bits
+                      , hw-hspec-hedgehog
+                      , hw-ip
+                      , lens
+                      , network
+                      , old-locale
+                      , profunctors
+                      , resourcet
+                      , temporary-resourcet
+                      , text
+                      , thyme
+                      , transformers
+                      , vector
+  type:                 exitcode-stdio-1.0
+  main-is:              Spec.hs
+  build-tool-depends:   hspec-discover:hspec-discover
+  other-modules:        Arbor.File.Format.Asif.ByteString.BuilderSpec
+                        Arbor.File.Format.Asif.Data.IpSpec
+                        Arbor.File.Format.Asif.ExtractSpec
+                        Arbor.File.Format.Asif.Format.SegmentValueSpec
+                        Arbor.File.Format.Asif.Format.TextSpec
+                        Arbor.File.Format.Asif.WriteSpec
+                        Arbor.File.Format.AsifSpec
+                        Arbor.TestUtils
+                        Gen.Feed
+                        TestApp
+                        Paths_asif
+  autogen-modules:      Paths_asif
+  hs-source-dirs:       test
+  default-extensions:   BangPatterns FlexibleContexts FlexibleInstances GeneralizedNewtypeDeriving MultiParamTypeClasses OverloadedStrings TupleSections
+  ghc-options:          -threaded -rtsopts -with-rtsopts=-N
+
+test-suite doctest
+  import:               base, config
+                      , asif
+                      , doctest
+                      , doctest-discover
+  type:                 exitcode-stdio-1.0
+  ghc-options:          -threaded
+  main-is:              DoctestDriver.hs
+  HS-Source-Dirs:       doctest
+  build-tool-depends:   doctest-discover:doctest-discover
diff --git a/doctest/DoctestDriver.hs b/doctest/DoctestDriver.hs
new file mode 100644
--- /dev/null
+++ b/doctest/DoctestDriver.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE CPP #-}
+
+#if MIN_VERSION_GLASGOW_HASKELL(8,4,4,0)
+{-# OPTIONS_GHC -F -pgmF doctest-discover #-}
+#else
+module Main where
+
+import qualified System.IO as IO
+
+main :: IO ()
+main = IO.putStrLn "WARNING: doctest will not run on GHC versions earlier than 8.4.4"
+#endif
diff --git a/src/Arbor/File/Format/Asif/ByteString/Builder.hs b/src/Arbor/File/Format/Asif/ByteString/Builder.hs
--- a/src/Arbor/File/Format/Asif/ByteString/Builder.hs
+++ b/src/Arbor/File/Format/Asif/ByteString/Builder.hs
@@ -1,5 +1,6 @@
-{-# LANGUAGE DataKinds        #-}
-{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE DataKinds         #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeApplications  #-}
 
 module Arbor.File.Format.Asif.ByteString.Builder
   ( magicString
diff --git a/src/Arbor/File/Format/Asif/Format/Text.hs b/src/Arbor/File/Format/Asif/Format/Text.hs
--- a/src/Arbor/File/Format/Asif/Format/Text.hs
+++ b/src/Arbor/File/Format/Asif/Format/Text.hs
@@ -1,20 +1,22 @@
-{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE LambdaCase        #-}
+{-# LANGUAGE OverloadedStrings #-}
+
 module Arbor.File.Format.Asif.Format.Text
-( segmentValueToText
-)
-where
+  ( segmentValueToText
+    ) where
 
-import qualified Arbor.File.Format.Asif.ByteString.Lazy     as LBS
-import           Arbor.File.Format.Asif.Data.Ip
-import           Arbor.File.Format.Asif.Format.SegmentValue
-import           Control.Lens
-import qualified Data.ByteString.Lazy                       as LBS
-import qualified Data.List                                  as L
-import           Data.Text                                  (Text)
-import qualified Data.Text                                  as T
-import qualified Data.Text.Encoding                         as T
-import           HaskellWorks.Data.Bits.BitShow             (bitShow)
-import           Numeric                                    (showHex)
+import Arbor.File.Format.Asif.Data.Ip
+import Arbor.File.Format.Asif.Format.SegmentValue
+import Control.Lens
+import Data.Text                                  (Text)
+import HaskellWorks.Data.Bits.BitShow             (bitShow)
+import Numeric                                    (showHex)
+
+import qualified Arbor.File.Format.Asif.ByteString.Lazy as LBS
+import qualified Data.ByteString.Lazy                   as LBS
+import qualified Data.List                              as L
+import qualified Data.Text                              as T
+import qualified Data.Text.Encoding                     as T
 
 segmentValueToText :: SegmentValue -> Text
 segmentValueToText = \case
diff --git a/src/Arbor/File/Format/Asif/Segment.hs b/src/Arbor/File/Format/Asif/Segment.hs
--- a/src/Arbor/File/Format/Asif/Segment.hs
+++ b/src/Arbor/File/Format/Asif/Segment.hs
@@ -1,5 +1,6 @@
-{-# LANGUAGE DataKinds        #-}
-{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE DataKinds         #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeApplications  #-}
 
 module Arbor.File.Format.Asif.Segment
   ( Z.Segment(..)
@@ -73,7 +74,7 @@
     let segs = fmap (\(o, l) -> LBS.take (fromIntegral l) $ LBS.drop (fromIntegral o) bs) header
     forM_ (zip segs header) $ \(seg, (_, len)) ->
       when (LC8.length seg /= fromIntegral len) $
-        fail "XXX segments not read correctly"
+        Left "XXX segments not read correctly"
     return segs
 
 segmentNamed :: String -> M.Map Text (Z.Segment LC8.ByteString) -> Either String LC8.ByteString
diff --git a/src/Arbor/File/Format/Asif/Write.hs b/src/Arbor/File/Format/Asif/Write.hs
--- a/src/Arbor/File/Format/Asif/Write.hs
+++ b/src/Arbor/File/Format/Asif/Write.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE DataKinds             #-}
-{-# LANGUAGE TypeApplications      #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TupleSections         #-}
+
 -- |
 -- Module: Arbor.File.Format.Asif.Write
 --
@@ -73,14 +74,14 @@
 import qualified Data.ByteString                   as BS
 import qualified Data.ByteString.Builder           as BB
 import qualified Data.ByteString.Lazy              as LBS
+import qualified Data.Foldable                     as Foldable
+import qualified Data.Map.Strict                   as Map
 import qualified Data.Text                         as T
 import qualified Data.Text.Encoding                as T
 import qualified Data.Text.Lazy                    as TL
 import qualified Data.Text.Lazy.Encoding           as TE
 import qualified HaskellWorks.Data.Network.Ip.Ipv4 as IP4
 import qualified HaskellWorks.Data.Network.Ip.Ipv6 as IP6
-import qualified Data.Map.Strict                   as Map
-import qualified Data.Foldable                     as Foldable
 
 import qualified Data.Thyme.Clock.POSIX as TY
 import qualified Data.Thyme.Time.Core   as TY
diff --git a/test/Arbor/File/Format/Asif/Format/SegmentValueSpec.hs b/test/Arbor/File/Format/Asif/Format/SegmentValueSpec.hs
--- a/test/Arbor/File/Format/Asif/Format/SegmentValueSpec.hs
+++ b/test/Arbor/File/Format/Asif/Format/SegmentValueSpec.hs
@@ -5,26 +5,23 @@
   ( spec
   ) where
 
-import           Arbor.File.Format.Asif.Data.Ip
-import           Arbor.File.Format.Asif.Format   as F
-import           Arbor.File.Format.Asif.Type
-import           Arbor.File.Format.Asif.Whatever
-import           Control.Lens
-import qualified Data.List                       as L
-import           Data.Semigroup                  ((<>))
-import           Data.Thyme.Time.Core
-
-import qualified Data.ByteString.Builder         as BB
-import qualified Data.ByteString.Lazy            as LBS
-import qualified Data.ByteString.Lazy.Char8      as LC8
-
-import           Arbor.TestUtils
-import           HaskellWorks.Hspec.Hedgehog
-import           Hedgehog
-import           Test.Hspec
+import Arbor.File.Format.Asif.Data.Ip
+import Arbor.File.Format.Asif.Format   as F
+import Arbor.File.Format.Asif.Type
+import Arbor.File.Format.Asif.Whatever
+import Arbor.TestUtils
+import Control.Lens
+import Data.Semigroup                  ((<>))
+import Data.Thyme.Time.Core
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
 
-import qualified Hedgehog.Gen                    as Gen
-import qualified Hedgehog.Range                  as Range
+import qualified Data.ByteString.Builder    as BB
+import qualified Data.ByteString.Lazy       as LBS
+import qualified Data.ByteString.Lazy.Char8 as LC8
+import qualified Hedgehog.Gen               as Gen
+import qualified Hedgehog.Range             as Range
 
 {-# ANN module ("HLint: ignore Redundant do"  :: String) #-}
 
