Skip to content

docs: checklist for adding or changing a .cabal file format field#12056

Open
andreabedini wants to merge 1 commit into
haskell:masterfrom
andreabedini:docs/cabal-format-field-checklist
Open

docs: checklist for adding or changing a .cabal file format field#12056
andreabedini wants to merge 1 commit into
haskell:masterfrom
andreabedini:docs/cabal-format-field-checklist

Conversation

@andreabedini

@andreabedini andreabedini commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a new section to CONTRIBUTING.md, "Adding or changing a .cabal file format field", documenting how to correctly gate new or changed .cabal fields behind cabal-version.

This is the class of bug described in #9331: when a new field is not gated, an older Cabal/cabal-install silently accepts it and does the wrong thing, or a newer field leaks into a package that claims an old cabal-version. Features that influence generated files (Paths_*.hs, cabal_macros.h, autogen sources, …) are especially dangerous when ungated.

I tried to be as clear as possible, please review and suggest changes.

What it documents

A step-by-step checklist around the CabalSpecVersion enum:

  1. Ensure a CabalSpecVersion constructor exists for the next unreleased (even) spec version — and that adding one is an API-breaking change requiring a major version bump, with the total functions that must be extended.
  2. Bump cabalSpecLatest in the same change, so the constructor and cabalSpecLatest never drift apart.
  3. Gate the field in FieldGrammar.hs with availableSince <literal constructor> []not the name cabalSpecLatest, which would retroactively move the field's introduction version forward on every spec bump.
  4. Add the matching checkSpecVer in Cabal/.../Check/Target.hs so cabal check reports the field used below its introduction version.
  5. Document the change in doc/file-format-changelog.rst and add a changelog.d/ entry.

Type of change

Documentation only — no code changes, no changelog entry required.

Copilot AI review requested due to automatic review settings June 29, 2026 02:49
@andreabedini andreabedini requested review from Mikolaj and ffaf1 June 29, 2026 02:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new CONTRIBUTING guide section describing the required workflow for introducing or changing .cabal file format fields, with a focus on correctly gating syntax behind cabal-version (and ensuring cabal check enforces the introduction version) to prevent issues like #9331.

Changes:

  • Documented a step-by-step checklist for adding/changing .cabal fields, centered on CabalSpecVersion and cabalSpecLatest.
  • Documented the correct way to gate fields in FieldGrammar.hs (and why not to use cabalSpecLatest by name).
  • Documented adding the corresponding checkSpecVer enforcement in Cabal/.../Check/Target.hs, plus changelog updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread CONTRIBUTING.md
Comment on lines +376 to +379
3. **Gate the field in the grammar.** In
`Cabal-syntax/src/Distribution/PackageDescription/FieldGrammar.hs` mark the
field with `availableSince <Constructor> []`.

Comment thread CONTRIBUTING.md
Comment on lines +380 to +386
> ⚠️ Use the **literal constructor whose value equals `cabalSpecLatest`
> today** (e.g. `availableSince CabalSpecV3_18 []`) — **not** the name
> `cabalSpecLatest`. `cabalSpecLatest` is bumped on every new spec version,
> so writing the name would retroactively (and wrongly) move the field's
> introduction version forward each time the spec advances. Hard-code the
> value; it must stay pinned to the version in which the field actually
> appeared.
Comment thread CONTRIBUTING.md
Comment on lines +367 to +374
2. **Bump `cabalSpecLatest`** (in the same module) to that constructor, in the
*same change* that adds it. The constructor and `cabalSpecLatest` should
never drift apart: a constructor for an unreleased spec version that is not
yet `cabalSpecLatest` is a latent bug. (As of this writing the tree is in
exactly that state — `CabalSpecV3_18` was added this cycle for the
`build-type: Make` removal, but `cabalSpecLatest` was left at
`CabalSpecV3_16` — which is why new fields were mis-gated. If you add a
field now, also fix the bump.)
Add a 'Adding or changing a `.cabal` file format field' section explaining how
to gate new fields behind `cabal-version` to avoid the haskell#9331 class of bug where
ungated fields are silently accepted by older Cabal.

The checklist covers the full mechanism around `CabalSpecVersion`: ensuring a
constructor exists for the next unreleased spec version (a major API break),
keeping `cabalSpecLatest` in sync, gating the field in `FieldGrammar.hs` with a
literal `availableSince` constructor (not the name `cabalSpecLatest`), adding a
matching `checkSpecVer` in `Check/Target.hs`, and documenting the change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants