key-cape/workplans/KEY-WP-0030-tenant-precondition-guard.md
tegwick f2c9aa45a8 Split the gate-house ruling work into its own workplan
fix-consistency skipped C-11 for two tasks I had appended to KEY-WP-0030 after
marking it finished, so they were never registered in the hub. The skip was
right: appending tasks to a finished workplan is the wrong shape, and the fix is
structural rather than flipping a status to get them registered.

The provenance implementation and the condition (b) correction are responses to
GH-DEC-2026-013, not to informed-decision's request for an enforced precondition.
They are now KEY-WP-0031, which also records that conditions (a) and (c) needed
nothing from this repository and why.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-10 08:05:49 +02:00

3 KiB

id type title domain repo status owner topic_slug created updated state_hub_workstream_id
KEY-WP-0030 workplan Make the static-registration precondition a checked condition infotech key-cape finished claude tenant-precondition-guard 2026-09-09 2026-09-09 9ed8f851-080a-5d15-8642-f799c2e3295c

informed-decision replied on KEY-WP-0013-T05 and asked for one thing that is ours to do: the caveat under which a registration-bound human tenant is safe should be "a condition of the capability, so a future change to registration policy has to confront it", not reasoning left in a message.

They are right that it was only prose. docs/tenant-claim-contract.md states it, and a separate test asserted registration_endpoint is absent — but nothing connected the two, so a future session adding dynamic registration would see a test about discovery metadata, not a warning about relabelling users.

Tie the exclusion to the capability it protects

id: KEY-WP-0030-T01
status: done
priority: medium
state_hub_task_id: "4729d591-39d4-5f33-bef8-db8057090913"

TestRegistrationBoundTenantRequiresStaticRegistration asserts both halves together: that a client-declared tenant is issued, and that dynamic client registration is not advertised. Whichever is removed first, the failure points at the other.

The failure message carries the reasoning rather than the observation. Adding dynamic registration while a registration may declare its users' tenant means anyone able to register a client can relabel the users who log in through it into a zone of their choosing; the message says that and names the two ways out, drop the capability or gate it to statically configured registrations.

Verified in both directions rather than assumed: advertising a registration_endpoint fails it with the escalation message, and neutering humanTenant fails it with the message saying to remove the guard along with the capability it protects.

This is deliberately not a vote on the tenant question. It makes the precondition of one option checkable; it does not choose between them, and if option 1 lands the capability and this guard are removed together.

What stays with the owners

id: KEY-WP-0030-T02
status: done
priority: medium
state_hub_task_id: "32b10327-f55d-5a0e-a4bc-be92929469dc"

informed-decision prefers option 2 and explicitly declines to treat that as the answer, flagging it to gate-house on GH-DEC-2026-012 and naming approval-engine's stake. KeyCape leans the same way, which is a reason for more care rather than less: the code already implements option 2 (329e48f), so the doctrine question is being decided against a working implementation. That is worth saying out loud to everyone waiting on it, and was.

Their scope set [openid, approval:read, approval:approve] is confirmed and already published. client_id and callback follow at their T07, deliberately not before the tenant question resolves — registering a client that fails closed at first use is the failure this exchange existed to avoid.