Skip to content

[USP][QA] Gate the Dart/WASM boundary and fix subscribe signature drift #1153

Description

@DevenDucommun

Purpose

Protect the production Dart-to-JavaScript-to-WASM boundary on the usp branch. Canonical program tracking: https://github.com/linksys/qa-usp-automation/issues/10

Verified defect

The real usp_client.d.ts exports subscribe(subscription_id, path, notification_type), while lib/core/usp/web/usp_client_wasm.dart and the current Playwright mock expose only subscribe(subscriptionId). The mock agrees with the wrapper while both disagree with the real artifact.

Acceptance criteria

  • Decide whether the Dart binding is used: either fix wrapper, mock, and callers to the real 3-argument contract, or remove the dead binding
  • Vendor usp_client.d.ts beside the JS/WASM assets
  • Record the source usp_framework commit SHA and hashes for JS, WASM, and .d.ts
  • Add a boundary checker that compares Dart external bindings with the .d.ts surface, including method arity and compatible types
  • Report intentionally unbound TypeScript methods explicitly
  • Include a deliberate arity mismatch fixture proving the check fails
  • Run the check for pull requests and pushes targeting the usp branch
  • Regenerate or verify vendored artifacts in CI instead of relying only on manual copies

Related: https://github.com/linksys/qa-usp-automation/issues/12


Investigation (2026-07-17): the drifted binding is dead code

Verified on the usp branch. The app's subscriptions run through the hand-written UspClient (lib/core/usp/services/usp_client.dart) via client.subscribe<T>(...), which is SSE-backed (createNotifySubscription + an SSE delegate), as the generated providers in lib/generated/*.g.dart use. The hand-written UspClient delegates to the Wasm wrapper UspClientWeb for transport (get/set/add/delete/operate), but its subscription path is SSE, not the wrapper's subscribe.

The Wasm wrapper's UspClientWeb.subscribe(String subscriptionId) (lib/core/usp/web/usp_client_wasm.dart:133) has no external caller. Nothing invokes it. So the 1-arg vs 3-arg drift against the real .d.ts sits in unused code.

This resolves the "decide whether the Dart binding is used" item: it is not used. The fix is a UI-team API call, either:

  • Remove the dead subscribe/unsubscribe from UspClientWeb (plus the stub, the JS externals, and the Playwright mock). Cleanest. The boundary checker then lists .d.ts subscribe/unsubscribe as intentionally unbound.
  • Or correct them to the 3-arg .d.ts contract if the binding is meant to be wired up later.

QA-owned deliverable is unchanged: the boundary checker (parse the vendored .d.ts, assert every Dart external binding matches arity and types, report intentionally-unbound methods, include a deliberate-mismatch fixture that proves the check fails, run on usp PRs/pushes).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions