Files
2026-06-04 16:20:56 -05:00

45 lines
3.0 KiB
Markdown

---
type: decision
date: 2026-05-19
project: cpas
tags:
- cpas
- snapshot
- backdating
- audit
- mpm
---
# [[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 with `incident_date > new_date AND incident_date <= new_date + 90 days`, recomputes each via the existing `getPriorActivePoints()` formula, and only writes UPDATEs where the value changed.
- `POST /api/violations` now wraps the insert + recompute in a single `db.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_recomputed` audit entry is written with `reason: 'backdated_insert'`, `trigger_incident_date`, and an `affected[]` 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 exception
- `AGENTS.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.js` passes
- 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).