Skip to content

Covered band: dismiss only the proved session notice, and only when it cut the band - #1740

Merged
abrichr merged 5 commits into
mainfrom
claude/covered-band-dismiss-guard
Nov 3, 2026
Merged

abrichr merged 5 commits into
mainfrom
claude/covered-band-dismiss-guard

Conversation

@abrichr

@abrichr abrichr commented Nov 3, 2026

Copy link
Copy Markdown
Member

Fixes the two problems the independent review of #1735 found on the self-repair side of #1724. The coordinator ruled both blockers before any live Windows covered-band repair.

1. The dismiss click is held to the proved dialog (SelfRepair._dismisses_the_cover, called from _new_click). A click is refused unless all of these hold:

  • Same window. owned_window_over is asked again at the click point, against the same verified window. It must return the same window (hwnd or window_id, plus pid) as the cover. A missing id never matches.

  • One click. The bridge is exactly one click, with nothing typed.

  • The label is "OK".

  • The dialog is a session notice. Its text (OCR lines inside its rect) passes an allowlist after NFKC:

    • every word is a session-notice word or a number, and a run-together OCR token (yoursession, in5minutes) counts only if it splits fully into such words;
    • the only punctuation is . , : ! and ×, so no question in any script;
    • it must say that a session expires;
    • an OCR line that crosses the dialog's edge refuses.

    "Discard unsaved changes?", "Log out of the other session?", "Your changes will be deleted", "Update the application now", a dialog in another language, and a dialog whose message wasn't read are all refused.

2. The cover must be what cut the band (_cover_explains_cut). The window's region must span the band from inside it to the band's right edge, at full height. The share of the band left uncovered must be within 0.1 of the share of the recorded text read. On the lab's Patient Notes notice these are 0.79 and 0.81. A tooltip over a column's ellipsis doesn't count, and a cover with no region is doubt. macOS now reports its sheet's region; Windows reports it since #1739.

3. Recheck test. When the dialog hides exactly where two records differ, test_the_probes_full_identity_check_refuses_what_the_dialog_hid shows that the unchanged identity template refuses the other record, and refuses the still-covered read.

A covered-band repair gets one attempt. A retry reopens the app, the dialog is then a new window, and its click is refused. The design note and changelog say so.

Reviews. Four rounds of independent adversarial review, each blocker fixed in turn:

  1. The message gate was a denylist.
  2. Update words and non-ASCII question marks got through.
  3. It allowed on missing evidence (an "OK"-only read).
  4. Run-together OCR words would refuse the real dialog. This one failed closed.

A final review runs on the last commit.

Tests. The covered-band and macOS sheet suites pass, along with the Windows backend and agent suites (304 tests). They include a real-OCR test on a drawn dialog. The wider self-repair, bridge, CLI, desktop, hold, element-identity and replayer suites (289 tests) passed on the first commit; later commits change only the message gate.

@abrichr

abrichr commented Nov 3, 2026

Copy link
Copy Markdown
Member Author

Independent adversarial review: five rounds. Round 5 approves with no blockers.

Earlier rounds each found a blocker, and each was fixed in turn:

  1. The message gate was a denylist. "Log out of the other session? OK", "Your changes will be deleted" and dialogs in other languages all passed. The gate is now an allowlist.
  2. "Update the application now. OK", "?" and "¿" passed. Fixed by removing update words, adding NFKC, and refusing any marks beyond . , : ! ×.
  3. An "OK"-only read passed, and so did a message line lost across the dialog's edge. Fixed: the dialog must say a session expires, and a line that crosses the edge refuses.
  4. RapidOCR runs words together (Yoursession expires in5minutes.), which would have refused the real dialog. That failed closed. Fixed: a run-together token passes only if it splits fully into allowed words.

Round 5 findings:

  • Segmentation (_notice_parts). It cannot produce a consequential word: its pieces are allowed words of two or more letters and ASCII digit runs, and one-letter words count only as whole tokens (5x, xok, axdelete refuse). The DP is correct: breaking on the first workable start never refuses a token that has a full split and never accepts one that lacks it.
  • Real-OCR test. It runs: rapidocr is a core dependency, so CI runs it too. It is meaningful: on macOS it reads Sessionnotice X Yoursessionexpiresin5minutes. OK, which passes only through the segmentation.
  • Whole PR. No fail-open path. A missing region, an OCR exception or empty text refuses; a line crossing the edge refuses; _window_key rejects bools and ids that are not positive; the label must be exactly "ok".

Non-blockers, left for a follow-up:

  • piece in words is a linear scan over a sorted list (use a frozenset), and the DP is quadratic. A 2,100-character token takes 0.5 s; cap the token length.
  • OCR that drops a low-confidence warning line leaves only notice words, so the dialog passes. That is a limit of any check built on OCR text; worth one line in the design note.
  • Marks such as OK! !! pass. That is harmless.

@abrichr
abrichr enabled auto-merge (squash) November 3, 2026 17:39
@abrichr
abrichr merged commit f0297fb into main Nov 3, 2026
45 checks passed
@abrichr
abrichr deleted the claude/covered-band-dismiss-guard branch November 3, 2026 17:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant