Summary
Migration 20260503221947_AddRefreshTokenReplacedBy is missing its .Designer.cs companion in both src/SentenceStudio.Shared/Migrations/ (Postgres) and src/SentenceStudio.Shared/Migrations/Sqlite/ folders. EF Core discovers migrations via the [Migration("…")] attribute that the Designer file carries — so without it, MigrateAsync silently skips this migration. The next migration's ApplicationDbContextModelSnapshot.cs already reflects the new column, masking the gap.
Symptom
- Azure Postgres prod DB:
__EFMigrationsHistory was missing this row; RefreshTokens had no ReplacedByToken column.
/api/auth/refresh threw Npgsql.PostgresException 42703: column r.ReplacedByToken does not exist (line 212 of AuthEndpoints.cs).
- Cascade: AI calls returned 401 → ClozureService deserialized empty response → Cloze page showed "No cloze sentences available" toast. (Also affects every other AI-backed activity once the access token expires.)
Affects
- Production Postgres: hot-patched 2026-05-09 via direct
ALTER TABLE + INSERT into __EFMigrationsHistory. No further action needed for this DB.
- Future fresh deploys (any new Postgres DB): migration will still silently skip;
NumbersActivityPhase1 will run on top, leaving ReplacedByToken column missing.
- Mobile SQLite: new app installs that bootstrap from migrations are likely affected too. Existing devices with a populated DB are fine because their schema predates the gap.
Files
src/SentenceStudio.Shared/Migrations/20260503221947_AddRefreshTokenReplacedBy.cs ← exists
src/SentenceStudio.Shared/Migrations/20260503221947_AddRefreshTokenReplacedBy.Designer.cs ← MISSING
src/SentenceStudio.Shared/Migrations/Sqlite/20260503221947_AddRefreshTokenReplacedBy.cs ← exists
src/SentenceStudio.Shared/Migrations/Sqlite/20260503221947_AddRefreshTokenReplacedBy.Designer.cs ← MISSING
Fix
Regenerate via dotnet ef:
- Remove the broken migration (won't roll back the schema since it never applied to Postgres prod via EF; the column was added manually).
- Re-add it via
dotnet ef migrations add AddRefreshTokenReplacedBy … — generates both .cs and .Designer.cs.
- Repeat for the SQLite provider — see
.squad/skills/ef-dual-provider-migrations/SKILL.md.
- Run
scripts/validate-mobile-migrations.sh.
- Verify the resulting migration is a no-op against current model snapshots (i.e.,
Up/Down only add/drop the column).
- Confirm
__EFMigrationsHistory row in prod (already inserted manually) matches the new MigrationId. If dotnet ef regenerates with a different timestamp, the prod row needs to be updated.
Workaround applied (reference only)
BEGIN;
ALTER TABLE "RefreshTokens" ADD COLUMN IF NOT EXISTS "ReplacedByToken" text NULL;
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20260503221947_AddRefreshTokenReplacedBy', '10.0.7')
ON CONFLICT ("MigrationId") DO NOTHING;
COMMIT;
Related
- Original migration commit:
0014a84c fix(auth): make login persist across restart + install (single-flight refresh, 24h JWT, grace window)
- Skill reference:
.squad/skills/ef-dual-provider-migrations/SKILL.md — dual-provider workflow that should have caught this.
Summary
Migration
20260503221947_AddRefreshTokenReplacedByis missing its.Designer.cscompanion in bothsrc/SentenceStudio.Shared/Migrations/(Postgres) andsrc/SentenceStudio.Shared/Migrations/Sqlite/folders. EF Core discovers migrations via the[Migration("…")]attribute that the Designer file carries — so without it, MigrateAsync silently skips this migration. The next migration'sApplicationDbContextModelSnapshot.csalready reflects the new column, masking the gap.Symptom
__EFMigrationsHistorywas missing this row;RefreshTokenshad noReplacedByTokencolumn./api/auth/refreshthrewNpgsql.PostgresException 42703: column r.ReplacedByToken does not exist(line 212 ofAuthEndpoints.cs).Affects
ALTER TABLE+INSERTinto__EFMigrationsHistory. No further action needed for this DB.NumbersActivityPhase1will run on top, leavingReplacedByTokencolumn missing.Files
Fix
Regenerate via
dotnet ef:dotnet ef migrations add AddRefreshTokenReplacedBy …— generates both.csand.Designer.cs..squad/skills/ef-dual-provider-migrations/SKILL.md.scripts/validate-mobile-migrations.sh.Up/Downonly add/drop the column).__EFMigrationsHistoryrow in prod (already inserted manually) matches the new MigrationId. Ifdotnet efregenerates with a different timestamp, the prod row needs to be updated.Workaround applied (reference only)
Related
0014a84c fix(auth): make login persist across restart + install (single-flight refresh, 24h JWT, grace window).squad/skills/ef-dual-provider-migrations/SKILL.md— dual-provider workflow that should have caught this.