Skip to content

feat(action): opt-in completeness-gated checkpoint ranges (#476) - #26

Open
chethanuk wants to merge 3 commits into
mainfrom
feat/issue-476-checkpoint-range
Open

feat(action): opt-in completeness-gated checkpoint ranges (#476)#26
chethanuk wants to merge 3 commits into
mainfrom
feat/issue-476-checkpoint-range

Conversation

@chethanuk

@chethanuk chethanuk commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Description

Incremental mode reduces duplicate publication, not review scope. On every PR update the Action recomputes merge-base-to-head and invokes OCR over that whole range (action.yml:239-245, :279), so later pushes on a long-lived PR keep paying for work already reviewed.

The measured case from alibaba#476: a push that changed 7 files / 323 lines was reviewed as 63 files / 15,700 lines — 48.6× larger by changed line count, 46:31 elapsed, 3.98M tokens.

This adds an opt-in checkpoint_range mode.

run N   full review of <merge-base>..<head-N>
        everything selected was reviewed, and published
        └─► <!-- ocr-checkpoint:v1 base64 --> appended to the sticky summary

run N+1 read marker → author-verify → ancestry-check → 12-reason gate
        ├─ all pass  → --from <head-N>     --to <head-N+1>   mode=checkpoint
        └─ any doubt → --from <merge-base> --to <head-N+1>   mode=full, reason=…

Default behaviour is unchanged. The review step expands ${RANGE_FROM:-$MERGE_BASE}, so with the input off the argv is byte-identical to before — verified by executing the expansion out of the edited file with RANGE_FROM unset and empty, not by reading the diff.

The gate is fail-closed and ordered. Thirteen distinct reasons, every one of which selects a full review and reports which one fired. Absent, corrupt, partial, failed, canceled, incompatible config, unreadable rules, non-ancestor, different base, wrong PR, wrong repo — all fall back to full. A wasted full review is cheap; a coverage gap is a correctness bug.

The checkpoint advances only on a run that is both complete and published. terminal_state === "complete" and stats.failed === 0 and stats.summaryUrl !== "" and a 40-hex head. Two publication signals are needed because stats.failed counts only failed inline posts, while findings routed to the summary are published solely in the finalizeSummary body. A run that cannot advance re-emits the previous marker byte-for-byte rather than erasing it, so one bad run does not reset the ratchet.

Two properties carry the safety argument:

  • ocr review --from A --to B reviews merge-base(A,B)..B. When A is a verified ancestor of B the reviewed set is exactly A..B, and it strictly contains B'..B for any B' between A and B — so a stale, older checkpoint can only widen the next range, never open a gap. This is why the canceled-run case from Add completeness-gated cross-push range checkpoints to the reusable GitHub Action alibaba/open-code-review#476 is safe: the surviving run covers last-complete-head through latest-head.
  • git merge-base --is-ancestor exits 128 when the object is not in the local store. That is treated as non-ancestor, never as ancestor, so an unknown checkpoint head falls back to full.

Checkpoint reads are author-verified before the payload is parsed, because findSummaryIssueComment matches on the marker substring alone and would otherwise trust a sticky comment posted by someone else.

Scope

In: issue behaviors 3 (fallback), 4 and 5 (never advance on incomplete/canceled), 8 (machine-readable mode, reason, and exact from/to SHAs), plus the manual full_review override (7).

Custom rules are fingerprinted by content, not just by path, so editing a rule file invalidates the checkpoint instead of narrowing the next range under rules the earlier commits were never reviewed against. An unreadable rule path forces a full review.

Deferred: behavior 6 (same-head rerun as an observable no-op) and the model-identity axis in 2 beyond the config fingerprint. Additive on top of this gate and easier to review separately.

No Go changes, and no second manifest format — this consumes the terminal_state vocabulary that landed in alibaba#520.

Limitations

  • terminal_state === "complete" is computed by computeTerminal (internal/session/manifest.go:941) from len(cov.Failed) == 0 over the selected set only. Waived items, and anything excluded before RegisterSelected, are inside "complete". The gate documents this where it reads the field rather than overclaiming that complete means every change was reviewed.
  • The author check authenticates the comment's author, not its integrity. Anyone with repo write/maintain permission can edit another account's comment body while the author field is unchanged. Fork PRs cannot do this, so fork-safety is retained, but the trust boundary is "write-permission holders are trusted" and is documented as such.
  • This repo's own .github/workflows/ocr-review.yml triggers on pull_request_target: types: [opened], so it never emits a synchronize event and cannot exercise this mode. It is exercised by consumers that review on update, which is where Add completeness-gated cross-push range checkpoints to the reusable GitHub Action alibaba/open-code-review#476's evidence comes from.

Type of Change

  • New feature (non-breaking change that adds functionality)

How Has This Been Tested?

  • make test passes locally
  • Manual testing (describe below)

npm run test:github-actions exits 0 and prints both suites' pass lines; make test and make check are unaffected (no Go changes). All 86 pre-existing post-review-comments.test.js cases are unmodified and green, with new cases added alongside them covering the write/read round trip, each gate reason, the byte-for-byte carry, and the base64 payload boundary.

Verification for the JS suite rests on test:github-actions in package.json:17 — worth noting that no workflow under .github/workflows currently runs it.

Checklist

  • My code follows the project's coding style (go fmt, go vet)
  • I have performed a self-review of my code
  • I have added tests that prove my fix is effective or my feature works
  • New and existing unit tests pass locally with my changes
  • I have updated the documentation accordingly (if applicable)
  • I have signed the CLA

Related Issues

closes alibaba#476

On every PR update the Action re-invokes OCR over the full
merge-base-to-head range, so later pushes on a long-lived PR get
progressively more expensive even when the newest change is small.

Adds an opt-in `checkpoint_range` mode. A run that reviewed everything
it selected records the head it covered in a `<!-- ocr-checkpoint:v1 -->`
marker inside its sticky summary comment; the next run reviews only
<checkpoint>..<head>. Default behaviour is unchanged: the review step
expands ${RANGE_FROM:-$MERGE_BASE}, so with the input off the argv is
byte-identical to before.

The gate is fail-closed and ordered — twelve distinct reasons, every one
of which selects a full review and reports why. The checkpoint advances
only when terminal_state is complete, no inline post failed, the summary
was actually published, and the head is 40-hex; a canceled, failed,
partial or ambiguously published run never advances it, and a run that
cannot advance re-emits the previous marker byte-for-byte rather than
erasing it.

Two properties carry the safety argument. `ocr review --from A --to B`
reviews merge-base(A,B)..B, so a stale older checkpoint can only widen
the next range, never open a coverage gap. And `git merge-base
--is-ancestor` exit 128 (object not in the local store) is treated as
non-ancestor, so an unknown checkpoint head falls back to full rather
than being trusted.

Checkpoint reads are author-verified before the payload is parsed,
because findSummaryIssueComment matches on the marker substring alone
and would otherwise trust a sticky comment posted by a third party.
@codeant-ai

codeant-ai Bot commented Aug 8, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR dd13584 Aug 08, 2026 · 07:15 07:20

@codeant-ai

codeant-ai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The action adds checkpoint-based incremental review ranges. It validates checkpoint metadata, configuration fingerprints, authorship, and commit ancestry before narrowing OCR input. It persists or carries checkpoint markers through sticky summaries and exposes range and checkpoint outputs.

Changes

Checkpoint-based incremental reviews

Layer / File(s) Summary
Range selection and action wiring
action.yml, examples/github_actions/README.md
The action adds checkpoint_range and full_review, computes the resolved OCR version and configuration fingerprint, selects the review range, exposes range outputs, and passes checkpoint state to posting. The documentation describes fallback and checkpoint behavior.
Checkpoint validation and resolution
scripts/github-actions/post-review-comments.js, scripts/github-actions/post-review-comments.test.js
Checkpoint helpers encode and validate markers, authenticate summary comments, verify configuration and ancestry, and return full-review results when validation fails. Tests cover read-path validation and fallback cases.
Checkpoint persistence and advancement
scripts/github-actions/post-review-comments.js, scripts/github-actions/post-review-comments.test.js
Sticky summaries advance checkpoints only for eligible complete runs, carry prior checkpoints when required, and expose checkpoint_after. Tests cover advancement, carry-forward, opt-out, and read/write behavior.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHubAction
  participant resolveCheckpointRange
  participant OCR
  participant runPostReviewComments
  participant StickySummary
  GitHubAction->>resolveCheckpointRange: resolve review range and checkpoint state
  resolveCheckpointRange->>StickySummary: read and validate checkpoint marker
  resolveCheckpointRange-->>GitHubAction: return selected range
  GitHubAction->>OCR: review selected range
  OCR-->>GitHubAction: return review results
  GitHubAction->>runPostReviewComments: publish results and checkpoint metadata
  runPostReviewComments->>StickySummary: advance or carry checkpoint marker
  runPostReviewComments-->>GitHubAction: return checkpoint_after
Loading

Suggested reviewers: stay-foolish-forever, lizhengfeng101, nitishagar

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the new opt-in checkpoint range feature and its completeness gate.
Description check ✅ Passed The description follows the template and provides scope, behavior, testing details, checklist status, documentation, limitations, and a related issue.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codeant-ai codeant-ai Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label Aug 8, 2026
@codeant-ai

codeant-ai Bot commented Aug 8, 2026

Copy link
Copy Markdown

User description

Description

Incremental mode reduces duplicate publication, not review scope. On every PR update the Action recomputes merge-base-to-head and invokes OCR over that whole range (action.yml:239-245, :279), so later pushes on a long-lived PR keep paying for work already reviewed.

The measured case from alibaba#476: a push that changed 7 files / 323 lines was reviewed as 63 files / 15,700 lines — 48.6× larger by changed line count, 46:31 elapsed, 3.98M tokens.

This adds an opt-in checkpoint_range mode.

run N   full review of <merge-base>..<head-N>
        everything selected was reviewed, and published
        └─► <!-- ocr-checkpoint:v1 base64 --> appended to the sticky summary

run N+1 read marker → author-verify → ancestry-check → 12-reason gate
        ├─ all pass  → --from <head-N>     --to <head-N+1>   mode=checkpoint
        └─ any doubt → --from <merge-base> --to <head-N+1>   mode=full, reason=…

Default behaviour is unchanged. The review step expands ${RANGE_FROM:-$MERGE_BASE}, so with the input off the argv is byte-identical to before — verified by executing the expansion out of the edited file with RANGE_FROM unset and empty, not by reading the diff.

The gate is fail-closed and ordered. Twelve distinct reasons, every one of which selects a full review and reports which one fired. Absent, corrupt, partial, failed, canceled, incompatible config, non-ancestor, different base, wrong PR, wrong repo — all fall back to full. A wasted full review is cheap; a coverage gap is a correctness bug.

The checkpoint advances only on a run that is both complete and published. terminal_state === "complete" and stats.failed === 0 and stats.summaryUrl !== "" and a 40-hex head. Two publication signals are needed because stats.failed counts only failed inline posts, while findings routed to the summary are published solely in the finalizeSummary body. A run that cannot advance re-emits the previous marker byte-for-byte rather than erasing it, so one bad run does not reset the ratchet.

Two properties carry the safety argument:

  • ocr review --from A --to B reviews merge-base(A,B)..B. When A is a verified ancestor of B the reviewed set is exactly A..B, and it strictly contains B'..B for any B' between A and B — so a stale, older checkpoint can only widen the next range, never open a gap. This is why the canceled-run case from Add completeness-gated cross-push range checkpoints to the reusable GitHub Action alibaba/open-code-review#476 is safe: the surviving run covers last-complete-head through latest-head.
  • git merge-base --is-ancestor exits 128 when the object is not in the local store. That is treated as non-ancestor, never as ancestor, so an unknown checkpoint head falls back to full.

Checkpoint reads are author-verified before the payload is parsed, because findSummaryIssueComment matches on the marker substring alone and would otherwise trust a sticky comment posted by someone else.

Scope

In: issue behaviors 3 (fallback), 4 and 5 (never advance on incomplete/canceled), 8 (machine-readable mode, reason, and exact from/to SHAs), plus the manual full_review override (7).

Deferred: behavior 6 (same-head rerun as an observable no-op) and the richer compatibility axes in 2 (model identity, rules) beyond the config fingerprint. They are additive on top of this gate and are easier to review separately.

No Go changes, and no second manifest format — this consumes the terminal_state vocabulary that landed in alibaba#520.

Limitations

  • terminal_state === "complete" is computed by computeTerminal (internal/session/manifest.go:941) from len(cov.Failed) == 0 over the selected set only. Waived items, and anything excluded before RegisterSelected, are inside "complete". The gate documents this where it reads the field rather than overclaiming that complete means every change was reviewed.
  • The author check authenticates the comment's author, not its integrity. Anyone with repo write/maintain permission can edit another account's comment body while the author field is unchanged. Fork PRs cannot do this, so fork-safety is retained, but the trust boundary is "write-permission holders are trusted" and is documented as such.
  • This repo's own .github/workflows/ocr-review.yml triggers on pull_request_target: types: [opened], so it never emits a synchronize event and cannot exercise this mode. It is exercised by consumers that review on update, which is where Add completeness-gated cross-push range checkpoints to the reusable GitHub Action alibaba/open-code-review#476's evidence comes from.

Type of Change

  • New feature (non-breaking change that adds functionality)

How Has This Been Tested?

  • make test passes locally
  • Manual testing (describe below)

npm run test:github-actions exits 0 and prints both suites' pass lines; make test and make check are unaffected (no Go changes). All 86 pre-existing post-review-comments.test.js cases are unmodified and green, with new cases added alongside them covering the write/read round trip, each gate reason, the byte-for-byte carry, and the base64 payload boundary.

Verification for the JS suite rests on test:github-actions in package.json:17 — worth noting that no workflow under .github/workflows currently runs it.

Checklist

  • My code follows the project's coding style (go fmt, go vet)
  • I have performed a self-review of my code
  • I have added tests that prove my fix is effective or my feature works
  • New and existing unit tests pass locally with my changes
  • I have updated the documentation accordingly (if applicable)
  • I have signed the CLA

Related Issues

closes alibaba#476


CodeAnt-AI Description

Review only new changes between pushes with fail-safe checkpoints

What Changed

  • Adds opt-in checkpoint_range support so later runs review only changes since the last successfully published, complete review.
  • Falls back to the full merge-base range whenever the checkpoint is missing, invalid, outdated, untrusted, incomplete, or cannot be verified.
  • Adds full_review to force a one-time full review while still recording a new checkpoint.
  • Records checkpoint status and the selected range through range_mode, range_summary, and checkpoint_after outputs.
  • Documents setup, fallback reasons, safety limits, and checkpoint behavior.

Impact

✅ Fewer repeated reviews on long-lived pull requests
✅ Full-range fallback when review coverage is uncertain
✅ Clearer range and checkpoint status

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

if (p.base_ref !== baseRef || p.merge_base !== mergeBase) return full("base_changed", seen);
// Model/prompt/rules/version changed: earlier findings are not comparable.
if (p.fingerprint !== fingerprint) return full("config_changed", seen);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The checkpoint gate trusts the caller-supplied fingerprint, but the action fingerprints the rule input path rather than the contents of the rule file. Changing a custom rule file, or a repository/project rule file used when rule is empty, therefore leaves the fingerprint unchanged and allows the next run to review only the new commit range under different effective rules. Include the effective rule-content hash in the fingerprint or reject the checkpoint when it cannot be verified. [api mismatch]

Severity Level: Major ⚠️
- ❌ Changed custom rules do not invalidate prior checkpoints.
- ❌ Previously reviewed code can be skipped under new project rules.
- ⚠️ Review results become inconsistent across PR pushes.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** scripts/github-actions/post-review-comments.js
**Line:** 2344:2344
**Comment:**
	*Api Mismatch: The checkpoint gate trusts the caller-supplied `fingerprint`, but the action fingerprints the `rule` input path rather than the contents of the rule file. Changing a custom rule file, or a repository/project rule file used when `rule` is empty, therefore leaves the fingerprint unchanged and allows the next run to review only the new commit range under different effective rules. Include the effective rule-content hash in the fingerprint or reject the checkpoint when it cannot be verified.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

CodeAnt flagged that the checkpoint fingerprint interpolated the `rule`
input's path string. rules.NewResolver reads that JSON file off the
workspace at review time, so editing it left the fingerprint unchanged
and let the next run narrow its range under rules the earlier commits
were never reviewed against.

Hash the file's contents into the fingerprint. An unreadable path forces
a full review (reason `rule_unreadable`) rather than trusting a stored
fingerprint that cannot be shown to mean the same rules. The built-in
rule set is embedded in the binary and already moves with the OCR
version, so only the custom-rule path needed covering.
@chethanuk

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chethanuk

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
scripts/github-actions/post-review-comments.js (2)

2250-2258: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

The isBotComment call is redundant here.

The second clause requires an exact match against botLogin. That condition already implies isBotComment(comment, botLogin), because isBotComment returns true whenever comment.user.login === botLogin. The first clause therefore never changes the result. Keeping both invites a later edit that removes the strict clause and leaves only the loose name-shaped test.

♻️ Proposed simplification
-  // isBotComment is the coarse "is this ours" test used by the dedup paths; it
-  // also accepts any login ending in "github-actions[bot]". That is too loose
-  // here, so the identity must ALSO match exactly: when this run authenticates
-  // as a GitHub App, a marker left by the default GITHUB_TOKEN is a different
-  // writer and must not be trusted.
-  if (!isBotComment(comment, botLogin) || (comment.user && comment.user.login) !== botLogin) {
+  // Exact identity match only. isBotComment (the dedup paths' coarse test) also
+  // accepts any login ending in "github-actions[bot]", which is too loose here:
+  // when this run authenticates as a GitHub App, a marker left by the default
+  // GITHUB_TOKEN is a different writer and must not be trusted.
+  if (!comment.user || comment.user.login !== botLogin) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/github-actions/post-review-comments.js` around lines 2250 - 2258,
Remove the redundant isBotComment(comment, botLogin) check from the author
validation near the summary-comment checkpoint, and rely solely on the exact
comment.user.login === botLogin comparison while preserving the existing
author_unverified return behavior.

2160-2170: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Derive the marker prefix from CHECKPOINT_VERSION.

CHECKPOINT_VERSION is 1, but v1 is hardcoded twice more: in CHECKPOINT_MARKER_PATTERN (line 2164) and in the template at line 2169. A future bump of CHECKPOINT_VERSION alone emits a v1 marker whose payload says v: 2. Readers parse it, then reject it with unsupported version, which looks like corruption rather than a version change. Tie the three together so one edit is enough.

Note: the reader must keep matching older prefixes to recognize a stale marker, so a version bump also needs the pattern to accept v\d+ rather than only the current version.

♻️ Proposed refactor
 const CHECKPOINT_VERSION = 1;
+const CHECKPOINT_MARKER_PREFIX = `ocr-checkpoint:v${CHECKPOINT_VERSION}`;
 // Marker shape: an HTML comment (invisible in the rendered summary) carrying a
 // base64 JSON payload, so payload text can contain "-->" or newlines without
 // breaking out of the comment.
-const CHECKPOINT_MARKER_PATTERN = "<!-- ocr-checkpoint:v1 ([A-Za-z0-9+/]+={0,2}) -->";
+const CHECKPOINT_MARKER_PATTERN = `<!-- ${CHECKPOINT_MARKER_PREFIX} ([A-Za-z0-9+/]+={0,2}) -->`;
 const CHECKPOINT_SHA_RE = /^[0-9a-f]{40}$/;
 
 function buildCheckpointMarker(payload) {
   const encoded = Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
-  return `<!-- ocr-checkpoint:v1 ${encoded} -->`;
+  return `<!-- ${CHECKPOINT_MARKER_PREFIX} ${encoded} -->`;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/github-actions/post-review-comments.js` around lines 2160 - 2170,
Update CHECKPOINT_MARKER_PATTERN and buildCheckpointMarker so the marker prefix
is derived from CHECKPOINT_VERSION instead of hardcoding v1, while retaining a
reader pattern that accepts v followed by any numeric version (v\d+) to
recognize stale markers. Ensure a version bump keeps emitted markers and payload
versions synchronized.
examples/github_actions/README.md (1)

204-208: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Separate the three consecutive blockquotes.

markdownlint reports MD028 at lines 205 and 207. A blank line between two blockquotes is ambiguous, and some renderers join them into one quote. Insert a non-quote separator, or merge the three notes into one blockquote with > on the blank lines.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/github_actions/README.md` around lines 204 - 208, Separate the three
consecutive blockquote notes in the README to satisfy MD028: either add a
non-quote separator between the blocks or merge them into one continuous
blockquote with `>` on blank lines. Preserve all existing caveat content and
headings.

Source: Linters/SAST tools

scripts/github-actions/post-review-comments.test.js (1)

3735-3754: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Pin the "advance supersedes carry" invariant on the with-findings path too.

testCheckpointAdvancesOnZeroFindings asserts that an advancing run does not also re-emit CARRY, but only through the zero-findings early return at line 214. The main body path (line 418) is a separate call site of appendCheckpoint. If a body ever carried two markers, parseCheckpointMarker returns null for "two markers in one body", and the next run silently falls back to corrupt_checkpoint forever.

Add one case: findings present, terminal_state: complete, nothing failed, and checkpointCarry: CARRY. Assert the body contains exactly one ocr-checkpoint marker and that parseCheckpointMarker(body).head === CK_RESOLVED.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/github-actions/post-review-comments.test.js` around lines 3735 -
3754, Extend the checkpoint advancement tests with a findings-present case using
terminal_state complete, no failures, and checkpointCarry set to CARRY. In the
new test, verify the summary body contains exactly one ocr-checkpoint marker and
that parseCheckpointMarker(body).head equals CK_RESOLVED, covering the main
appendCheckpoint path alongside testCheckpointAdvancesOnZeroFindings.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@action.yml`:
- Around line 292-296: Update the VERSION_ACTUAL assignment in the OCR version
resolution block to handle an empty result explicitly: fall back to the
configured OCR version spec, or otherwise force checkpoint invalidation/full
review. Preserve the guarantee that a successfully changed resolved OCR version
changes the fingerprint, while avoiding an empty value being written to
GITHUB_ENV.
- Around line 324-413: Wrap the checkpoint-range setup and output logic in the
action script’s top-level try/catch, including helper loading,
readCheckpointComment, resolveCheckpointRange, and export/output calls. On any
unexpected error, log a warning and force the full-review fallback by exporting
an empty RANGE_FROM and setting checkpoint outputs consistently, so the
subsequent ocr review still runs.

In `@examples/github_actions/README.md`:
- Around line 198-202: Update the README text introducing the checkpoint
behavior to say “Three properties” instead of “Two properties,” and revise the
phrase “which failed to post nothing” in the Widen-only bullet to clearly state
that the run posted no findings. Preserve the surrounding behavior descriptions
and bullet structure.

---

Nitpick comments:
In `@examples/github_actions/README.md`:
- Around line 204-208: Separate the three consecutive blockquote notes in the
README to satisfy MD028: either add a non-quote separator between the blocks or
merge them into one continuous blockquote with `>` on blank lines. Preserve all
existing caveat content and headings.

In `@scripts/github-actions/post-review-comments.js`:
- Around line 2250-2258: Remove the redundant isBotComment(comment, botLogin)
check from the author validation near the summary-comment checkpoint, and rely
solely on the exact comment.user.login === botLogin comparison while preserving
the existing author_unverified return behavior.
- Around line 2160-2170: Update CHECKPOINT_MARKER_PATTERN and
buildCheckpointMarker so the marker prefix is derived from CHECKPOINT_VERSION
instead of hardcoding v1, while retaining a reader pattern that accepts v
followed by any numeric version (v\d+) to recognize stale markers. Ensure a
version bump keeps emitted markers and payload versions synchronized.

In `@scripts/github-actions/post-review-comments.test.js`:
- Around line 3735-3754: Extend the checkpoint advancement tests with a
findings-present case using terminal_state complete, no failures, and
checkpointCarry set to CARRY. In the new test, verify the summary body contains
exactly one ocr-checkpoint marker and that parseCheckpointMarker(body).head
equals CK_RESOLVED, covering the main appendCheckpoint path alongside
testCheckpointAdvancesOnZeroFindings.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 33c2b01d-c387-4eda-8875-317df18fd1ac

📥 Commits

Reviewing files that changed from the base of the PR and between f8f0851 and 0d3b893.

📒 Files selected for processing (4)
  • action.yml
  • examples/github_actions/README.md
  • scripts/github-actions/post-review-comments.js
  • scripts/github-actions/post-review-comments.test.js

Comment thread action.yml
Comment on lines +292 to +296
# Resolved version (not the spec, which is usually "latest"). It feeds
# the checkpoint fingerprint so an OCR upgrade invalidates checkpoints
# taken by the previous version.
VERSION_ACTUAL=$(ocr version 2>/dev/null | head -n 1 | tr -d '\r' || true)
echo "OCR_VERSION_ACTUAL=${VERSION_ACTUAL}" >> "$GITHUB_ENV"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Handle an empty resolved OCR version.

If ocr version writes to stderr only, or prints nothing, VERSION_ACTUAL becomes empty. The fingerprint then folds in '' for every run, so an OCR upgrade no longer invalidates a checkpoint. The documented guarantee "the resolved OCR version changed → config_changed" silently stops holding. Consider falling back to the version spec, or forcing a full review when the resolved version is empty.

🛡️ Proposed fallback
-        VERSION_ACTUAL=$(ocr version 2>/dev/null | head -n 1 | tr -d '\r' || true)
+        VERSION_ACTUAL=$(ocr version 2>/dev/null | head -n 1 | tr -d '\r' || true)
+        # Never fingerprint an empty version: it would make every OCR upgrade
+        # look identical. Fall back to the requested spec.
+        VERSION_ACTUAL="${VERSION_ACTUAL:-spec:${OCR_VERSION}}"
         echo "OCR_VERSION_ACTUAL=${VERSION_ACTUAL}" >> "$GITHUB_ENV"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Resolved version (not the spec, which is usually "latest"). It feeds
# the checkpoint fingerprint so an OCR upgrade invalidates checkpoints
# taken by the previous version.
VERSION_ACTUAL=$(ocr version 2>/dev/null | head -n 1 | tr -d '\r' || true)
echo "OCR_VERSION_ACTUAL=${VERSION_ACTUAL}" >> "$GITHUB_ENV"
# Resolved version (not the spec, which is usually "latest"). It feeds
# the checkpoint fingerprint so an OCR upgrade invalidates checkpoints
# taken by the previous version.
VERSION_ACTUAL=$(ocr version 2>/dev/null | head -n 1 | tr -d '\r' || true)
# Never fingerprint an empty version: it would make every OCR upgrade
# look identical. Fall back to the requested spec.
VERSION_ACTUAL="${VERSION_ACTUAL:-spec:${OCR_VERSION}}"
echo "OCR_VERSION_ACTUAL=${VERSION_ACTUAL}" >> "$GITHUB_ENV"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@action.yml` around lines 292 - 296, Update the VERSION_ACTUAL assignment in
the OCR version resolution block to handle an empty result explicitly: fall back
to the configured OCR version spec, or otherwise force checkpoint
invalidation/full review. Preserve the guarantee that a successfully changed
resolved OCR version changes the fingerprint, while avoiding an empty value
being written to GITHUB_ENV.

Comment thread action.yml
Comment on lines +324 to +413
script: |
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const { spawnSync } = require('child_process');
// Same helper lookup as the posting step below.
const REL = 'scripts/github-actions/post-review-comments.js';
const roots = [process.env.GITHUB_ACTION_PATH, process.env.GITHUB_WORKSPACE].filter(Boolean);
const helper = roots.map(r => path.resolve(r, REL)).find(p => fs.existsSync(p));
if (!helper) throw new Error(`Could not locate ${REL}; searched roots: ${roots.join(', ')}`);
const { resolveCheckpointRange, readCheckpointComment } = require(helper);

// `rule` names a JSON file that OCR reads off the workspace at review
// time (rules.NewResolver only touches disk when the path is non-empty;
// the default rule set is embedded in the binary and so already moves
// with OCR_VERSION_ACTUAL). Fingerprinting the *path* alone would let an
// edit to that file narrow the next range under rules the earlier
// commits were never reviewed against, so hash the contents too.
let ruleDigest = 'none';
let ruleUnverified = false;
const rulePath = process.env.OCR_RULE_PATH || '';
if (rulePath) {
try {
const abs = path.resolve(process.env.GITHUB_WORKSPACE || '.', rulePath);
ruleDigest = crypto.createHash('sha256').update(fs.readFileSync(abs)).digest('hex');
} catch (e) {
// Cannot prove the rules are unchanged -> do not narrow. OCR itself
// would normally have failed on an unreadable rule file before this
// step runs, so this is a belt-and-braces path.
ruleUnverified = true;
core.warning(`checkpoint: cannot read rule file ${rulePath} (${e.message}); forcing a full review.`);
}
}

const fingerprint = crypto.createHash('sha256')
.update(`${process.env.OCR_FINGERPRINT_INPUTS || ''}|${process.env.OCR_VERSION_ACTUAL || ''}|${ruleDigest}`)
.digest('hex')
.slice(0, 16);

// git's own ancestry verdict: 0 = ancestor, 1 = not, 128 = the object
// is not in this clone (shallow fetch, force-push, head_sha override).
// Anything else (git missing, signal) is a resolver error. Never
// treated as "ancestor" except on a literal 0.
const isAncestor = (a, b) =>
spawnSync('git', ['merge-base', '--is-ancestor', a, b], { cwd: process.env.GITHUB_WORKSPACE }).status;

const common = {
github,
owner: context.repo.owner,
repo: context.repo.repo,
prNumber: context.issue.number,
log: (m) => core.info(m),
};
// One read serves both purposes: the range decision, and the verbatim
// marker the posting step re-emits on a run that does not advance the
// checkpoint (the summary body is rewritten wholesale, which would
// otherwise erase it). Passing it into the resolver as `read` is what
// keeps this to a single listComments pagination per run.
const existing = await readCheckpointComment(common);
const range = await resolveCheckpointRange(Object.assign({}, common, {
read: existing,
enabled: true,
sticky: process.env.OCR_STICKY_SUMMARY === 'true',
fullReview: process.env.OCR_FULL_REVIEW === 'true',
headSha: process.env.HEAD_SHA || '',
baseRef: process.env.BASE_REF || '',
mergeBase: process.env.MERGE_BASE || '',
fingerprint,
isAncestor,
}));

// Last gate, applied after the ordered twelve: the rules this run will
// apply could not be read, so no stored fingerprint can be trusted to
// mean "same rules". Widening is always safe; narrowing is not.
if (ruleUnverified && range.mode === 'checkpoint') {
range.mode = 'full';
range.reason = 'rule_unreadable';
}

// Empty RANGE_FROM means "review the full range": the review step
// expands ${RANGE_FROM:-$MERGE_BASE}, so unset and empty behave alike.
core.exportVariable('RANGE_FROM', range.mode === 'checkpoint' ? range.from : '');
core.exportVariable('OCR_CONFIG_FINGERPRINT', fingerprint);
core.exportVariable('OCR_CHECKPOINT_CARRY', existing.raw || '');
const summary = range.mode === 'checkpoint'
? `checkpoint (${range.reason}): ${range.from}..${range.to}`
: `full (${range.reason})`;
core.setOutput('range_mode', range.mode);
core.setOutput('range_summary', summary);
core.info(`[checkpoint] reviewing ${summary}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Wrap the resolver in a try/catch so an unexpected error still reviews the full range.

The script has no top-level error handling. resolveCheckpointRange catches its own known failures, but any other throw here fails the whole step, and therefore the job, before ocr review runs. Examples: require(helper) fails, context.issue.number is undefined for a trigger without an issue payload, or core.exportVariable receives an unexpected value. Today, without checkpoint_range, none of these paths exist and the review always runs.

The documented contract is "when in doubt, review the full range". Catching here makes the step match that contract.

🛡️ Proposed fix
-          const existing = await readCheckpointComment(common);
-          const range = await resolveCheckpointRange(Object.assign({}, common, {
-            read: existing,
-            enabled: true,
-            sticky: process.env.OCR_STICKY_SUMMARY === 'true',
-            fullReview: process.env.OCR_FULL_REVIEW === 'true',
-            headSha: process.env.HEAD_SHA || '',
-            baseRef: process.env.BASE_REF || '',
-            mergeBase: process.env.MERGE_BASE || '',
-            fingerprint,
-            isAncestor,
-          }));
+          let existing = { reason: 'resolver_error', payload: null, raw: '' };
+          let range = { mode: 'full', reason: 'resolver_error', from: '', to: process.env.HEAD_SHA || '' };
+          try {
+            existing = await readCheckpointComment(common);
+            range = await resolveCheckpointRange(Object.assign({}, common, {
+              read: existing,
+              enabled: true,
+              sticky: process.env.OCR_STICKY_SUMMARY === 'true',
+              fullReview: process.env.OCR_FULL_REVIEW === 'true',
+              headSha: process.env.HEAD_SHA || '',
+              baseRef: process.env.BASE_REF || '',
+              mergeBase: process.env.MERGE_BASE || '',
+              fingerprint,
+              isAncestor,
+            }));
+          } catch (e) {
+            // Widening is always safe; a resolver crash must not stop the review.
+            core.warning(`checkpoint: range resolution failed (${e.message}); reviewing the full range.`);
+          }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
script: |
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const { spawnSync } = require('child_process');
// Same helper lookup as the posting step below.
const REL = 'scripts/github-actions/post-review-comments.js';
const roots = [process.env.GITHUB_ACTION_PATH, process.env.GITHUB_WORKSPACE].filter(Boolean);
const helper = roots.map(r => path.resolve(r, REL)).find(p => fs.existsSync(p));
if (!helper) throw new Error(`Could not locate ${REL}; searched roots: ${roots.join(', ')}`);
const { resolveCheckpointRange, readCheckpointComment } = require(helper);
// `rule` names a JSON file that OCR reads off the workspace at review
// time (rules.NewResolver only touches disk when the path is non-empty;
// the default rule set is embedded in the binary and so already moves
// with OCR_VERSION_ACTUAL). Fingerprinting the *path* alone would let an
// edit to that file narrow the next range under rules the earlier
// commits were never reviewed against, so hash the contents too.
let ruleDigest = 'none';
let ruleUnverified = false;
const rulePath = process.env.OCR_RULE_PATH || '';
if (rulePath) {
try {
const abs = path.resolve(process.env.GITHUB_WORKSPACE || '.', rulePath);
ruleDigest = crypto.createHash('sha256').update(fs.readFileSync(abs)).digest('hex');
} catch (e) {
// Cannot prove the rules are unchanged -> do not narrow. OCR itself
// would normally have failed on an unreadable rule file before this
// step runs, so this is a belt-and-braces path.
ruleUnverified = true;
core.warning(`checkpoint: cannot read rule file ${rulePath} (${e.message}); forcing a full review.`);
}
}
const fingerprint = crypto.createHash('sha256')
.update(`${process.env.OCR_FINGERPRINT_INPUTS || ''}|${process.env.OCR_VERSION_ACTUAL || ''}|${ruleDigest}`)
.digest('hex')
.slice(0, 16);
// git's own ancestry verdict: 0 = ancestor, 1 = not, 128 = the object
// is not in this clone (shallow fetch, force-push, head_sha override).
// Anything else (git missing, signal) is a resolver error. Never
// treated as "ancestor" except on a literal 0.
const isAncestor = (a, b) =>
spawnSync('git', ['merge-base', '--is-ancestor', a, b], { cwd: process.env.GITHUB_WORKSPACE }).status;
const common = {
github,
owner: context.repo.owner,
repo: context.repo.repo,
prNumber: context.issue.number,
log: (m) => core.info(m),
};
// One read serves both purposes: the range decision, and the verbatim
// marker the posting step re-emits on a run that does not advance the
// checkpoint (the summary body is rewritten wholesale, which would
// otherwise erase it). Passing it into the resolver as `read` is what
// keeps this to a single listComments pagination per run.
const existing = await readCheckpointComment(common);
const range = await resolveCheckpointRange(Object.assign({}, common, {
read: existing,
enabled: true,
sticky: process.env.OCR_STICKY_SUMMARY === 'true',
fullReview: process.env.OCR_FULL_REVIEW === 'true',
headSha: process.env.HEAD_SHA || '',
baseRef: process.env.BASE_REF || '',
mergeBase: process.env.MERGE_BASE || '',
fingerprint,
isAncestor,
}));
// Last gate, applied after the ordered twelve: the rules this run will
// apply could not be read, so no stored fingerprint can be trusted to
// mean "same rules". Widening is always safe; narrowing is not.
if (ruleUnverified && range.mode === 'checkpoint') {
range.mode = 'full';
range.reason = 'rule_unreadable';
}
// Empty RANGE_FROM means "review the full range": the review step
// expands ${RANGE_FROM:-$MERGE_BASE}, so unset and empty behave alike.
core.exportVariable('RANGE_FROM', range.mode === 'checkpoint' ? range.from : '');
core.exportVariable('OCR_CONFIG_FINGERPRINT', fingerprint);
core.exportVariable('OCR_CHECKPOINT_CARRY', existing.raw || '');
const summary = range.mode === 'checkpoint'
? `checkpoint (${range.reason}): ${range.from}..${range.to}`
: `full (${range.reason})`;
core.setOutput('range_mode', range.mode);
core.setOutput('range_summary', summary);
core.info(`[checkpoint] reviewing ${summary}`);
script: |
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const { spawnSync } = require('child_process');
// Same helper lookup as the posting step below.
const REL = 'scripts/github-actions/post-review-comments.js';
const roots = [process.env.GITHUB_ACTION_PATH, process.env.GITHUB_WORKSPACE].filter(Boolean);
const helper = roots.map(r => path.resolve(r, REL)).find(p => fs.existsSync(p));
if (!helper) throw new Error(`Could not locate ${REL}; searched roots: ${roots.join(', ')}`);
const { resolveCheckpointRange, readCheckpointComment } = require(helper);
// `rule` names a JSON file that OCR reads off the workspace at review
// time (rules.NewResolver only touches disk when the path is non-empty;
// the default rule set is embedded in the binary and so already moves
// with OCR_VERSION_ACTUAL). Fingerprinting the *path* alone would let an
// edit to that file narrow the next range under rules the earlier
// commits were never reviewed against, so hash the contents too.
let ruleDigest = 'none';
let ruleUnverified = false;
const rulePath = process.env.OCR_RULE_PATH || '';
if (rulePath) {
try {
const abs = path.resolve(process.env.GITHUB_WORKSPACE || '.', rulePath);
ruleDigest = crypto.createHash('sha256').update(fs.readFileSync(abs)).digest('hex');
} catch (e) {
// Cannot prove the rules are unchanged -> do not narrow. OCR itself
// would normally have failed on an unreadable rule file before this
// step runs, so this is a belt-and-braces path.
ruleUnverified = true;
core.warning(`checkpoint: cannot read rule file ${rulePath} (${e.message}); forcing a full review.`);
}
}
const fingerprint = crypto.createHash('sha256')
.update(`${process.env.OCR_FINGERPRINT_INPUTS || ''}|${process.env.OCR_VERSION_ACTUAL || ''}|${ruleDigest}`)
.digest('hex')
.slice(0, 16);
// git's own ancestry verdict: 0 = ancestor, 1 = not, 128 = the object
// is not in this clone (shallow fetch, force-push, head_sha override).
// Anything else (git missing, signal) is a resolver error. Never
// treated as "ancestor" except on a literal 0.
const isAncestor = (a, b) =>
spawnSync('git', ['merge-base', '--is-ancestor', a, b], { cwd: process.env.GITHUB_WORKSPACE }).status;
const common = {
github,
owner: context.repo.owner,
repo: context.repo.repo,
prNumber: context.issue.number,
log: (m) => core.info(m),
};
// One read serves both purposes: the range decision, and the verbatim
// marker the posting step re-emits on a run that does not advance the
// checkpoint (the summary body is rewritten wholesale, which would
// otherwise erase it). Passing it into the resolver as `read` is what
// keeps this to a single listComments pagination per run.
let existing = { reason: 'resolver_error', payload: null, raw: '' };
let range = { mode: 'full', reason: 'resolver_error', from: '', to: process.env.HEAD_SHA || '' };
try {
existing = await readCheckpointComment(common);
range = await resolveCheckpointRange(Object.assign({}, common, {
read: existing,
enabled: true,
sticky: process.env.OCR_STICKY_SUMMARY === 'true',
fullReview: process.env.OCR_FULL_REVIEW === 'true',
headSha: process.env.HEAD_SHA || '',
baseRef: process.env.BASE_REF || '',
mergeBase: process.env.MERGE_BASE || '',
fingerprint,
isAncestor,
}));
} catch (e) {
// Widening is always safe; a resolver crash must not stop the review.
core.warning(`checkpoint: range resolution failed (${e.message}); reviewing the full range.`);
}
// Last gate, applied after the ordered twelve: the rules this run will
// apply could not be read, so no stored fingerprint can be trusted to
// mean "same rules". Widening is always safe; narrowing is not.
if (ruleUnverified && range.mode === 'checkpoint') {
range.mode = 'full';
range.reason = 'rule_unreadable';
}
// Empty RANGE_FROM means "review the full range": the review step
// expands ${RANGE_FROM:-$MERGE_BASE}, so unset and empty behave alike.
core.exportVariable('RANGE_FROM', range.mode === 'checkpoint' ? range.from : '');
core.exportVariable('OCR_CONFIG_FINGERPRINT', fingerprint);
core.exportVariable('OCR_CHECKPOINT_CARRY', existing.raw || '');
const summary = range.mode === 'checkpoint'
? `checkpoint (${range.reason}): ${range.from}..${range.to}`
: `full (${range.reason})`;
core.setOutput('range_mode', range.mode);
core.setOutput('range_summary', summary);
core.info(`[checkpoint] reviewing ${summary}`);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@action.yml` around lines 324 - 413, Wrap the checkpoint-range setup and
output logic in the action script’s top-level try/catch, including helper
loading, readCheckpointComment, resolveCheckpointRange, and export/output calls.
On any unexpected error, log a warning and force the full-review fallback by
exporting an empty RANGE_FROM and setting checkpoint outputs consistently, so
the subsequent ocr review still runs.

Comment on lines +198 to +202
Two properties are worth knowing before you enable it:

- **Widen-only.** The start of the range only ever moves back. An older checkpoint produces a wider review, never a narrower one, and a checkpoint only advances past a run whose manifest reported `terminal_state: complete`, which failed to post nothing, and whose summary comment actually published. A run that fails halfway carries the previous checkpoint forward unchanged rather than skipping the range it did not review.
- **Same-head reruns are empty.** Re-running the workflow without pushing produces a `checkpoint` range with `from == to` — nothing new to review.
- **The sticky summary shows the latest range, not the whole PR.** The summary comment is rewritten on every run, so findings it reported for an earlier range (findings with no line information, routed findings, warnings) are replaced by the new range's. Inline review comments are separate comments and stay. If you rely on the summary as a running list for the whole PR, use `full_review: 'true'` to rebuild it, or leave `checkpoint_range` off.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the item count and the double negative.

Line 198 says "Two properties", but three bullets follow. Line 200 contains "which failed to post nothing", which reads as a double negative.

✏️ Proposed fix
-Two properties are worth knowing before you enable it:
+Three properties are worth knowing before you enable it:
 
-- **Widen-only.** The start of the range only ever moves back. An older checkpoint produces a wider review, never a narrower one, and a checkpoint only advances past a run whose manifest reported `terminal_state: complete`, which failed to post nothing, and whose summary comment actually published. A run that fails halfway carries the previous checkpoint forward unchanged rather than skipping the range it did not review.
+- **Widen-only.** The start of the range only ever moves back. An older checkpoint produces a wider review, never a narrower one. A checkpoint advances only past a run whose manifest reported `terminal_state: complete`, whose findings all posted, and whose summary comment actually published. A run that fails halfway carries the previous checkpoint forward unchanged rather than skipping the range it did not review.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Two properties are worth knowing before you enable it:
- **Widen-only.** The start of the range only ever moves back. An older checkpoint produces a wider review, never a narrower one, and a checkpoint only advances past a run whose manifest reported `terminal_state: complete`, which failed to post nothing, and whose summary comment actually published. A run that fails halfway carries the previous checkpoint forward unchanged rather than skipping the range it did not review.
- **Same-head reruns are empty.** Re-running the workflow without pushing produces a `checkpoint` range with `from == to` — nothing new to review.
- **The sticky summary shows the latest range, not the whole PR.** The summary comment is rewritten on every run, so findings it reported for an earlier range (findings with no line information, routed findings, warnings) are replaced by the new range's. Inline review comments are separate comments and stay. If you rely on the summary as a running list for the whole PR, use `full_review: 'true'` to rebuild it, or leave `checkpoint_range` off.
Three properties are worth knowing before you enable it:
- **Widen-only.** The start of the range only ever moves back. An older checkpoint produces a wider review, never a narrower one. A checkpoint advances only past a run whose manifest reported `terminal_state: complete`, whose findings all posted, and whose summary comment actually published. A run that fails halfway carries the previous checkpoint forward unchanged rather than skipping the range it did not review.
- **Same-head reruns are empty.** Re-running the workflow without pushing produces a `checkpoint` range with `from == to` — nothing new to review.
- **The sticky summary shows the latest range, not the whole PR.** The summary comment is rewritten on every run, so findings it reported for an earlier range (findings with no line information, routed findings, warnings) are replaced by the new range's. Inline review comments are separate comments and stay. If you rely on the summary as a running list for the whole PR, use `full_review: 'true'` to rebuild it, or leave `checkpoint_range` off.
🧰 Tools
🪛 LanguageTool

[grammar] ~200-~200: Ensure spelling is correct
Context: ..._state: complete`, which failed to post nothing, and whose summary comment actually pub...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/github_actions/README.md` around lines 198 - 202, Update the README
text introducing the checkpoint behavior to say “Three properties” instead of
“Two properties,” and revise the phrase “which failed to post nothing” in the
Widen-only bullet to clearly state that the run posted no findings. Preserve the
surrounding behavior descriptions and bullet structure.

Source: Linters/SAST tools

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

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add completeness-gated cross-push range checkpoints to the reusable GitHub Action

1 participant