Skip to content

Add personal record sync and PR feedback UI#493

Merged
9thLevelSoftware merged 2 commits into
mainfrom
codex/phase-specific-prs
Jun 4, 2026
Merged

Add personal record sync and PR feedback UI#493
9thLevelSoftware merged 2 commits into
mainfrom
codex/phase-specific-prs

Conversation

@9thLevelSoftware

Copy link
Copy Markdown
Owner

Summary

  • Add personal record synchronization through the sync layer and portal DTOs
  • Update routine weight resolution, exercise config, and workout UI to surface PR-driven feedback
  • Add platform CSV exporter support and expand repository, sync, and view-model coverage

Testing

  • Unit tests updated for personal record repositories, sync manager, and routine weight resolution
  • UI-oriented test coverage updated for exercise config and sync-related behavior

Copilot AI review requested due to automatic review settings June 3, 2026 23:50

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@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 phase-specific personal records (PRs) across the application, updating repositories, view models, UI components, and the sync manager to support concentric, eccentric, and combined PR phases. Key additions include a backfill mechanism for historical sessions and authoritative top-level PR syncing to the portal. Feedback highlights a major performance bottleneck in the backfill process due to scanning the entire workout history on every sync, potential null-pointer exceptions in ExerciseEditBottomSheet when accessing nullable PR properties, and a sync issue where sessionId fails to resolve for PRs associated with previously synced sessions.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +1370 to +1373
override suspend fun backfillPhaseSpecificPRs(profileId: String): Int = withContext(Dispatchers.IO) {
val prRepository = SqlDelightPersonalRecordRepository(db)
val sessions = getWorkoutSessionsModifiedSince(0L, profileId)
var changedRows = 0

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.

high

Scanning the entire workout history from 0L on every sync operation is a major performance bottleneck. For users with a large history, this will execute thousands of database queries and transactions synchronously, blocking the sync process and draining the device's battery. Consider implementing a checkpoint mechanism (e.g., storing the last backfilled session timestamp in a settings/metadata table) or running this backfill only once when the app detects it hasn't been completed.

) {
Text(
text = "$weightPercentOfPR% of PR",
text = "$weightPercentOfPR% of ${currentExercisePR.phase.displayLabel()} PR",

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.

high

Since currentExercisePR is nullable, accessing currentExercisePR.phase directly without safe navigation will cause a compilation error or a NullPointerException at runtime when no PR is set. Use safe navigation and provide a fallback label.

Suggested change
text = "$weightPercentOfPR% of ${currentExercisePR.phase.displayLabel()} PR",
text = "$weightPercentOfPR% of ${currentExercisePR?.phase?.displayLabel() ?: "Combined"} PR",

Column {
Text(
"Personal Record",
"${pr.phase.displayLabel()} Personal Record",

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.

high

Since pr is nullable, accessing pr.phase directly without safe navigation will cause a compilation error or a NullPointerException at runtime. Use safe navigation and provide a fallback label.

Suggested change
"${pr.phase.displayLabel()} Personal Record",
"${pr?.phase?.displayLabel() ?: "Combined"} Personal Record",

Comment on lines +553 to +555
val sessionIdByPrKey = sessions.associate { session ->
"${session.exerciseId}:${session.timestamp}" to session.id
}

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

Since sessions only contains workout sessions modified since lastSync (delta-loaded), any personal record whose corresponding session was synced in a previous sync operation will fail to resolve its sessionId (it will be null). This breaks the session-to-PR relationship on the portal. Consider querying the database for the session IDs of recentPRs if they are not found in the delta sessions list.

@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: 7336caf24f

ℹ️ 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".

sessionId = sessionId,
achievedAt = epochToIso8601(record.timestamp),
updatedAt = epochToIso8601(currentTimeMillis()),
localProfileId = record.profileId,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve profile id when exporting PRs

For non-default profiles, the PersonalRecord instances passed into this new portal DTO path come from SqlDelightSyncRepository.getFullPRsModifiedSince, which currently constructs them without copying row.profile_id, so record.profileId falls back to the domain default of "default". That makes every dedicated PR row pushed through localProfileId look like it belongs to the default profile even though the query was scoped to the active profile, causing PRs to be deduped/attached under the wrong portal profile for multi-profile users. Please populate the profile id (and keep using it here) before sending these rows.

Useful? React with 👍 / 👎.

@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


P2 Badge Use the workout session timestamp for phase PRs

For phase PRs recorded during a normal completed workout, this passes the local timestamp value from line 116 (currentTimeMillis() at PR calculation time), while the saved WorkoutSession.timestamp is the workout start time (coordinator.workoutStartTime). The new sync linker later looks up sessions with exerciseId + achievedAt exact equality, and the backfill path will not rewrite equal-weight PRs, so these live phase PRs are pushed with sessionId = null and the matching set is not marked as a PR. Use the actual session timestamp/id when creating these rows, or make the sync/linker able to resolve the owning session without exact timestamp equality.

ℹ️ 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".

@9thLevelSoftware 9thLevelSoftware merged commit b16731e into main Jun 4, 2026
9 checks passed
@9thLevelSoftware 9thLevelSoftware deleted the codex/phase-specific-prs branch June 4, 2026 01:31
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