- Per-tag chronic-warning ack (`workspace.tagChronicAcks`)New JSONB column `workspace.tagChronicAcks` (`Record<tag, ISO date>`) + `acknowledgeTagChronicWarning()` helper + `POST /api/cost/by-tag/{tag}/chronic-ack` route + `TagChronicAckButton` client component mounted directly beside the rev-70 `โณ Nd` chronic chip on every tag row whose `consecutiveSpikeDays` has crossed the chronic threshold (3d+). The rev-70 chronic warning sub-sweep now skips tags whose chronic-ack stamp is younger than 7 days. **Strategic significance**: closes the named rev-70 next-sprint candidate ('per-tag chronic-spike ack'). Distinct from the rev-68 per-day daily ack (different surface, different TTL, different intent). The rev-67 daily alarm names today's anomaly โ operator response is 'stop alarming today' (per-day mute). The rev-70 chronic warning names a structural problem โ operator response is 'I see this, I'm intentionally letting it run' (7-day mute). Both can coexist on the same workstream: an operator who's seen both can ack each independently โ daily mute for one day, chronic mute for one week.
- Per-source chronic-spikes v1 endpoint (`GET /api/v1/cost/by-source/chronic-spikes`)Closes the named rev-70 next-sprint candidate ('per-source/per-assignee chronic v1 mirrors') at the per-source axis. New bearer-auth endpoint returns sources whose `source.consecutiveSpikeDays` (rev-61 counter) has crossed the chronic threshold (3d+), sorted by counter value descending. Each row carries today/baseline/spikeRatio when the source is also currently in the rev-58 daily detector; otherwise those fields read 0 (chronic state can persist a day after today's spend cooled). **Strategic significance**: rev 70 shipped the chronic axis on the v1 surface for per-tag but per-source had no v1 equivalent โ MCP hosts driving the desk could see the rev-58 daily alarm and the rev-62 chronic auto-pause action programmatically but couldn't read which sources had crossed the chronic threshold without polling the dashboard. Rev 71 closes that gap.
- Per-assignee chronic-spikes v1 endpoint (`GET /api/v1/cost/by-assignee/chronic-spikes`)Mirrors the rev-71 per-source endpoint at the per-recipient axis. Returns workspace members whose `workspace_member.consecutiveSpikeDays` (rev-64 counter) has crossed the chronic threshold (3d+), with name/email resolved server-side so the payload is self-contained. Today's spike state (rev-62 daily detector) projected when present. **Strategic significance**: closes the chronic axis on the v1 surface for per-assignee โ until rev 71 the rev-64 chronic counter + rev-64 chronic warning push existed only on the dashboard panel and the Slack/outbound surfaces. The chronic axis on the v1 surface now reads consistently across all three dimensions where chronic makes sense: per-source (rev 71) + per-assignee (rev 71) + per-tag (rev 70). The cost-axis MCP cluster has nothing left to design on the chronic surface.
- v1 chronic-ack mirror + visual polishNew bearer-auth `POST /api/v1/cost/by-tag/{tag}/chronic-ack` mirrors the rev-71 dashboard chronic-ack endpoint in lockstep โ the cadence pattern from rev 37 onward (ship the dashboard primitive + the v1 mirror in the same cycle) continues unbroken. New `.ld-cost-tag-chronic-ack` CSS uses an amber/warning palette distinct from the rev-68 daily ack button's red palette so the row-level visual story reads: โก pill (red, today's alarm) โ Ack button (red, mute today) :: โณ chip (red, structural alarm) โ Ack 7d button (amber, mute 7d). Different alarms, different acks, different colours, one consistent reading order. Cumulative micro-polish โ every rev 22+ has carried at least one โ but rev 71's polish is load-bearing because it answers the open question from rev-70: 'I keep seeing the chronic warning daily, what should I actually do?' โ the answer is now one chip-tap away.