feat: atomically journal and deliver authorized native operation outcomes
Some checks failed
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / pytest-smoke (push) Failing after 4s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e747-8f27-7242-8df8-8bc44f88c929
This commit is contained in:
tegwick 2026-09-28 14:00:26 +02:00
parent 3c5cbfbafe
commit f0eff0ac92
13 changed files with 583 additions and 28 deletions

View file

@ -68,6 +68,9 @@ def create_app(
browser = BrowserSessions(settings=browser_settings, controller=access_controller) if browser_settings else None
resolved_store = port_store or _create_store(resolved_settings)
owns_store = port_store is None
outcome_delivery = (access_controller is not None
and callable(getattr(access_controller.audit, "append_outcome", None))
and callable(getattr(resolved_store, "deliver_outcomes", None)))
resolved_repo_projection_client = repo_projection_client
owns_repo_projection_client = False
if (
@ -111,9 +114,14 @@ def create_app(
await workload_projection.refresh()
except WorkloadProjectionRejected:
pass
outcome_task = asyncio.create_task(_deliver_outcomes(resolved_store, access_controller.audit)) if outcome_delivery else None
try:
yield
finally:
if outcome_task is not None:
outcome_task.cancel()
with suppress(asyncio.CancelledError):
await outcome_task
if browser is not None:
browser.clear()
if refresh_task is not None:
@ -166,6 +174,8 @@ def create_app(
}
if resolved_settings.enforce_access:
dependency_checks["access_profile"] = "ok" if access_controller else "unavailable"
if callable(getattr(resolved_store, "deliver_outcomes", None)):
dependency_checks["outcome_delivery"] = (await resolved_store.outcome_readiness()) if outcome_delivery else "unavailable"
ready = resolved_settings.is_ready(resolved_store.backend_name) and all(
value in {"ok", "not_applicable"} for value in dependency_checks.values()
)
@ -191,6 +201,16 @@ def create_app(
return app
async def _deliver_outcomes(store, sink) -> None:
while True:
try:
await store.deliver_outcomes(sink)
except Exception:
# DB outages leave rows durable; readiness exposes missing/stale data.
pass
await asyncio.sleep(1)
async def _refresh_repository_projection(
service: RepositoryNavigationService,
interval_seconds: float,