Implement P05 checked services and safe selected delivery recovery
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 19s
Account journey acceptance / journeys (push) Successful in 5s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a092fe-13b1-7f12-ac74-7d258af4d79c
This commit is contained in:
tegwick 2026-09-13 22:11:49 +02:00
parent 99618488e0
commit ac0eb14b75
15 changed files with 735 additions and 88 deletions

View file

@ -109,6 +109,7 @@ class PortalApplication:
self.provisioning = provisioning
self.tenant_management = tenant_management
self.outbox_delivery = outbox_delivery
self.operations_probe = None
self.registration_verification = registration_verification
self.registration_clients = frozenset(registration_clients)
self.registration_tenants = frozenset(registration_tenants)
@ -791,6 +792,27 @@ class PortalApplication:
query = parse_qs(str(environ.get("QUERY_STRING", "")))
return self._html(start_response, self._platform_activity(
query.get("reference", [""])[0], query.get("tenant", [""])[0]), correlation_id)
if path == "/platform/operations/deliver" and method == "POST":
self.service.resolve_tenant_context(actor, PLATFORM_TENANT)
body = self._form_body(environ)
self._require_csrf(environ, body.get("csrf_token", ""))
event_id = body.get("event_id", "")
with self.service.store.outbox_delivery_guard(event_id):
event = self.service.store.outbox_event(event_id)
if event is None: raise NotFoundError("delivery record not found")
if event.delivered_at:
raise ConflictError("Delivery is already completed.")
if self.outbox_delivery is None: raise ValidationError("Delivery is unavailable")
confirmation = self._confirm_change(environ, start_response, body,
json.dumps(_jsonable(event),sort_keys=True), "Attempt this delivery",
"This submits only delivery " + event.event_id + " for " + event.tenant +
". Invitation messages will be sent to the recorded recipient. Provider acceptance does not prove the person received it. Keep support reference " + event.correlation_id + ".",
correlation_id)
if confirmation is not None: return confirmation
self.service.deliver_outbox(actor, self.outbox_delivery,
worker_id="platform-operator",event_id=event.event_id,
expected_attempts=event.delivery_attempts,correlation_id=correlation_id)
return self._redirect(start_response,"/platform/operations?"+urlencode({"event_id":event_id}),correlation_id)
if path in {"/platform/operations", "/platform/operations/replay"}:
self.service.resolve_tenant_context(actor, PLATFORM_TENANT)
if method == "POST" and path.endswith("/replay"):
@ -799,7 +821,7 @@ class PortalApplication:
event = self.service.store.outbox_event(str(body.get("event_id", "")))
if event is None:
raise NotFoundError("delivery record not found")
if event.delivered_at is not None or event.claimed_by:
if event.delivered_at is not None or (event.claimed_by and not event.failed_at):
raise ConflictError("Delivery is already completed or being processed. Refresh its status.")
self.service.replay_outbox(actor, event.event_id, correlation_id=correlation_id)
return self._redirect(start_response, "/platform/operations?"+urlencode({"event_id":event.event_id}), correlation_id)
@ -1191,6 +1213,8 @@ class PortalApplication:
@staticmethod
def _delivery_status(event: Any) -> str:
if event.delivered_at: return "Accepted by delivery adapter; receipt by the person is unverified"
if event.failure_reason == "delivery_outcome_unknown": return "Mail outcome unknown — check provider evidence before sending another message"
if event.failure_reason == "mail_unconfigured": return "Mail is not configured — use assisted setup or restore the mail lane"
if event.dead_lettered_at: return "Delivery stopped after repeated failures"
if event.failed_at: return "Delivery failed; retry pending"
if event.claimed_by: return "Being processed"
@ -1242,15 +1266,19 @@ class PortalApplication:
rows = ""
for event in events:
action = ""
if event.delivered_at is None and not event.claimed_by and (event.failed_at or event.dead_lettered_at):
action = f'<form method="post" action="/platform/operations/replay"><input type="hidden" name="csrf_token" value="{escape(csrf)}"><input type="hidden" name="event_id" value="{escape(event.event_id)}"><button type="submit">Queue a retry</button></form>'
if event.delivered_at is None:
action = f'<form method="post" action="/platform/operations/deliver"><input type="hidden" name="csrf_token" value="{escape(csrf)}"><input type="hidden" name="event_id" value="{escape(event.event_id)}"><button type="submit">Review delivery attempt</button></form>'
if event.delivered_at is None and (not event.claimed_by or event.failed_at) and (event.failed_at or event.dead_lettered_at):
action += f'<form method="post" action="/platform/operations/replay"><input type="hidden" name="csrf_token" value="{escape(csrf)}"><input type="hidden" name="event_id" value="{escape(event.event_id)}"><button type="submit">Queue a retry</button></form>'
rows += f'<tr><td>{escape(event.event_id)}</td><td>{escape(event.tenant)}</td><td>{escape(event.event_type)}</td><td>{escape(self._delivery_status(event))}</td><td>{escape(event.correlation_id)}</td><td>{action}</td></tr>'
configuration = self._operation_capabilities()
return self._page_html("Service recovery", '<h1>Service recovery</h1>' + configuration + '<p><a href="/platform/activity">Investigate a support reference</a></p><p>This view shows local delivery records. Live sign-in, email receipt and authenticator health are not verified here.</p>'
from user_engine.operations_status import check_services, selected_mail_status
evidence = selected_mail_status(self.outbox_delivery, events[0]) if event_id else ""
configuration = (self.operations_probe() if self.operations_probe else check_services(None,None)) + self._operation_capabilities()
return self._page_html("Service recovery", '<h1>Service recovery</h1>' + configuration + evidence + '<p><a href="/platform/activity">Investigate a support reference</a></p><p>Delivery records below describe recorded attempts. Component checks do not prove a complete sign-in or inbox receipt.</p>'
'<form method="get" action="/platform/operations"><label>Delivery record ID <input name="event_id"></label><button type="submit">Find delivery</button></form>'
'<table><thead><tr><th>Delivery</th><th>Tenant</th><th>Kind</th><th>Status</th><th>Support reference</th><th>Recovery</th></tr></thead><tbody>'
+ (rows or '<tr><td colspan="6">No delivery records. This does not prove mail was received.</td></tr>')
+ '</tbody></table><p>Queued retries are processed by the delivery worker. Check the record again for the result.</p><p><a href="/platform">Return to platform administration</a></p>')
+ '</tbody></table><p>Queueing a retry does not send it. Use Review delivery attempt to submit one selected record, then check its result. No background worker is enabled here.</p><p><a href="/platform">Return to platform administration</a></p>')
def _operation_capabilities(self) -> str:
capabilities = (