tenant-engine/SCOPE.md
tegwick 6644ad8402
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 50s
Onboard tenant-engine to the staged-promotion contract
TEN-WP-0008. railiance/app.toml declares criticality=high, empty secrets,
isolated canary, and the live PostgreSQL digest as previous_stable.
Manifests render through kustomize (deploy/ and deploy/canary/). Stage 1
passed. Stage 2/3 Helm-only CLI gap requested as RAIL-BS-IN-0001 rather
than a dummy chart.

Assistant: grok
Assistant-Session: 01a04cea-e5e8-7081-a0fc-808ebbc35fa9
2026-08-29 14:51:27 +02:00

6.9 KiB

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. Finished workplans TEN-WP-0001 through TEN-WP-0007, TEN-WP-0009, and TEN-WP-0010 shipped the domain model, the three boundary-contract APIs, the flex-auth write authorizer, lifecycle, guardrails, PostgreSQL as the production store, and mutable grouping. TEN-WP-0008 (staged-promotion onboarding) is still ready, not done.

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; AUDIT-IN-0002
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.

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
  • 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/