1. 0.01 s $ /nix/store/vzx1mi9c0xfadmsm9dhd83d005cb1qs9-coreutils-9.8/bin/timeout --kill-after=15s 1800s /nix/store/99b1z08awpxj8b6mzggn59gp1shljnff-nix-2.34.5/bin/nix --extra-experimental-features nix-command --extra-experimental-features flakes --log-format raw-with-logs build --no-link git+https://github.com/sellout/flaky?ref=docs&rev=8c7bfa3513eda13324eafa66edfe5e3f921478b8#checks.x86_64-linux.formatter --print-build-logs
  2. 0.07 s warning: ignoring untrusted flake configuration setting 'allow-import-from-derivation'.
  3. 0.07 s Pass '--accept-flake-config' to trust it
  4. 0.07 s warning: ignoring untrusted flake configuration setting 'extra-experimental-features'.
  5. 0.07 s Pass '--accept-flake-config' to trust it
  6. 0.07 s warning: ignoring untrusted flake configuration setting 'extra-substituters'.
  7. 0.07 s Pass '--accept-flake-config' to trust it
  8. 0.07 s warning: ignoring untrusted flake configuration setting 'extra-trusted-public-keys'.
  9. 0.07 s Pass '--accept-flake-config' to trust it
  10. 0.07 s warning: ignoring untrusted flake configuration setting 'sandbox'.
  11. 0.07 s Pass '--accept-flake-config' to trust it
  12. 0.07 s warning: ignoring untrusted flake configuration setting 'use-registries'.
  13. 0.07 s Pass '--accept-flake-config' to trust it
  14. 0.45 s error (ignored): SQLite database '/var/cache/private/nix-ci-worker/eval-cache-v6/c35873f8e9899069a2a63794fcf3e3d02fb9ecc53b4857113133e9bf7944bae3.sqlite' is busy
  15. 2.72 s treefmt v2.4.0traversed 66 files
  16. 2.72 s emitted 52 files for processing
  17. 2.72 s formatted 52 files (4 changed) in 388ms
  18. 2.73 s M docs/CONTRIBUTING.md
  19. 2.73 s M docs/CONTRIBUTING/haskell.md
  20. 2.73 s M docs/haskell-release-process.md
  21. 2.73 s M docs/haskell-strict-PVP.md
  22. 2.74 s diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
  23. 2.74 s index 2b499f5..5465a5d 100644
  24. 2.74 s --- a/docs/CONTRIBUTING.md
  25. 2.74 s +++ b/docs/CONTRIBUTING.md
  26. 2.74 s @@ -25,10 +25,10 @@ All contributions are welcome, we love improvements to docs and tests.
  27. 2.74 s ### terminology
  28. 2.74 s
  29. 2.74 s | generic | Haskell | Nix | Rust | versioned |
  30. 2.74 s -|------------|---------------|------------|-----------|-----------|
  31. 2.74 s -| repository | | | | ✔ |
  32. 2.74 s +| ---------- | ------------- | ---------- | --------- | --------- |
  33. 2.74 s +| repository | | | | ✔ |
  34. 2.74 s | project | Cabal project | flake | workspace | |
  35. 2.74 s -| package | Cabal package | derivation | crate | ✔ |
  36. 2.74 s +| package | Cabal package | derivation | crate | ✔ |
  37. 2.74 s | component | Cabal stanza | | | |
  38. 2.74 s
  39. 2.74 s There is usually one project per repository, but sometimes a project may be split across multiple repositories. It’s unlikely that more than one project would be in the same repository.
  40. 2.74 s diff --git a/docs/CONTRIBUTING/haskell.md b/docs/CONTRIBUTING/haskell.md
  41. 2.74 s index 963d786..4592132 100644
  42. 2.74 s --- a/docs/CONTRIBUTING/haskell.md
  43. 2.74 s +++ b/docs/CONTRIBUTING/haskell.md
  44. 2.74 s @@ -50,7 +50,7 @@ Documentation is very important, but it shouldn’t detract from good naming. Th
  45. 2.74 s
  46. 2.74 s Documentation is written using [Haddock](https://haskell-haddock.readthedocs.io/), and it’s helpful to add Doctest examples, as described in the “testing” section below.
  47. 2.74 s
  48. 2.74 s -__NB__: Haddock isn’t Markdown! But the similarities can make it easy to forget sometimes. Please try to review your doc changes using [`cabal haddock-project`](https://cabal.readthedocs.io/en/stable/cabal-commands.html#cabal-haddock-project) before submitting them.
  49. 2.74 s +**NB**: Haddock isn’t Markdown! But the similarities can make it easy to forget sometimes. Please try to review your doc changes using [`cabal haddock-project`](https://cabal.readthedocs.io/en/stable/cabal-commands.html#cabal-haddock-project) before submitting them.
  50. 2.74 s
  51. 2.74 s #### guidelines
  52. 2.74 s
  53. 2.74 s @@ -93,7 +93,7 @@ name foo
  54. 2.74 s library
  55. 2.74 s ```
  56. 2.74 s
  57. 2.74 s -``` cabal
  58. 2.74 s +```cabal
  59. 2.74 s name: foo-hedgehog
  60. 2.74 s
  61. 2.74 s library
  62. 2.74 s diff --git a/docs/haskell-release-process.md b/docs/haskell-release-process.md
  63. 2.74 s index c761703..e08874f 100644
  64. 2.74 s --- a/docs/haskell-release-process.md
  65. 2.74 s +++ b/docs/haskell-release-process.md
  66. 2.74 s @@ -20,7 +20,7 @@ Don’t lump documentation & testing improvements into a breaking change just be
  67. 2.74 s
  68. 2.74 s ### format the PR title as a CHANGELOG entry
  69. 2.74 s
  70. 2.74 s -__TODO__: How does this work when there are multiple packages?
  71. 2.74 s +**TODO**: How does this work when there are multiple packages?
  72. 2.74 s
  73. 2.74 s ## release updates
  74. 2.74 s
  75. 2.74 s @@ -37,7 +37,6 @@ In as far as the release is automated, the changes should be made in the merge c
  76. 2.74 s
  77. 2.74 s [^1]: This is delicate, because the CI build matrix doesn’t do a good job of solving for other versions of local packages.
  78. 2.74 s
  79. 2.74 s -
  80. 2.74 s ## Hackage info
  81. 2.74 s
  82. 2.74 s Hackage allows you to optionally tag a release as “preferred” or ”deprecated”.
  83. 2.74 s diff --git a/docs/haskell-strict-PVP.md b/docs/haskell-strict-PVP.md
  84. 2.74 s index fd77a77..a165ea2 100644
  85. 2.74 s --- a/docs/haskell-strict-PVP.md
  86. 2.74 s +++ b/docs/haskell-strict-PVP.md
  87. 2.74 s @@ -2,15 +2,15 @@
  88. 2.74 s
  89. 2.74 s This is a versioning system that’s compatible with [the Haskell Package Versioning Policy](https://pvp.haskell.org/), but tries to prevent more issues with dependencies.
  90. 2.74 s
  91. 2.74 s -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119).
  92. 2.74 s +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119).
  93. 2.74 s
  94. 2.74 s # terminology
  95. 2.74 s
  96. 2.74 s -- __bump__: this aligns with SemVer’s requirements, which are stricter than PVP here. “bumping” a component in a version means _incrementing_ that component while resetting all less-significant components to zero. (PVP doesn’t require resetting the less-significant components, but it’s certainly allowed and generally followed in practice.) __NB__: Because not all versions may be released, or may be unavailable for some reason, in practice it may appear as if the weaker requirements of PVP were followed (components increased instead of strictly incremented, and less significant components not reset).
  97. 2.74 s +- **bump**: this aligns with SemVer’s requirements, which are stricter than PVP here. “bumping” a component in a version means _incrementing_ that component while resetting all less-significant components to zero. (PVP doesn’t require resetting the less-significant components, but it’s certainly allowed and generally followed in practice.) **NB**: Because not all versions may be released, or may be unavailable for some reason, in practice it may appear as if the weaker requirements of PVP were followed (components increased instead of strictly incremented, and less significant components not reset).
  98. 2.74 s
  99. 2.74 s -- __change__: Some versioning documents talk about changing declarations, but any change to a type is an incompatible change, so we can see changes as simply a removal followed by an addition (with a conflicting name).
  100. 2.74 s +- **change**: Some versioning documents talk about changing declarations, but any change to a type is an incompatible change, so we can see changes as simply a removal followed by an addition (with a conflicting name).
  101. 2.74 s
  102. 2.74 s -- __fine-grained API tracking__: This is a term I’m coining (maybe there’s prior art) for actually looking at the full transitive API of a module (roughly, the interface file, but with some additions), and analyzing each individual change. It allows you to have narrower version bumps than is implied by dependency versions. __FIXME__: This needs a specification too (e.g., modified definitions aren’t apparent from an interface file, or, if they are, it’s not machine checkable whether they’re breaking changes – there should be a way to annotate these changes with how they affect the API, and if any annotations are missing, they can be inferred to be no more significant than the version bump)
  103. 2.74 s +- **fine-grained API tracking**: This is a term I’m coining (maybe there’s prior art) for actually looking at the full transitive API of a module (roughly, the interface file, but with some additions), and analyzing each individual change. It allows you to have narrower version bumps than is implied by dependency versions. **FIXME**: This needs a specification too (e.g., modified definitions aren’t apparent from an interface file, or, if they are, it’s not machine checkable whether they’re breaking changes – there should be a way to annotate these changes with how they affect the API, and if any annotations are missing, they can be inferred to be no more significant than the version bump)
  104. 2.74 s
  105. 2.74 s # summary of differences from PVP (non-normative)
  106. 2.74 s
  107. 2.74 s @@ -19,14 +19,14 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S
  108. 2.74 s - Strict PVP defines a “patch” level, corresponding to the `D` component (PVP references but never defines a “patch” level);
  109. 2.74 s - removing any instance or adding an orphan instance requires an `A` bump instead of an increase in `A.B`;
  110. 2.74 s - incompatible license changes require an `A` bump (PVP has nothing to say on licensing);
  111. 2.74 s -- adding a module moved from another package only __MAY__ bump the major version (it’s “SHOULD” in PVP);
  112. 2.74 s +- adding a module moved from another package only **MAY** bump the major version (it’s “SHOULD” in PVP);
  113. 2.74 s - deprecation only increments `D`, not `A.B` (compatible, because this is only a “SHOULD” in PVP);
  114. 2.74 s
  115. 2.74 s # specification
  116. 2.74 s
  117. 2.74 s -A package that follows Strict PVP __SHOULD__ declare that it does so (__FIXME__: We need a machine-checkable place to specify this declaration). This allows dependencies of the package to make additional assumptions based on the package version.
  118. 2.74 s +A package that follows Strict PVP **SHOULD** declare that it does so (**FIXME**: We need a machine-checkable place to specify this declaration). This allows dependencies of the package to make additional assumptions based on the package version.
  119. 2.74 s
  120. 2.74 s -A package that follows Strict PVP __MAY__ use fine-grained API tracking of its dependencies to use less significant version bumps than may be implied by the dependency versions.
  121. 2.74 s +A package that follows Strict PVP **MAY** use fine-grained API tracking of its dependencies to use less significant version bumps than may be implied by the dependency versions.
  122. 2.74 s
  123. 2.74 s ## version numbers
  124. 2.74 s
  125. 2.74 s @@ -48,7 +48,7 @@ If your imports are [package-qualified](https://downloads.haskell.org/ghc/latest
  126. 2.74 s
  127. 2.74 s #### all non-package-local imports must be either qualified or have explicit import lists
  128. 2.74 s
  129. 2.74 s -__TODO__: Determine if `Prelude` really is [an exception to this rule](https://wiki.haskell.org/Import_modules_properly#Exception_from_the_rule) – is it true that `Prelude` is fixed going forward?
  130. 2.74 s +**TODO**: Determine if `Prelude` really is [an exception to this rule](https://wiki.haskell.org/Import_modules_properly#Exception_from_the_rule) – is it true that `Prelude` is fixed going forward?
  131. 2.74 s
  132. 2.74 s #### restriction of multiple imports with the same qualifier
  133. 2.74 s
  134. 2.74 s @@ -62,7 +62,7 @@ Because of the transitivity of instances, orphans make you sensitive to your dep
  135. 2.74 s
  136. 2.74 s > _suggestion_: Cross-reference orphans in the Cabal package files. Collect the class names and relevant types for any orphans you define. Add a comment above the relevant dependencies in the Cabal package file listing which classes and types come from each.
  137. 2.74 s
  138. 2.74 s -__NB__: Alternatively, adding _any_ instance[^2] could be considered a transitively-breaking change. Then orphans wouldn’t need to trigger API sensitivity. On the one hand, that seems easier to manage and orphans are often unavoidable. However, it seems odd to penalize definers of non-orphan instances because of orphans, and relegating orphans to their own packages mitigates API sensitivity better than it mitigates transitively-breaking changes.
  139. 2.74 s +**NB**: Alternatively, adding _any_ instance[^2] could be considered a transitively-breaking change. Then orphans wouldn’t need to trigger API sensitivity. On the one hand, that seems easier to manage and orphans are often unavoidable. However, it seems odd to penalize definers of non-orphan instances because of orphans, and relegating orphans to their own packages mitigates API sensitivity better than it mitigates transitively-breaking changes.
  140. 2.74 s
  141. 2.74 s [^2]: Adding an instance at the same time as its class or a relevant type would always be a minor change, since there’s no way for an orphan to exist before that point.
  142. 2.74 s
  143. 2.74 s @@ -101,7 +101,7 @@ readAndTryChar :: IO (Either Error Char)
  144. 2.74 s readAndTryChar = tryChar <$> readLn
  145. 2.74 s ```
  146. 2.74 s
  147. 2.74 s -In this example, a new release of `top` adds a case to `Error`. Since the `NewError` pattern is exported, this is a breaking change, and is accordingly reported as one. `middle` builds cleanly with the new version of `top`, so a new revision (non-breaking) is cut with wider dependency bounds.
  148. 2.74 s +In this example, a new release of `top` adds a case to `Error`. Since the `NewError` pattern is exported, this is a breaking change, and is accordingly reported as one. `middle` builds cleanly with the new version of `top`, so a new revision (non-breaking) is cut with wider dependency bounds.
  149. 2.74 s
  150. 2.74 s [__FIXME: This example doesn’t really cause an issue with Haskell, because in order to pattern match on the type, you need a dependency on the `top`, which will collapse the issue – this is more of a problem with languages that don’t enforce such things – ilke languages with dictionaries – but with dictionaries, you should _always_ verify the key exists, right? Even so, removing the key means you no longer have access to that info, so there is an unofficial distinction between records and dictionaries in those languages]
  151. 2.74 s
  152. 2.74 s @@ -152,19 +152,19 @@ This can happen due to syntactic changes that don’t otherwise affect the API (
  153. 2.74 s
  154. 2.74 s #### removing support for a compiler version
  155. 2.74 s
  156. 2.74 s -__TODO__: Can this be constrained at all? E.g., can changing from supporting GHC 9.10.1(+) to 9.10.2(+) be considered a patch change?
  157. 2.74 s +**TODO**: Can this be constrained at all? E.g., can changing from supporting GHC 9.10.1(+) to 9.10.2(+) be considered a patch change?
  158. 2.74 s
  159. 2.74 s #### restricting an existing dependency’s version range in any way
  160. 2.74 s
  161. 2.74 s Consumers have to contend not only with our version bounds, but also with those of other libraries. It’s possible that some dependency overlapped in a very narrow way, and even just restricting a particular patch version of a dependency could make it impossible to find a dependency solution.
  162. 2.74 s
  163. 2.74 s -__TODO__: Determine if this is actually a lesser change. For example, can we get the solver to always fall back to a previous version (even if deprecated) if this version’s dependencies don’t intersect? If so, this is a patch change.
  164. 2.74 s +**TODO**: Determine if this is actually a lesser change. For example, can we get the solver to always fall back to a previous version (even if deprecated) if this version’s dependencies don’t intersect? If so, this is a patch change.
  165. 2.74 s
  166. 2.74 s #### adding a dependency
  167. 2.74 s
  168. 2.74 s A new dependency may make it impossible to find a solution in the face of other packages’ dependency ranges.
  169. 2.74 s
  170. 2.74 s -__TODO__: This may be similar to the previous case – will the solver go back to an older (even if deprecated) version that doesn’t have the new dependency?
  171. 2.74 s +**TODO**: This may be similar to the previous case – will the solver go back to an older (even if deprecated) version that doesn’t have the new dependency?
  172. 2.74 s
  173. 2.74 s ### non-breaking changes (bumps `C`)
  174. 2.74 s
  175. 2.74 s @@ -176,7 +176,7 @@ This is also what PVP recommends. However, unlike in PVP, this is because we rec
  176. 2.74 s
  177. 2.74 s Haskell does type resolution independently of constraints. It then sees if the type that was resolved satisfies the constraints. So removing constraints doesn’t affect what type is resolved, therefore it can’t cause a resolution failure.
  178. 2.74 s
  179. 2.74 s -__FIXME__: I think this might not be true with [type variable defaulting](https://downloads.haskell.org/ghc/9.14.1/docs/users_guide/exts/type_defaulting.html). For example, if you weaken a constraint from `RealFloat` to `Num`, and a consumer is using `default (Natural, Double)`, the switch from resolving `Double` to resolving `Natural` can then introduce a runtime failure when they call `negate`. There are mechanisms to disable defaulting, like `default ()` or requiring `-Werror=type-defaults`, but those must be applied in the consumer, not the definer.
  180. 2.74 s +**FIXME**: I think this might not be true with [type variable defaulting](https://downloads.haskell.org/ghc/9.14.1/docs/users_guide/exts/type_defaulting.html). For example, if you weaken a constraint from `RealFloat` to `Num`, and a consumer is using `default (Natural, Double)`, the switch from resolving `Double` to resolving `Natural` can then introduce a runtime failure when they call `negate`. There are mechanisms to disable defaulting, like `default ()` or requiring `-Werror=type-defaults`, but those must be applied in the consumer, not the definer.
  181. 2.74 s
  182. 2.74 s ### other changes (bumps `D`)
  183. 2.74 s
  184. 2.74 s @@ -190,7 +190,7 @@ The most common cases of this are
  185. 2.74 s
  186. 2.74 s #### deprecation
  187. 2.74 s
  188. 2.74 s -**NB**: This case is _weaker_ than PVP (but allowed), which indicates that packages __SHOULD__ bump their major version when adding `deprecated` pragmas.
  189. 2.74 s +**NB**: This case is _weaker_ than PVP (but allowed), which indicates that packages **SHOULD** bump their major version when adding `deprecated` pragmas.
  190. 2.74 s
  191. 2.74 s We disagree with this because packages shouldn’t be _publishing_ with `-Werror`. The intent of deprecation is to indicate that some API _will_ change. To make that signal a major change itself defeats the purpose. You want people to start seeing that warning as soon as possible. The major change occurs when you actually remove the old API.
  192. 2.74 s
  193. 2.74 s @@ -202,16 +202,16 @@ Yes, in development, `-Werror` is often (and should be) used. However, that just
  194. 2.74 s
  195. 2.74 s This is incompatible with both PVP and SPVP. It requires that a security fix be no more significant than a minor change.
  196. 2.74 s
  197. 2.74 s -__TODO__: This section includes some things that are outside the scope of a versioning system, and should be listed as “_suggestion_”s.
  198. 2.74 s +**TODO**: This section includes some things that are outside the scope of a versioning system, and should be listed as “_suggestion_”s.
  199. 2.74 s
  200. 2.74 s -A security fix __SHOULD__ be made without breaking the API. However, if that’s not possible, the breaking change __MUST__ bump `C` and leave `A` and `B` unchanged.
  201. 2.74 s +A security fix **SHOULD** be made without breaking the API. However, if that’s not possible, the breaking change **MUST** bump `C` and leave `A` and `B` unchanged.
  202. 2.74 s
  203. 2.74 s -A security fix, even if breaking, __MUST__ not include any other breaking changes. A security fix __SHOULD__ not include any unrelated changes at all. Even trivial changes can impede analysis, and my have some subtle effect that undermines the release.
  204. 2.74 s +A security fix, even if breaking, **MUST** not include any other breaking changes. A security fix **SHOULD** not include any unrelated changes at all. Even trivial changes can impede analysis, and my have some subtle effect that undermines the release.
  205. 2.74 s
  206. 2.74 s -Whatever mechanisms are available __SHOULD__ be used to deprecate[^4] the affected releases even before the fix is available. Once a fix is available, affected versions __SHOULD__ be made unavailable.
  207. 2.74 s +Whatever mechanisms are available **SHOULD** be used to deprecate[^4] the affected releases even before the fix is available. Once a fix is available, affected versions **SHOULD** be made unavailable.
  208. 2.74 s
  209. 2.74 s [^4]: In this case, “deprecate” refers to something like the Hackage mechanism, where a deprecated release is only used if no other compatible release is available. This means that users will be downgraded where possible before a fix is even available.
  210. 2.74 s
  211. 2.74 s This helps ensure that security fixes are propagated quickly.
  212. 2.74 s
  213. 2.74 s -__NB__: There’s what looks like a catch-22 here, but I think it’s an illusion – if a particular major version has an older unaffected release, then the actual fixed release may introduce an unnecessary breakage. But … if the older version wasn’t affected, then the fix must have been possible without breaking _that part_ of the API. That is, any breaking fix __SHOULD__ only cause breakage to APIs that have already been deprecated.
  214. 2.74 s +**NB**: There’s what looks like a catch-22 here, but I think it’s an illusion – if a particular major version has an older unaffected release, then the actual fixed release may introduce an unnecessary breakage. But … if the older version wasn’t affected, then the fix must have been possible without breaking _that part_ of the API. That is, any breaking fix **SHOULD** only cause breakage to APIs that have already been deprecated.
  215. 2.76 s error: Cannot build '/nix/store/1g96wfp5i7zbxh8j4g3f13shzcic3zjx-treefmt-check.drv'.
  216. 2.76 s Reason: builder failed with exit code 1.
  217. 2.76 s Output paths:
  218. 2.76 s /nix/store/grav8ff6lvl87xh0a8kwqymw3ibpypa3-treefmt-check
  219. 2.76 s Last 200 log lines:
  220. 2.76 s > treefmt v2.4.0traversed 66 files
  221. 2.76 s > emitted 52 files for processing
  222. 2.76 s > formatted 52 files (4 changed) in 388ms
  223. 2.76 s > M docs/CONTRIBUTING.md
  224. 2.76 s > M docs/CONTRIBUTING/haskell.md
  225. 2.76 s > M docs/haskell-release-process.md
  226. 2.76 s > M docs/haskell-strict-PVP.md
  227. 2.76 s > diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
  228. 2.76 s > index 2b499f5..5465a5d 100644
  229. 2.76 s > --- a/docs/CONTRIBUTING.md
  230. 2.76 s > +++ b/docs/CONTRIBUTING.md
  231. 2.76 s > @@ -25,10 +25,10 @@ All contributions are welcome, we love improvements to docs and tests.
  232. 2.76 s > ### terminology
  233. 2.76 s >
  234. 2.76 s > | generic | Haskell | Nix | Rust | versioned |
  235. 2.76 s > -|------------|---------------|------------|-----------|-----------|
  236. 2.76 s > -| repository | | | | ✔ |
  237. 2.76 s > +| ---------- | ------------- | ---------- | --------- | --------- |
  238. 2.76 s > +| repository | | | | ✔ |
  239. 2.76 s > | project | Cabal project | flake | workspace | |
  240. 2.76 s > -| package | Cabal package | derivation | crate | ✔ |
  241. 2.76 s > +| package | Cabal package | derivation | crate | ✔ |
  242. 2.76 s > | component | Cabal stanza | | | |
  243. 2.76 s >
  244. 2.76 s > There is usually one project per repository, but sometimes a project may be split across multiple repositories. It’s unlikely that more than one project would be in the same repository.
  245. 2.76 s > diff --git a/docs/CONTRIBUTING/haskell.md b/docs/CONTRIBUTING/haskell.md
  246. 2.76 s > index 963d786..4592132 100644
  247. 2.76 s > --- a/docs/CONTRIBUTING/haskell.md
  248. 2.76 s > +++ b/docs/CONTRIBUTING/haskell.md
  249. 2.76 s > @@ -50,7 +50,7 @@ Documentation is very important, but it shouldn’t detract from good naming. Th
  250. 2.76 s >
  251. 2.76 s > Documentation is written using [Haddock](https://haskell-haddock.readthedocs.io/), and it’s helpful to add Doctest examples, as described in the “testing” section below.
  252. 2.76 s >
  253. 2.76 s > -__NB__: Haddock isn’t Markdown! But the similarities can make it easy to forget sometimes. Please try to review your doc changes using [`cabal haddock-project`](https://cabal.readthedocs.io/en/stable/cabal-commands.html#cabal-haddock-project) before submitting them.
  254. 2.76 s > +**NB**: Haddock isn’t Markdown! But the similarities can make it easy to forget sometimes. Please try to review your doc changes using [`cabal haddock-project`](https://cabal.readthedocs.io/en/stable/cabal-commands.html#cabal-haddock-project) before submitting them.
  255. 2.76 s >
  256. 2.76 s > #### guidelines
  257. 2.76 s >
  258. 2.76 s > @@ -93,7 +93,7 @@ name foo
  259. 2.76 s > library
  260. 2.76 s > ```
  261. 2.76 s >
  262. 2.76 s > -``` cabal
  263. 2.76 s > +```cabal
  264. 2.76 s > name: foo-hedgehog
  265. 2.76 s >
  266. 2.76 s > library
  267. 2.76 s > diff --git a/docs/haskell-release-process.md b/docs/haskell-release-process.md
  268. 2.76 s > index c761703..e08874f 100644
  269. 2.76 s > --- a/docs/haskell-release-process.md
  270. 2.76 s > +++ b/docs/haskell-release-process.md
  271. 2.76 s > @@ -20,7 +20,7 @@ Don’t lump documentation & testing improvements into a breaking change just be
  272. 2.76 s >
  273. 2.76 s > ### format the PR title as a CHANGELOG entry
  274. 2.76 s >
  275. 2.76 s > -__TODO__: How does this work when there are multiple packages?
  276. 2.76 s > +**TODO**: How does this work when there are multiple packages?
  277. 2.76 s >
  278. 2.76 s > ## release updates
  279. 2.76 s >
  280. 2.76 s > @@ -37,7 +37,6 @@ In as far as the release is automated, the changes should be made in the merge c
  281. 2.76 s >
  282. 2.76 s > [^1]: This is delicate, because the CI build matrix doesn’t do a good job of solving for other versions of local packages.
  283. 2.76 s >
  284. 2.76 s > -
  285. 2.76 s > ## Hackage info
  286. 2.76 s >
  287. 2.76 s > Hackage allows you to optionally tag a release as “preferred” or ”deprecated”.
  288. 2.76 s > diff --git a/docs/haskell-strict-PVP.md b/docs/haskell-strict-PVP.md
  289. 2.76 s > index fd77a77..a165ea2 100644
  290. 2.76 s > --- a/docs/haskell-strict-PVP.md
  291. 2.76 s > +++ b/docs/haskell-strict-PVP.md
  292. 2.76 s > @@ -2,15 +2,15 @@
  293. 2.76 s >
  294. 2.76 s > This is a versioning system that’s compatible with [the Haskell Package Versioning Policy](https://pvp.haskell.org/), but tries to prevent more issues with dependencies.
  295. 2.76 s >
  296. 2.76 s > -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119).
  297. 2.76 s > +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119).
  298. 2.76 s >
  299. 2.76 s > # terminology
  300. 2.76 s >
  301. 2.76 s > -- __bump__: this aligns with SemVer’s requirements, which are stricter than PVP here. “bumping” a component in a version means _incrementing_ that component while resetting all less-significant components to zero. (PVP doesn’t require resetting the less-significant components, but it’s certainly allowed and generally followed in practice.) __NB__: Because not all versions may be released, or may be unavailable for some reason, in practice it may appear as if the weaker requirements of PVP were followed (components increased instead of strictly incremented, and less significant components not reset).
  302. 2.76 s > +- **bump**: this aligns with SemVer’s requirements, which are stricter than PVP here. “bumping” a component in a version means _incrementing_ that component while resetting all less-significant components to zero. (PVP doesn’t require resetting the less-significant components, but it’s certainly allowed and generally followed in practice.) **NB**: Because not all versions may be released, or may be unavailable for some reason, in practice it may appear as if the weaker requirements of PVP were followed (components increased instead of strictly incremented, and less significant components not reset).
  303. 2.76 s >
  304. 2.76 s > -- __change__: Some versioning documents talk about changing declarations, but any change to a type is an incompatible change, so we can see changes as simply a removal followed by an addition (with a conflicting name).
  305. 2.76 s > +- **change**: Some versioning documents talk about changing declarations, but any change to a type is an incompatible change, so we can see changes as simply a removal followed by an addition (with a conflicting name).
  306. 2.76 s >
  307. 2.76 s > -- __fine-grained API tracking__: This is a term I’m coining (maybe there’s prior art) for actually looking at the full transitive API of a module (roughly, the interface file, but with some additions), and analyzing each individual change. It allows you to have narrower version bumps than is implied by dependency versions. __FIXME__: This needs a specification too (e.g., modified definitions aren’t apparent from an interface file, or, if they are, it’s not machine checkable whether they’re breaking changes – there should be a way to annotate these changes with how they affect the API, and if any annotations are missing, they can be inferred to be no more significant than the version bump)
  308. 2.77 s > +- **fine-grained API tracking**: This is a term I’m coining (maybe there’s prior art) for actually looking at the full transitive API of a module (roughly, the interface file, but with some additions), and analyzing each individual change. It allows you to have narrower version bumps than is implied by dependency versions. **FIXME**: This needs a specification too (e.g., modified definitions aren’t apparent from an interface file, or, if they are, it’s not machine checkable whether they’re breaking changes – there should be a way to annotate these changes with how they affect the API, and if any annotations are missing, they can be inferred to be no more significant than the version bump)
  309. 2.77 s >
  310. 2.77 s > # summary of differences from PVP (non-normative)
  311. 2.77 s >
  312. 2.77 s > @@ -19,14 +19,14 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S
  313. 2.77 s > - Strict PVP defines a “patch” level, corresponding to the `D` component (PVP references but never defines a “patch” level);
  314. 2.77 s > - removing any instance or adding an orphan instance requires an `A` bump instead of an increase in `A.B`;
  315. 2.77 s > - incompatible license changes require an `A` bump (PVP has nothing to say on licensing);
  316. 2.77 s > -- adding a module moved from another package only __MAY__ bump the major version (it’s “SHOULD” in PVP);
  317. 2.77 s > +- adding a module moved from another package only **MAY** bump the major version (it’s “SHOULD” in PVP);
  318. 2.77 s > - deprecation only increments `D`, not `A.B` (compatible, because this is only a “SHOULD” in PVP);
  319. 2.77 s >
  320. 2.77 s > # specification
  321. 2.77 s >
  322. 2.77 s > -A package that follows Strict PVP __SHOULD__ declare that it does so (__FIXME__: We need a machine-checkable place to specify this declaration). This allows dependencies of the package to make additional assumptions based on the package version.
  323. 2.77 s > +A package that follows Strict PVP **SHOULD** declare that it does so (**FIXME**: We need a machine-checkable place to specify this declaration). This allows dependencies of the package to make additional assumptions based on the package version.
  324. 2.77 s >
  325. 2.77 s > -A package that follows Strict PVP __MAY__ use fine-grained API tracking of its dependencies to use less significant version bumps than may be implied by the dependency versions.
  326. 2.77 s > +A package that follows Strict PVP **MAY** use fine-grained API tracking of its dependencies to use less significant version bumps than may be implied by the dependency versions.
  327. 2.77 s >
  328. 2.77 s > ## version numbers
  329. 2.77 s >
  330. 2.77 s > @@ -48,7 +48,7 @@ If your imports are [package-qualified](https://downloads.haskell.org/ghc/latest
  331. 2.77 s >
  332. 2.77 s > #### all non-package-local imports must be either qualified or have explicit import lists
  333. 2.77 s >
  334. 2.77 s > -__TODO__: Determine if `Prelude` really is [an exception to this rule](https://wiki.haskell.org/Import_modules_properly#Exception_from_the_rule) – is it true that `Prelude` is fixed going forward?
  335. 2.77 s > +**TODO**: Determine if `Prelude` really is [an exception to this rule](https://wiki.haskell.org/Import_modules_properly#Exception_from_the_rule) – is it true that `Prelude` is fixed going forward?
  336. 2.77 s >
  337. 2.77 s > #### restriction of multiple imports with the same qualifier
  338. 2.77 s >
  339. 2.77 s > @@ -62,7 +62,7 @@ Because of the transitivity of instances, orphans make you sensitive to your dep
  340. 2.77 s >
  341. 2.77 s > > _suggestion_: Cross-reference orphans in the Cabal package files. Collect the class names and relevant types for any orphans you define. Add a comment above the relevant dependencies in the Cabal package file listing which classes and types come from each.
  342. 2.77 s >
  343. 2.77 s > -__NB__: Alternatively, adding _any_ instance[^2] could be considered a transitively-breaking change. Then orphans wouldn’t need to trigger API sensitivity. On the one hand, that seems easier to manage and orphans are often unavoidable. However, it seems odd to penalize definers of non-orphan instances because of orphans, and relegating orphans to their own packages mitigates API sensitivity better than it mitigates transitively-breaking changes.
  344. 2.77 s > +**NB**: Alternatively, adding _any_ instance[^2] could be considered a transitively-breaking change. Then orphans wouldn’t need to trigger API sensitivity. On the one hand, that seems easier to manage and orphans are often unavoidable. However, it seems odd to penalize definers of non-orphan instances because of orphans, and relegating orphans to their own packages mitigates API sensitivity better than it mitigates transitively-breaking changes.
  345. 2.77 s >
  346. 2.77 s > [^2]: Adding an instance at the same time as its class or a relevant type would always be a minor change, since there’s no way for an orphan to exist before that point.
  347. 2.77 s >
  348. 2.77 s > @@ -101,7 +101,7 @@ readAndTryChar :: IO (Either Error Char)
  349. 2.77 s > readAndTryChar = tryChar <$> readLn
  350. 2.77 s > ```
  351. 2.77 s >
  352. 2.77 s > -In this example, a new release of `top` adds a case to `Error`. Since the `NewError` pattern is exported, this is a breaking change, and is accordingly reported as one. `middle` builds cleanly with the new version of `top`, so a new revision (non-breaking) is cut with wider dependency bounds.
  353. 2.77 s > +In this example, a new release of `top` adds a case to `Error`. Since the `NewError` pattern is exported, this is a breaking change, and is accordingly reported as one. `middle` builds cleanly with the new version of `top`, so a new revision (non-breaking) is cut with wider dependency bounds.
  354. 2.77 s >
  355. 2.77 s > [__FIXME: This example doesn’t really cause an issue with Haskell, because in order to pattern match on the type, you need a dependency on the `top`, which will collapse the issue – this is more of a problem with languages that don’t enforce such things – ilke languages with dictionaries – but with dictionaries, you should _always_ verify the key exists, right? Even so, removing the key means you no longer have access to that info, so there is an unofficial distinction between records and dictionaries in those languages]
  356. 2.77 s >
  357. 2.77 s > @@ -152,19 +152,19 @@ This can happen due to syntactic changes that don’t otherwise affect the API (
  358. 2.77 s >
  359. 2.77 s > #### removing support for a compiler version
  360. 2.77 s >
  361. 2.77 s > -__TODO__: Can this be constrained at all? E.g., can changing from supporting GHC 9.10.1(+) to 9.10.2(+) be considered a patch change?
  362. 2.77 s > +**TODO**: Can this be constrained at all? E.g., can changing from supporting GHC 9.10.1(+) to 9.10.2(+) be considered a patch change?
  363. 2.77 s >
  364. 2.77 s > #### restricting an existing dependency’s version range in any way
  365. 2.77 s >
  366. 2.77 s > Consumers have to contend not only with our version bounds, but also with those of other libraries. It’s possible that some dependency overlapped in a very narrow way, and even just restricting a particular patch version of a dependency could make it impossible to find a dependency solution.
  367. 2.77 s >
  368. 2.77 s > -__TODO__: Determine if this is actually a lesser change. For example, can we get the solver to always fall back to a previous version (even if deprecated) if this version’s dependencies don’t intersect? If so, this is a patch change.
  369. 2.77 s > +**TODO**: Determine if this is actually a lesser change. For example, can we get the solver to always fall back to a previous version (even if deprecated) if this version’s dependencies don’t intersect? If so, this is a patch change.
  370. 2.77 s >
  371. 2.77 s > #### adding a dependency
  372. 2.77 s >
  373. 2.77 s > A new dependency may make it impossible to find a solution in the face of other packages’ dependency ranges.
  374. 2.77 s >
  375. 2.77 s > -__TODO__: This may be similar to the previous case – will the solver go back to an older (even if deprecated) version that doesn’t have the new dependency?
  376. 2.77 s > +**TODO**: This may be similar to the previous case – will the solver go back to an older (even if deprecated) version that doesn’t have the new dependency?
  377. 2.77 s >
  378. 2.77 s > ### non-breaking changes (bumps `C`)
  379. 2.77 s >
  380. 2.77 s > @@ -176,7 +176,7 @@ This is also what PVP recommends. However, unlike in PVP, this is because we rec
  381. 2.77 s >
  382. 2.77 s > Haskell does type resolution independently of constraints. It then sees if the type that was resolved satisfies the constraints. So removing constraints doesn’t affect what type is resolved, therefore it can’t cause a resolution failure.
  383. 2.77 s >
  384. 2.77 s > -__FIXME__: I think this might not be true with [type variable defaulting](https://downloads.haskell.org/ghc/9.14.1/docs/users_guide/exts/type_defaulting.html). For example, if you weaken a constraint from `RealFloat` to `Num`, and a consumer is using `default (Natural, Double)`, the switch from resolving `Double` to resolving `Natural` can then introduce a runtime failure when they call `negate`. There are mechanisms to disable defaulting, like `default ()` or requiring `-Werror=type-defaults`, but those must be applied in the consumer, not the definer.
  385. 2.77 s > +**FIXME**: I think this might not be true with [type variable defaulting](https://downloads.haskell.org/ghc/9.14.1/docs/users_guide/exts/type_defaulting.html). For example, if you weaken a constraint from `RealFloat` to `Num`, and a consumer is using `default (Natural, Double)`, the switch from resolving `Double` to resolving `Natural` can then introduce a runtime failure when they call `negate`. There are mechanisms to disable defaulting, like `default ()` or requiring `-Werror=type-defaults`, but those must be applied in the consumer, not the definer.
  386. 2.77 s >
  387. 2.77 s > ### other changes (bumps `D`)
  388. 2.77 s >
  389. 2.77 s > @@ -190,7 +190,7 @@ The most common cases of this are
  390. 2.77 s >
  391. 2.77 s > #### deprecation
  392. 2.77 s >
  393. 2.77 s > -**NB**: This case is _weaker_ than PVP (but allowed), which indicates that packages __SHOULD__ bump their major version when adding `deprecated` pragmas.
  394. 2.77 s > +**NB**: This case is _weaker_ than PVP (but allowed), which indicates that packages **SHOULD** bump their major version when adding `deprecated` pragmas.
  395. 2.77 s >
  396. 2.77 s > We disagree with this because packages shouldn’t be _publishing_ with `-Werror`. The intent of deprecation is to indicate that some API _will_ change. To make that signal a major change itself defeats the purpose. You want people to start seeing that warning as soon as possible. The major change occurs when you actually remove the old API.
  397. 2.77 s >
  398. 2.77 s > @@ -202,16 +202,16 @@ Yes, in development, `-Werror` is often (and should be) used. However, that just
  399. 2.77 s >
  400. 2.77 s > This is incompatible with both PVP and SPVP. It requires that a security fix be no more significant than a minor change.
  401. 2.77 s >
  402. 2.77 s > -__TODO__: This section includes some things that are outside the scope of a versioning system, and should be listed as “_suggestion_”s.
  403. 2.77 s > +**TODO**: This section includes some things that are outside the scope of a versioning system, and should be listed as “_suggestion_”s.
  404. 2.77 s >
  405. 2.77 s > -A security fix __SHOULD__ be made without breaking the API. However, if that’s not possible, the breaking change __MUST__ bump `C` and leave `A` and `B` unchanged.
  406. 2.77 s > +A security fix **SHOULD** be made without breaking the API. However, if that’s not possible, the breaking change **MUST** bump `C` and leave `A` and `B` unchanged.
  407. 2.77 s >
  408. 2.77 s > -A security fix, even if breaking, __MUST__ not include any other breaking changes. A security fix __SHOULD__ not include any unrelated changes at all. Even trivial changes can impede analysis, and my have some subtle effect that undermines the release.
  409. 2.77 s > +A security fix, even if breaking, **MUST** not include any other breaking changes. A security fix **SHOULD** not include any unrelated changes at all. Even trivial changes can impede analysis, and my have some subtle effect that undermines the release.
  410. 2.77 s >
  411. 2.77 s > -Whatever mechanisms are available __SHOULD__ be used to deprecate[^4] the affected releases even before the fix is available. Once a fix is available, affected versions __SHOULD__ be made unavailable.
  412. 2.77 s > +Whatever mechanisms are available **SHOULD** be used to deprecate[^4] the affected releases even before the fix is available. Once a fix is available, affected versions **SHOULD** be made unavailable.
  413. 2.77 s >
  414. 2.77 s > [^4]: In this case, “deprecate” refers to something like the Hackage mechanism, where a deprecated release is only used if no other compatible release is available. This means that users will be downgraded where possible before a fix is even available.
  415. 2.77 s >
  416. 2.77 s > This helps ensure that security fixes are propagated quickly.
  417. 2.77 s >
  418. 2.77 s > -__NB__: There’s what looks like a catch-22 here, but I think it’s an illusion – if a particular major version has an older unaffected release, then the actual fixed release may introduce an unnecessary breakage. But … if the older version wasn’t affected, then the fix must have been possible without breaking _that part_ of the API. That is, any breaking fix __SHOULD__ only cause breakage to APIs that have already been deprecated.
  419. 2.77 s > +**NB**: There’s what looks like a catch-22 here, but I think it’s an illusion – if a particular major version has an older unaffected release, then the actual fixed release may introduce an unnecessary breakage. But … if the older version wasn’t affected, then the fix must have been possible without breaking _that part_ of the API. That is, any breaking fix **SHOULD** only cause breakage to APIs that have already been deprecated.
  420. 2.77 s For full logs, run:
  421. 2.77 s nix log /nix/store/1g96wfp5i7zbxh8j4g3f13shzcic3zjx-treefmt-check.drv