Skip to content

fix(scripts): the objectui changeset digest reads a (breaking …) parenthetical inside a bold lead label - #23131

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23118-digest-lead-label-breaking
Oct 13, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23118-digest-lead-label-breaking

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #23118

Clause-②: no

What changed

One file, scripts/objectui-changeset-digest.mjs:

  • BREAKING_LEAD_LABEL, a new rule beside BREAKING_BLOCK_OPENER, which stays byte-identical. A line reads breaking when all three hold:
    • it opens with **, after optional indentation and an optional bullet (-, *, +), so the label is the line's first token;
    • the ( sits inside that first bold span: nothing before it closes the span, and the span closes on the same line;
    • breaking is the parenthetical's first word, in any case.
  • hasBreakingAnnotation tests the new rule on every line, not only at a block start. A bullet opens a line without opening a block: - **Strict authoring face.** … followed by - **Tolerant face (breaking for invalid documents).** … is a real objectui shape.
  • markBreaking / OPENS_WITH_BREAKING_LABEL: unchanged, by measurement. See Assumption 3 below.
  • Self-test: a new battery, #23118: a bold LEAD LABEL holding a (breaking …) parenthetical, with 16 cases and a floor of 16. The roster floor goes from 17 to 18.

The rule follows triage's grade on the card: a bold span opening the line, holding a parenthetical whose first word is breaking. A (breaking …) anywhere else is prose, and so is a bold span that is not the line's first token. The line-start opener rule from PR #23117 is unchanged.

Corpus reading

Tree: a blobless bare clone of objectstack-ai/objectui, with every head (1143 refs) and every pull-request head (7169 refs); objectui main at 45ae6b89e845. Every blob ever written under .changeset/*.md (README excluded) was read from each distinct .changeset tree object and fetched in full: 6449 blobs over 4825 paths. The heads-only subset is 5683 blobs; the earlier reading on the decoration card had 5678 at main 5595aabca30b. Each body was parsed with the digest's own parseChangeset and judged with hasBreakingAnnotation: the base at f931e765b (blob afaae0663b1a) against this branch.

Assumption 1 (reproduced on current main): at f931e765b, hasBreakingAnnotation(parseChangeset(text).body) returns false for objectui 8a55f0ccd's .changeset/12059-sidebar-no-reorder.md (blob 873e53f906). The positive control, objectui#12242's changeset at 1fb1ced36243, returns true.

Assumption 2, the split of the ( blobs by position. On the heads corpus, "breaking" right after ( occurs in 39 blobs / 23 paths. That matches the earlier reading's 39 / 23 exactly, so it is the same set.

position heads all refs
inside a bold lead label that opens the line (flips) 33 blobs / 18 paths 39 blobs / 18 paths
anywhere else (prose, no flip) 6 blobs / 5 paths 6 blobs / 5 paths
total 39 / 23 45 / 23

The 6 prose blobs are four shapes, and the rule leaves each of them unflagged:

  • a label that has already closed before the parenthetical: **Behaviour change on the console record page** (breaking in the objectui sense, (5896-feeditem-single-constructor.md, 2 blobs);
  • an unbolded plain-text label: Narrowed (breaking for an author who wrote them, … (11168-element-family-inputs.md, 11168-action-family-published-inputs.md, 1 blob each);
  • an unbolded code-span label: `@object-ui/i18n` (BREAKING; `minor` under this repository's release model …): (11674-shortcuts-dialog-wired-only.md, 1 blob);
  • mid-sentence prose: This narrows the accepted documents (breaking for a document of either shape). (11717-dashboard-widget-chart-measure-arity.md, 1 blob).

Two blobs of 6152-unmirrored-round4.md carry both a lead label and a wrapped prose line that opens with (breaking for invalid documents).. They flip because of the label. The prose line on its own does not read breaking: self-test case 4 pins that line.

Flips (blobs whose verdict moves from not-breaking to breaking):

  • 39 blobs / 18 paths over all refs; 33 / 18 on heads; 33 / 18 reachable from main.
  • Flips outside a lead label: 0. Every flipped blob carries a line the lead-label rule matches. The other two rules are byte-identical, so no flip can come from them. Across the 39 blobs there are 41 matching lines with 18 distinct texts, and each is a lead label. Examples: **`@object-ui/layout` (breaking, declared `minor` per the version policy).**, **Narrowed (breaking).**, **Retired (breaking), `@object-ui/types`.**, **Accept-set change (breaking semantics, released as minor by the version-alignment rule):**.
  • Lost readings (blobs the base reads as breaking and this branch does not): 0 of 6449.
  • Shapes the corpus never uses, so the rule does not admit them: a lead label behind __, a heading mark, an ordered-list mark or a pictograph; a lead-label span that crosses a line; a bold span holding (breaking that is not the line's first token. Each has 0 occurrences.

Assumption 3 (markBreaking), measured on the 39 flipped blobs: none of them opens its summary (the first paragraph) with the lead label. So the **BREAKING** — stamp lands on an ordinary summary in every real case. No rendered artifact below has a stamp followed by another bold label. OPENS_WITH_BREAKING_LABEL therefore stays as it is, and it is not widened for the hypothetical case either. A lead label names a package or a topic, not the class, so it is not one of the "breaking labels" the renderer keeps verbatim. The count note says "Each is marked BREAKING in the list above", and that is only true if such an entry is stamped. The self-test pins the decision (cases 10 and 14).

Real hops: the count line before and after

The digest ran over the last 11 console pin hops, 0abd4f9f8769 → … → 1fb1ced36243, plus the prospective next hop 1fb1ced36243..45ae6b89e845, with the base and with this branch at b7b8bf6d7.

  • The current pin's hop, 7578323a544e..1fb1ced36243, is byte-identical: → 10 releasing changeset(s), 2 breaking (0 declared major, 2 annotated), … before and after. No entry changes, because no lead-label changeset falls in this range. The prospective next hop is also byte-identical (1 breaking).
  • Two of the 11 hops change, and nothing else changes in them:

47b1f0bb7174..20c6d351ad74, before:

→ 33 releasing changeset(s), 6 breaking (0 declared major, 6 annotated), 0 release-nothing, 1 commit(s) without a changeset
⚠️ 6 of these carry a breaking change: 6 by the author's own breaking annotation in the changeset body — …

After:

→ 33 releasing changeset(s), 10 breaking (0 declared major, 10 annotated), 0 release-nothing, 1 commit(s) without a changeset
⚠️ 10 of these carry a breaking change: 10 by the author's own breaking annotation in the changeset body — …

The 4 entries now marked are objectui 8a55f0ccd (12059-sidebar-no-reorder.md, the card's example; its line now reads - **minor** — **BREAKING** — The console sidebar no longer lets a user drag …), c7b30bd66 (12063-unified-view-config-chart-retired.md), 025341692 (6152-list-view-legacy-chart-retired.md) and 3fd862510 (6152-list-view-readers-retired.md).

a58626c88dc8..f0268ad78485: 173 releasing …, 4 breaking → 173 releasing …, 10 breaking. The 6 entries now marked are 5d77c099b (6152-list-view-options-bag.md), cf62edf68 (6152-list-view-blocks-strict.md), b13ea3c67 (6152-grid-default-filters-gantt-map-filter.md), 1473757bf (6152-object-calendar-container-strict.md), d7e9e9ab6 (6152-grid-kanban-calendar-17-7-members.md) and d73d98770 (6152-resizable-columns-retired.md).

scripts/bump-objectui.sh, .objectui-sha and every .changeset/ file are untouched.

Self-test cases (battery #23118, 16)

Direct, against the criterion and the renderer:

  1. The card's example reads breaking: **`@object-ui/layout` (breaking, declared `minor` per the version policy).**, in 12059's own paragraphs, with a guard that the fixture really carries the label.
  2. The rule is line-initial. The second bullet of a list, which opens no block, reads breaking (- **Tolerant face (breaking for invalid documents).**).
  3. A label alone on its line (**Narrowed (breaking).**), a label with text after the parenthetical (**Narrowed (breaking), …**), and the word in upper case all read breaking.
  4. Prose (breaking …) outside a lead label does not: the 11717 mid-sentence line, and the round-4 wrapped line that opens with the parenthetical.
  5. A lead label without the parenthetical does not (**`@object-ui/app-shell`.**, - **Strict authoring face.**).
  6. A parenthetical after the label has closed does not (the 5896 line, verbatim).
  7. A bold span that is not the line's first token does not (See **… (breaking).** below., **Removed.** **… (breaking).**).
  8. breaking must be the parenthetical's first word: (non-breaking) and (not breaking …) do not read breaking.
  9. An unbolded label is prose: the 11168 plain-text label and the 11674 code-span label do not read breaking.
  10. markBreaking stamps a summary that opens with a lead label. **BREAKING (v17)** is still kept verbatim.

Through buildDigest, in a fixture repo of its own:

  1. Exactly the three lead-label annotations are counted (6 releasing, 3 breaking, 3 by annotation), and the three prose shapes are not.
  2. The count line reads ⚠️ 3 of these carry a breaking change: 3 by the author's own breaking annotation.
  3. The 12059-shaped entry gets the marker on its line.
  4. A summary that opens with a lead label is stamped once, with the label kept verbatim after the stamp.
  5. The three prose entries are not marked.
  6. A range whose only breaking entry is a lead label still raises the ADR-0087 disposition question.

Every shape-1 pin of PR #23117 holds: the #23112 battery (16 cases) and the #6099 battery (17) are unchanged and green.

Ablation

Both legs ran from the committed b7b8bf6d7 through scripts/ablation-replace.mjs in wrap mode. In each leg the anchor went 1 → 0 and the replacement 0 → 1. After each leg the tool confirmed that the blob equals HEAD (2e67cb6c2848) and that git diff HEAD is empty. This is a root script run from source, so no build or dist/ is involved.

  • Leg 1, the rule's call site removed: exactly 8 of the 16 #23118 cases go red, all of them positives (1, 2, 3, 11, 12, 13, 14, 16). The 7 negatives and the renderer pin stay green, and no other battery moves. Self-test exit 1. The corpus census over the mutated module shows 0 flips.
  • Leg 2, the rule widened to (breaking anywhere: 7 cases go red: negatives 4, 6, 7 and 9, and digest cases 11, 12 and 15. The census shows 45 blobs / 23 paths flipping, and 6 blobs / 5 paths flip outside a lead label. So the corpus check can fail.

Gates (at b7b8bf6d7)

  • Derived set: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on the actual change set derives 30 commands, identical to the dispatch's 30. All 30 exit 0. pnpm check:pm-dispatch-gates ran detached: ✓ dispatch-gates self-test (fast tier): 1833 cases pass, exit 0.
  • Reconciliation: --ran reports 30 derived, 30 run, 0 NOT-MEASURED, 0 UNRUN.
  • The digest's own suite and its consumers:
    • pnpm check:objectui-changeset: the digest self-test, 163 checks, all checks passed, followed by objectui-range --self-test (which imports classifyRange), also passed.
    • pnpm check:objectui-bump: bump-objectui self-test PASSED — 20 assertions across 5 cases.
    • pnpm check:changeset-gate-self-tests: check-empty-changeset 170 assertions, check-adr-0087-registration 548, check-changeset-no-major 401.
  • Lint, a proven narrowing:
    • The population is read from eslint.config.mjs: the **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} object covers scripts/*.mjs.
    • --format json reports 1 file, 0 errors, 0 warnings.
    • Every parserOptions in the config carries only ecmaVersion / sourceType, so no type-aware linting is enabled and this diff cannot move the verdict on any file it does not touch.
    • The full pnpm lint run is CI's.
  • Changeset: none. Root scripts/ ships in no package's files[], so this PR takes skip-changeset.

Acceptance notes

  • Out of scope, reported to the seat, not edited here (release text). Two console changesets still pending on main carry the old rule's under-count, and they will publish into @objectstack/console's CHANGELOG at the next release:
    • .changeset/console-20c6d351ad74.md line 43 reads ⚠️ 6 of these carry a breaking change. The fixed digest reads 10, and 4 entries there are unmarked.
    • .changeset/console-f0268ad78485.md line 111 reads ⚠️ 4 of these carry a breaking change. The fixed digest reads 10, and 6 entries there are unmarked.
    • The entries are the ones listed under Real hops. The other 9 pending console changesets read the same under both rules.
  • Further positions of the same family, outside triage's binding, left as prose. The 6 prose blobs above are the four positions the grade rules out: a label closed before the parenthetical, an unbolded plain-text label, an unbolded code-span label, and mid-sentence prose. Two of them, the 11674 code-span label and the 11717 mid-sentence line, sit inside the pending hops. They are reported for the family card, not admitted here.

Generated by Claude Code

…tical inside a bold lead label

A line that opens, after an optional bullet, with a bold span holding a
parenthetical whose first word is "breaking" now reads as an author's breaking
annotation (`BREAKING_LEAD_LABEL`, beside the unchanged block opener). The span
must be the line's first token and close on that line; a `(breaking ...)`
anywhere else stays prose. `markBreaking` keeps stamping such an entry: the
label names a package or topic, not the class.

Claude-Session: https://claude.ai/code/session_012zwsLMxQBwHUYJgPyrpEvx
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 13, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 13, 2026 03:06
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 13, 2026 03:06
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 13, 2026
Merged via the queue into main with commit 8807206 Oct 13, 2026
44 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-23118-digest-lead-label-breaking branch October 13, 2026 03:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

2 participants