Skip to content

bot: trim each recycled tag in the file the PR tagged it in - #96

Merged
Deicyde merged 3 commits into
mainfrom
claude/split-trim-file
Oct 19, 2026
Merged

Deicyde merged 3 commits into
mainfrom
claude/split-trim-file

Conversation

@Deicyde

@Deicyde Deicyde commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner

Fixes #86.

What changed

  • bot/split.py: --recycle takes QID=FILE pairs. plan() looks for each QID only in its file (the path settle.classify records from the PR diff) and only as a whole word. Before, it ran a substring grep over the whole checkout, upstream files included, and took the first file listed.
  • With --apply, the trim plans once against the fetched branch tip and prints that plan. Before, it printed a preview planned against whatever was checked out (master, in the poller's clone) and never printed the plan it applied.
  • It exits non-zero without pushing when a QID isn't in its file, or when a QID is still there after the edit (the files are restored first). poll.py already runs the split with check=True, so the tick goes red instead of re-settling and re-triaging the same tags every tick.
  • bot/poll.py and bot/daily_bot.py pass the pairs.

Tests

  • New bot/test_split.py, added to scripts/ci-python.sh. It runs split.py --apply --no-build against a local bare repo shaped like the poller's clone (on master, with an upstream remote), where master carries Q12 in another file and Q123 in a third:
    • two tags trimmed from the PR's file, the unused import dropped, the other files untouched;
    • a QID that isn't in its file (Q12 where only Q123 is, an untagged QID, a missing file) fails and the branch doesn't move;
    • a second copy left after the edit fails, the branch doesn't move, and the checkout is clean;
    • bare QIDs are refused.
  • bot/test_poll.py: do_settle passes Q3=Mathlib/Order/Basic.lean to split.py.
  • Mutants caught: whole-checkout grep, no missing-QID exit, no post-edit check, no restore.
  • Locally: test_split 4/4, test_poll 43/43, test_settle_gate 11/11, scripts/check_ci_python_tests.py OK.

Notes

  • Release-neutral (bot/ and scripts/ci-python.sh only). Merges cleanly with main at 905c6def.
  • Manual split.py runs need the QID=FILE form; the docstring shows it.
  • If GitHub still served the pre-trim diff to the next tick's re-settle, that tick would fail once and the one after would pass. Before, it silently re-ran triage.

split.py located each recycled QID with a substring grep over the whole
checkout, which includes upstream files, and took the first file listed.
A longer QID (Q123 for Q12) or an upstream copy of the tag could win, the
real tag stayed on the PR, and the poller re-settled and re-triaged it on
every tick while the header counted it as removed.

settle.classify already records each tag's file from the PR diff. poll.py
and daily_bot.py now pass QID=FILE pairs, and split.py looks only there,
matching whole words. On --apply it plans against the fetched tip only,
refuses when a tag isn't in its file, and refuses (restoring the files)
when a tag is still present after the edit, so the tick goes red instead
of looping.

Fixes #86.
…plit-trim-file

# Conflicts:
#	scripts/ci-python.sh
From the review of this PR:
- bot/README.md lists the two new red-tick messages and how to tell a
  stale diff (dispatch again) from a moved or doubly tagged file.
- A test pins settle.classify's per-tag file to the repo-relative path
  split.py joins onto the checkout (it fails if the b/ prefix survives).
- split.py's docstring said --apply amends and force-pushes; it commits
  and pushes fast-forward on the fetched tip.
@Deicyde
Deicyde merged commit e2eaef7 into main Oct 19, 2026
4 checks passed
@Deicyde

Deicyde commented Oct 19, 2026

Copy link
Copy Markdown
Owner Author

Merged (e2eaef7c). An independent review found the plumbing correct. settle.classify's per-tag file is the repo-relative path split.py joins onto the checkout, poll.do_settle and daily_bot.py are its only callers, and the conflict rebuild never runs split.py. Every bot/test_split.py case fails on the old code. Its fixes went in before the merge: a runbook entry under "A poller run is red" for the two new refusals, a test pinning classify's file paths (it fails if the b/ prefix survives), and a corrected docstring. One known narrow case: if upstream moves a tagged file without leaving a stub, every tick refuses until someone merges master into the fork branch. The runbook says how to clear it.

Posted by the WikiLean PR swarm (lead).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bot: split.py can leave a recycled tag on the batch PR while the header counts it as removed

1 participant