Skip to content

[CAT-UNVERIFIED tag](2) A rewritten reply still gets checked for proof - #416

Merged
EdbertChan merged 1 commit into
mainfrom
stack/EdbertChan/cat-unverified-tag/2-retry-checks-evidence
Sep 12, 2026
Merged

[CAT-UNVERIFIED tag](2) A rewritten reply still gets checked for proof#416
EdbertChan merged 1 commit into
mainfrom
stack/EdbertChan/cat-unverified-tag/2-retry-checks-evidence

Conversation

@EdbertChan

@EdbertChan EdbertChan commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Summary

Before Claude sends a reply, small checker scripts read it. One checks length. Others check that every claim comes with proof. If a check fails, Claude must rewrite.

The problem: when Claude rewrote, both checkers stepped aside completely. So the second draft could say anything, even a brand-new claim with no proof.

Why they stepped aside: the length check once blocked one reply nine times in a row. Letting every rewrite through ended that loop.

The fix: on a rewrite, only the length check steps aside. The proof checks run every time.

Before and After

We took the real rewrite that exposed this and sent it as a second try, first on the old code (509b9cd), then on this change. exit=0 means the reply went through. exit=2 means it was blocked.

before (509b9cd) exit=0
    (silent)
after            exit=2
    `UNVERIFIED:` is no longer an escape hatch -- it reads as ordinary prose and the claim beside it is judged on its own...

Review Claim

Approve this: on a rewrite, only the length check is skipped. The proof checks run every time.

Review Lane

behavior

Review Unit

engine-runtime

Safety Invariant

Claude always has a way to finish. The length check still steps aside on a rewrite, so the nine-block loop cannot come back. The proof checks always accept a note that says what Claude could not check and why. test_naming_the_blocker_ends_the_turn and test_naming_the_blocker_ends_the_turn_on_retry test this.

One known gap: this PR's checker names only the first unproven sentence, so a reply with two of them gets blocked twice. PR #433, stacked on this one, makes one block list every sentence.

Slice Rationale

This is part 2 of a stack. Part 1 adds the note that lets Claude say "I could not check this, and here is why." That note is the way out of a block, so this change needs part 1 first.

Non-goals

  • Which note counts as an excuse does not change.
  • The length limit and how words are counted do not change.

Test Plan

Test Plan
  • python3 engine/skills/make-pr/scripts/preflight.py --base <this PR's base>
unit    engine-runtime: 5 file(s)
declare Review Unit: engine-runtime
gate    python3 scripts/check_hook_test_coverage.py engine/hooks/diu-stop
        check_hook_test_coverage: OK (1 hook(s) checked)
gate    python3 scripts/check_hook_test_coverage.py engine/hooks/prove-it-ship-gate
        check_hook_test_coverage: OK (1 hook(s) checked)
ok      preflight passed
  • bash scripts/run_all_tests.sh -- exit 0, 45 suites OK, 0 failed, 1674 tests
  • test_naming_the_blocker_ends_the_turn (diu-stop) and test_naming_the_blocker_ends_the_turn_on_retry (prove-it-ship-gate) -- a tagged claim passes with and without stop_hook_active
  • test_retry_stops_checking_the_word_count -- the word count still does not fire on a retry

Revert Plan

Revert Plan
  • Safe to revert? Yes
  • Revert command: git revert <sha>
  • Post-revert steps: None
  • Data migration? No

🤖 Generated with Claude Code


Note

Medium Risk
Changes agent-facing stop-hook behavior for every rewrite after a block; mis-tuning could reintroduce word-count loops or over-block legitimate retries, though tests lock in the split behavior.

Overview
Stop-hook rewrites are no longer a blanket bypass for proof checks. When stop_hook_active is set after a first block, claude_stop_check and prove-it-ship-gate used to exit immediately; rewrites could introduce new unverified claims (e.g. bare UNVERIFIED:) without re-checking.

Only the diu word-count gate is relaxed on retry, because that check could loop (nine blocks on one long message). On retry, over_limit is false even when over WORD_LIMIT; unverified-claim, malformed {{CAT-UNVERIFIED}}, and ship-gate logic still run. The intended way to finish is a well-formed {{CAT-UNVERIFIED: … -- cannot verify: <reason>}} (or real evidence), documented in the module docstring.

Tests replace “passes on stop_hook_active” with cases that retries still block bad claims, still skip word count only, and pass once the blocker is named in the tag.

Reviewed by Cursor Bugbot for commit e34b32f. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor

cursor Bot commented Sep 11, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_48ffe756-9080-46fc-990d-666452c46c97)

@EdbertChan EdbertChan changed the title [CAT-UNVERIFIED tag](2) A retry skips the word count, not the evidence checks [CAT-UNVERIFIED tag](2) A rewritten reply still gets checked for proof Sep 11, 2026
@EdbertChan
EdbertChan changed the base branch from stack/EdbertChan/cat-unverified-tag/1-shared-tag-in-hooks to main September 11, 2026 19:31
@mergify

mergify Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Queued — the merge queue status continues in this comment ↓.

@EdbertChan

Copy link
Copy Markdown
Owner Author

@Mergifyio queue

@mergify

mergify Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-09-11 21:38 UTC · Rule: admin-bypass · triggered by @EdbertChan with the @mergifyio queue command
  • 🚫 Left the queue2026-09-11 21:43 UTC · at ae767eae8598a4ab50259047615695541d4409f3

This pull request spent 4 minutes 43 seconds in the queue, with no time running CI.

Reason

The pull request conflicts with the base branch

The pull request was held in the queue, conflicting with 1 pull request ahead of it. The conflict became a base branch one after #421 merged.

Hint

You should update or rebase your pull request.

If you want to requeue this pull request, you can post a @mergifyio queue comment.

Tick the box to put this pull request back in the merge queue (same as @mergifyio queue).

  • Requeue this pull request

@EdbertChan

Copy link
Copy Markdown
Owner Author

Mergify repair stopped: GitHub reports merge conflict. The retry cap was reached for current head ae767ea.

diu-stop and prove-it-ship-gate both returned on stop_hook_active before
any check ran. For diu-stop the reason was real -- trimming words reveals
more words to trim, and nine consecutive blocks on one 150-word message
were observed -- but returning early passed the whole message. The first
block of a turn bought a free pass for whatever the rewrite said next,
including a claim that was never checked.

That is what happened in the session behind this change. The same message,
sent as a retry, on 509b9cd and on this stack:

  before (509b9cd) exit=0
      (silent)
  after            exit=2
      `UNVERIFIED:` is no longer an escape hatch -- it reads as ordinary
      prose and the claim beside it is judged on its own...

A diu-stop retry now skips only the word count. prove-it-ship-gate has no
word count, so its bypass was a pure free pass and is gone.

These checks cannot loop the way the word count did: a well-formed tag
always passes and every block message names it, so there is always a move
that ends the turn. test_naming_the_blocker_ends_the_turn and
test_naming_the_blocker_ends_the_turn_on_retry pin that.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VKsvxJk65w6q7KnPSRYvNg
@EdbertChan
EdbertChan force-pushed the stack/EdbertChan/cat-unverified-tag/2-retry-checks-evidence branch from ae767ea to e34b32f Compare September 12, 2026 06:18
@cursor

cursor Bot commented Sep 12, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_b7fff640-a2d7-4494-9548-5a240a1841f8)

@EdbertChan
EdbertChan merged commit 33215be into main Sep 12, 2026
3 of 4 checks passed
@mergify mergify Bot removed the dequeued label Sep 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants