Add opt-in tenant-to-client bindings for invitation mail
Some checks failed
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 35s
Account journey acceptance / journeys (push) Failing after 7s

User-engine side of EMAIL-WP-0008: USER_ENGINE_MAIL_CLIENT_BINDINGS maps
tenant globs to a single client_id carried on invitation mail envelopes
only. Unmatched or conflicting tenants fail as mail_binding_denied before
either lane is contacted, and the outbox now records that reason instead
of collapsing it to delivery_unavailable. Unset keeps legacy envelopes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 445231@bnt-lap001
Assistant-Session: 024a807e-0cc5-4f2c-bc8a-b83322d1395d
This commit is contained in:
tegwick 2026-10-09 11:21:17 +02:00
parent a9360842f8
commit adf6e992a6
9 changed files with 199 additions and 2 deletions

View file

@ -106,6 +106,23 @@ class ServiceOperations(JourneyFixture):
self.app.service.store.outbox_event(event.event_id).delivered_at
)
def test_mail_binding_denial_is_recorded_not_collapsed(self):
event = self.seed()
def deny(event):
raise DeliveryError("mail_binding_denied")
self.app.outbox_delivery = deny
self.post(
"/platform/operations/deliver",
who="operator",
event_id=event.event_id,
confirmed=True,
)
failed = self.app.service.store.outbox_event(event.event_id)
self.assertEqual("mail_binding_denied", failed.failure_reason)
self.assertIsNone(failed.delivered_at)
def test_crashed_claim_reconciles_under_event_guard(self):
event = self.seed()
self.app.service.store.save_outbox(