Stop dual-writing workstream_id on State Hub progress POSTs
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 21s
Build and Publish Container Image / build-and-push (push) Successful in 1m24s

Progress scope helpers and schedule-miss alerts now send workplan_id only.
Legacy workstream_id in sink config still maps to workplan_id on the wire.
This commit is contained in:
tegwick 2026-07-09 00:31:55 +02:00
parent f171bb037a
commit 5a9292319e
6 changed files with 10 additions and 12 deletions

View file

@ -178,7 +178,6 @@ def post_missed_fire_alert(
scope_id = workplan_id or workstream_id
if scope_id:
body["workplan_id"] = scope_id
body["workstream_id"] = scope_id
# Dedup repeated alerts for the same missed window (same schedule + last fire).
last_fired = health.last_fired_at.isoformat() if health.last_fired_at else "none"

View file

@ -23,13 +23,12 @@ IDEMPOTENCY_HEADER = "Idempotency-Key"
def apply_progress_scope_fields(body: dict[str, Any], source: dict[str, Any]) -> None:
"""Copy topic/workplan/task/decision scope from a sink config into a progress body.
Prefers ``workplan_id``; dual-writes ``workstream_id`` for wire-compat until
legacy-meter retires the alias.
Prefers ``workplan_id``; accepts legacy ``workstream_id`` in sink config only
as a fallback source (maps to ``workplan_id`` on the wire).
"""
workplan_id = source.get("workplan_id") or source.get("workstream_id")
if workplan_id:
body["workplan_id"] = workplan_id
body["workstream_id"] = workplan_id
for key in ("topic_id", "task_id", "decision_id"):
if source.get(key):
body[key] = source[key]

View file

@ -124,7 +124,7 @@ def test_state_hub_progress_sink_posts_compact_probe_summary(monkeypatch) -> Non
body = posts[0]["json"]
assert body["summary"] == "Ops inventory probe: 1 ok, 0 degraded, 0 down, 1 skipped"
assert body["workplan_id"] == "workstream-1"
assert body["workstream_id"] == "workstream-1"
assert "workstream_id" not in body
assert body["task_id"] == "task-1"
assert body["detail"]["activity_core_run_id"] == _run_id()
assert body["detail"]["idempotency_key"] == result[0]["idempotency_key"]
@ -192,7 +192,7 @@ def test_legacy_meter_weekly_review_sink_posts_progress(monkeypatch) -> None:
assert body["event_type"] == "legacy_meter_weekly_review"
assert "2 retirement candidate(s)" in body["summary"]
assert body["workplan_id"] == "923bb94a-d16c-422c-b81e-16328bd7b60c"
assert body["workstream_id"] == "923bb94a-d16c-422c-b81e-16328bd7b60c"
assert "workstream_id" not in body
def test_state_hub_progress_prefers_workplan_id(monkeypatch) -> None:
@ -221,7 +221,7 @@ def test_state_hub_progress_prefers_workplan_id(monkeypatch) -> None:
body = posts[0]["json"]
assert body["workplan_id"] == "workplan-1"
assert body["workstream_id"] == "workplan-1"
assert "workstream_id" not in body
def test_core_hub_stabilization_sink_posts_progress(monkeypatch) -> None:

View file

@ -117,7 +117,7 @@ def test_state_hub_progress_sink_posts(monkeypatch) -> None:
]
assert posts[0]["url"] == "http://state-hub.test/progress/"
assert posts[0]["json"]["workplan_id"] == "workstream-1"
assert posts[0]["json"]["workstream_id"] == "workstream-1"
assert "workstream_id" not in posts[0]["json"]
assert posts[0]["json"]["detail"]["activity_core_run_id"] == payload_run_id()
assert posts[0]["json"]["detail"]["output_validated"] is True
assert posts[0]["json"]["detail"]["review_required"] is False

View file

@ -98,7 +98,7 @@ def test_post_missed_fire_alert_dual_writes_workplan_scope(monkeypatch) -> None:
assert result["status"] == "posted"
body = posts[0]["json"]
assert body["workplan_id"] == "wp-123"
assert body["workstream_id"] == "wp-123"
assert "workstream_id" not in body
def test_no_interval_and_no_fire_is_not_flagged() -> None:

View file

@ -41,15 +41,15 @@ def test_apply_progress_scope_prefers_workplan_id() -> None:
{"workplan_id": "wp-1", "workstream_id": "ws-legacy", "topic_id": "topic-1"},
)
assert body["workplan_id"] == "wp-1"
assert body["workstream_id"] == "wp-1"
assert "workstream_id" not in body
assert body["topic_id"] == "topic-1"
def test_apply_progress_scope_dual_writes_legacy_workstream_id() -> None:
def test_apply_progress_scope_maps_legacy_workstream_config_to_workplan_id() -> None:
body: dict[str, str] = {}
apply_progress_scope_fields(body, {"workstream_id": "ws-1"})
assert body["workplan_id"] == "ws-1"
assert body["workstream_id"] == "ws-1"
assert "workstream_id" not in body
def test_distinct_identities_get_distinct_keys() -> None: