refactor: remove all Vitruvian references — legal rebrand to Phoenix - #709
refactor: remove all Vitruvian references — legal rebrand to Phoenix#7099thLevelSoftware wants to merge 9 commits into
Conversation
- Rename iOS project: VitruvianPhoenix → PhoenixApp (directory, xcodeproj, scheme, swift, entitlements) - Rename Android: VitruvianApp → PhoenixApp, VitruvianTheme → PhoenixTheme - Rename SQLDelight: VitruvianDatabase.sq → PhoenixDatabase.sq - Update settings.gradle.kts root project name: ProjectPhoenix - Update AndroidManifest: Theme.PhoenixProject, .PhoenixApp - Replace all icon assets with new Phoenix logo - Scrub all Vitruvian/vitphoe references from source, tests, docs, CI workflows - Verified: grep -ri vitruvian = 0, grep -ri vitphoe = 0 - Builds verified: SQLDelight interface gen, Kotlin Android/iOS, Xcode device build
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 97235f036e
ℹ️ 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".
| companion object { | ||
| private const val TAG = "DriverFactory" | ||
| private const val DATABASE_NAME = "vitruvian.db" | ||
| private const val DATABASE_NAME = "phoenix.db" |
There was a problem hiding this comment.
Preserve the existing database filename during rebrand
On an upgrade from any released build, user data remains in vitruvian.db, but the unchanged application/bundle ID now opens phoenix.db; because there is no file migration or fallback lookup, SQLDelight creates a fresh empty database and all profiles, routines, and workout history appear lost. The same filename change is present in the iOS driver, so both platforms need to keep the on-disk name or rename/copy the existing database before opening it.
Useful? React with 👍 / 👎.
| private const val ENCRYPTED_PREFS_FILE = "phoenix_secure_preferences" | ||
| private const val PLAINTEXT_PREFS_FILE = "phoenix_preferences" |
There was a problem hiding this comment.
Migrate the existing Android preference stores
For users upgrading an existing Android installation, these new filenames create empty preference stores while vitruvian_preferences and vitruvian_secure_preferences retain all previous settings and encrypted portal credentials. Nothing copies from those legacy files—the token migration below only reads the newly named plaintext store—so users are logged out and lose units, theme, safety, and other persisted choices even if the database-name regression is fixed.
Useful? React with 👍 / 👎.
| name.startsWith("Vitruvian", ignoreCase = true) | ||
| if (isVitruvian) { | ||
| log.i { "Found Vitruvian by name: $name" } | ||
| name.startsWith("Phoenix", ignoreCase = true) |
There was a problem hiding this comment.
Keep accepting the legacy BLE advertised-name prefix
When a compatible machine advertises a non-null name beginning with Vitruvian rather than Vee_ or VIT, replacing the previously accepted prefix with Phoenix makes this filter return false immediately. Because the named-device branch exits before checking the known service UUID/service data, those physical machines disappear from the scan results and cannot be selected; branding can change in UI text without changing identifiers emitted by existing firmware.
Useful? React with 👍 / 👎.
| @@ -282,7 +282,7 @@ private fun EulaContent() { | |||
| content = null, | |||
| ) | |||
| Text( | |||
| text = "Project Phoenix is an independent, community-developed project. IT IS NOT AFFILIATED WITH, ENDORSED BY, AUTHORIZED BY, OR SUPPORTED BY VITRUVIAN INVESTMENTS PTY LTD (IN LIQUIDATION), MANAGED BY MERCHANTS ADVISORY, OR ANY OTHER EQUIPMENT MANUFACTURER.", | |||
| text = "Project Phoenix is an independent, community-developed project. IT IS NOT AFFILIATED WITH, ENDORSED BY, AUTHORIZED BY, OR SUPPORTED BY PHOENIX INVESTMENTS PTY LTD (IN LIQUIDATION), MANAGED BY MERCHANTS ADVISORY, OR ANY OTHER EQUIPMENT MANUFACTURER.", | |||
There was a problem hiding this comment.
Restore the actual company name in the legal disclaimer
The app's rebrand cannot rename the third-party legal entity: changing VITRUVIAN INVESTMENTS PTY LTD (IN LIQUIDATION) to PHOENIX INVESTMENTS PTY LTD makes the no-affiliation clause refer to a different or nonexistent company. In every accepted EULA this now fails to disclaim affiliation with the actual equipment manufacturer, undermining the stated legal purpose of the change.
Useful? React with 👍 / 👎.
| type = "application/json" | ||
| putExtra(Intent.EXTRA_STREAM, uri) | ||
| putExtra(Intent.EXTRA_SUBJECT, "Vitruvian Phoenix Backup") | ||
| putExtra(Intent.EXTRA_SUBJECT, "Phoenix Phoenix Backup") |
There was a problem hiding this comment.
🔥 The Roast: A blind global replace of Vitruvian → Phoenix turned "Vitruvian Phoenix Backup" into "Phoenix Phoenix Backup", and now your share-sheet subject line reads like a nervous stutter. Find-and-replace without grep is how you ship "Project Phoenix Phoenix Project".
🩹 The Fix:
| putExtra(Intent.EXTRA_SUBJECT, "Phoenix Phoenix Backup") | |
| putExtra(Intent.EXTRA_SUBJECT, "Phoenix Backup") |
📏 Severity: nitpick
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| @@ -43,7 +43,7 @@ private val DarkSlate = Color(0xFF0F172A) | |||
| private val DeepNavy = Color(0xFF1E293B) | |||
|
|
|||
| /** | |||
| * Animated splash screen with the Vitruvian Phoenix logo. | |||
| * Animated splash screen with the Phoenix Phoenix logo. | |||
There was a problem hiding this comment.
🔥 The Roast: Same find-and-replace felony as the backup subject — your splash screen's own KDoc now brags about "the Phoenix Phoenix logo", which is either a meditation on reincarnation or a typo. Either way, doc comments shouldn't develop a stammer.
🩹 The Fix:
| * Animated splash screen with the Phoenix Phoenix logo. | |
| * Animated splash screen with the Phoenix logo. |
📏 Severity: nitpick
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
|
|
||
| companion object { | ||
| const val CHANNEL_ID = "vitruvian_workout_channel" | ||
| const val CHANNEL_ID = "phoenix_workout_channel" |
There was a problem hiding this comment.
🔥 The Roast: Renaming the notification CHANNEL_ID from vitruvian_workout_channel to phoenix_workout_channel looks harmless until you remember Android persists channel-level user preferences (importance override, sound, DND bypass) keyed by that string forever. Existing users keep a ghost channel they can no longer reach from app settings, and their overrides quietly stop applying. This is the kind of change that turns into a "weird, my workout notifications changed" 1-star review six months later.
🩹 The Fix: Keep the existing vitruvian_workout_channel ID and only rename the user-visible channel name. If you really want the ID to match the brand, write a one-shot migration that copies the old channel's overrides onto the new one before deleting the old channel. Don't drop the old ID silently.
📏 Severity: warning
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| @@ -272,7 +272,7 @@ class IosDataBackupManager( | |||
| .replace("-", "") + "_" + | |||
| KmpUtils.formatTimestamp(KmpUtils.currentTimeMillis(), "HH:mm:ss") | |||
| .replace(":", "") | |||
| val fileName = "vitruvian_backup_$timestamp.json" | |||
| val fileName = "phoenix_backup_$timestamp.json" | |||
There was a problem hiding this comment.
🔥 The Roast: Renaming the backup filename prefix from vitruvian_backup_*.json to phoenix_backup_*.json means every user who emailed themselves a backup, dropped one in iCloud Drive, or pulled one off Files now has files the new app won't recognize as recent imports. They aren't corrupted — they're just abandoned with a different first name. Survives uninstall, dies on rebrand.
🩹 The Fix: Either keep vitruvian_backup_*.json (the file name is internal, the brand is in the JSON contents / UI label), or accept BOTH prefixes when listing/importing backups so existing files still surface. Don't make users redo work the rebrand didn't actually need to invalidate.
📏 Severity: warning
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| <exclude domain="database" path="vitruvian.db-shm" /> | ||
| <exclude domain="sharedpref" path="vitruvian_preferences.xml" /> | ||
| <exclude domain="sharedpref" path="vitruvian_secure_preferences.xml" /> | ||
| <exclude domain="database" path="phoenix.db" /> |
There was a problem hiding this comment.
🔥 The Roast: The auto-backup exclude paths were renamed from vitruvian.db/vitruvian_preferences.xml to phoenix.db/phoenix_preferences.xml, but the old files still live inside Google Drive backups of every user who installed v1. When they restore on a new device, Android dutifully puts vitruvian.db back — and the new app (looking for phoenix.db) sees an empty database, same data-loss outcome as the local rename. Two paths to the same cliff.
🩹 The Fix: Add the legacy paths alongside the new ones so old backups still skip what they used to skip, and pair this with a first-launch migration that renames any pre-existing vitruvian.db to phoenix.db before SQLDelight opens the driver (the right place for the DB rename, not here).
📏 Severity: warning
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| else -> VitruvianModel.Unknown | ||
| fun detectModel(deviceName: String): PhoenixModel = when { | ||
| deviceName.startsWith("Vee_", ignoreCase = true) -> PhoenixModel.VFormTrainer | ||
| deviceName.startsWith("VIT", ignoreCase = true) -> PhoenixModel.TrainerPlus |
There was a problem hiding this comment.
🔥 The Roast: fun getDeviceDisplayInfo(deviceName: String): String = "Phoenix Trainer ($deviceName)" — there is no such thing as a "Phoenix Trainer" sold on this planet. The hardware manufacturer did not rebrand; only your app did. Every telemetry payload, every analytics export, every diagnostic report now ships with manufacturer="Phoenix" for a device that was built, branded, and boxed as a Vitruvian. That is a misrepresentation baked into data your own EULA insists you don't misrepresent the manufacturer of.
🩹 The Fix: Keep the actual manufacturer string (Vitruvian) in the equipment/manufacturer fields used for telemetry and protocol logging, and only render "Phoenix" in UI text. If the goal is just a safer display, use "Trainer ($deviceName)" or pull from a localized UI resource. Don't lie into your own logs.
📏 Severity: warning
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
Code Review Roast 🔥Verdict: Request changes | Recommendation: One wrong diagnostic-code label in the new migration coordinator would mis-route every staging-cleanup failure to support. Overview
Issue Details (click to expand)
🏆 Best part: The new 💀 Worst part: Filing a staging-cleanup failure under 📊 Overall: A real upgrade path for once — readable, testable, and conservative about data loss — wrapped in enough scaffolding to file a planning application. The Ponytail pass leaves alone what it must (locks, fingerprints, recovery-then-cutover) and trims the rest. One bug in the diagnostic taxonomy, three ceremonies to delete, and this can ship. Files Reviewed (incremental diff — 31 files, ~4000 LOC)
Previously open P1s on unchanged files (BLE filter prefix, EULA legal entity name, notification channel ID, iOS backup filename, AndroidBackupRules vitruvian exclude paths, HardwareDetection "Phoenix Trainer" telemetry, Splash/Eula "Phoenix Phoenix") are out of incremental scope and intentionally not re-flagged. Fix these issues in Kilo Cloud Previous Review Summaries (2 snapshots, latest commit 2502317)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 2502317)Verdict: Incremental commit resolves 2 of 4 P1s (DB filename + SharedPreferences filenames on both platforms); 2 P1s and 6 lower-severity items remain open on unchanged files. Recommendation: Address remaining P1s (BLE filter, EULA legal entity) before merge. Overview
Resolved since previous review (click to expand)
New issue on changed lines
Carried-forward, still open on unchanged files (not re-commented per incremental scope)
🏆 Best part: The incremental fix is the right shape — keep the on-disk identifier stable, change the brand in UI strings. That's the textbook answer to "rebrand without orphaning users", and the author chose it twice (Android + iOS). Whoever wrote this commit clearly read the previous review and shipped the surgical version, not a refactor. 💀 Worst part: The fix is half the surgery. Same class of regression (rename without backward-compat) is still present in BLE filter, EULA, notification channel, and backup filenames, just on files this commit didn't touch. The author's instinct was right; the coverage was incomplete. 📊 Overall: Two bleeding wounds sutured, four still open. The patient can walk, but they shouldn't run the marathon yet. Files Reviewed (incremental diff — 7 files changed)
Ponytail ReviewIncremental diff is purely a restoration of original identifiers plus a binary icon swap. No new abstractions, no new helpers, no speculative config. The new test-constant fragility is the only deletion candidate: replace the three magic numbers with an
Ponytail net: -5 lines. Suggested Minimal Patch
Final Merge GuidanceDo not merge until the BLE filter prefix and EULA legal entity are fixed on unchanged files. After that, the rebrand is genuinely upgrade-safe and Ponytail is clean. The test-constant fragility on the changed line is a recommended cleanup but not merge-blocking — it's the same hazard the code already had. Fix these issues in Kilo Cloud Previous review (commit 97235f0)Verdict: 6 New Issues Found (10 total with existing P1s) | Recommendation: Address before merge Overview
Existing bot comments already flagged the 4 P1 data-loss / legal hazards:
My 6 new findings (this pass):
The same find-and-replace sloppiness also stuttered 🏆 Best part: The rebrand is honestly thorough — 465 files, generated SQLDelight interface, scheme/xcodeproj, Compose resource package, localization strings, CI scripts, all scrubbed. That's a real piece of work. 💀 Worst part: Four P1 data-loss regressions shipped in a PR whose only checks were 📊 Overall: Like pulling off a heist and leaving the getaway driver's keys in the vault — the brand is gone, but the cars (databases, prefs, notification channels, cloud backups) are still parked under the old name. One first-launch migration pass would turn this from a data-loss incident into a true 1.0.0. Files Reviewed (highlights; 465 changed)
Final Merge GuidanceDo not merge until the 4 existing P1s (DB filename, prefs filename, BLE filter, EULA legal entity) are fixed with a first-launch migration that renames Reviewed by minimax-m3 · Input: 59.5K · Output: 12.3K · Cached: 793.9K Review guidance: REVIEW.md from base branch |
- Revert DATABASE_NAME to 'vitruvian.db' (Android + iOS) to preserve existing user data on upgrade - Revert Android preference filenames to 'vitruvian_secure_preferences' / 'vitruvian_preferences' - Update SQLDelight fault injection statement IDs to match regenerated PhoenixDatabase identifiers - Add opaque black background to iOS AppIcon (Apple requires no transparent corners) - Remove accidentally committed HTML file (failed Google Drive download)
There was a problem hiding this comment.
Incremental review on commit 2502317 (fix: address PR #709 review — preserve upgrade paths and fix icon). Two of the four P1s (DB filename, SharedPreferences filenames) are resolved; two P1s (BLE filter, EULA legal entity) remain open on unchanged files. One new test-shrink finding on the changed test constants.
| const val SET_ACTIVE_PROFILE_IDENTIFIER = 373_348_112 | ||
| const val DELETE_PROFILE_IDENTIFIER = 787_673_935 | ||
| const val CLEAR_RECOVERY_JOURNAL_IDENTIFIER = 1_230_173_044 | ||
| const val SET_ACTIVE_PROFILE_IDENTIFIER = 415_176_795 |
There was a problem hiding this comment.
🔥 The Roast: Three hand-typed magic numbers (415_176_795, -1_674_170_908, 1_812_830_207) are supposed to match SQLDelight's internal Int hash of setActiveProfile:, deleteProfile:, and the recovery-journal clear query. The fact that this PR had to regenerate them — because the original rebrand renamed the database file and quietly re-hashed every query identifier — is the bug report writing itself. If a future engineer reorders a single query, renames the .sq file, or upgrades the SQLDelight Gradle plugin, every InjectedTransitionFailure test silently no-ops and the suite turns green while exercising nothing. This is "passing tests" as a hazard.
🩹 The Fix: Stop using opaque identifier integers. Either match on the sql text (the execute signature already passes it — if (sql.startsWith("UPDATE UserProfile SET isActive")) is human-readable and survives identifier churn), or import the generated query object from PhoenixDatabase and call setActiveProfileQueries directly with a wrapping driver. Either approach removes the silent-breakage class entirely and removes the need to ever re-derive these constants after a database rename.
📏 Severity: warning
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 250231795b
ℹ️ 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".
| @@ -73,7 +73,7 @@ class ThemeViewModel(private val settings: Settings) : ViewModel() { | |||
|
|
|||
| companion object { | |||
| const val THEME_MODE_KEY = "theme_mode" | |||
| const val THEME_PREFS_FILE = "vitruvian_preferences" | |||
| const val THEME_PREFS_FILE = "phoenix_preferences" | |||
There was a problem hiding this comment.
Keep startup reads on the restored preference store
On Android, PlatformModule.android.kt now correctly restores the live Settings store to vitruvian_preferences, but MainActivity and applyPersistedApplicationNightMode use this constant to read the theme and language before Compose starts. They therefore read an empty phoenix_preferences file, so upgraded users get the default system theme and locale during cold-start initialization instead of their saved choices. Fresh evidence after the earlier preference-store finding is this mismatch between the corrected DI store and the still-renamed startup constant.
Useful? React with 👍 / 👎.
| <exclude domain="database" path="phoenix.db" /> | ||
| <exclude domain="database" path="phoenix.db-journal" /> | ||
| <exclude domain="database" path="phoenix.db-wal" /> | ||
| <exclude domain="database" path="phoenix.db-shm" /> | ||
| <exclude domain="sharedpref" path="phoenix_preferences.xml" /> |
There was a problem hiding this comment.
Exclude the filenames the app actually persists
On Android 12+ device-transfer paths that apply these extraction rules, the exclusions no longer match the files opened by this revision: both drivers retain vitruvian.db, and PlatformModule retains vitruvian_preferences.xml and vitruvian_secure_preferences.xml. Consequently the database and sensitive preference stores are eligible for transfer despite this file's explicit exclusion intent; the API 23–30 backup rules have the same mismatch and should likewise retain the legacy paths.
Useful? React with 👍 / 👎.
|
|
||
| companion object { | ||
| const val CHANNEL_ID = "vitruvian_workout_channel" | ||
| const val CHANNEL_ID = "phoenix_workout_channel" |
There was a problem hiding this comment.
Preserve the installed notification channel ID
For Android users upgrading an existing installation, changing the channel ID makes createNotificationChannel() create a separate channel rather than renaming the existing workout channel. Any user-selected importance, sound, vibration, or disabled state attached to vitruvian_workout_channel is lost, and users who disabled that channel can begin receiving workout notifications again; keep the stable ID and change only the channel's display name.
Useful? React with 👍 / 👎.
| "\$migrationReady = \$false", | ||
| "do {", | ||
| " \$migrationLine = & \$adb shell run-as \$package grep -F profile_preferences_legacy_migration_complete_v1 shared_prefs/vitruvian_preferences.xml 2>\$null", | ||
| " \$migrationLine = & \$adb shell run-as \$package grep -F profile_preferences_legacy_migration_complete_v1 shared_prefs/phoenix_preferences.xml 2>\$null", |
There was a problem hiding this comment.
Point the schema fixture check at the retained stores
When the documented schema-42 upgrade workflow runs against this revision, this polling command checks phoenix_preferences.xml, while the application still stores the migration marker in vitruvian_preferences.xml; the workflow therefore times out even after a successful migration. The same test later requires databases/phoenix.db, so it currently enforces a guide that cannot inspect the database opened by DriverFactory rather than validating the real upgrade path.
Useful? React with 👍 / 👎.
| operations.delete(DatabaseArtifact.STAGING) | ||
| } catch (failure: Throwable) { | ||
| throw DatabaseFileMigrationException( | ||
| DatabaseMigrationFailureCode.RECOVERY_COPY_FAILED, |
There was a problem hiding this comment.
🔥 The Roast: This deleteIncompleteStaging() helper throws RECOVERY_COPY_FAILED when the action is "delete a stuck staging file from a completely different codepath." Three call sites funnel unrelated failures (post-migration cleanup, recovery reconstruction, plain target preparation) into a diagnostic code that screams "recovery copy is busted." When the user sees DB_RECOVERY_COPY_FAILED on the failure screen, support will hunt for a bad recovery copy that has nothing to do with the actual problem. The naming lies harder than a politician before election day.
🩹 The Fix:
| DatabaseMigrationFailureCode.RECOVERY_COPY_FAILED, | |
| DatabaseMigrationFailureCode.STAGING_CLEANUP_FAILED, |
…and add a matching STAGING_CLEANUP_FAILED entry to DatabaseMigrationFailureCode (line ~36). The other call sites that genuinely mean "recovery copy failed" are correct.
📏 Severity: warning
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| // Resolving this singleton is the persisted-file startup boundary. The | ||
| // values are intentionally resolved in this order so no feature dependency | ||
| // can observe a partially prepared database or preference store. | ||
| single { |
There was a problem hiding this comment.
🔥 The Roast: PersistedFileStartupPrerequisite is a data object whose entire purpose is "wait for these singletons to resolve." This is the dependency-injection equivalent of installing a revolving door in a hallway that's already a one-way corridor — PhoenixDatabase and both Settings are already single { ... }, so the moment ANY consumer asks Koin for them, Koin resolves them in the right order anyway. The "boundary" ceremony adds a token class plus three get<>() lines that just re-invoke what Koin already does for free.
🩹 The Fix: Replace the whole block with single<Unit> { Unit } named "persistedFileStartupPrerequisite", or — more idiomatically — drop the marker entirely and have AndroidAppHost / IosAppHost resolve a single composed single { PersistedFileReadiness(get(), get(), get()) } directly. Then data object PersistedFileStartupPrerequisite and its content delete.
📏 Severity: suggestion
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| applicationId = "com.devil.phoenixproject" | ||
| minSdk = 26 | ||
| targetSdk = 37 | ||
| testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" |
There was a problem hiding this comment.
🤏 The Roast: testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" is the default. Configuring the default to be the default is a tattoo that reads "I am here."
🩹 The Fix:
| testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" |
📏 Severity: nitpick
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b98aa9f89b
ℹ️ 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".
| @@ -73,7 +73,7 @@ class ThemeViewModel(private val settings: Settings) : ViewModel() { | |||
|
|
|||
| companion object { | |||
| const val THEME_MODE_KEY = "theme_mode" | |||
| const val THEME_PREFS_FILE = "vitruvian_preferences" | |||
| const val THEME_PREFS_FILE = "phoenix_preferences" | |||
There was a problem hiding this comment.
Migrate preferences before startup theme reads
On the first Android launch after upgrading, PhoenixApp.attachBaseContext() and MainActivity read this newly named store before AndroidAppHost resolves PersistedFileStartupPrerequisite, which is what actually runs AndroidPreferenceFileMigrator; they therefore see an empty store and apply the system theme instead of the saved explicit mode. The fresh evidence beyond the earlier store-mismatch comment is that the store is now migrated correctly but only after these cold-start reads, leaving the application night-mode qualifier incorrect until the user changes the setting or restarts.
Useful? React with 👍 / 👎.
| private val PHOENIX_DEVICE = Device( | ||
| manufacturer = "Phoenix", | ||
| model = "Trainer", | ||
| type = Device.TYPE_UNKNOWN, |
There was a problem hiding this comment.
Preserve the hardware manufacturer in Health Connect
When Android users export newly completed workouts, this value is written into Metadata.activelyRecorded for both exercise and calorie records, so Health Connect now records a nonexistent Phoenix device manufacturer. Phoenix is the app's new brand, not the manufacturer of the Trainer hardware; keep the actual hardware manufacturer here or omit the device attribution so exported health records retain accurate provenance.
Useful? React with 👍 / 👎.
…#711) * refactor: remove all Vitruvian references — legal rebrand to Phoenix - Rename iOS project: VitruvianPhoenix → PhoenixApp (directory, xcodeproj, scheme, swift, entitlements) - Rename Android: VitruvianApp → PhoenixApp, VitruvianTheme → PhoenixTheme - Rename SQLDelight: VitruvianDatabase.sq → PhoenixDatabase.sq - Update settings.gradle.kts root project name: ProjectPhoenix - Update AndroidManifest: Theme.PhoenixProject, .PhoenixApp - Replace all icon assets with new Phoenix logo - Scrub all Vitruvian/vitphoe references from source, tests, docs, CI workflows - Verified: grep -ri vitruvian = 0, grep -ri vitphoe = 0 - Builds verified: SQLDelight interface gen, Kotlin Android/iOS, Xcode device build * fix: address PR #709 review — preserve upgrade paths and fix icon - Revert DATABASE_NAME to 'vitruvian.db' (Android + iOS) to preserve existing user data on upgrade - Revert Android preference filenames to 'vitruvian_secure_preferences' / 'vitruvian_preferences' - Update SQLDelight fault injection statement IDs to match regenerated PhoenixDatabase identifiers - Add opaque black background to iOS AppIcon (Apple requires no transparent corners) - Remove accidentally committed HTML file (failed Google Drive download) * test: specify persisted database filename migration * feat(android): migrate persisted Phoenix database filename safely * feat(ios): migrate persisted Phoenix database filename safely * feat(android): migrate legacy preference filenames * feat: block startup until persisted-file migration is safe * test: verify Phoenix persisted-file upgrade path * docs: record PR 709 migration evidence --------- Co-authored-by: Devil <dasblueyeddevil@gmail.com> Co-authored-by: Codex <codex@openai.com>
Summary
Legal rebrand plus an upgrade-safe persisted-file migration. Existing Android and iOS installations keep their sandbox and local data while the active database and Android preference stores move to Phoenix filenames.
This supersedes the earlier “keep legacy persisted filenames” workaround. Fresh installs and successful upgrades use:
phoenix.dbphoenix-recovery.dbphoenix.db.migrating,phoenix-db-migration.lockphoenix_preferences,phoenix_secure_preferencesphoenix_preferences_recovery,phoenix_secure_preferences_recoveryRebrand changes
Persisted-file compatibility
DB_DUAL_DATABASES; neither candidate is opened, changed, selected, or merged automatically.Compatibility lookup remains indefinitely for skipped-release upgrades. Legacy filename literals are intentionally limited to:
DatabaseFileNames.LEGACYAndroidPreferenceFileNames.LEGACY_PLAINTEXTandLEGACY_ENCRYPTEDVerification completed
:shared:verifyCommonMainPhoenixDatabaseMigration: pass:shared:compileKotlinIosArm64: passgit diff --check: passThe disposable API 35 upgrade matrix passed all six scenarios: Fresh, v0.9.6 Upgrade, InterruptedStaging, CorruptSource, DualDatabase, and LowStorage. The upgrade retained 3 profiles, 10 workouts, 1 routine, plaintext preferences, and a real committed-WAL payload while advancing schema 43 → 47. Low storage reached 372 KiB free, blocked with
DB_RECOVERY_COPY_FAILED, preserved the legacy source, and completed through the rendered Retry action after recovery. Successful scenarios retained neutral recovery on the migrated launch and removed it on the next launch.Detailed procedure and evidence contract:
docs/qa/persisted-file-upgrade.md.Remaining release gates — do not merge yet
compileTestKotlinIosArm64is still blocked by three pre-existing errors in unchanged tests (RoutineSetWeightResolverTestandWorkoutExecutionGuardRestoredRuntimeTest).spotlessCheckstill reports 168 unrelated pre-existing Kotlin formatting violations; all files touched here are clean.Published implementation branch head:
b98aa9f8(rebrand/remove-vitruvian-references). Because the PR is closed, GitHub still exposes its historical pull ref at25023179until a maintainer reopens it.PR remains closed and is not being reopened automatically. Reopen only after the external signed/device gates are attached.