Add two-stage run verification and 24-hour Activity filter
All checks were successful
Deploy / deploy (push) Successful in 57s

Status now reads "Sent" when the confirmation click lands, since that
only means MassPrice accepted the run request, not that it finished —
their own processing is async and takes anywhere from ~1 to ~22
minutes in observed practice. A new "Complete" column tracks that
separately: run_rule() captures a watermark (the target rule's current
top data-activitylogid on /Activity/List, not the displayed timestamp
string, to sidestep fragile date/timezone parsing) before submitting,
and scheduler.py schedules a one-off verify_run() job
VERIFY_DELAY_MINUTES later to check whether a new "Complete" entry
appeared past that watermark.

rebuild_jobs() now only clears recurring "rule-*" jobs, not the one-off
"verify-*" jobs, so editing a schedule can't cancel a verification
that's already in flight for an earlier run.

Also scopes the Activity page to the last 24 hours per request.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6TgffxTvYhqxykAbVQg2v
This commit is contained in:
Barely Removable 2026-08-31 21:49:45 -07:00
parent 988db5d5c4
commit 8b58dadc5a
8 changed files with 249 additions and 20 deletions

View file

@ -9,6 +9,7 @@
--accent-dim: #1e3a5f;
--success: #34d399;
--failure: #f87171;
--warn: #fbbf24;
--radius: 8px;
}
@ -111,8 +112,12 @@ footer {
.rule-last-run { font-size: 0.82rem; }
.status-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; }
.status-dot.status-success { background: var(--success); }
.status-dot.status-success,
.status-dot.status-sent,
.status-dot.status-complete { background: var(--success); }
.status-dot.status-failure { background: var(--failure); }
.status-dot.status-pending { background: var(--text-dim); }
.status-dot.status-not-confirmed { background: var(--warn); }
.status-row-failure td { color: #f2a3a3; }
.schedule-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }