Skip to content

docs(changeset-gate): record the launch-window convention's end condition - #14227

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14043-launch-window-end-condition
Sep 1, 2026
Merged

baozhoutao merged 1 commit into
mainfrom
claude/issue-14043-launch-window-end-condition

Conversation

@claude

@claude claude Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Fixes #14043

Records the launch-window versioning convention's end condition in the header of scripts/check-changeset-no-major.mjs. Comment-only: the gate's behaviour is untouched.

Why here

The card offered two candidate homes and triage ruled for one: 「落在 check-changeset-* 今天记载该惯例的地方 —— declared = enforced 保持在同一处」, adding that it is the one place read by both machine and human. Derived on origin/main rather than assumed:

  • scripts/check-changeset-no-major.mjs — the only check-changeset-* file whose prose states the convention (WHY THIS EXISTS: "During the launch window we ship breaking changes as minor…").
  • scripts/check-changeset-fixed.mjs — documents lockstep membership only; never the minor-for-breaking convention. No second copy, so nothing to cross-reference and nothing to duplicate.
  • AGENTS.md — carries no mention of the launch window, no-major, major bumps or lockstep (git grep -i -E 'launch window|no-major|major bump|lockstep' -- AGENTS.md is empty). The convention's documented home is genuinely the gate header, so this stays an ordinary domain:devx PR rather than a governed-surface edit.
  • scripts/objectui-changeset-digest.mjs already points at this gate as the convention's home ("the same convention this repo's check-changeset-no-major.mjs enforces"). The reference direction was already correct and one-way.

What is recorded

Faithful to the maintainer-ruled text (director decision batch B, 2026-09-01, 「同意」), with no dates or version numbers the ruling does not contain:

  1. The convention applies during the launch window only.
  2. End condition — at GA, the fixed group's first general-availability major, the group returns to strict semver: a required member on a published interface, an accept-set narrowing, or any compile-breaking change to implementers then grades major.
  3. Until then, the **BREAKING** banner in the changeset body plus the ADR-0087 migration-ledger disposition are the mandatory information carriers for breaking-ness — during the window they are the only signal there is, because the bump level is not one.

Plus the self-referential sentence triage asked for: this guard is what gets disarmed at GA, so whoever closes the window retires this check and the allow-major escape hatch with it. "Reaching GA without touching this file means the window did not actually close."

Pin disposition — no pin, because no idiom exists for prose

The dispatch asked whether load-bearing header prose has an existing pin idiom to reuse. Measured, and the answer is no:

  • check-changeset-no-major.mjs --self-test never reads its own source (no import.meta.url read anywhere in selfTest()), so there is no in-file hook to extend.
  • The nearest idiom, A trailing YAML comment hides a bump entry from all three changeset frontmatter parsers #7004 in check-empty-changeset.mjs, pins a regex literal shared across four files — a code artifact, not prose.
  • The ~14 repo scripts whose self-tests do read their own source assert code shape or the absence of a bad pattern (e.g. check-vendor-version-stamps.mjs: "this gate offers no baseline/ledger expansion remedy"), never the presence of a prose sentence.
  • The only hits for "header prose" repo-wide are in check-stall-guard-budget.mjs, where the point is to mask header prose from being read as data — the opposite.

Per the dispatch fence, no pinning mechanism was invented for prose.

Enforcing state verified

So the paragraph's claims are true the day they land: .changeset/pre.json is absent (the RC exemption is not active), and the gate runs in its enforcing state, printing: ✓ This diff introduces no major bump.

Verification — all at HEAD 25d6547b

Gate family derived from the actual diff via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (never a hand-built path list). 14 path-derived families + 2 convention-triggered by editing a gate script, all exit 0:

gate exit
node scripts/check-changeset-no-major.mjs 0
node scripts/check-ci-filter-parity.mjs 0
node scripts/check-cross-package-test-inputs.mjs 0
node scripts/check-shard-attestation.mjs 0
node scripts/check-test-completeness.mjs 3 — NOT MEASURED (see below)
node scripts/pm/bare-root-worklist.mjs --self-test 0
pnpm check:agent-test-spelling 0
pnpm check:bash32-floor 0
pnpm check:changeset-gate-self-tests 0
pnpm check:cli-command-ids 0
pnpm check:cross-package-test-inputs 0
pnpm check:entry-guard 0
pnpm check:parse-guard 0
pnpm check:pnpm-filter-targets 0
pnpm check:watch-hint-literal 0
pnpm check:pm-dispatch-gates (convention) 0 — ✓ dispatch-gates self-test: 1110 cases pass.
node scripts/check-ratchet-remedy-authority.mjs (scripts/** prose) 0 — OK … 183 scripts swept

Every exit code captured by redirect-then-read, never across a pipe.

check-test-completeness is NOT MEASURED, not green and not red. Its own output: PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named. It does not run tests and cannot produce one; CI tees the log and passes the path. Recorded as unmeasured rather than counted as a pass.

Gate script's own test suite: this gate has no separate *.test.ts — git grep -l check-changeset-no-major -- '*.test.ts' '*.test.mjs' '*.spec.ts' returns nothing. Its test surface is --self-test, which runs green above via check:changeset-gate-self-tests.

ESLint — declared narrowing, not a skipped run. Ran eslint --no-inline-config --format json on the changed file instead of the repo-wide sweep, with all three pieces of evidence:

  1. Population read from ESLint's own config, not guessed: new ESLint().isPathIgnored('scripts/check-changeset-no-major.mjs') → false, so the file is genuinely in the linted set.
  2. Count read from --format json output: 1 file linted, 0 errors, 0 warnings.
  3. Invariance for untouched files: eslint.config.mjs states — and backs with a measured positive control — that this repo runs one config which "never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file". With no cross-file type program, a comment-only edit in one file cannot move the verdict on any file it does not touch.

CI runs the full pnpm lint unconditionally regardless.

Scope

skip-changeset — comment-only prose in scripts/, publishing nothing from any package.

⛔ Not touched: AGENTS.md (governed surface, and not the convention's home anyway) and content/docs/**. The customer-facing half is a separate follow-up. Worth noting for it: content/docs/protocol/backward-compatibility.mdx:207 currently says the closing condition "is tracked separately and is deliberately not stated here" — this PR is what it defers to, so that page can now be pointed at a written end condition instead of a gap.


Generated by Claude Code

…tion

The no-major guard documented the launch-window convention but not when it
stops applying. A window-period convention with no written end condition
erodes into a permanent exception.

Records, in the file that enforces the convention so declared = enforced stays
in one place: the convention applies during the launch window only; at GA (the
fixed group's first general-availability major) the group returns to strict
semver; until then the BREAKING banner and the ADR-0087 disposition are the
mandatory information carriers for breaking-ness. Adds the self-referential
note that this guard is what gets disarmed at GA.

Comment-only; the gate's behaviour is untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@github-actions github-actions Bot added the size/s label Sep 1, 2026
@baozhoutao baozhoutao added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 1, 2026 — with Claude
@baozhoutao
baozhoutao marked this pull request as ready for review September 1, 2026 15:28
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 1, 2026
Merged via the queue into main with commit b360cc7 Sep 1, 2026
34 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14043-launch-window-end-condition branch September 1, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants