tenant-engine/SCOPE.md
tegwick 7721ec6a31 Track the two external dispositions as TEN-WP-0012
TEN-WP-0011 closed correctly: T04 and T06 built everything this repo
owns. What neither could close is the other side — a sender credential
audit-core issues (AUDIT-IN-0002) and a canon edit only net-kingdom may
make (NET-IN-0002). Both intakes were filed outbound, so nothing in this
checkout held them.

Session protocol Step 3 scans workplans/ for open work. With every
workplan finished it found none, and each session re-derived the same two
externally-owned gaps from SCOPE.md prose and the audit-core source
before concluding there was nothing to do. TEN-WP-0012 holds that
conclusion so it is read rather than rediscovered, as a blocked workplan
with two wait tasks — the convention's status for work owed by another
party.

Records for each what would close it, including the decline branch, and
states the two things not to do: no editing net-kingdom canon from here,
and no requesting the audit-core token over the message bus.

No code change; 287 tests pass and ruff is clean.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 823014@bnt-lap001
Assistant-Session: 2a0786b1-efea-4c38-959b-6e86a493f259
2026-09-07 13:44:47 +02:00

142 lines
7.4 KiB
Markdown

# SCOPE
> Lightweight boundary for agents and contributors. Full contract:
> `net-kingdom/canon/standards/tenant-engine-boundary-contract_v0.1.md`.
> Aspirational role: `INTENT.md`. Layer declaration: Engine / PIP
> (`INTENT.md` frontmatter; `TEN-DEC-2026-001`).
---
## One-liner
Canonical PIP of tenant-as-an-entity facts for NetKingdom: existence,
lifecycle, onboarding grouping, capability roles, plan/subscription
assignment, and guardrail ceilings.
---
## Core Idea
`tenant-engine` answers "what is this tenant, what roles does it hold, what
plan is it on, and how far may it go" for two consumers: `key-cape`
(cached, at token issuance) and `access-engine` / `flex-auth` (live, for
high-stakes decisions). It never stores users, issues tokens, evaluates
approvals, or makes authorization decisions. Tenancy context is an input to
the decision, not a decision.
---
## Layer
| Key | Value |
| --- | --- |
| Layer | **Engine** |
| Role | **PIP** |
| Statute | `net-kingdom/canon/standards/security-layer-model_v0.7.md` |
| Companion | `net-kingdom/SECURITY-COMPANION.md` |
| Catalog row | tenant-as-an-entity facts (`§4`) |
| Tooling contacts | none (`key-cape` and OpenBao are not clients of this repo) |
| Non-Tooling clients | PostgreSQL / SQLite (own store); `flex-auth` `POST /v1/check` (Engine API on the write and authorized-read path); State Hub (work records, not a runtime dependency) |
| Write path | PEP-shaped: fail-closed when `access-engine` is unset or unreachable |
| Conformance today | Declaration is in our own voice. Mechanical `layer.yaml` check, persisted decision records, published stance map, and independent evidence custody are **not** yet shipped — see the review and `TEN-WP-0011`. |
---
## In Scope
- Tenant records: identifier, lifecycle (`active` / `retired`), current
onboarding grouping (ADR-0013). Grouping is mutable through an audited
reclassification, not by renaming `tenant_id`.
- Capability role grants/revocations: `PLTF`/`IAM`/`VEN`/`CUS` (ADR-0014),
audited, mostly plan-linked.
- Plan/subscription assignment, referenced by `adaptive-pricing` plan id.
- Guardrail/quota *policy*: spend / entity-count / action-count ceilings,
resolved as a total function of grouping, plan, override, and lifecycle.
Seeded key: `spend.monthly`. `trial` defaults to zero.
- Cache-read API for `key-cape` (token-issuance-time `tenant_roles` claim
source): `GET /tenants/{id}/roles`.
- Live-lookup API for `access-engine` (high-stakes, `aal2`-class
decisions): `GET /tenants/{id}/roles/live`. Store unavailability returns
`503`, never `200` plus empty roles.
- Write API for create / grant / revoke / plan / metadata / retire /
reactivate / grouping / guardrail mutations, authorization-gated by
`flex-auth`. Unset or unreachable authorizer denies.
- Authoritative tenant read with ETag / If-Match / idempotency on
lifecycle and guardrail mutations.
## Out of Scope
- Identity, authentication, MFA, token issuance — `key-cape`/Keycloak.
- Authorization decisions — `access-engine` is the PDP; `tenant-engine` is
a data source it queries, never the other way around.
- Approval objects and approval lifecycle — `approval-engine`. Contested
in `TEN-DEC-2026-001`; this repo will not grow one.
- Users, profiles, memberships — `user-engine`. `tenant_id` is the only key
shared between the two services.
- Pricing-model / plan term definitions — `adaptive-pricing`.
- Payment processing — not yet identified as owned by any repo.
- Runtime secret custody — OpenBao / `secrets-engine`.
- Metering / consumption counters — whoever meters the resource writes
them; this service does not observe spend.
- Rate limiting / traffic shaping — gateway concern, not `action_count`.
- Containment / actuation — unowned and held at zero estate-wide.
- Irreversible operational decisions without human approval.
- Direct Tooling-layer clients — Staff and agents reach tenant facts
through this Engine, not past it.
## Current State
Production service, not a bootstrap. Workplans `TEN-WP-0001` through
`TEN-WP-0011` are all `finished`: they shipped the domain model, the three
boundary-contract APIs, the `flex-auth` write authorizer, lifecycle,
guardrails, PostgreSQL as the production store, mutable grouping,
staged-promotion onboarding, and the security-layer conformance surfaces.
The only open workplan is `TEN-WP-0012`, which tracks two dispositions
owed by other repos and expects no code change here.
| Surface | Shipped | Notes |
| --- | --- | --- |
| Domain model + SQLite/in-memory store | yes | `TEN-WP-0002` |
| Cache-read / live-lookup / write APIs | yes | `TEN-WP-0002` |
| `flex-auth` `WriteAuthorizer` | yes | Fail-closed; `is_allowed()` returns a bool and **discards the decision envelope** |
| Production runtime | yes | `TEN-WP-0004`; image pin in `deploy/base/tenant-engine.yaml` |
| Lifecycle (update / retire / reactivate) | yes | `TEN-WP-0005`; no hard-delete |
| Guardrail policy | yes | `TEN-WP-0006` / `0007`; `docs/tenant-guardrail-policy.md` |
| PostgreSQL production store | yes | `TEN-WP-0009`; deploy mounts `TENANT_ENGINE_DATABASE_URL_FILE` |
| Mutable grouping | yes | `TEN-WP-0010`; identifier segment stays historical |
| Staged promotion | yes (declared) | `TEN-WP-0008`; `railiance/app.toml`; live pin recorded as `previous_stable`. Helm CLI apply is a railiance-bootstrap gap (`RAIL-BS-IN-0001`). |
| Machine-readable `layer.yaml` | yes | `TEN-WP-0011-T01`; check in `scripts/check_layer_conformance.py` |
| Persisted `authorization_decision_id` | yes | `authz_records` plus mutation event payload (`TEN-WP-0011-T02`) |
| Published unreachable-engine stance map | yes | `pep-stance.yaml`, fail-closed, tested equal to shipped behaviour |
| Independent audit-core emission | path shipped, sender pending | Local outbox + POST `/v1/events`; waiting on `AUDIT-IN-0002` (`TEN-WP-0012-T01`) |
| Bounded event-read interface | yes | `events_for(tenant_id)` only (`TEN-WP-0011-T05`) |
| Claim freshness / input-class lifetime | yes | `pip-claims.yaml` (`TEN-WP-0011-T03`) |
The boundary contract still labels guardrail policy "reserved, not
implemented" and still calls this repo "not a policy enforcement point".
Both sentences are stale: guardrails shipped, and the write path is
PEP-shaped even though this repo is not a PDP. Amendment is a
`net-kingdom` change, requested from `TEN-WP-0011` as `NET-IN-0002` and
tracked here as `TEN-WP-0012-T02`.
Those two rows are the only open items in this repo, and neither is ours
to close: one waits on a credential audit-core issues, the other on a
canon edit only `net-kingdom` may make. `TEN-WP-0012` holds both so they
are read rather than re-derived each session.
## Getting Oriented
- Start with: `INTENT.md`
- Working companion: `net-kingdom/SECURITY-COMPANION.md`
- Statute: `net-kingdom/canon/standards/security-layer-model_v0.7.md`
- Ownership contract: `net-kingdom/canon/standards/tenant-engine-boundary-contract_v0.1.md`
- Claim/carrying mechanism: `net-kingdom/canon/standards/iam-profile_v0.3.md`
- Layer declaration: `decisions/decisions.md` `TEN-DEC-2026-001`
- Review: `history/2026-08-29-security-layer-intent-scope-review.md`
- Evolution workplan: `workplans/TEN-WP-0011-security-layer-conformance.md`
- External waits: `workplans/TEN-WP-0012-external-conformance-waits.md`
- flex-auth write-authorization integration: `docs/flex-auth-integration.md`
- Guardrail contract: `docs/tenant-guardrail-policy.md`
- Lifecycle contract: `docs/tenant-lifecycle-api.md`
- Agent instructions: `AGENTS.md`, `CLAUDE.md`
- Workplans: `workplans/`