key-cape/workplans/KEY-WP-0024-tenant-roles-opt-in-wiring.md
tegwick a9296fdf84 chore(consistency): register KEY-WP-0024 [auto]
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-08 09:00:39 +02:00

2.3 KiB

id type title domain repo status owner topic_slug created updated state_hub_workstream_id
KEY-WP-0024 workplan Wire tenant_roles as explicit opt-in configuration infotech key-cape finished claude tenant-roles-opt-in-wiring 2026-09-08 2026-09-08 d75f52f2-df0d-5a56-8394-892feeec4b4d

Closes gap G07. The tenant-engine client and TokenHandler.TenantEngine were implemented and tested, but main.go supplied no client and exposed no configuration, so the stock executable left the field nil and never emitted tenant_roles. The capability existed at library level only.

Wired rather than documented away as library-only: the claim is cheap, the adapter already fails open, and leaving a tested capability unreachable from the binary invites the same gap being rediscovered later.

Add opt-in configuration and wire the client

id: KEY-WP-0024-T01
status: done
priority: medium
state_hub_task_id: "0e53485b-7e94-5dd8-8e02-1d18f5413a78"

Added a tenantEngine config block with baseURL and an optional timeout. An empty baseURL disables the claim, which keeps the stock server's behaviour exactly as it was — enabling it is a deliberate act.

Validation treats a configured source as one that must work: the URL must be http/https with a host, and the timeout must parse and fall in (0, 10s], since it sits on the synchronous token-issuance path. A timeout set without a baseURL is rejected rather than ignored — it means someone expected the claim to be on and it silently would not have been.

Verify it in the built executable

id: KEY-WP-0024-T02
status: done
priority: medium
state_hub_task_id: "c4279ce0-f6f8-5612-a48a-c1d2fd3da3b6"

G07's closure criterion is the built executable, not the wiring, so all three behaviours were checked by running bin/keycape and inspecting real tokens rather than by reading the code:

  • configured against a stub tenant-engine, a client_credentials token carries tenant_roles: [capability:approve, capability:observe];
  • with no tenantEngine block, the claim is absent;
  • configured but with the source down, issuance still succeeds and the claim is absent — the fail-open behaviour the adapter documents, confirmed end to end.

Nine validation cases cover the accepted and rejected configurations.