[PR #263] [MERGED] feat(cursor-review): carry the 422 fallback's findings into the ledger #266

Closed
opened 2026-10-26 22:37:55 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/Comfy-Org/github-workflows/pull/263
Author: @mattmillerai
Created: 9/5/2026
Status: ✅ Merged
Merged: 9/8/2026
Merged by: @mattmillerai

Base: main ← Head: matt/be-10002-fallback-sentinel


📝 Commits (3)

  • a57f1e5 feat(cursor-review): carry the 422 fallback's findings into the ledger
  • fb3edb8 fix(cursor-review): keep a prose floor under the fallback's sentinel (BE-10002)
  • 02723c9 test(cursor-review): pin the clamp-note reserve, and file the budget tests correctly

📊 Changes

4 files changed (+792 additions, -77 deletions)

View changed files

📝 .github/cursor-review/build-ledger.py (+91 -29)
📝 .github/cursor-review/post-review.py (+177 -23)
📝 .github/cursor-review/tests/test_build_ledger.py (+133 -0)
📝 .github/cursor-review/tests/test_post_review.py (+391 -25)

📄 Description

ELI-5

When GitHub rejects a review's inline comments, cursor-review re-posts the whole round as plain prose. Until now that prose carried a "these findings lost their threads" sentence but not the little machine-readable copy the next round reads, so the next review knew findings had been lost and could not see a single one of them — including the findings that anchored perfectly well and only lost their thread to the failed request. This PR puts that machine-readable copy in the fallback body too, marks the findings that were lost to the failed POST (rather than to the diff), and tells the next round's panel and judge that the "prefer not to re-raise" rule for unanchorable findings does not apply to those.

The copy is a guest in that body, not its owner: it may take at most half the size budget, and if the round is too big for that it carries the most urgent findings that fit rather than all or none. The prose a human reads keeps the other half.

What changed

post-review.py

  • render_body_only_sentinel emits an optional per-item "lost_to_fallback": true, only for an item that carries it and only on a literal True (matching build-ledger.py's reader) — a success-path payload is byte-identical to before, and the key contains no -, so the existing - dash escape still makes the HTML comment unclosable.
  • The wholesale-fallback branch builds sentinel items from all of enriched: items that came from the inline half are tagged lost_to_fallback, items that were already unanchorable are not (the POST outcome told us nothing about them). They are tagged by object identity while iterating enriched, so the sentinel keeps the same most→least-urgent order as the prose under it.
  • The tag is gated on a real anchor check. load_anchors(args.diff) is kept in anchors rather than consumed inline. When it returns None — no --diff, an unreadable or empty patch — partition_by_anchor fails open and calls every finding inline without testing one, so nothing is tagged and every finding renders [unanchorable]. The flag claims the finding passed the diff-anchor check, and only a real check can make that claim.
  • The fallback body is composed head-first: review_head → the existing _(Inline comments could not be anchored…)_ note → the sentinel → the findings prose. That is the same order render_body_only_findings uses and for the same two reasons — build-ledger.py only accepts a sentinel whose marker line sits immediately above it, and clamp_review_body cuts the tail, so a clamp eats least-urgent prose rather than the JSON.
  • Size guard, in two parts. A prose floor: FALLBACK_SENTINEL_MAX_CHARS = MAX_REVIEW_BODY_CHARS // 2 caps what the sentinel may take, and the new fit_sentinel_items() binary-searches the longest most-urgent prefix that fits it, so a round too big for a whole sentinel recovers part of one instead of none of it. And a clamp reserve: clamp_review_body's truncation note is subtracted from the budget, not merely the limit tested, so the sentinel is never posted where the clamp would cut into it. render_findings_markdown's separator and that note are now module constants, so the guard measures the real strings.

build-ledger.py

  • _body_only_entries copies lost_to_fallback: True onto the entry, matched with is True (the payload is model-adjacent text arriving through a public review body, so a stray "no" must not read as the flag). Everything mechanical is unchanged: anchored False, zeroed thread, empty discussion_url, cap-exempt.
  • render_ledger_markdown renders [post-failed] instead of [unanchorable] for such an entry, with a note saying the finding matched a line in the reviewed diff and lost its thread to a delivery failure, so re-raising it needs no repeat_of.
  • Separate aggregate. unanchorable_count now excludes these entries and a new post_failed_count carries them, each with its own clause in the block header and in ledger_note — so the aggregate a model reads first can no longer say "N unanchorable, so never answerable at all" of a finding whose own entry line two rows below reports that it matched the diff. Both renders read the new key with .get(...) or 0, so a ledger written before this change is unaffected.
  • One steering bullet added to each of _PANEL_STEERING and _JUDGE_STEERING: [post-failed] behaves like [unanchorable] for repeat purposes (no thread, never a repeat_of target, costs no repeat slot) but, unlike it, passed the diff-anchor check — so the "prefer not to re-raise" preference does not apply to it.

No sentinel version bump — v1 gains an optional key an older parser ignores.

Two defects this PR's own review found, and fixed

The sentinel displaced the review a human reads. The first size guard only asked whether the sentinel fit ahead of finding one, which let it take the whole budget. Measured on this branch: a round of 89 findings of ~700 chars posted 58,720 characters of sentinel and rendered zero findings, while the same round at 90 findings — one over the all-or-nothing guard, so the sentinel was dropped whole — rendered 79. The cliff ran backwards, and the rounds with the most to report showed the least. With the prose floor and prefix search, every size from 60 to 130 findings now posts 39 findings visible and 45 recovered. Pinned by test_the_sentinel_never_displaces_the_findings_a_reader_can_see and test_the_sentinel_keeps_the_most_urgent_findings_when_it_cannot_keep_all; reverting the cap fails 5 subtests.

A ~122-character window in which the clamp cut into the JSON. clamp_review_body cuts at limit - len(note), so a head+sentinel that fits MAX_REVIEW_BODY_CHARS by less than the note's length was cut mid-payload, drop_unterminated_comment then removed the sentinel back to its opener, and it took every finding after it. Measured on a 90-finding round: the posted review collapsed from 60,000 characters of findings to a 494-character header. The budget therefore reserves the clamp note. Because the prose floor now wins the min() on ordinary rounds, that reserve is pinned on the input where the other term wins — a panel summary large enough to make the head most of the body — and the assertion is about the prose, which is what the reserve actually saves: both settings end with no readable sentinel inside the window, but only the unreserved one also throws the findings away. Removing the reserve fails 3 of the 6 swept subtests.

Tests

  • Flipped test_the_fallback_round_degrades_loudly_in_the_next_round_s_ledger → …carries_its_findings_into_the_next_round_s_ledger: the 422 path now posts a sentinel, and the posted body is round-tripped through the real build_ledger, yielding two entries — the anchorable one lost_to_fallback and rendered [post-failed], the off-diff one plain [unanchorable].
  • New on the budget: the prose floor across four round sizes; the most-urgent-prefix property; the clamp-note reserve swept across its window; the floor where nothing fits (a single pathological path — bodies are capped at 600 chars but path is length-checked nowhere — so the marker is posted alone and the ledger discloses it); and FitSentinelItemsTest, a unit class for the search itself (prefix-ness, longest-prefix exactness, empty budget, empty input).
  • New: test_no_finding_is_called_post_failed_when_the_anchors_were_never_checked — with no --diff, nothing is tagged and both entries stay [unanchorable].
  • New ledger-side: TestLostToFallbackEntries (round-trip through the real writer, the [post-failed] render and its note, steering present for both audiences, forward-compat, and that only a real true sets the flag), plus test_the_two_thread_less_totals_are_reported_separately and test_a_round_with_no_post_failed_entry_reads_exactly_as_before for the split aggregate.
  • Assertions corrected: test_the_sentinel_is_never_posted_where_the_clamp_would_cut_it measured len(body), which counts the sentinel's HTML comment and so stayed large on precisely the body that rendered zero findings; it now counts rendered entries on the body with the comment line stripped, via a new module-level visible() helper that test_no_finding_is_rendered_twice_in_the_fallback also uses.
  • EndToEndPostTest.run_main gains an optional panel= argument (defaulting to today's fixture) so a test can control the one finding-independent part of the review head.
  • Kept green unchanged: test_a_422_still_degrades_wholesale_and_keeps_every_finding and the success-path sentinel tests. test_the_clamp_cuts_the_least_urgent_finding_in_the_fallback shrinks its four finding bodies from 19,000 to 18,000 characters because the sentinel now shares the budget; the property it pins — the cut landing on the least urgent — is unchanged, and it now also asserts the cut finding is still recoverable from the sentinel.

Scope swept

post-review.py posts four kinds of review body. The two that carry findings — the success path and this wholesale fallback — now both emit a sentinel. The other two carry no findings to encode (the "no high-signal findings" review, and the error review, which deliberately defangs both halves of the contract out of imported text). The three paths that deliver only to the job summary when findings exist (read-only token, no inline half to drop, both POSTs failed) still contribute nothing to the ledger, because no review reaches the PR at all on them.

Sentinel cost, for sizing: up to ~660 characters per finding (the 600-character body cap plus the path/line/severity keys). At that size the half-budget floor starts trimming the sentinel to a prefix at ~45 findings.

Residual

  • Both POSTs failing is still ledger-invisible — named as out of scope by the driving ticket and unchanged here. When the inline POST and the fallback POST both fail, no review body reaches the PR, so there is nothing for the next round's ledger to read; the run goes red and the full text goes to the job summary. The two sibling no-post degradations (a read-only token, and a failure with no inline half to drop) are invisible to the ledger for the same reason.
  • A nonzero gh result is not proof the review was not committed server-side. If the first POST did land, its findings have real threads and land in this sentinel, so the next ledger carries each twice: once with its thread and the author's reply, once as a cap-exempt [post-failed] entry asserting nobody could have answered it. Documented in-code where the tag is set. Confirming absence needs a read of the PR's reviews this script does not do, and a decision about what to do when that read fails — filed as a follow-up.
  • A [post-failed] entry carries no repeat lineage. The sentinel strips the rendered repeat_of line and carries the URL in no field, so a re-raise of a finding answered in a round that has since aged past MAX_ROUNDS costs no repeat slot. This predates the PR — it is true of every [unanchorable] entry since BE-9565 — and the steering that amplified it ("re-raise it freely") has been softened to "re-raise it if it still holds", with a test asserting freely appears in neither audience's steering. The lineage fix is filed as a follow-up.
  • The success path's sentinel still has no size guard. The mid-JSON clamp window this PR closes on the fallback path is open on the success path, where the demoted-findings section is the body's tail; with ~90+ demoted findings the cut lands in its JSON and drop_unterminated_comment takes the demoted prose with it. Not fixed here because it changes render_body_only_findings' signature and alters the path every review takes; fit_sentinel_items is now available for it. Filed as a follow-up.
  • A partial sentinel is silent about being partial. When the prose floor trims the sentinel to a prefix, the findings left out are simply absent from the next ledger — the same way all of them were absent when the whole sentinel was dropped, so this adds no new false claim, but the ledger cannot distinguish "trimmed" from "not found".
  • No live 422 was reproduced. Everything here is exercised through the repo's stubbed-gh harness (post_returncode=1, stderr="HTTP 422") and the real build_ledger parser, which is what the driving ticket names; no PR was 422'd against GitHub to confirm end to end.
  • Unexercised artifacts. The driving ticket cites a prior spike's findings comment as the evidence its design decisions rest on; that comment lives in a tracker this run has no access to, so its decisions were taken as given rather than re-derived. The ticket's line references also point at a merged PR's branch head rather than this branch's base, so every symbol it names was re-located by name on current main before being changed.

Provenance

  • Authored by: agent-work loop
  • Verified: python3 -m unittest discover -s .github/cursor-review/tests -p 'test_*.py': 402 tests, OK (0 failures); python3 -m unittest discover -s .github/groom/tests -p 'test_*.py': 374 tests, OK; python3 -m unittest discover -s .github/agents-md-integrity/tests -p 'test_*.py': 46 tests, OK; shellcheck -x .github/cursor-review/install-cursor-cli.sh .github/cursor-review/slack-notify.sh and -x .github/bump-callers/bump-callers.sh .github/bump-callers/tests/test_bump_callers.sh: clean; python3 .github/agents-md-integrity/check_agents_md.py --root .: passed (2 pre-existing warnings, both about a missing CODEOWNERS); python3 .github/workflow-pins/check_workflow_pins.py: OK, 11 workflows, 0 exempt. Mutation checks — replacing FALLBACK_SENTINEL_MAX_CHARS with an unbounded budget fails 5 subtests across the two prose-floor tests; deleting the - len(CLAMP_TRUNCATION_NOTE) reserve fails 3 of the 6 swept reserve subtests; both go green on restore. The 58,720-vs-zero and 39-visible/45-recovered figures above were measured on this branch through the test harness, before and after the fix.
  • Deviations: the size guard is a prose floor plus a prefix search rather than the plan's all-or-nothing threshold, and reserves clamp_review_body's truncation note rather than testing MAX_REVIEW_BODY_CHARS raw — both stricter than the plan, for the measured reasons in the defects section. The lost_to_fallback tag is additionally gated on a successful anchor parse, which the plan did not specify. Per this repo's public-repo guardrail the title and body carry no tracker reference — the branch name does.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/Comfy-Org/github-workflows/pull/263 **Author:** [@mattmillerai](https://github.com/mattmillerai) **Created:** 9/5/2026 **Status:** ✅ Merged **Merged:** 9/8/2026 **Merged by:** [@mattmillerai](https://github.com/mattmillerai) **Base:** `main` ← **Head:** `matt/be-10002-fallback-sentinel` --- ### 📝 Commits (3) - [`a57f1e5`](https://github.com/Comfy-Org/github-workflows/commit/a57f1e5f001f819a7b81afa19bf81657a5417efc) feat(cursor-review): carry the 422 fallback's findings into the ledger - [`fb3edb8`](https://github.com/Comfy-Org/github-workflows/commit/fb3edb8628c51014e040353c07204a154399340c) fix(cursor-review): keep a prose floor under the fallback's sentinel (BE-10002) - [`02723c9`](https://github.com/Comfy-Org/github-workflows/commit/02723c9e646ae554f58dd4c58acf1a6e5a4f5dc7) test(cursor-review): pin the clamp-note reserve, and file the budget tests correctly ### 📊 Changes **4 files changed** (+792 additions, -77 deletions) <details> <summary>View changed files</summary> 📝 `.github/cursor-review/build-ledger.py` (+91 -29) 📝 `.github/cursor-review/post-review.py` (+177 -23) 📝 `.github/cursor-review/tests/test_build_ledger.py` (+133 -0) 📝 `.github/cursor-review/tests/test_post_review.py` (+391 -25) </details> ### 📄 Description ## ELI-5 When GitHub rejects a review's inline comments, cursor-review re-posts the whole round as plain prose. Until now that prose carried a "these findings lost their threads" sentence but not the little machine-readable copy the *next* round reads, so the next review knew findings had been lost and could not see a single one of them — including the findings that anchored perfectly well and only lost their thread to the failed request. This PR puts that machine-readable copy in the fallback body too, marks the findings that were lost to the failed POST (rather than to the diff), and tells the next round's panel and judge that the "prefer not to re-raise" rule for unanchorable findings does not apply to those. The copy is a *guest* in that body, not its owner: it may take at most half the size budget, and if the round is too big for that it carries the most urgent findings that fit rather than all or none. The prose a human reads keeps the other half. ## What changed **`post-review.py`** * `render_body_only_sentinel` emits an optional per-item `"lost_to_fallback": true`, only for an item that carries it and only on a literal `True` (matching `build-ledger.py`'s reader) — a success-path payload is byte-identical to before, and the key contains no `-`, so the existing `-` dash escape still makes the HTML comment unclosable. * The wholesale-fallback branch builds sentinel items from **all** of `enriched`: items that came from the inline half are tagged `lost_to_fallback`, items that were already unanchorable are not (the POST outcome told us nothing about them). They are tagged by object identity while iterating `enriched`, so the sentinel keeps the same most→least-urgent order as the prose under it. * **The tag is gated on a real anchor check.** `load_anchors(args.diff)` is kept in `anchors` rather than consumed inline. When it returns `None` — no `--diff`, an unreadable or empty patch — `partition_by_anchor` fails *open* and calls every finding inline without testing one, so nothing is tagged and every finding renders `[unanchorable]`. The flag claims the finding passed the diff-anchor check, and only a real check can make that claim. * The fallback body is composed head-first: `review_head` → the existing `_(Inline comments could not be anchored…)_` note → the sentinel → the findings prose. That is the same order `render_body_only_findings` uses and for the same two reasons — `build-ledger.py` only accepts a sentinel whose marker line sits immediately above it, and `clamp_review_body` cuts the tail, so a clamp eats least-urgent prose rather than the JSON. * **Size guard, in two parts.** A *prose floor*: `FALLBACK_SENTINEL_MAX_CHARS = MAX_REVIEW_BODY_CHARS // 2` caps what the sentinel may take, and the new `fit_sentinel_items()` binary-searches the longest most-urgent **prefix** that fits it, so a round too big for a whole sentinel recovers part of one instead of none of it. And a *clamp reserve*: `clamp_review_body`'s truncation note is subtracted from the budget, not merely the limit tested, so the sentinel is never posted where the clamp would cut into it. `render_findings_markdown`'s separator and that note are now module constants, so the guard measures the real strings. **`build-ledger.py`** * `_body_only_entries` copies `lost_to_fallback: True` onto the entry, matched with `is True` (the payload is model-adjacent text arriving through a public review body, so a stray `"no"` must not read as the flag). Everything mechanical is unchanged: `anchored` False, zeroed thread, empty `discussion_url`, cap-exempt. * `render_ledger_markdown` renders `[post-failed]` instead of `[unanchorable]` for such an entry, with a note saying the finding *matched a line in the reviewed diff* and lost its thread to a delivery failure, so re-raising it needs no `repeat_of`. * **Separate aggregate.** `unanchorable_count` now excludes these entries and a new `post_failed_count` carries them, each with its own clause in the block header and in `ledger_note` — so the aggregate a model reads first can no longer say "N unanchorable, so never answerable at all" of a finding whose own entry line two rows below reports that it matched the diff. Both renders read the new key with `.get(...) or 0`, so a ledger written before this change is unaffected. * One steering bullet added to each of `_PANEL_STEERING` and `_JUDGE_STEERING`: `[post-failed]` behaves like `[unanchorable]` for repeat purposes (no thread, never a `repeat_of` target, costs no repeat slot) but, unlike it, passed the diff-anchor check — so the "prefer not to re-raise" preference does not apply to it. No sentinel version bump — `v1` gains an optional key an older parser ignores. ## Two defects this PR's own review found, and fixed **The sentinel displaced the review a human reads.** The first size guard only asked whether the sentinel fit *ahead of finding one*, which let it take the whole budget. Measured on this branch: a round of **89 findings of ~700 chars posted 58,720 characters of sentinel and rendered zero findings**, while the same round at 90 findings — one over the all-or-nothing guard, so the sentinel was dropped whole — rendered **79**. The cliff ran backwards, and the rounds with the most to report showed the least. With the prose floor and prefix search, every size from 60 to 130 findings now posts **39 findings visible and 45 recovered**. Pinned by `test_the_sentinel_never_displaces_the_findings_a_reader_can_see` and `test_the_sentinel_keeps_the_most_urgent_findings_when_it_cannot_keep_all`; reverting the cap fails 5 subtests. **A ~122-character window in which the clamp cut *into* the JSON.** `clamp_review_body` cuts at `limit - len(note)`, so a head+sentinel that fits `MAX_REVIEW_BODY_CHARS` by less than the note's length was cut mid-payload, `drop_unterminated_comment` then removed the sentinel back to its opener, and it took every finding after it. Measured on a 90-finding round: the posted review collapsed from 60,000 characters of findings to a **494-character header**. The budget therefore reserves the clamp note. Because the prose floor now wins the `min()` on ordinary rounds, that reserve is pinned on the input where the other term wins — a panel summary large enough to make the head most of the body — and the assertion is about the *prose*, which is what the reserve actually saves: both settings end with no readable sentinel inside the window, but only the unreserved one also throws the findings away. Removing the reserve fails 3 of the 6 swept subtests. ## Tests * Flipped `test_the_fallback_round_degrades_loudly_in_the_next_round_s_ledger` → `…carries_its_findings_into_the_next_round_s_ledger`: the 422 path now posts a sentinel, and the posted body is round-tripped through the real `build_ledger`, yielding two entries — the anchorable one `lost_to_fallback` and rendered `[post-failed]`, the off-diff one plain `[unanchorable]`. * New on the budget: the prose floor across four round sizes; the most-urgent-prefix property; the clamp-note reserve swept across its window; the floor where *nothing* fits (a single pathological `path` — bodies are capped at 600 chars but `path` is length-checked nowhere — so the marker is posted alone and the ledger discloses it); and `FitSentinelItemsTest`, a unit class for the search itself (prefix-ness, longest-prefix exactness, empty budget, empty input). * New: `test_no_finding_is_called_post_failed_when_the_anchors_were_never_checked` — with no `--diff`, nothing is tagged and both entries stay `[unanchorable]`. * New ledger-side: `TestLostToFallbackEntries` (round-trip through the real writer, the `[post-failed]` render and its note, steering present for both audiences, forward-compat, and that only a real `true` sets the flag), plus `test_the_two_thread_less_totals_are_reported_separately` and `test_a_round_with_no_post_failed_entry_reads_exactly_as_before` for the split aggregate. * Assertions corrected: `test_the_sentinel_is_never_posted_where_the_clamp_would_cut_it` measured `len(body)`, which counts the sentinel's HTML comment and so stayed large on precisely the body that rendered zero findings; it now counts rendered entries on the body with the comment line stripped, via a new module-level `visible()` helper that `test_no_finding_is_rendered_twice_in_the_fallback` also uses. * `EndToEndPostTest.run_main` gains an optional `panel=` argument (defaulting to today's fixture) so a test can control the one finding-independent part of the review head. * Kept green unchanged: `test_a_422_still_degrades_wholesale_and_keeps_every_finding` and the success-path sentinel tests. `test_the_clamp_cuts_the_least_urgent_finding_in_the_fallback` shrinks its four finding bodies from 19,000 to 18,000 characters because the sentinel now shares the budget; the property it pins — the cut landing on the least urgent — is unchanged, and it now also asserts the cut finding is still recoverable from the sentinel. ## Scope swept `post-review.py` posts four kinds of review body. The two that carry findings — the success path and this wholesale fallback — now both emit a sentinel. The other two carry no findings to encode (the "no high-signal findings" review, and the error review, which deliberately defangs both halves of the contract out of imported text). The three paths that deliver only to the job summary when findings exist (read-only token, no inline half to drop, both POSTs failed) still contribute nothing to the ledger, because no review reaches the PR at all on them. Sentinel cost, for sizing: up to ~660 characters per finding (the 600-character body cap plus the path/line/severity keys). At that size the half-budget floor starts trimming the sentinel to a prefix at ~45 findings. ## Residual * **Both POSTs failing is still ledger-invisible** — named as out of scope by the driving ticket and unchanged here. When the inline POST *and* the fallback POST both fail, no review body reaches the PR, so there is nothing for the next round's ledger to read; the run goes red and the full text goes to the job summary. The two sibling no-post degradations (a read-only token, and a failure with no inline half to drop) are invisible to the ledger for the same reason. * **A nonzero `gh` result is not proof the review was not committed server-side.** If the first POST did land, its findings have real threads *and* land in this sentinel, so the next ledger carries each twice: once with its thread and the author's reply, once as a cap-exempt `[post-failed]` entry asserting nobody could have answered it. Documented in-code where the tag is set. Confirming absence needs a read of the PR's reviews this script does not do, and a decision about what to do when *that* read fails — filed as a follow-up. * **A `[post-failed]` entry carries no repeat lineage.** The sentinel strips the rendered `repeat_of` line and carries the URL in no field, so a re-raise of a finding answered in a round that has since aged past `MAX_ROUNDS` costs no repeat slot. This predates the PR — it is true of every `[unanchorable]` entry since BE-9565 — and the steering that amplified it ("re-raise it freely") has been softened to "re-raise it if it still holds", with a test asserting *freely* appears in neither audience's steering. The lineage fix is filed as a follow-up. * **The success path's sentinel still has no size guard.** The mid-JSON clamp window this PR closes on the fallback path is open on the success path, where the demoted-findings section is the body's tail; with ~90+ demoted findings the cut lands in its JSON and `drop_unterminated_comment` takes the demoted prose with it. Not fixed here because it changes `render_body_only_findings`' signature and alters the path every review takes; `fit_sentinel_items` is now available for it. Filed as a follow-up. * **A partial sentinel is silent about being partial.** When the prose floor trims the sentinel to a prefix, the findings left out are simply absent from the next ledger — the same way *all* of them were absent when the whole sentinel was dropped, so this adds no new false claim, but the ledger cannot distinguish "trimmed" from "not found". * **No live 422 was reproduced.** Everything here is exercised through the repo's stubbed-`gh` harness (`post_returncode=1, stderr="HTTP 422"`) and the real `build_ledger` parser, which is what the driving ticket names; no PR was 422'd against GitHub to confirm end to end. * **Unexercised artifacts.** The driving ticket cites a prior spike's findings comment as the evidence its design decisions rest on; that comment lives in a tracker this run has no access to, so its decisions were taken as given rather than re-derived. The ticket's line references also point at a merged PR's branch head rather than this branch's base, so every symbol it names was re-located by name on current `main` before being changed. ## Provenance - **Authored by:** agent-work loop - **Verified:** `python3 -m unittest discover -s .github/cursor-review/tests -p 'test_*.py'`: 402 tests, OK (0 failures); `python3 -m unittest discover -s .github/groom/tests -p 'test_*.py'`: 374 tests, OK; `python3 -m unittest discover -s .github/agents-md-integrity/tests -p 'test_*.py'`: 46 tests, OK; `shellcheck -x .github/cursor-review/install-cursor-cli.sh .github/cursor-review/slack-notify.sh` and `-x .github/bump-callers/bump-callers.sh .github/bump-callers/tests/test_bump_callers.sh`: clean; `python3 .github/agents-md-integrity/check_agents_md.py --root .`: passed (2 pre-existing warnings, both about a missing CODEOWNERS); `python3 .github/workflow-pins/check_workflow_pins.py`: OK, 11 workflows, 0 exempt. Mutation checks — replacing `FALLBACK_SENTINEL_MAX_CHARS` with an unbounded budget fails 5 subtests across the two prose-floor tests; deleting the `- len(CLAMP_TRUNCATION_NOTE)` reserve fails 3 of the 6 swept reserve subtests; both go green on restore. The 58,720-vs-zero and 39-visible/45-recovered figures above were measured on this branch through the test harness, before and after the fix. - **Deviations:** the size guard is a prose floor plus a prefix search rather than the plan's all-or-nothing threshold, and reserves `clamp_review_body`'s truncation note rather than testing `MAX_REVIEW_BODY_CHARS` raw — both stricter than the plan, for the measured reasons in the defects section. The `lost_to_fallback` tag is additionally gated on a successful anchor parse, which the plan did not specify. Per this repo's public-repo guardrail the title and body carry no tracker reference — the branch name does. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-26 22:37:55 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Comfy-Org/github-workflows#266
No description provided.