Skip to content

feat: USP M2 documentation, SSE improvements & FW team request - #686

Merged
AustinChangLinksys merged 1 commit into
dev-2.1.0from
feat/usp-sse-improvements
Mar 16, 2026
Merged

feat: USP M2 documentation, SSE improvements & FW team request#686
AustinChangLinksys merged 1 commit into
dev-2.1.0from
feat/usp-sse-improvements

Conversation

@AustinChangLinksys

Copy link
Copy Markdown
Collaborator

Summary

  • SSE subscription registry: Simplified to bridge-only flow — bridge auto-creates OBUSPA Device.LocalAgent.Subscription.{i}, removing the previous 5-step client-side workaround (USP Add + 4x Set)
  • Bridge API contract update: POST /api/v1/subscription now uses string-based NotifType + ReferenceList (replaced old type int + path string)
  • USP test console: Updated subscription UI to use new bridge API format
  • M2 Roadmap (roadmap_m2.md): Comprehensive gap analysis for remaining 27/72 JNAP features — prioritized across 4 phases (M2-A through M2-D) with dependency map
  • FW Team Request (fw-team-request.md): 26 issues across 3 tiers (Bug Fix / bbfdm Plugin / Vendor Extension) for firmware team action
  • WiFi channel-per-width: Downgraded FW-008 from P1→P2 — client-side computable using IEEE 802.11 bonding rules + existing channel_constants.dart logic
  • Doc updates: Translated all documentation to English, updated SSE implementation guide, issue index, and cross-references

Changed Files

Code (5 files)

  • lib/usp/models/sse_subscription_record.dart — Model field updates
  • lib/usp/services/sse_manager.dart — Manager wiring fix
  • lib/usp/services/sse_subscription_registry.dart — Bridge-only subscription flow
  • lib/usp/services/usp_bridge_client_web.dart — String-based API contract
  • lib/page/usp_test/test_console/views/usp_test_console_view.dart — Test UI updates

Documentation (9 files)

  • doc/usp/integration/roadmap_m2.mdNEW: M2 migration gap analysis (40 items, 10 sections)
  • doc/usp/issues/fw-team-request.mdNEW: FW team request (26 issues, 3 tiers)
  • doc/usp/integration/sse_implementation.md — Updated for bridge-only subscription
  • doc/usp/issues/INDEX.md — Added new doc references
  • doc/usp/issues/wifi-settings-tr181-limitations.md — ISS-1 channel-per-width update
  • Plus 4 other doc files with minor updates

Test plan

  • SSE subscription register/unregister verified on _bridge_sub_fixed.img
  • OperationComplete (Ping/TraceRoute) via SSE verified
  • ValueChange notification via SSE verified
  • Bootstrap purge cleans orphaned OBUSPA subscriptions
  • Idempotent re-register on reconnect verified

🤖 Generated with Claude Code

- Add M2 roadmap with full USP migration gap analysis
- Add FW team request document (26 issues across 3 tiers)
- Update WiFi TR-181 limitations with SSH verification data
- Update SSE manager with reconnect max retries and lifecycle-aware resume
- Update SSE subscription registry and bridge client
- Update router firmware bugs, subscription notification docs
- Update USP test console view
- Update feature roadmap and SSE implementation docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@AustinChangLinksys
AustinChangLinksys changed the base branch from dev-1.2.1 to dev-2.1.0 March 16, 2026 04:21
@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Comprehensive test modernization, view refactoring, and code quality improvements

✨ Enhancement 🧪 Tests 📦 Other

Grey Divider

Walkthroughs

Description
• **Test infrastructure modernization**: Refactored multiple test files
  (apps_and_gaming_view_test.dart, dashboard_home_view_test.dart, node_detail_view_test.dart,
  wifi_main_view_test.dart) to use centralized TestHelper class, reducing code duplication and
  improving maintainability
• **Golden file testing**: Introduced visual regression testing with goldenFilename parameter
  across test suite for consistent UI validation
• **View refactoring**: Extracted internet settings view into separate child views
  (Ipv4ConnectionView, Ipv6ConnectionView, ReleaseAndRenewView) with form provider-based
  validation, removing 1400+ lines of inline code
• **Model improvements**: Enhanced null-safety in wifi_item.dart with sensible defaults; migrated
  port range triggering rule state to use new PortRangeTriggeringRuleUIModel
• **Layout simplification**: Removed spinner overlay logic from root_container.dart and
  restructured from Stack to Column with SafeArea wrapper
• **Route additions**: Added new PnP add nodes route configuration with centered column layout
• **Code cleanup**: Removed unused imports, consolidated re-exports, and fixed
  formatting/indentation issues across multiple files
• **Test utilities**: Added Mockito specs for form validity notifiers used in internet settings
  validation
Diagram
flowchart LR
  TestHelper["TestHelper<br/>Centralized Setup"]
  OldTests["Old Mock-Based<br/>Tests"]
  NewTests["Modernized Tests<br/>with Golden Files"]
  
  InternetView["Internet Settings<br/>View"]
  ChildViews["IPv4/IPv6<br/>Child Views"]
  
  RootContainer["Root Container<br/>Layout"]
  SimplifiedLayout["Simplified Column<br/>Layout"]
  
  OldTests -- "Refactor" --> NewTests
  TestHelper -- "Powers" --> NewTests
  InternetView -- "Extract" --> ChildViews
  RootContainer -- "Simplify" --> SimplifiedLayout
Loading

Grey Divider

File Changes

1. test/page/advanced_settings/apps_and_gaming/views/localizations/apps_and_gaming_view_test.dart 🧪 Tests +728/-1301

Comprehensive test refactoring with TestHelper integration and golden files

• Refactored test setup to use centralized TestHelper class instead of individual mock
 declarations
• Replaced testableSingleRoute with testHelper.pumpView for simplified widget testing
• Added comprehensive test documentation with View ID APPGAM and 36 test cases mapped to specific
 scenarios
• Introduced switchToTab helper function for TabController-based tab navigation
• Updated test assertions to use testHelper.loc(context) for localization and added golden file
 references
• Replaced deprecated widget finders (AppDropdownButton, AppIPFormField, LinksysIcons.add)
 with new equivalents (AppDropdown, TextField, Key-based lookups)
• Consolidated mobile and desktop test variants with unified screen configuration

test/page/advanced_settings/apps_and_gaming/views/localizations/apps_and_gaming_view_test.dart


2. lib/page/wifi_settings/providers/wifi_item.dart ✨ Enhancement +36/-179

Null-safety improvements and factory constructor cleanup

• Removed fromRadio factory constructor that depended on RouterRadio model
• Added null-safety checks in fromMap factory for all map fields with sensible defaults
• Changed import from radio_info.dart to wifi_enums.dart and added re-export
• Enhanced robustness by providing default values (WifiRadioBand.radio_24, empty strings, etc.)
 when map values are null

lib/page/wifi_settings/providers/wifi_item.dart


3. lib/page/instant_device/providers/device_list_state.dart Miscellaneous +2/-171

Import cleanup and re-export consolidation

• Removed ignore_for_file comment and unused collection import
• Changed import from device_manager_state.dart to device_list_item.dart
• Added re-export of DeviceListItem for cleaner API surface

lib/page/instant_device/providers/device_list_state.dart


View more (110)
4. lib/route/route_pnp.dart ✨ Enhancement +12/-35

Add PnP add nodes route configuration

• Removed extra blank line after part of statement
• Added new nested route pnpAddNodes under pnpRoute with AddNodesView builder
• Configured route with noNaviRail: true and centered column layout (6 columns)
• Route accepts extra arguments passed as Map<String, dynamic>

lib/route/route_pnp.dart


5. lib/page/instant_admin/providers/manual_firmware_update_state.dart Formatting +4/-2

Code formatting and indentation fixes

• Fixed indentation in ManualUpdateRebooting.stop() method (aligned @override annotation)
• Improved code formatting in ManualFirmwareUpdateState.fromMap factory with multi-line
 null-coalescing for status field

lib/page/instant_admin/providers/manual_firmware_update_state.dart


6. test/page/dashboard/localizations/dashboard_home_view_test.dart 🧪 Tests +470/-1246

Dashboard home view test refactor with TestHelper and golden files

• Refactored test file from 1293 to 517 lines with comprehensive restructuring of dashboard home
 view tests
• Replaced old mock-based setup with new TestHelper utility for cleaner test infrastructure
• Introduced organized test cases with semantic IDs (DHOME-NOLAN_BASE, DHOME-VERT_BASE, etc.)
 covering 17 distinct scenarios
• Added helper methods (pumpDashboard, scrollToQuickPanel, toggleInstantPrivacy) for improved
 test code reusability
• Updated imports to use new provider paths and UI Kit library components
• Implemented golden file testing with goldenFilename parameter for visual regression testing

test/page/dashboard/localizations/dashboard_home_view_test.dart


7. test/page/nodes/localizations/node_detail_view_test.dart 🧪 Tests +246/-721

Node detail view test refactor with TestHelper and semantic IDs

• Reduced test file from 809 to 334 lines with significant simplification and restructuring
• Replaced manual mock setup with TestHelper utility class for consistent test infrastructure
• Introduced 6 semantic test IDs (NDVL-INFO, NDVL-MOBILE, NDVL-MLO, NDVL-LIGHTS, NDVL-EDIT,
 NDVL-EDIT_LONG) with clear documentation
• Added pumpNodeDetailView helper method to reduce boilerplate and improve test maintainability
• Updated imports to use new provider paths and UI Kit library components
• Implemented golden file testing with goldenFilename parameter for visual regression

test/page/nodes/localizations/node_detail_view_test.dart


8. lib/page/advanced_settings/apps_and_gaming/ports/providers/port_range_triggering_rule_state.dart ✨ Enhancement +14/-9

Port range triggering rule state model migration to UI model

• Updated import to use new UI model class PortRangeTriggeringRuleUIModel instead of core JNAP
 model
• Replaced all references to PortRangeTriggeringRule with PortRangeTriggeringRuleUIModel
 throughout the state class
• Updated rules list type and rule property to use the new UI model
• Reformatted code for improved readability with proper line breaks in factory methods and toString

lib/page/advanced_settings/apps_and_gaming/ports/providers/port_range_triggering_rule_state.dart


9. lib/page/advanced_settings/internet_settings/views/internet_settings_view.dart ✨ Enhancement +128/-1792

Refactor internet settings view with extracted child views

• Refactored view to extract IPv4, IPv6, and release/renew functionality into separate child views
 (Ipv4ConnectionView, Ipv6ConnectionView, ReleaseAndRenewView)
• Removed 1400+ lines of inline UI code and TextEditingController management, replacing with form
 provider-based validation
• Simplified state management by removing originalState tracking and initUI/resetUI methods in
 favor of notifier's revert() and isDirty() methods
• Updated imports to use new ui_kit_library components and form validation providers

lib/page/advanced_settings/internet_settings/views/internet_settings_view.dart


10. test/page/wifi_settings/views/localizations/wifi_main_view_test.dart 🧪 Tests +321/-688

Modernize WiFi main view tests with TestHelper pattern

• Migrated from legacy mock-based testing to new TestHelper pattern with centralized mock setup
• Replaced 793 lines of repetitive test code with 426 lines using parameterized testLocalizations
 helper
• Added comprehensive test IDs (WIFIS-ADV_VIEW, WIFIS-MLO_WARN, WIFIS-MAC_VIEW, etc.) with golden
 file references for screenshot testing
• Introduced getWifiBundleTestState() helper to construct test state with dirty/clean variants

test/page/wifi_settings/views/localizations/wifi_main_view_test.dart


11. lib/page/components/layouts/root_container.dart ✨ Enhancement +24/-38

Simplify root container layout and remove spinner overlay

• Removed rootProvider and rootConfig dependencies, eliminating spinner overlay logic
• Restructured layout from Stack to Column with SafeArea wrapper for remote read-only banner
• Added idleCheckerPauseProvider check to conditionally pause idle timeout
• Replaced OverlayInfoView debug panel with simplified conditional rendering

lib/page/components/layouts/root_container.dart


12. test/mocks/mockito_specs/internet_settings_form_notifier_spec.dart 🧪 Tests +7/-0

Add form validity notifier mock specifications

• New file: Added Mockito spec for form validity notifiers used in internet settings
• Defines mock specs for InternetSettingsIPv4FormValidityNotifier,
 InternetSettingsIPv6FormValidityNotifier, and OptionalSettingsFormValidityNotifier

test/mocks/mockito_specs/internet_settings_form_notifier_spec.dart


13. .agent/workflows/manual-testing.md Additional files +169/-0

...

.agent/workflows/manual-testing.md


14. .agent/workflows/review-screenshot-tests.md Additional files +142/-0

...

.agent/workflows/review-screenshot-tests.md


15. .agent/workflows/service-decoupling-audit.md Additional files +193/-0

...

.agent/workflows/service-decoupling-audit.md


16. .claude/commands/speckit.analyze.md Additional files +184/-0

...

.claude/commands/speckit.analyze.md


17. .claude/commands/speckit.checklist.md Additional files +294/-0

...

.claude/commands/speckit.checklist.md


18. .claude/commands/speckit.clarify.md Additional files +181/-0

...

.claude/commands/speckit.clarify.md


19. .claude/commands/speckit.constitution.md Additional files +82/-0

...

.claude/commands/speckit.constitution.md


20. .claude/commands/speckit.implement.md Additional files +135/-0

...

.claude/commands/speckit.implement.md


21. .claude/commands/speckit.plan.md Additional files +89/-0

...

.claude/commands/speckit.plan.md


22. .claude/commands/speckit.specify.md Additional files +258/-0

...

.claude/commands/speckit.specify.md


23. .claude/commands/speckit.tasks.md Additional files +137/-0

...

.claude/commands/speckit.tasks.md


24. .claude/commands/speckit.taskstoissues.md Additional files +30/-0

...

.claude/commands/speckit.taskstoissues.md


25. .claude/skills/generate-usp-yaml/SKILL.md Additional files +308/-0

...

.claude/skills/generate-usp-yaml/SKILL.md


26. .claude/skills/implement-feature-with-checks/SKILL.md Additional files +385/-0

...

.claude/skills/implement-feature-with-checks/SKILL.md


27. .fvmrc Additional files +3/-0

...

.fvmrc


28. .github/workflows/ci.yml Additional files +167/-0

...

.github/workflows/ci.yml


29. .github/workflows/deploy-demo.yml Additional files +90/-0

...

.github/workflows/deploy-demo.yml


30. .gitmodules Additional files +0/-3

...

.gitmodules


31. .metadata Additional files +30/-0

...

.metadata


32. .specify/memory/constitution.md Additional files +1093/-0

...

.specify/memory/constitution.md


33. .specify/scripts/bash/check-prerequisites.sh Additional files +166/-0

...

.specify/scripts/bash/check-prerequisites.sh


34. .specify/scripts/bash/common.sh Additional files +156/-0

...

.specify/scripts/bash/common.sh


35. .specify/scripts/bash/create-new-feature.sh Additional files +297/-0

...

.specify/scripts/bash/create-new-feature.sh


36. .specify/scripts/bash/setup-plan.sh Additional files +61/-0

...

.specify/scripts/bash/setup-plan.sh


37. .specify/scripts/bash/update-agent-context.sh Additional files +799/-0

...

.specify/scripts/bash/update-agent-context.sh


38. .specify/templates/agent-file-template.md Additional files +28/-0

...

.specify/templates/agent-file-template.md


39. .specify/templates/checklist-template.md Additional files +40/-0

...

.specify/templates/checklist-template.md


40. .specify/templates/plan-template.md Additional files +104/-0

...

.specify/templates/plan-template.md


41. .specify/templates/spec-template.md Additional files +115/-0

...

.specify/templates/spec-template.md


42. .specify/templates/tasks-template.md Additional files +251/-0

...

.specify/templates/tasks-template.md


43. .vscode/launch.json Additional files +32/-84

...

.vscode/launch.json


44. .windsurfrules Additional files +385/-0

...

.windsurfrules


45. AGENTS.md Additional files +29/-0

...

AGENTS.md


46. APPGAP_MAPPING.md Additional files +148/-0

...

APPGAP_MAPPING.md


47. CHANGELOG.md Additional files +340/-0

...

CHANGELOG.md


48. CLAUDE.md Additional files +174/-0

...

CLAUDE.md


49. README.md Additional files +137/-10

...

README.md


50. SCREENSHOT_TESTING.md Additional files +146/-0

...

SCREENSHOT_TESTING.md


51. TEST_CASES.md Additional files +381/-0

...

TEST_CASES.md


52. THEME.md Additional files +201/-0

...

THEME.md


53. android/app/google-services.json Additional files +0/-46

...

android/app/google-services.json


54. android/app/src/debug/AndroidManifest.xml Additional files +0/-7

...

android/app/src/debug/AndroidManifest.xml


55. android/app/src/main/AndroidManifest.xml Additional files +0/-73

...

android/app/src/main/AndroidManifest.xml


56. android/app/src/main/kotlin/com/linksys/moab/app/MainActivity.kt Additional files +0/-7

...

android/app/src/main/kotlin/com/linksys/moab/app/MainActivity.kt


57. android/app/src/main/res/drawable-night-v21/launch_background.xml Additional files +0/-9

...

android/app/src/main/res/drawable-night-v21/launch_background.xml


58. android/app/src/main/res/drawable-night/launch_background.xml Additional files +0/-9

...

android/app/src/main/res/drawable-night/launch_background.xml


59. android/app/src/main/res/drawable-v21/launch_background.xml Additional files +0/-9

...

android/app/src/main/res/drawable-v21/launch_background.xml


60. android/app/src/main/res/drawable/launch_background.xml Additional files +0/-9

...

android/app/src/main/res/drawable/launch_background.xml


61. android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml Additional files +0/-5

...

android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml


62. android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml Additional files +0/-5

...

android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml


63. android/app/src/main/res/values-night-v31/styles.xml Additional files +0/-21

...

android/app/src/main/res/values-night-v31/styles.xml


64. android/app/src/main/res/values-night/styles.xml Additional files +0/-21

...

android/app/src/main/res/values-night/styles.xml


65. android/app/src/main/res/values-v31/styles.xml Additional files +0/-21

...

android/app/src/main/res/values-v31/styles.xml


66. android/app/src/main/res/values/styles.xml Additional files +0/-21

...

android/app/src/main/res/values/styles.xml


67. android/app/src/main/res/xml/network_security_config.xml Additional files +0/-7

...

android/app/src/main/res/xml/network_security_config.xml


68. android/app/src/profile/AndroidManifest.xml Additional files +0/-7

...

android/app/src/profile/AndroidManifest.xml


69. android/gradle.properties Additional files +0/-3

...

android/gradle.properties


70. android/gradle/wrapper/gradle-wrapper.properties Additional files +0/-6

...

android/gradle/wrapper/gradle-wrapper.properties


71. android/project.properties Additional files +0/-4

...

android/project.properties


72. assets/a2ui/widgets/device_count.json Additional files +73/-0

...

assets/a2ui/widgets/device_count.json


73. assets/a2ui/widgets/guest_network.json Additional files +144/-0

...

assets/a2ui/widgets/guest_network.json


74. assets/a2ui/widgets/network_traffic.json Additional files +188/-0

...

assets/a2ui/widgets/network_traffic.json


75. assets/a2ui/widgets/node_count.json Additional files +74/-0

...

assets/a2ui/widgets/node_count.json


76. assets/a2ui/widgets/quick_actions.json Additional files +206/-0

...

assets/a2ui/widgets/quick_actions.json


77. assets/a2ui/widgets/router_control.json Additional files +203/-0

...

assets/a2ui/widgets/router_control.json


78. assets/a2ui/widgets/system_health.json Additional files +266/-0

...

assets/a2ui/widgets/system_health.json


79. assets/a2ui/widgets/wan_status.json Additional files +81/-0

...

assets/a2ui/widgets/wan_status.json


80. assets/agents/env.template Additional files +5/-0

...

assets/agents/env.template


81. assets/brand/meta.json Additional files +26/-0

...

assets/brand/meta.json


82. assets/resources/demo_cache_data.json Additional files +1580/-0

...

assets/resources/demo_cache_data.json


83. build_android.sh Additional files +0/-61

...

build_android.sh


84. build_ios.sh Additional files +0/-53

...

build_ios.sh


85. build_web.sh Additional files +10/-2

...

build_web.sh


86. clear_goldens.sh Additional files +30/-0

...

clear_goldens.sh


87. constitution.md Additional files +1162/-0

...

constitution.md


88. coverage/lcov.info Additional files +59460/-0

...

coverage/lcov.info


89. dart_test.yaml Additional files +2/-1

...

dart_test.yaml


90. definitions/admin/admin_users.yaml Additional files +23/-0

...

definitions/admin/admin_users.yaml


91. definitions/core/firmware_images.yaml Additional files +27/-0

...

definitions/core/firmware_images.yaml


92. definitions/core/system_info.yaml Additional files +51/-0

...

definitions/core/system_info.yaml


93. definitions/core/time_settings.yaml Additional files +40/-0

...

definitions/core/time_settings.yaml


94. definitions/core/vendor_log_files.yaml Additional files +22/-0

...

definitions/core/vendor_log_files.yaml


95. definitions/devices/connected_devices.yaml Additional files +58/-0

...

definitions/devices/connected_devices.yaml


96. definitions/devices/wifi_clients.yaml Additional files +58/-0

...

definitions/devices/wifi_clients.yaml


97. definitions/firewall/dmz.yaml Additional files +47/-0

...

definitions/firewall/dmz.yaml


98. definitions/firewall/firewall_chain_rules.yaml Additional files +31/-0

...

definitions/firewall/firewall_chain_rules.yaml


99. definitions/firewall/ipv6_port_service.yaml Additional files +70/-0

...

definitions/firewall/ipv6_port_service.yaml


100. definitions/firewall/port_forwarding.yaml Additional files +54/-0

...

definitions/firewall/port_forwarding.yaml


101. definitions/firewall/port_triggering.yaml Additional files +68/-0

...

definitions/firewall/port_triggering.yaml


102. definitions/network/dhcp_clients.yaml Additional files +33/-0

...

definitions/network/dhcp_clients.yaml


103. definitions/network/dhcp_reservations.yaml Additional files +26/-0

...

definitions/network/dhcp_reservations.yaml


104. definitions/network/ethernet_interfaces.yaml Additional files +41/-0

...

definitions/network/ethernet_interfaces.yaml


105. definitions/network/ipv6_settings.yaml Additional files +65/-0

...

definitions/network/ipv6_settings.yaml


106. definitions/network/lan_network_info.yaml Additional files +53/-0

...

definitions/network/lan_network_info.yaml


107. definitions/network/multi_interface_traffic_stats.yaml Additional files +87/-0

...

definitions/network/multi_interface_traffic_stats.yaml


108. definitions/network/static_routing.yaml Additional files +60/-0

...

definitions/network/static_routing.yaml


109. definitions/network/wan_operations.yaml Additional files +13/-0

...

definitions/network/wan_operations.yaml


110. definitions/network/wan_settings.yaml Additional files +189/-0

...

definitions/network/wan_settings.yaml


111. definitions/network/wan_status.yaml Additional files +30/-0

...

definitions/network/wan_status.yaml


112. definitions/network/wan_traffic_stats.yaml Additional files +25/-0

...

definitions/network/wan_traffic_stats.yaml


113. Additional files not shown Additional files +0/-0

...

Additional files not shown


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Mar 16, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (4) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Dart SDK minimum raised 📘 Rule violation ✓ Correctness
Description
pubspec.yaml now requires Dart >=3.3.0, which no longer matches the documented supported range
starting at >=3.0.0. This reduces compatibility for environments pinned to Dart 3.0–3.2.x.
Code

pubspec.yaml[R20-22]

environment:
-  sdk: ">=3.0.0 <4.0.0"
+  sdk: ">=3.3.0 <4.0.0"
  flutter: ">=3.3.0 <4.0.0"
Evidence
PR Compliance ID 1 requires Dart SDK constraints to be >=3.0.0 <4.0.0, but the PR changes the Dart
minimum to >=3.3.0 in pubspec.yaml.

CLAUDE.md
pubspec.yaml[20-22]

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 updates `pubspec.yaml` to require Dart SDK `&gt;=3.3.0`, which no longer matches the documented supported range requirement (`&gt;=3.0.0 &lt;4.0.0`).

## Issue Context
Compliance requires keeping SDK constraints aligned to the documented toolchain expectations.

## Fix Focus Areas
- pubspec.yaml[20-22]

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


2. pnpIspSettingsProvider outside lib/providers 📘 Rule violation ✓ Correctness
Description
A new Riverpod provider is introduced under lib/page/.../providers/ instead of lib/providers/.
This breaks the required provider placement convention and makes providers harder to discover
consistently.
Code

lib/page/instant_setup/troubleshooter/providers/pnp_isp_settings_provider.dart[R16-25]

+final pnpIspSettingsProvider =
+    NotifierProvider<PnpIspSettingsNotifier, PnpIspSettingsStatus>(
+  PnpIspSettingsNotifier.new,
+);
+
+class PnpIspSettingsNotifier extends Notifier<PnpIspSettingsStatus> {
+  @override
+  PnpIspSettingsStatus build() {
+    return PnpIspSettingsStatus.initial;
+  }
Evidence
PR Compliance ID 4 requires providers to live under lib/providers/, but this PR adds
pnpIspSettingsProvider in a feature subdirectory under lib/page/.../providers/.

CLAUDE.md
lib/page/instant_setup/troubleshooter/providers/pnp_isp_settings_provider.dart[16-25]

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

## Issue description
A new Riverpod provider (`pnpIspSettingsProvider`) was added under `lib/page/.../providers/` instead of the required `lib/providers/` directory.

## Issue Context
The repository compliance rule requires provider-based state management to be implemented/located under `lib/providers/` to keep providers centralized and discoverable.

## Fix Focus Areas
- lib/page/instant_setup/troubleshooter/providers/pnp_isp_settings_provider.dart[16-25]

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


3. Chinese comments in devices_filter_widget 📘 Rule violation ✓ Correctness
Description
New inline comments were added in Chinese in devices_filter_widget.dart. This violates the
English-only comment requirement for newly added/modified comments.
Code

lib/page/instant_device/views/devices_filter_widget.dart[R300-301]

+              // FilteredChipsWidget 的 onSelected 是 (item, isSelected)
+              // 這裡需要模擬原本的行為:如果狀態改變了才觸發
Evidence
PR Compliance ID 3 requires all new/modified comments to be English, but the PR adds Chinese inline
comments in this widget.

CLAUDE.md
lib/page/instant_device/views/devices_filter_widget.dart[296-304]

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

## Issue description
New inline comments were added in Chinese in `devices_filter_widget.dart`, which violates the English-only comment requirement.

## Issue Context
All newly added or modified comments must be written in English.

## Fix Focus Areas
- lib/page/instant_device/views/devices_filter_widget.dart[296-304]

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


View more (4)
4. JWT logged via SSE 🐞 Bug ⛨ Security
Description
UspBridgeClient emits a debug SSE event containing a substring of the JWT token, and
SseConnectionManager logs that debug payload. On web, debug-level logs are cached even outside
kDebugMode, so token material is retained in-memory and can be exposed via diagnostics/log export
paths.
Code

lib/usp/services/usp_bridge_client_web.dart[R126-135]

+    try {
+      final url = '$_baseUrl/api/v1/notifications';
+      debug('Fetching $url ...');
+
+      final token = _token;
+      debug('Token: ${token.substring(0, 20)}...(${token.length} chars)');
+
+      final headers = web.Headers();
+      headers.append('Authorization', 'Bearer $token');
+      headers.append('Accept', 'text/event-stream');
Evidence
The SSE client explicitly logs the bearer token substring; the connection manager writes these
_debug events to the app logger; and the logger implementation caches debug logs on web regardless
of kDebugMode (kDebugMode only controls console printing).

lib/usp/services/usp_bridge_client_web.dart[126-135]
lib/usp/services/sse_connection_manager.dart[165-169]
lib/core/utils/logger.dart[34-63]

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 SSE fetch path emits `_debug` events that include a substring of the bearer JWT, and those `_debug` messages are logged and cached on web.

### Issue Context
On web, debug-level logs are stored via `CustomOutput` even when not in debug mode; `kDebugMode` only controls console printing.

### Fix Focus Areas
- lib/usp/services/usp_bridge_client_web.dart[120-135]
- lib/usp/services/sse_connection_manager.dart[165-169]
- lib/core/utils/logger.dart[34-63]

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


5. Heartbeat watchdog not reset 🐞 Bug ⛯ Reliability
Description
SseConnectionManager.connect() cancels only the stream subscription but leaves any existing
heartbeat watchdog timer active. A stale watchdog can fire after a reconnect and cancel a healthy
new SSE stream, forcing unnecessary disconnect/reconnect loops.
Code

lib/usp/services/sse_connection_manager.dart[R77-99]

+  /// Opens the SSE connection. Safe to call multiple times — disconnects
+  /// any existing connection first.
+  Future<void> connect() async {
+    if (_disposed) return;
+
+    await _cancelExistingStream();
+    _intentionalDisconnect = false;
+    connectionState.value = SseConnectionState.connecting;
+
+    logger.d('[SSE] Connecting...');
+
+    try {
+      final stream = _bridge.notifications();
+      _sseSubscription = stream.listen(
+        _onEvent,
+        onError: _onError,
+        onDone: _onDone,
+      );
+    } catch (e) {
+      logger.w('[SSE] Failed to open stream: $e');
+      _scheduleReconnect();
+    }
+  }
Evidence
connect() is documented as safe to call multiple times but does not cancel the watchdog timer, while
disconnect() does; the watchdog cancels the stream when it fires.

lib/usp/services/sse_connection_manager.dart[77-99]
lib/usp/services/sse_connection_manager.dart[101-107]
lib/usp/services/sse_connection_manager.dart[210-217]

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

### Issue description
`connect()` does not cancel an existing heartbeat watchdog timer, so an old timer may cancel a new stream.

### Issue Context
`disconnect()` explicitly cancels `_heartbeatWatchdog`, indicating the timer is intended to be tied to a single stream lifecycle.

### Fix Focus Areas
- lib/usp/services/sse_connection_manager.dart[77-114]
- lib/usp/services/sse_connection_manager.dart[203-217]

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


6. Resubscribe map mutation crash 🐞 Bug ⛯ Reliability
Description
SseSubscriptionRegistry.resubscribeAll iterates over _subscriptions.values while awaiting network
calls, so concurrent register/unregister can mutate the map mid-iteration and throw
ConcurrentModificationError. This is made more likely because SseManager triggers resubscribeAll on
connect without awaiting it.
Code

lib/usp/services/sse_subscription_registry.dart[R95-117]

+  Future<void> resubscribeAll() async {
+    if (_subscriptions.isEmpty) {
+      logger
+          .d('[SSE Registry] resubscribeAll: no subscriptions to re-register');
+      return;
+    }
+
+    logger.d('[SSE Registry] Re-registering ${_subscriptions.length} '
+        'subscriptions on bridge');
+
+    for (final record in _subscriptions.values) {
+      try {
+        await _bridge.subscribe(
+          subscriptionId: record.subscriptionId,
+          path: record.referenceList,
+          notifType: _notifTypeToInt(record.notifType),
+        );
+        logger.d('[SSE Registry] Re-registered ${record.subscriptionId}');
+      } catch (e) {
+        logger.w('[SSE Registry] Failed to re-register '
+            '${record.subscriptionId}: $e');
+      }
+    }
Evidence
resubscribeAll iterates over a live view of the map; register/unregister mutate the same map; and
SseManager starts resubscribeAll asynchronously (not awaited), increasing overlap likelihood during
reconnects.

lib/usp/services/sse_subscription_registry.dart[95-117]
lib/usp/services/sse_subscription_registry.dart[36-74]
lib/usp/services/sse_manager.dart[53-57]

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

### Issue description
`resubscribeAll()` iterates a mutable map view while awaited calls run; concurrent mutations can throw and abort resubscription.

### Issue Context
`SseManager` triggers resubscribe asynchronously on connect, which can overlap with normal subscribe/unsubscribe activity.

### Fix Focus Areas
- lib/usp/services/sse_subscription_registry.dart[32-67]
- lib/usp/services/sse_subscription_registry.dart[95-117]
- lib/usp/services/sse_manager.dart[52-57]

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


7. Bootstrap purges all subscriptions 🐞 Bug ✓ Correctness
Description
sseBootstrapProvider calls purgeAllSubscriptions on shell render, and purgeAllSubscriptions deletes
every Device.LocalAgent.Subscription.{i} instance it finds without filtering by
Recipient/ownership. This can remove subscriptions created by other controllers (the codebase
explicitly notes recipients are controller-specific), breaking other active sessions.
Code

lib/usp/providers/sse_providers.dart[R83-93]

+  // Step 1: Purge stale OBUSPA subscriptions from previous sessions.
+  // Browser refresh doesn't trigger dispose(), so old subscriptions
+  // accumulate on the router and cause duplicate SSE notifications.
+  try {
+    final purged = await usp.purgeAllSubscriptions();
+    if (purged > 0) {
+      logger.d('[SSE Bootstrap] Purged $purged stale OBUSPA subscriptions');
+    }
+  } catch (e) {
+    logger.w('[SSE Bootstrap] Failed to purge stale subscriptions: $e');
+  }
Evidence
Bootstrap always invokes purgeAllSubscriptions after login; purgeAllSubscriptions enumerates
subscription instance IDs and deletes them all; and UspService documents that subscriptions are tied
to a calling Controller (Recipient), implying multiple controllers can coexist and be impacted by
unfiltered deletion.

lib/usp/providers/sse_providers.dart[83-93]
lib/usp/services/usp_service.dart[496-542]
lib/usp/services/usp_service.dart[366-372]

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

### Issue description
Startup bootstrap deletes *all* OBUSPA subscriptions on the router, not just ones created by this app, because purgeAllSubscriptions does not filter by Recipient/ownership.

### Issue Context
The codebase documents that subscriptions are associated with a calling Controller via the `Recipient` field.

### Fix Focus Areas
- lib/usp/providers/sse_providers.dart[83-93]
- lib/usp/services/usp_service.dart[485-543]
- lib/usp/services/usp_service.dart[366-372]

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



Remediation recommended

8. assets/agents nonstandard asset 📘 Rule violation ✓ Correctness
Description
The PR introduces a new asset directory assets/agents/ and includes it in pubspec.yaml, which
falls outside the documented asset layout (icons/resources). This may make asset organization
inconsistent unless the documented structure is updated accordingly.
Code

pubspec.yaml[R128-131]

  assets:
+    - assets/agents/
    - assets/icons/
    - assets/resources/
Evidence
PR Compliance ID 6 requires assets to follow the documented layout (e.g., icons under
assets/icons/, resources under assets/resources/), but the PR adds and registers a new
assets/agents/ directory.

CLAUDE.md
pubspec.yaml[128-131]
assets/agents/env.template[1-5]

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

## Issue description
A new asset directory `assets/agents/` is added and registered in `pubspec.yaml`, which may not follow the documented asset layout expectations.

## Issue Context
Compliance expects assets to be organized under documented directories (e.g., `assets/icons/`, `assets/resources/`). Introducing new asset roots should follow established conventions or be documented.

## Fix Focus Areas
- pubspec.yaml[128-131]
- assets/agents/env.template[1-5]

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


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines 95 to 117
@@ -153,12 +113,11 @@ class SseSubscriptionRegistry {
} catch (e) {
logger.w('[SSE Registry] Failed to re-register '
'${record.subscriptionId}: $e');
// Non-fatal: continue with remaining subscriptions
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

6. Resubscribe map mutation crash 🐞 Bug ⛯ Reliability

SseSubscriptionRegistry.resubscribeAll iterates over _subscriptions.values while awaiting network
calls, so concurrent register/unregister can mutate the map mid-iteration and throw
ConcurrentModificationError. This is made more likely because SseManager triggers resubscribeAll on
connect without awaiting it.
Agent Prompt
### Issue description
`resubscribeAll()` iterates a mutable map view while awaited calls run; concurrent mutations can throw and abort resubscription.

### Issue Context
`SseManager` triggers resubscribe asynchronously on connect, which can overlap with normal subscribe/unsubscribe activity.

### Fix Focus Areas
- lib/usp/services/sse_subscription_registry.dart[32-67]
- lib/usp/services/sse_subscription_registry.dart[95-117]
- lib/usp/services/sse_manager.dart[52-57]

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

@AustinChangLinksys
AustinChangLinksys merged commit e695ab6 into dev-2.1.0 Mar 16, 2026
2 checks passed
@AustinChangLinksys
AustinChangLinksys deleted the feat/usp-sse-improvements branch March 16, 2026 04:56
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.

2 participants