geenforce: the backup hover names both dates, because they mean different things

"Checked 13 Aug 1:20 PM. Verified the backup taken 12 Aug 5:20 PM is still
current." Two facts, and one date could not carry both.

lastseenat moves on every successful confirmation and proves the check is still
running. collectedat moves only when the configuration actually CHANGED and says
what is stored. Showing lastseenat alone hid what is in the backup; showing
collectedat alone read as "last backup was a month ago" on a machine that is
perfectly healthy, because a stable config writes no new revision. The hover now
states the check and the capture separately and says outright that the second
being older is the normal case.

The stale wording gets the same treatment: it names the check that stopped AND
the newest copy that exists, which is the thing someone recovering from it
actually needs.

collectedat is exposed as backupcollectedat. Both stay tooltip-only - the badge
is still just the kind and a colour, so nothing here changes what a new backup
kind has to do to inherit it.
This commit is contained in:
cproudlock
2026-08-13 13:35:05 -04:00
parent 1d7191c2d3
commit 4bded210e4
4 changed files with 66 additions and 12 deletions

View File

@@ -960,7 +960,7 @@ def _asset_facts(hostnames):
'toolpluginid': None,
'displayrole': None,
'backupkind': None, 'backuplastseen': None,
'backuplastseenat': None,
'backuplastseenat': None, 'backupcollectedat': None,
}
_attach_controlled_assets(facts, assetidtohost)
@@ -1083,6 +1083,14 @@ def _attach_backup_state(facts, hostnames):
# Raw value kept beside the wire string so the verdict compares
# datetimes rather than re-parsing its own output.
entry['backuplastseenat'] = revision.lastseenat
# collectedat is when this configuration was CAPTURED, and it only
# moves when the config actually changed. Pairing it with lastseenat
# is what lets the hover say "checked X, and what it verified is
# still the backup taken at Y" instead of one date that has to mean
# both and ends up meaning neither.
entry['backupcollectedat'] = (
revision.collectedat.isoformat() + 'Z'
if revision.collectedat else None)
def _backup_ok(lastseenat, cutoff):
@@ -1225,6 +1233,7 @@ def list_reports():
# trust; the date alone reads as "nothing has happened since", which
# is the healthy steady state and looks like neglect.
'backupok': _backup_ok(known.get('backuplastseenat'), backupcutoff),
'backupcollectedat': known.get('backupcollectedat'),
'backupstaleafterdays': backupafterdays,
'scopename': report.scopename,
'phase': report.phase,