Skip to content

p0: dispatch-gates' .changeset/*.md population control makes Lint & Repo Gates red on the Version Packages PR — the release cannot be merged, and main goes red the moment it lands #15255

Description

@hotlong

What is broken

scripts/pm/dispatch-gates.mjs:13052 asserts, in its self-test, against the live working tree:

const changesetPop = suffixCorpus.filter((f) => /^\.changeset\/[^/]+\.md$/.test(f));
t('the tree really does hold a large `.changeset/*.md` population', changesetPop.length >= 100);

The block's own comment states the intent: "Read from the REAL corpus: a fixture cannot show that the tree still holds the population the trap needs, and this one grows with every merged PR."

A changesets version pass consumes every .changeset/*.md. On the Version Packages PR (#11336) that is 861 files, all removed. So changesetPop.length is 0 there and the control fails:

✗ the tree really does hold a large `.changeset/*.md` population
✗ dispatch-gates self-test: 1 of 1353 case(s) failed.
##[error]Process completed with exit code 1

Measured on #11336 head b8573e843, job 100940300762: 30 success, 1 failure — Lint & Repo Gates.

Why this is p0

  1. Lint & Repo Gates is one of the six required contexts (AGENTS.md §7). A required red means the Version Packages PR cannot be merged.
  2. Merging that PR is the release trigger (ADR-0125 D1). So this gate currently makes a GA release impossible — not slow, impossible.
  3. It also turns main red the moment the release lands. main carries 865 changesets today, so the control passes; a version pass consumes all of them, and the merge puts a tree with ~0 changesets on main. The same assertion then fails on main for every PR until 100 fresh changesets accumulate — shared damage, the class AGENTS.md says to stanch immediately.
  4. It is new: the assertion landed 2026-08-31 (eb717a12a, fix(pm): follow a final-segment basename glob in hintCovers, and stop the residue naming a move that never happened #13783); the last release was 2026-08-23. This is the first release cycle in which it exists, which is why nobody has hit it.

The shape of the fix (not a ruling — measure it)

The control exists to stop the two live-specimen assertions below it passing vacuously on an empty set, which is a real thing to guard. What it cannot do is require the tree to hold a population, because the population is zero by design twice in every release cycle (on the version PR, and on main right after it lands) and small for days afterwards.

So the honest shape is probably: when the population is empty, report NOT MEASURED loudly, naming why (this tree has no .changeset/*.md — that is what a version pass produces), and skip only the assertions that need the corpus; keep every population-independent assertion in that block running (the extension pin, the single-* segment pin, the directory-surface pin, the unrelated-root pin, and the four globCarriesLiteralSuffix pins all take literal inputs). A silent skip is the wrong answer — it would let the specimen rot unnoticed, which is the failure the ≥100 was reaching for.

⚠️ Note the threshold has a middle range too: between 1 and 99 changesets the assertion still fails, which is the state main is in for days after every release. Whatever replaces it must be correct at 0, at 3 and at 865.

Found while diagnosing the red on #11336 at the maintainer's request, 2026-09-04, during release preparation.

Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:devxpriority:p0Critical: blocker, must ship before MVP

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions