Skip to content

Merge vendor cddl files into shared BiDi schema and implement custom Firefox webExtension options - #17840

Merged
titusfortner merged 5 commits into
SeleniumHQ:trunkfrom
titusfortner:bidi-webextension-vendor-schema
Jul 29, 2026
Merged

Merge vendor cddl files into shared BiDi schema and implement custom Firefox webExtension options#17840
titusfortner merged 5 commits into
SeleniumHQ:trunkfrom
titusfortner:bidi-webextension-vendor-schema

Conversation

@titusfortner

@titusfortner titusfortner commented Jul 29, 2026

Copy link
Copy Markdown
Member

🔗 Related Issues

💥 What does this PR do?

  • Adds a vendor section to the generated WebDriver BiDi schema so bindings can expose browser-specific command params without adding them to the shared, cross-browser types.
  • The generated Ruby BiDi WebExtension domain now exposes Firefox's moz:allowPrivateBrowsing / moz:permanent install options as a typed, Firefox-scoped Moz module: WebExtension.for_moz(connection).install(extension_data:, allow_private_browsing:, permanent:).

🔧 Implementation Notes

  • This code includes 2 CDDL files in common/bidi/ that mirror the changes expected to land upstream — the extension point from W3C and Mozilla's vendored CDDL file as temporary stand-ins until those merge.
  • Vendor fields are provenance-tagged during CDDL parse (namespace derived from the wire-key prefix, e.g. moz:) and routed out of the shared types into vendor.<ns>. The //= still resolves against the real extension point during normalization — a genuine spec merge — so only the output is split; the shared schema still represents the spec faithfully. Verified every schema type outside webExtension.install is byte-identical to the pre-change build.
  • Ruby implementation
    • The generator emits, per namespace, a vendor module + a for_<namespace> class-method factory (called as WebExtension.for_moz(connection));
    • vendor param names drop the redundant namespace prefix (moz:permanentpermanent) while wire keys stay exact.
    • The shared install(extension_data:) stays browser-neutral — a Chromium session never sees the moz: options, and the shared InstallParameters type is byte-identical to what upstream emits.

🤖 AI assistance

  • No substantial AI assistance used
  • AI assisted (complete below)
    • Tool(s): Claude Code
    • What was generated: schema-generation pipeline changes, the Ruby vendor codegen, the CDDL overlays, and the tests
    • I reviewed all AI output and can explain the change

💡 Additional Considerations

  • Driver-level wiring is intentionally out of scope; I proved the concept locally but do not want to add this as user-facing code on the driver object yet
  • Removal is per-overlay and the two triggers are independent (either can land first):
    • W3C PR: once the pinned webref carries it, delete common/bidi/webdriver-bidi-1140.cddl and its override_cddl_files entry. The vendor overlay keeps working — its //= then resolves against upstream's InstallParametersExtension.
    • Firefox PR: once Mozilla's CDDL is referenceable via bazel, repoint vendor_cddl_files at it and delete our stand-in common/bidi/webextension-install-extensions.cddl. Our overlay already matches it, incl. .default false.
    • The --override-cddl / --vendor-cddl mechanisms and the vendor schema key stay either way (generic, dormant when unused).

🔄 Types of changes

  • New feature (non-breaking change which adds functionality and tests!)

@selenium-ci selenium-ci added C-rb Ruby Bindings C-nodejs JavaScript Bindings B-build Includes scripting, bazel and CI integrations B-devtools Includes everything BiDi or Chrome DevTools related B-support Issue or PR related to support classes labels Jul 29, 2026
@SeleniumHQ SeleniumHQ deleted a comment from selenium-ci Jul 29, 2026
@qodo-code-review

qodo-code-review Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Segregate vendor fields in BiDi schema and generate Ruby WebExtension::Moz install options

✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Add spec override and vendor CDDL overlays for webExtension.install extension points and moz:
 options.
• Project vendor-tagged fields into a separate schema vendor section while keeping shared types
 unchanged.
• Generate Ruby WebExtension::Moz install API with typed moz params and wire-key fidelity tests.
Diagram

graph TD
  A["Upstream BiDi CDDL"] --> B["generate_bidi.mjs"] --> C["Base AST (vendor-free)"]
  O["Override CDDL (#1140)"] --> B
  C --> D["Vendor AST"]
  V["Vendor CDDL (moz)"] --> D
  D --> E["project_bidi_schema.mjs"] --> F["Schema JSON (types + vendor)"]
  F --> G["Ruby bidi_generate.rb"] --> H["WebExtension + WebExtension::Moz"]
  subgraph Legend
    direction LR
    _spec["Spec input"] ~~~ _tool["Generator tool"] ~~~ _out["Generated artifact"]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Keep vendor fields in shared schema as namespaced fields
  • ➕ Simpler schema format (no new vendor top-level section)
  • ➕ Less generator logic for provenance tagging and extraction
  • ➖ Pollutes cross-browser bindings with browser-specific params
  • ➖ Harder to keep TS/Ruby/Java/Py APIs browser-neutral by default
  • ➖ Increases risk of accidental adoption of vendor-only keys in non-matching sessions
2. Expose vendor options only via untyped `extensions`/bag passthrough
  • ➕ No schema changes required beyond making params extensible
  • ➕ Lowest implementation complexity in generators
  • ➖ Bindings cannot provide typed, discoverable APIs for vendor options
  • ➖ Users must know exact wire keys and value shapes
  • ➖ Misses the core goal (typed vendor-specific params without spec pollution)
3. Language-specific vendor shims (no schema vendor section)
  • ➕ Avoids changing the shared schema format
  • ➕ Can tailor APIs per language idioms
  • ➖ Duplicates vendor mapping logic across language repos
  • ➖ Harder to keep behavior consistent across bindings
  • ➖ Still needs a source of truth for vendor fields (effectively re-creating a vendor schema)

Recommendation: The chosen approach (provenance-tag vendor overlay fields during parse, then extract them into a schema vendor section) is the best tradeoff: it keeps the shared spec-derived schema and TS binding byte-identical while still enabling typed, browser-scoped APIs in downstream bindings. The added complexity is contained to the schema-generation pipeline and is backed by normalization + serialization tests.

Files changed (16) +569 / -77

Enhancement (9) +408 / -56
webdriver-bidi-1140.cddlAdd local CDDL override for webExtension.install extension point (#1140) +8/-0

Add local CDDL override for webExtension.install extension point (#1140)

• Introduces a temporary overlay redefining webExtension.InstallParameters to include an extensible extension-point group, matching the upstream W3C proposal.

common/bidi/webdriver-bidi-1140.cddl

webextension-install-extensions.cddlAdd Firefox moz: vendor overlay for webExtension.install options +7/-0

Add Firefox moz: vendor overlay for webExtension.install options

• Defines moz:allowPrivateBrowsing and moz:permanent as optional boolean fields added via '//=', pending upstream Mozilla/W3C merges.

common/bidi/webextension-install-extensions.cddl

generate_bidi.mjsAdd override/vendor AST paths and reconcile cddl2ts alias+interface output +151/-40

Add override/vendor AST paths and reconcile cddl2ts alias+interface output

• Adds CLI flags for override/vendor overlays, produces a vendor-free base AST for model/TS generation, and a schema-only AST with tagged vendor defs. Enhances TypeScript post-processing to merge duplicate declarations and fold type-alias + interface pairs into intersections so '//=' extensions don’t drop fields.

javascript/selenium-webdriver/generate_bidi.mjs

project_bidi_schema.mjsTag projected fields with vendor provenance and extract 'schema.vendor' +60/-2

Tag projected fields with vendor provenance and extract 'schema.vendor'

• Propagates vendor/via tags from AST properties into projected fields, then partitions vendor-tagged fields out of shared 'types' into a namespaced 'vendor' section while dropping empty anchor types.

javascript/selenium-webdriver/project_bidi_schema.mjs

web_extension.rbMake InstallParameters extensible and add WebExtension::Moz vendor install +25/-7

Make InstallParameters extensible and add WebExtension::Moz vendor install

• Moves InstallParameters definition, marks it 'extensible: true', and adds a Moz subclass overriding install to accept typed vendor args while emitting exact moz:* wire keys via the extensions bag.

rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb

bidi_generate.rbGenerate Ruby vendor subclasses from schema 'vendor' section +135/-2

Generate Ruby vendor subclasses from schema 'vendor' section

• Adds vendor-aware IR (VendorModule/VendorCommand), supports colon-containing wire keys in safe_field_name, and builds per-namespace vendor subclasses that override commands with typed vendor params routed through the extensions bag.

rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb

module.rb.erbEmit vendor subclasses into generated Ruby domain modules +4/-0

Emit vendor subclasses into generated Ruby domain modules

• Extends the Ruby module template to render vendor subclasses (e.g., Moz) after the base domain commands.

rb/lib/selenium/webdriver/bidi/support/templates/module.rb.erb

module.rbs.erbEmit RBS signatures for vendor subclasses and their methods +8/-0

Emit RBS signatures for vendor subclasses and their methods

• Adds RBS output for vendor subclasses inheriting from the base domain and declaring the vendor-extended command method signatures.

rb/lib/selenium/webdriver/bidi/support/templates/module.rbs.erb

web_extension.rbsUpdate WebExtension RBS for extensible params and Moz subclass +10/-5

Update WebExtension RBS for extensible params and Moz subclass

• Reflects InstallParameters having an extensions bag and adds the Moz subclass install signature with optional allow_private_browsing/permanent keywords.

rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs

Bug fix (1) +23 / -10
normalize_bidi_ast.mjsFold '//=' choice-additions during AST de-duplication +23/-10

Fold '//=' choice-additions during AST de-duplication

• Extends dedupeDefs to merge 'IsChoiceAddition' definitions into the retained base definition (without mutating inputs), ensuring extension-point groups resolve before later flattening steps.

javascript/selenium-webdriver/normalize_bidi_ast.mjs

Tests (3) +71 / -2
bidi_schema_diff_test.mjsHandle quoted interface keys when diffing generated TS types +5/-2

Handle quoted interface keys when diffing generated TS types

• Updates top-level field parsing to accept quoted property keys (e.g., "moz:permanent") so schema/TS diffs remain accurate when vendor-prefixed wire keys are present.

javascript/selenium-webdriver/bidi_schema_diff_test.mjs

normalize_bidi_ast_test.mjsAdd tests for dedupeDefs folding behavior +18/-0

Add tests for dedupeDefs folding behavior

• Adds coverage verifying '//=' choice additions are merged into the base group and that the merge is non-mutating.

javascript/selenium-webdriver/normalize_bidi_ast_test.mjs

serialization_spec.rbTest moz vendor install serialization and shared API neutrality +48/-0

Test moz vendor install serialization and shared API neutrality

• Adds unit tests ensuring moz vendor options serialize under exact moz:* wire keys, unset options are omitted, the shared install signature stays vendor-free, and unknown vendor keys pass through the extensible extensions bag.

rb/spec/unit/selenium/webdriver/bidi/serialization_spec.rb

Other (3) +67 / -9
BUILD.bazelExport local BiDi overlay CDDL files to JS package +4/-0

Export local BiDi overlay CDDL files to JS package

• Adds a Bazel BUILD file exporting all CDDL files under common/bidi with visibility limited to the JS BiDi generator package.

common/bidi/BUILD.bazel

BUILD.bazelWire override/vendor CDDL overlays into BiDi generation macro +10/-0

Wire override/vendor CDDL overlays into BiDi generation macro

• Configures generate_bidi_library with 'override_cddl_files' for the spec-shaped #1140 overlay and 'vendor_cddl_files' for Firefox moz vendor fields.

javascript/selenium-webdriver/BUILD.bazel

generate_bidi.bzlSplit base vs schema-only AST generation and add overlay inputs +53/-9

Split base vs schema-only AST generation and add overlay inputs

• Adds 'override_cddl_files' and 'vendor_cddl_files' to the macro. Generates a base AST (spec + overrides) used for model/TS, and an optional vendor-augmented AST used only for schema projection.

javascript/selenium-webdriver/private/generate_bidi.bzl

@qodo-code-review

qodo-code-review Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (2) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. for_moz lacks cross-binding parity 📘 Rule violation ≡ Correctness
Description
The PR exposes Firefox-specific webExtension.install options only in Ruby, while another binding
such as Java still sends only extensionData. This creates an unexplained user-visible binding
disparity.
Code

rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb[R109-115]

+            def install(extension_data:, allow_private_browsing: Serialization::UNSET, permanent: Serialization::UNSET)
+              extensions = {
+                'moz:allowPrivateBrowsing' => allow_private_browsing,
+                'moz:permanent' => permanent
+              }.reject { |_, value| Serialization::UNSET.equal?(value) }
+              params = InstallParameters.new(extension_data: extension_data, extensions: extensions)
+              execute(cmd: 'webExtension.install', params: params, result: WebExtension::InstallResult)
Evidence
PR Compliance ID 4 requires user-visible behavior to be consistent with at least one other language
binding. Ruby adds typed moz:allowPrivateBrowsing and moz:permanent support, whereas Java's
corresponding install implementation still serializes only parameters.getExtensionData().toMap().

AGENTS.md: Maintain Cross-Binding Consistency for User-Visible Behavior
rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb[109-121]
java/src/org/openqa/selenium/bidi/webextension/WebExtension.java[46-49]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Firefox-specific `webExtension.install` options are exposed only through Ruby's `WebExtension.for_moz` API, violating the cross-binding consistency requirement.

## Issue Context
Add equivalent typed, Firefox-scoped support to at least one other language binding while preserving its browser-neutral install API. Include focused serialization or command-construction tests for the exact `moz:` wire keys.

## Fix Focus Areas
- rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb[109-121]
- java/src/org/openqa/selenium/bidi/webextension/WebExtension.java[42-50]
- java/test/org/openqa/selenium/bidi/webextension/WebExtensionTest.java[43-53]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. extensions: RBS type tightened 📘 Rule violation ⚙ Maintainability ⭐ New
Description
Several generated RBS constructors change the extensions: keyword from untyped to `Hash[String,
untyped]`, which is a stricter public type signature and can break type-checked downstream code that
previously type-checked. If this is intended, it should be treated as a compatibility-impacting
change and called out explicitly for users.
Code

rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[60]

+            def self.new: (extension_data: ::Selenium::WebDriver::BiDi::Protocol::WebExtension::ExtensionData, ?extensions: Hash[String, untyped]) -> instance
Evidence
PR Compliance ID 1 requires preserving public signatures unless explicitly directed. The changed RBS
constructors now require extensions: to be a Hash[String, untyped] (previously untyped), which
is a user-visible signature tightening across multiple protocol types.

AGENTS.md: Maintain API/ABI Compatibility for Public Interfaces
rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[57-61]
rb/sig/lib/selenium/webdriver/bidi/protocol/session.rbs[41-42]
rb/sig/lib/selenium/webdriver/bidi/protocol/script.rbs[231-236]
rb/sig/lib/selenium/webdriver/bidi/protocol/storage.rbs[40-44]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR tightens multiple public RBS `extensions:` keyword argument types from `untyped` to `Hash[String, untyped]`. This is more correct but can be a breaking change for users relying on the previous (looser) typing.

## Issue Context
These signatures are part of the published Ruby typing surface (RBS). Tightening them may require an explicit changelog note (or an intentional compatibility strategy) to satisfy the repo's API/ABI-compatibility expectations.

## Fix Focus Areas
- rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[57-61]
- rb/sig/lib/selenium/webdriver/bidi/protocol/session.rbs[41-42]
- rb/sig/lib/selenium/webdriver/bidi/protocol/script.rbs[231-236]
- rb/sig/lib/selenium/webdriver/bidi/protocol/storage.rbs[40-44]
- rb/CHANGES[1-8]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Extensions kwarg too loose ✓ Resolved 🐞 Bug ≡ Correctness
Description
WebExtension::InstallParameters RBS declares the extensions: constructor kwarg as untyped, but
the extensible Serialization::Record implementation treats it as a Hash (calls empty? and
merge!). This can let type-checked callers pass non-Hash values that later crash during
serialization.
Code

rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[R57-61]

+          class InstallParameters < ::Selenium::WebDriver::BiDi::Serialization::Record
+            attr_reader extension_data: ::Selenium::WebDriver::BiDi::Protocol::WebExtension::ExtensionData
+            attr_reader extensions: Hash[String, untyped]
+            def self.new: (extension_data: ::Selenium::WebDriver::BiDi::Protocol::WebExtension::ExtensionData, ?extensions: untyped) -> instance
+          end
Evidence
The RBS currently allows extensions: to be any type, but Serialization::Record#as_json merges
extensions into a Hash payload and checks extensions.empty?, which requires extensions to be a
Hash-like object; passing a non-Hash can raise at runtime.

rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[57-61]
rb/lib/selenium/webdriver/bidi/serialization/record.rb[269-281]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The generated RBS for `WebExtension::InstallParameters` types `?extensions:` as `untyped`, even though the underlying extensible record implementation expects a Hash and uses Hash methods (`empty?`, `merge!`) during serialization.

### Issue Context
- The reader is already typed as `extensions: Hash[String, untyped]`, so the constructor kwarg should match.
- This should be fixed in the generator to prevent the issue from reappearing on regeneration.

### Fix Focus Areas
- rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[57-61]
- rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb[419-425]
- rb/lib/selenium/webdriver/bidi/serialization/record.rb[269-281]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Factory erases vendor type ✓ Resolved 🐞 Bug ≡ Correctness
Description
The generated for_moz signature returns plain WebExtension, so static type checkers cannot see
Moz#install and reject the new allow_private_browsing: and permanent: keywords. Runtime
composition works, but the typed API introduced by this PR does not.
Code

rb/lib/selenium/webdriver/bidi/support/templates/module.rbs.erb[80]

+          def self.for_<%= vendor_module.namespace %>: (untyped source) -> instance
Evidence
The base WebExtension#install signature accepts only extension_data, while the extra keywords
are declared exclusively in Moz; nevertheless, the factory is typed as returning only the
enclosing WebExtension instance even though runtime extends it with Moz.

rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[63-70]
rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb[101-121]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The generated vendor factory returns `instance` in RBS, which represents plain `WebExtension` and omits the dynamically applied `Moz` module. Consequently, typed callers cannot use the vendor-specific `install` keywords.

## Issue Context
Runtime returns `new(source).extend(Moz)`, while the generated signature returns only the enclosing class instance. Represent the return as an intersection or equivalent project-supported type containing both `WebExtension` and `Moz`, and add a signature/type-checking regression test.

## Fix Focus Areas
- rb/lib/selenium/webdriver/bidi/support/templates/module.rbs.erb[72-80]
- rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[63-70]
- rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb[101-121]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
5. Vendor fields pollute shared types ✓ Resolved 🐞 Bug ≡ Correctness
Description
The vendor-enriched AST is also passed directly to cddl2ts, which folds the moz: additions into
the browser-neutral generated TypeScript declarations. The schema projector’s vendor partitioning
never runs on this path, so shared package typings advertise Firefox-only parameters to all
consumers.
Code

javascript/selenium-webdriver/generate_bidi.mjs[R170-171]

+    const withVendor = applyVendor(withOverrides, args['vendor-cddl'] ?? [])
+    writeJson(args['dump-ast'], withVendor, 'ast')
Evidence
Bazel supplies the same AST target to the TypeScript generator, which calls transform(ast)
directly; only the separate schema projector removes vendor fields. The new reconciliation code then
preserves an extension alias and its added interface fields as one shared declaration.

javascript/selenium-webdriver/private/generate_bidi.bzl[252-275]
javascript/selenium-webdriver/generate_bidi.mjs[283-291]
javascript/selenium-webdriver/generate_bidi.mjs[420-437]
javascript/selenium-webdriver/project_bidi_schema.mjs[652-698]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The single generated AST contains vendor overlays and is reused by the direct TypeScript generation path. Since that path does not partition vendor-tagged fields, Firefox-only options are emitted into shared TypeScript declarations.

## Issue Context
`project_bidi_schema.mjs` extracts vendor fields into a separate schema section, but `generate_bidi.mjs` invokes `cddl2ts` directly on the enriched AST. Use a vendor-free AST for shared TypeScript generation, or explicitly filter/segregate tagged fields before transformation, and add a generated-output regression test.

## Fix Focus Areas
- javascript/selenium-webdriver/generate_bidi.mjs[168-171]
- javascript/selenium-webdriver/generate_bidi.mjs[283-291]
- javascript/selenium-webdriver/private/generate_bidi.bzl[252-275]
- javascript/selenium-webdriver/project_bidi_schema.mjs[652-698]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Previous review results

Review updated until commit f017ae8

Results up to commit f69c878 ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. for_moz lacks cross-binding parity 📘 Rule violation ≡ Correctness
Description
The PR exposes Firefox-specific webExtension.install options only in Ruby, while another binding
such as Java still sends only extensionData. This creates an unexplained user-visible binding
disparity.
Code

rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb[R109-115]

+            def install(extension_data:, allow_private_browsing: Serialization::UNSET, permanent: Serialization::UNSET)
+              extensions = {
+                'moz:allowPrivateBrowsing' => allow_private_browsing,
+                'moz:permanent' => permanent
+              }.reject { |_, value| Serialization::UNSET.equal?(value) }
+              params = InstallParameters.new(extension_data: extension_data, extensions: extensions)
+              execute(cmd: 'webExtension.install', params: params, result: WebExtension::InstallResult)
Evidence
PR Compliance ID 4 requires user-visible behavior to be consistent with at least one other language
binding. Ruby adds typed moz:allowPrivateBrowsing and moz:permanent support, whereas Java's
corresponding install implementation still serializes only parameters.getExtensionData().toMap().

AGENTS.md: Maintain Cross-Binding Consistency for User-Visible Behavior
rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb[109-121]
java/src/org/openqa/selenium/bidi/webextension/WebExtension.java[46-49]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Firefox-specific `webExtension.install` options are exposed only through Ruby's `WebExtension.for_moz` API, violating the cross-binding consistency requirement.

## Issue Context
Add equivalent typed, Firefox-scoped support to at least one other language binding while preserving its browser-neutral install API. Include focused serialization or command-construction tests for the exact `moz:` wire keys.

## Fix Focus Areas
- rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb[109-121]
- java/src/org/openqa/selenium/bidi/webextension/WebExtension.java[42-50]
- java/test/org/openqa/selenium/bidi/webextension/WebExtensionTest.java[43-53]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
2. Vendor fields pollute shared types ✓ Resolved 🐞 Bug ≡ Correctness
Description
The vendor-enriched AST is also passed directly to cddl2ts, which folds the moz: additions into
the browser-neutral generated TypeScript declarations. The schema projector’s vendor partitioning
never runs on this path, so shared package typings advertise Firefox-only parameters to all
consumers.
Code

javascript/selenium-webdriver/generate_bidi.mjs[R170-171]

+    const withVendor = applyVendor(withOverrides, args['vendor-cddl'] ?? [])
+    writeJson(args['dump-ast'], withVendor, 'ast')
Evidence
Bazel supplies the same AST target to the TypeScript generator, which calls transform(ast)
directly; only the separate schema projector removes vendor fields. The new reconciliation code then
preserves an extension alias and its added interface fields as one shared declaration.

javascript/selenium-webdriver/private/generate_bidi.bzl[252-275]
javascript/selenium-webdriver/generate_bidi.mjs[283-291]
javascript/selenium-webdriver/generate_bidi.mjs[420-437]
javascript/selenium-webdriver/project_bidi_schema.mjs[652-698]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The single generated AST contains vendor overlays and is reused by the direct TypeScript generation path. Since that path does not partition vendor-tagged fields, Firefox-only options are emitted into shared TypeScript declarations.

## Issue Context
`project_bidi_schema.mjs` extracts vendor fields into a separate schema section, but `generate_bidi.mjs` invokes `cddl2ts` directly on the enriched AST. Use a vendor-free AST for shared TypeScript generation, or explicitly filter/segregate tagged fields before transformation, and add a generated-output regression test.

## Fix Focus Areas
- javascript/selenium-webdriver/generate_bidi.mjs[168-171]
- javascript/selenium-webdriver/generate_bidi.mjs[283-291]
- javascript/selenium-webdriver/private/generate_bidi.bzl[252-275]
- javascript/selenium-webdriver/project_bidi_schema.mjs[652-698]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Factory erases vendor type ✓ Resolved 🐞 Bug ≡ Correctness
Description
The generated for_moz signature returns plain WebExtension, so static type checkers cannot see
Moz#install and reject the new allow_private_browsing: and permanent: keywords. Runtime
composition works, but the typed API introduced by this PR does not.
Code

rb/lib/selenium/webdriver/bidi/support/templates/module.rbs.erb[80]

+          def self.for_<%= vendor_module.namespace %>: (untyped source) -> instance
Evidence
The base WebExtension#install signature accepts only extension_data, while the extra keywords
are declared exclusively in Moz; nevertheless, the factory is typed as returning only the
enclosing WebExtension instance even though runtime extends it with Moz.

rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[63-70]
rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb[101-121]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The generated vendor factory returns `instance` in RBS, which represents plain `WebExtension` and omits the dynamically applied `Moz` module. Consequently, typed callers cannot use the vendor-specific `install` keywords.

## Issue Context
Runtime returns `new(source).extend(Moz)`, while the generated signature returns only the enclosing class instance. Represent the return as an intersection or equivalent project-supported type containing both `WebExtension` and `Moz`, and add a signature/type-checking regression test.

## Fix Focus Areas
- rb/lib/selenium/webdriver/bidi/support/templates/module.rbs.erb[72-80]
- rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[63-70]
- rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb[101-121]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 10dcc37 ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Extensions kwarg too loose ✓ Resolved 🐞 Bug ≡ Correctness
Description
WebExtension::InstallParameters RBS declares the extensions: constructor kwarg as untyped, but
the extensible Serialization::Record implementation treats it as a Hash (calls empty? and
merge!). This can let type-checked callers pass non-Hash values that later crash during
serialization.
Code

rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[R57-61]

+          class InstallParameters < ::Selenium::WebDriver::BiDi::Serialization::Record
+            attr_reader extension_data: ::Selenium::WebDriver::BiDi::Protocol::WebExtension::ExtensionData
+            attr_reader extensions: Hash[String, untyped]
+            def self.new: (extension_data: ::Selenium::WebDriver::BiDi::Protocol::WebExtension::ExtensionData, ?extensions: untyped) -> instance
+          end
Evidence
The RBS currently allows extensions: to be any type, but Serialization::Record#as_json merges
extensions into a Hash payload and checks extensions.empty?, which requires extensions to be a
Hash-like object; passing a non-Hash can raise at runtime.

rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[57-61]
rb/lib/selenium/webdriver/bidi/serialization/record.rb[269-281]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The generated RBS for `WebExtension::InstallParameters` types `?extensions:` as `untyped`, even though the underlying extensible record implementation expects a Hash and uses Hash methods (`empty?`, `merge!`) during serialization.

### Issue Context
- The reader is already typed as `extensions: Hash[String, untyped]`, so the constructor kwarg should match.
- This should be fixed in the generator to prevent the issue from reappearing on regeneration.

### Fix Focus Areas
- rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs[57-61]
- rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb[419-425]
- rb/lib/selenium/webdriver/bidi/serialization/record.rb[269-281]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

Comment thread rb/lib/selenium/webdriver/bidi/protocol/web_extension.rb
Comment thread rb/lib/selenium/webdriver/bidi/support/templates/module.rbs.erb Outdated
Comment thread javascript/selenium-webdriver/generate_bidi.mjs Outdated
@titusfortner
titusfortner marked this pull request as draft July 29, 2026 03:34
@titusfortner
titusfortner force-pushed the bidi-webextension-vendor-schema branch from f69c878 to 10dcc37 Compare July 29, 2026 13:11
@titusfortner
titusfortner marked this pull request as ready for review July 29, 2026 13:12
@titusfortner titusfortner changed the title Generate a vendor schema section so BiDi bindings can expose Firefox webExtension.install moz: options Merge vendor cddl files into shared BiDi schema and implement custom Firefox webExtension options Jul 29, 2026
Comment thread rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 10dcc37

Comment thread rb/sig/lib/selenium/webdriver/bidi/protocol/web_extension.rbs
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit f017ae8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-build Includes scripting, bazel and CI integrations B-devtools Includes everything BiDi or Chrome DevTools related B-support Issue or PR related to support classes C-nodejs JavaScript Bindings C-rb Ruby Bindings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants