From b2613a3262ac83bad0c9976551730db722f662e8 Mon Sep 17 00:00:00 2001 From: Marc LeBlanc <7050295+marcleblanc2@users.noreply.github.com> Date: Thu, 10 Sep 2026 23:14:44 -0600 Subject: [PATCH 1/4] CSpell review: leave no orphaned review body once findings are fixed Post the inline-comment review with an empty body, minimize the summary comment as resolved when findings reach zero (and unminimize when new ones appear), and move the 'up to N inline' note into the summary. Co-authored-by: Amp Amp-Thread-ID: https://ampcode.com/threads/T-01a08e26-0c39-723b-95ad-65455002f541 --- dev/post-spelling-review.mjs | 85 +++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/dev/post-spelling-review.mjs b/dev/post-spelling-review.mjs index 467fbb12b..38d18a88e 100644 --- a/dev/post-spelling-review.mjs +++ b/dev/post-spelling-review.mjs @@ -2,7 +2,10 @@ /** * Reports CSpell findings on a pull request: one summary comment in the - * discussion, plus an inline review comment on each flagged line. + * discussion, plus an inline review comment on each flagged line. Once the + * findings are fixed, the summary is minimized as resolved and the inline + * comments are deleted; the review that carried them has no body, so nothing + * of it remains visible. * * Usage: node dev/post-spelling-review.mjs --findings [--dry-run] * @@ -66,6 +69,26 @@ async function githubWrite(method, route, body) { } } +// Minimizing a comment is GraphQL-only. Both mutations are idempotent. +async function setCommentMinimized(nodeId, minimized) { + const mutation = minimized + ? 'minimizeComment(input: {subjectId: $id, classifier: RESOLVED}) { clientMutationId }' + : 'unminimizeComment(input: {subjectId: $id}) { clientMutationId }'; + console.log( + `${DRY_RUN ? '[dry-run] ' : ''}${minimized ? 'minimize' : 'unminimize'} comment ${nodeId}` + ); + if (DRY_RUN) { + return; + } + const result = await github('POST', '/graphql', { + query: `mutation ($id: ID!) { ${mutation} }`, + variables: {id: nodeId} + }); + if (result.errors) { + throw new Error(`GraphQL failed: ${JSON.stringify(result.errors)}`); + } +} + function groupByFile(findings) { const grouped = new Map(); for (const finding of findings) { @@ -83,6 +106,11 @@ function summaryBody(findings) { `### ⚠️ CSpell found ${findings.length} spelling error(s) in this PR`, '', 'Only findings on lines added by this PR are shown.', + ...(findings.length > MAX_INLINE_COMMENTS + ? [ + `Up to ${MAX_INLINE_COMMENTS} of them are also commented inline.` + ] + : []), '' ]; for (const [file, fileFindings] of groupByFile(findings)) { @@ -111,29 +139,30 @@ async function upsertSummaryComment(findings) { comment.body.startsWith(SUMMARY_MARKER) ); - // Comment only when there is something to report, or an earlier report to resolve - let body; - if (findings.length > 0) { - body = summaryBody(findings); - } else if (existing) { - body = `${SUMMARY_MARKER}\n### ✅ The spelling errors reported on an earlier revision are fixed\n`; - } else { + if (!existing) { + if (findings.length > 0) { + await githubWrite( + 'POST', + `/repos/${REPOSITORY}/issues/${PR_NUMBER}/comments`, + {body: summaryBody(findings)} + ); + } return; } - if (existing) { - await githubWrite( - 'PATCH', - `/repos/${REPOSITORY}/issues/comments/${existing.id}`, - {body} - ); - } else { - await githubWrite( - 'POST', - `/repos/${REPOSITORY}/issues/${PR_NUMBER}/comments`, - {body} - ); - } + // Keep the earlier report, collapsed as resolved, so the discussion still + // shows what was flagged and fixed. Reopen it when new findings appear. + const resolved = findings.length === 0; + await githubWrite( + 'PATCH', + `/repos/${REPOSITORY}/issues/comments/${existing.id}`, + { + body: resolved + ? `${SUMMARY_MARKER}\n### ✅ The spelling errors reported on an earlier revision are fixed\n` + : summaryBody(findings) + } + ); + await setCommentMinimized(existing.node_id, resolved); } function findingKey({file, line, word}) { @@ -187,13 +216,6 @@ function inlineBody(finding) { ].join('\n'); } -function reviewBody(shown, total) { - const summary = `CSpell found ${total} spelling error(s) on lines added by this PR. Please correct them, or add them to ${ALLOW_LIST_LINK} if they are correct.`; - return shown < total - ? `${summary} The first ${shown} are commented inline; the summary comment lists them all.` - : summary; -} - async function syncInlineComments(findings) { const wanted = new Map( findings.map(finding => [findingKey(finding), finding]) @@ -221,15 +243,16 @@ async function syncInlineComments(findings) { if (fresh.length === 0) { return; } - const shown = fresh.slice(0, MAX_INLINE_COMMENTS); + // No review body: the inline comments say it all, and a submitted review + // cannot be deleted, so a body would outlive the comments once fixed. await githubWrite( 'POST', `/repos/${REPOSITORY}/pulls/${PR_NUMBER}/reviews`, { commit_id: HEAD_SHA, event: 'COMMENT', - body: reviewBody(shown.length, fresh.length), - comments: shown.map(finding => ({ + body: '', + comments: fresh.slice(0, MAX_INLINE_COMMENTS).map(finding => ({ path: finding.file, line: finding.line, side: 'RIGHT', From 5edacb80bae2239de27d04123c0fd8c3057366b7 Mon Sep 17 00:00:00 2001 From: Marc LeBlanc <7050295+marcleblanc2@users.noreply.github.com> Date: Thu, 10 Sep 2026 23:17:04 -0600 Subject: [PATCH 2/4] cspell: allow unminimize Co-authored-by: Amp --- cspell-allow-list.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cspell-allow-list.txt b/cspell-allow-list.txt index e5d99ffcd..5af900c92 100644 --- a/cspell-allow-list.txt +++ b/cspell-allow-list.txt @@ -570,6 +570,7 @@ unibeautify unindexed unioned unmigrated +unminimize untar updatecheck upperand From 33019720c876a2053ab9a2ccdad8c752a391a7aa Mon Sep 17 00:00:00 2001 From: Marc LeBlanc <7050295+marcleblanc2@users.noreply.github.com> Date: Thu, 10 Sep 2026 23:15:12 -0600 Subject: [PATCH 3/4] test: deliberate misspellings for CSpell workflow test (do not merge) Co-authored-by: Amp Amp-Thread-ID: https://ampcode.com/threads/T-01a08e26-0c39-723b-95ad-65455002f541 --- docs/analytics/api.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/analytics/api.mdx b/docs/analytics/api.mdx index ae19db78b..1079d4fa2 100644 --- a/docs/analytics/api.mdx +++ b/docs/analytics/api.mdx @@ -1,6 +1,6 @@ # Sourcegraph Analytics API -The Sourcegraph Analytics API is an API that provides programmatic access to your Sourcegraph Analytics data, including usage metrics, user activity, and performance data. +The Sourcegraph Analytics API is an API that provides programattic acess to your Sourcegraph Analytics data, including usage metrics, user activity, and performance data. ## Access tokens From 0e772c67c91ab91da5bc69bf3c1df73732747367 Mon Sep 17 00:00:00 2001 From: Marc LeBlanc <7050295+marcleblanc2@users.noreply.github.com> Date: Thu, 10 Sep 2026 23:17:07 -0600 Subject: [PATCH 4/4] test: fix the deliberate misspellings Co-authored-by: Amp --- docs/analytics/api.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/analytics/api.mdx b/docs/analytics/api.mdx index 1079d4fa2..ae19db78b 100644 --- a/docs/analytics/api.mdx +++ b/docs/analytics/api.mdx @@ -1,6 +1,6 @@ # Sourcegraph Analytics API -The Sourcegraph Analytics API is an API that provides programattic acess to your Sourcegraph Analytics data, including usage metrics, user activity, and performance data. +The Sourcegraph Analytics API is an API that provides programmatic access to your Sourcegraph Analytics data, including usage metrics, user activity, and performance data. ## Access tokens