Created Started Finished
Two rules about what a test file exports and defines Two module-level rules, one per commit, both about `*Spec.hs` files. **`HsTestOneSpecPerFile`** — a test file exports exactly `(spec)`. Three shapes are reported and each gets its own sentence: no export list at all, an empty one, and one holding anything besides `spec` (the message names what it exports). The finding is file-scoped, so the suppression the report offers is the `[allow:file:...]` form the parser will accept. **`TestNoTestHelpers`** — one finding per top-level value binding beside `spec`, scoped to that declaration. A type signature is not one, since it cannot move on its own and its binding is reported already. Neither is a type, a class or an instance. Let-bindings are untouched. ## What they cost `ModuleContext` carries two more facts. The declaration list was already read for comment attachment and was simply not exposed. The export list is new: `Hopinion.Facts.Export`, twenty-five lines of fact and thirty of reading, and documentation in an export list is not an entry, since a section heading exports nothing. Neither rule walks the module itself, which is the shape M5 wants. What a test file is gets asked in one place, `moduleContextIsSpecFile`, rather than once per rule. ## Measurement Zero findings for the export rule against this repository. Sixty-one for the helper rule, all of them in this repository's own test suite, and all of them fixed rather than suppressed: - helpers that hide what a test asserts became let-bindings in the spec that uses them, across twelve spec files; - helpers that build a `Spec` became functions in a new `Hopinion.TestUtils`: `ruleSpec`, `moduleScenario`, `projectScenario`, `projectScenarios`, `ownedSpec`, and the IO helpers only they use. That second kind is most of `RuleSpec`, which is now four meta-properties and one `mapM_`, and it is the fix the rule's own text names, so a repository adopting the rule is told where such a helper goes rather than only that it may not stay. ## Checking `nix flake check` passes on each commit separately, not only on the branch tip.