Delegate tenant lifecycle to the tenant authority
TEN-WP-0005 landed the authoritative metadata update and reversible retirement contract, so USER-WP-0021-T01's deferred tenant operations are now implementable without user-engine inventing lifecycle semantics. TenantManagementPort gains read, update, retire, and reactivate. The HTTP adapter echoes the record version as an If-Match ETag (never `*`), sends an Idempotency-Key plus actor/reason/correlation_id, and surfaces Idempotent-Replay. Authority failures map to redacted domain errors carrying only the contract's stable error_code; its detail text never crosses the boundary. Platform operators get the matching API routes and a CSRF-protected browser screen that reads the record before mutating it and hides the metadata form for a retired tenant. Portal OpenAPI moves to 0.3.0 with TenantRecord, UpdateTenant, and TenantLifecycleChange. Full suite: 145 tests, 3 external-provider skips. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
db8769cc8c
commit
667ea694c2
8 changed files with 952 additions and 11 deletions
|
|
@ -4,11 +4,11 @@ type: workplan
|
|||
title: "Expand user-engine portal beyond the proven Binky MVP"
|
||||
domain: communication
|
||||
repo: user-engine
|
||||
status: blocked
|
||||
status: active
|
||||
owner: codex
|
||||
topic_slug: netkingdom
|
||||
created: "2026-07-30"
|
||||
updated: "2026-08-10"
|
||||
updated: "2026-08-16"
|
||||
depends_on:
|
||||
- USER-WP-0020
|
||||
- TEN-WP-0005
|
||||
|
|
@ -24,7 +24,7 @@ holding the proven production MVP open. Activate according to tenant demand.
|
|||
|
||||
```task
|
||||
id: USER-WP-0021-T01
|
||||
status: progress
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "342299b8-d9a3-408d-bf0d-914496714d5f"
|
||||
```
|
||||
|
|
@ -222,6 +222,36 @@ Authorization headers differ. The full suite passes 132 tests with three
|
|||
external-provider skips. Production rollout still waits on governed delivery
|
||||
of both scoped credentials.
|
||||
|
||||
2026-08-16 tenant lifecycle completion: TEN-WP-0005 is finished, so the last
|
||||
deferred part of T01 is now implementable against a real authority.
|
||||
`TenantManagementPort` gained `tenant`, `update_tenant`, `retire_tenant`, and
|
||||
`reactivate_tenant`, and `HTTPTenantManagementAdapter` implements them against
|
||||
the `tenant-lifecycle-api.md` contract: version ETag as `If-Match` (never `*`),
|
||||
`Idempotency-Key`, actor/reason/correlation_id, and `Idempotent-Replay`
|
||||
surfaced as a `replayed` flag. Authority failures map to redacted domain errors
|
||||
carrying only the contract's stable `error_code`; the authority's `detail` text
|
||||
never crosses the boundary.
|
||||
|
||||
Platform operators get `GET`/`PATCH /api/v1/platform/tenants/{tenant}` plus
|
||||
`/retire` and `/reactivate`, and a CSRF-protected browser lifecycle screen that
|
||||
reads the record first and echoes its version. A retired tenant renders no
|
||||
metadata form, matching the authority's own transition rules. user-engine keeps
|
||||
no tenant table and invents no retirement semantics: every read and write goes
|
||||
to tenant-engine. Portal OpenAPI is now 0.3.0 with `TenantRecord`,
|
||||
`UpdateTenant`, and `TenantLifecycleChange` schemas, and the immutable
|
||||
identifier is documented as rejected rather than discovered from a 400.
|
||||
|
||||
Conformance proves ordinary-user denial, stale-version 409, replayed mutation
|
||||
without a second version bump, update-while-retired and double-retirement 409,
|
||||
reactivation, unknown-tenant 404, forged-CSRF rejection with unchanged
|
||||
lifecycle, and adapter-level redaction of authority detail text. The full suite
|
||||
passes 145 tests with three external-provider skips.
|
||||
|
||||
This closes the engineering scope of T01. Production activation of the outbox
|
||||
transport remains gated on governed delivery of the OpenBao event/mail tokens
|
||||
and transactional SMTP credentials — an operational gate outside this repo, not
|
||||
outstanding user-engine code.
|
||||
|
||||
2026-08-14 live retry finding: the PostgreSQL adapter excluded every row with
|
||||
`failed_at` set, while the in-memory contract correctly retains failures until
|
||||
`dead_lettered_at`. A first receiver error therefore required manual replay
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ status: blocked
|
|||
owner: codex
|
||||
topic_slug: netkingdom
|
||||
created: "2026-08-09"
|
||||
updated: "2026-08-10"
|
||||
updated: "2026-08-16"
|
||||
depends_on:
|
||||
- USER-WP-0021
|
||||
- NK-WP-0025
|
||||
|
|
@ -110,6 +110,20 @@ creating another session or requesting another email; reuse with different
|
|||
inputs returns 409. Raw keys and applicant fields are absent from idempotency
|
||||
evidence. The full suite passes 134 tests with three external skips.
|
||||
|
||||
2026-08-16 gate review: every implementation item listed for this task is
|
||||
built and covered — accessible start/verify/resume/cancel entry points,
|
||||
allow-listed anonymous routes, opaque intent handles, CSRF, per-peer rate
|
||||
limiting, required idempotency keys, and non-enumerating responses. The
|
||||
application-level registration limit is configured in the runtime manifest on
|
||||
top of the Traefik-wide limit, closing the ingress defense-in-depth item.
|
||||
|
||||
What remains is not user-engine code. Public registration stays disabled until
|
||||
the OpenBao verification and delivery tokens plus the transactional SMTP lane
|
||||
are delivered through governed channels. The service already fails closed when
|
||||
they are absent, and no placeholder or reused credential will be added to
|
||||
unblock it. This task stays in `wait` because the remaining gate is a
|
||||
credential-custody handoff, not an outstanding change here.
|
||||
|
||||
## T02 - Orchestrate provider identity creation
|
||||
|
||||
```task
|
||||
|
|
@ -221,6 +235,13 @@ the identity-link uniqueness boundary, leaves the original link unchanged, and
|
|||
never transfers that identity to the later registration. The full suite passes
|
||||
131 tests with three environment-dependent skips.
|
||||
|
||||
2026-08-16 authorization evidence: flex-auth reports FLEX-WP-0009 finished and
|
||||
handed back deployed-policy evidence for the user-engine surface, including the
|
||||
three registration-applicant fixtures (applicant allow, membership deny, wrong
|
||||
issuer deny) replayed against the live `POST /v1/check`. The fail-closed
|
||||
`FlexAuthHTTPAdapter` maps a missing or refused service to deny. This removes
|
||||
authorization from this task's gate; only the credential handoff remains.
|
||||
|
||||
The latest tested image is published at
|
||||
`forgejo.coulomb.social/coulomb/user-engine@sha256:a49a0a105d392e374f6da958f8ad1bff36f2cfa8779ac5cafa479b7f34b6efc1`;
|
||||
the matching email-connect image is
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue