From c8f476b330395031bc8f7a7aee8d848bc85c81e4 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Fri, 14 Aug 2026 01:28:36 -0400 Subject: [PATCH] Take every themed list in an entry, not the first one (#585) * Take every themed list in an entry, not the first one A long changelog entry is grouped into themed lists behind cf-group labels, and the extractor stopped at the first one. skill-v4.0.0 shipped 6 of its 19 bullets that way, and v4.1.0 would have shipped 6 of 21. This is the same shape as the bounded-search fix one commit earlier: the extractor treated "found a list" as "found the notes". It now collects every cf-items list inside the entry's own article and joins them, so grouping an entry for readability cannot silently truncate its release notes. Written with AI assistance (Claude Code). Co-Authored-By: Claude Opus 5 (1M context) * Name the malformed case separately An entry that opens a cf-items list and never closes it inside its article matched nothing, and the failure said the entry had no list of its own. That is a different repair, and the message sent you looking for the wrong thing. Written with AI assistance (Claude Code). Co-Authored-By: Claude Opus 5 (1M context) --------- Co-authored-by: Claude Opus 5 (1M context) --- scripts/release.mjs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/scripts/release.mjs b/scripts/release.mjs index ae9f661dd..b5d1bc9f6 100755 --- a/scripts/release.mjs +++ b/scripts/release.mjs @@ -173,14 +173,23 @@ if (headerIdx === -1) { // went out carrying v4.0.0's notes that way, and nothing failed. A mismatch // now stops the release instead of publishing another version's words. const articleEnd = changelogHtml.indexOf('', headerIdx); -const listStart = changelogHtml.indexOf('
    ', headerIdx); -const listEnd = changelogHtml.indexOf('
', listStart); -if (listStart === -1 || listEnd === -1) fail('Changelog entry markup is malformed.'); -if (articleEnd !== -1 && listStart > articleEnd) { - fail(`The changelog entry for "${cfg.changelogLabel}${version}" has no
    of its own. ` - + 'Its bullets are in a list this script cannot read, and the next entry\'s notes would ship instead.'); +if (articleEnd === -1) fail('Changelog entry markup is malformed.'); +// EVERY list in the entry, not the first. A long release is grouped into +// themed
      s behind cf-group labels, and taking only the first published one +// theme and silently dropped the rest. +const entryScope = changelogHtml.slice(headerIdx, articleEnd); +const lists = entryScope.match(/
        [\s\S]*?<\/ul>/g); +if (!lists || !lists.length) { + // An unclosed list and a missing one are different repairs, so they get + // different messages. Reporting "no list" for markup that plainly has one + // sends you looking for the wrong thing. + const opened = entryScope.includes('
          '); + fail(opened + ? `The changelog entry for "${cfg.changelogLabel}${version}" opens a
            that is never closed inside its
            . Fix the markup.` + : `The changelog entry for "${cfg.changelogLabel}${version}" has no
              of its own. ` + + 'Its bullets are in a list this script cannot read, and no notes would ship.'); } -const entryHtml = changelogHtml.slice(listStart, listEnd + '
            '.length); +const entryHtml = lists.join('\n'); const notes = htmlToMarkdown(entryHtml); ok('extracted');