Skip to content

fix(gate): defer the screenshot-table close on a capture-pipeline blip instead of treating it as missing evidence - #9207

Merged
JSONbored merged 1 commit into
mainfrom
fix/9030-screenshot-gate-capture-blip
Jul 27, 2026
Merged

fix(gate): defer the screenshot-table close on a capture-pipeline blip instead of treating it as missing evidence#9207
JSONbored merged 1 commit into
mainfrom
fix/9030-screenshot-gate-capture-blip

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

Visual capture failing outright (browserless down, a timeout, a GitHub hiccup fetching a token) looked identical to "capture concluded normally and found no visual evidence" — both left visualCaptureSatisfiedSha unset, so the very next maintenance pass could close a legitimate visual PR purely because an internal service blipped. missing before/after screenshot table was the single most common close reason in the 2026-07-26 ledger, so any false-positive rate here is expensive.

The same gap applied to a preview still building (previewPending) — it already self-heals via a scheduled recapture retry, but never suppressed the close on the very pass that discovered the preview wasn't ready yet.

  • visualCaptureRetryPendingSha (new column, migration 0190) marks the exact head SHA a bounded recapture retry is currently scheduled/in-flight for — set only while a retry chance genuinely remains (MAX_PREVIEW_POLL_ATTEMPTS), so the screenshot-table gate's close action defers for exactly as long as that chance exists and never indefinitely. Once the budget is exhausted, the marker is deliberately left unset and the gate falls through to its normal, accurate evaluation on the final attempt.
  • The deferral itself is audited (github_app.screenshot_table_close_deferred_capture_retry), not silent.
  • A subsequent successful capture for the same head clears the marker (markPullRequestVisualCaptureSatisfied).

Test plan

Closes #9030

…p instead of treating it as missing evidence

Visual capture failing outright (browserless down, a timeout, a GitHub hiccup
fetching a token) looked identical to "capture concluded normally and found no
visual evidence" -- both left visualCaptureSatisfiedSha unset, so the very next
maintenance pass could close a legitimate visual PR purely because an internal
service blipped. The same gap applied to a preview still building
(previewPending), which already self-heals via a scheduled recapture but never
suppressed the close on the pass that discovered it.

visualCaptureRetryPendingSha now marks the exact head a bounded recapture retry
is scheduled for -- set only while a retry chance remains (MAX_PREVIEW_POLL_ATTEMPTS),
so the screenshot-table gate's close defers for exactly as long as that chance
exists and never indefinitely. The deferral itself is audited
(github_app.screenshot_table_close_deferred_capture_retry), not silent.
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@JSONbored JSONbored self-assigned this Jul 27, 2026
@JSONbored
JSONbored merged commit 1b5e98d into main Jul 27, 2026
4 checks passed
@JSONbored
JSONbored deleted the fix/9030-screenshot-gate-capture-blip branch July 27, 2026 07:05
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 72.22222% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.94%. Comparing base (e1ae2f0) to head (b80f932).
⚠️ Report is 4 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/queue/processors.ts 68.75% 3 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9207      +/-   ##
==========================================
- Coverage   93.94%   93.94%   -0.01%     
==========================================
  Files         821      821              
  Lines       81601    81614      +13     
  Branches    24769    24774       +5     
==========================================
+ Hits        76662    76672      +10     
- Misses       3556     3557       +1     
- Partials     1383     1385       +2     
Flag Coverage Δ
backend 95.21% <72.22%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/db/repositories.ts 96.77% <100.00%> (+<0.01%) ⬆️
src/db/schema.ts 73.11% <ø> (ø)
src/types.ts 100.00% <ø> (ø)
src/queue/processors.ts 95.04% <68.75%> (-0.08%) ⬇️

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.

orb(gate): screenshot-table gate closes a legitimate visual PR when the capture service blips

1 participant