user-engine/workplans/ADHOC-2026-10-09.md

76 lines
2.8 KiB
Markdown
Raw Normal View History

---
id: USER-WP-ADHOC-2026-10-09
type: workplan
title: "Scoped invitation mail client bindings"
domain: communication
repo: user-engine
status: finished
owner: claude
created: "2026-10-09"
updated: "2026-10-09"
state_hub_workstream_id: "88817a88-4415-5400-be9a-939406e77831"
---
## Send an admitted tenant/client pair on invitation mail
```task
id: USER-WP-ADHOC-2026-10-09-T01
status: done
priority: medium
state_hub_task_id: "d62b2f0e-7b62-5bf2-945d-7d8a9f51b002"
```
User-engine side of email-connect EMAIL-WP-0008 (caller policy draft
2026-10-08): current invitation envelopes omit `client_id`, so a scoped
user-engine caller cannot be admitted. Opt-in
`USER_ENGINE_MAIL_CLIENT_BINDINGS` maps tenant globs to one literal client id.
Files:
- `src/user_engine/mail_bindings.py` — strict loader and single-match resolver
- `src/user_engine/adapters/delivery.py` — adds `client_id` to the mail
envelope only; denial contacts neither lane
- `src/user_engine/runtime.py` — reads the env var
- `src/user_engine/service.py`, `src/user_engine/web.py` — keep
`mail_binding_denied` as the recorded failure reason with an operator status
line instead of collapsing it to `delivery_unavailable`
- `docs/configuration.md`, `tests/test_mail_bindings.py`,
`tests/test_service_operations.py`
Acceptance: unset keeps legacy envelopes; invalid config stops startup;
unmatched or conflicting tenants are denied; platform events and outbox payloads
never carry `client_id`; `make test` and `make check-layer` pass.
Not done here: activation. Deploy config, email-connect caller admission
(EMAIL-WP-0008-T03) and token custody stay with their owners and the founder.
## Draft the deployment binding value
```task
id: USER-WP-ADHOC-2026-10-09-T02
status: done
priority: medium
```
Draft only, not applied. When email-connect admits the user-engine caller
(EMAIL-WP-0008-T03), add this to the user-engine container env in
`net-kingdom/sso-mfa/k8s/user-engine/runtime.yaml`, next to
`USER_ENGINE_MAIL_URL`:
```yaml
- name: USER_ENGINE_MAIL_CLIENT_BINDINGS
value: '[["tenant:coulomb","coulomb-social"],["tenant:*-family","coulomb-social"],["tenant:family-*","coulomb-social"]]'
```
It mirrors `bindings` plus `binding_patterns` in email-connect
`config/callers.user-engine.draft.json` one-to-one. Both sides match with
case-sensitive whole-string `fnmatchcase`, so user-engine sends only pairs the
receiver admits. Checked with the loader: `tenant:coulomb`,
`tenant:worsch-family` and `tenant:family-*` resolve to `coulomb-social`;
`tenant:platform` is denied before either lane.
Order matters. Apply the env var in the same rollout that switches
`USER_ENGINE_MAIL_TOKEN` to the scoped caller token. Before then the receiver
runs legacy mode, so leave the variable unset. If either side's patterns change,
change the other in the same review.