3.0 KiB
type, date, project, tags
| type | date | project | tags | |||||
|---|---|---|---|---|---|---|---|---|
| decision | 2026-05-19 | cpas |
|
CPAS — back-dated insert refreshes downstream snapshots
Context
On main branch (post ba2b631 documentation, pre any roll-off model overhaul), the CPAS app stores prior_active_points as an immutable snapshot at violation insert time. The PDF endpoint reads this snapshot to render "Prior Active Points → New Total → Tier".
When a violation is logged with a back-dated incident_date that precedes existing violations, the new violation's own snapshot is computed correctly, but existing later-dated violations' snapshots are stale — they were frozen before the back-dated event existed and so omit it from their 90-day prior window. Re-downloading their PDFs shows the pre-backdate prior/total/tier.
Decision
Refresh downstream snapshots on back-dated insert. Treat back-dating as a timeline rewrite and exempt it from the otherwise strict snapshot-immutability rule. Negate, restore, amend, and hard delete are NOT timeline rewrites and continue to leave snapshots alone.
Implementation (in server.js)
- New helper
recomputeSnapshotsAfter(employeeId, incidentDate)finds all violations for the employee withincident_date > new_date AND incident_date <= new_date + 90 days, recomputes each via the existinggetPriorActivePoints()formula, and only writes UPDATEs where the value changed. POST /api/violationsnow wraps the insert + recompute in a singledb.transaction()so a partial failure can't leave the system with a new violation and stale sibling snapshots.- When refresh affects ≥1 row, a
violation_snapshots_recomputedaudit entry is written withreason: 'backdated_insert',trigger_incident_date, and anaffected[]array of{id, incident_date, old, new}for full traceability. - Forward-dated inserts (the common case) do zero UPDATEs — affected query returns rows but the equality check skips them.
Docs
AGENTS.md"Prior-Points Snapshot" section updated with the back-dating exceptionAGENTS.md"What NOT to Do" updated — the "do not modify prior_active_points" line now carves out the back-dating path explicitly
Verification
node --check server.jspasses- Not runtime-tested in this session (better-sqlite3 won't compile on local Node v24 — see project file). Verification path: docker build, log V1 with a recent date, log V2 with an earlier back-dated date, re-download V1's PDF, confirm "Prior Active Points" now includes V2.
Relationship to roll-off model overhaul
The existing projects/cpas.md "Roll-off model fix (2026-05-27)" section describes a different implementation of recomputeSnapshotsAfter that widens the window to "all later violations" under a clean-cycle roll-off rule. That work is not on main as of today. If/when the roll-off overhaul lands on main, the helper's window scope will need to be widened to match (current scope is the legacy 90-day rolling window).