Files
msd-core/.changeset
Tom Boucher dc9b299b4e fix(#2359): CHANGELOG 1.4.0 Cursor commands entry cites #805, not #803 (#3252)
* test(#2359): failing-first regression for the 1.4.0 Cursor commands citation

The `## [1.4.0]` CHANGELOG entry for the `.cursor/commands/` surface carries
the trailing reference (#803) — the Cline PR, cited correctly by the entry two
lines below. The Cursor surface shipped in #805 (feat(#785)).

Adds four behavioral cases to the owning module's test file, asserting through
parseChangelog (the same parser cmdExtract/cmdVerify/cmdRender use) rather than
raw text matching:

  1. the Cursor bullet cites 805               - FAILS before the fix
  2. the adjacent Cline bullet still cites 803 - guards a global s/803/805/
  3. exactly one Cursor bullet exists          - guards drop/duplicate
  4. the two bullets cite different PRs        - the defect as an invariant

Folded into tests/changeset-serialize.test.cjs rather than a new
bug-2359-*.test.cjs file, per scripts/lint-regression-test-names.cjs.

Refs #2359

* fix(#2359): CHANGELOG 1.4.0 Cursor commands entry cites #805, not #803

The `## [1.4.0]` entry for `gsd install --cursor` writing
`.cursor/commands/gsd-<name>.md` carried the trailing reference (#803). That
PR is `feat(#787): elevate Cline` — cited correctly by the entry two lines
below. The Cursor slash-command surface shipped in #805 (`feat(#785): write
.cursor/commands/ Cursor 1.6 slash-command surface`).

Two adjacent bullets therefore claimed one PR, and only the second was right.
The trailing (#NNNN) is machine-parsed by parseChangelog and consumed by
`changeset extract`, so the wrong number is live data, not only prose — and it
had already propagated to a human reporter (#2341, quoted there as
"#785 / #803").

Single-occurrence, line-anchored edit. The Cline entry's (#803) is correct and
is deliberately untouched; the regression test added in the preceding commit
asserts both, so a global s/803/805/ fails.

Prose is unchanged, including the "both surfaces are written on every install"
clause the issue explicitly certifies as accurate.

Fixes #2359

* chore(#2359): changeset fragment for the Cursor commands citation fix

* test(#2359): assert bullet cardinality before reading it

Review findings, one root cause: each of the four cases re-derived the bullet
list, re-filtered by marker, then destructured `const [x] = ...` and read `.pr`
unguarded. A reworded or deleted entry therefore died with

  TypeError: Cannot read properties of undefined (reading 'pr')

instead of naming what was missing. The repetition was also duplicated logic
across all four cases.

Adds locateBullet(version, marker, label), which asserts exactly one match
before returning, and folds the two cardinality guards into one case covering
both entries. Failure mode verified: a marker matching nothing now raises
AssertionError "expected exactly one bogus bullet in the 1.4.0 section,
found 0".

Refs #2359

* chore(#2359): backfill changeset pr number (#3252)

---------

Co-authored-by: sim <sim@local>
2026-08-09 12:27:04 -04:00
..

Changeset Fragments

This directory holds per-PR CHANGELOG fragments. Every PR with user-facing changes drops one (or more) <random-name>.md files here describing its CHANGELOG entry. Fragments are consolidated into the top-level CHANGELOG.md at release time.

Why

Two PRs that both edit the ### Fixed block of CHANGELOG.md always conflict on merge — git can't pick a serialization order without human input. Two PRs that each add a fresh .changeset/<unique-name>.md never conflict because they don't share lines.

See #2975 for the full rationale.

Adding a fragment

node scripts/changeset/new.cjs \
  --type Fixed \
  --pr 1234 \
  --body "fix the thing — explain the user-visible change in one sentence"

This writes .changeset/<adjective>-<noun>-<noun>.md with frontmatter and a body. Three random words → concurrent PRs don't collide.

Format

---
type: Fixed
pr: 1234
---
**`/gsd-foo` no longer drops trailing slashes** — explain the user-visible change.

Allowed type: values follow Keep a Changelog: Added, Changed, Deprecated, Removed, Fixed, Security.

Opting out

PRs that legitimately have no user-facing impact can add the no-changelog label. CI honors it. When unsure, add the fragment.

At release time

Promotion is automatic. The release workflow's finalize job runs:

node scripts/changeset/cli.cjs render --version vX.Y.Z --date YYYY-MM-DD --allow-empty

This reads every fragment, groups bullets by type:, replaces ## [Unreleased] with a new ## [vX.Y.Z] - YYYY-MM-DD block, opens a fresh ## [Unreleased] above, and deletes consumed fragments. The --allow-empty flag ensures a no-change release still gets a dated heading (with a _No notable changes._ placeholder). A subsequent verify step confirms the promotion landed correctly. Maintainers do not run this by hand.

Archived fragments

.changeset/archived/ holds fragments for already-shipped releases (≤ 1.3.1), retained for provenance. Their content was hand-curated into the dated ## [1.x.y] sections of CHANGELOG.md during the #690 backfill — they were never consumed by render. All changeset tooling enumerates .changeset/ non-recursively, so archived fragments are never picked up or rendered. Do not move them back to the top level.