WIP: Claude Code rate-limit checkpoint (20dd5562)

This commit is contained in:
Claude Code 2026-08-18 15:25:17 +02:00
parent 3de72fe6f5
commit 150b1f55fb
8 changed files with 230 additions and 15 deletions

23
.claude/RESUME.md Normal file
View file

@ -0,0 +1,23 @@
# Claude Code — resume checkpoint
Session: 20dd5562-9f87-4ec7-9e89-0182ad59f4fa
Written: 2026-08-18T13:25:17.115Z
Trigger: rate-limited
Ref with your in-progress files: refs/claude/checkpoint-20dd5562
## To resume
claude --resume 20dd5562-9f87-4ec7-9e89-0182ad59f4fa
(or open Claude Code in this directory and run /resume)
## Plan (from TodoWrite state)
No task list was active; see transcript via the resume command above.
---
Don't want these changes? Resume this session (above), then run
`/rewind` to roll back the turn's tool edits (bash-made changes
excluded). refs/claude/checkpoint-20dd5562 holds a full snapshot until this session's
next checkpoint, or for up to ~2 weeks.

View file

@ -90,7 +90,7 @@
| task | FLEX-WP-0014-T03 | done | — | workplans/FLEX-WP-0014-tenant-guardrail-policy-actions.md |
| task | FLEX-WP-0014-T04 | done | — | workplans/FLEX-WP-0014-tenant-guardrail-policy-actions.md |
| task | FLEX-WP-0015-T01 | done | — | workplans/FLEX-WP-0015-tenancy-posture-conformance.md |
| task | FLEX-WP-0015-T02 | progress | — | workplans/FLEX-WP-0015-tenancy-posture-conformance.md |
| task | FLEX-WP-0015-T02 | wait | — | workplans/FLEX-WP-0015-tenancy-posture-conformance.md |
| task | FLEX-WP-0015-T03 | done | — | workplans/FLEX-WP-0015-tenancy-posture-conformance.md |
| task | FLEX-WP-0015-T04 | wait | — | workplans/FLEX-WP-0015-tenancy-posture-conformance.md |
| task | FLEX-WP-0015-T05 | done | — | workplans/FLEX-WP-0015-tenancy-posture-conformance.md |

View file

@ -6,11 +6,14 @@ flex-auth protected system (`FLEX-WP-0008-T01`). Action names here match
(`tenant_engine/src/tenant_engine/authz.py`) — coordinated between the two
repos, not independently invented.
| Action | tenant-engine write endpoint | Resource type | Decision effects |
| Action | tenant-engine endpoint | Resource type | Decision effects |
| --- | --- | --- | --- |
| `tenant.read` | `GET /tenants/{id}` | `tenant` | `allow`, `deny` |
| `tenant.create` | `POST /tenants` | `tenant` | `allow`, `deny` |
| `tenant.role.grant` | `POST /tenants/{id}/roles/grant` | `role-grant` | `allow`, `deny` |
| `tenant.role.revoke` | `POST /tenants/{id}/roles/revoke` | `role-grant` | `allow`, `deny` |
| `tenant.role.read` | `GET /tenants/{id}/roles` | `role-grant` | `allow`, `deny` |
| `tenant.role.read.live` | `GET /tenants/{id}/roles/live` | `role-grant` | `allow`, `deny` |
| `tenant.plan.assign` | `POST /tenants/{id}/plan` | `plan-assignment` | `allow`, `deny` |
| `tenant.update` | `PATCH /tenants/{id}` | `tenant` | `allow`, `deny` |
| `tenant.retire` | `POST /tenants/{id}/retire` | `tenant` | `allow`, `deny` |
@ -26,12 +29,12 @@ without granting the write. That split is used today: `flex-auth` may
may do both. Reasoning is recorded in
`examples/tenant-engine/policy_package.md`.
These are the only nine actions `tenant-engine` sends to `POST /v1/check` —
These are the only twelve actions `tenant-engine` sends to `POST /v1/check` —
its `FlexAuthCheckClient` (`TEN-WP-0003`) never sends anything else.
`tenant-engine`'s role reads (`/roles`, `/roles/live`) are still not gated
through flex-auth; they remain `tenant-engine`'s own cache-read and
live-lookup endpoints. The guardrail GET is different: it is authorized,
because a ceiling is an input to a decision, not an unauthenticated lookup.
Every tenant and role read is gated before the store is touched, preventing
both unauthorized data access and tenant-existence probing. `user-engine`
may read tenant records, `flex-auth` may perform the high-stakes live role
lookup, and no caller receives a role-read privilege through a mutation rule.
## Not in scope for this vocabulary

View file

@ -1,4 +1,40 @@
[
{
"id": "fixture:user-engine-tenant-read-allow",
"request": {
"id": "check:user-engine-tenant-read-t1",
"tenant": "tenant:friendly:binky",
"subject": {"id": "user-engine", "type": "service"},
"action": "tenant.read",
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
"context": {}
},
"expect": {"effect": "allow", "reason": "write_api_policy_matched"}
},
{
"id": "fixture:flex-auth-live-role-read-allow",
"request": {
"id": "check:flex-auth-live-role-read-t1",
"tenant": "tenant:friendly:binky",
"subject": {"id": "flex-auth", "type": "service"},
"action": "tenant.role.read.live",
"resource": {"id": "t-1", "type": "role-grant", "system": "tenant-engine"},
"context": {}
},
"expect": {"effect": "allow", "reason": "write_api_policy_matched"}
},
{
"id": "fixture:user-engine-live-role-read-deny",
"request": {
"id": "check:user-engine-live-role-read-t1",
"tenant": "tenant:friendly:binky",
"subject": {"id": "user-engine", "type": "service"},
"action": "tenant.role.read.live",
"resource": {"id": "t-1", "type": "role-grant", "system": "tenant-engine"},
"context": {}
},
"expect": {"effect": "deny", "reason": "action_not_granted"}
},
{
"id": "fixture:tenant-engine-create-allow",
"request": {

View file

@ -6,9 +6,12 @@ version: v1
status: ready
package: flexauth.tenant_engine.write_api
actions:
- tenant.read
- tenant.create
- tenant.role.grant
- tenant.role.revoke
- tenant.role.read
- tenant.role.read.live
- tenant.plan.assign
- tenant.update
- tenant.retire
@ -165,9 +168,12 @@ import future.keywords.if
import future.keywords.in
valid_actions := {
"tenant.read",
"tenant.create",
"tenant.role.grant",
"tenant.role.revoke",
"tenant.role.read",
"tenant.role.read.live",
"tenant.plan.assign",
"tenant.update",
"tenant.retire",
@ -176,15 +182,25 @@ valid_actions := {
"tenant.guardrail.set",
}
read_actions := {"tenant.guardrail.read"}
tenant_read_actions := {"tenant.read", "tenant.role.read"}
live_read_actions := {"tenant.role.read.live"}
guardrail_read_actions := {"tenant.guardrail.read"}
read_actions := tenant_read_actions | live_read_actions | guardrail_read_actions
mutate_actions := valid_actions - read_actions
known_subjects := {"tenant-engine", "flex-auth"}
known_subjects := {"tenant-engine", "user-engine", "flex-auth"}
read_subjects := {"tenant-engine", "flex-auth"}
tenant_read_subjects := {"tenant-engine", "user-engine"}
mutate_subjects := {"tenant-engine"}
live_read_subjects := {"flex-auth"}
guardrail_read_subjects := {"tenant-engine", "flex-auth"}
mutate_subjects := {"tenant-engine", "user-engine"}
decision := {"effect": "allow", "reason": "write_api_policy_matched"} if {
allowed
@ -194,9 +210,23 @@ decision := {"effect": "allow", "reason": "write_api_policy_matched"} if {
allowed if {
input.resource.system == "tenant-engine"
input.action in read_actions
input.action in tenant_read_actions
input.subject.type == "service"
input.subject.id in read_subjects
input.subject.id in tenant_read_subjects
}
allowed if {
input.resource.system == "tenant-engine"
input.action in live_read_actions
input.subject.type == "service"
input.subject.id in live_read_subjects
}
allowed if {
input.resource.system == "tenant-engine"
input.action in guardrail_read_actions
input.subject.type == "service"
input.subject.id in guardrail_read_subjects
}
allowed if {

View file

@ -33,6 +33,17 @@ resource_types:
A tenant's resolved ceiling (spend, seats, and similar limits) plus
the provenance of that value. Not an entitlement and not a meter.
actions:
- name: tenant.read
capabilities:
- View
- Audit
planes:
- Identity
- Audit
exposure_modes:
- Metadata
metadata:
required_context: []
- name: tenant.create
capabilities:
- Create
@ -68,6 +79,30 @@ actions:
- Metadata
metadata:
required_context: []
- name: tenant.role.read
capabilities:
- View
- Audit
planes:
- Identity
- Policy
- Audit
exposure_modes:
- Metadata
metadata:
required_context: []
- name: tenant.role.read.live
capabilities:
- View
- Audit
planes:
- Identity
- Policy
- Audit
exposure_modes:
- Metadata
metadata:
required_context: []
- name: tenant.plan.assign
capabilities:
- Bind

View file

@ -51,6 +51,23 @@
}
],
"actions": [
{
"name": "tenant.read",
"capabilities": [
"View",
"Audit"
],
"planes": [
"Identity",
"Audit"
],
"exposure_modes": [
"Metadata"
],
"metadata": {
"required_context": []
}
},
{
"name": "tenant.create",
"capabilities": [
@ -104,6 +121,42 @@
"required_context": []
}
},
{
"name": "tenant.role.read",
"capabilities": [
"View",
"Audit"
],
"planes": [
"Identity",
"Policy",
"Audit"
],
"exposure_modes": [
"Metadata"
],
"metadata": {
"required_context": []
}
},
{
"name": "tenant.role.read.live",
"capabilities": [
"View",
"Audit"
],
"planes": [
"Identity",
"Policy",
"Audit"
],
"exposure_modes": [
"Metadata"
],
"metadata": {
"required_context": []
}
},
{
"name": "tenant.plan.assign",
"capabilities": [
@ -258,6 +311,23 @@
"metadata": {
"description": "flex-auth's own service identity. Authorized only for tenant.guardrail.read so the PDP can consume ceilings without being able to change them (FLEX-WP-0014)."
}
},
{
"id": "user-engine",
"type": "Service",
"display_name": "user-engine service principal",
"organization_relation": "ServiceProvider",
"roles": [
"Operator"
],
"groups": [
"group:tenant-engine-writers",
"group:tenant-engine-readers"
],
"tenant": "tenant:platform",
"metadata": {
"description": "user-engine's service identity. It owns the portal workflow that reads and mutates tenant lifecycle records through tenant-engine."
}
}
],
"groups": [
@ -265,7 +335,8 @@
"id": "group:tenant-engine-writers",
"display_name": "tenant-engine Write API Callers",
"members": [
"tenant-engine"
"tenant-engine",
"user-engine"
],
"tenant": "tenant:platform"
},
@ -274,7 +345,8 @@
"display_name": "tenant-engine Guardrail Readers",
"members": [
"flex-auth",
"tenant-engine"
"tenant-engine",
"user-engine"
],
"tenant": "tenant:platform"
}

View file

@ -21,6 +21,20 @@ subjects:
tenant.role.revoke, tenant.plan.assign, the lifecycle actions
tenant.update, tenant.retire, tenant.reactivate, and the
guardrail actions tenant.guardrail.read, tenant.guardrail.set.
- id: user-engine
type: Service
display_name: user-engine service principal
organization_relation: ServiceProvider
roles:
- Operator
groups:
- group:tenant-engine-writers
- group:tenant-engine-readers
tenant: tenant:platform
metadata:
description: >-
user-engine's service identity. It owns the portal workflow that reads
and mutates tenant lifecycle records through tenant-engine.
- id: flex-auth
type: Service
display_name: flex-auth service principal
@ -40,10 +54,12 @@ groups:
display_name: tenant-engine Write API Callers
members:
- tenant-engine
- user-engine
tenant: tenant:platform
- id: group:tenant-engine-readers
display_name: tenant-engine Guardrail Readers
members:
- flex-auth
- tenant-engine
- user-engine
tenant: tenant:platform