Skip to content

Fix: disguised-ad-flag skips single card with content wrapper (#228 follow-up)#231

Merged
twschiller merged 1 commit into
mainfrom
fix/disguised-ad-flag-single-card-wrapper-228
Jun 9, 2026
Merged

Fix: disguised-ad-flag skips single card with content wrapper (#228 follow-up)#231
twschiller merged 1 commit into
mainfrom
fix/disguised-ad-flag-single-card-wrapper-228

Conversation

@twschiller

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #230 (review feedback from Unblocked bot).

PR #230's hasOtherCardSubtree guard rejected any candidate enclosing a descendant outside the label's chain that carried both an image and an outgoing link. A common card layout — label as a sibling to a single content wrapper that holds heading + image + link — tripped the guard, and the legitimate ad card escaped detection entirely.

<article>
  <span class="label">Sponsored</span>
  <div class="card-body">
    <h2><a href="/ad">Title</a></h2>
    <img src="ad.jpg" />
    <p>Long body text…</p>
  </div>
</article>

div.card-body is not the label, not contained by the label, and does not contain the label. It has both an <img> and an <a href> descendant → the pre-fix guard returned trueisArticleShaped returned false → the card was not hidden.

Fix

Rename hasOtherCardSubtreehasMultipleCardSubtrees and require two or more outermost non-overlapping qualifying subtrees before rejecting. The label's own containing chain does count toward the total (the candidate.contains(labelElement) skip is dropped), so a feed wrapper still trips at >= 2 (label's card + sibling cards), while a single card with one (or several stacked) content wrappers collapses to 1.

Verifying #228 still holds

  • Reddit <shreddit-feed> with 3 ad-post cards, one momentarily headless: walking from the headless card's label reaches the feed; the feed encloses 3 outermost card subtrees (each card has img+a) → count >= 2 → feed wrapper is rejected, individual headed cards still match on their own walk-up.
  • 2-card feed with one headless: 2 outermost card subtrees → count = 2 → feed rejected.

Test plan

  • bun run check — clean
  • bun run typecheck — clean
  • bun run knip — clean
  • ./node_modules/.bin/jest — 1918 tests passing, including:
    • new hides a single card whose content sits inside a wrapper div regression test in disguised-ad-flag.test.ts
    • new fast-check property in disguised-ad-flag.property.test.ts asserting that a single card with N stacked wrapper divs is always hidden (N ∈ [1, 5])
  • Manual on reddit.com with the unpacked extension after merge

🤖 Generated with Claude Code

…ollow-up)

PR #230's `hasOtherCardSubtree` guard rejected any candidate enclosing a
descendant outside the label's chain that carried both an image and an
outgoing link. A common card layout — label as sibling to a single
content wrapper that holds heading + image + link — tripped that guard,
and the legitimate ad card escaped detection.

Switch to counting *outermost* qualifying subtrees and reject only when
two or more exist. Include the label's own containing chain in the
count so a feed wrapper (label's card + sibling cards) still trips at
>= 2, while a single card with stacked wrapper divs collapses to 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agent-browser-shield-demo-site Ready Ready Preview, Comment Jun 9, 2026 2:41pm

Request Review

@twschiller twschiller added the bug Something isn't working label Jun 9, 2026
@twschiller twschiller self-assigned this Jun 9, 2026
@twschiller twschiller merged commit 5844bef into main Jun 9, 2026
7 checks passed
@twschiller twschiller deleted the fix/disguised-ad-flag-single-card-wrapper-228 branch June 9, 2026 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant