feat(storage): remember which server generation wrote the cached catalog
The cache was version-blind: nothing recorded which Jellyfin generation produced a row, so a server upgraded underneath the app kept serving rows parsed under the previous generation's assumptions. Migration 026 adds servers.catalog_generation and deliberately does NOT clear synced_at the way migration 025 did. The column starts NULL, which reads as "no generation recorded yet" rather than "changed", so the first connection after upgrading simply records what it finds. Invalidation happens only when the recorded generation actually changes. That distinction is the point. Treating absent information as a change would charge every existing user a full catalog re-fetch to defend against a server upgrade that has not happened — and at the time of writing, 12.0 is hours old, so essentially no installed server is on the newer generation at all. Capabilities are also wired at repository creation: the version storage already holds is read once, resolved, and handed to the online repository. A missing or unparseable version is not an error — it resolves to the older generation, whose request shapes work on both. TRACES: UR-085 | IR-035, DR-280, DR-284 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,7 @@ pub const MIGRATIONS: &[(&str, &str)] = &[
|
||||
("023_downloads_expiry", MIGRATION_023),
|
||||
("024_multi_user_profiles", MIGRATION_024),
|
||||
("025_backfill_item_library_id", MIGRATION_025),
|
||||
("026_server_catalog_generation", MIGRATION_026),
|
||||
];
|
||||
|
||||
/// Initial schema migration
|
||||
@@ -921,6 +922,25 @@ const MIGRATION_025: &str = r#"
|
||||
UPDATE items SET synced_at = NULL;
|
||||
"#;
|
||||
|
||||
/// Remember which server generation wrote the cached catalog.
|
||||
///
|
||||
/// The cache was version-blind: nothing recorded which Jellyfin generation
|
||||
/// produced a row, so a server upgraded underneath the app kept serving rows
|
||||
/// parsed under the previous generation's assumptions.
|
||||
///
|
||||
/// This deliberately does **not** clear `synced_at` the way MIGRATION_025 did.
|
||||
/// The column starts NULL, which reads as "no generation recorded yet", and the
|
||||
/// first connection after upgrading simply records what it finds. Invalidation
|
||||
/// happens only when the recorded generation actually *changes* — punishing
|
||||
/// every existing user with a full re-fetch for a server upgrade that has not
|
||||
/// happened would cost real bandwidth to defend against nothing. At the time of
|
||||
/// writing no installed server is on the newer generation at all.
|
||||
///
|
||||
/// TRACES: UR-085 | DR-284
|
||||
const MIGRATION_026: &str = r#"
|
||||
ALTER TABLE servers ADD COLUMN catalog_generation TEXT;
|
||||
"#;
|
||||
|
||||
#[cfg(test)]
|
||||
mod migration_024_tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user