From the /pr-review of PR #394:
- the profile database opens only once prepare_profile_db has resolved
(deferred preparation; a load started early used to pass, RT1);
- a real VACUUM INTO failure, through a dangling symlink, names the full
path and comes out scrubbed (RV6); the test first checks the raw message
does name the folder;
- deleting a profile removes the -journal side file, the only one this
app produces (RV5);
- test folders are removed when each test ends, a failing one included
(TestDir guard), instead of 42 folders left in /tmp per run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The released-states loop stops at v0.10-v0.14 (state E). State F, the
consolidated schema of v0.15.0 to v0.17.0 without a history, only had
its floor checked; this test runs the whole preparation on it: history
recorded up to v17, nothing applied, no copy, flag repaired.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ADR 0021 records the catch-up rules and amends ADR 0003 and 0005, whose
claims about secondary profiles were false. architecture.md, CLAUDE.md
and the migration rule describe the two migration paths; the guide tells
where the pre-update copy lives and how to remove a database a deletion
on Linux left behind.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tauri-plugin-sql migrates only the database registered with add_migrations,
the default profile's. A secondary profile kept the consolidated schema of
the version that created it and never received a migration afterwards.
prepare_profile_db runs before every Database.load:
- secondary profiles catch up with the same migrations() list (pinned
SHA-384), history kept in _sqlx_migrations; a database without history
gets a floor inferred from its schema (the seven released creation
states are test fixtures), so nothing at or below it is ever replayed;
- a VACUUM INTO copy is taken before the first write, synced, then renamed;
- each version runs in its own transaction with foreign keys on; one that
fails on a foreign key is retried once without them and its orphans are
set to NULL where the key declares ON DELETE SET NULL;
- every profile gets its TEXT manual-categorization flags repaired;
- failures are logged with file names only and the profile still opens.
New profiles are born with their full history (get_new_profile_init_sql).
The plugin keeps databases under app_config_dir(), not app_data_dir():
the same folder on Windows and macOS, not on Linux. repair_migrations,
delete_profile_db and compute_account_return looked in the wrong folder
there. profile_db_path resolves the plugin's folder and validates the
file name; deleting a profile now also removes its SQLite side files and
catch-up copies.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
updateTransactionCategory bound the JS boolean `true`. tauri-plugin-sql
passes a bool to sqlx as a JSON value, so the column received the TEXT
'true', which the getting-started checklist's `is_manually_categorized = 1`
never matches: step 5 never ticked.
toSqlFlag turns a boolean, a number or a backup's string into 0/1. It is
used when a category is set by hand and when a JSON or CSV backup is
restored, since a backup exported while the bug stood carries "true"
(the CSV path read it as 0).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>