Skip to content

Codex/fix high priority bug in insightstab.kt#420

Merged
9thLevelSoftware merged 5 commits into
mainfrom
codex/fix-high-priority-bug-in-insightstab.kt
May 6, 2026
Merged

Codex/fix high priority bug in insightstab.kt#420
9thLevelSoftware merged 5 commits into
mainfrom
codex/fix-high-priority-bug-in-insightstab.kt

Conversation

@9thLevelSoftware

Copy link
Copy Markdown
Owner

No description provided.

Copilot AI review requested due to automatic review settings May 6, 2026 03:38
@9thLevelSoftware 9thLevelSoftware merged commit 4cd905a into main May 6, 2026
3 of 6 checks passed
@9thLevelSoftware 9thLevelSoftware deleted the codex/fix-high-priority-bug-in-insightstab.kt branch May 6, 2026 03:38

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 002875b9e1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
Text(title, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
Text(definition, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
TimeframeBadge(timeframe)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P0 Badge Define TimeframeBadge before using it in SmartInsightsTab

TimeframeBadge(...) is called here (and again in InsightCard) but there is no TimeframeBadge function in SmartInsightsTab.kt, and the only one in the repo is private inside InsightsTab.kt. This makes the symbol unresolved at compile time, so the shared module cannot build after this commit.

Useful? React with 👍 / 👎.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a structured hierarchy to the Insights and Smart Insights tabs by adding section headers and descriptive metadata to the training cards. The feedback highlights a critical compilation error due to the private visibility of the TimeframeBadge component, which is accessed across different files. Additionally, there is significant code duplication between the two modified files that should be refactored into shared components. Finally, the new metadata strings are currently hardcoded and need to be moved to resource files to support localization.



@Composable
private fun TimeframeBadge(label: String) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

The TimeframeBadge composable is marked as private, but it is being called from SmartInsightsTab.kt (lines 628 and 671). This will cause a compilation error because private functions are only visible within the file they are defined in. Please change the visibility to internal (the default in Kotlin) or move it to a shared component file like InsightCards.kt.

Suggested change
private fun TimeframeBadge(label: String) {
fun TimeframeBadge(label: String) {


// This Week Summary Card - week-over-week comparison
item {
InsightMetadata("Summary of completed sessions and personal records.", selectedPeriod.label, "Check if this period is on track before changing your plan.")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This line introduces hardcoded strings for the insight metadata. To support localization and maintain consistency with the rest of the project, please use string resources (e.g., stringResource(Res.string.key)) instead of hardcoded literals.

Comment on lines +636 to +639
private fun InsightHierarchyHeader(title: String, subtitle: String) {
Text(title, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
Text(subtitle, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The InsightHierarchyHeader composable is identical to InsightSectionHeader in InsightsTab.kt. Similarly, InsightContextBlock is nearly identical to InsightMetadata. To avoid code duplication and ensure a consistent UI across the app, these components should be moved to a common location, such as a shared UI components file.

@Composable
private fun WeeklyVolumeCard(report: WeeklyVolumeReport) {
InsightCard(title = stringResource(Res.string.insights_weekly_volume)) {
InsightCard(title = stringResource(Res.string.insights_weekly_volume), definition = "Weekly muscle-group workload breakdown.", timeframe = "Last 7 days", soWhat = "Use as drill-down detail after checking the main total-volume trend.") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The definition, timeframe, and soWhat arguments are using hardcoded strings. Since the project uses a resource-based localization system (as seen with the title parameter), these should also be moved to the resource files.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates both Insights UI tabs to add a clearer hierarchy (“Snapshot / Trends / Diagnostics / Actions”) and to attach contextual metadata (definition, timeframe, “So what?” guidance) to each insight card/section.

Changes:

  • Added section hierarchy headers to SmartInsightsTab and InsightsTab LazyColumn content.
  • Extended SmartInsightsTab’s InsightCard to render definition/timeframe/“So what?” metadata.
  • Introduced new metadata/badge composables in InsightsTab (e.g., TimeframeBadge) and a context block in SmartInsightsTab.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/SmartInsightsTab.kt Adds hierarchy headers + metadata rendering to insight cards; introduces new shared UI helpers.
shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/InsightsTab.kt Adds section headers + per-card metadata blocks and introduces a timeframe badge component.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +625 to +629
Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
Text(title, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
Text(definition, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
TimeframeBadge(timeframe)
Text("So what? $soWhat", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Medium)
Comment on lines +637 to +638
Text(title, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
Text(subtitle, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
Comment on lines +181 to +188
item { InsightHierarchyHeader("1. Snapshot", "Current status") }

// Section A: Weekly Volume (SUGG-01)
item {
WeeklyVolumeCard(weeklyVolume)
}

item { InsightHierarchyHeader("2. Trends", "How it changed") }
Comment on lines +87 to +97
Text(
text = title,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onSurface,
)
Text(
text = subtitle,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
Comment on lines +246 to 254
// 1) Snapshot
item {
InsightSectionHeader("1. Snapshot", "Current status")
}

// This Week Summary Card - week-over-week comparison
item {
InsightMetadata("Summary of completed sessions and personal records.", selectedPeriod.label, "Check if this period is on track before changing your plan.")
ResponsiveCardWrapper {
9thLevelSoftware added a commit that referenced this pull request May 14, 2026
* Refresh Smart Insights now timestamp on fetch (#412)

* Refresh time-sensitive Smart Insights and recompute on clock updates (#418)

* Align Smart Insights nowMs refresh with fetch and timer

* Stabilize Smart Insights timer effect lifecycle

* Remove periodic SmartInsights timer refresh loop

* Harden SmartInsights loading state during refresh

* Avoid mutating compose state from IO dispatcher

* Align SmartInsights query and weekly-volume computation to shared nowMs (Option A) (#413)

* Align insights query and weekly volume with shared nowMs

* Harden insights anchor timestamp lifecycle

* Fix SmartInsights loading guard for null anchor timestamp

* Reset insights anchor before each profile refresh

* Expand SmartSuggestions muscle-group taxonomy and add unknown-group fallback tracking (#415)

* Expand muscle-group aliases and track unknown fallback usage

* Refine unknown muscle-group fallback tracking

* Keep SmartSuggestions fallback tracking stateless

* Resolve review nits in muscle-group fallback docs/tests

* Standardize inclusive cutoff policy (>=) in ReadinessEngine and add boundary tests (#416)

* Define inclusive readiness cutoff policy and add boundary tests

* Refine readiness boundary tests and add exclusion coverage

* Address review cleanup in readiness boundary tests

* Centralize inclusive readiness cutoff check

* Unify insights into Snapshot→Trends→Diagnostics→Actions and add per-card metadata (#417)

* Refactor analytics insights into unified hierarchy

* Address review feedback on insight timeframe badges

* Resolve review feedback on insights cards and cleanup

* Resolve follow-up comments on readiness insight presentation

* Use average intensity for Time-of-Day insights with confidence gating (#414)

* Refine time-of-day insight to average intensity with confidence gating

* Align time insight session-threshold copy with confidence gating

* Add time-of-day tests for distinct-day gating and intensity scoring

* Generalize time-window confidence copy across locales

* Codex/fix high priority bug in insightstab.kt (#420)

* Refactor analytics insights into unified hierarchy

* Address review feedback on insight timeframe badges

* Resolve review feedback on insights cards and cleanup

* Resolve follow-up comments on readiness insight presentation

* Fix missing RoundedCornerShape import in InsightsTab

* Refresh Smart Insights now timestamp on fetch (#419)

* Refresh Smart Insights now timestamp on fetch

* Fix Compose state mutation in IO dispatcher and reset loading state on profile change

Agent-Logs-Url: https://github.com/9thLevelSoftware/Project-Phoenix-MP/sessions/23e4c8a0-93e7-428f-8d00-b84a01429a58

Co-authored-by: 9thLevelSoftware <69057727+9thLevelSoftware@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* fix(rep-counter): ignore firmware warmup sync for variable warmup sets (#422)

* Request transient duck audio focus for Android workout cues (#423)

* Fix Android cue audio precedence over background music

* Fix audio focus release timing for workout cues

* Align audio focus attributes with playback usage

* Add focusChangeListener as identity token in requestTransientDuckAudioFocus

Agent-Logs-Url: https://github.com/9thLevelSoftware/Project-Phoenix-MP/sessions/1d2923b8-cdaf-4080-bc22-8839a6940e94

Co-authored-by: 9thLevelSoftware <69057727+9thLevelSoftware@users.noreply.github.com>

* Add focusHoldDurationMs helper and use event-specific delay in abandonAfterDelay

Agent-Logs-Url: https://github.com/9thLevelSoftware/Project-Phoenix-MP/sessions/cd565f28-356a-4acd-9102-45b2602e7e02

Co-authored-by: 9thLevelSoftware <69057727+9thLevelSoftware@users.noreply.github.com>

* Tie ducking focus hold to cue duration metadata

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* build: update dependencies and add device metadata to Health Connect

Update Health Connect to the stable 1.1.0 release and include device attribution in synced exercise records.

- **Health**: Update `androidx-health-connect` to `1.1.0` stable and remove alpha-pinning workarounds in `shared/build.gradle.kts`.
- **Health**: Implement `Metadata.activelyRecorded` for `ExerciseSessionRecord` and `TotalCaloriesBurnedRecord` to identify the "Vitruvian Trainer" device.
- **Versions**: Upgrade Kotlin to `2.3.21`, AGP to `9.2.1`, and Gradle to `9.5.0`.
- **Versions**: Bump Compose BOM to `2026.05.00`, Compose Navigation to `2.9.8`, and Ktor to `3.4.3`.

* Revert audio focus duck attempt (#423) — restore audio output for #421 (#428)

* Revert "Request transient duck audio focus for Android workout cues (#423)"

This reverts commit 6371274.

* fix(audio): release MediaPlayer on exception, dedupe sound name lists

Address gemini-code-assist review on PR #428:

- playWithMediaPlayer: hoist `mediaPlayer` declaration out of the `try`
  block and release it from `catch`. Previous structure leaked the native
  player if setVolume/setOnCompletionListener/start threw.
- Extract BADGE_SOUND_NAMES and PR_SOUND_NAMES to private top-level vals.
  Eliminates duplication between the SoundPool-loading `remember` block
  and getRandomBadgeSound/getRandomPRSound, and removes per-call list
  allocations on the random helpers.

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Restore Android workout cue audio routing and ignore code-review artifacts (#429)

* Address PR #429 review feedback: route workout cues to STREAM_MUSIC (#430)

* Address PR #429 review feedback: route cues to STREAM_MUSIC

P1 (chatgpt-codex-connector / gemini-code-assist): the previous change to
USAGE_ASSISTANCE_SONIFICATION routed cues to STREAM_SYSTEM, breaking the
existing volumeControlStream = STREAM_MUSIC contract. Hardware volume
buttons would no longer adjust workout cue loudness, leaving users with
silent or unbalanced cues.

- Switch STANDARD_ANDROID_CUE_USAGE to USAGE_MEDIA so SoundPool and
  MediaPlayer both route through STREAM_MUSIC, matching the activity's
  volumeControlStream and the existing media-volume warning logic.
- Update warnIfMediaVolumeMuted comment/message to reflect USAGE_MEDIA.
- Reword MainActivity volumeControlStream comment to reflect the actual
  scope (entire activity lifetime, not just the workout UI).
- Update structural test assertions to match USAGE_MEDIA and add a guard
  preventing accidental reintroduction of USAGE_ASSISTANCE_SONIFICATION.
- Replace silent fallbacks in HapticFeedbackAudioRoutingGuardTest with
  explicit checks so a missing project root, source file, or raw resource
  directory fails with an actionable message instead of an opaque
  FileNotFoundException or "every cue missing" report.

* Address PR #430 review feedback: harden cue source parser

- gemini-code-assist (high) / chatgpt-codex-connector (P2): the
  multi-line branch in soundNamesInConstantList searched for `\n)`,
  which only matches a closing paren at column 0. Replace with a
  simple `indexOf(")", start)`. Sound names only contain `[a-z0-9_]`
  so the first `)` after `start` is reliably the listOf(...) closer
  regardless of single-line, multi-line, or indented formatting.
- gemini-code-assist (medium): extract the rep-count range
  (`(1..N).mapNotNull`) from the source instead of duplicating
  `1..25`, so the guard stays in sync if the upper bound changes.

Skipped: the suggestion to skip SoundPool initialization on Fire OS
(pre-existing behavior, out of scope for this PR's audio-routing
focus).

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Fix top-level superset reorder persistence and restore audio routing

* Fix Android cue packaging and audio routing (#431)

* Harden Compose layouts for iOS accessibility scaling (#432)

* Harden iOS accessibility layouts for issue 389

* Fix cue audio resource lookup in release builds

* Fix per-cable weight display and softMax handling (#433)

* fix: preserve stall detection in portal sync

* chore: remove stale generated artifacts

* Codex/stu experiment (#436)

* Fix per-cable weight display and softMax handling

* Fix BLE force target to keep progression separate

* Replace Just Lift auto-detection with post-set exercise tagging (#435)

* Fix Just Lift retag PR tracking and completed set sync

* fix: prevent Just Lift retag PR duplication

* test: align AMRAP target weight expectation

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
9thLevelSoftware added a commit that referenced this pull request May 14, 2026
* Refresh Smart Insights now timestamp on fetch (#412)

* Refresh time-sensitive Smart Insights and recompute on clock updates (#418)

* Align Smart Insights nowMs refresh with fetch and timer

* Stabilize Smart Insights timer effect lifecycle

* Remove periodic SmartInsights timer refresh loop

* Harden SmartInsights loading state during refresh

* Avoid mutating compose state from IO dispatcher

* Align SmartInsights query and weekly-volume computation to shared nowMs (Option A) (#413)

* Align insights query and weekly volume with shared nowMs

* Harden insights anchor timestamp lifecycle

* Fix SmartInsights loading guard for null anchor timestamp

* Reset insights anchor before each profile refresh

* Expand SmartSuggestions muscle-group taxonomy and add unknown-group fallback tracking (#415)

* Expand muscle-group aliases and track unknown fallback usage

* Refine unknown muscle-group fallback tracking

* Keep SmartSuggestions fallback tracking stateless

* Resolve review nits in muscle-group fallback docs/tests

* Standardize inclusive cutoff policy (>=) in ReadinessEngine and add boundary tests (#416)

* Define inclusive readiness cutoff policy and add boundary tests

* Refine readiness boundary tests and add exclusion coverage

* Address review cleanup in readiness boundary tests

* Centralize inclusive readiness cutoff check

* Unify insights into Snapshot→Trends→Diagnostics→Actions and add per-card metadata (#417)

* Refactor analytics insights into unified hierarchy

* Address review feedback on insight timeframe badges

* Resolve review feedback on insights cards and cleanup

* Resolve follow-up comments on readiness insight presentation

* Use average intensity for Time-of-Day insights with confidence gating (#414)

* Refine time-of-day insight to average intensity with confidence gating

* Align time insight session-threshold copy with confidence gating

* Add time-of-day tests for distinct-day gating and intensity scoring

* Generalize time-window confidence copy across locales

* Codex/fix high priority bug in insightstab.kt (#420)

* Refactor analytics insights into unified hierarchy

* Address review feedback on insight timeframe badges

* Resolve review feedback on insights cards and cleanup

* Resolve follow-up comments on readiness insight presentation

* Fix missing RoundedCornerShape import in InsightsTab

* Refresh Smart Insights now timestamp on fetch (#419)

* Refresh Smart Insights now timestamp on fetch

* Fix Compose state mutation in IO dispatcher and reset loading state on profile change

Agent-Logs-Url: https://github.com/9thLevelSoftware/Project-Phoenix-MP/sessions/23e4c8a0-93e7-428f-8d00-b84a01429a58

Co-authored-by: 9thLevelSoftware <69057727+9thLevelSoftware@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* fix(rep-counter): ignore firmware warmup sync for variable warmup sets (#422)

* Request transient duck audio focus for Android workout cues (#423)

* Fix Android cue audio precedence over background music

* Fix audio focus release timing for workout cues

* Align audio focus attributes with playback usage

* Add focusChangeListener as identity token in requestTransientDuckAudioFocus

Agent-Logs-Url: https://github.com/9thLevelSoftware/Project-Phoenix-MP/sessions/1d2923b8-cdaf-4080-bc22-8839a6940e94

Co-authored-by: 9thLevelSoftware <69057727+9thLevelSoftware@users.noreply.github.com>

* Add focusHoldDurationMs helper and use event-specific delay in abandonAfterDelay

Agent-Logs-Url: https://github.com/9thLevelSoftware/Project-Phoenix-MP/sessions/cd565f28-356a-4acd-9102-45b2602e7e02

Co-authored-by: 9thLevelSoftware <69057727+9thLevelSoftware@users.noreply.github.com>

* Tie ducking focus hold to cue duration metadata

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* build: update dependencies and add device metadata to Health Connect

Update Health Connect to the stable 1.1.0 release and include device attribution in synced exercise records.

- **Health**: Update `androidx-health-connect` to `1.1.0` stable and remove alpha-pinning workarounds in `shared/build.gradle.kts`.
- **Health**: Implement `Metadata.activelyRecorded` for `ExerciseSessionRecord` and `TotalCaloriesBurnedRecord` to identify the "Vitruvian Trainer" device.
- **Versions**: Upgrade Kotlin to `2.3.21`, AGP to `9.2.1`, and Gradle to `9.5.0`.
- **Versions**: Bump Compose BOM to `2026.05.00`, Compose Navigation to `2.9.8`, and Ktor to `3.4.3`.

* Revert audio focus duck attempt (#423) — restore audio output for #421 (#428)

* Revert "Request transient duck audio focus for Android workout cues (#423)"

This reverts commit 6371274.

* fix(audio): release MediaPlayer on exception, dedupe sound name lists

Address gemini-code-assist review on PR #428:

- playWithMediaPlayer: hoist `mediaPlayer` declaration out of the `try`
  block and release it from `catch`. Previous structure leaked the native
  player if setVolume/setOnCompletionListener/start threw.
- Extract BADGE_SOUND_NAMES and PR_SOUND_NAMES to private top-level vals.
  Eliminates duplication between the SoundPool-loading `remember` block
  and getRandomBadgeSound/getRandomPRSound, and removes per-call list
  allocations on the random helpers.

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Restore Android workout cue audio routing and ignore code-review artifacts (#429)

* Address PR #429 review feedback: route workout cues to STREAM_MUSIC (#430)

* Address PR #429 review feedback: route cues to STREAM_MUSIC

P1 (chatgpt-codex-connector / gemini-code-assist): the previous change to
USAGE_ASSISTANCE_SONIFICATION routed cues to STREAM_SYSTEM, breaking the
existing volumeControlStream = STREAM_MUSIC contract. Hardware volume
buttons would no longer adjust workout cue loudness, leaving users with
silent or unbalanced cues.

- Switch STANDARD_ANDROID_CUE_USAGE to USAGE_MEDIA so SoundPool and
  MediaPlayer both route through STREAM_MUSIC, matching the activity's
  volumeControlStream and the existing media-volume warning logic.
- Update warnIfMediaVolumeMuted comment/message to reflect USAGE_MEDIA.
- Reword MainActivity volumeControlStream comment to reflect the actual
  scope (entire activity lifetime, not just the workout UI).
- Update structural test assertions to match USAGE_MEDIA and add a guard
  preventing accidental reintroduction of USAGE_ASSISTANCE_SONIFICATION.
- Replace silent fallbacks in HapticFeedbackAudioRoutingGuardTest with
  explicit checks so a missing project root, source file, or raw resource
  directory fails with an actionable message instead of an opaque
  FileNotFoundException or "every cue missing" report.

* Address PR #430 review feedback: harden cue source parser

- gemini-code-assist (high) / chatgpt-codex-connector (P2): the
  multi-line branch in soundNamesInConstantList searched for `\n)`,
  which only matches a closing paren at column 0. Replace with a
  simple `indexOf(")", start)`. Sound names only contain `[a-z0-9_]`
  so the first `)` after `start` is reliably the listOf(...) closer
  regardless of single-line, multi-line, or indented formatting.
- gemini-code-assist (medium): extract the rep-count range
  (`(1..N).mapNotNull`) from the source instead of duplicating
  `1..25`, so the guard stays in sync if the upper bound changes.

Skipped: the suggestion to skip SoundPool initialization on Fire OS
(pre-existing behavior, out of scope for this PR's audio-routing
focus).

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Fix top-level superset reorder persistence and restore audio routing

* Fix Android cue packaging and audio routing (#431)

* Harden Compose layouts for iOS accessibility scaling (#432)

* Harden iOS accessibility layouts for issue 389

* Fix cue audio resource lookup in release builds

* Fix per-cable weight display and softMax handling

* Fix per-cable weight display and softMax handling (#433)

* Fix BLE force target to keep progression separate

* fix: preserve stall detection in portal sync

* chore: remove stale generated artifacts

* Replace Just Lift auto-detection with post-set exercise tagging (#435)

* Fix Just Lift retag PR tracking and completed set sync

* fix: prevent Just Lift retag PR duplication

* test: align AMRAP target weight expectation

* fix: test legacy Kable GATT writes for Pixel starts

* Codex/issue 333 ready gate test (#438)

* fix: gate BLE ready state for Pixel diagnostics

* fix(ble): optimize connection flow and improve Pixel device compatibility

Refine BLE communication by introducing device-specific timing adjustments for Google Pixel hardware and streamlining the command observation sequence.

- **DeviceInfo**: Add `isPixel()` and `isSamsung()` to the common `DeviceInfo` interface to support platform-specific hardware workarounds.
- **BLE**: Implement observation for the `SAMPLE` characteristic to support raw monitor packets without opcode prefixes.
- **BLE**: Update `parseMetricsPacket` in `KableBleRepository` to handle both opcoded (0x01) and raw monitor data payloads.
- **BLE**: Introduce a 500ms `preDelayMs` on Pixel devices after sending program configurations to improve diagnostic read reliability.
- **Session**: Remove the redundant manual `START` command (0x03) from `ActiveSessionEngine` prior to starting workout polling.
- **Kable Patch**: Optimize `Connection.kt` by removing an unnecessary `async`/`await` wrapper when receiving GATT responses, reducing coroutine overhead.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
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