Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add disguised-ad-flag rule for native advertorials#116

Merged
twschiller merged 3 commits into
mainfrom
worktree-staged-brewing-lemur
Jun 3, 2026
Merged

Add disguised-ad-flag rule for native advertorials#116
twschiller merged 3 commits into
mainfrom
worktree-staged-brewing-lemur

Conversation

@twschiller

Copy link
Copy Markdown
Contributor

Summary

  • New disguised-ad-flag rule (Context pollution group, default on) that hides article-shaped blocks carrying a visible "Sponsored" / "Promoted" / "Advertorial" / "Paid Post" / "Partner Content" disclosure label. Fills the gap left by ads-hide: EasyList catches infrastructure-level ads via network selectors, but native advertorials rendered by the publisher's own CMS share DOM shape with editorial articles and slip through.
  • False-positive guards: whole-string regex on a leaf-ish label element (≤80 chars, ≤3 children) keeps editorial prose ("the team is sponsored by Adidas") from matching; an interactive-ancestor walk excludes filter chips, nav links, and form controls; data-abs-hidden="ads-hide" ancestors are skipped to avoid double-flagging; bracket form [Ad] is case-sensitive on the A so Latin "[ad hoc]" doesn't trigger.
  • Replaces matched cards with the standard click-to-reveal placeholder (200 px height cap, same pattern as irrelevant-sections-redact). Subtree-watched so lazy-injected advertorials (Outbrain/Taboola native, infinite scroll feeds) get caught after document_idle.
  • Docs section under Context pollution explains the label-only detection, the FTC .com Disclosures rationale, and the Kohlschütter/Readability prior art.
  • New AdvertorialCard demo fixture with three label variants (Sponsored, [Ad], Paid for and presented by Acme) interleaved with real product cards, plus an editorial negative fixture whose body contains "sponsored by Adidas" as prose. Lets a reviewer toggle the rule in the popup and watch the advertorials collapse while the editorial card stays put.

Test plan

  • bun --filter extension run test — 960 tests pass (25 new in disguised-ad-flag.test.ts)
  • bun --filter extension run lint clean
  • bun --filter extension run typecheck clean
  • bun --filter demo-site run check clean
  • bun --filter demo-site run build clean
  • bun --filter docs run build clean (8 pages built)
  • Load the unpacked extension against the demo site, toggle disguised-ad-flag on in the popup, and visually confirm: the three advertorial cards in "From Our Partners" collapse to placeholders; the editorial article mentioning "sponsored by Adidas" stays visible; existing product cards are untouched.
  • Spot-check on a real NYT T Brand Studio / BuzzFeed branded post / Atlantic Re:Think page — the advertorial card replaces with the placeholder.
  • Spot-check that pages with a "Sponsored" link in the nav and Google Shopping pages with a "Sponsored" filter are NOT affected.

🤖 Generated with Claude Code

EasyList catches infrastructure-level ads via network selectors; native
advertorials rendered by the publisher's own CMS share DOM shape with
editorial articles and slip through. This rule detects them by the
visible disclosure label ("Sponsored", "Promoted", "Advertorial",
"Paid Post", "Partner Content", bracket forms like "[Ad]", and suffix
forms like "Paid for and presented by X") combined with an
article-shape check (heading + image-or-link + prose body) and replaces
matching cards with a click-to-reveal placeholder.

False-positive guards: whole-string regex on a leaf-ish label element
keeps editorial prose mentioning sponsorship from matching; an
interactive-ancestor walk excludes filter chips and nav links;
ads-hide-marked ancestors are skipped to avoid double-flagging.

Includes catalog wiring (Context pollution group, default on), docs
under rules.md, a new AdvertorialCard demo fixture with three label
variants plus an editorial negative fixture on the home page, and 25
unit tests covering positive matches and FP cases.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@vercel

vercel Bot commented Jun 3, 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 3, 2026 3:09pm

Request Review

@unblocked unblocked Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found.

About Unblocked

Unblocked has been set up to automatically review your team's pull requests to identify genuine bugs and issues.

📖 Documentation — Learn more in our docs.

💬 Ask questions — Mention @unblocked to request a review or summary, or ask follow-up questions.

👍 Give feedback — React to comments with 👍 or 👎 to help us improve.

⚙️ Customize — Adjust settings in your preferences.

Comment thread extension/src/rules/disguised-ad-flag.ts Outdated
Comment thread extension/src/rules/index.ts
Pre-commit hooks reflow the rules.md paragraph break differently than my
local editor; biome's `check` (vs `lint`) flags two test-file expect()
lines as too long. Also updates the rule count in rules.md from 32 to 33.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
- isArticleShaped's prose-length tally used to walk every <p>/<span>/<div>/<li>
  descendant and count the same characters at each ancestor level. A nested
  <div><p><span>X</span></p></div> would count X three times and let cards
  with ~30 chars of actual prose slip past the 80-char minimum. Now skip
  candidates that contain another selector-matched descendant (leaf-ish
  only). Adds a regression test that fails on the old code.
- Register disguised-ad-flag in skills/agent-browser-shield-config/SKILL.md's
  Rule IDs list per CONTRIBUTING.md and AGENTS.md.
- Document the disguised-ad-flag placeholder copy in
  skills/agent-browser-shield/SKILL.md so agents reading a revealed
  advertorial treat it as advertising rather than editorial.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@twschiller twschiller merged commit 68279ec into main Jun 3, 2026
7 checks passed
@twschiller twschiller deleted the worktree-staged-brewing-lemur branch June 3, 2026 15:14
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