Skip to content

Conversation

@jdorweiler
Copy link

Asana Task/Github Issue:

Description

Building on #2048 with a more generalize framework for breakage reports.

New detector service:

  • Registry + caching with configurable TTL
  • Auto-registration from remote config during page load
  • Optional auto-run with configurable delay (default 100ms)
  • Domain gating + custom shouldRun() checks (only during auto-run)
  • Multi-consumer design (any feature can import and use)

Changed:

  • Architecture: Service with dynamic registration
  • Caching: Built-in with TTL vs re-scan every call
  • Configuration: Remote config vs function parameters
  • Lifecycle: Auto-registers on page load + optional auto-run vs on-demand only
  • Gating: Domain restrictions + custom checks
  • Consumers: Any feature can use service

See the injected/src/detectors/README.md for more details

Testing Steps

Checklist

Please tick all that apply:

  • I have tested this change locally
  • I have tested this change locally in all supported browsers
  • This change will be visible to users
  • I have added automated tests that cover this change
  • I have ensured the change is gated by config
  • This change was covered by a ship review
  • This change was covered by a tech design
  • Any dependent config has been merged

@netlify
Copy link

netlify bot commented Nov 10, 2025

Deploy Preview for content-scope-scripts ready!

Name Link
🔨 Latest commit 443628a
🔍 Latest deploy log https://app.netlify.com/projects/content-scope-scripts/deploys/6914ab5855938a0008463a97
😎 Deploy Preview https://deploy-preview-2052--content-scope-scripts.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link

github-actions bot commented Nov 10, 2025

Temporary Branch Update

The temporary branch has been updated with the latest changes. Below are the details:

Please use the above install command to update to the latest version.

@github-actions
Copy link

github-actions bot commented Nov 10, 2025

[Beta] Generated file diff

Time updated: Wed, 12 Nov 2025 15:46:34 GMT

Android
    - android/adsjsContentScope.js
  • android/autofillImport.js
  • android/brokerProtection.js
  • android/contentScope.js

File has changed

Apple
    - apple/contentScope.js
  • apple/contentScopeIsolated.js

File has changed

Chrome-mv3
    - chrome-mv3/inject.js

File has changed

Firefox
    - firefox/inject.js

File has changed

Integration
    - integration/contentScope.js

File has changed

Windows
    - windows/contentScope.js

File has changed

Copy link
Contributor

@madblex madblex left a comment

Choose a reason for hiding this comment

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

This looks great. I added some comments and a couple more here:

  1. I'd like to see how this integrates with content features, especially broker protection, i.e. the equivalent of this
  2. I see we removed WebInterferenceDetection content feature. Is it because you don't think we'll need a standalone feature for this? i.e. the detectors will only be called from other features.
  3. I see we're going the functional route (from classes). Not feeling strongly (I prefer functional most of the time), I just believe the trade-off is that interfaces will be more difficult to enforce. I think classes provide a bit of a better structure, but this is opinionated.

const bundledFeatureNames = typeof importConfig.injectName === 'string' ? platformSupport[importConfig.injectName] : [];

// Initialize detectors early so they're available when features init
initDetectors(args.bundledConfig);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is running on a critical path, I believe we should surround it with try/catch and fire a pixel on error here.

Copy link
Author

Choose a reason for hiding this comment

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

💯 good catch

* @param {boolean} [options._autoRun] - Internal flag indicating auto-run (gates apply)
* @returns {Promise<Record<string, any>>} Object mapping detector IDs to their data
*/
export async function getDetectorBatch(detectorIds, options = {}) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We should use a better name here, currently it's a bit misleading. getDetectorBatch makes me think we're just getting the detectors based on args, not that they'll also be running. Suggestions:

runDetectors / getDetectorsData, etc.

Since this is also a "public" service to the repo, I'd interject the word web to make it clear what these detectors are about, i.e. runWebDetectors / getWebDetectorsData or similar.

Copy link
Author

Choose a reason for hiding this comment

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

Yeah good point. I'll go with getDetectorsData. I don't think we need web prefix as we're not following that naming scheme elsewhere (e.g., getJsPerformanceMetrics, getExpandedPerformanceMetrics)

Copy link
Contributor

Choose a reason for hiding this comment

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

Will we still be needing this?

Copy link
Author

Choose a reason for hiding this comment

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

No, I can drop this

@@ -0,0 +1,62 @@
import { isVisible, queryAllSelectors } from '../utils/detection-utils.js';
const DEFAULT_CONFIG = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not add to DEFAULT_DETECTOR_SETTINGS?

@jdorweiler
Copy link
Author

This looks great. I added some comments and a couple more here:

1. I'd like to see how this integrates with content features, especially broker protection, i.e. the equivalent of [this](https://github.com/duckduckgo/content-scope-scripts/pull/2048/files#r2513656558)

2. I see we removed `WebInterferenceDetection` content feature. Is it because you don't think we'll need a standalone feature for this? i.e. the detectors will **only** be called from other features.

3. I see we're going the functional route (from classes). Not feeling strongly (I prefer functional most of the time), I just believe the trade-off is that interfaces will be more difficult to enforce. I think classes provide a bit of a better structure, but this is opinionated.
  1. Commented here https://github.com/duckduckgo/content-scope-scripts/pull/2048/files#r2514564110
  2. Yeah, I changed it so detectors auto register via detector-init.js during the load phase, and features import the service directly. So detector initialization is handled for you. Then you just need to add the message handler to broker protection (see my comment linked in 1)
  3. I'm not strongly attached to this approach. I wanted to see what functional approach looked like vs classes but I'm open to switching to classes if you think the structure is worth it.

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.

3 participants