* fix(3265): prefer YAML frontmatter for state-snapshot canonical fields stateSnapshot in both sdk/src/query/state.ts and the CJS twin (get-shit-done/bin/lib/state.cjs cmdStateSnapshot) passed the whole STATE.md blob to stateExtractField, whose bold pattern (**Field:**) has no line anchor. A body table cell such as "**Status:** to ✅ COMPLETE" therefore silenced the correct YAML frontmatter value. Fix: extractFrontmatter(content) first; stripFrontmatter(content) for the body passed to stateExtractField; for each canonical scalar field prefer the non-empty frontmatter value, falling back to body extraction when the key is absent or the file has no frontmatter block at all. Regression tests added in sdk/src/query/state.test.ts (vitest) and tests/state.test.cjs (node:test) covering: - frontmatter status beats **Status:** inside a table cell - frontmatter current_plan beats bold body value - no-frontmatter files continue to extract from body - field absent from frontmatter falls through to body extractor Fixes #3265 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: add changeset for #3275 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: reproduce fmStr drops non-string YAML scalars (#3275 CR finding) Add tests/bug-3275-fmstr-non-string-scalars.test.cjs with 5 cases covering CJS state-snapshot with numeric frontmatter scalars (current_phase: 19, total_phases: 7, total_plans_in_phase: 5), string regression, and no-frontmatter body fallback regression. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(state): fmStr accepts numeric/boolean YAML scalars (CR finding) Rename `fmStr` to `fmScalar` in both state.cjs and sdk/src/query/state.ts and broaden the type guard so that non-null number/boolean frontmatter values are coerced to String(v) instead of being discarded. The previous `typeof v === 'string'` check was a latent bug: if the YAML parser ever returns typed scalars (e.g. `current_phase: 19` as the number 19), the frontmatter value would be silently dropped and the stale body value used instead. Both files are updated identically (k014 parity). Also adds three SDK vitest regression cases (numeric current_phase, total_phases, total_plans_in_phase) in sdk/src/query/state.test.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
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
node scripts/changeset/cli.cjs render --version vX.Y.Z --date YYYY-MM-DD
Reads every fragment, groups bullets by type:, replaces ## [Unreleased] with a new ## [vX.Y.Z] - YYYY-MM-DD block, opens a fresh ## [Unreleased] above, deletes consumed fragments. Idempotent.