Add pending_decisions state-hub query + monthly secrets-elevation review
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 3s
Build and Publish Container Image / build-and-push (push) Successful in 1m4s

New context_resolvers/state_hub.py query type: pending_decisions, a thin
GET /decisions/ passthrough (topic_id/workstream_id/workplan_id/decision_type
passed through, status defaults to open). Generic -- not special-cased to
any one decision.

New activity-definitions/monthly-secrets-elevation-review.md: fires 08:00
Berlin on the 1st of each month, sweeps open State Hub decisions under the
infotech/reuse-surface topic, and opens a review task for each. First
target: the temporary autoMode.allow/permissions.allow elevation added to
~/.claude/settings.json on 2026-07-07 (decision 11bf5cbf-458d-4275-a870-
77a82b4058b9, deadline 2026-07-31) for ops-warden/kubectl/OpenBao secret
reads.

Requested by Bernd: no existing scheduling mechanism (session-only cron,
cloud routines with no local access) can durably re-check a local security
posture a month out -- this closes that gap using activity-core's own
durable Temporal-backed trigger instead.

Verified: definition_parser.parse_file + scan_and_parse load it cleanly
alongside the two existing definitions; new resolver tests pass (20/20 in
that file); pending_decisions confirmed against the live local State Hub.
Full suite: 241 passed, 2 pre-existing unrelated failures (confirmed via
git stash -- present before this change too).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-07-07 15:26:00 +02:00
parent ce03e78e26
commit d563d516f5
3 changed files with 116 additions and 0 deletions

View file

@ -77,6 +77,53 @@ def test_daily_triage_queries(monkeypatch) -> None:
]
def test_pending_decisions_query(monkeypatch) -> None:
calls: list[dict[str, Any]] = []
def fake_get(url: str, **kwargs: Any) -> DummyResponse:
calls.append({"url": url, **kwargs})
return DummyResponse([{"id": "d1", "status": "open", "deadline": "2026-07-31T00:00:00Z"}])
monkeypatch.setenv("STATE_HUB_URL", "http://state-hub.test")
monkeypatch.setattr(httpx, "get", fake_get)
resolver = StateHubContextResolver()
result = resolver.resolve(
"pending_decisions", None, {"topic_id": "topic-1", "workstream_id": "wp-1"}
)
assert result == [{"id": "d1", "status": "open", "deadline": "2026-07-31T00:00:00Z"}]
assert calls == [
{
"url": "http://state-hub.test/decisions/",
"params": {"topic_id": "topic-1", "workstream_id": "wp-1", "status": "open"},
"timeout": 10.0,
}
]
def test_pending_decisions_query_defaults_status_open(monkeypatch) -> None:
calls: list[dict[str, Any]] = []
def fake_get(url: str, **kwargs: Any) -> DummyResponse:
calls.append({"url": url, **kwargs})
return DummyResponse([])
monkeypatch.setenv("STATE_HUB_URL", "http://state-hub.test")
monkeypatch.setattr(httpx, "get", fake_get)
resolver = StateHubContextResolver()
resolver.resolve("pending_decisions", None, {})
assert calls == [
{
"url": "http://state-hub.test/decisions/",
"params": {"status": "open"},
"timeout": 10.0,
}
]
def test_existing_queries_still_resolve(monkeypatch) -> None:
calls: list[dict[str, Any]] = []