Give every fact its own module Stacked on #1. Base is `no-semigroup-on-text` until that merges, then master. `Hopinion.Facts` was one module holding fourteen types and re-exporting four more. Everything that wanted one fact imported all of them, so no file said which of them it needed. Each type now lives in the module that gives it meaning, and **no module re-exports another**. | New module | Holds | |---|---| | `Facts.Component` | `ComponentKind`, its text/parse pair, its persist instances | | `Facts.Outcome` | `ParseOutcome`, its codec and persist instances | | `Facts.Instance` | `InstanceMethods`, `InstanceOrigin`, `InstanceFact` | | `Facts.TypeApp` | `TypeAppFact` | | `Facts.Concat` | `ConcatOperand`, `ConcatChain` | | `Facts.Occurrence` | `NameFact` | | `Facts.TemplateHaskell` | `TemplateHaskellUse`, its text/parse pair, its persist instance | | `Facts.Module` | `ModuleContext`, `moduleContextRef` | | `Facts.Package` | `PackageRole`, `GenPackage`, their text/parse pairs | | `Facts.Version` | `FormatVersion`, `currentFormatVersion` | beside the four that already existed (`Name`, `Place`, `Decl`, `Suppression`) and `Persist`. `hopinion/src/Hopinion/Facts.hs` is gone. ## What it costs Import lines, rather than saving them: **131 where there were 33**. That is the trade. What each of those lines says is now true, and a module's imports are a statement of what it is about rather than one line that says nothing. The rule about concatenation is the clearest case, from fourteen blanket imports to the two it uses: ```haskell import Hopinion.Facts.Concat import Hopinion.Facts.Module ``` ## What it exposed Three dependencies nobody could see, all now said outright: - **`Hopinion.Compiled`** uses `CompiledModule` and `DeclaredInstance`, which reached it through `Facts` re-exporting `Hopinion.Hie`. It imports `Hie` directly now. - **`GenValidSpecPerGenValid`** uses `declaredInstanceType` and `declaredInstanceClass`, field accessors it only ever saw through two layers of re-export. Same fix. - **`validity-aeson`** was a dependency of the library only because `Facts` imported `Data.Validity.Aeson ()` for orphan instances no `Validity` instance here needs. The import alone satisfied `-Wunused-packages`; removing it took the dependency with it. ## One placement decision `NameFact` is in `Facts.Occurrence`, not in `Facts.Name` where a name-shaped thing would seem to belong. It carries a `Span` and a `ScopeKey`, and `Facts.Place` already imports `Facts.Name`, so putting it there would have closed an import cycle. The name it ended up with is the more honest one: it is an occurrence of a name rather than a name. No behaviour change: no type, field, constructor or function was renamed, added or removed. `nix flake check` passes.