Skip to content

fix(ci): scope spell-check to the PR's own diff, not a stale base ref - #3640

Open
Imran Siddique (imran-siddique) wants to merge 3 commits into
mainfrom
fix/spell-check-merge-base-scope
Open

fix(ci): scope spell-check to the PR's own diff, not a stale base ref#3640
Imran Siddique (imran-siddique) wants to merge 3 commits into
mainfrom
fix/spell-check-merge-base-scope

Conversation

@imran-siddique

@imran-siddique Imran Siddique (imran-siddique) commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Hardening for the spell-check scoping in #3514, plus one real defect in changed_lines.py.

Correction to the original framing

This PR previously claimed that actions/checkout narrows remote.origin.fetch, leaving refs/remotes/origin/<base> stale and causing the job to over-scan. That is wrong, and I have withdrawn it. MohammadHaroonAbuomar was right on all three points, and I checked each rather than taking them:

What this PR is now

1. Explicit refspec on the base fetch — hardening, not a bug fix.

git fetch --no-tags origin "+${base}:refs/remotes/origin/${base}"

git fetch origin <branch> is only guaranteed to write FETCH_HEAD. Whether it also updates refs/remotes/origin/<branch> depends on the configured remote.origin.fetch. On this workflow today the wildcard is intact, so the plain form works and there is no live bug here. Naming the destination ref makes the next step's --base origin/<base> correct regardless of remote configuration. The reason it is worth doing at all is the failure mode: a stale tracking ref does not fail loudly, because git merge-base against one still succeeds, so the fallback warning never fires and an over-scan looks exactly like a correctly scoped run. The workflow comment has been rewritten to say this rather than the causal claim.

2. extract_added_lines silently dropped added content — a genuine live bug.

Raised by MohammadHaroonAbuomar in review. The +++ b/path file header was skipped by prefix:

if line.startswith("+++"):
    continue

An added source line whose own content starts with ++ is rendered +++... in a unified diff and is indistinguishable from that header by prefix. It was therefore dropped, and its words were never spell-checked. File headers only appear before the first @@ of each file, so tracking whether a hunk is open separates the two exactly.

This fails in the direction the script must not fail in. Over-reporting is noise; under-reporting means the check passes on text nobody looked at.

3. Tests.

  • test_added_line_whose_content_starts_with_plus_plus_is_not_dropped — fails on the previous implementation, passes on this one.
  • test_file_headers_are_still_skipped_across_several_files — the position rule must not start admitting real +++ b/path headers.
  • test_fallback_emits_a_workflow_annotation_only_under_github_actions — the annotation-branch coverage asked for in review, both directions.

4. Two dictionary entries, unchanged from before: linkbase (#3620's step id) and unpermitted (#3200's test name).

Verification

pytest tests/ci/ is 76 passed, 6 skipped. ruff check --select E,F,W --ignore E501 clean on both touched Python files. The workflow YAML parses.

Still open, not addressed here

MohammadHaroonAbuomar's point about #3620 inheriting the same git fetch pattern stands, but since the stale-ref concern is hardening rather than a live bug, it is no longer urgent and does not need to block that PR.

`git fetch origin <branch>` only writes FETCH_HEAD unless the configured
refspec covers the branch. actions/checkout narrows remote.origin.fetch to
the ref it checked out, so on a pull request `refs/remotes/origin/<base>`
keeps whatever value it had at checkout time.

`--base origin/<base>` then resolves a merge base against that stale ref.
It succeeds, so no warning fires, but it points far enough back that every
commit landing on the base since is reported as added. PR #3567 changes two
TypeScript files totalling 83 added lines and was spell-checked against
several hundred lines it never touched, failing on words absent from its
diff (AEDT, anthonyonazure, Clendenen, langgenius, ringbreachdetector).
22 of 68 open PRs currently have a red spell-check.

- Fetch the base with an explicit refspec so the remote-tracking ref is
  actually updated.
- Emit the merge-base fallback as a ::warning:: annotation as well as on
  stderr. On stderr alone an over-reporting run is indistinguishable from a
  correctly scoped one at the point where the check result is read, which is
  how this went unnoticed while failing unrelated PRs.
- Add the two words genuinely introduced by open PRs: `linkbase` (#3620) and
  `unpermitted` (#3200). The rest of the currently-flagged words are
  artifacts of the over-report and go away with the scoping fix.

Refs #3514.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Imran Siddique <imran.siddique@opaque.co>
Copilot AI lite review requested due to automatic review settings August 6, 2026 16:01
@github-actions github-actions Bot added the size/S Small PR (< 50 lines) label Aug 6, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

TL;DR: 0 blockers, 0 warnings. No issues found. Clean change.

This PR fixes CI spell-check scoping so the job computes the merge-base against an up-to-date origin/<base> remote-tracking ref, preventing unrelated base-branch changes from being treated as “added lines” in PR runs.

Changes:

  • Update the PR base fetch to use an explicit refspec so refs/remotes/origin/${{ github.base_ref }} is actually refreshed on pull_request runs.
  • Improve changed_lines.py’s merge-base fallback visibility by emitting a GitHub Actions ::warning:: annotation (while keeping stdout clean for consumers).
  • Add two repo dictionary terms (linkbase, unpermitted) to avoid legitimate PR-introduced words failing cspell.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
scripts/ci/changed_lines.py Emits a workflow annotation when merge-base resolution fails, without contaminating stdout output.
.github/workflows/spell-check.yml Fetches the base branch with an explicit refspec to avoid stale origin/<base> during merge-base computation.
.cspell-repo-terms.txt Adds two new project terms to prevent false-positive spellcheck failures.

@MohammadHaroonAbuomar MohammadHaroonAbuomar left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • .github/workflows/spell-check.yml: the 10-line comment (and the PR body) attribute the over-scan to checkout narrowing remote.origin.fetch so origin/ stays stale - this does not hold on current main: the runner logs show plain git remote add (wildcard refspec intact) with fetch-depth: 0, and a runner-faithful reproduction shows git fetch origin main updating the tracking ref, with correct single-line scoping both before and after this change. The over-scan evidence cited (the 2026-08-04 run, the 22 red PRs) predates #3530 and shows the OLD workflow; those checks just need a re-run/rebase. Please rewrite the comment and body to present the explicit refspec as what it is - defensive hardening that guarantees the tracking ref exists regardless of remote config - and drop the stale-ref causal claim.

Minor:

  • the refspec itself, the ::warning:: annotation, and the two dictionary terms are all fine and verified; a small test for the GITHUB_ACTIONS annotation branch would be welcome. CI at this head died in a GitHub Actions infra outage - full re-run needed regardless. The pre-existing extract_added_lines '++ '-line skip remains open if you want a genuinely live bug in this file.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

PR Review Summary

Check Status Details
🔍 Code Review ⚠️ Missing No current-run comment
🛡️ Security Scan ⚠️ Missing No current-run comment
🔄 Breaking Changes ⚠️ Missing No current-run comment
📝 Docs Sync ⚠️ Missing No current-run comment
🧪 Test Coverage ⚠️ Missing No current-run comment

Verdict: ⚠️ AI review incomplete; ready for human review

AI review comments are untrusted advisory output. The summary reports workflow-generated completion status only, not model-authored pass/fail claims.

@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@github-actions github-actions Bot added tests scripts/ci/cd size/M Medium PR (< 200 lines) and removed size/S Small PR (< 50 lines) labels Aug 12, 2026
@imran-siddique

Copy link
Copy Markdown
Collaborator Author

MohammadHaroonAbuomar you were right on all three, and I checked each rather than just taking them. Body and workflow comment rewritten, causal claim withdrawn.

The mechanism. #3530 merged 2026-08-05 03:42 and already fixed the scoping. Runs after it scope correctly: #3648 flags cooldown, which appears 11 times in its own diff, and #3646 flags Bleichenbacher, SPKI, OCSP, FFDH, AESGCM, all from the 42-line audit doc it adds. Neither touches anything outside itself.

My evidence was stale and I should have caught that. The #3567 run I quoted completed 2026-08-04 22:00, five hours before #3530 landed. The 22-red-PRs figure was true when I measured it and became a count of old-workflow runs while the PR sat open. The refspec is now presented as what it is: hardening that makes --base origin/<base> correct regardless of remote config, worth having only because a stale tracking ref fails silently rather than loudly.

The outage. Confirmed, Failed to resolve action download info. Error: Service Unavailable on Validate PR title, three times, with the other 17 sharing the signature and window. This push should give a clean run.

Your extract_added_lines tip was the best thing in the review, and it is a real bug. An added source line whose content starts with ++ renders as +++... and was dropped by the prefix test, so its words were never checked. Skipping by hunk position instead separates header from content exactly. Worth noting it fails in the direction this script must not fail in: over-reporting is noise, under-reporting means the check goes green on text nobody read.

Also added the annotation-branch test you asked for, both directions, and a guard that the position rule does not start admitting real +++ b/path headers. pytest tests/ci/ is 76 passed, 6 skipped.

The '++ '-line skip you mentioned separately in extract_added_lines is the same one, unless you meant something else in that file, in which case point me at it.

…ines

Rewrites the spell-check.yml comment to present the explicit refspec as
hardening rather than as the fix for an observed over-scan. The stale-ref
causal claim did not hold: #3530 had already corrected the scoping, and
runs after it scope correctly.

Also fixes a real defect in extract_added_lines. The `+++ b/path` header
was skipped by prefix, which silently drops an added line whose own
content starts with `++` (rendered `+++...` in the diff). Skipping by
hunk position separates the two exactly. Adds a regression test that
fails without the fix, plus coverage for the GITHUB_ACTIONS annotation
branch.

Signed-off-by: Imran Siddique <imran.siddique@opaque.co>
The new tests exercise extract_added_lines, which only extracts, so the
fixtures never needed misspelled words. Using them meant the added lines
reintroduced typoo and tokenn into the spell-check scan, which the job
correctly flagged.

Adds refspec to the repo terms: a genuine git term now used in the
spell-check.yml comment.

Signed-off-by: Imran Siddique <imran.siddique@opaque.co>
@imran-siddique

Copy link
Copy Markdown
Collaborator Author

Cross-reference for whoever picks this up: the two dictionary entries in this PR are load-bearing for other people's work.

linkbase is the step id introduced by #3620, liamcrumm's markdown-link-check merge-base fix. That PR's only failing check is Spell-check changed files, failing twice on exactly that word, and it has been open eight days. So a maintainer's CI fix is blocked on a one-line dictionary entry sitting in this PR, and neither PR's checks make that visible.

If this one is going to sit, the linkbase line should move to #3620 so it can go green on its own. Happy to do that either way, just say which you prefer.

unpermitted is the same shape for #3200's test name, though that PR has other things outstanding.

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

Labels

scripts/ci/cd size/M Medium PR (< 200 lines) tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants