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

@@ -171,12 +171,14 @@ down. This is handed off to state-hub (see the coordination message / proposal);
activity-core's only responsibilities under this model are thin:
- **Idempotent writes (do now, in-repo):** attach a stable idempotency key
(e.g. `run_id` + `instruction_id` + `event_type`) to every State Hub write so a
beachhead flush — possibly replayed after an outage — cannot create duplicate
`daily_triage`/progress events. The report sink already does a read-based dedup
check (`_progress_exists`); make the guarantee explicit and not dependent on a
live read.
- **Idempotent writes — DONE (2026-06-23, in-repo):** added
`activity_core/state_hub_write` (`idempotency_headers`); 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`. 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, not
a live read. Tests in `tests/test_state_hub_write.py`; documented in
`docs/runbook.md`.
- **Adopt the beachhead endpoint (blocked on state-hub):** keep `STATE_HUB_URL`
pointed at the local beachhead, and **retire the bespoke
`actcore-state-hub-bridge` proxy** (the inline `hostNetwork` proxy in