feat(ACTIVITY-WP-0014): idempotency-keyed State Hub writes (T05, in-repo part)

Add activity_core/state_hub_write: every State Hub write (report-sink,
ops-evidence, schedule-miss) now sends a stable Idempotency-Key header derived
from run_id:instruction_id:event_type. Makes writes safe to buffer/replay under
the future state-hub beachhead without duplicate progress/triage events. The
read-based _progress_exists dedup is now best-effort (returns False on connection
error instead of hard-failing), so the guarantee lives on the keyed write rather
than a live read. Tests + runbook note. Endpoint adoption / proxy retirement stays
blocked on the state-hub beachhead capability.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 21:38:46 +02:00
parent f90591c5f1
commit 88fe359385
7 changed files with 181 additions and 19 deletions

View File

@@ -358,6 +358,27 @@ Legacy values are still accepted: `catchup` → `catchup_all`,
> brief outage at trigger time silently dropped the fire with no recovery and no
> log line. The `daily-statehub-wsjf-triage` definition now uses `catchup_latest`.
## State Hub write idempotency (ACTIVITY-WP-0014 T05)
Every State Hub write from activity-core (report-sink progress, ops-evidence
progress, schedule-miss alerts) carries a stable **`Idempotency-Key`** header
derived deterministically from the write's identity
(`run_id:instruction_id:event_type`, or `schedule_miss:activity_id:last_fired`
for miss alerts). This makes writes safe to **buffer and replay** under the
planned State Hub *beachhead* (per-machine read cache + write outbox): a flush —
possibly retried after an outage — cannot create duplicate progress/triage
events once State Hub / the beachhead honours the header.
The guarantee lives on the write, not on a live dedup read. The read-based
`_progress_exists` check is now best-effort only: if State Hub is unreachable it
returns `False` (proceed to the keyed write) rather than hard-failing. The header
passes untouched through the `actcore-state-hub-bridge` proxy and is ignored by
State Hub versions that do not yet honour it.
> The queue/cache itself is **not** built in activity-core — it belongs to the
> state-hub beachhead. activity-core only emits the key. See the proposal sent to
> the `state-hub` agent.
## Troubleshooting
### Worker fails to start: "ACTCORE_DB_URL is required"