You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(review): keep exactly one review comment under concurrent runs (#98)
* fix(review): keep exactly one review comment under concurrent runs
postReviewComment listed comments, looked for its own, then created one if
absent — a check-then-act with nothing making it atomic. Concurrent runs all
observed "no comment yet" and each created one. Concurrency here is routine,
not exceptional: one sync fires `opened` plus a `labeled` event per label, so
lecture-python-programming.fr#6 got five runs in four seconds, two surviving
comments, and scores that matched no single review (each had been overwritten
by a different run than the one that created it).
Issue comments have no conditional-write primitive, so the fix reconciles
instead of locking. Every comment carries a hidden marker
(`<!-- action-translation-review -->`); after writing, a run deletes every
marked comment with a lower id. Ids increase with creation time and each run
lists after it writes, so the run holding the highest id always sees and
removes the rest — one comment survives any interleaving. Note this is the
mirror of the rule sketched in #96: deleting *newer* ids leaves duplicates
whenever the winner lists before a slower run creates.
Matching is anchored at the start of the body. The old prose predicate matched
"Translation Quality Review" and "action-translation" anywhere in a comment, so
it could adopt — and now would delete — a human comment quoting a review.
Pre-marker comments still match by their generated heading, so the duplicates
already on .fr#6 self-heal on its next review.
Converging the comment does not converge the spend: each racing run still pays
for a full review. That is workflow-side, and the trigger list #96 blames on the
target repo is shipped by our own docs — connect-existing.md, which .fa also
follows. All four review templates gain a per-PR `concurrency` group; the one
triggering on `labeled` now ignores labels other than `action-translation`
(`labeled` itself is load-bearing — labels land after the PR opens); and all
declare `permissions` explicitly, since removing a duplicate needs
`pull-requests: write`.
Tests drive concurrent reviewers against a shared fake comments API; the
natural await interleaving reproduces the race. Verified they fail against the
pre-fix implementation (5 comments for 5 runs).
Refs #96
Workflow-side fix in QuantEcon/lecture-python-programming.fr#7
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(dev): track PR #98 in STATE; note the #96 sighting against #92
Leaves `verified:` at 2026-07-15 and the Health line describing main as-is —
this only records the in-flight PR and the #92-family lead #96 turned up, it is
not a full re-verification of the document.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+6-1Lines changed: 6 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,7 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
8
8
## [Unreleased]
9
9
10
-
## [0.16.1] - 2026-07-15
10
+
### Fixed
11
+
-**Concurrent review runs no longer post duplicate review comments**: `postReviewComment` listed comments, looked for its own, then created one if absent — a check-then-act with nothing making it atomic, so every concurrent run saw "no comment yet" and created one. Observed on `lecture-python-programming.fr#6`, which carried two "Translation Quality Review" comments a second apart, each subsequently overwritten by a *different* run, leaving scores that matched no single review. Review comments now carry a hidden `<!-- action-translation-review -->` marker, and each run deletes any older marked comment after writing its own. Because ids increase with creation time and every run lists after it writes, the run holding the highest id always sees and removes the rest: exactly one comment survives any interleaving. Pre-existing duplicates (from v0.16.1 and earlier, which have no marker) are cleaned up on the next review of that PR.
12
+
13
+
### Changed
14
+
-**Review comments are identified by marker, not prose**: the old predicate matched any comment containing both "Translation Quality Review" and "action-translation" anywhere in its body — it could match, and overwrite, a human comment quoting a review. Matching is now anchored at the start of the body, so quoted or reposted reviews are never touched.
15
+
-**Review workflow templates gained a `concurrency` group** (docs): the action-side fix converges the *comment*, but each racing run still pays for a full review. A per-PR `concurrency` group with `cancel-in-progress` collapses the `opened` and `labeled` events a single sync produces into one review. The `connect-existing` template additionally ignores `labeled` events for labels other than `action-translation` — it triggers on `labeled` (necessary, since labels are applied after the PR is opened), and a sync applying two labels was starting a full review per label. Templates now also declare `permissions` explicitly (`pull-requests: write`, required to remove duplicate comments). Existing target repos should copy these guards; without them a sync bills several reviews of the same diff.
11
16
12
17
### Fixed
13
18
-**French typography no longer corrupts footnote/link-reference definitions**: the NBSP pass rewrote `[^id]: text` as `[^id] : text`, which stops the line parsing as a definition — it rendered as literal text and broke every reference (shipped in the fr seed, e.g. `pandas.md`). Definition labels are now masked, and the exact corruption is repaired on contact, so running `scripts/typography/apply.mjs` over an affected repo heals it. The definition text after the colon is still typeset.
0 commit comments