Skip to content

docs(changeset): drop the deleted api-surface-declarations family from four pending release notes - #19627

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-19372-changesets-name-deleted-api-surface-declarations
Sep 22, 2026
Merged

hotlong merged 1 commit into
mainfrom
claude/issue-19372-changesets-name-deleted-api-surface-declarations

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes #19372

Clause-②: no

Four unreleased changesets on main still described packages/spec/api-surface-declarations/ — a family the revert 2277d1fcd10 deleted outright: 17 shards, its build script, its two package scripts (gen:api-surface-declarations and check:api-surface-declarations) and its entry in packages/spec's files[]. Changeset prose is compiled verbatim into CHANGELOG.md at the next cut, which then deletes the consumed file, and the release PR carrying packages/spec at 17.5.0 is open right now. So whatever stands in these four files at the cut is what publishes: a shipped entry telling a reader the package ships a directory it does not have, amendable afterwards only by a docs-only PR against a published entry.

Five sentences, four files, ten changed lines. No code, no files[], no packages/spec/**, no second changeset, no label.

⚠️ Check Changeset is RED on this PR by design — no commit clears it

This PR modifies four .changeset/*.md that exist on the merge base and were not added by it, so scripts/check-empty-changeset.mjs refuses it under the foreign-changeset rule. Measured on this branch's head: the empty-frontmatter rule passes ("No empty-frontmatter changeset introduced by this diff (4 declaring changeset(s) added)") and the foreign rule exits 1 naming all four paths.

The refusal is correct, and the remedy it prints for this class is the one being followed:

DELIBERATE CORRECTION -- your change may have made this PENDING release note false, and you rewrote it in the same stroke. Remedy: do NOT restore it -- say so on the PR and get it confirmed; restoring it from the base would put the false sentence back.

  • Restoring the base text is the one thing not to do. It puts five false sentences back in front of a live release cut.
  • skip-changeset is not applied. The dispatching seat carries a maintainer ruling on 18375 refusing that label by name for a PR that edits an existing changeset; the gate stays advisory red instead.
  • The gate is advisory. Check Changeset is not one of the seven contexts registered in scripts/check-required-contexts.mjs — grepped on this branch, absent (exit 1), with Lint & Repo Gates present (exit 0) as the control that the grep fired.
  • The confirmation is the maintainer's word and is outstanding. A seat may only carry it. This PR's job is the other half the remedy names: each note, and what changed under it.

⚠️ One precision, because the gate's own wording does not quite fit this PR

The DELIBERATE CORRECTION text reads "the note you rewrote describes behaviour THIS PR changed". Here a third PR falsified the notes — the deleting revert 2277d1fcd10 — and this PR repairs only the prose in its wake. The remedy is still the right one, because restoring the base text would republish false sentences. But neither declared class describes "a landed sibling falsified a pending note; this PR repairs the note and nothing else". Noted, not filed.

Each note, and exactly what changed under it

1. .changeset/17108-element-text-variant-published-nine.md (@objectstack/spec: minor) — the closing projection clause named api-surface-declarations/ui.txt as gaining the seven new element:text.variant members. That shard is gone. The clause is deleted; the surviving generated projection named in the same sentence is kept, and verified to carry the widening (overline, the value only this change added, is present in content/docs/references/ui/component.mdx, with a fabricated value as the dark control returning 0). The check:api-surface sentence after it is untouched.

2. .changeset/18605-enable-on-install-one-authority.md (@objectstack/spec: minor) — api-surface-declarations was one of four artifacts listed as unchanged. Dropped from the list; api-surface, authorable-surface and authorable-defaults stay exactly as written. Naming a non-existent directory in a list of unchanged artifacts tells a reader the package has it.

3. .changeset/19085-metadata-form-declared-rows.md (@objectstack/spec: minor, @objectstack/platform-objects: patch) — the sentence claimed check:api-surface and check:api-surface-declarations were both green with no regeneration. The second script no longer exists in packages/spec's manifest (the revert removed both gen: and check: entries), so it is dropped. The claim about check:api-surface is unchanged.

4. .changeset/18991-user-export-slot-is-a-real-optin-grant.md (@objectstack/spec: patch) — two spots, and the second is the reason this card was filed sharp. Detail below.

The sharpest leg: 18991's stated reason to publish — re-measured, and it stands

That changeset's Why this publishes rather than taking skip-changeset paragraph rested its decision on two files[] entries moving, and named api-surface-declarations/ as the first. That entry is gone from packages/spec's files[]. The question the card left open is whether the remaining reason carries the publish on its own. It does, and the reading is this:

  • dist/ is in packages/spec's files[], and the build still emits declarations (BUILD_DTS=true tsup second pass, gated by scripts/check-dts-emitted.mjs).
  • dist/data/index.d.ts reproduces both corrected docblocks byte-for-byte against packages/spec/src/data/api-derivation.ts on this branch. Normalising only the comment-prefix whitespace, sha256 of source block equals sha256 of emitted block: fe70486a… for the ResolveApiOptions.userExportAllowed member block, 2f78bac0… for the API_METHOD_DERIVATION leading block. Control: the same comparison run against a different docblock in the same file differs, so the equality is not an artifact of the comparison.
  • ⇒ a consumer reading the packed .d.ts reads different bytes after that change. It publishes. skip-changeset would have been wrong then and would be wrong now.

So the repair is to the prose only, and the changeset keeps its patch level and its Clause-②: no. Two things had to move with the dead entry:

  • The count: "Two entries of this package's files[] move" becomes one.
  • The parenthetical "leading TSDoc is excluded; an interior member's is not". That was a fact about how the deleted artifact recorded declaration text, and it is false of the emitted declaration, which carries leading docblocks too — measured: the API_METHOD_DERIVATION leading block is in dist/data/index.d.ts. Keeping it while re-pointing the sentence at dist/ would have swapped one false sentence for another.

The other spot in the same file is the No behaviour change paragraph's trailing clause, "and the generated declaration baseline that reproduces one of them". No generated baseline reproduces either docblock any more, and the emitted declaration reproduces both, not one — so the clause is deleted rather than re-pointed; the paragraph below it already states where the text reaches a consumer.

What this PR deliberately does not do

  • ⛔ No second changeset. Correcting a pending release note is an edit to that note. .changeset appears in 0 of the 70 workspace files[] arrays (control: 70 of 70 name CHANGELOG.md), so this diff ships nothing by itself; a changeset of its own would be an erratum in a later entry, which the packages/*/CHANGELOG.md guardrail refuses by name.
  • ⛔ No regeneration. The only generator that mentions .changeset at all (packages/spec/scripts/build-migration-registry.ts) mentions it in a docblock as an analogy, never as an input, so no checked-in artifact derives from this prose. check:adr-0087-registration sees four non-breaking changesets and asks for no disposition marker.
  • ⛔ No label, ⛔ no touch to packages/spec/package.json, the deleted family, the release PR, or any non-changeset file.

Verified on this branch

  • Derived gate families: scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack derived 19 families from the four paths; all 19 run with exit codes recorded, reconciliation reports "19 derived, 19 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero)". Eighteen exit 0. The one exit 1 is check-empty-changeset --base origin/main, by design, above.
  • Affected packages: none. turbo ls --affected against the merge base reports "0 no packages"; the same instrument with the revert commit as its base lists the whole packages/spec closure, which is the control that it fires. Blind spots stated: the set comes from the package dependency graph, so it is blind to a test that reads another package's source off disk, and the repo-root package is not in turbo ls at all — so "not on the graph", never "cannot move". .changeset/ belongs to no package, so there is no dependency closure to build and no package test or typecheck is owed.
  • Repo-wide lint: empty population, proven, not skipped. eslint's own configuration supplies no matching configuration for a .changeset/*.md path — its own message, not an assumption — so of the 1 file passed in, 0 are linted and 0 rules evaluate. Type-aware linting is not reached for these paths either, so nothing in this diff can move a verdict on any untouched file.
  • Control bytes: check:nul-bytes green (9178 text files scanned, no raw ASCII control bytes), plus an own scan of the four edited files over the non-tab, non-newline control range — clean, with a vertical-tab and a delete-byte probe as the controls that the scan fires.
  • The family is gone everywhere else: after this change, a repo-wide search for the family name returns nothing (exit 1, 0 files), with api-surface as the control returning hits on the same instrument at the same radius. Before it, the same search returned exactly these four files.

Acceptance notes

  • The check-empty-changeset two-class taxonomy has no arm for "a landed sibling falsified a pending note; a later PR repairs only the note". The printed remedy is still correct for that case, so nothing goes wrong — recorded here rather than filed, and no carrier is in flight.
  • The four notes' other claims were left exactly as their authors measured them. This PR re-measured only the sentences it changed.

Generated by Claude Code

…m four pending release notes

The revert 2277d1f deleted packages/spec/api-surface-declarations/ (17
shards plus its build script), its two package scripts, and its entry in
packages/spec's files[]. Four unreleased changesets still described that
family in prose, and a release compiles changeset prose verbatim into
CHANGELOG.md before deleting the consumed file -- so the next cut would
publish sentences telling a reader the package ships a directory it does not.

Five sentences, one per stale claim:

- 17108: the projection clause named api-surface-declarations/ui.txt; the
  surviving generated projection named in the same sentence
  (content/docs/references/ui/component.mdx) is kept and verified to carry
  the widening.
- 18605: api-surface-declarations dropped from the list of unchanged
  artifacts.
- 19085: check:api-surface-declarations dropped; that script no longer
  exists in packages/spec's manifest.
- 18991, two spots. The stated reason to publish rested on two files[]
  entries, one of which is gone. Re-measured: the surviving entry carries it
  alone. dist/ is in files[], and dist/data/index.d.ts reproduces BOTH
  corrected docblocks byte-for-byte against src/data/api-derivation.ts --
  the ResolveApiOptions.userExportAllowed member block (sha256 fe70486a...)
  and the API_METHOD_DERIVATION leading block (sha256 2f78bac0...). So the
  publish decision stands and only the prose is repaired. The parenthetical
  about leading TSDoc being excluded was specific to the deleted artifact's
  recording rule and would be false of the emitted declaration, which
  carries leading docblocks too, so it goes with it.

No new changeset and no label: correcting a pending release note is an edit
to that note, not an erratum in a later entry.

Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2
Co-authored-by: Claude <noreply@anthropic.com>

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: d23eafccf28632551a66e12dcac5dd03b2b35a14

① Derived judgments

Re-measured from GitHub and the tree at the head sha. ⛔ Nothing below is adopted from the PR body or the dispatch.

Instrument radius, stated first so the zeros are readable. The working checkout is a SHALLOW clone — 7 commits reachable from the base — and its HEAD 5c5b67fc41 is an ancestor of the base 744a0a3f1d, so the worktree is not the reviewed state and history-walking instruments are truncated. Every zero below was therefore taken with git grep / git ls-tree at d23eafccf2, each paired with a lit control at the same radius. 2277d1fcd10 is a fetched object that is not reachable in that truncated graph (merge-base --is-ancestor exit 1 against base, head and worktree HEAD alike), so the deletion is established from the tree and the API, never from ancestry: git ls-tree -d packages/spec/api-surface-declarations exits 128 at base and head, with api-surface at exit 0 as the control that the probe fires, and #19024 reads merged with merge_commit_sha 2277d1fcd10, 31 files, 239156 deletions.

Diff shape. 4 files, +5/−5, 10 content lines, every path under .changeset/. Nothing outside. No frontmatter and no Clause-② line is touched, so all four notes keep their declared levels.

The family is gone, and these four files were the last of it. At the head, a tree-wide git grep -l 'api-surface-declarations' exits 1 with 0 files; the lit control api-surface exits 0 with 153 files at the same radius. At the base the same probe exits 0 with exactly 4 files — precisely the four this PR edits. That base reading is the known target outside the post-change radius: it proves the instrument fires, and it proves the repair set is complete rather than merely non-empty. packages/spec's files[] at the head carries no such entry (dist, json-schema, liveness, prompts, llms.txt, README.md, src/**/*.zod.ts, CHANGELOG.md, api-surface, spec-changes.json) and is byte-identical to the base — this PR does not touch it.

The window is real, not rhetorical. Release PR #17076 is open and not a draft, bumps packages/spec 17.4.017.5.0, and consumes all four of these changesets (each appears with status removed in its file list). So the stale prose sits on the cut path, and the packages/*/CHANGELOG.md guardrail applies verbatim: the release "deletes that input and publishes the sentence".

The five repairs, judged one at a time.

  1. 17108 — deletes the projection clause that named api-surface-declarations/ui.txt. Right repair, and deletion beats re-pointing. The clause's grammatical subject was the deleted shard; "on ElementTextPropsSchema and on ComponentPropsMap['element:text']" were prepositional phrases locating the members inside that shard, so they lose their referent with it rather than surviving as free-standing facts. Nothing independently true is lost: the note already states the widening per value, two paragraphs above, through ElementTextPropsSchema.safeParse. Re-pointing at json-schema/ would have been strictly worse — it is gitignored (.gitignore:63) and absent from the tree at the head (ls-tree exit 128, control api-surface exit 0), so it swaps a false sentence for an unverifiable one. The retained clause is true and verified: content/docs/references/ui/component.mdx:290 carries the eleven-value enum including overline, with a fabricated value as the dark control at exit 1.
  2. 18605 — drops the dead name from a four-item "unchanged" list, leaving the other three. Correct: listing a non-existent directory among unchanged artifacts asserts the package has one.
  3. 19085 — drops check:api-surface-declarations from a claim that two scripts were green. Verified independently of the author: packages/spec's script table at the head contains only gen:api-surface and check:api-surface — both *-declarations scripts are gone, so the old sentence claimed a verdict from a script that cannot run. Verb agreement moves with it.
  4. 18991, two spots — the files[] count and the dead-baseline clause. Level judgment in ② below.

Clause-②: no is correct, judged from the diff. The entire payload is changeset prose: no files[] array ships .changeset (0 of 70; lit control 70 of 70 name CHANGELOG.md), and no accept set, authorable key or published answer moves. The released log holds this exact class as precedent — "Prose only. Clause-②: no".

No new changeset, and that is right on both legs. Reproduced at full workspace radius: 81 workspace manifests, 70 carrying a files[] array, 0 naming .changeset, 70 of 70 naming CHANGELOG.md. So the diff ships nothing by itself. And a changeset of its own would be an erratum in a later entry, which AGENTS.md:690 refuses by name — "⛔ never an erratum in a later entry and never a rider on code changes", the remedy being "a dedicated docs-only PR", which is exactly this diff's shape. Both legs hold.

Affected packages: none — derived structurally rather than re-run. No pnpm-workspace.yaml glob matches .changeset, and there is no .changeset/package.json, so the changed paths belong to no package and there is no dependency closure to build. ⚠️ I did not reproduce turbo ls --affected: the checkout sits at an older commit than the base and I am read-only, so that run would have measured a different tree. Recorded as an unreproduced leg, not as a pass.

Check Changeset red is by design and not mine to chase. All four files are present on the merge base and modified by this PR ⇒ FOREIGN_NOTE class M ⇒ the DELIBERATE CORRECTION arm, whose own text says "this gate stays red either way" and "no label and no diff shape makes that safe". It is advisory: absent from scripts/check-required-contexts.mjs (grep exit 1) with Lint & Repo Gates present (exit 0, line 381) as the control that the grep fired.

skip-changeset is not applied — live label read is documentation, size/s, tooling, needs:contract-review. The #18375 ruling (comment 5729188290) refuses it by name for this class and names the confirmation channel instead. Confirmed as compliance by the author; see ③ for the half that is outstanding.

check-issue-citations does not reach this diff, as the dev measured and the seat confirmed: .changeset/** is in DEFERRED_SURFACES at scripts/check-issue-citations.mjs:267, and no CITATION_SURFACES glob matches it. ⛔ Not expected here. One observation the reading earns: **/CHANGELOG.md is a citation surface, so prose that survives the cut lands on a swept surface — a further reason this repair belongs before the cut, and a further reason deletion beats naming a path nobody can verify.

PR body does the author's half of the remedy. It names each of the four notes and exactly what changed under each, and it states plainly that the confirmation is the maintainer's word and outstanding.

② Semver level

18991 keeps patch and Clause-②: no, and that is correct — verified, not inherited. The question the card turns on is whether half (b) carries the publish once (a) is false. It does, and it is not a close call, because the guardrail makes it mandatory rather than optional:

  • dist is in packages/spec's files[], so it ships in the tarball.
  • The ./data subpath publishes its types as ./dist/data/index.d.ts under both the import and require conditions (root types is dist/index.d.ts). That file is the carrier at issue.
  • Declarations are emitted and gated: build runs BUILD_DTS=true tsup as a second pass whenever OS_SKIP_DTS is unset, then scripts/check-dts-emitted.mjs, which asserts the DECLARED surface (types, typings, and exports types conditions) exists. A release build that failed to emit that file fails the gate.
  • The emitted file carries both corrected docblocks. Re-measured independently: normalizing only comment-prefix whitespace, the API_METHOD_DERIVATION leading block (source 122–139) equals dist 3432–3449, and the ResolveApiOptions.userExportAllowed member block (source 198–213) equals dist 3478–3493. Negative control: perturbing a single character of each source block breaks both equalities, so the match is not an artifact of the comparison.

⇒ consumer-visible published bytes move. Per AGENTS.md step 3, skip-changeset is for "a diff that publishes nothing from any released package", so it would be wrong here and a changeset is required; since no accept set moves, Clause-②: no and patch is the correct floor. The level is right, and the prose-only repair is the right shape.

The staleness caveat, weighed rather than inherited — it closes, for a reason the PR body does not give. The author's self-dating argument is sound but narrow: the distinctive phrase dates only the one block that contains it. The decisive fact is that packages/spec/src/data/api-derivation.ts is byte-identical between the checkout HEAD the build was taken from (5c5b67fc41, sha256 bb048c01…) and the reviewed head d23eafccf2git diff over that path between them is empty. For the ranges at issue there is no drift between the build's input and the reviewed source, so the staleness question does not arise. And structurally the gap can only produce a false negative: a build predating the change could only fail to contain the post-change text; it cannot manufacture a byte-exact match with text that did not exist when it ran. The positive result is therefore not corruptible by the hole the author flagged. The build is genuinely stale in other respects — its mtime precedes the revert's merge — which is exactly why the identity of this one file, and not the build's freshness, is what carries the conclusion; the build also holds no reference to the deleted family (grep exit 1, lit control api-surface hitting 10 files under dist).

Nit, nothing publishing: the two sha256 prefixes quoted in the PR body are not reproducible without the exact normalizer used — mine differ under a different whitespace normalization while the equality verdict reproduces identically. The verdict is what carries weight; the digests are weak evidence for a later reader. PR-body only, absent from the shipped prose, so ⛔ not a finding.

The other three notes keep minor (and 19085's second package patch) untouched by this diff.

③ Boundary flags

CI at review time, on d23eafccf2, read at 2026-09-22T02:30Z: converged. 30 check runs, 0 pending, combined commit status success. The only non-green is Check Changesetfailure, twice — which is the by-design red above. Lint & Repo Gates concluded success; it was in_progress when this review opened and I waited for it rather than passing on an unconverged head. Nothing is red other than Check Changeset, so there is no finding here.

Outstanding, for the maintainer and not for this seat: the written confirmation the #18375 ruling requires — arm ② B, the maintainer's own word on the PR with who / what / where, naming the note and what changed under it. This PR carried zero comments before this record, so it is unmet. ⛔ Neither this seat's nor the author's to supply; it is the other half of the remedy and it gates landing, not correctness.

PR is a draft with mergeable_state blocked and needs:contract-review on. This review wrote no label, pushed nothing, approved nothing and flipped nothing.

Gap I am not asserting past: I did not build packages/spec, so "the release tarball will carry these bytes" rests on the emission gate plus the byte identity in ②, not on a build I produced. The one instrument I did not reproduce is turbo ls --affected, for the reason given in ①.

Implemented-by: claude/issue-19372-changesets-name-deleted-api-surface-declarations
Reviewed-by: session_01AmH9bKvGoLjiY86Q4Z3og2

VERDICT: PASS


Generated by Claude Code

@os-steve
os-steve marked this pull request as ready for review September 22, 2026 02:44
@hotlong
hotlong merged commit 34545d6 into main Sep 22, 2026
32 of 35 checks passed
@hotlong
hotlong deleted the claude/issue-19372-changesets-name-deleted-api-surface-declarations branch September 22, 2026 02:46

Copy link
Copy Markdown
Collaborator Author

The DELIBERATE CORRECTION was confirmed by the maintainer's own merge, 2026-09-22T02:51Z

This PR modifies four .changeset/*.md notes that were present on the merge base and not added by it — check-empty-changeset.mjs's DELIBERATE CORRECTION class (scripts/check-empty-changeset.mjs:127), whose remedy is «do NOT restore it -- say so on the PR and get it confirmed» (:551). Ruling #18375 ② B reserves that confirmation for the maintainer; a seat may only carry it with who / what / where. ⛔ I never wrote one here on my own authority.

The confirmation arrived as an act, not as text:

The four notes, and what changed under each as merged — every edit strips a claim about the retired api-surface-declarations artifact:

  • .changeset/17108-element-text-variant-published-nine.md (+1 −1) — the generated-projections sentence loses «api-surface-declarations/ui.txt gains the seven members on ElementTextPropsSchema and on ComponentPropsMap['element:text']», keeping the content/docs/references/ui/component.mdx property table it also named.
  • .changeset/18605-enable-on-install-one-authority.md (+1 −1) — the unchanged-artifacts list drops api-surface-declarations, going from four names to three.
  • .changeset/18991-user-export-slot-is-a-real-optin-grant.md (+2 −2) — drops «and the generated declaration baseline that reproduces one of them», and restates the files[] paragraph from two moved entries to one: dist/ alone, with the check:api-surface-declarations reshaped-shard reading removed and the packed dist/data/index.d.ts carrying both corrected docblocks.
  • .changeset/19085-metadata-form-declared-rows.md (+1 −1) — «check:api-surface and check:api-surface-declarations are green» → check:api-surface alone.

The premise these four edits rest on holds on main after the merge: git grep -l api-surface-declarations origin/main returns 0 files tree-wide, .changeset/ included; the paired control check:api-surface returns 52. So this PR removed the last four references to a name nothing in the tree still produces.

⚠️ Stated rather than papered over: this is an act-record, not the verbatim word the ruling's letter asks for. Nothing on this thread names the four notes in the maintainer's own words; what the merge says is that all six lines of this diff were accepted by the authority the ruling names.

Check Changeset was advisory red at merge time — the clause-② carrier axis (scripts/check-changeset-no-major.mjs:1576), absent from the seven REQUIRED_CONTEXTS (scripts/check-required-contexts.mjs:40). The PR read mergeable_state: unstable, not blocked, so no admin bypass was needed.


Generated by Claude Code

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

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

3 participants