diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,8 @@
+
+# 0.1
+
+* Added doctests
+
 # 0.0.0.1
 
 * conception
diff --git a/cabal-fix.cabal b/cabal-fix.cabal
--- a/cabal-fix.cabal
+++ b/cabal-fix.cabal
@@ -1,31 +1,29 @@
 cabal-version: 3.0
 name: cabal-fix
-version: 0.0.0.2
+version: 0.1.0.0
 license: BSD-3-Clause
 license-file: LICENSE
 category: distribution
 author: Tony Day
 maintainer: tonyday567@gmail.com
-homepage: https://github.com/tonyday567/cabal-fixes#readme
-bug-reports: https://github.com/tonyday567/cabal-fixes/issues
+homepage: https://github.com/tonyday567/cabal-fix#readme
+bug-reports: https://github.com/tonyday567/cabal-fix/issues
 synopsis: Fix for cabal files.
 description:
     An executable and library to help fix cabal files and explore cabal.
 build-type: Simple
 tested-with:
-    GHC == 8.10.7
-    GHC == 9.2.8
-    GHC == 9.4.8
-    GHC == 9.6.4
-    GHC == 9.8.1
+    , GHC == 9.10.1
+    , GHC == 9.6.5
+    , GHC == 9.8.2
 extra-doc-files:
     ChangeLog.md
     other/textdeps.svg
-    readme.org
+    readme.md
 
 source-repository head
     type: git
-    location: https://github.com/tonyday567/cabal-fixes
+    location: https://github.com/tonyday567/cabal-fix
 
 common ghc-options-exe-stanza
     ghc-options:
@@ -44,67 +42,14 @@
         -Wredundant-constraints
 
 common ghc2021-stanza
-    if impl ( ghc >= 9.2 )
-        default-language: GHC2021
-
-    if impl ( ghc < 9.2 )
-        default-language: Haskell2010
-        default-extensions:
-            BangPatterns
-            BinaryLiterals
-            ConstrainedClassMethods
-            ConstraintKinds
-            DeriveDataTypeable
-            DeriveFoldable
-            DeriveFunctor
-            DeriveGeneric
-            DeriveLift
-            DeriveTraversable
-            DoAndIfThenElse
-            EmptyCase
-            EmptyDataDecls
-            EmptyDataDeriving
-            ExistentialQuantification
-            ExplicitForAll
-            FlexibleContexts
-            FlexibleInstances
-            ForeignFunctionInterface
-            GADTSyntax
-            GeneralisedNewtypeDeriving
-            HexFloatLiterals
-            ImplicitPrelude
-            InstanceSigs
-            KindSignatures
-            MonomorphismRestriction
-            MultiParamTypeClasses
-            NamedFieldPuns
-            NamedWildCards
-            NumericUnderscores
-            PatternGuards
-            PolyKinds
-            PostfixOperators
-            RankNTypes
-            RelaxedPolyRec
-            ScopedTypeVariables
-            StandaloneDeriving
-            StarIsType
-            TraditionalRecordSyntax
-            TupleSections
-            TypeApplications
-            TypeOperators
-            TypeSynonymInstances
-
-    if impl ( ghc < 9.2 ) && impl ( ghc >= 8.10 )
-        default-extensions:
-            ImportQualifiedPost
-            StandaloneKindSignatures
+    default-language: GHC2021
 
 library
     import: ghc-options-stanza
     import: ghc2021-stanza
     hs-source-dirs: src
     build-depends:
-        , Cabal-syntax       >=3.10 && <3.11
+        , Cabal-syntax       >=3.10 && <3.15
         , algebraic-graphs   >=0.7 && <0.8
         , base               >=4.14 && <5
         , bytestring         >=0.11 && <0.13
@@ -142,3 +87,13 @@
         , pretty-simple        >=4.1 && <4.2
         , text                 >=2.0 && <2.2
         , tree-diff            >=0.3 && <0.4
+
+test-suite doctests
+    import: ghc2021-stanza
+    main-is: doctests.hs
+    hs-source-dirs: test
+    build-depends:
+        , base             >=4.14 && <5
+        , doctest-parallel >=0.3 && <0.4
+    ghc-options: -threaded
+    type: exitcode-stdio-1.0
diff --git a/readme.md b/readme.md
new file mode 100644
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,828 @@
+
+# Table of Contents
+
+1.  [cabal-fix](#orgbfbcd8c)
+2.  [App Usage](#org2f4aafb)
+3.  [App Configuration](#orga921360)
+4.  [Library Usage](#orgbb0e777)
+5.  [cabal init](#orge6fca8d)
+    1.  [minimal](#orgc14dafe)
+    2.  [code example](#orgd8c294c)
+    3.  [simple](#org2493565)
+6.  [Archive Exploration](#org733a366)
+    1.  [imports](#org69e0aa6)
+    2.  [tar file to list of cabal files](#org241dfdb)
+        1.  [entries](#orgdc43fe9)
+        2.  [Maximum file size:](#org39c1923)
+        3.  [zero size](#orgcf21c34)
+        4.  [preferred-versions](#orgb39b7ed)
+        5.  [package.json](#org9b4f148)
+        6.  [cabal files](#orge4acb82)
+    3.  [latestCabals to CabalFields map](#org9ce30f8)
+    4.  [CabalFields map to dependency graph](#orgb4f4cbb)
+    5.  [algebraic-graphs](#org6f1757a)
+    6.  [sections](#orgd2876cc)
+        1.  [section count](#org39f7aed)
+        2.  [section types](#orge952475)
+        3.  [section in section](#org74c0b33)
+        4.  [zero-section cfs](#orgd5e491e)
+    7.  [Dependency counts](#org9a284e6)
+    8.  [version ranges](#org198f27d)
+        1.  [all versions are unique?](#org0b08b16)
+        2.  [Version counts](#org39af952)
+7.  [Field re-ordering](#org9771b7b)
+8.  [references](#org15314af)
+
+
+<a id="orgbfbcd8c"></a>
+
+# cabal-fix
+
+[![img](https://img.shields.io/hackage/v/cabal-fix.svg)](https://hackage.haskell.org/package/cabal-fix)
+[![img](https://github.com/tonyday567/cabal-fix/workflows/haskell-ci/badge.svg)](https://github.com/tonyday567/cabal-fix/actions?query=workflow%3Ahaskell-ci)
+
+`cabal-fix` helps fix your cabal files. This package:
+
+-   Contains an app which parses your existing cabal file, re-renders it according to some config, then either displays a diff or alters your cabal file, in-place.
+-   Is an idempotent parser of a cabal file or ByteString, into the `Field` type used in Cabal.
+-   Is an inexact printer.
+-   Contains code to explore the cabal index archive at the base of your cabal installation.
+
+
+<a id="org2f4aafb"></a>
+
+# App Usage
+
+    
+    #+end_export
+    cabal-fix --help
+
+    fixes your cabal file
+    
+    Usage: cabal-fix COMMAND [-d|--directory ARG] [-c|--config ARG]
+    
+      cabal fixer
+    
+    Available options:
+      -d,--directory ARG       project directory
+      -c,--config ARG          config file
+      -h,--help                Show this help text
+    
+    Available commands:
+      inplace                  fix cabal file inplace
+      check                    check cabal file
+      genConfig                generate config file
+
+
+<a id="orga921360"></a>
+
+# App Configuration
+
+The configuration of cabal-fix is encapsulated in the Config type. The configuration file generated by the app (via `cabal-fix genConfig`) just (pretty) prints defaultConfig.
+
+    import Text.Pretty.Simple
+    pPrint defaultConfig
+
+    Config
+        { freeTexts = [ "description" ]
+        , fieldRemovals = []
+        , preferredDeps =
+            [
+                ( "base"
+                , ">=4.7 && <5"
+                )
+            ]
+        , addFields = []
+        , fixCommas =
+            [
+                ( "extra-doc-files"
+                , NoCommas
+                )
+            ,
+                ( "build-depends"
+                , PrefixCommas
+                )
+            ]
+        , sortFieldLines =
+            [ "build-depends"
+            , "exposed-modules"
+            , "default-extensions"
+            , "ghc-options"
+            , "extra-doc-files"
+            , "tested-with"
+            ]
+        , sortFields = True
+        , fieldOrdering =
+            [
+                ( "cabal-version"
+                , 0.0
+                )
+            ,
+                ( "import"
+                , 1.0
+                )
+            ,
+                ( "main-is"
+                , 2.0
+                )
+            ,
+                ( "default-language"
+                , 3.0
+                )
+            ,
+                ( "name"
+                , 4.0
+                )
+            ,
+                ( "hs-source-dirs"
+                , 5.0
+                )
+            ,
+                ( "version"
+                , 6.0
+                )
+            ,
+                ( "build-depends"
+                , 7.0
+                )
+            ,
+                ( "exposed-modules"
+                , 8.0
+                )
+            ,
+                ( "license"
+                , 9.0
+                )
+            ,
+                ( "license-file"
+                , 10.0
+                )
+            ,
+                ( "other-modules"
+                , 11.0
+                )
+            ,
+                ( "copyright"
+                , 12.0
+                )
+            ,
+                ( "category"
+                , 13.0
+                )
+            ,
+                ( "author"
+                , 14.0
+                )
+            ,
+                ( "default-extensions"
+                , 15.0
+                )
+            ,
+                ( "ghc-options"
+                , 16.0
+                )
+            ,
+                ( "maintainer"
+                , 17.0
+                )
+            ,
+                ( "homepage"
+                , 18.0
+                )
+            ,
+                ( "bug-reports"
+                , 19.0
+                )
+            ,
+                ( "synopsis"
+                , 20.0
+                )
+            ,
+                ( "description"
+                , 21.0
+                )
+            ,
+                ( "build-type"
+                , 22.0
+                )
+            ,
+                ( "tested-with"
+                , 23.0
+                )
+            ,
+                ( "extra-doc-files"
+                , 24.0
+                )
+            ,
+                ( "source-repository"
+                , 25.0
+                )
+            ,
+                ( "type"
+                , 26.0
+                )
+            ,
+                ( "common"
+                , 27.0
+                )
+            ,
+                ( "location"
+                , 28.0
+                )
+            ,
+                ( "library"
+                , 29.0
+                )
+            ,
+                ( "executable"
+                , 30.0
+                )
+            ,
+                ( "test-suite"
+                , 31.0
+                )
+            ]
+        , fixBuildDeps = True
+        , depAlignment = DepAligned
+        , removeBlankFields = True
+        , valueAligned = ValueUnaligned
+        , sectionMargin = Margin
+        , commentMargin = NoMargin
+        , narrowN = 60
+        , indentN = 4
+        }
+
+
+<a id="orgbb0e777"></a>
+
+# Library Usage
+
+    :set -XOverloadedStrings
+    :set -XOverloadedLabels
+    :set -Wno-incomplete-uni-patterns
+    :set -Wno-name-shadowing
+    import CabalFix
+    import Optics.Extra
+    import Data.ByteString.Char8 qualified as C
+    bs = minimalExampleBS
+    cfg = defaultConfig
+    (Just cf) = preview (cabalFields' cfg) bs
+    fs = cf & view (#fields % fieldList')
+
+    Build profile: -w ghc-9.4.8 -O1
+    In order, the following will be built (use -v for more details):
+     - cabal-fix-0.0.0.1 (lib) (ephemeral targets)
+    Preprocessing library for cabal-fix-0.0.0.1..
+    GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
+    [1 of 4] Compiling CabalFix.FlatParse ( src/CabalFix/FlatParse.hs, interpreted )
+    [2 of 4] Compiling CabalFix         ( src/CabalFix.hs, interpreted )
+    [3 of 4] Compiling CabalFix.Archive ( src/CabalFix/Archive.hs, interpreted )
+    [4 of 4] Compiling CabalFix.Patch   ( src/CabalFix/Patch.hs, interpreted )
+    Ok, four modules loaded.
+
+    cf & review (cabalFields' cfg) & C.putStr
+
+    cabal-version: 3.0
+    name: minimal
+    version: 0.1.0.0
+    license: BSD-2-Clause
+    license-file: LICENSE
+    build-type: Simple
+    extra-doc-files: CHANGELOG.md
+    
+    common warnings
+        ghc-options: -Wall
+    
+    library
+        import: warnings
+        exposed-modules: MyLib
+        build-depends: base ^>=4.17.2.1
+        hs-source-dirs: src
+        default-language: GHC2021
+    
+    test-suite minimal-test
+        import: warnings
+        default-language: GHC2021
+        type: exitcode-stdio-1.0
+        hs-source-dirs: test
+        main-is: Main.hs
+        build-depends:
+            base ^>=4.17.2.1,
+            minimal
+
+
+<a id="orge6fca8d"></a>
+
+# cabal init
+
+
+<a id="orgc14dafe"></a>
+
+## minimal
+
+A minimal `cabal init`
+
+    mkdir minimal && cd minimal && cabal init --minimal --simple --overwrite --lib --tests --language=GHC2021 --license=BSD-2-Clause  -p minimal
+
+    [Log] Using cabal specification: 3.0
+    [Log] Creating fresh file LICENSE...
+    [Log] Creating fresh file CHANGELOG.md...
+    [Log] Creating fresh directory ./src...
+    [Log] Creating fresh file src/MyLib.hs...
+    [Log] Creating fresh directory ./test...
+    [Log] Creating fresh file test/Main.hs...
+    [Log] Creating fresh file minimal.cabal...
+    [Warning] No synopsis given. You should edit the .cabal file and add one.
+    [Info] You may want to edit the .cabal file and add a Description field.
+
+Compared with the original `cabal init` contents, `cabal-fix`:
+
+-   widens the `base` range, in line with standard practice.
+-   reorders the `test-suite` section fields, in line with the ordering of the `library` section ones.
+
+    cabal-fix check -d "minimal" -c "other/minimal.config"
+
+    Right (Just [
+      -"    build-depends:    base ^>=4.17.2.1",
+      +"    build-depends:    base >=4.14 && <5",
+      -"    default-language: GHC2021",
+      +"    main-is:          Main.hs",
+      -"    type:             exitcode-stdio-1.0",
+      +"    build-depends:",
+      -"    hs-source-dirs:   test",
+      +"        base    >=4.14 && <5,",
+      -"    main-is:          Main.hs",
+      +"        minimal",
+      -"    build-depends:",
+      +"    hs-source-dirs:   test",
+      -"        base ^>=4.17.2.1,",
+      +"    default-language: GHC2021",
+      -"        minimal",
+      +"    type:             exitcode-stdio-1.0"])
+
+
+<a id="orgd8c294c"></a>
+
+## code example
+
+For reference, the code below should produce the same results as the app run above:
+
+    :set -XOverloadedStrings
+    :set -XOverloadedLabels
+    :set -Wno-incomplete-uni-patterns
+    :set -Wno-name-shadowing
+    :set -Wno-type-defaults
+    import CabalFix
+    import Text.Pretty.Simple
+    import CabalFix.Patch
+    import Data.TreeDiff
+    bs = minimalExampleBS
+    cfg = minimalConfig
+    (Just cf) = preview (cabalFields' cfg) bs
+    bs' = review (cabalFields' cfg) cf
+    (Just cf') = preview (cabalFields' cfg) bs'
+    cfFixed = fixCabalFields cfg cf
+    bsFixed = review (cabalFields' cfg) cfFixed
+    fmap ansiWlBgEditExpr $ patch (C.lines bs) (C.lines bsFixed)
+
+    Just [
+      -"    build-depends:    base ^>=4.17.2.1",
+      +"    build-depends:    base >=4.14 && <5",
+      -"    default-language: GHC2021",
+      +"    main-is:          Main.hs",
+      -"    type:             exitcode-stdio-1.0",
+      +"    build-depends:",
+      -"    hs-source-dirs:   test",
+      +"        base    >=4.14 && <5,",
+      -"    main-is:          Main.hs",
+      +"        minimal",
+      -"    build-depends:",
+      +"    hs-source-dirs:   test",
+      -"        base ^>=4.17.2.1,",
+      +"    default-language: GHC2021",
+      -"        minimal",
+      +"    type:             exitcode-stdio-1.0"]
+
+
+<a id="org2493565"></a>
+
+## simple
+
+    mkdir simple && cd simple && cabal init --simple --overwrite --lib --tests --language=GHC2021 --license=BSD-2-Clause  -p simple
+
+    [Log] Using cabal specification: 3.0
+    [Log] Creating fresh file LICENSE...
+    [Log] Creating fresh file CHANGELOG.md...
+    [Log] Creating fresh directory ./src...
+    [Log] Creating fresh file src/MyLib.hs...
+    [Log] Creating fresh directory ./test...
+    [Log] Creating fresh file test/Main.hs...
+    [Log] Creating fresh file simple.cabal...
+    [Warning] No synopsis given. You should edit the .cabal file and add one.
+    [Info] You may want to edit the .cabal file and add a Description field.
+
+    cabal-fix check -d "simple" -c "other/minimal.config"
+
+    Right (Just [
+      +"cabal-version:   3.0",
+      -"cabal-version:      3.0",
+      +"",
+      -"name:               simple",
+      +"name:            simple",
+      -"version:            0.1.0.0",
+      +"version:         0.1.0.0",
+      -"license:            BSD-2-Clause",
+      +"license:         BSD-2-Clause",
+      -"license-file:       LICENSE",
+      +"license-file:    LICENSE",
+      -"build-type:         Simple",
+      +"build-type:      Simple",
+      -"extra-doc-files:    CHANGELOG.md",
+      +"extra-doc-files: CHANGELOG.md",
+      -"    build-depends:    base ^>=4.17.2.1",
+      +"    build-depends:    base >=4.14 && <5",
+      -"    -- Base language which the package is written in.",
+      +"    -- The entrypoint to the test suite.",
+      -"    default-language: GHC2021",
+      +"    main-is:          Main.hs",
+      -"    -- Modules included in this executable, other than Main.",
+      -"    -- other-modules:",
+      +"    -- Test dependencies.",
+      -"",
+      +"    build-depends:",
+      -"    -- LANGUAGE extensions used by modules in this package.",
+      +"        base   >=4.14 && <5,",
+      -"    -- other-extensions:",
+      +"        simple",
+      -"    -- The interface type and version of the test suite.",
+      +"    -- Directories containing source files.",
+      -"    type:             exitcode-stdio-1.0",
+      +"    hs-source-dirs:   test",
+      -"    -- Directories containing source files.",
+      +"    -- Base language which the package is written in.",
+      -"    hs-source-dirs:   test",
+      +"    default-language: GHC2021",
+      -"    -- The entrypoint to the test suite.",
+      +"    -- Modules included in this executable, other than Main.",
+      -"    main-is:          Main.hs",
+      +"    -- other-modules:",
+      +"    -- LANGUAGE extensions used by modules in this package.",
+      -"    -- Test dependencies.",
+      +"    -- other-extensions:",
+      -"    build-depends:",
+      +"",
+      -"        base ^>=4.17.2.1,",
+      +"    -- The interface type and version of the test suite.",
+      -"        simple",
+      +"    type:             exitcode-stdio-1.0"])
+
+
+<a id="org733a366"></a>
+
+# Archive Exploration
+
+CabalFix.Archive contains functions to extract and explore cabal files listed in your cabal index file.
+
+The sections below are some exploration notes.
+
+
+<a id="org69e0aa6"></a>
+
+## imports
+
+    :r
+    :set -Wno-type-defaults
+    :set -Wno-name-shadowing
+    :set -XOverloadedLabels
+    :set -XOverloadedStrings
+    :set -Wno-incomplete-uni-patterns
+    import Algebra.Graph
+    import Algebra.Graph.ToGraph qualified as ToGraph
+    import CabalFix
+    import CabalFix.Archive
+    import CabalFix.FlatParse
+    import Codec.Archive.Tar qualified as Tar
+    import Control.Monad
+    import Data.Bifunctor
+    import Data.ByteString (ByteString)
+    import Data.ByteString qualified as BS
+    import Data.ByteString.Char8 qualified as C
+    import Data.ByteString.Lazy qualified as BSL
+    import Data.Char
+    import Data.Either
+    import Data.Function
+    import Data.List qualified as List
+    import Data.Map.Strict qualified as Map
+    import Data.Ord
+    import Data.Set qualified as Set
+    import DotParse
+    import FlatParse.Basic qualified as FP
+    import System.Directory
+    import Text.Pretty.Simple
+
+    Ok, four modules loaded.
+
+
+<a id="org241dfdb"></a>
+
+## tar file to list of cabal files
+
+
+<a id="orgdc43fe9"></a>
+
+### entries
+
+    es <- cabalEntries
+    length es
+
+    317368
+
+    Tar.entryPath <$> take 5 es
+
+    ["iconv/0.2/iconv.cabal","Crypto/3.0.3/Crypto.cabal","HDBC/1.0.1/HDBC.cabal","HDBC-odbc/1.0.1.0/HDBC-odbc.cabal","HDBC-postgresql/1.0.1.0/HDBC-postgresql.cabal"]
+
+They are all normal files
+
+    (length [x | (Tar.NormalFile x _) <- Tar.entryContent <$> es])
+
+    317368
+
+
+<a id="org39c1923"></a>
+
+### Maximum file size:
+
+    (\xs -> filter ((maximum (snd <$> xs) ==) . snd) xs) $ [(fp,x) | (fp, Tar.NormalFile _ x) <- (\e -> (Tar.entryPath e, Tar.entryContent e)) <$> es]
+
+    [("acme-everything/2018.11.18/acme-everything.cabal",261865)]
+
+
+<a id="orgcf21c34"></a>
+
+### zero size
+
+    take 4 $ (\xs -> filter ((0 ==) . snd) xs) $ [(fp,x) | (fp, Tar.NormalFile _ x) <- (\e -> (Tar.entryPath e, Tar.entryContent e)) <$> es]
+
+    [("lzma/preferred-versions",0),("signal/preferred-versions",0),("peyotls-codec/preferred-versions",0),("th-orphans/preferred-versions",0)]
+
+
+<a id="orgb39b7ed"></a>
+
+### preferred-versions
+
+[Cabal: preferred and deprecated versions | Hackage](https://hackage.haskell.org/package/Cabal/preferred)
+
+    take 3 $ (\xs -> filter ((List.isSuffixOf "preferred-versions") . fst) xs) $ [(fp,bs) | (fp, Tar.NormalFile bs _) <- (\e -> (Tar.entryPath e, Tar.entryContent e)) <$> es]
+
+    [("ADPfusion/preferred-versions","ADPfusion <0.4.0.0 || >0.4.0.0"),("AesonBson/preferred-versions","AesonBson <0.2.0 || >0.2.0 && <0.2.1 || >0.2.1"),("BiobaseXNA/preferred-versions","BiobaseXNA <0.9.1.0 || >0.9.1.0")]
+
+    length $ (\xs -> filter ((List.isSuffixOf "preferred-versions") . fst) xs) $ [(fp,bs) | (fp, Tar.NormalFile bs _) <- (\e -> (Tar.entryPath e, Tar.entryContent e)) <$> es]
+
+    3376
+
+
+<a id="org9b4f148"></a>
+
+### package.json
+
+`package-json` content is a security/signing feature you can read about in [hackage-security](https://github.com/haskell-ng/hackage-security/blob/master/README.md).
+
+    length $ filter ((== "package.json") . filenameFN . runParser_ filenameP . FP.strToUtf8 . fst) $ filter (not . (List.isSuffixOf "preferred-versions") . fst) $ [(fp,bs) | (fp, Tar.NormalFile bs _) <- (\e -> (Tar.entryPath e, Tar.entryContent e)) <$> es]
+
+    137524
+
+
+<a id="orge4acb82"></a>
+
+### cabal files
+
+Unique package/version combinations.
+
+There are multiple versions of package/versions because of revisions. See [revisions-information.md](https://github.com/haskell-infra/hackage-trustees/blob/master/revisions-information.md)
+
+Unique `*/*.cabal/version` entries
+
+    cs <- cabals
+    length cs
+
+    137524
+
+Unique cabal packages
+
+    lcs <- latestCabals
+    Map.size lcs
+
+    17631
+
+Average number of versions per package
+
+    (fromIntegral (length cs)) / fromIntegral (Map.size lcs)
+
+    7.800124780216664
+
+
+<a id="org9ce30f8"></a>
+
+## latestCabals to CabalFields map
+
+    lcs <- latestCabals defaultConfig
+    Map.size lcs
+    cfg = defaultConfig
+    lcs' = fmap (second (parseCabalFields cfg)) lcs
+    Map.size $ Map.filter (snd >>> isLeft) lcs'
+    :t lcs'
+    badParse = Map.filter (isLeft . parseCabalFields cfg . snd) lcs
+    Map.size badParse
+
+    17631
+    6
+    lcs' :: Map.Map ByteString (Version, Either ByteString CabalFields)
+    6
+
+
+<a id="orgb4f4cbb"></a>
+
+## CabalFields map to dependency graph
+
+    lcfs <- latestCabalFields
+    vlds = validLibDeps $ fmap snd lcfs
+    Map.size vlds
+    depG = allDepGraph $ fmap snd lcfs
+    vertexCount depG
+    edgeCount depG
+
+    15547
+    15621
+    107566
+
+
+<a id="org6f1757a"></a>
+
+## algebraic-graphs
+
+An (algebraic) graph of dependencies:
+
+`text` package dependency example
+
+    supers = upstreams "text" depG <> Set.singleton "text"
+    superG = induce (`elem` (Data.Foldable.toList supers)) depG
+
+    supers
+
+    fromList ["array","binary","bytestring","deepseq","ghc-prim","template-haskell","text"]
+
+    baseGraph = defaultGraph & attL GraphType (ID "size") .~ Just (IDQuoted "5!") & attL NodeType (ID "shape") .~ Just (ID "box") & attL NodeType (ID "height") .~ Just (ID 2) & gattL (ID "rankdir") .~ Just (IDQuoted "TB")
+    g = toDotGraphWith Directed baseGraph superG
+    processDotWith Directed ["-Tsvg", "-oother/textdeps.svg"] (dotPrint defaultDotConfig g)
+    BS.writeFile "other/textdeps.dot" (dotPrint defaultDotConfig g)
+
+![img](other/textdeps.svg)
+
+
+<a id="orgd2876cc"></a>
+
+## sections
+
+
+<a id="org39f7aed"></a>
+
+### section count
+
+    cfs = lcfs & Map.toList & fmap (snd . snd)
+    cfs & toListOf (each % #fields % fieldList') & fmap (filter isSection >>> length) & count_
+
+    fromList [(0,359),(1,2559),(2,5508),(3,4730),(4,2224),(5,956),(6,479),(7,236),(8,138),(9,98),(10,63),(11,57),(12,31),(13,32),(14,22),(15,16),(16,12),(17,7),(18,11),(19,8),(20,8),(21,8),(22,4),(23,3),(24,7),(25,4),(26,6),(27,1),(28,1),(29,4),(30,2),(32,4),(33,2),(34,4),(36,1),(37,4),(38,1),(39,2),(40,1),(41,1),(43,2),(47,2),(48,2),(50,1),(65,1),(93,1),(97,1),(295,1)]
+
+
+<a id="orge952475"></a>
+
+### section types
+
+    cfs & toListOf (each % #fields % fieldList') & fmap (filter isSection) & fmap (fmap (view fieldName')) & mconcat & count_ & Map.toList & List.sortOn (Down . snd)
+
+    [("library",16028),("source-repository",13889),("test-suite",8718),("executable",7292),("flag",4134),("common",2302),("benchmark",1246),("custom-setup",321),("foreign-library",4)]
+
+combinations:
+
+    cfs & toListOf (each % #fields % fieldList') & fmap (filter isSection) & fmap (fmap (view fieldName')) & fmap (filter (not . (flip List.elem) ["source-repository", "custom-setup", "foreign-library", "flag", "common"])) & fmap (count_ >>> Map.toList >>> List.sortOn fst) & count_ & Map.toList & List.sortOn (Down . snd) & take 10
+
+    [([("library",1)],7291),([("library",1),("test-suite",1)],4195),([("executable",1),("library",1)],1148),([("executable",1)],1105),([("executable",1),("library",1),("test-suite",1)],901),([("benchmark",1),("library",1),("test-suite",1)],520),([("library",1),("test-suite",2)],416),([],359),([("executable",2),("library",1)],163),([("executable",2),("library",1),("test-suite",1)],133)]
+
+at least 1 combinations:
+
+    cfs & toListOf (each % #fields % fieldList') & fmap (filter isSection) & fmap (fmap (view fieldName')) & fmap (filter (not . (flip List.elem) ["source-repository", "custom-setup", "foreign-library", "flag", "common"])) & fmap (count_ >>> Map.toList >>> fmap fst >>> List.sortOn id) & count_ & Map.toList & List.sortOn (Down . snd) & take 10
+
+    [(["library"],7297),(["library","test-suite"],4778),(["executable","library"],1490),(["executable","library","test-suite"],1309),(["executable"],1263),(["benchmark","library","test-suite"],739),([],359),(["benchmark","executable","library","test-suite"],182),(["executable","test-suite"],119),(["benchmark","library"],59)]
+
+
+<a id="org74c0b33"></a>
+
+### section in section
+
+    sections' = to (filter isSection)
+    -- cfs & fmap (foldOf (#fields % fieldList' % sections' % each % secFields' % sections')) & filter (not . null) & fmap (second (fmap (view fieldName'))) & fmap snd & mconcat & count_
+    cfs & fmap (foldOf (#fields % fieldList' % sections' % each % secFields' % sections')) & filter (not . null) & fmap ((fmap (view fieldName'))) & mconcat & count_
+
+    fromList [("elif",52),("else",3203),("if",11459),("library",3)]
+
+Embedded libraries are all deprecated.
+
+
+<a id="orgd5e491e"></a>
+
+### zero-section cfs
+
+Looks like library fields used to be allowed at the top level&#x2026;
+
+    cfs0 = cfs & toListOf (each % #fields % fieldList') & filter ((==0) . length . (filter isSection))
+    length cfs0
+    count_ $ cfs0 & fmap (foldOf (field' "build-depends") >>> length)
+    cfs00 = cfs0 & filter (foldOf (field' "build-depends") >>> length >>> (==0))
+    length cfs00
+
+    359
+    fromList [(0,2),(1,349),(2,7),(4,1)]
+    2
+
+
+<a id="org9a284e6"></a>
+
+## Dependency counts
+
+package dependency count:
+
+    lcfs & fmap (snd >>> libDeps >>> fmap dep >>> List.nub >>> length) & Map.toList & List.sortOn (Down . snd) & take 20
+
+    [("acme-everything",7533),("yesod-platform",132),("planet-mitchell",109),("freckle-app",78),("cachix",76),("btc-lsp",71),("too-many-cells",70),("swarm",68),("ghcide",67),("pandoc",67),("sprinkles",65),("pantry-tmp",64),("taffybar",63),("NGLess",60),("project-m36",59),("stack",59),("espial",58),("hermes",58),("purescript",56),("futhark",55)]
+
+dependency count:
+
+    lcfs & fmap (snd >>> libDeps >>> fmap dep >>> List.nub) & Map.toList & fmap snd & mconcat & count_ & Map.toList & List.sortOn (snd >>> Down) & take 40
+
+    [("base",14883),("bytestring",5384),("text",4972),("containers",4753),("mtl",3468),("transformers",3070),("aeson",2013),("time",1961),("vector",1793),("directory",1597),("filepath",1510),("template-haskell",1472),("unordered-containers",1392),("deepseq",1240),("lens",1173),("hashable",930),("binary",929),("array",892),("exceptions",855),("process",844),("stm",819),("random",811),("http-types",784),("attoparsec",781),("network",756),("parsec",744),("data-default",609),("QuickCheck",597),("conduit",503),("http-client",497),("split",472),("primitive",470),("ghc-prim",456),("async",449),("semigroups",427),("monad-control",424),("scientific",420),("resourcet",401),("unix",398),("utf8-string",392)]
+
+
+<a id="org198f27d"></a>
+
+## version ranges
+
+    cs <- cabals
+    length cs
+
+    137323
+
+    :t cs
+    
+    mVersions = Map.fromListWith (<>) $ ((\x -> (nameFN x, (:[]) $ (versionInts $ versionFN x))) . fst) <$> cs
+    Map.size mVersions
+
+    cs :: [(FileName, ByteString)]
+    17631
+
+    (Just x1) = Map.lookup "chart-svg" mVersions
+    x1
+    minimum x1
+    maximum x1
+
+    [[0,6,0,0],[0,5,2,0],[0,5,1,1],[0,5,1,0],[0,5,0,0],[0,4,1,1],[0,4,1,0],[0,4,0],[0,3,3],[0,3,2],[0,3,1],[0,3,0],[0,2,3],[0,2,2],[0,2,1],[0,2,0],[0,1,3],[0,1,2],[0,1,1],[0,1,0],[0,0,3],[0,0,2],[0,0,1]]
+    [0,0,1]
+    [0,6,0,0]
+
+
+<a id="org0b08b16"></a>
+
+### all versions are unique?
+
+    take 10 $ Map.toList $ Map.filter (\a -> length a /= length (List.nub a)) mVersions
+
+    []
+
+
+<a id="org39af952"></a>
+
+### Version counts
+
+    take 10 $ List.sortOn (Down . snd) $ Map.toList $ Map.map length mVersions
+
+    [("haskoin-store",298),("git-annex",282),("hlint",221),("yesod-core",216),("purescript",204),("warp",204),("pandoc",193),("hakyll",192),("egison",190),("persistent",186)]
+
+
+<a id="org9771b7b"></a>
+
+# Field re-ordering
+
+    zipWith (\o l -> (fst l, o)) [0..] (List.sortOn snd $ fieldOrdering defaultConfig)
+
+    [("cabal-version",0),("import",1),("main-is",2),("default-language",3),("name",4),("hs-source-dirs",5),("version",6),("build-depends",7),("exposed-modules",8),("license",9),("license-file",10),("other-modules",11),("copyright",12),("category",13),("author",14),("default-extensions",15),("ghc-options",16),("maintainer",17),("homepage",18),("bug-reports",19),("synopsis",20),("description",21),("build-type",22),("tested-with",23),("extra-doc-files",24),("source-repository",25),("type",26),("common",27),("location",28),("library",29),("executable",30),("test-suite",31)]
+
+
+<a id="org15314af"></a>
+
+# references
+
+[Distribution.Fields.Field](https://hackage.haskell.org/package/Cabal-syntax-3.10.2.0/docs/Distribution-Fields-Field.html)
+
+[optics-core: Optics as an abstract interface: core definitions](https://hackage.haskell.org/package/optics-core-0.4.1.1)
+
+[6. Package Description — Cabal 3.10.1.0 User&rsquo;s Guide](https://cabal.readthedocs.io/en/stable/cabal-package.html#package-descriptions)
+
diff --git a/readme.org b/readme.org
deleted file mode 100644
--- a/readme.org
+++ /dev/null
@@ -1,838 +0,0 @@
-* cabal-fix
-
-[[https://hackage.haskell.org/package/cabal-fix][https://img.shields.io/hackage/v/cabal-fix.svg]]
-[[https://github.com/tonyday567/cabal-fix/actions?query=workflow%3Ahaskell-ci][https://github.com/tonyday567/cabal-fix/workflows/haskell-ci/badge.svg]]
-
-~cabal-fix~ helps fix your cabal files. This package:
-
-- Contains an app which parses your existing cabal file, re-renders it according to some config, then either displays a diff or alters your cabal file, in-place.
-- Is an idempotent parser of a cabal file or ByteString, into the ~Field~ type used in Cabal.
-- Is an inexact printer.
-- Contains code to explore the cabal index archive at the base of your cabal installation.
-
-* App Usage
-
-#+begin_src sh :results output :exports both
-
-#+end_export
-cabal-fix --help
-#+end_src
-
-#+RESULTS:
-#+begin_example
-fixes your cabal file
-
-Usage: cabal-fix COMMAND [-d|--directory ARG] [-c|--config ARG]
-
-  cabal fixer
-
-Available options:
-  -d,--directory ARG       project directory
-  -c,--config ARG          config file
-  -h,--help                Show this help text
-
-Available commands:
-  inplace                  fix cabal file inplace
-  check                    check cabal file
-  genConfig                generate config file
-#+end_example
-
-* App Configuration
-
-The configuration of cabal-fix is encapsulated in the Config type. The configuration file generated by the app (via =cabal-fix genConfig=) just (pretty) prints defaultConfig.
-
-#+begin_src haskell-ng :results output :exports both
-import Text.Pretty.Simple
-pPrint defaultConfig
-#+end_src
-
-#+RESULTS:
-#+begin_example
-Config
-    { freeTexts = [ "description" ]
-    , fieldRemovals = []
-    , preferredDeps =
-        [
-            ( "base"
-            , ">=4.7 && <5"
-            )
-        ]
-    , addFields = []
-    , fixCommas =
-        [
-            ( "extra-doc-files"
-            , NoCommas
-            )
-        ,
-            ( "build-depends"
-            , PrefixCommas
-            )
-        ]
-    , sortFieldLines =
-        [ "build-depends"
-        , "exposed-modules"
-        , "default-extensions"
-        , "ghc-options"
-        , "extra-doc-files"
-        , "tested-with"
-        ]
-    , sortFields = True
-    , fieldOrdering =
-        [
-            ( "cabal-version"
-            , 0.0
-            )
-        ,
-            ( "import"
-            , 1.0
-            )
-        ,
-            ( "main-is"
-            , 2.0
-            )
-        ,
-            ( "default-language"
-            , 3.0
-            )
-        ,
-            ( "name"
-            , 4.0
-            )
-        ,
-            ( "hs-source-dirs"
-            , 5.0
-            )
-        ,
-            ( "version"
-            , 6.0
-            )
-        ,
-            ( "build-depends"
-            , 7.0
-            )
-        ,
-            ( "exposed-modules"
-            , 8.0
-            )
-        ,
-            ( "license"
-            , 9.0
-            )
-        ,
-            ( "license-file"
-            , 10.0
-            )
-        ,
-            ( "other-modules"
-            , 11.0
-            )
-        ,
-            ( "copyright"
-            , 12.0
-            )
-        ,
-            ( "category"
-            , 13.0
-            )
-        ,
-            ( "author"
-            , 14.0
-            )
-        ,
-            ( "default-extensions"
-            , 15.0
-            )
-        ,
-            ( "ghc-options"
-            , 16.0
-            )
-        ,
-            ( "maintainer"
-            , 17.0
-            )
-        ,
-            ( "homepage"
-            , 18.0
-            )
-        ,
-            ( "bug-reports"
-            , 19.0
-            )
-        ,
-            ( "synopsis"
-            , 20.0
-            )
-        ,
-            ( "description"
-            , 21.0
-            )
-        ,
-            ( "build-type"
-            , 22.0
-            )
-        ,
-            ( "tested-with"
-            , 23.0
-            )
-        ,
-            ( "extra-doc-files"
-            , 24.0
-            )
-        ,
-            ( "source-repository"
-            , 25.0
-            )
-        ,
-            ( "type"
-            , 26.0
-            )
-        ,
-            ( "common"
-            , 27.0
-            )
-        ,
-            ( "location"
-            , 28.0
-            )
-        ,
-            ( "library"
-            , 29.0
-            )
-        ,
-            ( "executable"
-            , 30.0
-            )
-        ,
-            ( "test-suite"
-            , 31.0
-            )
-        ]
-    , fixBuildDeps = True
-    , depAlignment = DepAligned
-    , removeBlankFields = True
-    , valueAligned = ValueUnaligned
-    , sectionMargin = Margin
-    , commentMargin = NoMargin
-    , narrowN = 60
-    , indentN = 4
-    }
-#+end_example
-
-* Library Usage
-
-#+begin_src haskell-ng :results output :exports both
-:set -XOverloadedStrings
-:set -XOverloadedLabels
-:set -Wno-incomplete-uni-patterns
-:set -Wno-name-shadowing
-import CabalFix
-import Optics.Extra
-import Data.ByteString.Char8 qualified as C
-bs = minimalExampleBS
-cfg = defaultConfig
-(Just cf) = preview (cabalFields' cfg) bs
-fs = cf & view (#fields % fieldList')
-#+end_src
-
-#+RESULTS:
-#+begin_example
-Build profile: -w ghc-9.4.8 -O1
-In order, the following will be built (use -v for more details):
- - cabal-fix-0.0.0.1 (lib) (ephemeral targets)
-Preprocessing library for cabal-fix-0.0.0.1..
-GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
-[1 of 4] Compiling CabalFix.FlatParse ( src/CabalFix/FlatParse.hs, interpreted )
-[2 of 4] Compiling CabalFix         ( src/CabalFix.hs, interpreted )
-[3 of 4] Compiling CabalFix.Archive ( src/CabalFix/Archive.hs, interpreted )
-[4 of 4] Compiling CabalFix.Patch   ( src/CabalFix/Patch.hs, interpreted )
-Ok, four modules loaded.
-#+end_example
-
-#+begin_src haskell-ng :results output :exports both
-cf & review (cabalFields' cfg) & C.putStr
-#+end_src
-
-#+RESULTS:
-#+begin_example
-cabal-version: 3.0
-name: minimal
-version: 0.1.0.0
-license: BSD-2-Clause
-license-file: LICENSE
-build-type: Simple
-extra-doc-files: CHANGELOG.md
-
-common warnings
-    ghc-options: -Wall
-
-library
-    import: warnings
-    exposed-modules: MyLib
-    build-depends: base ^>=4.17.2.1
-    hs-source-dirs: src
-    default-language: GHC2021
-
-test-suite minimal-test
-    import: warnings
-    default-language: GHC2021
-    type: exitcode-stdio-1.0
-    hs-source-dirs: test
-    main-is: Main.hs
-    build-depends:
-        base ^>=4.17.2.1,
-        minimal
-#+end_example
-
-* cabal init
-
-** minimal
-
-A minimal =cabal init=
-
-#+begin_src sh :results output :exports both
-mkdir minimal && cd minimal && cabal init --minimal --simple --overwrite --lib --tests --language=GHC2021 --license=BSD-2-Clause  -p minimal
-#+end_src
-
-#+RESULTS:
-#+begin_example
-[Log] Using cabal specification: 3.0
-[Log] Creating fresh file LICENSE...
-[Log] Creating fresh file CHANGELOG.md...
-[Log] Creating fresh directory ./src...
-[Log] Creating fresh file src/MyLib.hs...
-[Log] Creating fresh directory ./test...
-[Log] Creating fresh file test/Main.hs...
-[Log] Creating fresh file minimal.cabal...
-[Warning] No synopsis given. You should edit the .cabal file and add one.
-[Info] You may want to edit the .cabal file and add a Description field.
-
-#+end_example
-
-Compared with the original =cabal init= contents, =cabal-fix=:
-
-- widens the =base= range, in line with standard practice.
-- reorders the =test-suite= section fields, in line with the ordering of the =library= section ones.
-
-#+begin_src sh :results output :exports both
-cabal-fix check -d "minimal" -c "other/minimal.config"
-#+end_src
-
-#+RESULTS:
-#+begin_example
-Right (Just [
-  -"    build-depends:    base ^>=4.17.2.1",
-  +"    build-depends:    base >=4.14 && <5",
-  -"    default-language: GHC2021",
-  +"    main-is:          Main.hs",
-  -"    type:             exitcode-stdio-1.0",
-  +"    build-depends:",
-  -"    hs-source-dirs:   test",
-  +"        base    >=4.14 && <5,",
-  -"    main-is:          Main.hs",
-  +"        minimal",
-  -"    build-depends:",
-  +"    hs-source-dirs:   test",
-  -"        base ^>=4.17.2.1,",
-  +"    default-language: GHC2021",
-  -"        minimal",
-  +"    type:             exitcode-stdio-1.0"])
-#+end_example
-
-** code example
-
-For reference, the code below should produce the same results as the app run above:
-
-#+begin_src haskell-ng :results output :exports both
-:set -XOverloadedStrings
-:set -XOverloadedLabels
-:set -Wno-incomplete-uni-patterns
-:set -Wno-name-shadowing
-:set -Wno-type-defaults
-import CabalFix
-import Text.Pretty.Simple
-import CabalFix.Patch
-import Data.TreeDiff
-bs = minimalExampleBS
-cfg = minimalConfig
-(Just cf) = preview (cabalFields' cfg) bs
-bs' = review (cabalFields' cfg) cf
-(Just cf') = preview (cabalFields' cfg) bs'
-cfFixed = fixCabalFields cfg cf
-bsFixed = review (cabalFields' cfg) cfFixed
-fmap ansiWlBgEditExpr $ patch (C.lines bs) (C.lines bsFixed)
-#+end_src
-
-#+RESULTS:
-#+begin_example
-Just [
-  -"    build-depends:    base ^>=4.17.2.1",
-  +"    build-depends:    base >=4.14 && <5",
-  -"    default-language: GHC2021",
-  +"    main-is:          Main.hs",
-  -"    type:             exitcode-stdio-1.0",
-  +"    build-depends:",
-  -"    hs-source-dirs:   test",
-  +"        base    >=4.14 && <5,",
-  -"    main-is:          Main.hs",
-  +"        minimal",
-  -"    build-depends:",
-  +"    hs-source-dirs:   test",
-  -"        base ^>=4.17.2.1,",
-  +"    default-language: GHC2021",
-  -"        minimal",
-  +"    type:             exitcode-stdio-1.0"]
-#+end_example
-
-** simple
-
-#+begin_src sh :results output :exports both
-mkdir simple && cd simple && cabal init --simple --overwrite --lib --tests --language=GHC2021 --license=BSD-2-Clause  -p simple
-#+end_src
-
-#+RESULTS:
-#+begin_example
-[Log] Using cabal specification: 3.0
-[Log] Creating fresh file LICENSE...
-[Log] Creating fresh file CHANGELOG.md...
-[Log] Creating fresh directory ./src...
-[Log] Creating fresh file src/MyLib.hs...
-[Log] Creating fresh directory ./test...
-[Log] Creating fresh file test/Main.hs...
-[Log] Creating fresh file simple.cabal...
-[Warning] No synopsis given. You should edit the .cabal file and add one.
-[Info] You may want to edit the .cabal file and add a Description field.
-
-#+end_example
-
-#+begin_src sh :results output :exports both
-cabal-fix check -d "simple" -c "other/minimal.config"
-#+end_src
-
-#+RESULTS:
-#+begin_example
-Right (Just [
-  +"cabal-version:   3.0",
-  -"cabal-version:      3.0",
-  +"",
-  -"name:               simple",
-  +"name:            simple",
-  -"version:            0.1.0.0",
-  +"version:         0.1.0.0",
-  -"license:            BSD-2-Clause",
-  +"license:         BSD-2-Clause",
-  -"license-file:       LICENSE",
-  +"license-file:    LICENSE",
-  -"build-type:         Simple",
-  +"build-type:      Simple",
-  -"extra-doc-files:    CHANGELOG.md",
-  +"extra-doc-files: CHANGELOG.md",
-  -"    build-depends:    base ^>=4.17.2.1",
-  +"    build-depends:    base >=4.14 && <5",
-  -"    -- Base language which the package is written in.",
-  +"    -- The entrypoint to the test suite.",
-  -"    default-language: GHC2021",
-  +"    main-is:          Main.hs",
-  -"    -- Modules included in this executable, other than Main.",
-  -"    -- other-modules:",
-  +"    -- Test dependencies.",
-  -"",
-  +"    build-depends:",
-  -"    -- LANGUAGE extensions used by modules in this package.",
-  +"        base   >=4.14 && <5,",
-  -"    -- other-extensions:",
-  +"        simple",
-  -"    -- The interface type and version of the test suite.",
-  +"    -- Directories containing source files.",
-  -"    type:             exitcode-stdio-1.0",
-  +"    hs-source-dirs:   test",
-  -"    -- Directories containing source files.",
-  +"    -- Base language which the package is written in.",
-  -"    hs-source-dirs:   test",
-  +"    default-language: GHC2021",
-  -"    -- The entrypoint to the test suite.",
-  +"    -- Modules included in this executable, other than Main.",
-  -"    main-is:          Main.hs",
-  +"    -- other-modules:",
-  +"    -- LANGUAGE extensions used by modules in this package.",
-  -"    -- Test dependencies.",
-  +"    -- other-extensions:",
-  -"    build-depends:",
-  +"",
-  -"        base ^>=4.17.2.1,",
-  +"    -- The interface type and version of the test suite.",
-  -"        simple",
-  +"    type:             exitcode-stdio-1.0"])
-#+end_example
-
-* Archive Exploration
-
-CabalFix.Archive contains functions to extract and explore cabal files listed in your cabal index file.
-
-The sections below are some exploration notes.
-
-** imports
-#+begin_src haskell-ng :results output :exports both
-:r
-:set -Wno-type-defaults
-:set -Wno-name-shadowing
-:set -XOverloadedLabels
-:set -XOverloadedStrings
-:set -Wno-incomplete-uni-patterns
-import Algebra.Graph
-import Algebra.Graph.ToGraph qualified as ToGraph
-import CabalFix
-import CabalFix.Archive
-import CabalFix.FlatParse
-import Codec.Archive.Tar qualified as Tar
-import Control.Monad
-import Data.Bifunctor
-import Data.ByteString (ByteString)
-import Data.ByteString qualified as BS
-import Data.ByteString.Char8 qualified as C
-import Data.ByteString.Lazy qualified as BSL
-import Data.Char
-import Data.Either
-import Data.Function
-import Data.List qualified as List
-import Data.Map.Strict qualified as Map
-import Data.Ord
-import Data.Set qualified as Set
-import DotParse
-import FlatParse.Basic qualified as FP
-import System.Directory
-import Text.Pretty.Simple
-#+end_src
-
-#+RESULTS:
-: Ok, four modules loaded.
-
-** tar file to list of cabal files
-*** entries
-
-#+begin_src haskell-ng :results output :exports both
-es <- cabalEntries
-length es
-#+end_src
-
-#+RESULTS:
-: 317368
-
-#+begin_src haskell-ng :results output :exports both
-Tar.entryPath <$> take 5 es
-#+end_src
-
-#+RESULTS:
-: ["iconv/0.2/iconv.cabal","Crypto/3.0.3/Crypto.cabal","HDBC/1.0.1/HDBC.cabal","HDBC-odbc/1.0.1.0/HDBC-odbc.cabal","HDBC-postgresql/1.0.1.0/HDBC-postgresql.cabal"]
-
-They are all normal files
-
-#+begin_src haskell-ng :results output :exports both
-(length [x | (Tar.NormalFile x _) <- Tar.entryContent <$> es])
-#+end_src
-
-#+RESULTS:
-: 317368
-
-*** Maximum file size:
-
-#+begin_src haskell-ng :results output :exports both
-(\xs -> filter ((maximum (snd <$> xs) ==) . snd) xs) $ [(fp,x) | (fp, Tar.NormalFile _ x) <- (\e -> (Tar.entryPath e, Tar.entryContent e)) <$> es]
-#+end_src
-
-#+RESULTS:
-: [("acme-everything/2018.11.18/acme-everything.cabal",261865)]
-
-*** zero size
-
-#+begin_src haskell-ng :results output :exports both
-take 4 $ (\xs -> filter ((0 ==) . snd) xs) $ [(fp,x) | (fp, Tar.NormalFile _ x) <- (\e -> (Tar.entryPath e, Tar.entryContent e)) <$> es]
-#+end_src
-
-#+RESULTS:
-: [("lzma/preferred-versions",0),("signal/preferred-versions",0),("peyotls-codec/preferred-versions",0),("th-orphans/preferred-versions",0)]
-
-*** preferred-versions
-
-[[https://hackage.haskell.org/package/Cabal/preferred][Cabal: preferred and deprecated versions | Hackage]]
-
-#+begin_src haskell-ng :results output :exports both
-take 3 $ (\xs -> filter ((List.isSuffixOf "preferred-versions") . fst) xs) $ [(fp,bs) | (fp, Tar.NormalFile bs _) <- (\e -> (Tar.entryPath e, Tar.entryContent e)) <$> es]
-#+end_src
-
-#+RESULTS:
-: [("ADPfusion/preferred-versions","ADPfusion <0.4.0.0 || >0.4.0.0"),("AesonBson/preferred-versions","AesonBson <0.2.0 || >0.2.0 && <0.2.1 || >0.2.1"),("BiobaseXNA/preferred-versions","BiobaseXNA <0.9.1.0 || >0.9.1.0")]
-
-#+begin_src haskell-ng :results output :exports both
-length $ (\xs -> filter ((List.isSuffixOf "preferred-versions") . fst) xs) $ [(fp,bs) | (fp, Tar.NormalFile bs _) <- (\e -> (Tar.entryPath e, Tar.entryContent e)) <$> es]
-#+end_src
-
-#+RESULTS:
-: 3376
-
-*** package.json
-
-=package-json= content is a security/signing feature you can read about in [[https://github.com/haskell-ng/hackage-security/blob/master/README.md][hackage-security]].
-
-#+begin_src haskell-ng :results output :exports both
-length $ filter ((== "package.json") . filenameFN . runParser_ filenameP . FP.strToUtf8 . fst) $ filter (not . (List.isSuffixOf "preferred-versions") . fst) $ [(fp,bs) | (fp, Tar.NormalFile bs _) <- (\e -> (Tar.entryPath e, Tar.entryContent e)) <$> es]
-#+end_src
-
-#+RESULTS:
-: 137524
-
-*** cabal files
-
-Unique package/version combinations.
-
-There are multiple versions of package/versions because of revisions. See [[https://github.com/haskell-infra/hackage-trustees/blob/master/revisions-information.md][revisions-information.md]]
-
-Unique =*/*.cabal/version= entries
-
-#+begin_src haskell-ng :results output :exports both
-cs <- cabals
-length cs
-#+end_src
-
-#+RESULTS:
-: 137524
-
-Unique cabal packages
-
-#+begin_src haskell-ng :results output :exports both
-lcs <- latestCabals
-Map.size lcs
-#+end_src
-
-#+RESULTS:
-: 17631
-
-Average number of versions per package
-
-#+begin_src haskell-ng :results output :exports both
-(fromIntegral (length cs)) / fromIntegral (Map.size lcs)
-#+end_src
-
-#+RESULTS:
-: 7.800124780216664
-
-** latestCabals to CabalFields map
-
-#+begin_src haskell-ng :results output :exports both
-lcs <- latestCabals defaultConfig
-Map.size lcs
-cfg = defaultConfig
-lcs' = fmap (second (parseCabalFields cfg)) lcs
-Map.size $ Map.filter (snd >>> isLeft) lcs'
-:t lcs'
-badParse = Map.filter (isLeft . parseCabalFields cfg . snd) lcs
-Map.size badParse
-#+end_src
-
-#+RESULTS:
-: 17631
-: 6
-: lcs' :: Map.Map ByteString (Version, Either ByteString CabalFields)
-: 6
-** CabalFields map to dependency graph
-
-#+begin_src haskell-ng :results output :exports both
-lcfs <- latestCabalFields
-vlds = validLibDeps $ fmap snd lcfs
-Map.size vlds
-depG = allDepGraph $ fmap snd lcfs
-vertexCount depG
-edgeCount depG
-#+end_src
-
-#+RESULTS:
-: 15547
-: 15621
-: 107566
-
-** algebraic-graphs
-
-An (algebraic) graph of dependencies:
-
-=text= package dependency example
-
-#+begin_src haskell-ng
-supers = upstreams "text" depG <> Set.singleton "text"
-superG = induce (`elem` (Data.Foldable.toList supers)) depG
-#+end_src
-
-#+RESULTS:
-
-#+begin_src haskell-ng :results output :exports both
-supers
-#+end_src
-
-#+RESULTS:
-: fromList ["array","binary","bytestring","deepseq","ghc-prim","template-haskell","text"]
-
-
-#+begin_src haskell-ng :file other/textdeps.svg :results output graphics file :exports results
- baseGraph = defaultGraph & attL GraphType (ID "size") .~ Just (IDQuoted "5!") & attL NodeType (ID "shape") .~ Just (ID "box") & attL NodeType (ID "height") .~ Just (ID 2) & gattL (ID "rankdir") .~ Just (IDQuoted "TB")
- g = toDotGraphWith Directed baseGraph superG
- processDotWith Directed ["-Tsvg", "-oother/textdeps.svg"] (dotPrint defaultDotConfig g)
- BS.writeFile "other/textdeps.dot" (dotPrint defaultDotConfig g)
- #+end_src
-
-#+RESULTS:
-[[file:other/textdeps.svg]]
-
-** sections
-*** section count
-
-#+begin_src haskell-ng :results output :exports both
-cfs = lcfs & Map.toList & fmap (snd . snd)
-cfs & toListOf (each % #fields % fieldList') & fmap (filter isSection >>> length) & count_
-#+end_src
-
-#+RESULTS:
-: fromList [(0,359),(1,2559),(2,5508),(3,4730),(4,2224),(5,956),(6,479),(7,236),(8,138),(9,98),(10,63),(11,57),(12,31),(13,32),(14,22),(15,16),(16,12),(17,7),(18,11),(19,8),(20,8),(21,8),(22,4),(23,3),(24,7),(25,4),(26,6),(27,1),(28,1),(29,4),(30,2),(32,4),(33,2),(34,4),(36,1),(37,4),(38,1),(39,2),(40,1),(41,1),(43,2),(47,2),(48,2),(50,1),(65,1),(93,1),(97,1),(295,1)]
-
-*** section types
-
-#+begin_src haskell-ng
-cfs & toListOf (each % #fields % fieldList') & fmap (filter isSection) & fmap (fmap (view fieldName')) & mconcat & count_ & Map.toList & List.sortOn (Down . snd)
-
-#+end_src
-
-#+RESULTS:
-: [("library",16028),("source-repository",13889),("test-suite",8718),("executable",7292),("flag",4134),("common",2302),("benchmark",1246),("custom-setup",321),("foreign-library",4)]
-
-combinations:
-
-#+begin_src haskell-ng :results output :exports both
-cfs & toListOf (each % #fields % fieldList') & fmap (filter isSection) & fmap (fmap (view fieldName')) & fmap (filter (not . (flip List.elem) ["source-repository", "custom-setup", "foreign-library", "flag", "common"])) & fmap (count_ >>> Map.toList >>> List.sortOn fst) & count_ & Map.toList & List.sortOn (Down . snd) & take 10
-#+end_src
-
-#+RESULTS:
-: [([("library",1)],7291),([("library",1),("test-suite",1)],4195),([("executable",1),("library",1)],1148),([("executable",1)],1105),([("executable",1),("library",1),("test-suite",1)],901),([("benchmark",1),("library",1),("test-suite",1)],520),([("library",1),("test-suite",2)],416),([],359),([("executable",2),("library",1)],163),([("executable",2),("library",1),("test-suite",1)],133)]
-
-at least 1 combinations:
-
-#+begin_src haskell-ng :results output :exports both
-cfs & toListOf (each % #fields % fieldList') & fmap (filter isSection) & fmap (fmap (view fieldName')) & fmap (filter (not . (flip List.elem) ["source-repository", "custom-setup", "foreign-library", "flag", "common"])) & fmap (count_ >>> Map.toList >>> fmap fst >>> List.sortOn id) & count_ & Map.toList & List.sortOn (Down . snd) & take 10
-#+end_src
-
-#+RESULTS:
-: [(["library"],7297),(["library","test-suite"],4778),(["executable","library"],1490),(["executable","library","test-suite"],1309),(["executable"],1263),(["benchmark","library","test-suite"],739),([],359),(["benchmark","executable","library","test-suite"],182),(["executable","test-suite"],119),(["benchmark","library"],59)]
-
-*** section in section
-
-#+begin_src haskell-ng :results output :exports both
-sections' = to (filter isSection)
--- cfs & fmap (foldOf (#fields % fieldList' % sections' % each % secFields' % sections')) & filter (not . null) & fmap (second (fmap (view fieldName'))) & fmap snd & mconcat & count_
-cfs & fmap (foldOf (#fields % fieldList' % sections' % each % secFields' % sections')) & filter (not . null) & fmap ((fmap (view fieldName'))) & mconcat & count_
-#+end_src
-
-#+RESULTS:
-: fromList [("elif",52),("else",3203),("if",11459),("library",3)]
-
-Embedded libraries are all deprecated.
-
-*** zero-section cfs
-
-Looks like library fields used to be allowed at the top level...
-
-#+begin_src haskell-ng :results output :exports both
-cfs0 = cfs & toListOf (each % #fields % fieldList') & filter ((==0) . length . (filter isSection))
-length cfs0
-count_ $ cfs0 & fmap (foldOf (field' "build-depends") >>> length)
-cfs00 = cfs0 & filter (foldOf (field' "build-depends") >>> length >>> (==0))
-length cfs00
-#+end_src
-
-#+RESULTS:
-: 359
-: fromList [(0,2),(1,349),(2,7),(4,1)]
-: 2
-
-** Dependency counts
-
-package dependency count:
-
-#+begin_src haskell-ng :results output :exports both
-lcfs & fmap (snd >>> libDeps >>> fmap dep >>> List.nub >>> length) & Map.toList & List.sortOn (Down . snd) & take 20
-#+end_src
-
-#+RESULTS:
-: [("acme-everything",7533),("yesod-platform",132),("planet-mitchell",109),("freckle-app",78),("cachix",76),("btc-lsp",71),("too-many-cells",70),("swarm",68),("ghcide",67),("pandoc",67),("sprinkles",65),("pantry-tmp",64),("taffybar",63),("NGLess",60),("project-m36",59),("stack",59),("espial",58),("hermes",58),("purescript",56),("futhark",55)]
-
-dependency count:
-
-#+begin_src haskell-ng :results output :exports both
-lcfs & fmap (snd >>> libDeps >>> fmap dep >>> List.nub) & Map.toList & fmap snd & mconcat & count_ & Map.toList & List.sortOn (snd >>> Down) & take 40
-#+end_src
-
-#+RESULTS:
-: [("base",14883),("bytestring",5384),("text",4972),("containers",4753),("mtl",3468),("transformers",3070),("aeson",2013),("time",1961),("vector",1793),("directory",1597),("filepath",1510),("template-haskell",1472),("unordered-containers",1392),("deepseq",1240),("lens",1173),("hashable",930),("binary",929),("array",892),("exceptions",855),("process",844),("stm",819),("random",811),("http-types",784),("attoparsec",781),("network",756),("parsec",744),("data-default",609),("QuickCheck",597),("conduit",503),("http-client",497),("split",472),("primitive",470),("ghc-prim",456),("async",449),("semigroups",427),("monad-control",424),("scientific",420),("resourcet",401),("unix",398),("utf8-string",392)]
-
-** version ranges
-
-#+begin_src haskell-ng :results output :exports both
-cs <- cabals
-length cs
-#+end_src
-
-#+RESULTS:
-: 137323
-
-#+begin_src haskell-ng :results output :exports both
-:t cs
-
-mVersions = Map.fromListWith (<>) $ ((\x -> (nameFN x, (:[]) $ (versionInts $ versionFN x))) . fst) <$> cs
-Map.size mVersions
-#+end_src
-
-#+RESULTS:
-: cs :: [(FileName, ByteString)]
-: 17631
-
-#+begin_src haskell-ng :results output :exports both
-(Just x1) = Map.lookup "chart-svg" mVersions
-x1
-minimum x1
-maximum x1
-#+end_src
-
-#+RESULTS:
-: [[0,6,0,0],[0,5,2,0],[0,5,1,1],[0,5,1,0],[0,5,0,0],[0,4,1,1],[0,4,1,0],[0,4,0],[0,3,3],[0,3,2],[0,3,1],[0,3,0],[0,2,3],[0,2,2],[0,2,1],[0,2,0],[0,1,3],[0,1,2],[0,1,1],[0,1,0],[0,0,3],[0,0,2],[0,0,1]]
-: [0,0,1]
-: [0,6,0,0]
-
-*** all versions are unique?
-
-#+begin_src haskell-ng :results output :exports both
-take 10 $ Map.toList $ Map.filter (\a -> length a /= length (List.nub a)) mVersions
-#+end_src
-
-#+RESULTS:
-: []
-
-*** Version counts
-
-#+begin_src haskell-ng :results output :exports both
-take 10 $ List.sortOn (Down . snd) $ Map.toList $ Map.map length mVersions
-#+end_src
-
-#+RESULTS:
-: [("haskoin-store",298),("git-annex",282),("hlint",221),("yesod-core",216),("purescript",204),("warp",204),("pandoc",193),("hakyll",192),("egison",190),("persistent",186)]
-
-* Field re-ordering
-
-#+begin_src haskell-ng :results output :exports both
-zipWith (\o l -> (fst l, o)) [0..] (List.sortOn snd $ fieldOrdering defaultConfig)
-#+end_src
-
-#+RESULTS:
-: [("cabal-version",0),("import",1),("main-is",2),("default-language",3),("name",4),("hs-source-dirs",5),("version",6),("build-depends",7),("exposed-modules",8),("license",9),("license-file",10),("other-modules",11),("copyright",12),("category",13),("author",14),("default-extensions",15),("ghc-options",16),("maintainer",17),("homepage",18),("bug-reports",19),("synopsis",20),("description",21),("build-type",22),("tested-with",23),("extra-doc-files",24),("source-repository",25),("type",26),("common",27),("location",28),("library",29),("executable",30),("test-suite",31)]
-
-* references
-
-[[https://hackage.haskell.org/package/Cabal-syntax-3.10.2.0/docs/Distribution-Fields-Field.html][Distribution.Fields.Field]]
-
-[[https://hackage.haskell.org/package/optics-core-0.4.1.1][optics-core: Optics as an abstract interface: core definitions]]
-
-[[https://cabal.readthedocs.io/en/stable/cabal-package.html#package-descriptions][6. Package Description — Cabal 3.10.1.0 User's Guide]]
diff --git a/src/CabalFix.hs b/src/CabalFix.hs
--- a/src/CabalFix.hs
+++ b/src/CabalFix.hs
@@ -1,15 +1,13 @@
 {-# LANGUAGE DataKinds #-}
-{-# LANGUAGE DerivingStrategies #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE OverloadedLabels #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE QuasiQuotes #-}
 {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
-{-# OPTIONS_GHC -Wno-name-shadowing #-}
 {-# OPTIONS_GHC -Wno-orphans #-}
-{-# OPTIONS_GHC -Wno-unused-matches #-}
+{-# OPTIONS_GHC -Wno-x-partial #-}
 
--- | Tools to print, parse and fix cabal files, 'ByteString' and 'Field' lists.
+-- | Tools to print, parse and fix cabal files.
 module CabalFix
   ( -- * Usage
     -- $usage
@@ -104,6 +102,7 @@
 --
 -- >>> :set -XOverloadedStrings
 -- >>> :set -XOverloadedLabels
+-- >>> :set -Wno-x-partial
 -- >>> import CabalFix
 -- >>> import Optics.Extra
 -- >>> import Data.ByteString.Char8 qualified as C
@@ -374,10 +373,10 @@
 fieldSet :: FieldName -> CabalFields -> Maybe (Field Comment) -> CabalFields
 fieldSet name cf f =
   case V.findIndex ((== name) . getName . fieldName) (view #fields cf) of
-    Just i -> case f of
-      Nothing -> cf & over #fields (\v -> V.take i v <> V.drop (i + 1) v)
-      Just f' -> cf & over #fields (\v -> V.take i v <> V.singleton f' <> V.drop (i + 1) v)
-    Nothing -> cf & maybe id (over #fields . (\f -> (<> V.singleton f))) f
+    Just i' -> case f of
+      Nothing -> cf & over #fields (\v -> V.take i' v <> V.drop (i' + 1) v)
+      Just f' -> cf & over #fields (\v -> V.take i' v <> V.singleton f' <> V.drop (i' + 1) v)
+    Nothing -> cf & maybe id (over #fields . (\x -> (<> V.singleton x))) f
 
 -- | A lens by name into a field (but not a section).
 --
@@ -633,7 +632,7 @@
 -- >>> fs & toListOf (section' "test-suite" % each % secFields' % field' "build-depends" % each) & fmap (fixBuildDeps cfg "minimal")
 -- [Field (Name [] "build-depends") [FieldLine [] ", base    >=4.14 && <5",FieldLine [] ", minimal"]]
 fixBuildDeps :: Config -> FieldName -> Field ann -> Field ann
-fixBuildDeps cfg pname f = overField (bool id (over fieldLines' (fixBDLines cfg pname)) (isName "build-depends" f)) f
+fixBuildDeps cfg pn f = overField (bool id (over fieldLines' (fixBDLines cfg pn)) (isName "build-depends" f)) f
 
 fixBDLines :: Config -> ByteString -> [FieldLine ann] -> [FieldLine ann]
 fixBDLines cfg libdep fls = fls'
@@ -725,7 +724,7 @@
   PP.vcat $
     mconcat $
       [ PP.text . fromUTF8BS <$> cs <> [bs]
-        | FieldLine cs bs <- fls
+      | FieldLine cs bs <- fls
       ]
 
 -- | Used in 'fromParsecFields'.
@@ -856,7 +855,7 @@
 parseCabalFields cfg bs = case readFields bs of
   Left err -> Left $ C.pack (show err)
   Right fps ->
-    (\(fs, ec) -> Right (CabalFields (V.fromList fs) ec)) $
+    (\(fs', ec) -> Right (CabalFields (V.fromList fs') ec)) $
       foldl' (&) (fmap (fmap (const [])) fs, []) (uncurry addComment <$> cfs)
     where
       fs = convertFreeTexts (view #freeTexts cfg) fps
@@ -925,7 +924,7 @@
 makePositionTree :: [Field Position] -> Map.Map Int ([Int], String)
 makePositionTree fs = foldFss Map.empty [] fs
   where
-    foldFss m cursor fs = fst $ foldl' stepFss (m, cursor <> [0]) fs
+    foldFss m cursor fs' = fst $ foldl' stepFss (m, cursor <> [0]) fs'
     stepFss (m, cursor) (Field (Name (Position c _) _) fls) =
       (foldFls (Map.insertWith (\_ o -> o) c (cursor, "fieldname") m) cursor fls, inc cursor)
     stepFss (m, cursor) (Section (Name (Position c _) _) sas fss) =
@@ -944,7 +943,7 @@
 addComment (Just (cursor, tag)) cs (fs, extras) = (addc cs cursor tag fs, extras)
 
 addc :: [ByteString] -> [Int] -> String -> [Field [ByteString]] -> [Field [ByteString]]
-addc comments [] _ fs = fs
+addc _ [] _ fs = fs
 addc comments [x] "fieldname" fs = take x fs <> [f'] <> drop (x + 1) fs
   where
     (Field (Name cs n) fls) = (List.!!) fs x
diff --git a/src/CabalFix/Archive.hs b/src/CabalFix/Archive.hs
--- a/src/CabalFix/Archive.hs
+++ b/src/CabalFix/Archive.hs
@@ -1,6 +1,5 @@
 {-# LANGUAGE OverloadedLabels #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# OPTIONS_GHC -Wno-name-shadowing #-}
 
 -- | Archive investigation
 module CabalFix.Archive where
@@ -83,13 +82,13 @@
   where
     libFields = cf & foldOf (#fields % fieldList' % section' "library" % each % secFields')
     libBds = libFields & foldOf (fieldValues' "build-depends")
-    libDeps = runParser_ (FP.many depP) libBds
+    libDeps' = runParser_ (FP.many depP) libBds
     libImports = libFields & toListOf (fieldValues' "import")
     cs = cf & foldOf (#fields % fieldList' % section' "common")
     libCommons = cs & filter (all (`elem` libImports) . toListOf (secArgs' % each % secArgBS' % _2))
     commonsBds = libCommons & foldOf (fieldValues' "build-depends")
     commonsDeps = runParser_ (FP.many depP) commonsBds
-    deps = fmap (uncurry Dep) (libDeps <> commonsDeps)
+    deps = fmap (uncurry Dep) (libDeps' <> commonsDeps)
 
 -- | Map of valid dependencies
 validLibDeps :: Map.Map ByteString CabalFields -> Map.Map ByteString [ByteString]
diff --git a/test/doctests.hs b/test/doctests.hs
new file mode 100644
--- /dev/null
+++ b/test/doctests.hs
@@ -0,0 +1,6 @@
+import System.Environment (getArgs)
+import Test.DocTest (mainFromCabal)
+import Prelude (IO, (=<<))
+
+main :: IO ()
+main = mainFromCabal "cabal-fix" =<< getArgs
