"""backups: record when a configuration was last confirmed unchanged. Dedup means an unchanged config writes NO revision, so `collectedat` moves only when something changes. A machine whose settings have been stable for six months therefore has a six-month-old newest revision and is entirely healthy - and ShopDB had no way to tell it apart from a machine whose backup stopped running six months ago. The evidence that a check happened existed only in a log file on the PC. `lastseenat` records the check rather than the change. It is touched on every matching post, including the no-op that writes nothing else. Backfilled from `collectedat` (falling back to `createdat`) so existing rows start from the last moment we can actually prove the config was current, rather than from now - claiming a fresh check that never happened would be worse than saying nothing. """ from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'backups0002lastseenat' down_revision = 'backups0001baseline' branch_labels = None depends_on = None def upgrade(): columns = {c['name'] for c in sa.inspect(op.get_bind()).get_columns('backuprevisions')} if 'lastseenat' not in columns: op.add_column('backuprevisions', sa.Column('lastseenat', sa.DateTime(), nullable=True)) op.execute('UPDATE backuprevisions ' 'SET lastseenat = COALESCE(collectedat, createdat)') def downgrade(): columns = {c['name'] for c in sa.inspect(op.get_bind()).get_columns('backuprevisions')} if 'lastseenat' in columns: op.drop_column('backuprevisions', 'lastseenat')