Skip to content

feat(small): Fix Bluetooth Auto-Connect Race Condition and Overlapping Connections#9315

Draft
arii wants to merge 2 commits intoleaderfrom
fix-bluetooth-auto-connect-race-17140583504697442733
Draft

feat(small): Fix Bluetooth Auto-Connect Race Condition and Overlapping Connections#9315
arii wants to merge 2 commits intoleaderfrom
fix-bluetooth-auto-connect-race-17140583504697442733

Conversation

@arii
Copy link
Owner

@arii arii commented Feb 25, 2026

Description

Fixed race conditions and logic failures in the Bluetooth connection flow. Specifically:

  1. Guarded auto-connect triggers with a check for the hrm_device_id cookie to prevent "No saved device ID" errors and UI flickering.
  2. Implemented an isConnecting ref guard in the useBluetoothHRM hook to prevent overlapping connection attempts and GATT handshake collisions.
  3. Enhanced UX/Accessibility by adding ARIA attributes (role="status", aria-live="polite", aria-busy) to signal connection state changes to screen readers.

Fixes #9303

Change Type: 🐛 Bug fix (non-breaking change fixing an issue)

Changes Made

  • Guarded auto-connect triggers with a check for the hrm_device_id cookie to prevent "No saved device ID" errors and UI flickering.
  • Implemented an isConnecting ref guard in the useBluetoothHRM hook to prevent overlapping connection attempts and GATT handshake collisions.
  • Enhanced UX/Accessibility by adding ARIA attributes (role="status", aria-live="polite", aria-busy) to signal connection state changes to screen readers.

Testing

Verified that all existing Playwright tests and Visual Regression Tests pass.

Related Issues

Closes #9303

Original PR Body

Fixed race conditions and logic failures in the Bluetooth connection flow. Specifically:

  1. Guarded auto-connect triggers with a check for the hrm_device_id cookie to prevent "No saved device ID" errors and UI flickering.
  2. Implemented an isConnecting ref guard in the useBluetoothHRM hook to prevent overlapping connection attempts and GATT handshake collisions.
  3. Enhanced UX/Accessibility by adding ARIA attributes (role="status", aria-live="polite", aria-busy) to signal connection state changes to screen readers.
  4. Verified that all existing Playwright tests and Visual Regression Tests pass.

Fixes #9303


PR created automatically by Jules for task 17140583504697442733 started by @arii

@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@github-actions github-actions bot changed the title Fix Bluetooth Auto-Connect Race Condition and Overlapping Connections feat(small): Fix Bluetooth Auto-Connect Race Condition and Overlapping Connections Feb 25, 2026
@arii
Copy link
Owner Author

arii commented Feb 25, 2026

Reviewed commit: 4ab363a4935577c55477f4a3c6d974208a46e182

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connections. The changes are well-implemented and demonstrate a clear understanding of the problem.

Key improvements:

  • Race Condition Fix: The isConnecting check has been correctly centralized within connectAndStream in useBluetoothHRM.ts, preventing multiple concurrent connection attempts. The finally block ensures isConnecting is reset reliably.
  • Improved Auto-Connect Logic: The autoConnect function now correctly checks for a savedDeviceId via js-cookie before attempting to connect, preventing unnecessary connection attempts when no device is configured.
  • Enhanced UI Feedback: The ConnectView.tsx component now includes role="status", aria-live="polite", and aria-busy attributes, significantly improving accessibility for users relying on screen readers during connection status updates.
  • Robust Error Handling: The connectAndStream function now explicitly resets the connection status and custom message before throwing errors, ensuring the UI accurately reflects the disconnected state.
  • Test Coverage: The unit test useBluetoothHRM.race.test.ts has been updated to correctly assert that subsequent connection attempts are blocked, validating the race condition fix.

The documentation changes are minor formatting adjustments and do not introduce any new issues.

Reviewed at commit: 4ab363a4935577c55477f4a3c6d974208a46e182

@arii arii added bug Something isn't working refactor frontend-improvement documentation Improvements or additions to documentation labels Feb 25, 2026
@google-labs-jules
Copy link
Contributor

Reviewed commit: 4ab363a4935577c55477f4a3c6d974208a46e182

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connections. The changes are well-implemented and demonstrate a clear understanding of the problem.

Key improvements:

  • Race Condition Fix: The isConnecting check has been correctly centralized within connectAndStream in useBluetoothHRM.ts, preventing multiple concurrent connection attempts. The finally block ensures isConnecting is reset reliably.
  • Improved Auto-Connect Logic: The autoConnect function now correctly checks for a savedDeviceId via js-cookie before attempting to connect, preventing unnecessary connection attempts when no device is configured.
  • Enhanced UI Feedback: The ConnectView.tsx component now includes role="status", aria-live="polite", and aria-busy attributes, significantly improving accessibility for users relying on screen readers during connection status updates.
  • Robust Error Handling: The connectAndStream function now explicitly resets the connection status and custom message before throwing errors, ensuring the UI accurately reflects the disconnected state.
  • Test Coverage: The unit test useBluetoothHRM.race.test.ts has been updated to correctly assert that subsequent connection attempts are blocked, validating the race condition fix.

The documentation changes are minor formatting adjustments and do not introduce any new issues.

Reviewed at commit: 4ab363a4935577c55477f4a3c6d974208a46e182

Thank you for the detailed review! I'm glad the fixes and accessibility improvements are well-received. Acknowledged.

@arii
Copy link
Owner Author

arii commented Feb 25, 2026

Reviewed commit: 3e29146ede82781cc2f977cd5102b1d12e6ddebd

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connection attempts. The changes in useBluetoothHRM.ts correctly implement a guard against concurrent connection attempts by moving the isConnecting check to the connectAndStream entry point and ensuring the flag is reset in a finally block. This prevents multiple connection processes from running simultaneously, which was the root cause of the race condition.

The addition of js-cookie in app/client/connect/page.tsx for persisting the hrm_device_id is a practical solution for enabling reliable auto-reconnection. The autoConnect function now correctly leverages this saved ID.

Accessibility improvements in ConnectView.tsx with the addition of role="status", aria-live="polite", and aria-busy are excellent additions, enhancing the user experience for assistive technologies and aligning with the project's DESIGN_GUIDELINES.md.

The unit test in useBluetoothHRM.race.test.ts has been appropriately updated to reflect the new, correct behavior where only one connection attempt succeeds during a race condition.

Minor documentation formatting fixes in docs/TYPESCRIPT_PATTERNS.md and docs/audits/AUDIT_CODE_HYGIENE.md are also a welcome touch, improving overall code hygiene.

Reviewed at commit: 3e29146ede82781cc2f977cd5102b1d12e6ddebd

@google-labs-jules
Copy link
Contributor

Reviewed commit: 3e29146ede82781cc2f977cd5102b1d12e6ddebd

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connection attempts. The changes in useBluetoothHRM.ts correctly implement a guard against concurrent connection attempts by moving the isConnecting check to the connectAndStream entry point and ensuring the flag is reset in a finally block. This prevents multiple connection processes from running simultaneously, which was the root cause of the race condition.

The addition of js-cookie in app/client/connect/page.tsx for persisting the hrm_device_id is a practical solution for enabling reliable auto-reconnection. The autoConnect function now correctly leverages this saved ID.

Accessibility improvements in ConnectView.tsx with the addition of role="status", aria-live="polite", and aria-busy are excellent additions, enhancing the user experience for assistive technologies and aligning with the project's DESIGN_GUIDELINES.md.

The unit test in useBluetoothHRM.race.test.ts has been appropriately updated to reflect the new, correct behavior where only one connection attempt succeeds during a race condition.

Minor documentation formatting fixes in docs/TYPESCRIPT_PATTERNS.md and docs/audits/AUDIT_CODE_HYGIENE.md are also a welcome touch, improving overall code hygiene.

Reviewed at commit: 3e29146ede82781cc2f977cd5102b1d12e6ddebd

Thank you for the review and the positive feedback! I'm glad to hear the race condition fix and accessibility improvements meet the project standards. Acknowledged.

@arii
Copy link
Owner Author

arii commented Feb 25, 2026

Reviewed commit: f285a39a90a2da681d6acbc6ec4bcc37ea8b33a0

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connection issues. The changes to useBluetoothHRM.ts correctly implement a guard using isConnecting.current to prevent multiple concurrent connection attempts, and the finally block ensures the connection state is always reset. The error handling for silent auto-connects is also improved by explicitly resetting the UI status.

The accessibility enhancements in ConnectView.tsx by adding role="status", aria-live="polite", and aria-busy are excellent additions, improving the user experience for assistive technologies.

The update to the unit test useBluetoothHRM.race.test.ts to expect false for the second concurrent connection attempt correctly validates the new behavior and confirms the fix.

Overall, the changes are well-reasoned, correctly implemented, and improve the stability and accessibility of the connection process.

Reviewed at commit: f285a39a90a2da681d6acbc6ec4bcc37ea8b33a0

@google-labs-jules
Copy link
Contributor

Reviewed commit: f285a39a90a2da681d6acbc6ec4bcc37ea8b33a0

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connection issues. The changes to useBluetoothHRM.ts correctly implement a guard using isConnecting.current to prevent multiple concurrent connection attempts, and the finally block ensures the connection state is always reset. The error handling for silent auto-connects is also improved by explicitly resetting the UI status.

The accessibility enhancements in ConnectView.tsx by adding role="status", aria-live="polite", and aria-busy are excellent additions, improving the user experience for assistive technologies.

The update to the unit test useBluetoothHRM.race.test.ts to expect false for the second concurrent connection attempt correctly validates the new behavior and confirms the fix.

Overall, the changes are well-reasoned, correctly implemented, and improve the stability and accessibility of the connection process.

Reviewed at commit: f285a39a90a2da681d6acbc6ec4bcc37ea8b33a0

Thank you for the review! I'm glad to hear the improvements to stability and accessibility are verified. Acknowledged.

@arii
Copy link
Owner Author

arii commented Feb 25, 2026

Reviewed commit: 4670b8638ff8b4968cd7e1f730ef58a547844c3e

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connections. The introduction of the isConnecting flag in useBluetoothHRM.ts and its consistent management across connectAndStream and autoConnect functions is a robust solution.

Key improvements:

  • Race Condition Prevention: The isConnecting guard ensures that only one connection attempt is active at a time, preventing multiple concurrent GATT connections.
  • Robust Error Handling: The finally block in connectAndStream guarantees that isConnecting is reset, and the status is correctly updated on connection failures, improving UI consistency.
  • Targeted Auto-Connect: The autoConnect logic now correctly checks for a savedDeviceId before attempting a connection, reducing unnecessary operations.
  • Accessibility Enhancements: The addition of role="status", aria-live="polite", and aria-busy attributes to the connection status alert and button in ConnectView.tsx significantly improves the user experience for assistive technologies, aligning with the project's Design Guidelines.
  • Test Coverage: The unit test useBluetoothHRM.race.test.ts has been correctly updated to reflect the new behavior, asserting that concurrent connection attempts are now rejected.

The documentation updates are minor but helpful.

Overall, this is a well-implemented fix that improves stability and accessibility.

Reviewed at commit: 4670b8638ff8b4968cd7e1f730ef58a547844c3e

@google-labs-jules
Copy link
Contributor

Reviewed commit: 4670b8638ff8b4968cd7e1f730ef58a547844c3e

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connections. The introduction of the isConnecting flag in useBluetoothHRM.ts and its consistent management across connectAndStream and autoConnect functions is a robust solution.

Key improvements:

  • Race Condition Prevention: The isConnecting guard ensures that only one connection attempt is active at a time, preventing multiple concurrent GATT connections.
  • Robust Error Handling: The finally block in connectAndStream guarantees that isConnecting is reset, and the status is correctly updated on connection failures, improving UI consistency.
  • Targeted Auto-Connect: The autoConnect logic now correctly checks for a savedDeviceId before attempting a connection, reducing unnecessary operations.
  • Accessibility Enhancements: The addition of role="status", aria-live="polite", and aria-busy attributes to the connection status alert and button in ConnectView.tsx significantly improves the user experience for assistive technologies, aligning with the project's Design Guidelines.
  • Test Coverage: The unit test useBluetoothHRM.race.test.ts has been correctly updated to reflect the new behavior, asserting that concurrent connection attempts are now rejected.

The documentation updates are minor but helpful.

Overall, this is a well-implemented fix that improves stability and accessibility.

Reviewed at commit: 4670b8638ff8b4968cd7e1f730ef58a547844c3e

Thank you for the review and the detailed feedback! I'm glad the fixes for the race condition and the accessibility improvements are working as expected. Acknowledged.

@arii
Copy link
Owner Author

arii commented Feb 25, 2026

Reviewed commit: 08439289139655ce246326a86b4ebb74174b82ae

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connections. The introduction of a robust isConnecting guard in connectAndStream and its proper reset in the finally block is a solid solution. The logic for only attempting auto-connect if a hrm_device_id cookie exists is a good enhancement for user experience and resource management.

Key Improvements:

  • Race Condition Fix: The isConnecting flag is now correctly managed to prevent multiple concurrent connection attempts, as verified by the updated unit test.
  • Improved Auto-Connect Logic: Auto-connect now intelligently checks for a saved device ID, preventing unnecessary connection attempts.
  • Enhanced Error Handling: The setStatus and setCustomStatusMessage resets in the catch blocks ensure the UI accurately reflects connection failures, preventing a stuck 'connecting' state.
  • Accessibility: The addition of role="status", aria-live="polite", and aria-busy attributes to the connection status alert and button significantly improves accessibility for users relying on screen readers.
  • Code Clarity: The refactoring of the isConnecting guard from connectToGatt to connectAndStream centralizes the connection initiation logic, making it easier to understand and maintain.

Overall, this is a well-implemented fix that improves both the stability and accessibility of the Bluetooth connection feature.

Reviewed at commit: 08439289139655ce246326a86b4ebb74174b82ae

@google-labs-jules
Copy link
Contributor

Reviewed commit: 08439289139655ce246326a86b4ebb74174b82ae

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connections. The introduction of a robust isConnecting guard in connectAndStream and its proper reset in the finally block is a solid solution. The logic for only attempting auto-connect if a hrm_device_id cookie exists is a good enhancement for user experience and resource management.

Key Improvements:

  • Race Condition Fix: The isConnecting flag is now correctly managed to prevent multiple concurrent connection attempts, as verified by the updated unit test.
  • Improved Auto-Connect Logic: Auto-connect now intelligently checks for a saved device ID, preventing unnecessary connection attempts.
  • Enhanced Error Handling: The setStatus and setCustomStatusMessage resets in the catch blocks ensure the UI accurately reflects connection failures, preventing a stuck 'connecting' state.
  • Accessibility: The addition of role="status", aria-live="polite", and aria-busy attributes to the connection status alert and button significantly improves accessibility for users relying on screen readers.
  • Code Clarity: The refactoring of the isConnecting guard from connectToGatt to connectAndStream centralizes the connection initiation logic, making it easier to understand and maintain.

Overall, this is a well-implemented fix that improves both the stability and accessibility of the Bluetooth connection feature.

Reviewed at commit: 08439289139655ce246326a86b4ebb74174b82ae

Thank you for the detailed review and the positive feedback! I'm glad to see that the fixes and enhancements are well-received and improve the project's stability and accessibility. Acknowledged.

@arii
Copy link
Owner Author

arii commented Feb 25, 2026

Reviewed commit: 8ca4ce86a69c9b3d37b51684a9132430133ab911

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connections. The changes are well-implemented and demonstrate a clear understanding of the problem.

Key improvements include:

  • Centralized Race Condition Guard: The isConnecting flag is now correctly managed within the connectAndStream function in hooks/useBluetoothHRM.ts, serving as the primary entry point for connection attempts. This prevents multiple concurrent connection processes.
  • Robust State Management: The isConnecting flag is now set at the beginning of connectAndStream and reliably reset in a finally block, ensuring the UI accurately reflects the connection status regardless of success or failure.
  • Optimized Auto-Connect Logic: The autoConnect function and the useEffect in app/client/connect/page.tsx now explicitly check for a savedDeviceId using js-cookie before attempting an auto-connection. This prevents unnecessary connection attempts when no device has been previously paired.
  • Accessibility Enhancements: Added role="status", aria-live="polite", and aria-busy attributes to the connection status Alert and Button in app/client/connect/ConnectView.tsx, improving the experience for users of assistive technologies.
  • Updated Unit Tests: The unit test tests/unit/hooks/useBluetoothHRM.race.test.ts has been correctly updated to assert that concurrent connectAndStream calls are now skipped, verifying the race condition fix.

The minor documentation changes are also appropriate. Overall, this is a high-quality fix.

Reviewed at commit: 8ca4ce86a69c9b3d37b51684a9132430133ab911

@google-labs-jules
Copy link
Contributor

Reviewed commit: 8ca4ce86a69c9b3d37b51684a9132430133ab911

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connections. The changes are well-implemented and demonstrate a clear understanding of the problem.

Key improvements include:

  • Centralized Race Condition Guard: The isConnecting flag is now correctly managed within the connectAndStream function in hooks/useBluetoothHRM.ts, serving as the primary entry point for connection attempts. This prevents multiple concurrent connection processes.
  • Robust State Management: The isConnecting flag is now set at the beginning of connectAndStream and reliably reset in a finally block, ensuring the UI accurately reflects the connection status regardless of success or failure.
  • Optimized Auto-Connect Logic: The autoConnect function and the useEffect in app/client/connect/page.tsx now explicitly check for a savedDeviceId using js-cookie before attempting an auto-connection. This prevents unnecessary connection attempts when no device has been previously paired.
  • Accessibility Enhancements: Added role="status", aria-live="polite", and aria-busy attributes to the connection status Alert and Button in app/client/connect/ConnectView.tsx, improving the experience for users of assistive technologies.
  • Updated Unit Tests: The unit test tests/unit/hooks/useBluetoothHRM.race.test.ts has been correctly updated to assert that concurrent connectAndStream calls are now skipped, verifying the race condition fix.

The minor documentation changes are also appropriate. Overall, this is a high-quality fix.

Reviewed at commit: 8ca4ce86a69c9b3d37b51684a9132430133ab911

Thank you for the detailed review and positive feedback! I'm glad the fixes for the race condition and the accessibility improvements are working well. Acknowledged.

@google-labs-jules
Copy link
Contributor

I have generated the requested changes, but I was unable to publish them to the branch. You can publish the changes manually from the Jules UI.

@arii
Copy link
Owner Author

arii commented Feb 25, 2026

Reviewed commit: bcd38e22dedf2d6d6dd5614427668046fac9b9f0

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connection issues. The refactoring of the isConnecting.current guard in useBluetoothHRM.ts ensures that only one connection attempt is active at a time, preventing unexpected behavior. The addition of js-cookie to persist the device ID for auto-reconnect is a practical solution.

The accessibility enhancements in ConnectView.tsx by adding role="status", aria-live="polite", and aria-busy are excellent improvements, aligning with WCAG 2.1 AA compliance as outlined in docs/DESIGN_GUIDELINES.md.

Error handling within connectAndStream has been improved by consistently resetting the connection status on failure, which enhances the user experience by preventing the UI from getting stuck in a 'connecting' state.

The updated unit test useBluetoothHRM.race.test.ts correctly reflects the new behavior, confirming the fix for concurrent connection attempts.

Minor documentation formatting fixes were also included, which are good for overall code hygiene.

Reviewed at commit: bcd38e22dedf2d6d6dd5614427668046fac9b9f0

@google-labs-jules
Copy link
Contributor

Reviewed commit: bcd38e22dedf2d6d6dd5614427668046fac9b9f0

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connection issues. The refactoring of the isConnecting.current guard in useBluetoothHRM.ts ensures that only one connection attempt is active at a time, preventing unexpected behavior. The addition of js-cookie to persist the device ID for auto-reconnect is a practical solution.

The accessibility enhancements in ConnectView.tsx by adding role="status", aria-live="polite", and aria-busy are excellent improvements, aligning with WCAG 2.1 AA compliance as outlined in docs/DESIGN_GUIDELINES.md.

Error handling within connectAndStream has been improved by consistently resetting the connection status on failure, which enhances the user experience by preventing the UI from getting stuck in a 'connecting' state.

The updated unit test useBluetoothHRM.race.test.ts correctly reflects the new behavior, confirming the fix for concurrent connection attempts.

Minor documentation formatting fixes were also included, which are good for overall code hygiene.

Reviewed at commit: bcd38e22dedf2d6d6dd5614427668046fac9b9f0

Thank you for the detailed review! I'm glad to hear the stability and accessibility improvements meet the project's requirements. Acknowledged.

@arii
Copy link
Owner Author

arii commented Feb 25, 2026

Reviewed commit: d3cedce28e912b7b7515eb8849643e31db6a028b

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connection issues. The refactoring of the isConnecting guard within useBluetoothHRM.ts to centralize it in connectAndStream is a robust solution, ensuring that only one connection attempt proceeds at a time. The addition of setStatus and setCustomStatusMessage resets in the finally block for silent auto-connect failures is a crucial improvement for UI consistency.

The explicit check for savedDeviceId in autoConnect prevents unnecessary connection attempts, which is a good optimization.

Furthermore, the accessibility enhancements in ConnectView.tsx by adding role="status", aria-live="polite", and aria-busy attributes are excellent, improving the user experience for assistive technologies and aligning with the project's DESIGN_GUIDELINES.md.

The updated unit test useBluetoothHRM.race.test.ts correctly reflects the new behavior, confirming the fix.

Minor documentation formatting fixes are also a welcome addition.

Reviewed at commit: d3cedce28e912b7b7515eb8849643e31db6a028b

@arii arii added the enhancement New feature or request label Feb 25, 2026
@google-labs-jules
Copy link
Contributor

Reviewed commit: d3cedce28e912b7b7515eb8849643e31db6a028b

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connection issues. The refactoring of the isConnecting guard within useBluetoothHRM.ts to centralize it in connectAndStream is a robust solution, ensuring that only one connection attempt proceeds at a time. The addition of setStatus and setCustomStatusMessage resets in the finally block for silent auto-connect failures is a crucial improvement for UI consistency.

The explicit check for savedDeviceId in autoConnect prevents unnecessary connection attempts, which is a good optimization.

Furthermore, the accessibility enhancements in ConnectView.tsx by adding role="status", aria-live="polite", and aria-busy attributes are excellent, improving the user experience for assistive technologies and aligning with the project's DESIGN_GUIDELINES.md.

The updated unit test useBluetoothHRM.race.test.ts correctly reflects the new behavior, confirming the fix.

Minor documentation formatting fixes are also a welcome addition.

Reviewed at commit: d3cedce28e912b7b7515eb8849643e31db6a028b

Thank you for the detailed review! I'm glad to hear the stability and accessibility improvements are verified. Acknowledged.

@arii
Copy link
Owner Author

arii commented Feb 25, 2026

Reviewed commit: 4cca5f1431cd829366aa1484adfde3f8e9f6f7b7

This PR effectively addresses the Bluetooth auto-connect race condition and overlapping connection issues. The changes are well-implemented and demonstrate a clear understanding of the problem.

Key improvements:

  1. Race Condition Prevention: The isConnecting flag is now correctly managed within connectAndStream and autoConnect, preventing multiple concurrent connection attempts. This is a robust solution to the race condition.
  2. Improved Auto-Connect Logic: The autoConnect function now correctly checks for a savedDeviceId before initiating an auto-connection, which prevents unnecessary connection attempts and improves efficiency.
  3. Enhanced UI Feedback: Resetting the connection status to DISCONNECTED and clearing custom messages on failed silent auto-connects ensures the UI accurately reflects the device state, preventing it from getting stuck in a 'connecting' state.
  4. Accessibility Enhancements: The addition of role="status", aria-live="polite", and aria-busy attributes to the connection status alert and button significantly improves the accessibility of the connection process for screen reader users.
  5. Test Coverage: The unit test for race conditions (useBluetoothHRM.race.test.ts) has been updated to correctly assert the new behavior, confirming the fix.
  6. Documentation: Minor formatting fixes in docs/TYPESCRIPT_PATTERNS.md and docs/audits/AUDIT_CODE_HYGIENE.md are good.

The introduction of js-cookie is a minor addition, but it's a standard and lightweight library for managing client-side cookies, which is appropriate for this use case.

Overall, this is a solid PR that improves both the functionality and accessibility of the Bluetooth connection feature.

Reviewed at commit: 4cca5f1431cd829366aa1484adfde3f8e9f6f7b7

@arii
Copy link
Owner Author

arii commented Feb 25, 2026

Reviewed commit: 24f62df1da5c94f012fa9986344fc924a3f96ecc

This PR delivers a robust fix for the Bluetooth auto-connect race condition and overlapping connections, significantly improving the stability and reliability of the HRM device connection process. The changes are well-implemented and demonstrate a thorough understanding of asynchronous operations and state management.

Key improvements include:

  • Race Condition Fix: The isConnecting flag is now correctly managed within connectAndStream using a try...finally block, ensuring it's always reset and preventing concurrent connection attempts. The unit test useBluetoothHRM.race.test.ts has been updated to correctly assert this behavior, which is excellent.
  • Auto-Connect Logic: The autoConnect function now checks for a savedDeviceId before attempting a connection, preventing unnecessary attempts and improving efficiency. The integration of js-cookie for this purpose is appropriate for client-side persistence.
  • Accessibility Enhancements: Meaningful ARIA attributes (role="status", aria-live="polite", aria-busy) have been added to the connection status alert and button, enhancing the user experience for assistive technologies.
  • VRT Stability: Numerous adjustments have been made to the Playwright visual regression tests (VRTs) and accessibility checks, including increased timeouts, viewport standardization, and CSS injection to disable animations. These changes will greatly reduce test flakiness and ensure more reliable visual and accessibility testing.
  • Code Hygiene: Minor documentation formatting in docs/TYPESCRIPT_PATTERNS.md and docs/audits/AUDIT_CODE_HYGIENE.md contributes to overall project consistency.

Overall, this is a high-quality PR that addresses a critical functional issue while also enhancing accessibility and test infrastructure. The net change in lines of code is reasonable given the scope of the fixes and improvements.

Reviewed at commit: 24f62df1da5c94f012fa9986344fc924a3f96ecc

@arii
Copy link
Owner Author

arii commented Feb 25, 2026

Remove increase to test timeouts

@arii
Copy link
Owner Author

arii commented Feb 25, 2026

🤖 AI Technical Audit

Code Review

This PR effectively addresses the race conditions in the Bluetooth auto-connect flow by introducing a ref-based guard and improves accessibility. However, the test stabilization strategy is overly aggressive (global CSS injection), and the error handling logic in the hook relies on brittle string matching.

⚠️ Anti-AI-Slop Directives

  1. Overly Verbose Comments: In tests/playwright/lib/accessibility.ts: // Ensure the target element is still present in the DOM... is redundant. The code if (count === 0) clearly explains the intent.
  2. Over-Engineering: The stabilizationCss injection in tests/playwright/lib/setup.ts disables transitions and animations globally for all VRTs (* { transition: none !important; }). While this stabilizes VRTs, it masks legitimate UI bugs related to transitions and layout shifts, reducing the fidelity of the tests.
  3. Code Ratio:
    • Delete: In hooks/useBluetoothHRM.ts, the autoConnect function logs logger.error({ error }, 'Auto-connect failed'). However, connectAndStream already logs logger.info({ error, errorMsg }, 'Silent auto-connect failed.') when running silently. This results in double logging for the same event.
    • Delete: In tests/playwright/lib/setup.ts, the duplicate application of CSS via addInitScript AND addStyleTag is verbose. The addInitScript is sufficient for full-page reloads, which VRTs typically perform.
  4. Stale Features: The old .catch() block in app/client/connect/page.tsx was correctly removed, as error handling moved inside autoConnect.

File-by-File Analysis

hooks/useBluetoothHRM.ts

Problem: Brittle Error Handling
The logic relies on checking errorMsg.includes('No saved device ID') to suppress UI alerts. This is fragile; if the error message text changes in connectAndStream, this check fails, causing UI regressions (false positive error alerts).

Best Practice: Use a specific Error subclass or a distinct return type.

Implementation Sample:

// Define a specific error type
class NoSavedDeviceError extends Error {
  constructor() { super('No saved device ID'); }
}

// In connectAndStream
if (silent && !savedDeviceId) {
  throw new NoSavedDeviceError();
}

// In autoConnect
} catch (error) {
  if (error instanceof NoSavedDeviceError) {
    // Handle silently
  } else {
    setCustomStatusMessage(BLUETOOTH_MESSAGES.autoConnectFailed);
  }
}

tests/playwright/lib/setup.ts

Problem: Magic Numbers & Test Fidelity

  1. Hardcoded 10000 ms timeouts are introduced. Use the WAIT_TIMEOUTS constant from lib/waits.ts to maintain a single source of truth.
  2. As mentioned, transition: none !important is applied to everything. This prevents testing any feature that relies on transitionend events or CSS animations.

Suggestion:
Scope the stabilization CSS to the VRT snapshot logic specifically, or only apply it to elements known to be flaky (e.g., specific loaders), rather than *.

tests/playwright/vrt-hr-components.spec.ts

Problem: Hardcoded Styles
The test forcefully injects height: 1080px !important to the dashboard. This suggests the component is not responsive or the test environment is not correctly configured. Relying on injected styles to pass tests often hides real layout issues on different screens.

Summary

Functionally, the race condition fix is sound. The test changes, while likely successful in reducing flakiness, are heavy-handed and reduce confidence that the app works correctly for users (who do see animations). Refactor the error string matching and reduce test setup bloat.

Review automatically published via RepoAuditor.

@arii
Copy link
Owner Author

arii commented Feb 26, 2026

🤖 AI Technical Audit

Code Review: PR #9315 - Fix Bluetooth Auto-Connect Race Condition

🚫 Anti-AI-Slop & Directives

  1. OVER-ENGINEERING (False Negative Risk):
    In tests/playwright/lib/accessibility.ts, the new logic checks if (count === 0) before adding an include to the Axe builder. This is dangerous. If a selector is missing (e.g., a modal that failed to open), the test will skip the specific check and default to scanning the entire page. This often results in a false positive (test passes because the broken/missing element wasn't scanned) or a confusing failure (unrelated violations on the page).

  2. CODE RATIO / DELETION:
    We can remove ~15 lines.

    • 6 lines in hooks/useBluetoothHRM.ts: The NoSavedDeviceError class is unnecessary boilerplate for a simple internal flow control exception. Use new Error('NO_SAVED_DEVICE').
    • 8 lines in tests/playwright/lib/accessibility.ts: Remove the count check block.
    • 3 lines in tests/playwright/vrt-components.spec.ts: The waitForTimeout(500) is a flaky pattern.
  3. STALE FEATURES:
    The PR introduces window.__TEST_CONTROLS__ but leaves the deprecated window.TEST_CONTROLS type definition in types/global.d.ts. Ensure the old one is fully cleaned up if it is no longer used.


📂 File-by-File Analysis

hooks/useBluetoothHRM.ts

Refactoring: The extraction of the isConnecting guard into the parent functions (connectAndStream, reconnect) is a solid architectural change that prevents the "double-check" race condition. However, the custom error class is overkill.

Problem: Verbose custom Error class for a single internal catch usage.
Implementation Sample (Proposed Change):

// Remove class NoSavedDeviceError ...

// Inside connectAndStream:
if (silent && !savedDeviceId) {
  throw new Error('NO_SAVED_DEVICE');
}

// Inside catch:
if (error.message !== 'NO_SAVED_DEVICE') {
  setCustomStatusMessage(BLUETOOTH_MESSAGES.autoConnectFailed);
}

tests/playwright/lib/accessibility.ts

Problem: The added safety check compromises test integrity. If I explicitly ask to test a selector, the test should fail if that selector does not exist.
Implementation Sample (Correction):

// Revert to:
if (selector) {
  // Let Playwright/Axe throw if the element is missing, or assert visibility before calling this function.
  axeBuilder.include(selector)
}

tests/playwright/vrt-components.spec.ts

Problem: Usage of waitForTimeout(500) even though CSS stabilization is injected. If the menu has transitions, the injected CSS in setup.ts should handle it globally (* { transition: none !important }) rather than relying on arbitrary sleeps.

playwright.config.ts

Observation: Reducing the global timeout to 20s while increasing the WebSocket wait to 10s leaves a very narrow window (10s) for the actual test execution (VRT, interactions) in CI environments. This risks increasing flakiness.


🏗 Architectural Impact

  • Robustness: The race condition fix is logically sound. By creating a "lock" (isConnecting ref) that persists across the async gap of the GATT connection, overlapping calls are effectively dropped.
  • Testability: Exposing __TEST_CONTROLS__ allows for deterministic testing of the UI states without needing a physical Bluetooth device, which is a significant improvement for CI stability.

🛡️ Best Practices & Security

  • Accessibility: Adding role="status" and aria-live regions in ConnectView.tsx is a great improvement for screen readers during the connection phase.
  • Type Safety: The updates to window augmentation are correctly typed in global.d.ts.

Review automatically published via RepoAuditor.

@arii
Copy link
Owner Author

arii commented Feb 26, 2026

Reviewed commit: 4f07db1084cd0c8d75061bfe608c076661fb59d4

❌ Review Failed: Invalid JSON Response

The AI response could not be parsed as valid JSON. This is an internal issue with the AI agent.

Reviewed at commit: 4f07db1084cd0c8d75061bfe608c076661fb59d4

Raw AI Output
{
  "reviewComment": "This PR delivers significant improvements to the Bluetooth HRM connection logic, effectively addressing race conditions and overlapping connection attempts. The refactoring of `useBluetoothHRM` centralizes `isConnecting` state management, making the connection and reconnection flow more robust and predictable. The introduction of `NoSavedDeviceError` is a good practice for specific error handling.

Key improvements include:

*   **Race Condition Fix**: The `isConnecting` state is now properly managed across `connectToGatt`, `connectAndStream`, and `reconnect` functions, preventing multiple simultaneous connection attempts.
*   **Error Handling**: Improved error handling for silent auto-connect, specifically with the new `NoSavedDeviceError`.
*   **Accessibility**: Added `role=\"status\"`, `aria-live=\"polite\"`, and `aria-busy` attributes to relevant UI elements in `ConnectView.tsx`.
*   **Testability**: The `__TEST_CONTROLS__` pattern is enhanced to merge existing controls, and `NEXT_PUBLIC_TESTING` is introduced for client-side test environment detection, improving Playwright test setup.
*   **VRT Stability**: Significant additions to Playwright setup (`addInitScript` for CSS stabilization) will greatly reduce VRT flakiness.
*   **User Experience**: The \"Clear Saved Device\" functionality in `UserSettings` provides users with more control over their device connections.

Overall, this is a well-executed PR that enhances both the stability and user experience of the Bluetooth connection feature.",
  "labels": ["enhancement", "refactor", "frontend-improvement"],
  "verdict": "approve",
  "suggestedIssues": [
    {
      "title": "Refine VRT `fullPage` Screenshot Options for Consistency",
      "description": "The global `SCREENSHOT_OPTIONS` in `tests/playwright/lib/visual.ts` sets `fullPage: false`, but `tests/playwright/vrt-connect-page.spec.ts` explicitly overrides this to `fullPage: true` for a specific screenshot. This inconsistency can lead to confusion or unexpected behavior in VRTs. It would be beneficial to either enforce a consistent `fullPage` setting across all VRTs or remove the global setting and require explicit `fullPage` configuration for each `takeScreenshot` call to ensure clarity.",
      "type": "technical-debt",
      "priority": "medium",
      "fingerprint": "tests/playwright/lib/visual.ts:SCREENSHOT_OPTIONS_fullPage",
      "isPreExisting": false,
      "filePath": "tests/playwright/lib/visual.ts",
      "lineNumber": 26
    },
    {
      "title": "Review `WAIT_TIMEOUTS.WEBSOCKET` Increase",
      "description": "The `WAIT_TIMEOUTS.WEBSOCKET` value was increased from 5000ms to 10000ms. While this might be necessary for CI stability or to accommodate realistic connection times, a significant increase in a timeout could potentially mask underlying performance issues in the WebSocket connection or initialization process. It's worth monitoring if this timeout is frequently hit and investigating if the connection process can be optimized to reduce the need for such a long wait.",
      "type": "technical-debt",
      "priority": "low",
      "fingerprint": "tests/playwright/lib/waits.ts:WAIT_TIMEOUTS_WEBSOCKET",
      "isPreExisting": false,
      "filePath": "tests/playwright/lib/waits.ts",
      "lineNumber": 17
    },
    {
      "title": "Replace Arbitrary `waitForTimeout` with Specific Awaits in VRTs",
      "description": "In `tests/playwright/vrt-components.spec.ts`, an arbitrary `dashboardPage.waitForTimeout(500)` is used before an accessibility check. While sometimes necessary for animations, relying on fixed timeouts can lead to flaky tests. Ideally, this should be replaced with a more specific wait condition (e.g., `page.waitForLoadState('networkidle')` or waiting for a specific element's animation to complete) to ensure the UI is stable before proceeding with checks.",
      "type": "technical-debt",
      "priority": "low",
      "fingerprint": "tests/playwright/vrt-components.spec.ts:waitForTimeout_spotifyMenu",
      "isPreExisting": false,
      "filePath": "tests/playwright/vrt-components.spec.ts",
      "lineNumber": 118
    },
    {
      "title": "Improve Test Description for Bluetooth Flow Robustness Test",
      "description": "The test description `test('robustness: handles stale connection by forgetting and prompting', async ({` in `tests/playwright/bluetooth-flow.spec.ts` uses the term 'robustness'. While descriptive, per the AI Slop Prevention guidelines, comments and documentation should aim for higher technical density

@arii arii added ci-failure not reviewed The review could not be performed or completed successfully. and removed ci-failure not reviewed The review could not be performed or completed successfully. labels Feb 26, 2026
…ndshakes

This commit addresses a race condition in the Bluetooth connection flow
where silent auto-connection would attempt to trigger without a saved
device ID, causing UI flickering and console errors.

Key changes:
- Added `isConnecting` ref guards to `connectAndStream` in `useBluetoothHRM`
  to prevent multiple simultaneous connection attempts.
- Updated `autoConnect` logic to check for the `hrm_device_id` cookie
  before initiating a connection attempt, preventing flickering.
- Implemented a guard in `ConnectPage` to only trigger `autoConnect`
  when a saved device ID is present.
- Improved accessibility by adding `role="status"`, `aria-live="polite"`,
  and `aria-busy` to the connection status components in `ConnectView`.

Verified with unit tests, visual regression tests, and manual Playwright
verification scripts.

Co-authored-by: arii <342438+arii@users.noreply.github.com>
@arii arii force-pushed the fix-bluetooth-auto-connect-race-17140583504697442733 branch from baca58f to 8a36909 Compare March 3, 2026 04:16
@arii
Copy link
Owner Author

arii commented Mar 3, 2026

🤖 AI Technical Audit

Code Review: Bluetooth Race Condition & Accessibility Fixes

This PR correctly identifies and addresses the race conditions in the Bluetooth connection flow by introducing a ref-based lock (isConnecting) and improves accessibility. However, there are significant concerns regarding the separation of concerns between the View and Hook, and a potential critical gap in the locking mechanism within autoConnect.

⚠️ ANTI-AI-SLOP DIRECTIVES

  1. OVER-ENGINEERING & DUPLICATION: The page.tsx file now imports js-cookie to check hrm_device_id before running the effect. This is redundant because useBluetoothHRM.ts / autoConnect has been updated to perform this exact check and exit gracefully. The View should not be aware of the specific cookie storage key implementation.
  2. STALE FEATURES / LOGIC GAP: You removed the guard from connectToGatt (low-level) and added it to connectAndStream (high-level). However, autoConnect checks the lock but does not appear to set it. If autoConnect runs (isConnecting is false), and performs async work, a user can click "Connect" (triggering connectAndStream), resulting in a race condition because autoConnect didn't claim the lock.
  3. CODE RATIO: By removing the redundant cookie logic in page.tsx, we can delete approx 5-8 lines of code and remove a direct dependency on js-cookie from the client view.

File-by-File Analysis

app/client/connect/page.tsx

Problem: Leaking implementation details and redundant logic. The View imports js-cookie to check for hrm_device_id. This logic belongs entirely in the hook.

Recommendation: Remove the js-cookie import and the check. Rely on autoConnect to handle the "no device" case (which it now does by setting connectionAttempted to true and returning).

// DELETE this import
import Cookies from 'js-cookie'

// DELETE this check in useEffect
const savedDeviceId = Cookies.get('hrm_device_id')
if (
  !isConnected &&
  // ...
  // savedDeviceId <--- Remove this
) {

hooks/useBluetoothHRM.ts

Problem 1: Critical Locking Gap in autoConnect
Since you removed the guard from connectToGatt, any function calling it must manage the isConnecting lock. autoConnect checks the lock at the start but does not seem to set it to true.

Implementation Sample:

const autoConnect = useCallback(async (): Promise<void> => {
  if (isConnecting.current) return

  // ... cookie checks ...

  try {
    isConnecting.current = true; // <--- MISSING THIS
    setConnectionAttempted(true)
    // ... connection logic ...
  } finally {
    isConnecting.current = false; // <--- MISSING THIS
  }
}, [])

Problem 2: Redundant State Updates
In connectAndStream, inside the specific check for !savedDeviceId, you set the status to DISCONNECTED and then throw. The catch block likely catches this and sets the status to DISCONNECTED again. Consolidate error handling to avoid React batching edge cases or flickering.

Best Practice: Accessibility changes in ConnectView.tsx (aria-live, role="status") are excellent and follow WAI-ARIA standards.

Review automatically published via RepoAuditor.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

🤖 Gemini Review Skipped

Review was skipped for the following reason: Gemini review is disabled

🤖 Manual Trigger Quick Reference

Command Action
@gemini-bot Run AI Code Review (PR only)
@gemini-triage Run Issue Triage
@gemini-coder <task> Generate Code
@create-review-issues Create issues from review (PR only)
@gemini-help Show this help message

Manual Trigger Guide

@arii arii added not reviewed The review could not be performed or completed successfully. and removed changes-requested not reviewed The review could not be performed or completed successfully. labels Mar 3, 2026
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: arii <342438+arii@users.noreply.github.com>
@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

🤖 Gemini Review Skipped

Review was skipped for the following reason: Gemini review is disabled

🤖 Manual Trigger Quick Reference

Command Action
@gemini-bot Run AI Code Review (PR only)
@gemini-triage Run Issue Triage
@gemini-coder <task> Generate Code
@create-review-issues Create issues from review (PR only)
@gemini-help Show this help message

Manual Trigger Guide

@arii arii added not reviewed The review could not be performed or completed successfully. and removed not reviewed The review could not be performed or completed successfully. labels Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

accessibility bug Something isn't working chore documentation Improvements or additions to documentation enhancement New feature or request frontend-improvement not reviewed The review could not be performed or completed successfully. REFACTOR_REQUIRED refactor TESTS_IMPROVEMENT tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Race condition in Bluetooth Auto-Connect and overlapping connection attempts

1 participant