Skip to content

release-notes: restore in-flight -unreleased naming + per-preview rollup (R1/R2/R3) - #4179

Merged
mattleibow merged 5 commits into
mainfrom
mattleibow/api-diff-stable-rollup
Jun 17, 2026
Merged

release-notes: restore in-flight -unreleased naming + per-preview rollup (R1/R2/R3)#4179
mattleibow merged 5 commits into
mainfrom
mattleibow/api-diff-stable-rollup

Conversation

@mattleibow

Copy link
Copy Markdown
Contributor

Why

The versions.json supersession migration (#4171/#4174) correctly made which version supersedes which deterministic via versions.json, but its move from per-push branch runs to a bulk --all pass silently regressed three documented behaviours. Pages were migrated in #4174 without the script emitting the data those pages used to contain, so the features were dropped on the next regeneration instead of failing loudly.

Two separate deterministic sources, no magic:

  • versions.json answers "which version supersedes which."
  • Published prerelease git tags answer "which previews shipped and when."

The three regressions (each restored from a deterministic source, not heuristics)

Regression Fix Source
R1 In-flight 4.148/4.150 written as terminal {version}.md; cleanup then deleted the real {version}-unreleased.md terminal-vs-in-flight rule in _page_filename + ownership defer in cmd_all (line head main/release/X.Y.x owns the page; matching rc/preview branch deferred) branch suffix + versions.json
R2 In-flight .x rollup was a servicing-delta instead of full cumulative rollup determine_diff_range honors versions.json compare_to first (4.148.0 → 3.119.4); servicing delta only once .0 has a stable tag versions.json
R3 Trailing ## Preview N (date) sections lost (present in original 3.119.2.md #3763 + TEMPLATE.md; SKILL rules 9/10 mandate them; #4174 deleted them on regen) collect_preview_milestones enumerates them from published prerelease tags in the page's diff range (deduped to latest build per milestone, dated, chained compare links); a page rolls up a skipped predecessor minor's previews too git tags

Self-documentation (so it can't silently regress on the next migration)

  • Code comments on every fix referencing R1/R2/R3 + TEMPLATE/SKILL.
  • New SKILL.md "Page naming & preview rollup (deterministic — script-owned)" section + rule 10 now points at the preview milestones data ("do not invent previews").

Validation (offline --all dry-run, no repo mutation, network stubbed)

  • Correct -unreleased filenames; no bare 4.148.0.md/4.150.0.md.
  • 4.148.0-unreleased.md: diff 3.119.4..release/4.148.x, rolls up 4.147 p1/p2/p3 + 4.148 rc1.
  • 4.150.0-unreleased.md: diff 4.148.0-rc.1..main, lists 4.150 preview1.
  • 4.147.0.md kept (superseded + banner + own previews); 3.119.x unchanged.
  • The 3.119.2.md compare links reproduce the original page exactly.

Not changed (intentionally kept)

versions.json supersession, --all idempotency, contributor crediting, skia link resolution, and the previously-dropped effort metric.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

mattleibow and others added 3 commits June 17, 2026 02:01
The unified-versioning refactor (#4171) started passing
--nugetDiffPrerelease=true to docs-api-diff-past so the 4.x line — which
ships only as previews/rcs until it stabilises — would get changelogs.
But the loop still emitted a folder for *every* enumerated version, so
every intermediate preview now produced its own directory: the API Diff
run filled bot/api-diff (PR #4173) with 4.147.0-preview.{1,2,3},
4.148.0-rc.1.2 and 4.150.0-preview.1.1 dirs across every tracked package
(~2,300 added files). Historically changelogs/ held stable versions only.

Collapse the feed to one entry per release line (the numeric version core
with the prerelease label stripped: 4.148.0-rc.1.2 -> 4.148.0; a genuine
4-part stable like 1.49.2.1 keeps its fourth digit) and emit a single
rollup changelog per line, diffed against the line's representative
package — the newest stable if it shipped, otherwise the newest
prerelease. This mirrors the release-notes pages, which are stable-named
rollups of the previews in between.

A line is emitted when it shipped stable, or when it is an active dev line
(preview-only, not superseded, and newer than the last stable, e.g.
4.148/4.150). Abandoned preview-only lines (superseded in versions.json,
e.g. 4.147) and old never-shipped previews are skipped; their changes are
absorbed into the successor's cumulative diff. Baselines are unchanged:
versions.json compare_to overrides win, otherwise diff against the
previous emitted line.

For SkiaSharp this regenerates to the stable set plus the two active
lines: it adds 3.119.4 (the shipped stable, previously missing) and the
4.148.0/4.150.0 rollups, and prunes the superseded preview-only 3.0.0 and
3.119.3 directories that predated versions.json.

RunBreakingAndFullDiff (published overload) now takes the changelog folder
name separately from the diffed package version, since they differ while a
line is still in preview.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The "Update Release Notes" agentic workflow
(.github/workflows/update-release-notes.md, timeout-minutes: 15) timed out on
its first post-merge run. The cause was the per-PR "effort" badge: it ran one
network `git fetch refs/pull/N/head` per PR to recover pre-squash commit
detail. For the 4.148 release that is 162 serial fetches, each paying full
proxied-TLS setup (~4s) behind the workflow's Squid firewall — ~11 min plus an
unshallow, blowing the 15-min cap. On timeout `safe_outputs` is skipped, so no
PR is ever opened and the cold author-cache never warms: the cold start cannot
self-heal.

The effort value (commit count + working days) earned none of that cost: it is
not rendered in the notes and the model never surfaced it. Everything actually
shown — title, author, number, body, companion skia link — already comes from a
single local `git log`.

Changes:

  * Remove the effort computation and its rendering entirely
    (_get_pr_effort_from_git, compute_pr_effort, _fetch_skia_pr_effort,
    add_pr_effort). This alone takes a cold full `--all` from a 15-min timeout
    to ~35s.
  * Keep the companion `skia: mono/skia#N` hint, parsed locally from the PR
    body, and add the `mono/skia#N` shorthand that milestone bumps use.
  * Resolve the companion link for submodule-bump PRs that don't spell it out,
    purely locally. The bump and its target skia SHA are read from the
    superproject tree (`git rev-parse <commit>:externals/skia` vs its parent);
    the bumped skia commit's own subject ((#N) / "Merge pull request #N") is then
    read from the submodule. The only network is one batched, blobless, shallow
    `git fetch` of just the bumped SHAs; already-present commits are skipped, so
    `--all` fetches each skia commit at most once (a handful per run, not 162).

For 4.148 this lifts companion-link coverage of skia-bumping PRs from 18 to 22
of 23. The single remaining gap is an anomalous backwards gitlink (PR #4081
resets the submodule to mono/skia's scaffold root, which has no PR); its real
companion, skia #242, is already linked via the forward bump. The other
historical misses are skia commits pushed directly to mono/skia with no PR at
all, so there is nothing to link.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lup (R1/R2/R3)

The versions.json supersession migration (#4171/#4174) correctly made
"which version supersedes which" deterministic via versions.json, but its
move from per-push branch runs to a bulk `--all` pass silently regressed
three documented behaviours. Pages were migrated in #4174 without the
script emitting the data those pages used to contain, so the features were
dropped on the next regeneration instead of failing loudly.

Three regressions, each restored from a deterministic source (not heuristics):

R1 — in-flight naming. 4.148 and 4.150 were written as terminal
`{version}.md` and the cleanup pass then deleted the real
`{version}-unreleased.md`. Root cause: `--all` picks the rc.1/preview.1
branch as canonical for the version. Fixed with a terminal-vs-in-flight
rule in `_page_filename` (suffix-less `release/X.Y.Z` branch exists, or
`status: superseded` in versions.json => `{version}.md`; otherwise
`{version}-unreleased.md`) plus an ownership filter in `cmd_all` so the
line head (main / `release/X.Y.x`) owns the `-unreleased` page and the
matching rc/preview branch is deferred instead of colliding.

R2 — in-flight `.x` rollup was a servicing-delta instead of the full
cumulative rollup. `determine_diff_range` now honors the versions.json
`compare_to` first (4.148.0 -> 3.119.4) and only does a servicing delta
once the `.0` has actually shipped a stable tag.

R3 — the trailing `## Preview N (date)` sections were lost. The original
3.119.2.md (#3763) and TEMPLATE.md have them and SKILL rules 9/10 mandate
them, but #4174 deleted them on regen because the script never emitted
preview data. `collect_preview_milestones` now enumerates them from the
published prerelease git tags within the page's diff range (deduped to the
latest build per milestone, dated, with chained compare links). A page
rolls up a skipped predecessor minor's previews too, so the 4.148 page
lists the 4.147 previews that match its rolled-up PRs.

Two separate deterministic sources, no magic: versions.json answers "which
version supersedes which"; published tags answer "which previews shipped
and when". Documented in code comments (R1/R2/R3) and a new SKILL.md
"Page naming & preview rollup" section so this can't silently regress on
the next migration. Validated with an offline `--all` dry-run: correct
`-unreleased` filenames, 4.148 rolls up 4.147 p1/p2/p3 + rc1, no bare
4.148.0.md/4.150.0.md, 3.119.x unchanged, and the 3.119.2 compare links
reproduce the original page exactly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

📦 Try the packages from this PR

Warning

Do not run these scripts without first reviewing the code in this PR.

Step 1 — Download the packages

bash / macOS / Linux:

curl -fsSL https://raw.githubusercontent.com/mono/SkiaSharp/main/scripts/get-skiasharp-pr.sh | bash -s -- 4179

PowerShell / Windows:

iex "& { $(irm https://raw.githubusercontent.com/mono/SkiaSharp/main/scripts/get-skiasharp-pr.ps1) } 4179"

Step 2 — Add the local NuGet source

dotnet nuget add source ~/.skiasharp/hives/pr-4179/packages --name skiasharp-pr-4179
More options
Option Description
--successful-only / -SuccessfulOnly Only use successful builds
--force / -Force Overwrite previously downloaded packages
--list / -List List available artifacts without downloading
--build-id ID / -BuildId ID Download from a specific build

Or download manually from Azure Pipelines — look for the nuget artifact on the build for this PR.

Remove the source when you're done:

dotnet nuget remove source skiasharp-pr-4179

mattleibow and others added 2 commits June 17, 2026 10:32
…lup (R1/R2/R3)

The versions.json supersession migration (#4171/#4174) correctly made
"which version supersedes which" deterministic via versions.json, but its
move from per-push branch runs to a bulk `--all` pass silently regressed
three documented behaviours. Pages were migrated in #4174 without the
script emitting the data those pages used to contain, so the features were
dropped on the next regeneration instead of failing loudly.

Three regressions, each restored from a deterministic source (not heuristics):

R1 — in-flight naming. 4.148 and 4.150 were written as terminal
`{version}.md` and the cleanup pass then deleted the real
`{version}-unreleased.md`. Root cause: `--all` picks the rc.1/preview.1
branch as canonical for the version. Fixed with a terminal-vs-in-flight
rule in `_page_filename` (suffix-less `release/X.Y.Z` branch exists, or
`status: superseded` in versions.json => `{version}.md`; otherwise
`{version}-unreleased.md`) plus an ownership filter in `cmd_all` so the
line head (main / `release/X.Y.x`) owns the `-unreleased` page and the
matching rc/preview branch is deferred instead of colliding.

R2 — in-flight `.x` rollup was a servicing-delta instead of the full
cumulative rollup. `determine_diff_range` now honors the versions.json
`compare_to` first (4.148.0 -> 3.119.4) and only does a servicing delta
once the `.0` has actually shipped a stable tag.

R3 — the trailing `## Preview N (date)` sections were lost. The original
3.119.2.md (#3763) and TEMPLATE.md have them and SKILL rules 9/10 mandate
them, but #4174 deleted them on regen because the script never emitted
preview data. `collect_preview_milestones` now enumerates them from the
published prerelease git tags within the page's diff range (deduped to the
latest build per milestone, dated, with chained compare links). A page
rolls up a skipped predecessor minor's previews too, so the 4.148 page
lists the 4.147 previews that match its rolled-up PRs.

Two separate deterministic sources, no magic: versions.json answers "which
version supersedes which"; published tags answer "which previews shipped
and when". Documented in code comments (R1/R2/R3) and a new SKILL.md
"Page naming & preview rollup" section so this can't silently regress on
the next migration. Validated with an offline `--all` dry-run: correct
`-unreleased` filenames, 4.148 rolls up 4.147 p1/p2/p3 + rc1, no bare
4.148.0.md/4.150.0.md, 3.119.x unchanged, and the 3.119.2 compare links
reproduce the original page exactly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

📖 Documentation Preview

The documentation for this PR has been deployed and is available at:

🔗 View Staging Site
🔗 View Staging Docs
🔗 View Staging Gallery (Blazor)
🔗 View Staging Gallery (Uno Platform)
🔗 View Staging SkiaFiddle

This preview will be updated automatically when you push new commits to this PR.


This comment is automatically updated by the documentation staging workflow.

@mattleibow
mattleibow merged commit 61f6d31 into main Jun 17, 2026
5 of 6 checks passed
@mattleibow
mattleibow deleted the mattleibow/api-diff-stable-rollup branch June 17, 2026 13:51
mattleibow added a commit that referenced this pull request Jun 17, 2026
A version's "released" and "unreleased" states are orthogonal: a version
can be on NuGet as a shipped prerelease (e.g. 4.150.0-preview.1) AND have
newer, not-yet-released commits on its head branch (main). The original
two-file model gave each of those its own page — a full-rollup released
`{version}.md` and a small-delta `{version}-unreleased.md` — and they
coexisted while the version was in flight.

A five-PR refactor stack (#4174, #4177, #4179) collapsed this into a
single page per version:

  * #4174 added `--all` + `cleanup_stale_unreleased`, which deleted
    `{v}-unreleased.md` whenever `{v}.md` existed — killing the
    coexisting in-flight delta page.
  * #4179 (R2) forced `main`/`.x` heads to honor `versions.json`
    `compare_to`, turning the small "what may ship next" delta into a
    full rollup.
  * #4179 (R1) remapped prerelease branches to `-unreleased` and
    deferred them, collapsing released + unreleased onto one file.

Restore the original delta semantics while keeping the genuinely-good
additions from the stack (versions.json supersession + compare_to on the
RELEASED rollup pages, preview-milestone rollup, contributor credit,
local skia links, `--all` idempotency):

  * `_page_filename`: versioned branch (incl. -rc/-preview) -> released
    `{version}.md`; `main`/`.x` head -> `{version}-unreleased.md`.
  * `determine_diff_range` (main + servicing `.x`): drop the versions.json
    `compare_to` override on heads so the unreleased page is again the
    small delta from the last release to head, not a rollup. `compare_to`
    still drives the released rollup pages produced by versioned branches.
  * `cmd_all`: process main + servicing + ALL canonical versioned branches;
    no deferral (distinct filenames never collide).
  * `cleanup_stale_unreleased`: delete `{v}-unreleased.md` only once the
    line advances to a strictly-higher version in the same minor — keeps
    the in-flight released+unreleased pair, still prunes obsolete deltas
    (e.g. 3.119.4-unreleased once 3.119.5 appears).
  * `_write_page`: an unreleased head with an empty delta emits no page
    (and prunes any stale one) — nothing to ship next.

Net effect on the 4.x line: 4.148.0.md / 4.150.0.md are full released
rollups (with preview milestones + supersede banners), 4.150.0-unreleased.md
is the small `release/4.150.0-preview.1..main` delta, and 4.148.0 has no
unreleased page because release/4.148.x has zero commits past the rc.
Verified by running the script for real (`--all`): it emitted exactly
those pages and listed only the changed ones under "Files to polish".

Keep the page model where it belongs — in the SCRIPT. The script owns ALL
file creation, naming, diff ranges, supersession, and cleanup; the AI/skill
only polishes the prose of the files the script lists. The detailed model
now lives in the script's module + function docstrings, and SKILL.md is
trimmed to a clear "division of responsibility" instead of duplicating
(and drifting from) the naming rules.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mattleibow added a commit that referenced this pull request Jun 17, 2026
A version's "released" and "unreleased" states are orthogonal: a version
can be on NuGet as a shipped prerelease (e.g. 4.150.0-preview.1) AND have
newer, not-yet-released commits on its head branch (main). The original
two-file model gave each of those its own page — a full-rollup released
`{version}.md` and a small-delta `{version}-unreleased.md` — and they
coexisted while the version was in flight.

A five-PR refactor stack (#4174, #4177, #4179) collapsed this into a
single page per version:

  * #4174 added `--all` + `cleanup_stale_unreleased`, which deleted
    `{v}-unreleased.md` whenever `{v}.md` existed — killing the
    coexisting in-flight delta page.
  * #4179 (R2) forced `main`/`.x` heads to honor `versions.json`
    `compare_to`, turning the small "what may ship next" delta into a
    full rollup.
  * #4179 (R1) remapped prerelease branches to `-unreleased` and
    deferred them, collapsing released + unreleased onto one file.

Restore the original delta semantics while keeping the genuinely-good
additions from the stack (versions.json supersession + compare_to on the
RELEASED rollup pages, preview-milestone rollup, contributor credit,
local skia links, `--all` idempotency):

  * `_page_filename`: versioned branch (incl. -rc/-preview) -> released
    `{version}.md`; `main`/`.x` head -> `{version}-unreleased.md`.
  * `determine_diff_range` (main + servicing `.x`): drop the versions.json
    `compare_to` override on heads so the unreleased page is again the
    small delta from the last release to head, not a rollup. `compare_to`
    still drives the released rollup pages produced by versioned branches.
  * `cmd_all`: process main + servicing + ALL canonical versioned branches;
    no deferral (distinct filenames never collide).
  * `cleanup_stale_unreleased`: delete `{v}-unreleased.md` only once the
    line advances to a strictly-higher version in the same minor — keeps
    the in-flight released+unreleased pair, still prunes obsolete deltas
    (e.g. 3.119.4-unreleased once 3.119.5 appears).
  * `_write_page`: an unreleased head with an empty delta emits no page
    (and prunes any stale one) — nothing to ship next.

Net effect on the 4.x line: 4.148.0.md / 4.150.0.md are full released
rollups (with preview milestones + supersede banners), 4.150.0-unreleased.md
is the small `release/4.150.0-preview.1..main` delta, and 4.148.0 has no
unreleased page because release/4.148.x has zero commits past the rc.
Verified by running the script for real (`--all`): it emitted exactly
those pages and listed only the changed ones under "Files to polish".

Keep the page model where it belongs — in the SCRIPT. The script owns ALL
file creation, naming, diff ranges, supersession, and cleanup; the AI/skill
only polishes the prose of the files the script lists. The detailed model
now lives in the script's module + function docstrings, and SKILL.md is
trimmed to a clear "division of responsibility" instead of duplicating
(and drifting from) the naming rules.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mattleibow added a commit that referenced this pull request Jun 17, 2026
A version's "released" and "unreleased" states are orthogonal: a version
can be on NuGet as a shipped prerelease (e.g. 4.150.0-preview.1) AND have
newer, not-yet-released commits on its head branch (main). The original
two-file model gave each of those its own page — a full-rollup released
`{version}.md` and a small-delta `{version}-unreleased.md` — and they
coexisted while the version was in flight.

A five-PR refactor stack (#4174, #4177, #4179) collapsed this into a
single page per version:

  * #4174 added `--all` + `cleanup_stale_unreleased`, which deleted
    `{v}-unreleased.md` whenever `{v}.md` existed — killing the
    coexisting in-flight delta page.
  * #4179 (R2) forced `main`/`.x` heads to honor `versions.json`
    `compare_to`, turning the small "what may ship next" delta into a
    full rollup.
  * #4179 (R1) remapped prerelease branches to `-unreleased` and
    deferred them, collapsing released + unreleased onto one file.

Restore the original delta semantics while keeping the genuinely-good
additions from the stack (versions.json supersession + compare_to on the
RELEASED rollup pages, preview-milestone rollup, contributor credit,
local skia links, `--all` idempotency):

  * `_page_filename`: versioned branch (incl. -rc/-preview) -> released
    `{version}.md`; `main`/`.x` head -> `{version}-unreleased.md`.
  * `determine_diff_range` (main + servicing `.x`): drop the versions.json
    `compare_to` override on heads so the unreleased page is again the
    small delta from the last release to head, not a rollup. `compare_to`
    still drives the released rollup pages produced by versioned branches.
  * `cmd_all`: process main + servicing + ALL canonical versioned branches;
    no deferral (distinct filenames never collide).
  * `cleanup_stale_unreleased`: delete `{v}-unreleased.md` only once the
    line advances to a strictly-higher version in the same minor — keeps
    the in-flight released+unreleased pair, still prunes obsolete deltas
    (e.g. 3.119.4-unreleased once 3.119.5 appears).
  * `_write_page`: an unreleased head with an empty delta emits no page
    (and prunes any stale one) — nothing to ship next.

Net effect on the 4.x line: 4.148.0.md / 4.150.0.md are full released
rollups (with preview milestones + supersede banners), 4.150.0-unreleased.md
is the small `release/4.150.0-preview.1..main` delta, and 4.148.0 has no
unreleased page because release/4.148.x has zero commits past the rc.
Verified by running the script for real (`--all`): it emitted exactly
those pages and listed only the changed ones under "Files to polish".

Keep the page model where it belongs — in the SCRIPT. The script owns ALL
file creation, naming, diff ranges, supersession, and cleanup; the AI/skill
only polishes the prose of the files the script lists. The detailed model
now lives in the script's module + function docstrings, and SKILL.md is
trimmed to a clear "division of responsibility" instead of duplicating
(and drifting from) the naming rules.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mattleibow added a commit that referenced this pull request Jun 17, 2026
A version's "released" and "unreleased" states are orthogonal: a version
can be on NuGet as a shipped prerelease (e.g. 4.150.0-preview.1) AND have
newer, not-yet-released commits on its head branch (main). The original
two-file model gave each of those its own page — a full-rollup released
`{version}.md` and a small-delta `{version}-unreleased.md` — and they
coexisted while the version was in flight.

A five-PR refactor stack (#4174, #4177, #4179) collapsed this into a
single page per version:

  * #4174 added `--all` + `cleanup_stale_unreleased`, which deleted
    `{v}-unreleased.md` whenever `{v}.md` existed — killing the
    coexisting in-flight delta page.
  * #4179 (R2) forced `main`/`.x` heads to honor `versions.json`
    `compare_to`, turning the small "what may ship next" delta into a
    full rollup.
  * #4179 (R1) remapped prerelease branches to `-unreleased` and
    deferred them, collapsing released + unreleased onto one file.

Restore the original delta semantics while keeping the genuinely-good
additions from the stack (versions.json supersession + compare_to on the
RELEASED rollup pages, preview-milestone rollup, contributor credit,
local skia links, `--all` idempotency):

  * `_page_filename`: versioned branch (incl. -rc/-preview) -> released
    `{version}.md`; `main`/`.x` head -> `{version}-unreleased.md`.
  * `determine_diff_range` (main + servicing `.x`): drop the versions.json
    `compare_to` override on heads so the unreleased page is again the
    small delta from the last release to head, not a rollup. `compare_to`
    still drives the released rollup pages produced by versioned branches.
  * `cmd_all`: process main + servicing + ALL canonical versioned branches;
    no deferral (distinct filenames never collide).
  * `cleanup_stale_unreleased`: delete `{v}-unreleased.md` only once the
    line advances to a strictly-higher version in the same minor — keeps
    the in-flight released+unreleased pair, still prunes obsolete deltas
    (e.g. 3.119.4-unreleased once 3.119.5 appears).
  * `_write_page`: an unreleased head with an empty delta emits no page
    (and prunes any stale one) — nothing to ship next.

Bucket PRs per preview so the AI can summarize each milestone directly.
A released rollup spans several prerelease tags; a single flat PR list
left the AI guessing which work shipped in which preview. The script now
partitions the PRs into per-preview buckets via git ancestry — each PR
under the EARLIEST milestone tag whose range contains its commit, i.e.
the preview it first shipped in (`bucket_prs_by_milestone`). The buckets
exhaustively cover the range (every PR lands in exactly one), so they ARE
the full list — no separate flat list to drift. The AI renders one
`## Preview N` section per bucket and merges them for the Highlights.
Verified: 4.148.0.md partitions its 162 PRs as RC1 35 + P3 37 + P2 27 +
P1 63 = 162 (no leftover); 4.150.0.md as Preview 1 = 2; the
4.150.0-unreleased.md delta has no previews and stays a flat 7-PR list.

Keep the page model where it belongs — in the SCRIPT. The script owns ALL
file creation, naming, diff ranges, supersession, cleanup, and PR
bucketing; the AI/skill only polishes prose and, on any anomaly (missing
or unexpected page, bad data), STOPS and reports rather than editing the
script or working around it. The model lives in the script's module +
function docstrings; SKILL.md is trimmed to a "division of responsibility"
plus how to consume the pre-bucketed PR data, instead of duplicating (and
drifting from) the naming rules.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant