* fix(#4379): make the TDD RED pathspec language-agnostic The pathspec IS this gate's definition of "a test file", and it listed only JS/TS conventions. Go's *_test.go matches none of them, so a commit adding a failing Go test was invisible, RED_COMMIT came back empty, and every behaviour-adding task halted with TDD GATE TRIPPED. references/tdd.md already advertises `go test ./...` and `cargo test` as supported, so the gate was refusing to see tests the docs promised to support. Two corrections, both measured against a seeded repo rather than reasoned: - cover the conventions tdd.md advertises: *_test.go, test_*.py, *_test.py, *_test.exs, *_spec.rb, *_test.rb. - drop the `**/` prefix. It does NOT match a path with no directory component, so a root-level foo.test.js was invisible even in the language the gate did support -- a second defect the report did not mention. A bare glob matches at every depth. Deliberately not widened to ordinary source: a pathspec matching implementation files would make the gate pass on any in-scope commit, which is worse than tripping wrongly. Rust is a known gap for that exact reason and is now documented rather than silently broken. Driving the shipped pathspec against a seeded repo: before, 0 of 7 language/root conventions matched; after, 7 of 7, with src/impl.go and src/lib.rs correctly unmatched in both. Emitted-Drift-Ack-Growth: execute-phase.md — the widened pathspec plus the comment recording why it must not cover ordinary source Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(#4379): drive the shipped RED pathspec against a real repo The existing row pinned the pathspec as a literal string, which the fix makes stale. Re-point it, and add behavioural coverage that EXTRACTS the pathspec from the shipped workflow and runs git log with it against a seeded repo -- re-typing the pattern into the test would only assert that two copies of a string agree. Rows: every advertised convention is visible; a root-level test file is not invisible (the half the report missed); existing JS/TS still matches; implementation files never match, so the gate can still trip; and Rust inline #[test] stays out of reach, asserted rather than left silent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore(#4379): add changeset fragment Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(#4379): be honest about the widened pathspec's cost Adversarial review: the rationale comment claimed the change was safe without naming what it gives up. `*.spec.*` can match a non-test file carrying the word (api.spec.json, openapi.spec.yaml), which lets the gate pass on a commit touching only that. Not new -- `**/*.spec.*` already matched those at any nested path, so dropping `**/` extends the same class to the root -- but the comment should say so rather than imply the widening is free. Also: the tdd.md list named Ruby and Elixir as recognised while the detection step above it enumerates only Node/Python/Go/Rust. Say explicitly that the gate's pathspec is wider than the detected project types, and why that is deliberate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(#4379): drop a vacuous row, fold its point into a real one Adversarial review: the "rust inline #[test] remains out of reach" row asserted src/lib.rs never matches -- the identical assertion to the "implementation files never match" row directly below it. It exercised nothing about #[test] semantics and would have passed against almost any fix, so it was coverage theatre. Delete it and move its rationale into the row that already carries the assertion, where it explains WHY the Rust gap follows from that row holding: the two cannot both be satisfied by a path-based gate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(#4379): move the pathspec rationale out of a size-capped file execute-phase.md sits under a FROZEN byte ceiling (ADR-857 Phase 6, #1168: < 93600). The 20-line rationale comment I added pushed it to 93933 and tripped seven tests, all the same ceiling. Base was 92371, so the budget was 1229 bytes and the comment spent 1481. Keep six lines at the call site -- what the pathspec is, why it is not wider, where to read more -- and move the trade-off detail to references/tdd.md, which has no ceiling. That is the right home anyway: the workflow is loaded into context on every run, the reference is read on demand. 92882 bytes, 718 under. Pathspec line byte-identical; re-proved behaviour after the trim: 0/7 conventions before, 7/7 after, no implementation files matched either way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore(#4379): refresh the compact-content benchmark baseline execute-phase.md changed size, so the committed baseline drifted. The script's own contract makes it a report that exits 0, but the test asserts the committed baseline is up to date -- refresh via --write, which is what the drift message instructs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore(#4379): backfill the changeset PR number Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: sim <sim@local> Co-authored-by: Claude Opus 5 <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
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.