# URS-36 — Licensing, Entitlements & Subscription Management

## Target-State User Requirements Specification — Verixa Launch URS Pack

**Revision:** v1.0 — Target State URS (remaining work tracked via the six open blockers in §17)

---

## 0. Controlled Document Header

| Field | Value |
|---|---|
| Document Title | URS-36 — Licensing, Entitlements & Subscription Management — Target-State |
| Document Type | Target-State User Requirements Specification |
| Scope | Three-entity commercial-governance + technical-isolation model (`customer_account` / `tenant_environment` / `subscription`), per-tenant-environment technical isolation per ADR-004, per-module entitlement matrix, per-seat / named-user / authority-profile-tied license assignment, subscription lifecycle with on-hold + grace + shield + expired-read-only + termination, billing-provider abstraction isolated from GxP access state, dunning workflow with split routine / fast-path / compliance-hold paths, usage metering, license-event audit, tenant-environment provisioning state machine, Mid-Workflow Continuity Shield with causally-linked child workflow exemption, emergency inspector access (break-glass), inspection-mode override (planned), retention-period read-only access, multi-currency + tax + FX, environment-class hard separation. |
| Status | **Target State URS v1.0** — locked. **This document specifies the target behaviour; implementation evidence remains subject to repository verification and validation evidence. The RLS conflict between the architecture document and ADR-004 (§0.6) remains an unresolved blocker — resolution required before validation.** |
| Audience | Founder / Chairman & MD; QA Head; Finance Head; Sales Head; Customer Success Head; RA Head; Information Security Head; Validation Head; DevOps/SRE Lead; Customer Admin (per customer_account); Verixa Platform Admin; external auditors / regulators (FDA, EMA, MHRA, CDSCO, PIC/S). |
| Source Documents | URS-MASTER-STRUCTURE; URS-02 RBAC & Permissions; URS-04 Workflow / HITL / E-Sig / Authority; URS-05 Authority Profile / Delegation / SoD; URS-06 Audit Trail / Hash Chain / Tamper-Evident; URS-08 Tenant Management Lifecycle; URS-12 Document Control; URS-13 Change Control; URS-22 Inspection Management; URS-28 Training Management & Qualification; URS-30 Notifications; URS-35 Infrastructure / Operational Resilience; **ADR-004 / VX-FLOW-038 — Tenant Database Architecture Options**; Verixa Platform Architecture (dev-vimal-deploy branch). |
| Effective Date | 2026-05-13 |
| Caveat | This document describes target application behaviour. It is not evidence of executed validation, implemented code, or regulatory compliance. AI legal posture is presented as internal forward-looking governance subject to a future jurisdiction-specific legal assessment. Hash-chain audit claims (DEC-36-26) are conditional on URS-06 implementation evidence proving the hash chain; until proven, the substrate is append-only audit only. |

---

### 0.1 Module Purpose (One-line)

URS-36 establishes Licensing, Entitlements & Subscription Management as the canonical commercial-governance and tenant-isolation substrate of Verixa, structured on three first-class entities — `customer_account` (commercial parent / invoice / SLA rollup), `tenant_environment` (**one or more per customer_account**; **one or more per `environment_class` permitted** — each tenant_environment carries a unique `environment_slug` within its customer_account, and an `environment_class` ∈ {`validated_production`, `validated_test`, `sandbox`, `demo`}; each carries its own isolation model, data region, KMS key mode + ref, backup policy, validation status, migration version), and `subscription` (the contract attached to one tenant_environment for one contract term; uniqueness via PostgreSQL exclusion constraint on `(tenant_environment_id, tstzrange(effective_from, effective_to)) WITH &&` — no overlapping active contract date ranges per tenant_environment). The License Gate routes regulated-write decisions by `tenant_environment_id`, never by customer or tenant identity alone.

### 0.2 Scope Boundary

In-scope:
- Three-entity model: `customer_account` → `tenant_environment` (1..N per customer_account; one OR MORE per environment_class permitted; unique on `(customer_account_id, environment_slug)`) → `subscription` (no overlapping active contract date ranges per tenant_environment; exclusion constraint on `effective_from`/`effective_to`).
- Per-tenant-environment **technical isolation model** per ADR-004 (`OPTION_B_SCHEMA_PER_TENANT` / `OPTION_B_PLUS_SCHEMA_RLS_ROLE` / `OPTION_C_DEDICATED_DB` / `OPTION_D_HYBRID_ROUTED`).
- Per-tenant-environment data_region, KMS key mode + ref, backup policy ref, tenant-environment provisioning state machine, migration version.
- Per-subscription commercial plan, contract term, seat ceilings, currency, billing schedule, channel partner, lifecycle state, environment_class (denormalised from parent tenant_environment for fast gate evaluation).
- Per-subscription module-entitlement matrix.
- Named-user license assignment (mandatory for `validated_*` environment classes).
- Authority-profile-tied seat allocation with URS-28 qualification dependency.
- Subscription lifecycle: `draft → quote_pending → active → renewing → subscription_on_hold → grace_period → shielded_expiry_pending → expired_read_only → terminated`.
- License-assignment lifecycle: `unassigned → assigned → active → suspended → revoked → reassigned → archived`.
- License Gate at canonical pipeline position (§0.5) with two-layer cache (per-request memoisation + versioned Redis cache + short safety TTL + fail-closed-on-write).
- Module entitlement enforcement.
- Mid-Workflow Continuity Shield with **causally-linked child workflow exemption** (DEC-36-14).
- Inspector access: **two distinct paths** — (a) planned inspection-mode override (DEC-36-16); (b) emergency break-glass inspector access (DEC-36-15-EMG) with credential capture + escalation-not-revoke model: 24h binding-overdue escalation (access continues), 48h platform-admin placeholder URS-22 context permitted, 72h absolute emergency expiry unless converted to planned override.
- Dunning workflow with **three paths**: (a) routine cadence; (b) fast-path commercial hold (chargeback / fraud / rescission / bankruptcy); (c) compliance hold (sanctions / regulatory order).
- Validated vs sandbox vs demo hard data segregation.
- Retention-period read-only access.
- Trial / Pilot licensing.
- Channel partner registry.
- Billing-provider abstraction isolated from GxP access via `billing_events` queue + controlled rules.
- Usage metering, invoice + payment + dunning + refund + write-off.
- Tax + FX per jurisdiction + currency.
- License-event append-only audit (hash-chain conditional on URS-06 evidence).

Out-of-scope (owned by adjacent modules): URS-08 tenant operational mechanics; URS-02 RBAC catalogue; URS-05 SoD definitions; URS-06 hash-chain substrate; URS-13 CR records; URS-30 template authoring; URS-35 IaC + backup engines (URS-36 holds policy refs); tax + FX external providers; GL postings.

---

### 0.3 Glossary

| Term | Definition |
|---|---|
| Customer Account | The commercial parent entity. One per real-world customer organisation (e.g., Aeonn Health, Pfizer, GSK). Owns the master service agreement, the commercial relationship, the consolidated invoice + SLA rollup. Does NOT directly own GxP records or isolation routing. |
| Tenant Environment | A discrete operating environment within a customer account. **One or more per `environment_class` permitted** (e.g., a large customer may run multiple `validated_production` environments by region / site / business unit). Carries the technical isolation model (per ADR-004), data_region, KMS key mode + ref, backup policy ref, tenant-environment provisioning state, migration version, validation status. Each tenant_environment has a unique `environment_slug` within its customer_account. **The License Gate routes regulated-write decisions by `tenant_environment_id`.** |
| Subscription | The contract attached to ONE tenant_environment for ONE contract term. Carries commercial plan, seat ceilings, billing schedule, currency, channel partner, lifecycle state. A tenant_environment may have a sequence of subscriptions over time (one per term); only one active at any moment per environment. |
| Environment Class | Fixed enum on tenant_environment: `validated_production` / `validated_test` / `sandbox` / `demo`. Drives named-user mandate, GxP-write permissibility, watermark rendering, audit retention. |
| Commercial Plan | The named product packaging on a subscription (`starter` / `pro` / `enterprise` / `custom`). Governs pricing + default module bundle. **Decoupled from technical isolation.** |
| Technical Isolation Model | The physical / logical tenant isolation strategy on a tenant_environment per ADR-004. One of `OPTION_B_SCHEMA_PER_TENANT` / `OPTION_B_PLUS_SCHEMA_RLS_ROLE` / `OPTION_C_DEDICATED_DB` / `OPTION_D_HYBRID_ROUTED`. **First-class field on tenant_environment; NEVER derived from commercial plan name.** |
| Tenant Schema | Field on tenant_environment for Options B / B+ / D-shared. PostgreSQL schema name (`tenant_<env_slug>`). |
| DB Instance Ref | Field on tenant_environment for Options C / D-dedicated. Dedicated RDS instance / cluster handle (ARN). |
| Data Region | The AWS / Azure / GCP region where the tenant_environment's data physically resides. Mandatory for jurisdictional binding. |
| KMS Key Mode | One of `shared_platform_key` / `customer_managed_kms` / `dedicated_kms` per ADR-004 tiering. |
| Backup Policy Ref | Reference to URS-35 per-tenant-environment backup policy. |
| Tenant Environment Provisioning State | State machine on tenant_environment: `pending → provisioning → provisioned → validation_pending → active → provisioning_failed → decommissioned`. Independent of subscription lifecycle. |
| Migration Version | The migration version applied to the tenant_environment's schema / DB. Mismatch with platform version blocks regulated writes (`MIGRATION_VERSION_MISMATCH`). |
| Validation Status | On tenant_environment: `not_validated` / `iq_complete` / `oq_complete` / `pq_complete` / `validated`. `validated` required before `environment_class = validated_*` activation. |
| Plan ↔ Isolation Permissibility Map | Versioned map of which isolation models are permitted for which commercial plans (e.g., Starter→{B}; Enterprise→{B+, C, D}). |
| Module Entitlement | Boolean per subscription per module. Drives License Gate. |
| License Assignment | Right-to-use granted under a subscription, bound to a userId + seat class + module scope. |
| Named-User License | License assigned to a specific userId. Mandatory for `validated_*` environment classes — **rationale: deterministic seat availability + EU Annex 11 §16 (incident management) + 21 CFR Part 11 §11.10(c) (ready retrieval). Not because attribution would otherwise be lost; attribution is preserved at the record level via authenticated JWT userId regardless of licensing model.** |
| Concurrent-Session License | License consumed at peak concurrent session count. Permitted ONLY for `sandbox` / `demo` environment classes. |
| Seat | Unit of license capacity. |
| Seat Class | The class of seat consumed: `general` / `qp_release_authority` / `inspection_owner_authority` / `final_quality_approver` / `rp_release_authority` / etc. |
| Soft Cap / Hard Cap | Per DEC-36-10. Soft cap = alert + auto URS-13 CR; hard cap = block. |
| Subscription On-Hold | New state between `active` and `grace_period`. Entered when (a) routine dunning Day 21 reached; or (b) fast-path commercial hold triggered (chargeback / fraud / rescission / bankruptcy); or (c) compliance hold triggered (sanctions / regulatory order — via separate compliance_hold path). In on-hold: regulated writes are SHIELDED (Mid-Workflow Shield applies), not immediately blocked. Cure-able via payment + URS-13 CR. |
| Mid-Workflow Continuity Shield | Mechanism that prevents license-state transitions from interrupting in-flight critical regulated workflows. Permits: (a) completion of in-flight workflows that started before the triggering state change; (b) **causally-linked child workflows** declared by parent workflow modules per `workflow_dependency_declaration` (DEC-36-14). New independent regulated workflows are blocked. |
| Causally-Linked Child Workflow | A regulated workflow that is declared (in versioned platform configuration) to be a permitted child of a parent in-flight workflow. Each child workflow record carries `parent_workflow_id`, `causal_reason`, `inherited_shield_id`. Example: a deviation (URS-16) arising during a batch QP-release (URS-23) is a permitted child if `(URS-23, qp_certification_in_progress)` declares URS-16 as a child class. |
| Inspector Account | A user account bound to `inspector_authority` Authority Profile. Exempt from seat-ceiling and license-state blocking **only within tenant_environment boundary, RBAC scope, audit logging, and inspection-context binding**. |
| Planned Inspection-Mode Override | Pre-approved regulator access during `expired_read_only` (DEC-36-16). Dual approval (`inspection_mode_override_authority` Verixa + `executive_authority` customer); 14-day default; URS-22 inspection-context bound BEFORE grant. |
| Emergency Inspector Access (Break-Glass) | Granted-on-arrival regulator access for unannounced inspections (DEC-36-15-EMG). Triggered by **pre-authorized `inspection_grantor_authority`** (customer-side; not any executive_authority). Credential capture mandatory (regulator ID, agency reference, badge photo URL or equivalent). Read-only scope. **Escalation-not-revoke model:** 24h binding-overdue escalation (access continues; URS-30 escalation); 48h platform-admin placeholder URS-22 context permitted (access continues); 72h absolute expiry unless converted to planned override (DEC-36-16). Access is NEVER auto-revoked at 24h or 48h. Manual revoke available at any time. |
| Compliance Hold | Separate hold path triggered by `sanctions_violation` / `regulatory_order` / `legal_hold_order`. Routes via `compliance_hold_authority` (Verixa-internal + Legal Counsel + Executive). NOT part of ordinary dunning. Different state machine. |
| Retention-Period Read-Only Access | Post-termination read-only access for regulatory retention period (10-year default; jurisdiction-configurable). URS-35 cold-storage bound. |
| License-Cache Version | Monotonically-increasing counter per `(tenant_environment_id, subscription_id)`. Bumped on any subscription / entitlement / license / isolation / environment / migration write. Cached License Gate decisions key on the version stamp; stale version stamps fail to match → forced re-evaluation. |
| Fail-Closed-on-Write | License Gate behaviour: for regulated WRITE actions, a cache miss or stale-cache version stamp causes the gate to perform a fresh authoritative DB evaluation. Cache hits accepted only for READ-side decisions. |
| Workflow Dependency Declaration | Versioned platform configuration mapping `(parent_module, parent_state) → permitted_child_modules + permitted_child_actions`. Drives DEC-36-14 child-workflow exemption. Changes are super_admin-controlled with URS-13 CR. |
| Root Workflow ID | The top-most shield-eligible parent in a chain of causally-linked child workflows. Used to detect cycles and enforce DEC-36-14 max-depth-3 rule. |
| Shield Depth | Integer 1..3. 1 = direct child of shield-eligible parent. 2 = grandchild. 3 = great-grandchild. Depths >3 require URS-13 CR + executive + final_quality_approver override. |
| Inherited Shield ID | The shield context ID inherited by a child workflow from its parent. Allows audit traceability of which root-workflow's shield protects each descendant. |
| Disclosure Class | Field on every hold record (commercial + compliance) controlling URS-30 notification routing. Values: `full_disclosure` / `restricted_disclosure` / `internal_only` / `legal_counsel_only` / `restricted_pending_legal_review`. Legal-controlled; defaults are starting points only and require per-order classification within 5 business days for `restricted_pending_legal_review`. |
| Subscription On-Hold Contact Support | Canonical neutral customer-facing license-state label rendered when the hold's `disclosure_class` is `restricted_*` / `internal_only` / `legal_counsel_only`. No hold-class or hold-reason disclosed to customer admin. |
| License Cache Version Stamp | Monotonic bigint per `(tenant_environment_id, subscription_id)` in the `license_cache_versions` DB table. The DB row is the source of truth. Redis cache stamps are replicas. |
| In-Transaction Version Bump | Cache invalidation contract: every state-changing write to subscription / entitlement / license / isolation / environment / migration / compliance-hold tables MUST bump the `license_cache_versions.version_stamp` in the SAME database transaction as the underlying write. Async invalidation is prohibited. |
| Post-Commit Redis Outbox | Pattern for propagating in-transaction version bumps to Redis cache after the DB transaction commits. Uses PostgreSQL `LISTEN/NOTIFY` or a transactional outbox table consumed by a Redis-update worker. |

---

### 0.4 Module Architectural Picture

```mermaid
graph LR
  subgraph M36 [Module 36 — Licensing, Entitlements & Subscription Management]
    CA[Customer Account]
    TE[Tenant Environment]
    SUB[Subscription]
    PLAN[Commercial Plan Catalogue]
    ISOL[Technical Isolation Model]
    ENT[Module Entitlement Matrix]
    REGION[Data Region]
    KMS[KMS Key Mode + Ref]
    BACKUP[Backup Policy Ref]
    PROV[Tenant Env Provisioning State]
    VAL[Validation Status]
    MIGV[Migration Version]
    SEAT[Seat Allocation Register]
    LIC[License Assignment Register]
    USAGE[Usage Metering]
    BILL[Billing Event Queue]
    INV[Invoice + Payment Register]
    DUN[Dunning Workflow]
    HOLD[Compliance Hold]
    GATE[License Gate API]
    CACHE[Versioned License Cache]
    SHIELD[Mid-Workflow Continuity Shield]
    WFDEP[Workflow Dependency Declaration]
    INSPP[Planned Inspection Override]
    INSPE[Emergency Inspector Break-Glass]
    RET[Retention-Period Read-Only]
    PIMP[Plan-Isolation Permissibility Map]
  end

  CA --> TE
  TE --> SUB
  TE --> ISOL
  TE --> REGION
  TE --> KMS
  TE --> BACKUP
  TE --> PROV
  TE --> VAL
  TE --> MIGV
  SUB --> ENT
  SUB --> SEAT
  SUB --> LIC
  SUB --> USAGE
  SUB --> INV
  PLAN --> SUB
  PIMP --> ISOL
  PIMP --> SUB
  M2[URS-02 RBAC & Permissions] --> GATE
  M4[URS-04 Workflow / HITL / E-Sig] --> SUB
  M5[URS-05 Authority Profile / SoD] --> LIC
  M6[URS-06 Audit / Append-Only] --> SUB
  M6 --> LIC
  M6 --> ENT
  M6 --> SEAT
  M6 --> INV
  M6 --> ISOL
  M6 --> HOLD
  M6 --> INSPE
  M8[URS-08 Tenant Lifecycle] <--> CA
  M8 <--> TE
  M8 <--> PROV
  M12[URS-12 Document Control] <--> SUB
  M13[URS-13 Change Control] <--> SUB
  M13 <--> PLAN
  M13 <--> ISOL
  M13 <--> ENT
  M13 <--> HOLD
  M22[URS-22 Inspection Management] <--> INSPP
  M22 <--> INSPE
  M28[URS-28 Training Qualification Gate] --> LIC
  M30[URS-30 Notifications] --> DUN
  M30 --> HOLD
  M30 --> SUB
  M35[URS-35 Infrastructure / Backup] <--> BACKUP
  M35 <--> REGION
  M35 <--> KMS
  M35 <--> RET
  GATE --> CACHE
  CACHE --> GATE
  GATE --> M14[URS-14..URS-35 Consumer modules]
  WFDEP --> SHIELD
  SHIELD --> M23[URS-23 Batch Records]
  SHIELD --> M15[URS-15 OOS / OOT]
  SHIELD --> M27[URS-27 Recall Execution]
  SHIELD --> M22
  SHIELD --> M31[URS-31 DQG Filing]
  BILL --> DUN
  DUN --> SUB
  HOLD --> SUB
```

---

### 0.5 Request Pipeline Position of License Gate (Canonical)

```
HTTP request
   ↓
1. CSRF verify
   ↓
2. Correlation ID
   ↓
3. authenticate (JWT → customer_account_id + userId)
   ↓
4. environmentScope (resolve `tenant_environment_id` per the hardened rules below)
   ↓
5. tenantScope (set per-environment routing: search_path for B/B+/D-shared OR dedicated connection for C/D-dedicated; SET app.current_tenant_environment_id)
   ↓
6. contextScope (URS-03 study / site / product / supplier — scope-validated against the resolved tenant_environment_id)
   ↓
7. requirePermission (URS-02 RBAC)
   ↓
8. requireLicense (URS-36 License Gate — keyed on tenant_environment_id)
   ↓
9. authorityCheck (URS-05 Authority Profile)
   ↓
10. trainingGate (URS-28; for authority actions)
   ↓
11. Route handler
   ↓
12. URS-06 append-only audit hook
```

The License Gate is keyed by `tenant_environment_id` (NOT customer_account_id, NOT tenant_id alone). A user with access to both `aeonn-prod` (validated_production) and `aeonn-test` (validated_test) environments holds two separate license assignments under two separate subscriptions; the gate consults the one matching the request's tenant_environment_id.

**Hardened `environmentScope` rules (normative; mirrors Cross-Module Patch Set PATCH-01-006 + PATCH-01-007):**

1. **JWT model.** JWT carries `userId`, `customer_account_id`, `accessible_tenant_environment_ids` (array; computed at issue time), `current_tenant_environment_id` (selected at session start; mutable only via the controlled environment-switch endpoint below), `roles`, `permissions`, `iat`, `exp`.
2. **Header / JWT matching.** If the request carries an `X-Env-Id` header, it MUST match the JWT's `current_tenant_environment_id` exactly; mismatch → 401 `ENV_ID_HEADER_JWT_MISMATCH`. If `X-Env-Id` is absent, fall back to the JWT's `current_tenant_environment_id`. The header is NOT trusted independently of the JWT.
3. **Accessibility check.** The resolved `tenant_environment_id` MUST be in the JWT's `accessible_tenant_environment_ids`; if not → 403 `ENV_NOT_ACCESSIBLE`.
4. **Controlled environment switch.** Mutating `current_tenant_environment_id` is permitted only via `POST /api/v1/auth/switch-environment` with payload `{target_tenant_environment_id}`. On success the current session is terminated (JWT revoked), a new JWT is issued with the new `current_tenant_environment_id`, and a distinct session record is created per URS-01 session audit log. Direct mutation outside this endpoint is prohibited.
5. **Live access re-check via `environment_access_resolver`.** On every request, the resolver re-checks live accessibility against the union of all valid access paths: (a) active `license_assignments` row for `(user_id, tenant_environment_id)` with subscription in a writable-or-readable state per the License Gate; OR (b) active `emergency_inspection_grants` row for `(user_id, tenant_environment_id)`, `current_time < absolute_expiry_at_72h`, state ∈ {`active_unbound`, `binding_overdue_escalated`, `placeholder_bound`, `bound_to_urs_22`}; OR (c) active `inspection_mode_overrides` row for `(user_id, tenant_environment_id)`, `current_time ∈ [effective_from, effective_to]`, `revoked_at IS NULL`; OR (d) active retention-read-only grant for `(user_id, tenant_environment_id)` for post-terminated environments within their retention window per DEC-36-17; OR (e) platform-admin permitted context per `platform_context.ts` cross-tenant authorisation (super_admin / platform_admin with documented break-glass per URS-08 + URS-06 audit). The resolver returns the **access path used** + **scope envelope** (read-only vs write-eligible) which is propagated to subsequent License Gate evaluation.
6. **Fail closed.** If none of (a)–(e) resolves → 403 `ENV_ACCESS_REVOKED`. JWT staleness (e.g., license revoked after JWT issue, grant expired, override revoked) MUST result in `ENV_ACCESS_REVOKED`.
7. **Audit.** The access path chosen by the resolver is logged in URS-06 audit per request for inspection-readiness.

---

### 0.6 RLS Conflict Resolution Gate (Unresolved Blocker)

The architecture document (`Verixa.ARCHITECTURE.md`, dev-vimal-deploy branch) states: *"PostgreSQL Row-Level Security (RLS) on every table"* and *"SET LOCAL app.current_tenant_id via TDAL."*

ADR-004 / VX-FLOW-038 (v1.0, May 2026) states: *"PostgreSQL Row-Level Security (RLS) is NOT enabled on any table. Tenant isolation is 100% application-layer-only."* and *"Missing WHERE clauses found in 3 endpoints."*

These two statements cannot both be true. URS-36 fails closed on this conflict: **the tenant-isolation posture is `Unknown — repo evidence required`** until resolved. Resolution required before any URS-36 validation event.

**Evidence required to resolve:**
- PostgreSQL policy dump (`pg_dump --schema-only --no-owner` + `\dp` per table)
- Migration files that enable `ENABLE ROW LEVEL SECURITY` + `CREATE POLICY` per table
- Negative integration tests proving cross-tenant queries return zero rows when middleware is bypassed
- Endpoint-level tests for the three known missing `WHERE tenant_id =` endpoints (`GET /em/results`, `GET /investigations/overdue`, `GET /em/trends/:locationId`)
- TDAL unit tests proving `SET LOCAL app.current_tenant_id` is invoked on every connection

Until resolved, URS-36 §0.5 License Gate operates under the **conservative assumption that RLS is not enabled**, and `requireLicense` performs explicit `tenant_environment_id` filtering on every license query as a defence-in-depth measure regardless of underlying RLS state.

---

## 1. Module Purpose

URS-36 is the canonical commercial-governance + technical-isolation substrate. It maintains, per customer:

1. **The commercial parent** — `customer_accounts` row. Invoice rollup, SLA rollup, channel partner relationship, contract signatory binding.
2. **One or more environments** — `tenant_environments` rows. Each carries its own isolation model, region, KMS, backup, validation status, migration version, provisioning state. Validated production, validated test, sandbox, demo each is a separate tenant_environment with its own lifecycle.
3. **Subscriptions per environment** — `subscriptions` rows. Each subscription is attached to ONE tenant_environment for ONE contract term. Carries commercial plan, seat ceilings, currency, billing schedule.
4. **Entitlements, licenses, and gating** — per-subscription module entitlements + per-subscription named-user license assignments + License Gate consulting these at canonical pipeline position.

The License Gate fails closed. It resolves decisions by `tenant_environment_id`, not customer or tenant alone. It uses a two-layer cache (per-request memoisation + versioned Redis) with explicit invalidation on writes + fail-closed-on-write + short safety TTL.

URS-36 enforces hard separation between environment classes, hard boundary on the Mid-Workflow Shield (with causally-linked child workflow exemption), break-glass inspector emergency access (separate from planned override), and split dunning paths (routine / commercial-fast-path / compliance-hold). Every state transition is append-only audited via URS-06; hash-chain integrity is claimed only if URS-06 evidence proves it.

---

## 2. Operating Preconditions

For URS-36 to operate, the following preconditions MUST hold. Each is Blocking; failure fails the gate closed.

- **URS-08 tenant exists** before any URS-36 customer_account / tenant_environment / subscription is created.
- **`tenant_environment_provisioning_status = active`** (per environment, not per tenant) before any regulated write under any subscription on that environment. Provisioning includes schema / DB creation per isolation model, migration application, audit setup, backup policy binding, KMS key binding, data-region routing, and migration-version verification. Each tenant_environment is provisioned independently.
- **URS-02 RBAC catalogue is active.** License Gate runs after RBAC.
- **URS-05 Authority Profile catalogue is active** with the new licensing-specific Authority Profiles registered (§4).
- **URS-06 append-only audit substrate is running.** Every license event is logged; audit-write failure blocks the originating action.
- **URS-13 Change Control is active.** Tier change, entitlement change, isolation-model change, environment-class change, contract amendment all route to URS-13.
- **URS-22 Inspection Management is active** (for inspection-mode override binding and emergency-grant URS-22 context creation).
- **URS-28 Training Qualification Gate is active** (for Authority-Profile-tied seat consumption).
- **URS-30 Notification substrate is running.**
- **URS-35 Infrastructure substrate is running** with per-tenant-environment backup policy, PITR (for Options C / D-dedicated), `pg_dump -n` capability (for Options B / B+ / D-shared) per ADR-004 §5–7.
- **NTP-synchronised system clock.** Subscription lifecycle transitions, grace-period boundaries, dunning cadences, emergency-grant 24h/48h/72h checkpoints are all time-bound; clock drift compromises enforcement.
- **§0.6 RLS conflict resolution status** — until resolved, License Gate operates under the conservative assumption (explicit `tenant_environment_id` filter on every license query).

---

## 3. Canonical Decision Register (DEC Catalogue)

| DEC ID | Decision |
|---|---|
| DEC-36-01 | **Three-entity model.** `customer_accounts` (1..1 per real-world customer organisation) → `tenant_environments` (**1..N per customer_account; one OR MORE per `environment_class` permitted** — large customers may operate multiple `validated_production` environments by region / site / business unit; each tenant_environment carries a unique `environment_slug` within its customer_account) → `subscriptions` (1..N per tenant_environment over time, but with **no overlapping active contract date ranges per tenant_environment**). Uniqueness: `tenant_environments` is unique on `(customer_account_id, environment_slug)`. `subscriptions` uses a **PostgreSQL exclusion constraint** on `(tenant_environment_id, tstzrange(effective_from, effective_to))` with `WITH &&` (no overlapping ranges per tenant_environment) — there is no `contract_term` column; the `effective_from` / `effective_to` pair defines the term. Consolidated invoice rolls up at customer_account level across all tenant_environments. |
| DEC-36-02 | **Commercial plan + technical isolation model are independent first-class fields on different entities.** `subscriptions.commercial_plan` (`starter`/`pro`/`enterprise`/`custom`). `tenant_environments.isolation_model` (`OPTION_B_SCHEMA_PER_TENANT` / `OPTION_B_PLUS_SCHEMA_RLS_ROLE` / `OPTION_C_DEDICATED_DB` / `OPTION_D_HYBRID_ROUTED`). Plan name MUST NOT imply isolation model. Permissibility constrained by `plan_isolation_permissibility` map. |
| DEC-36-03 | **Plan ↔ Isolation Permissibility Map.** Versioned. Default at launch: Starter→{B}; Pro→{B, B+}; Enterprise→{B+, C, D}; Custom→{B, B+, C, D}. Validated-production environment_class requires at minimum Option B per ADR-004 GxP scoring. Map changes super_admin-controlled with URS-13 CR. |
| DEC-36-04 | **Per-subscription per-module entitlement.** `module_entitlements` table holds `(subscription_id, module_id, enabled, effective_from, effective_to, source_change_control_id)`. URS-01..URS-06 platform-foundational and not separately entitleable. URS-07..URS-35 entitleable. |
| DEC-36-05 | **Tenant Environment Provisioning state machine.** States: `pending → provisioning → provisioned → validation_pending → active → provisioning_failed → decommissioned`. Provisioning steps per ADR-004: create schema (B / B+) or dedicated DB (C / D-dedicated) → run migrations → bind audit substrate → configure per-tenant-environment backup policy → bind KMS → configure data-region routing → verify migration version. **Per environment, not per tenant.** A customer with three environments has three independent provisioning state rows. Tenant_environment cannot enter `environment_class = validated_*` activation until `provisioning_status = active` AND `validation_status >= validated` AND `migration_version` matches platform version. |
| DEC-36-06 | **Environment-class drives named-user enforcement. Rationale: deterministic seat availability + EU Annex 11 §16 + 21 CFR Part 11 §11.10(c).** For `validated_production` or `validated_test`: named-user licensing mandatory regardless of commercial plan. For `sandbox` / `demo`: concurrent-session licensing permitted. **Attribution is preserved at the record level via authenticated JWT `userId` regardless of licensing model; the named-user mandate is about availability, not attribution.** |
| DEC-36-07 | **Hard environment-class separation.** Each tenant_environment is a discrete database / schema / record set. Records cannot cross environment boundaries except via explicit migration-validated promotion (URS-13 CR + IQ/OQ/PQ on migrated data). Every record in `sandbox` / `demo` carries `record_gxp_status = non_gxp` + `test_data_flag = true`. Server-side watermark "SANDBOX — NOT FOR GxP USE" on every page + export when `environment_class ∈ {sandbox, demo}`. |
| DEC-36-08 | **Module-tied per-user license.** A user may hold different module-tied licenses (e.g., GMP licensed but not GCP). License Gate consults `license_assignments.module_scope_jsonb`. |
| DEC-36-09 | **Authority-profile-tied seats are separately ceilinged + priced. URS-28 qualification + active URS-05 Authority Profile binding required before seat activation.** Authority seats consumed from authority pool, never general pool. |
| DEC-36-10 | **Seat ceilings enforced at user-invite + Authority Profile bind time.** Soft cap default 0.9 × ceiling → URS-30 alert + auto URS-13 CR (non-blocking). Hard cap = ceiling → `LICENSE_SEAT_LIMIT_REACHED` (HTTP 422). |
| DEC-36-11 | **Subscription lifecycle.** `draft → quote_pending → active → renewing → subscription_on_hold → grace_period → shielded_expiry_pending → expired_read_only → terminated`. `subscription_on_hold` is reachable from `active` via routine dunning Day 21 OR fast-path commercial hold OR compliance hold (latter via separate state). All hold paths trigger Mid-Workflow Continuity Shield; cure path returns to `active`. |
| DEC-36-12 | **License-assignment lifecycle.** States: `unassigned → assigned → active → suspended → revoked → reassigned → archived`. Transitions: assign (`license_assignment_authority` + e-sig) → `assigned`; `user_first_login` → `active`; `rescind_before_login` → `unassigned`; suspend (`license_revocation_authority` + e-sig; SoD: revoker ≠ assigner) → `suspended`; reinstate → `active`; revoke (`license_revocation_authority` + e-sig; SoD) → `revoked`; `reassign_seat` → `reassigned (new user)`; `becomes_active` → `active`; archive → `archived` (terminal). Every transition append-only audited per URS-06. **SoD: assigner ≠ revoker** when dual-approval is configured. |
| DEC-36-13 | **Grace period — split between tenant-environment default and subscription snapshot.** Default 30 days; min 14 days (pharma-minimum to preserve mid-workflow continuity); max 90 days (Verixa policy). **Configuration:** `tenant_environments.default_grace_period_days` holds the tenant-environment-level default (administrative configuration); `subscriptions.grace_period_days_snapshot` holds the contract-term snapshot taken from the tenant_environment default at subscription activation. **The subscription snapshot value is the authoritative number used by the active contract term** — even if the tenant_environment default is subsequently changed, the live subscription continues to use its snapshot value until renewal, when a new snapshot is taken. Changes to either value follow URS-13 CR. URS-30 dispatches daily reminder during grace. |
| DEC-36-14 | **Mid-Workflow Continuity Shield with bounded transitive child workflow exemption.** A scheduled lifecycle state change (`active → on_hold`, `on_hold → grace`, `grace → expired_read_only`) is held by the Shield if any **in-flight critical workflow** exists on the affected subscription's tenant_environment. **Shield-permitted actions:** (a) completion of in-flight workflows that started before the triggering state change; (b) **causally-linked child workflows** under bounded transitive inheritance. Child workflow record MUST carry: `parent_workflow_id` (immediate parent), `root_workflow_id` (top-most shield-eligible parent), `causal_reason` (free-text justification), `inherited_shield_id` (parent's shield context), `shield_depth` (1 for direct child of shield-eligible parent; 2 for grandchild; 3 for great-grandchild). **Constraints**: `shield_depth ≤ 3` by default. Depths >3 are blocked with `SHIELD_DEPTH_EXCEEDED` unless an explicit case-by-case override is recorded — the override path requires `is_depth_override = true` on the `workflow_shield_inheritance` row, with all four fields populated: `override_source_change_control_id` (URS-13 CR), `override_reason` (free-text justification), `override_executive_e_sig_id`, `override_final_quality_approver_e_sig_id`. DB CHECK constraint enforces atomicity (cannot record depth >3 without all override fields populated). **No cycles**: `root_workflow_id` MUST be unique up the chain; a workflow MAY NOT appear as both ancestor and descendant in the same shield chain (cycle detection enforced at creation; `SHIELD_CYCLE_DETECTED` on violation). **Shield-blocked actions:** new independent regulated workflows (no causal link); child workflows whose declared `(parent_module, parent_state) → child_module` mapping is not present in `workflow_dependency_declarations`. Shield-eligible *root* parent workflows: URS-23 batch in QP-release / staged-review; URS-15 OOS investigation Phase IA/IB/II; URS-27 recall in execution; URS-22 inspection in back-room-active; URS-31 DQG filing in flight; URS-18 CAPA effectiveness pending. State during shield wait: `shielded_expiry_pending`. URS-13-controlled. |
| DEC-36-15-EMG | **Emergency Inspector Access (Break-Glass) for unannounced inspections — escalation model, not auto-revoke.** Trigger: pre-authorized `inspection_grantor_authority` (customer-side; NOT any executive_authority — must be specifically pre-authorized for break-glass grants) initiates emergency inspector access on regulator arrival. Required capture: (a) regulator name + agency + agency reference ID + badge / credential evidence URL or hash; (b) inspection purpose (free text); (c) inspector_user account creation. Default scope: read-only, tenant-environment-bound, RBAC-scoped, audit-logged on every read. Time-bound state machine: **(0h)** access granted; emergency_inspection_grants state = `active_unbound`. **(0h immediate)** URS-30 notification within 5 minutes to customer_account `executive_authority` + Verixa platform admin + RA Head + Founder. **(24h checkpoint)** if no URS-22 inspection_context_id has been bound, state transitions to `binding_overdue_escalated`; access continues; URS-30 escalation to Verixa platform admin + customer_account_admin + Founder. **Access is NOT revoked at 24h.** **(48h checkpoint)** if still unbound, Verixa platform admin MAY (via URS-04 e-sig) create a placeholder URS-22 inspection context (`urs_22_placeholder_reason = emergency_grant_binding_overdue_48h`) and auto-bind the inspector to it; state transitions to `placeholder_bound`. **(72h absolute expiry)** emergency access expires unconditionally; conversion to longer-term access requires planned override path (DEC-36-16) and a normal URS-22 inspection_context. State after expiry: `expired`. **Manual revoke** by `inspection_grantor_authority` or Verixa platform admin permitted at any point: state → `revoked`. Immediate URS-06 audit on grant + every state transition + every read. |
| DEC-36-16 | **Planned Inspection-Mode Override** (distinct from emergency break-glass DEC-36-15-EMG). Pre-approved regulator access during `expired_read_only` state. Dual approval (`inspection_mode_override_authority` Verixa + `executive_authority` customer). 14-day default (renewable via URS-13 CR). URS-22 inspection-context bound BEFORE grant. URS-04 e-sig. Immutable expiry. |
| DEC-36-17 | **Retention-period read-only access.** Post-termination, the customer retains read-only access to all GxP records for the regulatory retention period. Default 10 years; per-jurisdiction configurable via `tenant_environments.retention_years` per URS-08 jurisdiction binding. Data migrates to URS-35 cold storage per DEC-36-32 termination cascade step (7). Access gated by `retention_read_only` license type — separate from active subscription; granted to customer admin + tenant_environment admin for the retention window. |
| DEC-36-18 | **Environment-class change is super_admin + URS-13 CR + migration validation.** Cannot downgrade `validated_production` → `sandbox` or similar without IQ/OQ/PQ revalidation. Environment-class downgrade with regulated records in flight is blocked. |
| DEC-36-19 | **Trial / Pilot licensing.** A `trial` subscription is time-bounded (default 30 days; max 90 days per URS-13 CR), seat-limited (default 5 seats), environment-class-bound (`sandbox` or `validated_test`). Conversion to paid via URS-13 CR with `executive_authority` (customer) + `subscription_admin_authority` (Verixa) co-sign. Trial expiry without conversion auto-transitions to `expired_read_only`. |
| DEC-36-20 | **Channel partner registry.** Per-subscription optional `channel_partner_id` per `subscriptions.channel_partner_id`. Partners are pre-registered via URS-13 CR (`channel_partner_registration` CR type) with discount terms recorded in `channel_partners.discount_terms_jsonb`. Partner-attributed revenue is computed in the usage-and-revenue rollup at customer_account level. |
| DEC-36-21 | **Deployment class.** `tenant_environments.deployment_class` ∈ {`verixa_managed`, `byoc`, `on_premise`}. `verixa_managed` = Verixa hosts in Verixa's cloud account; `byoc` = customer's cloud account, Verixa deploys via IaC + remote management; `on_premise` = customer's data centre, restricted to specified customer profiles per URS-13 CR. BYOC and on-premise variants carry higher unit licensing rates, require additional security agreements per URS-12 (`byoc_security_agreement` / `on_premise_security_agreement` document types), and require `executive_authority` (customer) approval. |
| DEC-36-22 | **Usage metering substrate.** Every metered event (`api_call`, `ai_inference`, `audit_event_write`, `storage_gb_hour`, `batch_record_released`, `document_uploaded`, `regulated_record_created`) emits a row to `usage_records`. Roll-up per period (default daily). Per-tenant_environment overage thresholds emit URS-30 alerts. Per-period roll-up feeds invoice generation. |
| DEC-36-23 | **Billing-provider events isolated from GxP access via `billing_events` queue.** Provider webhooks land in `billing_events` (idempotency-keyed on `(provider, provider_event_id)`). Provider event lifecycle: `received → validated → reconciled → action_pending → action_applied`. Subscription service consumes `action_pending` events via controlled rules; **payment-failed events route to dunning workflow per DEC-36-25, NOT directly to subscription state**. |
| DEC-36-24 | **Tax + FX per jurisdiction + currency.** Tax rates sourced from `tax_rates` cache (provider-fed: Avalara / TaxJar / manual override). Per-jurisdiction rules respected (India GST + SGST/CGST, EU VAT, US sales tax, UK VAT). Tax-exempt status configurable per subscription. Currency on `subscriptions.currency` (INR / EUR / USD / GBP / JPY / CHF / SGD / AUD / CAD / BRL). FX rates locked at invoice issue via `fx_rates` snapshot; consolidation uses locked rates. |
| DEC-36-25 | **Dunning workflow with THREE distinct paths + LEGAL-CONTROLLED disclosure class.** **(a) Routine path** for ordinary payment failure: Day 1 `payment_failed_notice` → Day 7 `dunning_attempt_2` → Day 14 `dunning_attempt_3` → Day 21 `subscription_on_hold` → Day 51 `grace_period` → Day 81 `terminated` (URS-13 CR). **(b) Fast-path commercial hold** for `chargeback` / `fraud_flag` / `contractual_rescission` / `bankruptcy_declared`: immediately on Day 1 → `subscription_on_hold` with executive_authority (Verixa CFO) + `finance_review_authority` co-sign. **(c) Compliance hold path** for `sanctions_violation` / `regulatory_order` / `legal_hold_order`: routes via SEPARATE `compliance_holds` state machine, controlled by `compliance_hold_authority` (Verixa Legal + Executive). NOT part of ordinary dunning. Severities: `temporary_hold` / `permanent_hold` / `full_lockout`. All hold paths trigger Mid-Workflow Continuity Shield. Cure: payment + URS-13 CR (commercial); legal release + URS-13 CR + jurisdictional approval (compliance). **Disclosure class on every hold (NEW; legal-controlled, NOT automatic):** Every hold (commercial + compliance) carries a `disclosure_class` ∈ {`full_disclosure`, `restricted_disclosure`, `internal_only`, `legal_counsel_only`, `restricted_pending_legal_review`}. Default mapping (defaults only — Legal may override per-instance via URS-13 CR): routine commercial hold → `full_disclosure`; chargeback / fraud / rescission / bankruptcy → `restricted_disclosure`; legal_hold_order with secrecy clause → `legal_counsel_only`; sanctions_violation (before legal classification of jurisdiction-specific disclosure obligations) → `restricted_pending_legal_review`. **`disclosure_class` is the canonical gate on URS-30 notification routing**: `full_disclosure` permits customer-facing URS-30 dispatch; `restricted_disclosure` permits customer admin notification only (no broader stakeholder dispatch); `internal_only` blocks all customer-facing notifications (Verixa-internal stakeholders only); `legal_counsel_only` blocks all but Verixa Legal Counsel; `restricted_pending_legal_review` blocks all customer-facing notifications pending Legal classification — Legal MUST classify within 5 business days, post-classification routing follows the classified class. Customer-facing license-state in all restricted/internal/counsel-only/pending cases appears as **generic `subscription_on_hold_contact_support`** with neutral language and no hold-class or hold-reason disclosure; full hold detail is retained in Verixa platform_audit, not in tenant audit visible to customer admin. **The spec does NOT assert "sanctions notification is legally prohibited" as a universal rule** — disclosure obligations are jurisdiction- and order-sensitive, vary by legal regime (US OFAC / EU restrictive measures / India FEMA / UK OFSI / AML SAR-style "tipping off" / etc.), and require per-order Legal classification before routing is finalised. |
| DEC-36-26 | **License-event append-only audit; hash-chain conditional on URS-06 evidence.** Every license event — subscription create / tier change / entitlement toggle / seat allocation / license assignment / license revocation / invoice issue / payment post / dunning step / grace-period entry / expiry transition / termination / inspection-mode override / retention-mode entry / compliance hold / emergency inspection grant / workflow shield inheritance — produces a URS-06 append-only audit row attributable to a named user (customer admin / platform admin / named system-bot for clock-triggered events). Audit-write failure blocks the originating license action via `LICENSE_ACTION_AUDIT_WRITE_FAILED` (HTTP 500; originating action does NOT commit). **Hash-chain integrity claim is conditional on URS-06 implementation evidence proving the hash chain.** Until proven, the substrate is append-only audit only; URS-36 documentation MUST NOT overclaim Part 11 §11.10(e) hash-chain integrity. |
| DEC-36-27 | **License Gate two-layer cache with DB-as-source-of-truth + in-transaction version bump + post-commit Redis outbox + short safety TTL + fail-closed-on-write.** **Source of truth.** The `license_cache_versions` DB table is the authoritative version-stamp registry, keyed on `(tenant_environment_id, subscription_id)`, holding a monotonic `version_stamp` (bigint). The Redis cache is a **replica only**, never the source of truth. **Layer 1 — Per-request memoisation.** Within a single HTTP request, `requireLicense(tenant_environment_id, user_id, module_id, action)` computed at most once. **Layer 2 — Versioned Redis cache.** Cache key embeds the DB `version_stamp`. **Version bump is synchronous and in-transaction.** Any write to subscriptions / entitlements / license-assignments / isolation-model / environment-class / migration-version / compliance-hold MUST bump the `license_cache_versions.version_stamp` row in the SAME database transaction as the underlying write. **Async invalidation is prohibited.** **Post-commit Redis outbox.** Immediately after transaction commit, an outbox pattern (PostgreSQL `LISTEN/NOTIFY` or transactional outbox table consumed by a Redis-update worker) propagates the new stamp to Redis via SETEX. **Safety TTL of 30 seconds** on Redis entries — only as a backstop for Redis-vs-DB inconsistency (network partition between Redis worker and Redis cluster, Redis eviction, Redis restart). The 30s TTL does NOT cover write-to-invalidation lag because invalidation is in-transaction. **Fail-closed-on-write:** for any regulated WRITE action, the gate MUST verify the DB `version_stamp` before permitting the action. If the DB `version_stamp` cannot be verified (DB unreachable, query failed), the write is rejected with `LICENSE_CACHE_VERSION_VERIFICATION_FAILED` (HTTP 503). The gate NEVER permits a regulated write based solely on a Redis hit. **Read-side decisions** may be served from Redis hits when the cached `version_stamp` matches the latest DB stamp; if the cached stamp is older than the DB stamp, the entry is stale and re-evaluation is forced. Latency budget: p95 ≤ 2ms cache hit + DB stamp verify; p95 ≤ 20ms cache miss; p95 ≤ 1ms per-request memoisation hit. |
| DEC-36-28 | **Tier change → URS-13 CR + regulatory-impact assessment.** Every tier change is a URS-13 record with: business justification, financial impact (ARR delta, currency, effective date), contractual amendment doc (URS-12 `subscription_amendment`), customer signatory + Verixa signatory e-sig, module-entitlement diff, seat-ceiling diff. Downgrade with entitlement decrease requires regulatory-impact assessment (potential GxP coverage gap); if in-flight regulated records depend on disabled modules, downgrade is blocked with `TIER_DOWNGRADE_IN_FLIGHT_WORKFLOW_BLOCK`. |
| DEC-36-29 | **Isolation-model change → URS-13 CR + migration plan.** Every isolation-model change (e.g., Option B → Option C upgrade) is a URS-13 record with migration plan (URS-12 `isolation_change_plan` doc), downtime window, `isolation_model_admin_authority` (Verixa) + `executive_authority` (customer) dual e-sig, data-region validation, KMS rebinding plan, backup-policy re-binding plan, post-migration validation evidence. Isolation downgrade on a `validated_production` subscription requires regulatory-impact assessment. |
| DEC-36-30 | **SoD additions to URS-05 catalogue.** SOD-36-01: `subscription_admin_authority` ∩ `billing_admin_authority` = ∅. SOD-36-02: License assigner ≠ License revoker per `license_assignments.assigned_by_user_id` ≠ `revoked_by_user_id`. SOD-36-03: Customer admin cannot self-assign Authority-Profile-tied seat. SOD-36-04: Verixa platform admin cannot self-approve subscription modification (dual-approval required). SOD-36-05: `subscription_admin_authority` cannot also be `executive_authority` for the customer they manage. SOD-36-06: `inspection_grantor_authority` (customer-side, pre-authorized for break-glass) MUST be a distinct user from `contract_signatory_authority` (customer-side) — break-glass grant cannot be made by the user who signed the contract. SOD-36-07: `compliance_hold_authority` ∩ `subscription_admin_authority` = ∅ (compliance hold is legal/regulatory, not commercial). |
| DEC-36-31 | **Reason-for-Change mandatory** on every license-state-changing action: tier change, entitlement toggle, seat re-allocation, license assignment, license revocation, contract amendment, grace-period extension, inspection override, isolation change, environment-class change, data-region change, KMS rotation, manual subscription state transition. Missing reason → 400 `REASON_REQUIRED`. |
| DEC-36-32 | **Termination cascade per tenant_environment.** Ordered steps: (1) revoke all active license assignments → `archived`; (2) suspend all sessions for the tenant_environment's users (URS-01 hook); (3) suspend integrations (URS-30 outbound channels paused); (4) freeze writes (URS-08 freeze flag); (5) issue final invoice + payment reconciliation; (6) initiate retention-period read-only transition with effective-from = termination_date + 1 day; (7) seal append-only audit snapshot (URS-06 `HASH_CHAIN_SEAL_TERMINATION` event); (8) migration to cold storage per URS-35. Ordered execution; no step may be skipped. |
| DEC-36-33 | **Renewal cadence.** 90 / 60 / 30 / 15 / 3 / 1 day URS-30 reminders before `effective_to`. 30 days before: `active → renewing`. Auto-renewal flag (`auto_renew`) per subscription; default `false` for Enterprise + Custom; default `true` for Starter + Pro (with 30-day opt-out window). On counter-signature + payment: state returns to `active` with new `effective_from` / `effective_to`. On non-renewal at `effective_to`: grace-period begins (DEC-36-13). |
| DEC-36-34 | **Multi-year contracts.** A subscription may have a contract term of up to 5 years (URS-13 CR for extensions beyond default 1-year). Multi-year contracts carry billing schedule (annual / semi-annual / quarterly / monthly) recorded in `subscriptions.billing_schedule`. Multi-year discount logic recorded in `plans.multi_year_discount_jsonb`. |
| DEC-36-35 | **Tier-aware feature flags.** Each module may declare feature flags conditional on tier (e.g., `mira_advanced_reasoning` requires `enterprise` or `custom`; `multi_jurisdiction_export` requires `pro` or higher). Feature flags evaluated at the License Gate; rejected actions return `LICENSE_TIER_INSUFFICIENT`. Feature flags recorded in `module_entitlements.feature_flags_jsonb`. |
| DEC-36-36 | **Migration version mismatch blocks regulated writes per tenant_environment.** If `tenant_environments.migration_version` ≠ platform version on a regulated-write attempt, gate rejects with `MIGRATION_VERSION_MISMATCH` (HTTP 503) until tenant_environment migration completes. Read access continues unimpeded. |
| DEC-36-37 | **Tenant + tenant_environment + initial subscription atomic create.** `POST /customer-accounts` may bootstrap initial tenant_environment + initial subscription atomically. Subsequent `POST /tenant-environments/by-customer/:caid` adds environments. Subsequent `POST /subscriptions/by-environment/:teid` adds subscriptions to existing environments. Provisioning runs asynchronously; subscription cannot transition to `active` until parent tenant_environment is `provisioning_status = active` AND `validation_status = validated`. |
| DEC-36-38 | **Workflow dependency declaration (DEC-36-14 support).** Platform configuration table `workflow_dependency_declarations` with rows `(parent_module_id, parent_state, permitted_child_module_id, permitted_child_actions_jsonb, causal_reason_required: bool, effective_from, effective_to, source_change_control_id, created_e_sig_id)`. Versioned; super_admin + URS-13 CR controlled. Examples at launch: `(URS-23, qp_certification_in_progress) → URS-16 deviation create`; `(URS-15, phase_ia) → URS-16 deviation create`; `(URS-27, recall_in_execution) → URS-14 complaint create + URS-16 deviation create`; `(URS-22, back_room_active) → URS-21 finding create`. |

---

## 4. Roles & Authority Profiles

New Authority Profiles to be registered in the URS-05 catalogue (16 total):

| Authority Profile | Scope | Purpose |
|---|---|---|
| `super_admin` (existing role) | Verixa-internal | Plan catalogue, isolation model catalogue, permissibility map, module entitlement schema. |
| `platform_admin` (existing role) | Verixa-internal | Subscription provisioning; channel partner config; tax + currency config. |
| `subscription_admin_authority` | Verixa-internal | Create/amend subscriptions; tier change; seat ceiling change; entitlement toggle (with URS-13 CR). **Mutually exclusive with `billing_admin_authority`** per SOD-36-01. |
| `billing_admin_authority` | Verixa-internal | Issue invoices; post payments; process refunds; execute dunning. **Mutually exclusive with `subscription_admin_authority`** per SOD-36-01. |
| `entitlement_admin_authority` | Verixa-internal | Toggle module entitlements (with URS-13 CR). |
| `isolation_model_admin_authority` | Verixa-internal | Change tenant_environment isolation_model (with URS-13 CR + migration plan); manage Plan ↔ Isolation Permissibility Map. |
| `tenant_provisioning_authority` | Verixa-internal | Execute tenant_environment provisioning state machine; run migrations per schema / per DB; bind backup policies; bind KMS keys; configure data-region routing. |
| `data_region_admin_authority` | Verixa-internal | Change data region (with URS-13 CR + migration plan); validate jurisdictional bindings. |
| `kms_key_admin_authority` | Verixa-internal | Bind / rotate / change KMS key mode and ref. |
| `inspection_mode_override_authority` | Verixa-internal | Grant planned inspection-mode override per DEC-36-16 (with `executive_authority` customer co-sign). |
| `contract_signatory_authority` (Verixa-side) | Verixa-internal | Sign subscription contracts on Verixa's behalf. |
| `contract_signatory_authority` (Customer-side) | Customer-side | Sign subscription contracts on customer's behalf (typically customer CFO or COO). |
| `customer_account_admin_authority` | Customer-side | Customer's account-level admin for the parent `customer_accounts` row — manages MSA, billing rollup, channel-partner relationship. Distinct from per-environment customer admin. |
| `tenant_environment_admin_authority` | Customer-side | Per-environment customer admin — assigns licenses within the environment's subscription, manages users for that environment. Per-environment scoped. |
| `license_assignment_authority` | Customer-side | Assigns named-user licenses within the seat ceiling. Delegable from `customer_account_admin_authority` or `tenant_environment_admin_authority` with time bounds. |
| `license_revocation_authority` | Customer-side | Revokes / suspends named-user licenses. **SoD: revoker ≠ assigner** per SOD-36-02. |
| `finance_review_authority` | Verixa-internal | Financial sign-off on tier changes, refunds, write-offs, late renewal, pricing concessions. |
| `inspection_grantor_authority` | Customer-side | Pre-authorized customer-side user permitted to invoke DEC-36-15-EMG break-glass emergency inspector grants. Distinct from contract_signatory_authority per SOD-36-06. Typically the customer's QA Head or Site Head. Not delegable. |
| `compliance_hold_authority` | Verixa-internal | Authorizes compliance holds (sanctions / regulatory order / legal hold). Mutually exclusive with subscription_admin_authority per SOD-36-07. Requires Verixa Legal Counsel + Executive co-sign for permanent holds. Not delegable. |
| `executive_authority` (existing) | Customer-side | Founder approval for: high-value contract amendments above ARR threshold; late renewal exits from expired_read_only; on-premise deployment approvals; inspection-mode override co-sign. |
| `inspector_authority` (existing) | Regulator / Inspector | Read-only access scoped per DEC-36-15 / DEC-36-15-EMG / DEC-36-16; never seat-counted; never tenant-isolation-bypassing. |

SoD constraints (additions to URS-05 SoD set; canonical list per DEC-36-30):

- SOD-36-01: `subscription_admin_authority` ∩ `billing_admin_authority` = ∅
- SOD-36-02: License assigner ≠ License revoker (`license_assignments.assigned_by_user_id` ≠ `revoked_by_user_id`)
- SOD-36-03: Customer admin cannot self-assign Authority-Profile-tied seat
- SOD-36-04: Verixa platform admin cannot self-approve subscription modification (dual-approval required)
- SOD-36-05: `subscription_admin_authority` cannot also be `executive_authority` for the customer they manage
- SOD-36-06: `inspection_grantor_authority` (customer-side) ≠ `contract_signatory_authority` (customer-side) — break-glass cannot be granted by the contract signatory
- SOD-36-07: `compliance_hold_authority` ∩ `subscription_admin_authority` = ∅

---

## 5. Worked Examples

### 5.1 Worked Example A — Customer onboard with production + test + sandbox environments

**Scenario.** Aeonn Health onboards. Three environments needed: `aeonn-prod` (validated_production), `aeonn-test` (validated_test), `aeonn-sandbox` (sandbox).

**Sequence.**
1. `POST /api/v1/customer-accounts` creates `customer_account` `CA-2026-0041` (parent commercial entity).
2. `POST /api/v1/tenant-environments/by-customer/CA-2026-0041` creates three tenant_environments: `aeonn-prod`, `aeonn-test`, `aeonn-sandbox`. Each with its own `isolation_model` (Option B for prod; Option B for test; Option B for sandbox — all per Permissibility Map for Enterprise plan), `data_region = ap-south-1`, `kms_key_mode = shared_platform_key`, distinct `tenant_schema` per environment.
3. Provisioning runs in parallel for the three environments. Each runs `CREATE SCHEMA tenant_aeonn_prod` / `tenant_aeonn_test` / `tenant_aeonn_sandbox`, applies migrations, binds audit, configures backup, binds KMS, configures routing.
4. Validation pack runs per environment. `aeonn-prod` requires full IQ/OQ/PQ — takes longer. `aeonn-test` requires reduced validation. `aeonn-sandbox` skips validation (no GxP records).
5. As each environment reaches `provisioning_status = active` AND `validation_status >= validated` (for validated_* classes), its subscription can transition `draft → quote_pending → active`.
6. `aeonn-prod` activates first under Subscription `SUB-2026-0041-PROD` (Enterprise plan, 200 general + 12 QP seats, validated_production, INR currency).
7. `aeonn-test` activates under Subscription `SUB-2026-0041-TEST` (Pro plan, 50 seats, validated_test, INR, $50K/year).
8. `aeonn-sandbox` activates under Subscription `SUB-2026-0041-SBX` (Starter trial, 10 seats, sandbox, no charge for 90 days).
9. Customer-level consolidated invoice rolls up at `CA-2026-0041` level.
10. Anand attempts to create a deviation in production. Pipeline (per §0.5): authenticate → environmentScope (`X-Env-Id: aeonn-prod` resolved → tenant_environment_id) → tenantScope (`SET search_path = tenant_aeonn_prod`) → context → RBAC → License Gate (subscription SUB-PROD active ✓, env validated_production ✓, named-user license active ✓, URS-16 module entitled ✓) → handler.

### 5.2 Worked Example B — Causally-linked child workflow under Shield

**Scenario.** Aeonn `aeonn-prod` subscription is in `shielded_expiry_pending`. Priya is in QP release of Batch VRX-25-A-00417. During final review she discovers an unrecorded deviation in the IPC log.

**Sequence.**
1. Priya invokes `POST /api/v1/deviations` with `parent_workflow_id = batch_VRX-25-A-00417_qp_release`, `causal_reason = unrecorded_ipc_deviation_during_qp_review`.
2. License Gate evaluates: env = `aeonn-prod`, subscription state = `shielded_expiry_pending`, action = URS-16 create.
3. Shield consults `workflow_dependency_declarations`: finds `(URS-23, qp_certification_in_progress) → URS-16 deviation create` permitted with `causal_reason_required = true`. Causal reason supplied.
4. Shield verifies parent workflow is active and in declared state: `batch_VRX-25-A-00417` is in `qp_certification_in_progress`. ✓
5. Child deviation created with `inherited_shield_id` linking to parent's shield context. URS-06 audit emitted.
6. If Priya attempted to create a deviation NOT linked to the batch (a new unrelated investigation), Shield would reject with `SHIELDED_NEW_INDEPENDENT_WORKFLOW_BLOCKED`.

### 5.3 Worked Example C — Emergency inspector access (break-glass)

**Scenario.** Unannounced MHRA inspector arrives at Aeonn Hyderabad. Aeonn QA Head is the pre-authorized `inspection_grantor_authority` (and is distinct from the contract signatory Aeonn CFO).

**Sequence.**
1. QA Head invokes `POST /api/v1/emergency-inspection-grants` with: regulator_name = `Dr. James Whitaker`, agency = `MHRA`, agency_reference_id = `MHRA-INS-2026-0142`, credential_evidence_url = `s3://aeonn-attachments/2026/inspector-badge.jpg`, inspection_purpose = `unannounced GMP inspection Hyderabad`.
2. URS-04 e-sig captured. URS-06 audit emitted.
3. Inspector account `inspector-mhra-0142` created bound to `inspector_authority`, scoped to tenant_environment `aeonn-prod`, read-only, state = `active_unbound`, 72-hour absolute expiry.
4. URS-30 notification dispatched (within 5 minutes): customer_account `executive_authority` (Vimal), Verixa platform admin, RA Head, Founder.
5. Inspector logs in immediately. Every read URS-06 audited.
6. **Escalation timeline (per DEC-36-15-EMG; access is never auto-revoked at 24h or 48h):**
   - **0–24h:** QA Head expected to create the URS-22 inspection context and bind `inspector-mhra-0142`. If bound: state → `bound_to_urs_22`; access continues to 72h absolute expiry.
   - **24h reached unbound:** state → `binding_overdue_escalated`; access CONTINUES; URS-30 escalation dispatched to Verixa platform admin + customer_account_admin + Founder. (Scenario covers Friday-afternoon and weekend cases where QA Head is unavailable.)
   - **48h reached unbound:** Verixa platform admin MAY (with URS-04 e-sig) auto-create a placeholder URS-22 context (`urs_22_placeholder_reason = emergency_grant_binding_overdue_48h`) and bind the inspector to it; state → `placeholder_bound`; access continues.
   - **72h absolute expiry:** access auto-revokes unconditionally; state → `expired`. Longer-term access requires conversion to planned override (DEC-36-16) with its own dual-approval requirement and a normal URS-22 inspection context.
7. Manual revoke remains available at any point to `inspection_grantor_authority` or Verixa platform admin.

### 5.4 Worked Example D — Fast-path dunning (chargeback)

**Scenario.** Aeonn's Stripe webhook reports a chargeback on Invoice `INV-2026-0041-H2`.

**Sequence.**
1. Stripe webhook arrives. `billing_events` row created with `provider_event_id = ch_xxx`, `event_type = chargeback`.
2. Adapter validates signature. `billing_events.status = validated`.
3. Subscription service consumes event. Detects `event_type = chargeback` → fast-path commercial hold per DEC-36-25(b).
4. Action: `subscription_on_hold` transition queued. Verixa CFO (`finance_review_authority`) + Verixa executive (`executive_authority`) confirmation required (dual e-sig).
5. On confirmation: subscription state `active → subscription_on_hold`. Mid-Workflow Shield activates: in-flight critical workflows continue under Shield; new independent workflows blocked.
6. URS-30 notifications: Aeonn customer_account_admin + Verixa account manager.
7. Cure: chargeback reversal + payment received → subscription_on_hold → active.

### 5.5 Worked Example E — Compliance hold (sanctions)

**Scenario.** US OFAC adds a parent company to the sanctioned-entity list; Aeonn is identified as a subsidiary.

**Sequence.**
1. `compliance_hold_authority` (Verixa Legal + Executive) invokes `POST /api/v1/compliance-holds` with `hold_type = sanctions_violation`, `severity = permanent_hold` (writes blocked + reads only via inspection/legal channels), `legal_basis_document_id` (URS-12), `tenant_environments_affected = [aeonn-prod, aeonn-test, aeonn-sandbox]`.
2. URS-04 dual e-sig (Legal + Executive). URS-06 audit.
3. All three affected subscriptions transition to `subscription_on_hold` with `hold_class = compliance_permanent`. Mid-Workflow Shield still applies for graceful in-flight workflow completion.
4. Customer's regulated writes blocked. Reads only permitted via planned inspection-mode override (DEC-36-16) for legal/regulatory parties.
5. Cure: NOT possible from customer-side. Hold released only by Verixa Legal + Executive + URS-13 CR with legal-basis-of-release document. On release: subscriptions return to prior state.

---

## 6. State Machines

### 6.1 Subscription Lifecycle

```
draft
   ↓ submit_quote
quote_pending
   ↓ countersign (customer)
   ↓ countersign (verixa)
active
   ↓ renewal_triggered (90d before effective_to)
renewing
   ↓ renewal_signed → active (new term)
   ↓ renewal_lapsed → grace_period
   ↓ on_hold_triggered (routine_dunning_day_21 | fast_path_commercial | compliance_hold) → subscription_on_hold
subscription_on_hold
   ↓ cure_payment_received → active
   ↓ cure_legal_release → active (for compliance holds; URS-13 CR)
   ↓ on_hold_lapsed_to_grace → grace_period
   ↓ on_hold_lapsed_to_expired (rare; only if shield permits) → expired_read_only
grace_period
   ↓ late_renewal_signed → active
   ↓ grace_lapsed (in-flight workflows) → shielded_expiry_pending
   ↓ grace_lapsed (no in-flight) → expired_read_only
shielded_expiry_pending
   ↓ all_in_flight_completed → expired_read_only
   ↓ late_renewal_signed → active
expired_read_only
   ↓ late_renewal_signed (executive + finance_review) → active
   ↓ termination_triggered (URS-13 CR) → terminated
terminated
   ↓ retention_period_begin → retention_read_only (URS-35 cold storage)
   ↓ retention_period_end → archived_sealed
```

### 6.2 Tenant Environment Provisioning State

```
pending
   ↓ start_provisioning (tenant_provisioning_authority)
provisioning
   ↓ provisioning_completed → provisioned
   ↓ provisioning_failed → provisioning_failed
provisioned
   ↓ validation_pack_started → validation_pending
validation_pending
   ↓ validation_passed → active
   ↓ validation_failed → provisioning_failed
provisioning_failed
   ↓ remediation_complete → pending (retry)
   ↓ abandon → decommissioned
active
   ↓ decommission_triggered → decommissioned
decommissioned (terminal)
```

### 6.3 License-Assignment Lifecycle (per DEC-36-12)

```
unassigned
   ↓ assign (license_assignment_authority + e-sig)
assigned
   ↓ user_first_login → active
   ↓ rescind_before_login → unassigned
active
   ↓ suspend (license_revocation_authority + e-sig; SoD: revoker ≠ assigner)
suspended
   ↓ reinstate → active
   ↓ revoke → revoked
   ↓ revoke (license_revocation_authority + e-sig; SoD) [from active]
revoked
   ↓ reassign_seat → reassigned (new user)
   ↓ archive → archived
reassigned
   ↓ becomes_active → active
archived (terminal)
```

### 6.4 Invoice Lifecycle

```
draft → issued → (paid | overdue) → reconciled | written_off | refunded
```

### 6.5 Billing Event Lifecycle (per DEC-36-23)

```
received → validated → reconciled → action_pending → action_applied
```

`action_applied` may emit `dunning_events` rows or trigger compliance-hold review; it never directly mutates subscription state — the subscription service consumes `action_pending` events via controlled rules per DEC-36-23.

### 6.6 Compliance Hold State Machine

```
proposed (compliance_hold_authority)
   ↓ legal_evidence_attached + dual_e_sig (Legal + Executive)
active_temporary_hold
   ↓ legal_release (URS-13 CR; Legal + Executive) → released
   ↓ severity_escalation → active_permanent_hold
   ↓ severity_escalation → active_full_lockout

active_permanent_hold
   ↓ legal_release (URS-13 CR; Legal + Executive) → released

active_full_lockout (terminal-until-released)
   ↓ legal_release (URS-13 CR; Legal + Executive; jurisdictional approval) → released

released (terminal)
```

---

## 7. Data Model

### 7.1 Canonical Tables

| Table | Purpose | Core columns | Uniqueness | Lifecycle | Retention | Indexed |
|---|---|---|---|---|---|---|
| `customer_accounts` | Commercial parent entity | `id`, `customer_legal_name`, `display_name`, `parent_company_jsonb`, `commercial_msa_document_id` (FK URS-12), `consolidated_billing_currency`, `channel_partner_id` (nullable), `account_admin_authority_user_id`, `effective_from`, `effective_to` (nullable), `created_e_sig_id` | unique(`id`) | versioned | retain (long-term) | yes |
| `tenant_environments` | Per-environment isolation + provisioning. **Multiple environments per `environment_class` permitted** (e.g., a large customer may run `aeonn-prod-hyd` + `aeonn-prod-pune` both as `validated_production` for different sites). | `id`, `customer_account_id` (FK), `tenant_id` (FK URS-08), `environment_slug` (e.g., `aeonn-prod-hyd`; unique per customer_account), `environment_class` (`validated_production`/`validated_test`/`sandbox`/`demo`), `isolation_model`, `tenant_schema` (nullable; populated for B/B+/D-shared), `db_instance_ref` (nullable; populated for C/D-dedicated), `data_region`, `kms_key_mode`, `kms_key_ref`, `backup_policy_ref`, `tenant_environment_provisioning_status` (per §6.2), `migration_version`, `validation_status`, `retention_years`, **`default_grace_period_days`** (tenant-environment-level administrative default per DEC-36-13; min 14 / default 30 / max 90), `created_e_sig_id` | unique(`customer_account_id`, `environment_slug`) — environment_class is NOT in the unique constraint, permitting multiple environments of the same class | stateful | retain (long-term) | yes |
| `subscriptions` | Per-environment per-term contract | `id`, `tenant_environment_id` (FK), `plan_id` (FK), `commercial_plan`, `state` (DEC-36-11), `effective_from`, `effective_to`, `currency`, `billing_schedule`, `auto_renew`, `seat_ceiling_general`, `seat_ceiling_authority_jsonb`, `cap_policy_jsonb`, `jurisdictions_jsonb`, **`grace_period_days_snapshot`** (snapshot of `tenant_environments.default_grace_period_days` taken at subscription activation; this is the authoritative value for the active contract term per DEC-36-13), `superseded_by_id`, `created_e_sig_id`, `customer_signatory_e_sig_id`, `verixa_signatory_e_sig_id` | PostgreSQL exclusion constraint: `EXCLUDE USING gist (tenant_environment_id WITH =, tstzrange(effective_from, effective_to) WITH &&)` filtered to active subscription states — no overlapping active contract date ranges per tenant_environment | versioned | retain (long-term) | yes |
| `plans` | Verixa-global commercial plan catalogue | `id`, `commercial_plan` (`starter`/`pro`/`enterprise`/`custom`), `default_module_set_jsonb`, `default_seat_ceiling`, `default_authority_seats_jsonb`, `default_cap_policy_jsonb`, `default_environment_class_options_jsonb`, `pricing_jsonb`, `multi_year_discount_jsonb`, `effective_from`, `effective_to`, `created_e_sig_id` | unique(`id`) | versioned | retain (long-term) | yes |
| `plan_isolation_permissibility` | Plan ↔ Isolation Permissibility Map per DEC-36-03 | `id`, `commercial_plan`, `isolation_model`, `permitted` (bool), `environment_class_constraint_jsonb`, `effective_from`, `effective_to`, `source_change_control_id`, `created_e_sig_id` | unique active(`commercial_plan`, `isolation_model`) | versioned | retain (long-term) | yes |
| `module_entitlements` | Per-subscription per-module on/off | `id`, `subscription_id` (FK), `module_id`, `enabled`, `effective_from`, `effective_to`, `tier_required` (nullable), `feature_flags_jsonb`, `source_change_control_id`, `created_e_sig_id` | unique active(`subscription_id`, `module_id`) | versioned | retain (long-term) | yes |
| `seat_allocations` | Seat ceiling vs consumption per seat_class | `id`, `subscription_id` (FK), `seat_class`, `ceiling`, `consumed`, `soft_cap_threshold`, `hard_cap_threshold`, `last_recomputed_at` | unique(`subscription_id`, `seat_class`) | computed | retain (long-term) | yes |
| `license_assignments` | Per-user license assignment | `id`, `subscription_id` (FK), `user_id` (FK URS-02), `seat_class`, `module_scope_jsonb`, `state` (DEC-36-12), `assigned_by_user_id`, `assigned_e_sig_id`, `revoked_by_user_id` (SoD: ≠ assigner), `revoked_e_sig_id`, `assigned_at`, `revoked_at`, `reassigned_from_id` (nullable) | unique active(`subscription_id`, `user_id`, `seat_class`) | stateful | retain (long-term) | yes |
| `usage_records` | Immutable per-event usage capture | `id`, `subscription_id` (FK), `event_type` (`api_call`/`ai_inference`/`audit_event_write`/`storage_gb_hour`/`batch_record_released`/`document_uploaded`/`regulated_record_created`), `event_count`, `event_metadata_jsonb`, `event_timestamp`, `roll_up_period` | append-only | append-only | retain (cold after 24mo) | yes |
| `invoices` | Per-period invoice | `id`, `subscription_id` (FK), `period_from`, `period_to`, `state` (per §6.4), `subtotal`, `tax_jsonb`, `total`, `currency`, `fx_rate_locked`, `due_at`, `paid_at` (nullable), `provider_invoice_id`, `issued_e_sig_id` | unique(`subscription_id`, `period_from`) | stateful | retain (long-term) | yes |
| `payments` | Per-payment record | `id`, `invoice_id` (FK), `amount`, `currency`, `payment_method`, `provider_payment_id`, `received_at`, `posted_e_sig_id` | unique(`provider_payment_id`) | append-only | retain (long-term) | yes |
| `dunning_events` | Dunning step register | `id`, `invoice_id` (FK), `step` (per DEC-36-25), `triggered_at`, `urs_30_event_id`, `escalation_chain_jsonb` | append-only | append-only | retain (long-term) | yes |
| `channel_partners` | Reseller / SI registry | `id`, `partner_name`, `partner_type`, `discount_terms_jsonb`, `registration_doc_id` (FK URS-12), `effective_from`, `effective_to`, `created_e_sig_id` | unique(`id`) | versioned | retain (long-term) | yes |
| `tax_rates` | Per-jurisdiction tax rate cache | `id`, `jurisdiction`, `rate_type` (`gst`/`vat`/`sales_tax`/`sut`), `rate_pct`, `effective_from`, `effective_to`, `source_provider` | unique(`jurisdiction`, `rate_type`, `effective_from`) | versioned | retain (long-term) | yes |
| `fx_rates` | FX rate lock-on-issue | `id`, `from_currency`, `to_currency`, `rate`, `effective_on` | unique(`from_currency`, `to_currency`, `effective_on`) | append-only | retain (long-term) | yes |
| `license_audit_events` | Append-only license-event shadow (canonical in URS-06) | mirrors URS-06 with `event_class = licensing` | append-only | append-only | retain (long-term) | yes |
| `billing_events` | Provider event queue with fast-path classification | `id`, `subscription_id`, `provider`, `provider_event_id`, `event_type`, `fast_path_classification` (nullable: `chargeback`/`fraud_flag`/`contractual_rescission`/`bankruptcy_declared`/`sanctions_referral`/null=routine), `payload_jsonb`, `status` (DEC-36-23), `received_at`, `validated_at`, `reconciled_at`, `action_applied_at` | unique(`provider`, `provider_event_id`) | stateful | retain (long-term) | yes |
| `compliance_holds` | Compliance hold registry | `id`, `tenant_environments_affected_jsonb` (array of tenant_environment_ids), `hold_type` (`sanctions_violation`/`regulatory_order`/`legal_hold_order`), `severity` (`temporary_hold`/`permanent_hold`/`full_lockout`), `disclosure_class` (`full_disclosure`/`restricted_disclosure`/`internal_only`/`legal_counsel_only`/`restricted_pending_legal_review`), `disclosure_classified_at` (nullable; populated when Legal classifies `restricted_pending_legal_review` into a concrete class), `disclosure_classified_by_user_id` (nullable), `state` (per §6.4), `legal_basis_document_id` (FK URS-12), `proposed_by_user_id`, `legal_co_sign_e_sig_id`, `executive_co_sign_e_sig_id`, `effective_from`, `released_at` (nullable), `release_legal_basis_document_id` (nullable), `release_e_sig_id` (nullable) | unique(`id`) | stateful | retain (long-term) | yes |
| `emergency_inspection_grants` | Break-glass inspector access registry | `id`, `tenant_environment_id` (FK), `inspector_user_id` (FK URS-02; created at grant time), `grantor_user_id` (FK; bound to `inspection_grantor_authority`), `regulator_name`, `agency`, `agency_reference_id`, `credential_evidence_url`, `inspection_purpose`, `granted_at`, `escalation_at_24h` (= granted_at + 24h), `placeholder_eligible_at_48h` (= granted_at + 48h), `absolute_expiry_at_72h` (= granted_at + 72h), `state` (`active_unbound` / `binding_overdue_escalated` / `placeholder_bound` / `bound_to_urs_22` / `expired` / `revoked`), `urs_22_inspection_context_id` (nullable; populated when bound — either by `inspection_grantor_authority` within 24h or by platform admin via placeholder at 48h), `urs_22_placeholder_reason` (nullable; populated only when placeholder context auto-created at 48h), `urs_22_bound_at` (nullable), `urs_22_placeholder_created_by_platform_admin_id` (nullable; populated only for 48h placeholder), `urs_22_placeholder_e_sig_id` (nullable), `revoked_at` (nullable), `revocation_reason` (`72h_absolute_expiry` / `manual_revoke` / `escalated_to_planned_override`), `granted_e_sig_id` | unique(`id`) | stateful | retain (long-term) | yes |
| `inspection_mode_overrides` | Planned inspection override (DEC-36-16) | `id`, `tenant_environment_id` (FK), `inspector_user_id` (FK URS-02), `inspection_context_id` (FK URS-22; pre-bound), `granted_by_platform_admin_id`, `customer_co_sign_e_sig_id` (executive_authority customer-side), `verixa_co_sign_e_sig_id` (inspection_mode_override_authority), `effective_from`, `effective_to` (default = effective_from + 14 days; renewable via URS-13 CR), `scope_jsonb`, `revoked_at` (nullable), `revocation_reason` (nullable) | unique(`id`) | stateful | retain (long-term) | yes |
| `workflow_dependency_declarations` | DEC-36-38 platform configuration | `id`, `parent_module_id`, `parent_state`, `permitted_child_module_id`, `permitted_child_actions_jsonb`, `causal_reason_required`, `max_depth_permitted` (default 3 per DEC-36-14), `effective_from`, `effective_to`, `source_change_control_id`, `created_e_sig_id` | unique active(`parent_module_id`, `parent_state`, `permitted_child_module_id`) | versioned | retain (long-term) | yes |
| `workflow_shield_inheritance` | Per-child-workflow shield inheritance trail (supports DEC-36-14 transitive inheritance + cycle detection) | `id`, `child_workflow_id`, `child_module_id`, `parent_workflow_id`, `root_workflow_id`, `causal_reason`, `inherited_shield_id`, `shield_depth` (integer; 1..3 by default; >3 only with override fields populated below), `is_depth_override` (bool; default false; true only when `shield_depth > 3`), `override_source_change_control_id` (nullable; required when `is_depth_override = true`), `override_reason` (nullable; required when `is_depth_override = true`), `override_executive_e_sig_id` (nullable; required when `is_depth_override = true`), `override_final_quality_approver_e_sig_id` (nullable; required when `is_depth_override = true`), `created_at` | unique(`child_workflow_id`); CHECK constraint: `(shield_depth <= 3 AND is_depth_override = false) OR (shield_depth > 3 AND is_depth_override = true AND override_source_change_control_id IS NOT NULL AND override_reason IS NOT NULL AND override_executive_e_sig_id IS NOT NULL AND override_final_quality_approver_e_sig_id IS NOT NULL)` | append-only with cycle-detection check at insert | retain (long-term) | yes |
| `license_cache_versions` | Per-tenant_environment per-subscription version stamp — DB source of truth (DEC-36-27) | `tenant_environment_id`, `subscription_id`, `version_stamp` (bigint; monotonic), `last_bumped_at`, `last_bumped_by_event`, `last_bumped_in_transaction_id` | unique(`tenant_environment_id`, `subscription_id`) | computed (in-transaction bump on every state-changing write) | retain (last 30 days hot; rolling archive) | yes |
| `tenant_environment_provisioning_status` | Per-environment provisioning state machine row | One row per tenant_environment (or embedded in `tenant_environments`) | | | | | |

### 7.2 Isolation Routing (per ADR-004; per tenant_environment)

Per ADR-004 isolation model, routing is keyed on `tenant_environment_id`:
- Option B / B+ / D-shared-tier: `SET search_path = <tenant_environments.tenant_schema>, public` set on every connection via TDAL. `tenant_environments.tenant_schema` is the source of truth for routing.
- Option B+: PostgreSQL role per tenant_environment (`tenant_<env_slug>_role`) + RLS policy enabled on every table.
- Option C / D-dedicated-tier: per-tenant-environment dedicated RDS instance routed via `tenant_environments.db_instance_ref` (ARN).
- Option D (hybrid): at connection time, look up the tenant_environment's `isolation_model`; if `OPTION_C_DEDICATED_DB`, route to dedicated; else set `search_path` per Option B.

URS-36 control-plane tables live in platform schema; per-environment data tables live in the per-environment schema/DB.

---

## 8. API Endpoints

### 8.1 Customer Account + Environment + Subscription endpoints

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/customer-accounts` | `platform_admin` + `customer_account_admin_authority` (customer-side e-sig) |
| GET / PATCH | `/api/v1/customer-accounts/:id` | platform_admin / customer_account_admin_authority |
| POST | `/api/v1/tenant-environments/by-customer/:caid` | `platform_admin` + `tenant_provisioning_authority` |
| GET / PATCH | `/api/v1/tenant-environments/:id` | platform_admin / tenant_environment_admin_authority (per env) |
| POST | `/api/v1/tenant-environments/:id/provisioning/start` | `tenant_provisioning_authority` |
| POST | `/api/v1/tenant-environments/:id/provisioning/retry` | `tenant_provisioning_authority` |
| POST | `/api/v1/tenant-environments/:id/isolation-change` | `isolation_model_admin_authority` + URS-13 CR |
| POST | `/api/v1/tenant-environments/:id/environment-class-change` | `super_admin` + URS-13 CR |
| POST | `/api/v1/tenant-environments/:id/data-region-change` | `data_region_admin_authority` + URS-13 CR |
| POST | `/api/v1/tenant-environments/:id/kms-rotation` | `kms_key_admin_authority` + URS-13 CR |
| POST | `/api/v1/subscriptions/by-environment/:teid` | `subscription_admin_authority` |

### 8.2 Emergency Inspector + Compliance Hold endpoints

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/emergency-inspection-grants` | `inspection_grantor_authority` (customer-side; pre-authorized; SoD-36-06) |
| POST | `/api/v1/emergency-inspection-grants/:id/bind-urs-22-context` | `inspection_grantor_authority` or Verixa platform admin |
| POST | `/api/v1/emergency-inspection-grants/:id/revoke` | `inspection_grantor_authority` or Verixa platform admin |
| GET | `/api/v1/emergency-inspection-grants/by-environment/:teid` | tenant_environment_admin_authority |
| POST | `/api/v1/compliance-holds` | `compliance_hold_authority` (Verixa Legal + Executive dual e-sig) |
| POST | `/api/v1/compliance-holds/:id/release` | `compliance_hold_authority` + URS-13 CR + jurisdictional approval |

### 8.3 Workflow Dependency + License Gate endpoints

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/workflow-dependencies` | `super_admin` + URS-13 CR |
| GET | `/api/v1/workflow-dependencies` | service-to-service (Shield consults) |
| POST | `/api/v1/licensing/gate/check` | service-to-service |
| POST | `/api/v1/licensing/cache/redis-evict` | service-to-service. **Redis-only operational endpoint** for Redis warm/evict operations — used by the post-commit outbox worker to propagate the DB-side `license_cache_versions.version_stamp` to Redis, and for operational cache eviction during Redis maintenance. **This endpoint is NOT the source-of-truth invalidation mechanism**; correctness is enforced by DEC-36-27's in-transaction `license_cache_versions` row bump in the same DB transaction as the underlying write. Calling this endpoint without a corresponding DB version-stamp bump has no correctness effect. Idempotent. |
| POST | `/api/v1/licensing/cache/redis-warm` | service-to-service. Redis-only operational endpoint for pre-warming Redis entries from the current DB version stamps. Operational use only. |

### 8.4 All other endpoints

**Entitlement endpoints:**

| Method | Path | Authority |
|---|---|---|
| GET | `/api/v1/entitlements/by-subscription/:id` | customer admin / `entitlement_admin_authority` |
| POST | `/api/v1/entitlements/:id/toggle` | `entitlement_admin_authority` + URS-13 CR (e-sig) |

**License-assignment endpoints:**

| Method | Path | Authority |
|---|---|---|
| GET | `/api/v1/licenses/by-subscription/:id` | customer admin |
| POST | `/api/v1/licenses/assign` | `license_assignment_authority` (e-sig) |
| POST | `/api/v1/licenses/:id/revoke` | `license_revocation_authority` (SoD: distinct from assigner) |
| POST | `/api/v1/licenses/:id/reassign` | `license_assignment_authority` (e-sig) |
| POST | `/api/v1/licenses/:id/suspend` | `license_revocation_authority` (e-sig) |
| POST | `/api/v1/licenses/:id/reinstate` | `license_assignment_authority` (e-sig) |

**Billing + invoice + payment endpoints:**

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/billing/invoices` | `billing_admin_authority` (e-sig) |
| POST | `/api/v1/billing/invoices/:id/post-payment` | `billing_admin_authority` |
| POST | `/api/v1/billing/invoices/:id/refund` | `billing_admin_authority` + `finance_review_authority` co-sign |
| POST | `/api/v1/billing/invoices/:id/write-off` | `finance_review_authority` + `executive_authority` co-sign |
| POST | `/api/v1/billing/webhooks/:provider` | service-to-service (idempotency-keyed per DEC-36-23) |
| POST | `/api/v1/billing/dunning/:invoiceId/advance-step` | system / `billing_admin_authority` |

**Usage endpoints:**

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/usage/records` | service-to-service (batched) |
| GET | `/api/v1/usage/rollup/:subscriptionId` | customer admin / `subscription_admin_authority` |

**Planned inspection override endpoints:**

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/licensing/inspection-overrides` | `inspection_mode_override_authority` (Verixa) + `executive_authority` (customer) dual e-sig per DEC-36-16 |
| POST | `/api/v1/licensing/inspection-overrides/:id/revoke` | as above |
| GET | `/api/v1/licensing/inspection-overrides/by-environment/:teid` | customer admin |

**Channel partner + plan + tax endpoints:**

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/plans` | `super_admin` |
| POST | `/api/v1/channel-partners` | `platform_admin` |
| GET / POST | `/api/v1/tax-rates` | `platform_admin` |
| GET | `/api/v1/fx-rates` | service-to-service |
| POST | `/api/v1/plan-isolation-permissibility` | `super_admin` + URS-13 CR |

---

## 9. Frontend Surfaces

### 9.1 Customer-facing surfaces (under `/organization/*`)

- **Organization page** — read-only badge: organization name, environments list (with `environment_class` + region + status badge per env), tier, contract effective dates, deployment class. Replaces customer-facing `/tenants`. Platform-internal fields (`isolation_model`, `tenant_schema`, `db_instance_ref`, `kms_key_ref`) NOT shown.
- **License Allocations page (per environment)** — seat ceiling vs consumed by seat class; assign / revoke / reassign users; SoD-aware UI (revoke action disabled for the same user who assigned).
- **Subscription Status banner (per environment)** — license state (active / renewing / subscription_on_hold / grace_period / shielded_expiry_pending / expired_read_only / terminated); during grace shows days remaining + "Renew now" CTA. For hold states with `disclosure_class ∉ full_disclosure`, displays neutral "Subscription on hold — contact support" label per DEC-36-25.
- **Renewal page** — proposal preview, customer countersign, payment.
- **Module Entitlements page** — read-only view; "Request entitlement change" CTA opens URS-13 CR.
- **Invoices page (consolidated at customer_account)** — list of invoices across environments; status; payment posting; download CSV / PDF.
- **Usage page (per environment)** — current-period usage by event type; overage indicators; URS-30 preferences.

### 9.2 Verixa-internal surfaces (under `/admin/licensing/*`)

- **Customer Account Manager** — list customer_accounts; create new; bind channel_partner.
- **Tenant Environment Manager** — list environments per customer; provision new environment; isolation_model / data_region / kms_key change controls (each URS-13 CR-gated).
- **Subscription Manager** — list subscriptions per environment; create / countersign; tier change; amendment; renewal; late renewal; termination.
- **Plan Catalogue + Plan ↔ Isolation Permissibility Map editor** — super_admin only.
- **Tenant Environment Provisioning Console** — view + retry + remediation for `provisioning_failed`.
- **Isolation Migration Console** — orchestrate Option B → Option C upgrades.
- **Channel Partner Registry**.
- **Emergency Inspection Grant Console** + **Planned Inspection Override Console**.
- **Compliance Hold Console** (gated to `compliance_hold_authority`).
- **Workflow Dependency Declaration editor** (super_admin + URS-13 CR).
- **Dunning Console** — view dunning state across customers.
- **Tax / FX Manager**.
- **Usage Dashboard** — per-environment + customer_account rollup; revenue attribution; overage alerts.
- **License Gate Decision Inspector** — debug surface that replays a gate decision for a given userId / tenant_environment_id / moduleId / action; reads from `license_audit_events`.

### 9.3 Sandbox watermark (per DEC-36-07 / DEC-36-18)

When `tenant_environments.environment_class ∈ {sandbox, demo}`, every page renders a non-dismissable top-of-viewport banner: `SANDBOX — NOT FOR GxP USE. Records here are non-validated, test-data only.` Watermark also applied to every PDF / export artifact.

---

## 10. Cross-Module Integration

| Integration | Direction | Contract |
|---|---|---|
| URS-02 RBAC | URS-02 → URS-36 | After `requirePermission` passes, the route handler MUST call `requireLicense(tenant_environment_id, user_id, module_id, action)`. If license denied, route returns 422 / 423 / 503 with reason code per URS-36 §0.2. |
| URS-04 Workflow / E-Sig | URS-04 ↔ URS-36 | Every subscription / license / entitlement / isolation / environment / region / KMS / compliance-hold / inspection-grant state transition is performed via URS-04 Controlled Approval Modal with e-sig. Dual e-sig for tier change, isolation change, late renewal, planned override, write-off, termination, compliance hold proposal/release. |
| URS-05 Authority Profile / SoD | URS-05 → URS-36 | New Authority Profiles registered per §4. SoD-36-01..07 added to URS-05 SoD set. License assigner ≠ revoker. |
| URS-06 Audit | URS-36 → URS-06 | Every license event append-only audited per DEC-36-26. Hash-chain claim conditional on URS-06 implementation evidence. License-event audit write occurs in the same DB transaction as the underlying state-changing write and the `license_cache_versions` version-stamp bump per DEC-36-27. |
| URS-08 Tenant Lifecycle | URS-08 ↔ URS-36 | Tenant create flows through `POST /api/v1/customer-accounts` per DEC-36-37 (atomic customer_account + tenant_environment + initial subscription). Tenant suspension / termination cascades to DEC-36-32. |
| URS-12 Document Control | URS-36 → URS-12 | Contract docs (MSA / OF / Amendment / BYOC / On-Prem / Isolation-Change-Plan / Region-Change-Plan / KMS-Rotation-Plan / Legal-Basis-of-Hold) stored. |
| URS-13 Change Control | URS-36 → URS-13 | Every tier / entitlement / isolation / environment_class / region / KMS / contract amendment / late renewal / termination / compliance hold classification / compliance hold release / channel partner / plan permissibility / workflow dependency / shield depth override change generates a URS-13 CR. |
| URS-22 Inspection Management | URS-36 ↔ URS-22 | Two inbound binding paths: (a) emergency inspector grant (DEC-36-15-EMG); (b) planned inspection-mode override (DEC-36-16). URS-22 records both `urs_22_inspection_context_id ↔ emergency_inspection_grant_id` and `urs_22_inspection_context_id ↔ inspection_mode_override_id` bindings. Inspector actions during grant/override window are bound into the URS-22 inspection record. |
| URS-23 Batch Records | URS-23 → URS-36 | Shield queries URS-23 for in-flight batches in shield-eligible boundary states (`qp_certification_in_progress`, `staged_review_in_progress`, `final_disposition_pending`). |
| URS-27 Recall Management | URS-27 → URS-36 | Shield queries URS-27 for in-flight recall executions (`recall_in_execution`). |
| URS-28 Training Qualification Gate | URS-28 ↔ URS-36 | Authority-Profile-tied seat consumption requires URS-28 `qualified=true` for the relevant Authority Profile. License Gate consults URS-28 before authority-bound writes. |
| URS-30 Notifications | URS-36 → URS-30 | Renewal cadence (90/60/30/15/3/1d); grace; shield-extension; expiry; overage; routine dunning 3-step; fast-path commercial hold; compliance hold (with `disclosure_class` routing); planned inspection override; emergency inspector grant (24h/48h/72h checkpoints); tier / isolation / region / KMS changes; seat soft/hard cap. |
| URS-31 DQG | URS-31 → URS-36 | Shield queries URS-31 for in-flight DQG filings (`filing_in_flight`). |
| URS-35 Infrastructure | URS-35 ↔ URS-36 | Per-tenant_environment backup policy (`pg_dump -n` for B/B+/D-shared; PITR for C/D-dedicated); data-region routing; KMS binding; cold-storage migration on retention-period entry. |

---

## 11. Change-Impact Matrix (CIM)

| Change | Class | Impact | Revalidation |
|---|---|---|---|
| Add commercial plan tier | 1 | RBAC gate; every consumer module's gate | Full regression |
| Add isolation model option | 1 | TDAL; provisioning engine; every per-tenant query path | Full regression |
| Change Plan ↔ Isolation Permissibility map | 1 | URS-13 CR per affected customer | Full regression |
| Add environment_class option | 1 | License Gate; watermark engine; record_gxp_status enforcement | Full regression |
| Change License Gate API contract | 1 | Every consumer module | Full regression |
| Change Mid-Workflow Shield behaviour | 1 | Every shield-eligible regulated workflow module | Full regression |
| Change isolation model on existing tenant_environment | 1 (per env) | Per-environment migration; URS-13 CR | Full regression on that environment |
| Change data region on existing tenant_environment | 1 (per env) | Per-environment migration; URS-13 CR | Full regression on that environment |
| Change KMS key mode | 1 (per env) | Per-environment rotation; URS-13 CR | Full regression on that environment |
| Change tier default entitlement set | 2 | Per-affected-tenant URS-13 CR | Targeted regression |
| Change default seat ceiling | 2 | Per-affected-tenant URS-13 CR | Targeted regression |
| Change grace period default | 2 | URS-13 CR; URS-30 reminders | Targeted regression |
| Change dunning cadence | 2 | URS-30 templates; finance reporting | Targeted regression |
| Add tax jurisdiction / currency | 3 | tax_rates substrate; invoice generation | Unit regression |
| Add billing provider | 2 | Billing integration substrate | Targeted regression |
| Add channel partner | 3 | channel_partners registry | Unit regression |
| Three-entity model rollout (customer_account / tenant_environment / subscription) | 1 | Every API; every per-tenant query path; every customer-facing surface | Full regression |
| Add `subscription_on_hold` state | 1 | License Gate; Shield; URS-30 templates | Full regression |
| Add fast-path commercial hold | 2 | Dunning; URS-30 templates; finance reporting | Targeted regression |
| Add compliance hold path | 1 | License Gate; Shield; new compliance_holds module | Full regression |
| Add workflow_dependency_declarations | 1 | Shield; every shield-eligible parent workflow module | Full regression |
| Change License Cache strategy | 2 | License Gate; consumer modules; perf benchmarks | Targeted regression |
| Add emergency_inspection_grants module | 1 | URS-22; License Gate; URS-30; URS-06 | Full regression |
| Change inspection_grantor_authority binding | 1 | URS-05; SoD; customer onboarding flow | Full regression |

---

## 12. Risk Register

Risks and mitigations:

| Risk | Severity | Likelihood | Mitigation |
|---|---|---|---|
| Mid-batch lockout disrupts regulated workflow | High | Low (with Shield) | DEC-36-14 Mid-Workflow Continuity Shield; URS-30 alerts; grace-period minimum 14 days |
| Regulator blocked from accessing data during contract dispute | High | Low | DEC-36-15 regulator account exemption; DEC-36-15-EMG emergency break-glass; DEC-36-16 planned override; DEC-36-17 retention-period read-only |
| Seat ceiling raise lags behind business growth | Medium | Medium | DEC-36-10 soft-cap alert + auto URS-13 CR; URS-30 escalation |
| Sandbox subscription mis-classified as validated | High | Low | DEC-36-07 + DEC-36-18 environment_class enforcement + `record_gxp_status` + `test_data_flag` + non-dismissable watermark + write block |
| License-state cache stale → wrong gate decision | Medium | Very low | DEC-36-27 in-transaction version bump + post-commit Redis outbox + 30s safety TTL + fail-closed on DB-verify failure |
| Invoice issued in wrong currency / FX | Medium | Low | DEC-36-23 + DEC-36-24 currency + FX lock-on-issue |
| Channel partner discount applied incorrectly | Medium | Low | Plan-level discount logic; `finance_review_authority` sign-off on contract |
| Contract documents tampered post-signature | High | Very low | URS-12 immutable doc versions; URS-06 hash chain; e-sig replay block |
| Inspection-mode override extended without need | Medium | Low | DEC-36-16 14-day default; URS-13 CR for extension; URS-22 inspection-context binding |
| Tier-downgrade mid-cycle leaves regulated records orphaned | High | Low | DEC-36-29 regulatory-impact assessment; `TIER_DOWNGRADE_IN_FLIGHT_WORKFLOW_BLOCK` |
| Termination cascade leaves data exposed | High | Very low | DEC-36-32 strict ordered cascade; final `HASH_CHAIN_SEAL_TERMINATION` |
| Read-only-with-inspection-access mis-permits regulated write | High | Very low | License Gate fails closed; `SUBSCRIPTION_EXPIRED_READ_ONLY` on every write attempt; audit on each rejected attempt |
| Multi-currency reporting incorrect at consolidation | Medium | Medium | FX lock at invoice issue; consolidation report uses lock rates; quarterly FX reconciliation |
| Mid-renewal payment failure leaves customer in ambiguous state | Medium | Medium | DEC-36-25 dunning cadence; URS-30 escalation; `subscription_on_hold` state |
| Causally-linked child workflows misused to bypass shield (incl. deep chain abuse) | High | Low | DEC-36-14 + DEC-36-38 parent + root + causal_reason + shield_depth required; depth ≤ 3 hard-capped; cycle detection on insert; >3 requires URS-13 CR + executive + final_quality_approver co-sign |
| Emergency inspector grant abused (not a real inspector) | Critical | Low | DEC-36-15-EMG credential capture mandatory; URS-30 notification within 5 min to customer executive + Verixa platform admin + RA Head + Founder; URS-22 binding via escalation; absolute 72h max |
| Emergency inspector access blocked during Friday-afternoon / holiday inspections by mechanical 24h timer | Critical | Low | DEC-36-15-EMG escalation model: 24h escalation (not revoke); 48h placeholder; 72h absolute is the only hard expiry |
| Fast-path commercial hold mistakenly applied to routine failure | High | Low | DEC-36-25 classification on `billing_events.fast_path_classification`; CFO + finance_review dual e-sig confirmation required |
| Compliance hold blocked / delayed | Critical | Very low | DEC-36-25 distinct compliance_holds state machine + compliance_hold_authority separate from commercial; full_lockout reserved for extreme cases |
| Compliance hold disclosed to customer in violation of jurisdiction-specific legal restriction | High | Low | DEC-36-25 `disclosure_class` defaults route sanctions to `restricted_pending_legal_review`; 5-business-day Legal classification window; customer-facing state genericised to `subscription_on_hold_contact_support` for all restricted classes; Legal-controlled per-order classification |
| Spec overclaims legal certainty on sanctions disclosure prohibition | Medium | Low | DEC-36-25 explicitly states spec does NOT assert universal sanctions-non-disclosure rule; defaults are starting points only; Legal classification per-order required |
| License cache invalidation race window allows write on stale entitlement | Critical | Very low | DEC-36-27 in-transaction version bump; DB `license_cache_versions` is source of truth; Redis is replica only; fail-closed on DB-stamp-verify failure; 30s safety TTL only as Redis-vs-DB safety |
| Multi-environment customer confused about which env they are in | Medium | Medium | Mandatory environment badge in frontend header; environment-specific URL routing; explicit environment selection at login |

| Risk | Severity | Likelihood | Mitigation |
|---|---|---|---|
| Causally-linked child workflows misused to bypass shield (incl. deep chain abuse) | High | Low | DEC-36-14 + DEC-36-38: parent + root + causal_reason + shield_depth required; shield_depth ≤ 3 hard-capped; cycle detection on insert; >3 requires URS-13 CR + executive + final_quality_approver co-sign; every child workflow URS-06 audited with full inheritance trail |
| Emergency inspector grant abused (not a real inspector) | Critical | Low | DEC-36-15-EMG: credential capture (badge / agency ref ID) mandatory; URS-30 notification within 5 min to customer executive + Verixa platform admin + RA Head + Founder; URS-22 binding pursued via 24h escalation → 48h platform-admin placeholder → 72h absolute expiry; manual revoke available at any point |
| Emergency inspector access blocked during Friday-afternoon / holiday inspections by mechanical 24h timer | Critical | Low | DEC-36-15-EMG escalation model: at 24h URS-22 unbinding triggers ESCALATION (URS-30 to platform admin + customer admin + Founder), NOT revocation; at 48h platform admin may auto-bind to placeholder context; 72h absolute is the only hard expiry |
| Compliance hold disclosed to customer in violation of jurisdiction-specific legal restriction | High | Low | DEC-36-25 `disclosure_class` defaults route sanctions to `restricted_pending_legal_review` (NOT automatic `legal_counsel_only`); 5-business-day Legal classification window; customer-facing state genericised to `subscription_on_hold_contact_support` for all restricted classes; Legal-controlled per-order classification |
| Spec overclaims legal certainty on sanctions disclosure prohibition | Medium | Low | DEC-36-25 explicitly states spec does NOT assert universal sanctions-non-disclosure rule; defaults are starting points only; Legal classification per-order required |
| License cache invalidation race window allows write on stale entitlement | Critical | Very low | DEC-36-27 in-transaction version bump on every state-changing write; DB `license_cache_versions` is source of truth; Redis is replica only; post-commit outbox propagates stamp; regulated writes fail closed on DB-stamp-verify failure; 30s TTL only as Redis-vs-DB inconsistency safety |
| Fast-path commercial hold mistakenly applied to routine failure | High | Low | DEC-36-25: classification on `billing_events.fast_path_classification`; CFO + finance_review dual e-sig confirmation required before transition |
| Compliance hold blocked / delayed | Critical | Very low | DEC-36-25: distinct compliance_holds state machine + compliance_hold_authority separate from commercial; full_lockout reserved for extreme sanctions |
| License cache stale during invalidation race | High | Low | DEC-36-27: versioned cache keys + 30s safety TTL + fail-closed-on-write |
| Multi-environment customer confused about which env they are in | Medium | Medium | Mandatory environment badge in frontend header; environment-specific URL routing (`aeonn-prod.verixa.com` / `aeonn-test.verixa.com`); explicit environment selection at login |

---

## 13. Records Retained

| Record | Purpose | Retention | Owner |
|---|---|---|---|
| `customer_accounts` rows + version chain | Commercial parent record | retain (long-term) | Finance / Customer Account Admin |
| `tenant_environments` rows + state history | Per-environment isolation + provisioning record | retain (long-term) | Verixa platform admin / Customer Admin |
| `subscriptions` rows + supersede chain | Contract evidence | retain (long-term; default 10 years post-termination) | Finance / Subscription Admin |
| `plans` + `plan_isolation_permissibility` rows | Plan catalogue + permissibility evidence | retain (long-term) | Super Admin |
| `module_entitlements` rows + version chain | Per-module entitlement evidence | retain (long-term) | Subscription Admin |
| `seat_allocations` rollups | Seat consumption evidence (computed) | retain (long-term per GxP audit) | Customer Admin |
| `license_assignments` rows | Per-user license evidence | retain (long-term per GxP audit retention) | Customer Admin / Subscription Admin |
| `usage_records` (hot tier) | Last 24 months usage | retain hot; migrate to cold tier after | Subscription Admin / URS-35 |
| `usage_records` (cold tier) | Historical usage | retain (long-term per audit retention) | URS-35 |
| `billing_events` rows | Provider webhook event history | retain (long-term) | Billing Admin |
| `invoices` + `payments` rows | Financial evidence | retain (long-term per finance retention; jurisdiction-specific minimums) | Finance |
| `dunning_events` | Collection-action evidence | retain (long-term) | Finance |
| `compliance_holds` rows | Compliance hold evidence | retain (long-term; platform-scoped for `internal_only` / `legal_counsel_only` classes) | Verixa Legal Counsel |
| `emergency_inspection_grants` rows | Break-glass inspector access evidence | retain (long-term) | Customer Admin / Verixa Platform Admin |
| `inspection_mode_overrides` rows | Planned override evidence | retain (long-term) | Customer Admin / Verixa Platform Admin |
| `workflow_dependency_declarations` rows | Shield permitted-child configuration history | retain (long-term) | Super Admin |
| `workflow_shield_inheritance` rows | Per-child-workflow shield-inheritance audit trail | retain (long-term) | Per workflow module |
| `license_cache_versions` rows | Version stamp registry (rolling) | retain 30 days hot; rolling archive | Engineering |
| `license_audit_events` (URS-06 shadow) | Audit shadow (canonical in URS-06) | retain (long-term) | URS-06 substrate |
| Contract documents (MSA / OF / Amendment / BYOC / On-Prem / Legal-Basis-of-Hold) | Legal evidence | retain (long-term; per URS-12 retention policy) | URS-12 |

---

## 14. Acceptance Criteria (AC-36-*)

Thirteen canonical functional ACs from the drift matrix, refined per push-back corrections:

- **AC-36-FUNC-001** — Three-entity model: customer_account / tenant_environment / subscription. `tenant_environments` unique on `(customer_account_id, environment_slug)` with multiple environments per `environment_class` permitted. `subscriptions` use PostgreSQL exclusion constraint on `(tenant_environment_id, tstzrange(effective_from, effective_to)) WITH &&` — no overlapping active contract date ranges per tenant_environment. License Gate keys on `tenant_environment_id`. Priority CRITICAL.
- **AC-36-FUNC-002** — Subscription master record per environment per term; activation blocked if tenant_environment provisioning_status != active OR validation_status < validated for validated_* classes. Priority CRITICAL.
- **AC-36-FUNC-003** — Atomic create of customer_account + initial tenant_environment + initial subscription; provisioning runs asynchronously per environment. Priority CRITICAL.
- **AC-36-FUNC-004** — License Gate at canonical pipeline position §0.5; keyed on tenant_environment_id; two-layer cache + versioned + 30s safety TTL + fail-closed-on-write. Priority CRITICAL.
- **AC-36-FUNC-005** — Module entitlement enforcement at runtime; backend authoritative. Priority HIGH.
- **AC-36-FUNC-006** — Named-user for `validated_*` environment_class regardless of plan; rationale = availability not attribution. Priority CRITICAL.
- **AC-36-FUNC-007** — Authority-Profile-tied seats with URS-28 qualification + URS-05 binding. Priority HIGH.
- **AC-36-FUNC-008** — Mid-Workflow Continuity Shield with bounded transitive child workflow exemption per DEC-36-14 / DEC-36-38: child workflows carry parent + root + causal_reason + inherited_shield_id + shield_depth (1..3); cycles blocked; depths >3 require URS-13 CR + executive + final_quality_approver override. Priority CRITICAL.
- **AC-36-FUNC-009** — Inspector access: two paths — (a) planned override (DEC-36-16; pre-bound URS-22 context); (b) emergency break-glass (DEC-36-15-EMG; credential capture; **escalation-not-revoke model**: 24h binding-overdue escalation → 48h platform-admin placeholder URS-22 context → 72h absolute expiry; access NEVER auto-revokes at 24h or 48h; inspection_grantor_authority SoD distinct from contract_signatory). Priority CRITICAL.
- **AC-36-FUNC-010** — Environment-class hard separation per DEC-36-07. Priority HIGH.
- **AC-36-FUNC-011** — License-event append-only audit per URS-06; hash-chain conditional. Priority CRITICAL.
- **AC-36-FUNC-012** — Dunning split into three paths per DEC-36-25: routine / fast-path commercial / compliance hold. Compliance hold is separate state machine + separate authority. Every hold (commercial + compliance) carries `disclosure_class` per DEC-36-25; URS-30 routing gates on disclosure_class; `restricted_pending_legal_review` classified within 5 business days; customer-facing state for restricted/internal/counsel-only classes is generic `subscription_on_hold_contact_support`. Priority HIGH.
- **AC-36-FUNC-013** — License Cache invalidation is synchronous and in-transaction per DEC-36-27. DB `license_cache_versions` table is the source of truth. Version bump occurs in the SAME database transaction as the underlying state-changing write (async invalidation prohibited). Redis cache is a replica only, updated via post-commit outbox; Redis 30s safety TTL covers only Redis-vs-DB inconsistency, never write-to-invalidation lag. Regulated writes fail closed if DB stamp cannot be verified. Priority CRITICAL.

Plus integration + negative ACs extended for: `SHIELDED_NEW_INDEPENDENT_WORKFLOW_BLOCKED`, `CAUSAL_REASON_REQUIRED`, `PARENT_WORKFLOW_NOT_IN_SHIELD_ELIGIBLE_STATE`, `SHIELD_DEPTH_EXCEEDED`, `SHIELD_CYCLE_DETECTED`, `EMERGENCY_GRANT_BINDING_OVERDUE_24H_ESCALATED`, `EMERGENCY_GRANT_PLACEHOLDER_BOUND_AT_48H`, `EMERGENCY_GRANT_ABSOLUTE_EXPIRY_72H_REACHED`, `INSPECTION_GRANTOR_SOD_VIOLATION`, `COMPLIANCE_HOLD_REQUIRES_LEGAL_AND_EXECUTIVE_CO_SIGN`, `DISCLOSURE_CLASS_PENDING_LEGAL_REVIEW_5_BUSINESS_DAY_BREACH`, `LICENSE_CACHE_VERSION_STAMP_STALE`, `LICENSE_CACHE_VERSION_VERIFICATION_FAILED`, `LICENSE_WRITE_FAIL_CLOSED_ON_DB_VERIFY_FAILURE`.

---

## 15. Regulatory Mapping

| Standard | Provision | URS-36 mapping |
|---|---|---|
| 21 CFR Part 11 §11.10(a) | System validation | All ACs in §14; provisioning IQ/OQ/PQ per tenant_environment |
| 21 CFR Part 11 §11.10(c) | Record protection | DEC-36-17 retention-period read-only; URS-35 cold storage; per-tenant_environment backup |
| 21 CFR Part 11 §11.10(d) | Access control | License Gate post-RBAC; named-user (DEC-36-06); Authority Profile (URS-05); SoD |
| 21 CFR Part 11 §11.10(e) | Audit trail | Every license event append-only audited; hash-chain claim conditional per DEC-36-26 |
| 21 CFR Part 11 §11.10(g) | Authority checks | URS-04 e-sig + URS-05 Authority Profile |
| 21 CFR Part 11 §11.50 | Signed records | Subscription contracts, tier changes, license assignments — all e-signed |
| 21 CFR Part 11 §11.100 | E-signature components | URS-04 substrate carries name + date + meaning + reason for every license-state e-sig |
| EU GMP Annex 11 §4 | Operational documentation | This URS + downstream validation pack |
| EU GMP Annex 11 §7.1 | Logical separation | Per-tenant_environment isolation per ADR-004 Options B / B+ / C / D |
| EU GMP Annex 11 §12 | Access controls | License Gate fail-closed; per-tenant DB role (B+) or dedicated DB (C) |
| EU GMP Annex 11 §16 | Incident management | Dunning workflow + URS-30 escalation chain |
| EU GMP Annex 11 §17 | Periodic review | Renewal cadence (DEC-36-33) + module-entitlement review |
| EU GMP Annex 22 (Draft) §7 | AI/ML manual continuity | ARCH-AI-001 alignment with shield + named-user |
| GAMP 5 Cat-5 | Custom software validation | Full IQ/OQ/PQ per acceptance criteria above; per-environment provisioning validation |
| MHRA ALCOA+ Attributable | Named-user enforcement for validated environments (rationale: availability not attribution) |
| MHRA ALCOA+ Contemporaneous | Server-side timestamps on every license event |
| MHRA ALCOA+ Original | Subscription supersede + URS-06 append-only + URS-35 PITR (Options C / D-dedicated) |
| MHRA ALCOA+ Available | Retention-period read-only access for 10+ years post-termination |
| ICH Q10 | Data integrity | Per-tenant_environment audit trail (B+ schema-isolated audit log) |
| ICH Q9 | Quality risk | DEC-36-28 / DEC-36-29 regulatory-impact assessment for downgrades |
| HIPAA §164.502(b) | Minimum necessary | Module entitlement + named-user |
| GDPR Art. 5(1)(c) + Art. 44 | Data minimisation + transfer | Per-tenant_environment `data_region`; KMS CMK (B+/C) |
| India DPDP Act 2023 §8 | Purpose limitation | Subscription scope + data-region binding |
| India CDSCO Schedule M | GMP | Environment-class separation; named-user |
| US OFAC / EU restrictive measures / India FEMA / UK OFSI / AML SAR-style "tipping off" | Disclosure-class jurisdictional rules | DEC-36-25 `disclosure_class` with Legal-controlled per-order classification; spec does not assert universal disclosure prohibition |

---

## 16. Cross-Module Event Contract

**Emitted by URS-36:**

- Customer account: `customer_account.created`
- Tenant environment: `tenant_environment.created`, `tenant_environment.provisioning_started`, `tenant_environment.provisioning_completed`, `tenant_environment.provisioning_failed`, `tenant_environment.validation_passed`, `tenant_environment.validation_failed`, `tenant_environment.isolation_changed`, `tenant_environment.environment_class_changed`, `tenant_environment.data_region_changed`, `tenant_environment.kms_rotated`, `tenant_environment.migration_version_advanced`, `tenant_environment.decommissioned`
- Subscription lifecycle: `subscription.created`, `subscription.quote_pending`, `subscription.countersigned_customer`, `subscription.countersigned_verixa`, `subscription.activated`, `subscription.renewing_entered`, `subscription.renewed`, `subscription.on_hold_entered`, `subscription.fast_path_hold_applied`, `subscription.grace_entered`, `subscription.shielded_expiry_pending`, `subscription.shield_extended_for_in_flight_workflow`, `subscription.expired_read_only`, `subscription.late_renewed`, `subscription.terminated`
- Tier / amendment: `subscription.tier_changed`, `subscription.amended`
- Module entitlement: `module.entitlement_toggled`
- Seat: `seat.allocated`, `seat.consumed`, `seat.released`, `seat.reallocated`, `seat.soft_cap_breached`, `seat.hard_cap_breached`
- License assignment: `license.assigned`, `license.suspended`, `license.revoked`, `license.reassigned`, `license.archived`
- Invoice + payment + dunning: `invoice.issued`, `invoice.paid`, `invoice.overdue`, `invoice.refunded`, `invoice.written_off`, `payment.posted`, `dunning.step_advanced`, `dunning.escalated`
- Billing event: `billing.webhook_received`, `billing.webhook_validated`, `billing.webhook_reconciled`
- Compliance hold: `compliance_hold.proposed`, `compliance_hold.active`, `compliance_hold.disclosure_classified`, `compliance_hold.released`
- Inspection — planned override: `inspection_override.granted`, `inspection_override.revoked`
- Inspection — emergency break-glass: `emergency_inspection_grant.created`, `emergency_inspection_grant.binding_overdue_escalated_at_24h`, `emergency_inspection_grant.placeholder_bound_at_48h`, `emergency_inspection_grant.urs_22_bound`, `emergency_inspection_grant.absolute_expired_at_72h`, `emergency_inspection_grant.manually_revoked`
- Workflow shield: `workflow_dependency_declaration.updated`, `workflow_shield_inheritance.created`, `shield_depth_override.granted`
- Usage: `usage.threshold_breached`
- License gate: `license_gate.denied` (payload: `user_id`, `tenant_environment_id`, `module_id`, `action`, `reason_code`)
- Cache: `license_cache_versions.bumped_in_transaction`, `license_cache.redis_warmed`, `license_cache.redis_evicted`
- Audit seal: `hash_chain.seal_termination`

**Consumed by URS-36:**

- `tenant.created` (URS-08) — triggers Initial Subscription requirement
- `tenant.suspended` (URS-08) — cascades to license state change
- `tenant.terminated` (URS-08) — triggers DEC-36-32 cascade
- `urs_13.cr_approved` (URS-13) — triggers tier change / amendment / isolation change execution
- `urs_28.qualified` / `urs_28.qualification_expired` (URS-28) — updates Authority-Profile seat eligibility
- `urs_22.inspection_opened` (URS-22) — eligible context for inspection-mode override request
- `urs_22.placeholder_context_reconciled` (URS-22) — closes emergency-grant 48h placeholder
- `urs_35.cold_storage_migration_complete` (URS-35) — confirms retention-period transition
- `workflow.in_flight_check` (URS-04) — input to Mid-Workflow Continuity Shield
- `billing.provider_webhook` (external) — provider payment / chargeback / fraud signal

---

## 17. Open Blockers Register

| Blocker | Description | Evidence Required | Risk if Unresolved |
|---|---|---|---|
| **BLK-36-01** | RLS conflict between architecture and ADR-004 (§0.6) | PostgreSQL policy dump; RLS-enabling migrations; cross-tenant negative tests; missing-WHERE-clause endpoint fix evidence (3 endpoints per ADR-004) | Cross-tenant data exposure; 21 CFR Part 11 §11.10(d) finding; failed validation |
| **BLK-36-02** | No code evidence of URS-36 implementation | `customer_accounts` / `tenant_environments` / `subscriptions` / `module_entitlements` / `license_assignments` migrations; `requireLicense` middleware source; route plugin registration; integration tests; audit-registry entries | URS-36 may be approved without buildable / testable implementation path |
| **BLK-36-03** | License Gate absent from current request pipeline | Backend `app.ts` hook order; route plugin registration; middleware tests proving gate runs before service handler and after RBAC | Unlicensed regulated writes possible |
| **BLK-36-04** | Tenant-environment provisioning state machine not implemented (per environment, not per tenant) | `tenant_environment_provisioning_status` table + migrations; provisioning engine source; per-schema migration runner; backup-policy binding service; KMS-binding service; data-region routing | Tenant_environments may onboard without validated isolation |
| **BLK-36-05** | Hash-chain audit claim not evidenced in URS-06 | URS-06 implementation; hash-chain schema; tamper-evidence tests | DEC-36-26 conditional; overclaim of Part 11 §11.10(e) integrity if locked |
| **BLK-36-06** | workflow_dependency_declarations + Shield child-workflow exemption requires URS-04 / URS-13 / URS-23 / URS-15 / URS-22 / URS-27 / URS-31 hook surfaces | Cross-module hook implementation evidence; declaration consumer code per shield-eligible parent module; integration tests | Shield child-workflow exemption may not function across consumer modules |

---

## 18. References

- 21 CFR Part 11 — Electronic Records; Electronic Signatures
- 21 CFR Part 211 — current Good Manufacturing Practice
- EU GMP Annex 11 — Computerised Systems
- EU GMP Annex 22 (Draft 2025) — AI/ML in Pharmaceutical Manufacturing
- EU AI Act (Regulation 2024/1689)
- FDA CSA Final Guidance (September 2025) — Computer Software Assurance
- ICH E6(R3) — Good Clinical Practice
- ICH Q9 — Quality Risk Management
- ICH Q10 — Pharmaceutical Quality System
- ISO 27001:2022 — Information security management
- ISO 22301:2019 — Business continuity management
- NIST SP 800-34 — Contingency Planning
- MHRA Data Integrity Guidance (2018) — ALCOA+ principles
- WHO Technical Report Series No. 996, Annex 5
- PIC/S PI 041 — Data integrity
- HIPAA §164.502(b) — Minimum necessary
- GDPR (Regulation 2016/679) — Article 5(1)(c) Data minimisation; Article 44 Data transfers
- India DPDP Act 2023
- India IT Act 2000
- India CDSCO Schedule M
- US OFAC sanctions program
- EU restrictive measures regulations
- India FEMA
- UK OFSI sanctions
- FinCEN advisories on SAR confidentiality (referenced for disclosure_class jurisdictional context only; no universal disclosure rule asserted)
- ADR-004 / VX-FLOW-038 — Tenant Database Architecture Options (v1.0, May 2026)
- Verixa Platform Architecture (dev-vimal-deploy branch, 2026-05-13)
- Founder push-back review (consolidated; dated 2026-05-13)
- AICPA SOC 2 Type II — Trust Services Criteria (where applicable to commercial-governance controls)
- US Sarbanes-Oxley Act §404 — Internal control over financial reporting (where applicable to revenue-cycle controls)

### Revision history

| Version | Date | Change |
|---|---|---|
| v1.0 | 2026-05-13 | Initial Target State URS lock. Locked content: three-entity model (customer_account / tenant_environment / subscription); ADR-004-aligned isolation_model + data_region + KMS + backup policy + provisioning state machine as first-class fields on tenant_environment; License Gate at canonical pipeline position keyed on tenant_environment_id; named-user enforcement by environment_class (rationale: deterministic seat availability + Annex 11 §16 + Part 11 §11.10(c)); sandbox / demo environment hard segregation; bounded transitive Mid-Workflow Shield (max depth 3 + cycle detection + override path); emergency inspector escalation-not-revoke model (24h escalation → 48h placeholder → 72h absolute expiry); compliance-hold disclosure-class with legal-controlled defaults; synchronous in-transaction cache invalidation + versioned Redis replica; subscription uniqueness via PostgreSQL exclusion constraint on date ranges; multi-environment-per-class permitted; grace-period split between tenant_environments.default_grace_period_days and subscriptions.grace_period_days_snapshot. The six open blockers BLK-36-01..BLK-36-06 in §17 carry forward as the canonical pre-validation evidence checklist; document is not validation-ready until they resolve. |

---

End of URS-36 Target State URS v1.0.
# URS-36 — Licensing, Entitlements & Subscription Management

## Target-State User Requirements Specification — Verixa Launch URS Pack

**Revision:** v1.0 — Target State URS (remaining work tracked via the six open blockers in §17)

---

## 0. Controlled Document Header

| Field | Value |
|---|---|
| Document Title | URS-36 — Licensing, Entitlements & Subscription Management — Target-State |
| Document Type | Target-State User Requirements Specification |
| Scope | Three-entity commercial-governance + technical-isolation model (`customer_account` / `tenant_environment` / `subscription`), per-tenant-environment technical isolation per ADR-004, per-module entitlement matrix, per-seat / named-user / authority-profile-tied license assignment, subscription lifecycle with on-hold + grace + shield + expired-read-only + termination, billing-provider abstraction isolated from GxP access state, dunning workflow with split routine / fast-path / compliance-hold paths, usage metering, license-event audit, tenant-environment provisioning state machine, Mid-Workflow Continuity Shield with causally-linked child workflow exemption, emergency inspector access (break-glass), inspection-mode override (planned), retention-period read-only access, multi-currency + tax + FX, environment-class hard separation. |
| Status | **Target State URS v1.0** — locked. **This document specifies the target behaviour; implementation evidence remains subject to repository verification and validation evidence. The RLS conflict between the architecture document and ADR-004 (§0.6) remains an unresolved blocker — resolution required before validation.** |
| Audience | Founder / Chairman & MD; QA Head; Finance Head; Sales Head; Customer Success Head; RA Head; Information Security Head; Validation Head; DevOps/SRE Lead; Customer Admin (per customer_account); Verixa Platform Admin; external auditors / regulators (FDA, EMA, MHRA, CDSCO, PIC/S). |
| Source Documents | URS-MASTER-STRUCTURE; URS-02 RBAC & Permissions; URS-04 Workflow / HITL / E-Sig / Authority; URS-05 Authority Profile / Delegation / SoD; URS-06 Audit Trail / Hash Chain / Tamper-Evident; URS-08 Tenant Management Lifecycle; URS-12 Document Control; URS-13 Change Control; URS-22 Inspection Management; URS-28 Training Management & Qualification; URS-30 Notifications; URS-35 Infrastructure / Operational Resilience; **ADR-004 / VX-FLOW-038 — Tenant Database Architecture Options**; Verixa Platform Architecture (dev-vimal-deploy branch). |
| Effective Date | 2026-05-13 |
| Caveat | This document describes target application behaviour. It is not evidence of executed validation, implemented code, or regulatory compliance. AI legal posture is presented as internal forward-looking governance subject to a future jurisdiction-specific legal assessment. Hash-chain audit claims (DEC-36-26) are conditional on URS-06 implementation evidence proving the hash chain; until proven, the substrate is append-only audit only. |

---

### 0.1 Module Purpose (One-line)

URS-36 establishes Licensing, Entitlements & Subscription Management as the canonical commercial-governance and tenant-isolation substrate of Verixa, structured on three first-class entities — `customer_account` (commercial parent / invoice / SLA rollup), `tenant_environment` (**one or more per customer_account**; **one or more per `environment_class` permitted** — each tenant_environment carries a unique `environment_slug` within its customer_account, and an `environment_class` ∈ {`validated_production`, `validated_test`, `sandbox`, `demo`}; each carries its own isolation model, data region, KMS key mode + ref, backup policy, validation status, migration version), and `subscription` (the contract attached to one tenant_environment for one contract term; uniqueness via PostgreSQL exclusion constraint on `(tenant_environment_id, tstzrange(effective_from, effective_to)) WITH &&` — no overlapping active contract date ranges per tenant_environment). The License Gate routes regulated-write decisions by `tenant_environment_id`, never by customer or tenant identity alone.

### 0.2 Scope Boundary

In-scope:
- Three-entity model: `customer_account` → `tenant_environment` (1..N per customer_account; one OR MORE per environment_class permitted; unique on `(customer_account_id, environment_slug)`) → `subscription` (no overlapping active contract date ranges per tenant_environment; exclusion constraint on `effective_from`/`effective_to`).
- Per-tenant-environment **technical isolation model** per ADR-004 (`OPTION_B_SCHEMA_PER_TENANT` / `OPTION_B_PLUS_SCHEMA_RLS_ROLE` / `OPTION_C_DEDICATED_DB` / `OPTION_D_HYBRID_ROUTED`).
- Per-tenant-environment data_region, KMS key mode + ref, backup policy ref, tenant-environment provisioning state machine, migration version.
- Per-subscription commercial plan, contract term, seat ceilings, currency, billing schedule, channel partner, lifecycle state, environment_class (denormalised from parent tenant_environment for fast gate evaluation).
- Per-subscription module-entitlement matrix.
- Named-user license assignment (mandatory for `validated_*` environment classes).
- Authority-profile-tied seat allocation with URS-28 qualification dependency.
- Subscription lifecycle: `draft → quote_pending → active → renewing → subscription_on_hold → grace_period → shielded_expiry_pending → expired_read_only → terminated`.
- License-assignment lifecycle: `unassigned → assigned → active → suspended → revoked → reassigned → archived`.
- License Gate at canonical pipeline position (§0.5) with two-layer cache (per-request memoisation + versioned Redis cache + short safety TTL + fail-closed-on-write).
- Module entitlement enforcement.
- Mid-Workflow Continuity Shield with **causally-linked child workflow exemption** (DEC-36-14).
- Inspector access: **two distinct paths** — (a) planned inspection-mode override (DEC-36-16); (b) emergency break-glass inspector access (DEC-36-15-EMG) with credential capture + escalation-not-revoke model: 24h binding-overdue escalation (access continues), 48h platform-admin placeholder URS-22 context permitted, 72h absolute emergency expiry unless converted to planned override.
- Dunning workflow with **three paths**: (a) routine cadence; (b) fast-path commercial hold (chargeback / fraud / rescission / bankruptcy); (c) compliance hold (sanctions / regulatory order).
- Validated vs sandbox vs demo hard data segregation.
- Retention-period read-only access.
- Trial / Pilot licensing.
- Channel partner registry.
- Billing-provider abstraction isolated from GxP access via `billing_events` queue + controlled rules.
- Usage metering, invoice + payment + dunning + refund + write-off.
- Tax + FX per jurisdiction + currency.
- License-event append-only audit (hash-chain conditional on URS-06 evidence).

Out-of-scope (owned by adjacent modules): URS-08 tenant operational mechanics; URS-02 RBAC catalogue; URS-05 SoD definitions; URS-06 hash-chain substrate; URS-13 CR records; URS-30 template authoring; URS-35 IaC + backup engines (URS-36 holds policy refs); tax + FX external providers; GL postings.

---

### 0.3 Glossary

| Term | Definition |
|---|---|
| Customer Account | The commercial parent entity. One per real-world customer organisation (e.g., Aeonn Health, Pfizer, GSK). Owns the master service agreement, the commercial relationship, the consolidated invoice + SLA rollup. Does NOT directly own GxP records or isolation routing. |
| Tenant Environment | A discrete operating environment within a customer account. **One or more per `environment_class` permitted** (e.g., a large customer may run multiple `validated_production` environments by region / site / business unit). Carries the technical isolation model (per ADR-004), data_region, KMS key mode + ref, backup policy ref, tenant-environment provisioning state, migration version, validation status. Each tenant_environment has a unique `environment_slug` within its customer_account. **The License Gate routes regulated-write decisions by `tenant_environment_id`.** |
| Subscription | The contract attached to ONE tenant_environment for ONE contract term. Carries commercial plan, seat ceilings, billing schedule, currency, channel partner, lifecycle state. A tenant_environment may have a sequence of subscriptions over time (one per term); only one active at any moment per environment. |
| Environment Class | Fixed enum on tenant_environment: `validated_production` / `validated_test` / `sandbox` / `demo`. Drives named-user mandate, GxP-write permissibility, watermark rendering, audit retention. |
| Commercial Plan | The named product packaging on a subscription (`starter` / `pro` / `enterprise` / `custom`). Governs pricing + default module bundle. **Decoupled from technical isolation.** |
| Technical Isolation Model | The physical / logical tenant isolation strategy on a tenant_environment per ADR-004. One of `OPTION_B_SCHEMA_PER_TENANT` / `OPTION_B_PLUS_SCHEMA_RLS_ROLE` / `OPTION_C_DEDICATED_DB` / `OPTION_D_HYBRID_ROUTED`. **First-class field on tenant_environment; NEVER derived from commercial plan name.** |
| Tenant Schema | Field on tenant_environment for Options B / B+ / D-shared. PostgreSQL schema name (`tenant_<env_slug>`). |
| DB Instance Ref | Field on tenant_environment for Options C / D-dedicated. Dedicated RDS instance / cluster handle (ARN). |
| Data Region | The AWS / Azure / GCP region where the tenant_environment's data physically resides. Mandatory for jurisdictional binding. |
| KMS Key Mode | One of `shared_platform_key` / `customer_managed_kms` / `dedicated_kms` per ADR-004 tiering. |
| Backup Policy Ref | Reference to URS-35 per-tenant-environment backup policy. |
| Tenant Environment Provisioning State | State machine on tenant_environment: `pending → provisioning → provisioned → validation_pending → active → provisioning_failed → decommissioned`. Independent of subscription lifecycle. |
| Migration Version | The migration version applied to the tenant_environment's schema / DB. Mismatch with platform version blocks regulated writes (`MIGRATION_VERSION_MISMATCH`). |
| Validation Status | On tenant_environment: `not_validated` / `iq_complete` / `oq_complete` / `pq_complete` / `validated`. `validated` required before `environment_class = validated_*` activation. |
| Plan ↔ Isolation Permissibility Map | Versioned map of which isolation models are permitted for which commercial plans (e.g., Starter→{B}; Enterprise→{B+, C, D}). |
| Module Entitlement | Boolean per subscription per module. Drives License Gate. |
| License Assignment | Right-to-use granted under a subscription, bound to a userId + seat class + module scope. |
| Named-User License | License assigned to a specific userId. Mandatory for `validated_*` environment classes — **rationale: deterministic seat availability + EU Annex 11 §16 (incident management) + 21 CFR Part 11 §11.10(c) (ready retrieval). Not because attribution would otherwise be lost; attribution is preserved at the record level via authenticated JWT userId regardless of licensing model.** |
| Concurrent-Session License | License consumed at peak concurrent session count. Permitted ONLY for `sandbox` / `demo` environment classes. |
| Seat | Unit of license capacity. |
| Seat Class | The class of seat consumed: `general` / `qp_release_authority` / `inspection_owner_authority` / `final_quality_approver` / `rp_release_authority` / etc. |
| Soft Cap / Hard Cap | Per DEC-36-10. Soft cap = alert + auto URS-13 CR; hard cap = block. |
| Subscription On-Hold | New state between `active` and `grace_period`. Entered when (a) routine dunning Day 21 reached; or (b) fast-path commercial hold triggered (chargeback / fraud / rescission / bankruptcy); or (c) compliance hold triggered (sanctions / regulatory order — via separate compliance_hold path). In on-hold: regulated writes are SHIELDED (Mid-Workflow Shield applies), not immediately blocked. Cure-able via payment + URS-13 CR. |
| Mid-Workflow Continuity Shield | Mechanism that prevents license-state transitions from interrupting in-flight critical regulated workflows. Permits: (a) completion of in-flight workflows that started before the triggering state change; (b) **causally-linked child workflows** declared by parent workflow modules per `workflow_dependency_declaration` (DEC-36-14). New independent regulated workflows are blocked. |
| Causally-Linked Child Workflow | A regulated workflow that is declared (in versioned platform configuration) to be a permitted child of a parent in-flight workflow. Each child workflow record carries `parent_workflow_id`, `causal_reason`, `inherited_shield_id`. Example: a deviation (URS-16) arising during a batch QP-release (URS-23) is a permitted child if `(URS-23, qp_certification_in_progress)` declares URS-16 as a child class. |
| Inspector Account | A user account bound to `inspector_authority` Authority Profile. Exempt from seat-ceiling and license-state blocking **only within tenant_environment boundary, RBAC scope, audit logging, and inspection-context binding**. |
| Planned Inspection-Mode Override | Pre-approved regulator access during `expired_read_only` (DEC-36-16). Dual approval (`inspection_mode_override_authority` Verixa + `executive_authority` customer); 14-day default; URS-22 inspection-context bound BEFORE grant. |
| Emergency Inspector Access (Break-Glass) | Granted-on-arrival regulator access for unannounced inspections (DEC-36-15-EMG). Triggered by **pre-authorized `inspection_grantor_authority`** (customer-side; not any executive_authority). Credential capture mandatory (regulator ID, agency reference, badge photo URL or equivalent). Read-only scope. **Escalation-not-revoke model:** 24h binding-overdue escalation (access continues; URS-30 escalation); 48h platform-admin placeholder URS-22 context permitted (access continues); 72h absolute expiry unless converted to planned override (DEC-36-16). Access is NEVER auto-revoked at 24h or 48h. Manual revoke available at any time. |
| Compliance Hold | Separate hold path triggered by `sanctions_violation` / `regulatory_order` / `legal_hold_order`. Routes via `compliance_hold_authority` (Verixa-internal + Legal Counsel + Executive). NOT part of ordinary dunning. Different state machine. |
| Retention-Period Read-Only Access | Post-termination read-only access for regulatory retention period (10-year default; jurisdiction-configurable). URS-35 cold-storage bound. |
| License-Cache Version | Monotonically-increasing counter per `(tenant_environment_id, subscription_id)`. Bumped on any subscription / entitlement / license / isolation / environment / migration write. Cached License Gate decisions key on the version stamp; stale version stamps fail to match → forced re-evaluation. |
| Fail-Closed-on-Write | License Gate behaviour: for regulated WRITE actions, a cache miss or stale-cache version stamp causes the gate to perform a fresh authoritative DB evaluation. Cache hits accepted only for READ-side decisions. |
| Workflow Dependency Declaration | Versioned platform configuration mapping `(parent_module, parent_state) → permitted_child_modules + permitted_child_actions`. Drives DEC-36-14 child-workflow exemption. Changes are super_admin-controlled with URS-13 CR. |
| Root Workflow ID | The top-most shield-eligible parent in a chain of causally-linked child workflows. Used to detect cycles and enforce DEC-36-14 max-depth-3 rule. |
| Shield Depth | Integer 1..3. 1 = direct child of shield-eligible parent. 2 = grandchild. 3 = great-grandchild. Depths >3 require URS-13 CR + executive + final_quality_approver override. |
| Inherited Shield ID | The shield context ID inherited by a child workflow from its parent. Allows audit traceability of which root-workflow's shield protects each descendant. |
| Disclosure Class | Field on every hold record (commercial + compliance) controlling URS-30 notification routing. Values: `full_disclosure` / `restricted_disclosure` / `internal_only` / `legal_counsel_only` / `restricted_pending_legal_review`. Legal-controlled; defaults are starting points only and require per-order classification within 5 business days for `restricted_pending_legal_review`. |
| Subscription On-Hold Contact Support | Canonical neutral customer-facing license-state label rendered when the hold's `disclosure_class` is `restricted_*` / `internal_only` / `legal_counsel_only`. No hold-class or hold-reason disclosed to customer admin. |
| License Cache Version Stamp | Monotonic bigint per `(tenant_environment_id, subscription_id)` in the `license_cache_versions` DB table. The DB row is the source of truth. Redis cache stamps are replicas. |
| In-Transaction Version Bump | Cache invalidation contract: every state-changing write to subscription / entitlement / license / isolation / environment / migration / compliance-hold tables MUST bump the `license_cache_versions.version_stamp` in the SAME database transaction as the underlying write. Async invalidation is prohibited. |
| Post-Commit Redis Outbox | Pattern for propagating in-transaction version bumps to Redis cache after the DB transaction commits. Uses PostgreSQL `LISTEN/NOTIFY` or a transactional outbox table consumed by a Redis-update worker. |

---

### 0.4 Module Architectural Picture

```mermaid
graph LR
  subgraph M36 [Module 36 — Licensing, Entitlements & Subscription Management]
    CA[Customer Account]
    TE[Tenant Environment]
    SUB[Subscription]
    PLAN[Commercial Plan Catalogue]
    ISOL[Technical Isolation Model]
    ENT[Module Entitlement Matrix]
    REGION[Data Region]
    KMS[KMS Key Mode + Ref]
    BACKUP[Backup Policy Ref]
    PROV[Tenant Env Provisioning State]
    VAL[Validation Status]
    MIGV[Migration Version]
    SEAT[Seat Allocation Register]
    LIC[License Assignment Register]
    USAGE[Usage Metering]
    BILL[Billing Event Queue]
    INV[Invoice + Payment Register]
    DUN[Dunning Workflow]
    HOLD[Compliance Hold]
    GATE[License Gate API]
    CACHE[Versioned License Cache]
    SHIELD[Mid-Workflow Continuity Shield]
    WFDEP[Workflow Dependency Declaration]
    INSPP[Planned Inspection Override]
    INSPE[Emergency Inspector Break-Glass]
    RET[Retention-Period Read-Only]
    PIMP[Plan-Isolation Permissibility Map]
  end

  CA --> TE
  TE --> SUB
  TE --> ISOL
  TE --> REGION
  TE --> KMS
  TE --> BACKUP
  TE --> PROV
  TE --> VAL
  TE --> MIGV
  SUB --> ENT
  SUB --> SEAT
  SUB --> LIC
  SUB --> USAGE
  SUB --> INV
  PLAN --> SUB
  PIMP --> ISOL
  PIMP --> SUB
  M2[URS-02 RBAC & Permissions] --> GATE
  M4[URS-04 Workflow / HITL / E-Sig] --> SUB
  M5[URS-05 Authority Profile / SoD] --> LIC
  M6[URS-06 Audit / Append-Only] --> SUB
  M6 --> LIC
  M6 --> ENT
  M6 --> SEAT
  M6 --> INV
  M6 --> ISOL
  M6 --> HOLD
  M6 --> INSPE
  M8[URS-08 Tenant Lifecycle] <--> CA
  M8 <--> TE
  M8 <--> PROV
  M12[URS-12 Document Control] <--> SUB
  M13[URS-13 Change Control] <--> SUB
  M13 <--> PLAN
  M13 <--> ISOL
  M13 <--> ENT
  M13 <--> HOLD
  M22[URS-22 Inspection Management] <--> INSPP
  M22 <--> INSPE
  M28[URS-28 Training Qualification Gate] --> LIC
  M30[URS-30 Notifications] --> DUN
  M30 --> HOLD
  M30 --> SUB
  M35[URS-35 Infrastructure / Backup] <--> BACKUP
  M35 <--> REGION
  M35 <--> KMS
  M35 <--> RET
  GATE --> CACHE
  CACHE --> GATE
  GATE --> M14[URS-14..URS-35 Consumer modules]
  WFDEP --> SHIELD
  SHIELD --> M23[URS-23 Batch Records]
  SHIELD --> M15[URS-15 OOS / OOT]
  SHIELD --> M27[URS-27 Recall Execution]
  SHIELD --> M22
  SHIELD --> M31[URS-31 DQG Filing]
  BILL --> DUN
  DUN --> SUB
  HOLD --> SUB
```

---

### 0.5 Request Pipeline Position of License Gate (Canonical)

```
HTTP request
   ↓
1. CSRF verify
   ↓
2. Correlation ID
   ↓
3. authenticate (JWT → customer_account_id + userId)
   ↓
4. environmentScope (resolve `tenant_environment_id` per the hardened rules below)
   ↓
5. tenantScope (set per-environment routing: search_path for B/B+/D-shared OR dedicated connection for C/D-dedicated; SET app.current_tenant_environment_id)
   ↓
6. contextScope (URS-03 study / site / product / supplier — scope-validated against the resolved tenant_environment_id)
   ↓
7. requirePermission (URS-02 RBAC)
   ↓
8. requireLicense (URS-36 License Gate — keyed on tenant_environment_id)
   ↓
9. authorityCheck (URS-05 Authority Profile)
   ↓
10. trainingGate (URS-28; for authority actions)
   ↓
11. Route handler
   ↓
12. URS-06 append-only audit hook
```

The License Gate is keyed by `tenant_environment_id` (NOT customer_account_id, NOT tenant_id alone). A user with access to both `aeonn-prod` (validated_production) and `aeonn-test` (validated_test) environments holds two separate license assignments under two separate subscriptions; the gate consults the one matching the request's tenant_environment_id.

**Hardened `environmentScope` rules (normative; mirrors Cross-Module Patch Set PATCH-01-006 + PATCH-01-007):**

1. **JWT model.** JWT carries `userId`, `customer_account_id`, `accessible_tenant_environment_ids` (array; computed at issue time), `current_tenant_environment_id` (selected at session start; mutable only via the controlled environment-switch endpoint below), `roles`, `permissions`, `iat`, `exp`.
2. **Header / JWT matching.** If the request carries an `X-Env-Id` header, it MUST match the JWT's `current_tenant_environment_id` exactly; mismatch → 401 `ENV_ID_HEADER_JWT_MISMATCH`. If `X-Env-Id` is absent, fall back to the JWT's `current_tenant_environment_id`. The header is NOT trusted independently of the JWT.
3. **Accessibility check.** The resolved `tenant_environment_id` MUST be in the JWT's `accessible_tenant_environment_ids`; if not → 403 `ENV_NOT_ACCESSIBLE`.
4. **Controlled environment switch.** Mutating `current_tenant_environment_id` is permitted only via `POST /api/v1/auth/switch-environment` with payload `{target_tenant_environment_id}`. On success the current session is terminated (JWT revoked), a new JWT is issued with the new `current_tenant_environment_id`, and a distinct session record is created per URS-01 session audit log. Direct mutation outside this endpoint is prohibited.
5. **Live access re-check via `environment_access_resolver`.** On every request, the resolver re-checks live accessibility against the union of all valid access paths: (a) active `license_assignments` row for `(user_id, tenant_environment_id)` with subscription in a writable-or-readable state per the License Gate; OR (b) active `emergency_inspection_grants` row for `(user_id, tenant_environment_id)`, `current_time < absolute_expiry_at_72h`, state ∈ {`active_unbound`, `binding_overdue_escalated`, `placeholder_bound`, `bound_to_urs_22`}; OR (c) active `inspection_mode_overrides` row for `(user_id, tenant_environment_id)`, `current_time ∈ [effective_from, effective_to]`, `revoked_at IS NULL`; OR (d) active retention-read-only grant for `(user_id, tenant_environment_id)` for post-terminated environments within their retention window per DEC-36-17; OR (e) platform-admin permitted context per `platform_context.ts` cross-tenant authorisation (super_admin / platform_admin with documented break-glass per URS-08 + URS-06 audit). The resolver returns the **access path used** + **scope envelope** (read-only vs write-eligible) which is propagated to subsequent License Gate evaluation.
6. **Fail closed.** If none of (a)–(e) resolves → 403 `ENV_ACCESS_REVOKED`. JWT staleness (e.g., license revoked after JWT issue, grant expired, override revoked) MUST result in `ENV_ACCESS_REVOKED`.
7. **Audit.** The access path chosen by the resolver is logged in URS-06 audit per request for inspection-readiness.

---

### 0.6 RLS Conflict Resolution Gate (Unresolved Blocker)

The architecture document (`Verixa.ARCHITECTURE.md`, dev-vimal-deploy branch) states: *"PostgreSQL Row-Level Security (RLS) on every table"* and *"SET LOCAL app.current_tenant_id via TDAL."*

ADR-004 / VX-FLOW-038 (v1.0, May 2026) states: *"PostgreSQL Row-Level Security (RLS) is NOT enabled on any table. Tenant isolation is 100% application-layer-only."* and *"Missing WHERE clauses found in 3 endpoints."*

These two statements cannot both be true. URS-36 fails closed on this conflict: **the tenant-isolation posture is `Unknown — repo evidence required`** until resolved. Resolution required before any URS-36 validation event.

**Evidence required to resolve:**
- PostgreSQL policy dump (`pg_dump --schema-only --no-owner` + `\dp` per table)
- Migration files that enable `ENABLE ROW LEVEL SECURITY` + `CREATE POLICY` per table
- Negative integration tests proving cross-tenant queries return zero rows when middleware is bypassed
- Endpoint-level tests for the three known missing `WHERE tenant_id =` endpoints (`GET /em/results`, `GET /investigations/overdue`, `GET /em/trends/:locationId`)
- TDAL unit tests proving `SET LOCAL app.current_tenant_id` is invoked on every connection

Until resolved, URS-36 §0.5 License Gate operates under the **conservative assumption that RLS is not enabled**, and `requireLicense` performs explicit `tenant_environment_id` filtering on every license query as a defence-in-depth measure regardless of underlying RLS state.

---

## 1. Module Purpose

URS-36 is the canonical commercial-governance + technical-isolation substrate. It maintains, per customer:

1. **The commercial parent** — `customer_accounts` row. Invoice rollup, SLA rollup, channel partner relationship, contract signatory binding.
2. **One or more environments** — `tenant_environments` rows. Each carries its own isolation model, region, KMS, backup, validation status, migration version, provisioning state. Validated production, validated test, sandbox, demo each is a separate tenant_environment with its own lifecycle.
3. **Subscriptions per environment** — `subscriptions` rows. Each subscription is attached to ONE tenant_environment for ONE contract term. Carries commercial plan, seat ceilings, currency, billing schedule.
4. **Entitlements, licenses, and gating** — per-subscription module entitlements + per-subscription named-user license assignments + License Gate consulting these at canonical pipeline position.

The License Gate fails closed. It resolves decisions by `tenant_environment_id`, not customer or tenant alone. It uses a two-layer cache (per-request memoisation + versioned Redis) with explicit invalidation on writes + fail-closed-on-write + short safety TTL.

URS-36 enforces hard separation between environment classes, hard boundary on the Mid-Workflow Shield (with causally-linked child workflow exemption), break-glass inspector emergency access (separate from planned override), and split dunning paths (routine / commercial-fast-path / compliance-hold). Every state transition is append-only audited via URS-06; hash-chain integrity is claimed only if URS-06 evidence proves it.

---

## 2. Operating Preconditions

For URS-36 to operate, the following preconditions MUST hold. Each is Blocking; failure fails the gate closed.

- **URS-08 tenant exists** before any URS-36 customer_account / tenant_environment / subscription is created.
- **`tenant_environment_provisioning_status = active`** (per environment, not per tenant) before any regulated write under any subscription on that environment. Provisioning includes schema / DB creation per isolation model, migration application, audit setup, backup policy binding, KMS key binding, data-region routing, and migration-version verification. Each tenant_environment is provisioned independently.
- **URS-02 RBAC catalogue is active.** License Gate runs after RBAC.
- **URS-05 Authority Profile catalogue is active** with the new licensing-specific Authority Profiles registered (§4).
- **URS-06 append-only audit substrate is running.** Every license event is logged; audit-write failure blocks the originating action.
- **URS-13 Change Control is active.** Tier change, entitlement change, isolation-model change, environment-class change, contract amendment all route to URS-13.
- **URS-22 Inspection Management is active** (for inspection-mode override binding and emergency-grant URS-22 context creation).
- **URS-28 Training Qualification Gate is active** (for Authority-Profile-tied seat consumption).
- **URS-30 Notification substrate is running.**
- **URS-35 Infrastructure substrate is running** with per-tenant-environment backup policy, PITR (for Options C / D-dedicated), `pg_dump -n` capability (for Options B / B+ / D-shared) per ADR-004 §5–7.
- **NTP-synchronised system clock.** Subscription lifecycle transitions, grace-period boundaries, dunning cadences, emergency-grant 24h/48h/72h checkpoints are all time-bound; clock drift compromises enforcement.
- **§0.6 RLS conflict resolution status** — until resolved, License Gate operates under the conservative assumption (explicit `tenant_environment_id` filter on every license query).

---

## 3. Canonical Decision Register (DEC Catalogue)

| DEC ID | Decision |
|---|---|
| DEC-36-01 | **Three-entity model.** `customer_accounts` (1..1 per real-world customer organisation) → `tenant_environments` (**1..N per customer_account; one OR MORE per `environment_class` permitted** — large customers may operate multiple `validated_production` environments by region / site / business unit; each tenant_environment carries a unique `environment_slug` within its customer_account) → `subscriptions` (1..N per tenant_environment over time, but with **no overlapping active contract date ranges per tenant_environment**). Uniqueness: `tenant_environments` is unique on `(customer_account_id, environment_slug)`. `subscriptions` uses a **PostgreSQL exclusion constraint** on `(tenant_environment_id, tstzrange(effective_from, effective_to))` with `WITH &&` (no overlapping ranges per tenant_environment) — there is no `contract_term` column; the `effective_from` / `effective_to` pair defines the term. Consolidated invoice rolls up at customer_account level across all tenant_environments. |
| DEC-36-02 | **Commercial plan + technical isolation model are independent first-class fields on different entities.** `subscriptions.commercial_plan` (`starter`/`pro`/`enterprise`/`custom`). `tenant_environments.isolation_model` (`OPTION_B_SCHEMA_PER_TENANT` / `OPTION_B_PLUS_SCHEMA_RLS_ROLE` / `OPTION_C_DEDICATED_DB` / `OPTION_D_HYBRID_ROUTED`). Plan name MUST NOT imply isolation model. Permissibility constrained by `plan_isolation_permissibility` map. |
| DEC-36-03 | **Plan ↔ Isolation Permissibility Map.** Versioned. Default at launch: Starter→{B}; Pro→{B, B+}; Enterprise→{B+, C, D}; Custom→{B, B+, C, D}. Validated-production environment_class requires at minimum Option B per ADR-004 GxP scoring. Map changes super_admin-controlled with URS-13 CR. |
| DEC-36-04 | **Per-subscription per-module entitlement.** `module_entitlements` table holds `(subscription_id, module_id, enabled, effective_from, effective_to, source_change_control_id)`. URS-01..URS-06 platform-foundational and not separately entitleable. URS-07..URS-35 entitleable. |
| DEC-36-05 | **Tenant Environment Provisioning state machine.** States: `pending → provisioning → provisioned → validation_pending → active → provisioning_failed → decommissioned`. Provisioning steps per ADR-004: create schema (B / B+) or dedicated DB (C / D-dedicated) → run migrations → bind audit substrate → configure per-tenant-environment backup policy → bind KMS → configure data-region routing → verify migration version. **Per environment, not per tenant.** A customer with three environments has three independent provisioning state rows. Tenant_environment cannot enter `environment_class = validated_*` activation until `provisioning_status = active` AND `validation_status >= validated` AND `migration_version` matches platform version. |
| DEC-36-06 | **Environment-class drives named-user enforcement. Rationale: deterministic seat availability + EU Annex 11 §16 + 21 CFR Part 11 §11.10(c).** For `validated_production` or `validated_test`: named-user licensing mandatory regardless of commercial plan. For `sandbox` / `demo`: concurrent-session licensing permitted. **Attribution is preserved at the record level via authenticated JWT `userId` regardless of licensing model; the named-user mandate is about availability, not attribution.** |
| DEC-36-07 | **Hard environment-class separation.** Each tenant_environment is a discrete database / schema / record set. Records cannot cross environment boundaries except via explicit migration-validated promotion (URS-13 CR + IQ/OQ/PQ on migrated data). Every record in `sandbox` / `demo` carries `record_gxp_status = non_gxp` + `test_data_flag = true`. Server-side watermark "SANDBOX — NOT FOR GxP USE" on every page + export when `environment_class ∈ {sandbox, demo}`. |
| DEC-36-08 | **Module-tied per-user license.** A user may hold different module-tied licenses (e.g., GMP licensed but not GCP). License Gate consults `license_assignments.module_scope_jsonb`. |
| DEC-36-09 | **Authority-profile-tied seats are separately ceilinged + priced. URS-28 qualification + active URS-05 Authority Profile binding required before seat activation.** Authority seats consumed from authority pool, never general pool. |
| DEC-36-10 | **Seat ceilings enforced at user-invite + Authority Profile bind time.** Soft cap default 0.9 × ceiling → URS-30 alert + auto URS-13 CR (non-blocking). Hard cap = ceiling → `LICENSE_SEAT_LIMIT_REACHED` (HTTP 422). |
| DEC-36-11 | **Subscription lifecycle.** `draft → quote_pending → active → renewing → subscription_on_hold → grace_period → shielded_expiry_pending → expired_read_only → terminated`. `subscription_on_hold` is reachable from `active` via routine dunning Day 21 OR fast-path commercial hold OR compliance hold (latter via separate state). All hold paths trigger Mid-Workflow Continuity Shield; cure path returns to `active`. |
| DEC-36-12 | **License-assignment lifecycle.** States: `unassigned → assigned → active → suspended → revoked → reassigned → archived`. Transitions: assign (`license_assignment_authority` + e-sig) → `assigned`; `user_first_login` → `active`; `rescind_before_login` → `unassigned`; suspend (`license_revocation_authority` + e-sig; SoD: revoker ≠ assigner) → `suspended`; reinstate → `active`; revoke (`license_revocation_authority` + e-sig; SoD) → `revoked`; `reassign_seat` → `reassigned (new user)`; `becomes_active` → `active`; archive → `archived` (terminal). Every transition append-only audited per URS-06. **SoD: assigner ≠ revoker** when dual-approval is configured. |
| DEC-36-13 | **Grace period — split between tenant-environment default and subscription snapshot.** Default 30 days; min 14 days (pharma-minimum to preserve mid-workflow continuity); max 90 days (Verixa policy). **Configuration:** `tenant_environments.default_grace_period_days` holds the tenant-environment-level default (administrative configuration); `subscriptions.grace_period_days_snapshot` holds the contract-term snapshot taken from the tenant_environment default at subscription activation. **The subscription snapshot value is the authoritative number used by the active contract term** — even if the tenant_environment default is subsequently changed, the live subscription continues to use its snapshot value until renewal, when a new snapshot is taken. Changes to either value follow URS-13 CR. URS-30 dispatches daily reminder during grace. |
| DEC-36-14 | **Mid-Workflow Continuity Shield with bounded transitive child workflow exemption.** A scheduled lifecycle state change (`active → on_hold`, `on_hold → grace`, `grace → expired_read_only`) is held by the Shield if any **in-flight critical workflow** exists on the affected subscription's tenant_environment. **Shield-permitted actions:** (a) completion of in-flight workflows that started before the triggering state change; (b) **causally-linked child workflows** under bounded transitive inheritance. Child workflow record MUST carry: `parent_workflow_id` (immediate parent), `root_workflow_id` (top-most shield-eligible parent), `causal_reason` (free-text justification), `inherited_shield_id` (parent's shield context), `shield_depth` (1 for direct child of shield-eligible parent; 2 for grandchild; 3 for great-grandchild). **Constraints**: `shield_depth ≤ 3` by default. Depths >3 are blocked with `SHIELD_DEPTH_EXCEEDED` unless an explicit case-by-case override is recorded — the override path requires `is_depth_override = true` on the `workflow_shield_inheritance` row, with all four fields populated: `override_source_change_control_id` (URS-13 CR), `override_reason` (free-text justification), `override_executive_e_sig_id`, `override_final_quality_approver_e_sig_id`. DB CHECK constraint enforces atomicity (cannot record depth >3 without all override fields populated). **No cycles**: `root_workflow_id` MUST be unique up the chain; a workflow MAY NOT appear as both ancestor and descendant in the same shield chain (cycle detection enforced at creation; `SHIELD_CYCLE_DETECTED` on violation). **Shield-blocked actions:** new independent regulated workflows (no causal link); child workflows whose declared `(parent_module, parent_state) → child_module` mapping is not present in `workflow_dependency_declarations`. Shield-eligible *root* parent workflows: URS-23 batch in QP-release / staged-review; URS-15 OOS investigation Phase IA/IB/II; URS-27 recall in execution; URS-22 inspection in back-room-active; URS-31 DQG filing in flight; URS-18 CAPA effectiveness pending. State during shield wait: `shielded_expiry_pending`. URS-13-controlled. |
| DEC-36-15-EMG | **Emergency Inspector Access (Break-Glass) for unannounced inspections — escalation model, not auto-revoke.** Trigger: pre-authorized `inspection_grantor_authority` (customer-side; NOT any executive_authority — must be specifically pre-authorized for break-glass grants) initiates emergency inspector access on regulator arrival. Required capture: (a) regulator name + agency + agency reference ID + badge / credential evidence URL or hash; (b) inspection purpose (free text); (c) inspector_user account creation. Default scope: read-only, tenant-environment-bound, RBAC-scoped, audit-logged on every read. Time-bound state machine: **(0h)** access granted; emergency_inspection_grants state = `active_unbound`. **(0h immediate)** URS-30 notification within 5 minutes to customer_account `executive_authority` + Verixa platform admin + RA Head + Founder. **(24h checkpoint)** if no URS-22 inspection_context_id has been bound, state transitions to `binding_overdue_escalated`; access continues; URS-30 escalation to Verixa platform admin + customer_account_admin + Founder. **Access is NOT revoked at 24h.** **(48h checkpoint)** if still unbound, Verixa platform admin MAY (via URS-04 e-sig) create a placeholder URS-22 inspection context (`urs_22_placeholder_reason = emergency_grant_binding_overdue_48h`) and auto-bind the inspector to it; state transitions to `placeholder_bound`. **(72h absolute expiry)** emergency access expires unconditionally; conversion to longer-term access requires planned override path (DEC-36-16) and a normal URS-22 inspection_context. State after expiry: `expired`. **Manual revoke** by `inspection_grantor_authority` or Verixa platform admin permitted at any point: state → `revoked`. Immediate URS-06 audit on grant + every state transition + every read. |
| DEC-36-16 | **Planned Inspection-Mode Override** (distinct from emergency break-glass DEC-36-15-EMG). Pre-approved regulator access during `expired_read_only` state. Dual approval (`inspection_mode_override_authority` Verixa + `executive_authority` customer). 14-day default (renewable via URS-13 CR). URS-22 inspection-context bound BEFORE grant. URS-04 e-sig. Immutable expiry. |
| DEC-36-17 | **Retention-period read-only access.** Post-termination, the customer retains read-only access to all GxP records for the regulatory retention period. Default 10 years; per-jurisdiction configurable via `tenant_environments.retention_years` per URS-08 jurisdiction binding. Data migrates to URS-35 cold storage per DEC-36-32 termination cascade step (7). Access gated by `retention_read_only` license type — separate from active subscription; granted to customer admin + tenant_environment admin for the retention window. |
| DEC-36-18 | **Environment-class change is super_admin + URS-13 CR + migration validation.** Cannot downgrade `validated_production` → `sandbox` or similar without IQ/OQ/PQ revalidation. Environment-class downgrade with regulated records in flight is blocked. |
| DEC-36-19 | **Trial / Pilot licensing.** A `trial` subscription is time-bounded (default 30 days; max 90 days per URS-13 CR), seat-limited (default 5 seats), environment-class-bound (`sandbox` or `validated_test`). Conversion to paid via URS-13 CR with `executive_authority` (customer) + `subscription_admin_authority` (Verixa) co-sign. Trial expiry without conversion auto-transitions to `expired_read_only`. |
| DEC-36-20 | **Channel partner registry.** Per-subscription optional `channel_partner_id` per `subscriptions.channel_partner_id`. Partners are pre-registered via URS-13 CR (`channel_partner_registration` CR type) with discount terms recorded in `channel_partners.discount_terms_jsonb`. Partner-attributed revenue is computed in the usage-and-revenue rollup at customer_account level. |
| DEC-36-21 | **Deployment class.** `tenant_environments.deployment_class` ∈ {`verixa_managed`, `byoc`, `on_premise`}. `verixa_managed` = Verixa hosts in Verixa's cloud account; `byoc` = customer's cloud account, Verixa deploys via IaC + remote management; `on_premise` = customer's data centre, restricted to specified customer profiles per URS-13 CR. BYOC and on-premise variants carry higher unit licensing rates, require additional security agreements per URS-12 (`byoc_security_agreement` / `on_premise_security_agreement` document types), and require `executive_authority` (customer) approval. |
| DEC-36-22 | **Usage metering substrate.** Every metered event (`api_call`, `ai_inference`, `audit_event_write`, `storage_gb_hour`, `batch_record_released`, `document_uploaded`, `regulated_record_created`) emits a row to `usage_records`. Roll-up per period (default daily). Per-tenant_environment overage thresholds emit URS-30 alerts. Per-period roll-up feeds invoice generation. |
| DEC-36-23 | **Billing-provider events isolated from GxP access via `billing_events` queue.** Provider webhooks land in `billing_events` (idempotency-keyed on `(provider, provider_event_id)`). Provider event lifecycle: `received → validated → reconciled → action_pending → action_applied`. Subscription service consumes `action_pending` events via controlled rules; **payment-failed events route to dunning workflow per DEC-36-25, NOT directly to subscription state**. |
| DEC-36-24 | **Tax + FX per jurisdiction + currency.** Tax rates sourced from `tax_rates` cache (provider-fed: Avalara / TaxJar / manual override). Per-jurisdiction rules respected (India GST + SGST/CGST, EU VAT, US sales tax, UK VAT). Tax-exempt status configurable per subscription. Currency on `subscriptions.currency` (INR / EUR / USD / GBP / JPY / CHF / SGD / AUD / CAD / BRL). FX rates locked at invoice issue via `fx_rates` snapshot; consolidation uses locked rates. |
| DEC-36-25 | **Dunning workflow with THREE distinct paths + LEGAL-CONTROLLED disclosure class.** **(a) Routine path** for ordinary payment failure: Day 1 `payment_failed_notice` → Day 7 `dunning_attempt_2` → Day 14 `dunning_attempt_3` → Day 21 `subscription_on_hold` → Day 51 `grace_period` → Day 81 `terminated` (URS-13 CR). **(b) Fast-path commercial hold** for `chargeback` / `fraud_flag` / `contractual_rescission` / `bankruptcy_declared`: immediately on Day 1 → `subscription_on_hold` with executive_authority (Verixa CFO) + `finance_review_authority` co-sign. **(c) Compliance hold path** for `sanctions_violation` / `regulatory_order` / `legal_hold_order`: routes via SEPARATE `compliance_holds` state machine, controlled by `compliance_hold_authority` (Verixa Legal + Executive). NOT part of ordinary dunning. Severities: `temporary_hold` / `permanent_hold` / `full_lockout`. All hold paths trigger Mid-Workflow Continuity Shield. Cure: payment + URS-13 CR (commercial); legal release + URS-13 CR + jurisdictional approval (compliance). **Disclosure class on every hold (NEW; legal-controlled, NOT automatic):** Every hold (commercial + compliance) carries a `disclosure_class` ∈ {`full_disclosure`, `restricted_disclosure`, `internal_only`, `legal_counsel_only`, `restricted_pending_legal_review`}. Default mapping (defaults only — Legal may override per-instance via URS-13 CR): routine commercial hold → `full_disclosure`; chargeback / fraud / rescission / bankruptcy → `restricted_disclosure`; legal_hold_order with secrecy clause → `legal_counsel_only`; sanctions_violation (before legal classification of jurisdiction-specific disclosure obligations) → `restricted_pending_legal_review`. **`disclosure_class` is the canonical gate on URS-30 notification routing**: `full_disclosure` permits customer-facing URS-30 dispatch; `restricted_disclosure` permits customer admin notification only (no broader stakeholder dispatch); `internal_only` blocks all customer-facing notifications (Verixa-internal stakeholders only); `legal_counsel_only` blocks all but Verixa Legal Counsel; `restricted_pending_legal_review` blocks all customer-facing notifications pending Legal classification — Legal MUST classify within 5 business days, post-classification routing follows the classified class. Customer-facing license-state in all restricted/internal/counsel-only/pending cases appears as **generic `subscription_on_hold_contact_support`** with neutral language and no hold-class or hold-reason disclosure; full hold detail is retained in Verixa platform_audit, not in tenant audit visible to customer admin. **The spec does NOT assert "sanctions notification is legally prohibited" as a universal rule** — disclosure obligations are jurisdiction- and order-sensitive, vary by legal regime (US OFAC / EU restrictive measures / India FEMA / UK OFSI / AML SAR-style "tipping off" / etc.), and require per-order Legal classification before routing is finalised. |
| DEC-36-26 | **License-event append-only audit; hash-chain conditional on URS-06 evidence.** Every license event — subscription create / tier change / entitlement toggle / seat allocation / license assignment / license revocation / invoice issue / payment post / dunning step / grace-period entry / expiry transition / termination / inspection-mode override / retention-mode entry / compliance hold / emergency inspection grant / workflow shield inheritance — produces a URS-06 append-only audit row attributable to a named user (customer admin / platform admin / named system-bot for clock-triggered events). Audit-write failure blocks the originating license action via `LICENSE_ACTION_AUDIT_WRITE_FAILED` (HTTP 500; originating action does NOT commit). **Hash-chain integrity claim is conditional on URS-06 implementation evidence proving the hash chain.** Until proven, the substrate is append-only audit only; URS-36 documentation MUST NOT overclaim Part 11 §11.10(e) hash-chain integrity. |
| DEC-36-27 | **License Gate two-layer cache with DB-as-source-of-truth + in-transaction version bump + post-commit Redis outbox + short safety TTL + fail-closed-on-write.** **Source of truth.** The `license_cache_versions` DB table is the authoritative version-stamp registry, keyed on `(tenant_environment_id, subscription_id)`, holding a monotonic `version_stamp` (bigint). The Redis cache is a **replica only**, never the source of truth. **Layer 1 — Per-request memoisation.** Within a single HTTP request, `requireLicense(tenant_environment_id, user_id, module_id, action)` computed at most once. **Layer 2 — Versioned Redis cache.** Cache key embeds the DB `version_stamp`. **Version bump is synchronous and in-transaction.** Any write to subscriptions / entitlements / license-assignments / isolation-model / environment-class / migration-version / compliance-hold MUST bump the `license_cache_versions.version_stamp` row in the SAME database transaction as the underlying write. **Async invalidation is prohibited.** **Post-commit Redis outbox.** Immediately after transaction commit, an outbox pattern (PostgreSQL `LISTEN/NOTIFY` or transactional outbox table consumed by a Redis-update worker) propagates the new stamp to Redis via SETEX. **Safety TTL of 30 seconds** on Redis entries — only as a backstop for Redis-vs-DB inconsistency (network partition between Redis worker and Redis cluster, Redis eviction, Redis restart). The 30s TTL does NOT cover write-to-invalidation lag because invalidation is in-transaction. **Fail-closed-on-write:** for any regulated WRITE action, the gate MUST verify the DB `version_stamp` before permitting the action. If the DB `version_stamp` cannot be verified (DB unreachable, query failed), the write is rejected with `LICENSE_CACHE_VERSION_VERIFICATION_FAILED` (HTTP 503). The gate NEVER permits a regulated write based solely on a Redis hit. **Read-side decisions** may be served from Redis hits when the cached `version_stamp` matches the latest DB stamp; if the cached stamp is older than the DB stamp, the entry is stale and re-evaluation is forced. Latency budget: p95 ≤ 2ms cache hit + DB stamp verify; p95 ≤ 20ms cache miss; p95 ≤ 1ms per-request memoisation hit. |
| DEC-36-28 | **Tier change → URS-13 CR + regulatory-impact assessment.** Every tier change is a URS-13 record with: business justification, financial impact (ARR delta, currency, effective date), contractual amendment doc (URS-12 `subscription_amendment`), customer signatory + Verixa signatory e-sig, module-entitlement diff, seat-ceiling diff. Downgrade with entitlement decrease requires regulatory-impact assessment (potential GxP coverage gap); if in-flight regulated records depend on disabled modules, downgrade is blocked with `TIER_DOWNGRADE_IN_FLIGHT_WORKFLOW_BLOCK`. |
| DEC-36-29 | **Isolation-model change → URS-13 CR + migration plan.** Every isolation-model change (e.g., Option B → Option C upgrade) is a URS-13 record with migration plan (URS-12 `isolation_change_plan` doc), downtime window, `isolation_model_admin_authority` (Verixa) + `executive_authority` (customer) dual e-sig, data-region validation, KMS rebinding plan, backup-policy re-binding plan, post-migration validation evidence. Isolation downgrade on a `validated_production` subscription requires regulatory-impact assessment. |
| DEC-36-30 | **SoD additions to URS-05 catalogue.** SOD-36-01: `subscription_admin_authority` ∩ `billing_admin_authority` = ∅. SOD-36-02: License assigner ≠ License revoker per `license_assignments.assigned_by_user_id` ≠ `revoked_by_user_id`. SOD-36-03: Customer admin cannot self-assign Authority-Profile-tied seat. SOD-36-04: Verixa platform admin cannot self-approve subscription modification (dual-approval required). SOD-36-05: `subscription_admin_authority` cannot also be `executive_authority` for the customer they manage. SOD-36-06: `inspection_grantor_authority` (customer-side, pre-authorized for break-glass) MUST be a distinct user from `contract_signatory_authority` (customer-side) — break-glass grant cannot be made by the user who signed the contract. SOD-36-07: `compliance_hold_authority` ∩ `subscription_admin_authority` = ∅ (compliance hold is legal/regulatory, not commercial). |
| DEC-36-31 | **Reason-for-Change mandatory** on every license-state-changing action: tier change, entitlement toggle, seat re-allocation, license assignment, license revocation, contract amendment, grace-period extension, inspection override, isolation change, environment-class change, data-region change, KMS rotation, manual subscription state transition. Missing reason → 400 `REASON_REQUIRED`. |
| DEC-36-32 | **Termination cascade per tenant_environment.** Ordered steps: (1) revoke all active license assignments → `archived`; (2) suspend all sessions for the tenant_environment's users (URS-01 hook); (3) suspend integrations (URS-30 outbound channels paused); (4) freeze writes (URS-08 freeze flag); (5) issue final invoice + payment reconciliation; (6) initiate retention-period read-only transition with effective-from = termination_date + 1 day; (7) seal append-only audit snapshot (URS-06 `HASH_CHAIN_SEAL_TERMINATION` event); (8) migration to cold storage per URS-35. Ordered execution; no step may be skipped. |
| DEC-36-33 | **Renewal cadence.** 90 / 60 / 30 / 15 / 3 / 1 day URS-30 reminders before `effective_to`. 30 days before: `active → renewing`. Auto-renewal flag (`auto_renew`) per subscription; default `false` for Enterprise + Custom; default `true` for Starter + Pro (with 30-day opt-out window). On counter-signature + payment: state returns to `active` with new `effective_from` / `effective_to`. On non-renewal at `effective_to`: grace-period begins (DEC-36-13). |
| DEC-36-34 | **Multi-year contracts.** A subscription may have a contract term of up to 5 years (URS-13 CR for extensions beyond default 1-year). Multi-year contracts carry billing schedule (annual / semi-annual / quarterly / monthly) recorded in `subscriptions.billing_schedule`. Multi-year discount logic recorded in `plans.multi_year_discount_jsonb`. |
| DEC-36-35 | **Tier-aware feature flags.** Each module may declare feature flags conditional on tier (e.g., `mira_advanced_reasoning` requires `enterprise` or `custom`; `multi_jurisdiction_export` requires `pro` or higher). Feature flags evaluated at the License Gate; rejected actions return `LICENSE_TIER_INSUFFICIENT`. Feature flags recorded in `module_entitlements.feature_flags_jsonb`. |
| DEC-36-36 | **Migration version mismatch blocks regulated writes per tenant_environment.** If `tenant_environments.migration_version` ≠ platform version on a regulated-write attempt, gate rejects with `MIGRATION_VERSION_MISMATCH` (HTTP 503) until tenant_environment migration completes. Read access continues unimpeded. |
| DEC-36-37 | **Tenant + tenant_environment + initial subscription atomic create.** `POST /customer-accounts` may bootstrap initial tenant_environment + initial subscription atomically. Subsequent `POST /tenant-environments/by-customer/:caid` adds environments. Subsequent `POST /subscriptions/by-environment/:teid` adds subscriptions to existing environments. Provisioning runs asynchronously; subscription cannot transition to `active` until parent tenant_environment is `provisioning_status = active` AND `validation_status = validated`. |
| DEC-36-38 | **Workflow dependency declaration (DEC-36-14 support).** Platform configuration table `workflow_dependency_declarations` with rows `(parent_module_id, parent_state, permitted_child_module_id, permitted_child_actions_jsonb, causal_reason_required: bool, effective_from, effective_to, source_change_control_id, created_e_sig_id)`. Versioned; super_admin + URS-13 CR controlled. Examples at launch: `(URS-23, qp_certification_in_progress) → URS-16 deviation create`; `(URS-15, phase_ia) → URS-16 deviation create`; `(URS-27, recall_in_execution) → URS-14 complaint create + URS-16 deviation create`; `(URS-22, back_room_active) → URS-21 finding create`. |

---

## 4. Roles & Authority Profiles

New Authority Profiles to be registered in the URS-05 catalogue (16 total):

| Authority Profile | Scope | Purpose |
|---|---|---|
| `super_admin` (existing role) | Verixa-internal | Plan catalogue, isolation model catalogue, permissibility map, module entitlement schema. |
| `platform_admin` (existing role) | Verixa-internal | Subscription provisioning; channel partner config; tax + currency config. |
| `subscription_admin_authority` | Verixa-internal | Create/amend subscriptions; tier change; seat ceiling change; entitlement toggle (with URS-13 CR). **Mutually exclusive with `billing_admin_authority`** per SOD-36-01. |
| `billing_admin_authority` | Verixa-internal | Issue invoices; post payments; process refunds; execute dunning. **Mutually exclusive with `subscription_admin_authority`** per SOD-36-01. |
| `entitlement_admin_authority` | Verixa-internal | Toggle module entitlements (with URS-13 CR). |
| `isolation_model_admin_authority` | Verixa-internal | Change tenant_environment isolation_model (with URS-13 CR + migration plan); manage Plan ↔ Isolation Permissibility Map. |
| `tenant_provisioning_authority` | Verixa-internal | Execute tenant_environment provisioning state machine; run migrations per schema / per DB; bind backup policies; bind KMS keys; configure data-region routing. |
| `data_region_admin_authority` | Verixa-internal | Change data region (with URS-13 CR + migration plan); validate jurisdictional bindings. |
| `kms_key_admin_authority` | Verixa-internal | Bind / rotate / change KMS key mode and ref. |
| `inspection_mode_override_authority` | Verixa-internal | Grant planned inspection-mode override per DEC-36-16 (with `executive_authority` customer co-sign). |
| `contract_signatory_authority` (Verixa-side) | Verixa-internal | Sign subscription contracts on Verixa's behalf. |
| `contract_signatory_authority` (Customer-side) | Customer-side | Sign subscription contracts on customer's behalf (typically customer CFO or COO). |
| `customer_account_admin_authority` | Customer-side | Customer's account-level admin for the parent `customer_accounts` row — manages MSA, billing rollup, channel-partner relationship. Distinct from per-environment customer admin. |
| `tenant_environment_admin_authority` | Customer-side | Per-environment customer admin — assigns licenses within the environment's subscription, manages users for that environment. Per-environment scoped. |
| `license_assignment_authority` | Customer-side | Assigns named-user licenses within the seat ceiling. Delegable from `customer_account_admin_authority` or `tenant_environment_admin_authority` with time bounds. |
| `license_revocation_authority` | Customer-side | Revokes / suspends named-user licenses. **SoD: revoker ≠ assigner** per SOD-36-02. |
| `finance_review_authority` | Verixa-internal | Financial sign-off on tier changes, refunds, write-offs, late renewal, pricing concessions. |
| `inspection_grantor_authority` | Customer-side | Pre-authorized customer-side user permitted to invoke DEC-36-15-EMG break-glass emergency inspector grants. Distinct from contract_signatory_authority per SOD-36-06. Typically the customer's QA Head or Site Head. Not delegable. |
| `compliance_hold_authority` | Verixa-internal | Authorizes compliance holds (sanctions / regulatory order / legal hold). Mutually exclusive with subscription_admin_authority per SOD-36-07. Requires Verixa Legal Counsel + Executive co-sign for permanent holds. Not delegable. |
| `executive_authority` (existing) | Customer-side | Founder approval for: high-value contract amendments above ARR threshold; late renewal exits from expired_read_only; on-premise deployment approvals; inspection-mode override co-sign. |
| `inspector_authority` (existing) | Regulator / Inspector | Read-only access scoped per DEC-36-15 / DEC-36-15-EMG / DEC-36-16; never seat-counted; never tenant-isolation-bypassing. |

SoD constraints (additions to URS-05 SoD set; canonical list per DEC-36-30):

- SOD-36-01: `subscription_admin_authority` ∩ `billing_admin_authority` = ∅
- SOD-36-02: License assigner ≠ License revoker (`license_assignments.assigned_by_user_id` ≠ `revoked_by_user_id`)
- SOD-36-03: Customer admin cannot self-assign Authority-Profile-tied seat
- SOD-36-04: Verixa platform admin cannot self-approve subscription modification (dual-approval required)
- SOD-36-05: `subscription_admin_authority` cannot also be `executive_authority` for the customer they manage
- SOD-36-06: `inspection_grantor_authority` (customer-side) ≠ `contract_signatory_authority` (customer-side) — break-glass cannot be granted by the contract signatory
- SOD-36-07: `compliance_hold_authority` ∩ `subscription_admin_authority` = ∅

---

## 5. Worked Examples

### 5.1 Worked Example A — Customer onboard with production + test + sandbox environments

**Scenario.** Aeonn Health onboards. Three environments needed: `aeonn-prod` (validated_production), `aeonn-test` (validated_test), `aeonn-sandbox` (sandbox).

**Sequence.**
1. `POST /api/v1/customer-accounts` creates `customer_account` `CA-2026-0041` (parent commercial entity).
2. `POST /api/v1/tenant-environments/by-customer/CA-2026-0041` creates three tenant_environments: `aeonn-prod`, `aeonn-test`, `aeonn-sandbox`. Each with its own `isolation_model` (Option B for prod; Option B for test; Option B for sandbox — all per Permissibility Map for Enterprise plan), `data_region = ap-south-1`, `kms_key_mode = shared_platform_key`, distinct `tenant_schema` per environment.
3. Provisioning runs in parallel for the three environments. Each runs `CREATE SCHEMA tenant_aeonn_prod` / `tenant_aeonn_test` / `tenant_aeonn_sandbox`, applies migrations, binds audit, configures backup, binds KMS, configures routing.
4. Validation pack runs per environment. `aeonn-prod` requires full IQ/OQ/PQ — takes longer. `aeonn-test` requires reduced validation. `aeonn-sandbox` skips validation (no GxP records).
5. As each environment reaches `provisioning_status = active` AND `validation_status >= validated` (for validated_* classes), its subscription can transition `draft → quote_pending → active`.
6. `aeonn-prod` activates first under Subscription `SUB-2026-0041-PROD` (Enterprise plan, 200 general + 12 QP seats, validated_production, INR currency).
7. `aeonn-test` activates under Subscription `SUB-2026-0041-TEST` (Pro plan, 50 seats, validated_test, INR, $50K/year).
8. `aeonn-sandbox` activates under Subscription `SUB-2026-0041-SBX` (Starter trial, 10 seats, sandbox, no charge for 90 days).
9. Customer-level consolidated invoice rolls up at `CA-2026-0041` level.
10. Anand attempts to create a deviation in production. Pipeline (per §0.5): authenticate → environmentScope (`X-Env-Id: aeonn-prod` resolved → tenant_environment_id) → tenantScope (`SET search_path = tenant_aeonn_prod`) → context → RBAC → License Gate (subscription SUB-PROD active ✓, env validated_production ✓, named-user license active ✓, URS-16 module entitled ✓) → handler.

### 5.2 Worked Example B — Causally-linked child workflow under Shield

**Scenario.** Aeonn `aeonn-prod` subscription is in `shielded_expiry_pending`. Priya is in QP release of Batch VRX-25-A-00417. During final review she discovers an unrecorded deviation in the IPC log.

**Sequence.**
1. Priya invokes `POST /api/v1/deviations` with `parent_workflow_id = batch_VRX-25-A-00417_qp_release`, `causal_reason = unrecorded_ipc_deviation_during_qp_review`.
2. License Gate evaluates: env = `aeonn-prod`, subscription state = `shielded_expiry_pending`, action = URS-16 create.
3. Shield consults `workflow_dependency_declarations`: finds `(URS-23, qp_certification_in_progress) → URS-16 deviation create` permitted with `causal_reason_required = true`. Causal reason supplied.
4. Shield verifies parent workflow is active and in declared state: `batch_VRX-25-A-00417` is in `qp_certification_in_progress`. ✓
5. Child deviation created with `inherited_shield_id` linking to parent's shield context. URS-06 audit emitted.
6. If Priya attempted to create a deviation NOT linked to the batch (a new unrelated investigation), Shield would reject with `SHIELDED_NEW_INDEPENDENT_WORKFLOW_BLOCKED`.

### 5.3 Worked Example C — Emergency inspector access (break-glass)

**Scenario.** Unannounced MHRA inspector arrives at Aeonn Hyderabad. Aeonn QA Head is the pre-authorized `inspection_grantor_authority` (and is distinct from the contract signatory Aeonn CFO).

**Sequence.**
1. QA Head invokes `POST /api/v1/emergency-inspection-grants` with: regulator_name = `Dr. James Whitaker`, agency = `MHRA`, agency_reference_id = `MHRA-INS-2026-0142`, credential_evidence_url = `s3://aeonn-attachments/2026/inspector-badge.jpg`, inspection_purpose = `unannounced GMP inspection Hyderabad`.
2. URS-04 e-sig captured. URS-06 audit emitted.
3. Inspector account `inspector-mhra-0142` created bound to `inspector_authority`, scoped to tenant_environment `aeonn-prod`, read-only, state = `active_unbound`, 72-hour absolute expiry.
4. URS-30 notification dispatched (within 5 minutes): customer_account `executive_authority` (Vimal), Verixa platform admin, RA Head, Founder.
5. Inspector logs in immediately. Every read URS-06 audited.
6. **Escalation timeline (per DEC-36-15-EMG; access is never auto-revoked at 24h or 48h):**
   - **0–24h:** QA Head expected to create the URS-22 inspection context and bind `inspector-mhra-0142`. If bound: state → `bound_to_urs_22`; access continues to 72h absolute expiry.
   - **24h reached unbound:** state → `binding_overdue_escalated`; access CONTINUES; URS-30 escalation dispatched to Verixa platform admin + customer_account_admin + Founder. (Scenario covers Friday-afternoon and weekend cases where QA Head is unavailable.)
   - **48h reached unbound:** Verixa platform admin MAY (with URS-04 e-sig) auto-create a placeholder URS-22 context (`urs_22_placeholder_reason = emergency_grant_binding_overdue_48h`) and bind the inspector to it; state → `placeholder_bound`; access continues.
   - **72h absolute expiry:** access auto-revokes unconditionally; state → `expired`. Longer-term access requires conversion to planned override (DEC-36-16) with its own dual-approval requirement and a normal URS-22 inspection context.
7. Manual revoke remains available at any point to `inspection_grantor_authority` or Verixa platform admin.

### 5.4 Worked Example D — Fast-path dunning (chargeback)

**Scenario.** Aeonn's Stripe webhook reports a chargeback on Invoice `INV-2026-0041-H2`.

**Sequence.**
1. Stripe webhook arrives. `billing_events` row created with `provider_event_id = ch_xxx`, `event_type = chargeback`.
2. Adapter validates signature. `billing_events.status = validated`.
3. Subscription service consumes event. Detects `event_type = chargeback` → fast-path commercial hold per DEC-36-25(b).
4. Action: `subscription_on_hold` transition queued. Verixa CFO (`finance_review_authority`) + Verixa executive (`executive_authority`) confirmation required (dual e-sig).
5. On confirmation: subscription state `active → subscription_on_hold`. Mid-Workflow Shield activates: in-flight critical workflows continue under Shield; new independent workflows blocked.
6. URS-30 notifications: Aeonn customer_account_admin + Verixa account manager.
7. Cure: chargeback reversal + payment received → subscription_on_hold → active.

### 5.5 Worked Example E — Compliance hold (sanctions)

**Scenario.** US OFAC adds a parent company to the sanctioned-entity list; Aeonn is identified as a subsidiary.

**Sequence.**
1. `compliance_hold_authority` (Verixa Legal + Executive) invokes `POST /api/v1/compliance-holds` with `hold_type = sanctions_violation`, `severity = permanent_hold` (writes blocked + reads only via inspection/legal channels), `legal_basis_document_id` (URS-12), `tenant_environments_affected = [aeonn-prod, aeonn-test, aeonn-sandbox]`.
2. URS-04 dual e-sig (Legal + Executive). URS-06 audit.
3. All three affected subscriptions transition to `subscription_on_hold` with `hold_class = compliance_permanent`. Mid-Workflow Shield still applies for graceful in-flight workflow completion.
4. Customer's regulated writes blocked. Reads only permitted via planned inspection-mode override (DEC-36-16) for legal/regulatory parties.
5. Cure: NOT possible from customer-side. Hold released only by Verixa Legal + Executive + URS-13 CR with legal-basis-of-release document. On release: subscriptions return to prior state.

---

## 6. State Machines

### 6.1 Subscription Lifecycle

```
draft
   ↓ submit_quote
quote_pending
   ↓ countersign (customer)
   ↓ countersign (verixa)
active
   ↓ renewal_triggered (90d before effective_to)
renewing
   ↓ renewal_signed → active (new term)
   ↓ renewal_lapsed → grace_period
   ↓ on_hold_triggered (routine_dunning_day_21 | fast_path_commercial | compliance_hold) → subscription_on_hold
subscription_on_hold
   ↓ cure_payment_received → active
   ↓ cure_legal_release → active (for compliance holds; URS-13 CR)
   ↓ on_hold_lapsed_to_grace → grace_period
   ↓ on_hold_lapsed_to_expired (rare; only if shield permits) → expired_read_only
grace_period
   ↓ late_renewal_signed → active
   ↓ grace_lapsed (in-flight workflows) → shielded_expiry_pending
   ↓ grace_lapsed (no in-flight) → expired_read_only
shielded_expiry_pending
   ↓ all_in_flight_completed → expired_read_only
   ↓ late_renewal_signed → active
expired_read_only
   ↓ late_renewal_signed (executive + finance_review) → active
   ↓ termination_triggered (URS-13 CR) → terminated
terminated
   ↓ retention_period_begin → retention_read_only (URS-35 cold storage)
   ↓ retention_period_end → archived_sealed
```

### 6.2 Tenant Environment Provisioning State

```
pending
   ↓ start_provisioning (tenant_provisioning_authority)
provisioning
   ↓ provisioning_completed → provisioned
   ↓ provisioning_failed → provisioning_failed
provisioned
   ↓ validation_pack_started → validation_pending
validation_pending
   ↓ validation_passed → active
   ↓ validation_failed → provisioning_failed
provisioning_failed
   ↓ remediation_complete → pending (retry)
   ↓ abandon → decommissioned
active
   ↓ decommission_triggered → decommissioned
decommissioned (terminal)
```

### 6.3 License-Assignment Lifecycle (per DEC-36-12)

```
unassigned
   ↓ assign (license_assignment_authority + e-sig)
assigned
   ↓ user_first_login → active
   ↓ rescind_before_login → unassigned
active
   ↓ suspend (license_revocation_authority + e-sig; SoD: revoker ≠ assigner)
suspended
   ↓ reinstate → active
   ↓ revoke → revoked
   ↓ revoke (license_revocation_authority + e-sig; SoD) [from active]
revoked
   ↓ reassign_seat → reassigned (new user)
   ↓ archive → archived
reassigned
   ↓ becomes_active → active
archived (terminal)
```

### 6.4 Invoice Lifecycle

```
draft → issued → (paid | overdue) → reconciled | written_off | refunded
```

### 6.5 Billing Event Lifecycle (per DEC-36-23)

```
received → validated → reconciled → action_pending → action_applied
```

`action_applied` may emit `dunning_events` rows or trigger compliance-hold review; it never directly mutates subscription state — the subscription service consumes `action_pending` events via controlled rules per DEC-36-23.

### 6.6 Compliance Hold State Machine

```
proposed (compliance_hold_authority)
   ↓ legal_evidence_attached + dual_e_sig (Legal + Executive)
active_temporary_hold
   ↓ legal_release (URS-13 CR; Legal + Executive) → released
   ↓ severity_escalation → active_permanent_hold
   ↓ severity_escalation → active_full_lockout

active_permanent_hold
   ↓ legal_release (URS-13 CR; Legal + Executive) → released

active_full_lockout (terminal-until-released)
   ↓ legal_release (URS-13 CR; Legal + Executive; jurisdictional approval) → released

released (terminal)
```

---

## 7. Data Model

### 7.1 Canonical Tables

| Table | Purpose | Core columns | Uniqueness | Lifecycle | Retention | Indexed |
|---|---|---|---|---|---|---|
| `customer_accounts` | Commercial parent entity | `id`, `customer_legal_name`, `display_name`, `parent_company_jsonb`, `commercial_msa_document_id` (FK URS-12), `consolidated_billing_currency`, `channel_partner_id` (nullable), `account_admin_authority_user_id`, `effective_from`, `effective_to` (nullable), `created_e_sig_id` | unique(`id`) | versioned | retain (long-term) | yes |
| `tenant_environments` | Per-environment isolation + provisioning. **Multiple environments per `environment_class` permitted** (e.g., a large customer may run `aeonn-prod-hyd` + `aeonn-prod-pune` both as `validated_production` for different sites). | `id`, `customer_account_id` (FK), `tenant_id` (FK URS-08), `environment_slug` (e.g., `aeonn-prod-hyd`; unique per customer_account), `environment_class` (`validated_production`/`validated_test`/`sandbox`/`demo`), `isolation_model`, `tenant_schema` (nullable; populated for B/B+/D-shared), `db_instance_ref` (nullable; populated for C/D-dedicated), `data_region`, `kms_key_mode`, `kms_key_ref`, `backup_policy_ref`, `tenant_environment_provisioning_status` (per §6.2), `migration_version`, `validation_status`, `retention_years`, **`default_grace_period_days`** (tenant-environment-level administrative default per DEC-36-13; min 14 / default 30 / max 90), `created_e_sig_id` | unique(`customer_account_id`, `environment_slug`) — environment_class is NOT in the unique constraint, permitting multiple environments of the same class | stateful | retain (long-term) | yes |
| `subscriptions` | Per-environment per-term contract | `id`, `tenant_environment_id` (FK), `plan_id` (FK), `commercial_plan`, `state` (DEC-36-11), `effective_from`, `effective_to`, `currency`, `billing_schedule`, `auto_renew`, `seat_ceiling_general`, `seat_ceiling_authority_jsonb`, `cap_policy_jsonb`, `jurisdictions_jsonb`, **`grace_period_days_snapshot`** (snapshot of `tenant_environments.default_grace_period_days` taken at subscription activation; this is the authoritative value for the active contract term per DEC-36-13), `superseded_by_id`, `created_e_sig_id`, `customer_signatory_e_sig_id`, `verixa_signatory_e_sig_id` | PostgreSQL exclusion constraint: `EXCLUDE USING gist (tenant_environment_id WITH =, tstzrange(effective_from, effective_to) WITH &&)` filtered to active subscription states — no overlapping active contract date ranges per tenant_environment | versioned | retain (long-term) | yes |
| `plans` | Verixa-global commercial plan catalogue | `id`, `commercial_plan` (`starter`/`pro`/`enterprise`/`custom`), `default_module_set_jsonb`, `default_seat_ceiling`, `default_authority_seats_jsonb`, `default_cap_policy_jsonb`, `default_environment_class_options_jsonb`, `pricing_jsonb`, `multi_year_discount_jsonb`, `effective_from`, `effective_to`, `created_e_sig_id` | unique(`id`) | versioned | retain (long-term) | yes |
| `plan_isolation_permissibility` | Plan ↔ Isolation Permissibility Map per DEC-36-03 | `id`, `commercial_plan`, `isolation_model`, `permitted` (bool), `environment_class_constraint_jsonb`, `effective_from`, `effective_to`, `source_change_control_id`, `created_e_sig_id` | unique active(`commercial_plan`, `isolation_model`) | versioned | retain (long-term) | yes |
| `module_entitlements` | Per-subscription per-module on/off | `id`, `subscription_id` (FK), `module_id`, `enabled`, `effective_from`, `effective_to`, `tier_required` (nullable), `feature_flags_jsonb`, `source_change_control_id`, `created_e_sig_id` | unique active(`subscription_id`, `module_id`) | versioned | retain (long-term) | yes |
| `seat_allocations` | Seat ceiling vs consumption per seat_class | `id`, `subscription_id` (FK), `seat_class`, `ceiling`, `consumed`, `soft_cap_threshold`, `hard_cap_threshold`, `last_recomputed_at` | unique(`subscription_id`, `seat_class`) | computed | retain (long-term) | yes |
| `license_assignments` | Per-user license assignment | `id`, `subscription_id` (FK), `user_id` (FK URS-02), `seat_class`, `module_scope_jsonb`, `state` (DEC-36-12), `assigned_by_user_id`, `assigned_e_sig_id`, `revoked_by_user_id` (SoD: ≠ assigner), `revoked_e_sig_id`, `assigned_at`, `revoked_at`, `reassigned_from_id` (nullable) | unique active(`subscription_id`, `user_id`, `seat_class`) | stateful | retain (long-term) | yes |
| `usage_records` | Immutable per-event usage capture | `id`, `subscription_id` (FK), `event_type` (`api_call`/`ai_inference`/`audit_event_write`/`storage_gb_hour`/`batch_record_released`/`document_uploaded`/`regulated_record_created`), `event_count`, `event_metadata_jsonb`, `event_timestamp`, `roll_up_period` | append-only | append-only | retain (cold after 24mo) | yes |
| `invoices` | Per-period invoice | `id`, `subscription_id` (FK), `period_from`, `period_to`, `state` (per §6.4), `subtotal`, `tax_jsonb`, `total`, `currency`, `fx_rate_locked`, `due_at`, `paid_at` (nullable), `provider_invoice_id`, `issued_e_sig_id` | unique(`subscription_id`, `period_from`) | stateful | retain (long-term) | yes |
| `payments` | Per-payment record | `id`, `invoice_id` (FK), `amount`, `currency`, `payment_method`, `provider_payment_id`, `received_at`, `posted_e_sig_id` | unique(`provider_payment_id`) | append-only | retain (long-term) | yes |
| `dunning_events` | Dunning step register | `id`, `invoice_id` (FK), `step` (per DEC-36-25), `triggered_at`, `urs_30_event_id`, `escalation_chain_jsonb` | append-only | append-only | retain (long-term) | yes |
| `channel_partners` | Reseller / SI registry | `id`, `partner_name`, `partner_type`, `discount_terms_jsonb`, `registration_doc_id` (FK URS-12), `effective_from`, `effective_to`, `created_e_sig_id` | unique(`id`) | versioned | retain (long-term) | yes |
| `tax_rates` | Per-jurisdiction tax rate cache | `id`, `jurisdiction`, `rate_type` (`gst`/`vat`/`sales_tax`/`sut`), `rate_pct`, `effective_from`, `effective_to`, `source_provider` | unique(`jurisdiction`, `rate_type`, `effective_from`) | versioned | retain (long-term) | yes |
| `fx_rates` | FX rate lock-on-issue | `id`, `from_currency`, `to_currency`, `rate`, `effective_on` | unique(`from_currency`, `to_currency`, `effective_on`) | append-only | retain (long-term) | yes |
| `license_audit_events` | Append-only license-event shadow (canonical in URS-06) | mirrors URS-06 with `event_class = licensing` | append-only | append-only | retain (long-term) | yes |
| `billing_events` | Provider event queue with fast-path classification | `id`, `subscription_id`, `provider`, `provider_event_id`, `event_type`, `fast_path_classification` (nullable: `chargeback`/`fraud_flag`/`contractual_rescission`/`bankruptcy_declared`/`sanctions_referral`/null=routine), `payload_jsonb`, `status` (DEC-36-23), `received_at`, `validated_at`, `reconciled_at`, `action_applied_at` | unique(`provider`, `provider_event_id`) | stateful | retain (long-term) | yes |
| `compliance_holds` | Compliance hold registry | `id`, `tenant_environments_affected_jsonb` (array of tenant_environment_ids), `hold_type` (`sanctions_violation`/`regulatory_order`/`legal_hold_order`), `severity` (`temporary_hold`/`permanent_hold`/`full_lockout`), `disclosure_class` (`full_disclosure`/`restricted_disclosure`/`internal_only`/`legal_counsel_only`/`restricted_pending_legal_review`), `disclosure_classified_at` (nullable; populated when Legal classifies `restricted_pending_legal_review` into a concrete class), `disclosure_classified_by_user_id` (nullable), `state` (per §6.4), `legal_basis_document_id` (FK URS-12), `proposed_by_user_id`, `legal_co_sign_e_sig_id`, `executive_co_sign_e_sig_id`, `effective_from`, `released_at` (nullable), `release_legal_basis_document_id` (nullable), `release_e_sig_id` (nullable) | unique(`id`) | stateful | retain (long-term) | yes |
| `emergency_inspection_grants` | Break-glass inspector access registry | `id`, `tenant_environment_id` (FK), `inspector_user_id` (FK URS-02; created at grant time), `grantor_user_id` (FK; bound to `inspection_grantor_authority`), `regulator_name`, `agency`, `agency_reference_id`, `credential_evidence_url`, `inspection_purpose`, `granted_at`, `escalation_at_24h` (= granted_at + 24h), `placeholder_eligible_at_48h` (= granted_at + 48h), `absolute_expiry_at_72h` (= granted_at + 72h), `state` (`active_unbound` / `binding_overdue_escalated` / `placeholder_bound` / `bound_to_urs_22` / `expired` / `revoked`), `urs_22_inspection_context_id` (nullable; populated when bound — either by `inspection_grantor_authority` within 24h or by platform admin via placeholder at 48h), `urs_22_placeholder_reason` (nullable; populated only when placeholder context auto-created at 48h), `urs_22_bound_at` (nullable), `urs_22_placeholder_created_by_platform_admin_id` (nullable; populated only for 48h placeholder), `urs_22_placeholder_e_sig_id` (nullable), `revoked_at` (nullable), `revocation_reason` (`72h_absolute_expiry` / `manual_revoke` / `escalated_to_planned_override`), `granted_e_sig_id` | unique(`id`) | stateful | retain (long-term) | yes |
| `inspection_mode_overrides` | Planned inspection override (DEC-36-16) | `id`, `tenant_environment_id` (FK), `inspector_user_id` (FK URS-02), `inspection_context_id` (FK URS-22; pre-bound), `granted_by_platform_admin_id`, `customer_co_sign_e_sig_id` (executive_authority customer-side), `verixa_co_sign_e_sig_id` (inspection_mode_override_authority), `effective_from`, `effective_to` (default = effective_from + 14 days; renewable via URS-13 CR), `scope_jsonb`, `revoked_at` (nullable), `revocation_reason` (nullable) | unique(`id`) | stateful | retain (long-term) | yes |
| `workflow_dependency_declarations` | DEC-36-38 platform configuration | `id`, `parent_module_id`, `parent_state`, `permitted_child_module_id`, `permitted_child_actions_jsonb`, `causal_reason_required`, `max_depth_permitted` (default 3 per DEC-36-14), `effective_from`, `effective_to`, `source_change_control_id`, `created_e_sig_id` | unique active(`parent_module_id`, `parent_state`, `permitted_child_module_id`) | versioned | retain (long-term) | yes |
| `workflow_shield_inheritance` | Per-child-workflow shield inheritance trail (supports DEC-36-14 transitive inheritance + cycle detection) | `id`, `child_workflow_id`, `child_module_id`, `parent_workflow_id`, `root_workflow_id`, `causal_reason`, `inherited_shield_id`, `shield_depth` (integer; 1..3 by default; >3 only with override fields populated below), `is_depth_override` (bool; default false; true only when `shield_depth > 3`), `override_source_change_control_id` (nullable; required when `is_depth_override = true`), `override_reason` (nullable; required when `is_depth_override = true`), `override_executive_e_sig_id` (nullable; required when `is_depth_override = true`), `override_final_quality_approver_e_sig_id` (nullable; required when `is_depth_override = true`), `created_at` | unique(`child_workflow_id`); CHECK constraint: `(shield_depth <= 3 AND is_depth_override = false) OR (shield_depth > 3 AND is_depth_override = true AND override_source_change_control_id IS NOT NULL AND override_reason IS NOT NULL AND override_executive_e_sig_id IS NOT NULL AND override_final_quality_approver_e_sig_id IS NOT NULL)` | append-only with cycle-detection check at insert | retain (long-term) | yes |
| `license_cache_versions` | Per-tenant_environment per-subscription version stamp — DB source of truth (DEC-36-27) | `tenant_environment_id`, `subscription_id`, `version_stamp` (bigint; monotonic), `last_bumped_at`, `last_bumped_by_event`, `last_bumped_in_transaction_id` | unique(`tenant_environment_id`, `subscription_id`) | computed (in-transaction bump on every state-changing write) | retain (last 30 days hot; rolling archive) | yes |
| `tenant_environment_provisioning_status` | Per-environment provisioning state machine row | One row per tenant_environment (or embedded in `tenant_environments`) | | | | | |

### 7.2 Isolation Routing (per ADR-004; per tenant_environment)

Per ADR-004 isolation model, routing is keyed on `tenant_environment_id`:
- Option B / B+ / D-shared-tier: `SET search_path = <tenant_environments.tenant_schema>, public` set on every connection via TDAL. `tenant_environments.tenant_schema` is the source of truth for routing.
- Option B+: PostgreSQL role per tenant_environment (`tenant_<env_slug>_role`) + RLS policy enabled on every table.
- Option C / D-dedicated-tier: per-tenant-environment dedicated RDS instance routed via `tenant_environments.db_instance_ref` (ARN).
- Option D (hybrid): at connection time, look up the tenant_environment's `isolation_model`; if `OPTION_C_DEDICATED_DB`, route to dedicated; else set `search_path` per Option B.

URS-36 control-plane tables live in platform schema; per-environment data tables live in the per-environment schema/DB.

---

## 8. API Endpoints

### 8.1 Customer Account + Environment + Subscription endpoints

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/customer-accounts` | `platform_admin` + `customer_account_admin_authority` (customer-side e-sig) |
| GET / PATCH | `/api/v1/customer-accounts/:id` | platform_admin / customer_account_admin_authority |
| POST | `/api/v1/tenant-environments/by-customer/:caid` | `platform_admin` + `tenant_provisioning_authority` |
| GET / PATCH | `/api/v1/tenant-environments/:id` | platform_admin / tenant_environment_admin_authority (per env) |
| POST | `/api/v1/tenant-environments/:id/provisioning/start` | `tenant_provisioning_authority` |
| POST | `/api/v1/tenant-environments/:id/provisioning/retry` | `tenant_provisioning_authority` |
| POST | `/api/v1/tenant-environments/:id/isolation-change` | `isolation_model_admin_authority` + URS-13 CR |
| POST | `/api/v1/tenant-environments/:id/environment-class-change` | `super_admin` + URS-13 CR |
| POST | `/api/v1/tenant-environments/:id/data-region-change` | `data_region_admin_authority` + URS-13 CR |
| POST | `/api/v1/tenant-environments/:id/kms-rotation` | `kms_key_admin_authority` + URS-13 CR |
| POST | `/api/v1/subscriptions/by-environment/:teid` | `subscription_admin_authority` |

### 8.2 Emergency Inspector + Compliance Hold endpoints

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/emergency-inspection-grants` | `inspection_grantor_authority` (customer-side; pre-authorized; SoD-36-06) |
| POST | `/api/v1/emergency-inspection-grants/:id/bind-urs-22-context` | `inspection_grantor_authority` or Verixa platform admin |
| POST | `/api/v1/emergency-inspection-grants/:id/revoke` | `inspection_grantor_authority` or Verixa platform admin |
| GET | `/api/v1/emergency-inspection-grants/by-environment/:teid` | tenant_environment_admin_authority |
| POST | `/api/v1/compliance-holds` | `compliance_hold_authority` (Verixa Legal + Executive dual e-sig) |
| POST | `/api/v1/compliance-holds/:id/release` | `compliance_hold_authority` + URS-13 CR + jurisdictional approval |

### 8.3 Workflow Dependency + License Gate endpoints

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/workflow-dependencies` | `super_admin` + URS-13 CR |
| GET | `/api/v1/workflow-dependencies` | service-to-service (Shield consults) |
| POST | `/api/v1/licensing/gate/check` | service-to-service |
| POST | `/api/v1/licensing/cache/redis-evict` | service-to-service. **Redis-only operational endpoint** for Redis warm/evict operations — used by the post-commit outbox worker to propagate the DB-side `license_cache_versions.version_stamp` to Redis, and for operational cache eviction during Redis maintenance. **This endpoint is NOT the source-of-truth invalidation mechanism**; correctness is enforced by DEC-36-27's in-transaction `license_cache_versions` row bump in the same DB transaction as the underlying write. Calling this endpoint without a corresponding DB version-stamp bump has no correctness effect. Idempotent. |
| POST | `/api/v1/licensing/cache/redis-warm` | service-to-service. Redis-only operational endpoint for pre-warming Redis entries from the current DB version stamps. Operational use only. |

### 8.4 All other endpoints

**Entitlement endpoints:**

| Method | Path | Authority |
|---|---|---|
| GET | `/api/v1/entitlements/by-subscription/:id` | customer admin / `entitlement_admin_authority` |
| POST | `/api/v1/entitlements/:id/toggle` | `entitlement_admin_authority` + URS-13 CR (e-sig) |

**License-assignment endpoints:**

| Method | Path | Authority |
|---|---|---|
| GET | `/api/v1/licenses/by-subscription/:id` | customer admin |
| POST | `/api/v1/licenses/assign` | `license_assignment_authority` (e-sig) |
| POST | `/api/v1/licenses/:id/revoke` | `license_revocation_authority` (SoD: distinct from assigner) |
| POST | `/api/v1/licenses/:id/reassign` | `license_assignment_authority` (e-sig) |
| POST | `/api/v1/licenses/:id/suspend` | `license_revocation_authority` (e-sig) |
| POST | `/api/v1/licenses/:id/reinstate` | `license_assignment_authority` (e-sig) |

**Billing + invoice + payment endpoints:**

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/billing/invoices` | `billing_admin_authority` (e-sig) |
| POST | `/api/v1/billing/invoices/:id/post-payment` | `billing_admin_authority` |
| POST | `/api/v1/billing/invoices/:id/refund` | `billing_admin_authority` + `finance_review_authority` co-sign |
| POST | `/api/v1/billing/invoices/:id/write-off` | `finance_review_authority` + `executive_authority` co-sign |
| POST | `/api/v1/billing/webhooks/:provider` | service-to-service (idempotency-keyed per DEC-36-23) |
| POST | `/api/v1/billing/dunning/:invoiceId/advance-step` | system / `billing_admin_authority` |

**Usage endpoints:**

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/usage/records` | service-to-service (batched) |
| GET | `/api/v1/usage/rollup/:subscriptionId` | customer admin / `subscription_admin_authority` |

**Planned inspection override endpoints:**

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/licensing/inspection-overrides` | `inspection_mode_override_authority` (Verixa) + `executive_authority` (customer) dual e-sig per DEC-36-16 |
| POST | `/api/v1/licensing/inspection-overrides/:id/revoke` | as above |
| GET | `/api/v1/licensing/inspection-overrides/by-environment/:teid` | customer admin |

**Channel partner + plan + tax endpoints:**

| Method | Path | Authority |
|---|---|---|
| POST | `/api/v1/plans` | `super_admin` |
| POST | `/api/v1/channel-partners` | `platform_admin` |
| GET / POST | `/api/v1/tax-rates` | `platform_admin` |
| GET | `/api/v1/fx-rates` | service-to-service |
| POST | `/api/v1/plan-isolation-permissibility` | `super_admin` + URS-13 CR |

---

## 9. Frontend Surfaces

### 9.1 Customer-facing surfaces (under `/organization/*`)

- **Organization page** — read-only badge: organization name, environments list (with `environment_class` + region + status badge per env), tier, contract effective dates, deployment class. Replaces customer-facing `/tenants`. Platform-internal fields (`isolation_model`, `tenant_schema`, `db_instance_ref`, `kms_key_ref`) NOT shown.
- **License Allocations page (per environment)** — seat ceiling vs consumed by seat class; assign / revoke / reassign users; SoD-aware UI (revoke action disabled for the same user who assigned).
- **Subscription Status banner (per environment)** — license state (active / renewing / subscription_on_hold / grace_period / shielded_expiry_pending / expired_read_only / terminated); during grace shows days remaining + "Renew now" CTA. For hold states with `disclosure_class ∉ full_disclosure`, displays neutral "Subscription on hold — contact support" label per DEC-36-25.
- **Renewal page** — proposal preview, customer countersign, payment.
- **Module Entitlements page** — read-only view; "Request entitlement change" CTA opens URS-13 CR.
- **Invoices page (consolidated at customer_account)** — list of invoices across environments; status; payment posting; download CSV / PDF.
- **Usage page (per environment)** — current-period usage by event type; overage indicators; URS-30 preferences.

### 9.2 Verixa-internal surfaces (under `/admin/licensing/*`)

- **Customer Account Manager** — list customer_accounts; create new; bind channel_partner.
- **Tenant Environment Manager** — list environments per customer; provision new environment; isolation_model / data_region / kms_key change controls (each URS-13 CR-gated).
- **Subscription Manager** — list subscriptions per environment; create / countersign; tier change; amendment; renewal; late renewal; termination.
- **Plan Catalogue + Plan ↔ Isolation Permissibility Map editor** — super_admin only.
- **Tenant Environment Provisioning Console** — view + retry + remediation for `provisioning_failed`.
- **Isolation Migration Console** — orchestrate Option B → Option C upgrades.
- **Channel Partner Registry**.
- **Emergency Inspection Grant Console** + **Planned Inspection Override Console**.
- **Compliance Hold Console** (gated to `compliance_hold_authority`).
- **Workflow Dependency Declaration editor** (super_admin + URS-13 CR).
- **Dunning Console** — view dunning state across customers.
- **Tax / FX Manager**.
- **Usage Dashboard** — per-environment + customer_account rollup; revenue attribution; overage alerts.
- **License Gate Decision Inspector** — debug surface that replays a gate decision for a given userId / tenant_environment_id / moduleId / action; reads from `license_audit_events`.

### 9.3 Sandbox watermark (per DEC-36-07 / DEC-36-18)

When `tenant_environments.environment_class ∈ {sandbox, demo}`, every page renders a non-dismissable top-of-viewport banner: `SANDBOX — NOT FOR GxP USE. Records here are non-validated, test-data only.` Watermark also applied to every PDF / export artifact.

---

## 10. Cross-Module Integration

| Integration | Direction | Contract |
|---|---|---|
| URS-02 RBAC | URS-02 → URS-36 | After `requirePermission` passes, the route handler MUST call `requireLicense(tenant_environment_id, user_id, module_id, action)`. If license denied, route returns 422 / 423 / 503 with reason code per URS-36 §0.2. |
| URS-04 Workflow / E-Sig | URS-04 ↔ URS-36 | Every subscription / license / entitlement / isolation / environment / region / KMS / compliance-hold / inspection-grant state transition is performed via URS-04 Controlled Approval Modal with e-sig. Dual e-sig for tier change, isolation change, late renewal, planned override, write-off, termination, compliance hold proposal/release. |
| URS-05 Authority Profile / SoD | URS-05 → URS-36 | New Authority Profiles registered per §4. SoD-36-01..07 added to URS-05 SoD set. License assigner ≠ revoker. |
| URS-06 Audit | URS-36 → URS-06 | Every license event append-only audited per DEC-36-26. Hash-chain claim conditional on URS-06 implementation evidence. License-event audit write occurs in the same DB transaction as the underlying state-changing write and the `license_cache_versions` version-stamp bump per DEC-36-27. |
| URS-08 Tenant Lifecycle | URS-08 ↔ URS-36 | Tenant create flows through `POST /api/v1/customer-accounts` per DEC-36-37 (atomic customer_account + tenant_environment + initial subscription). Tenant suspension / termination cascades to DEC-36-32. |
| URS-12 Document Control | URS-36 → URS-12 | Contract docs (MSA / OF / Amendment / BYOC / On-Prem / Isolation-Change-Plan / Region-Change-Plan / KMS-Rotation-Plan / Legal-Basis-of-Hold) stored. |
| URS-13 Change Control | URS-36 → URS-13 | Every tier / entitlement / isolation / environment_class / region / KMS / contract amendment / late renewal / termination / compliance hold classification / compliance hold release / channel partner / plan permissibility / workflow dependency / shield depth override change generates a URS-13 CR. |
| URS-22 Inspection Management | URS-36 ↔ URS-22 | Two inbound binding paths: (a) emergency inspector grant (DEC-36-15-EMG); (b) planned inspection-mode override (DEC-36-16). URS-22 records both `urs_22_inspection_context_id ↔ emergency_inspection_grant_id` and `urs_22_inspection_context_id ↔ inspection_mode_override_id` bindings. Inspector actions during grant/override window are bound into the URS-22 inspection record. |
| URS-23 Batch Records | URS-23 → URS-36 | Shield queries URS-23 for in-flight batches in shield-eligible boundary states (`qp_certification_in_progress`, `staged_review_in_progress`, `final_disposition_pending`). |
| URS-27 Recall Management | URS-27 → URS-36 | Shield queries URS-27 for in-flight recall executions (`recall_in_execution`). |
| URS-28 Training Qualification Gate | URS-28 ↔ URS-36 | Authority-Profile-tied seat consumption requires URS-28 `qualified=true` for the relevant Authority Profile. License Gate consults URS-28 before authority-bound writes. |
| URS-30 Notifications | URS-36 → URS-30 | Renewal cadence (90/60/30/15/3/1d); grace; shield-extension; expiry; overage; routine dunning 3-step; fast-path commercial hold; compliance hold (with `disclosure_class` routing); planned inspection override; emergency inspector grant (24h/48h/72h checkpoints); tier / isolation / region / KMS changes; seat soft/hard cap. |
| URS-31 DQG | URS-31 → URS-36 | Shield queries URS-31 for in-flight DQG filings (`filing_in_flight`). |
| URS-35 Infrastructure | URS-35 ↔ URS-36 | Per-tenant_environment backup policy (`pg_dump -n` for B/B+/D-shared; PITR for C/D-dedicated); data-region routing; KMS binding; cold-storage migration on retention-period entry. |

---

## 11. Change-Impact Matrix (CIM)

| Change | Class | Impact | Revalidation |
|---|---|---|---|
| Add commercial plan tier | 1 | RBAC gate; every consumer module's gate | Full regression |
| Add isolation model option | 1 | TDAL; provisioning engine; every per-tenant query path | Full regression |
| Change Plan ↔ Isolation Permissibility map | 1 | URS-13 CR per affected customer | Full regression |
| Add environment_class option | 1 | License Gate; watermark engine; record_gxp_status enforcement | Full regression |
| Change License Gate API contract | 1 | Every consumer module | Full regression |
| Change Mid-Workflow Shield behaviour | 1 | Every shield-eligible regulated workflow module | Full regression |
| Change isolation model on existing tenant_environment | 1 (per env) | Per-environment migration; URS-13 CR | Full regression on that environment |
| Change data region on existing tenant_environment | 1 (per env) | Per-environment migration; URS-13 CR | Full regression on that environment |
| Change KMS key mode | 1 (per env) | Per-environment rotation; URS-13 CR | Full regression on that environment |
| Change tier default entitlement set | 2 | Per-affected-tenant URS-13 CR | Targeted regression |
| Change default seat ceiling | 2 | Per-affected-tenant URS-13 CR | Targeted regression |
| Change grace period default | 2 | URS-13 CR; URS-30 reminders | Targeted regression |
| Change dunning cadence | 2 | URS-30 templates; finance reporting | Targeted regression |
| Add tax jurisdiction / currency | 3 | tax_rates substrate; invoice generation | Unit regression |
| Add billing provider | 2 | Billing integration substrate | Targeted regression |
| Add channel partner | 3 | channel_partners registry | Unit regression |
| Three-entity model rollout (customer_account / tenant_environment / subscription) | 1 | Every API; every per-tenant query path; every customer-facing surface | Full regression |
| Add `subscription_on_hold` state | 1 | License Gate; Shield; URS-30 templates | Full regression |
| Add fast-path commercial hold | 2 | Dunning; URS-30 templates; finance reporting | Targeted regression |
| Add compliance hold path | 1 | License Gate; Shield; new compliance_holds module | Full regression |
| Add workflow_dependency_declarations | 1 | Shield; every shield-eligible parent workflow module | Full regression |
| Change License Cache strategy | 2 | License Gate; consumer modules; perf benchmarks | Targeted regression |
| Add emergency_inspection_grants module | 1 | URS-22; License Gate; URS-30; URS-06 | Full regression |
| Change inspection_grantor_authority binding | 1 | URS-05; SoD; customer onboarding flow | Full regression |

---

## 12. Risk Register

Risks and mitigations:

| Risk | Severity | Likelihood | Mitigation |
|---|---|---|---|
| Mid-batch lockout disrupts regulated workflow | High | Low (with Shield) | DEC-36-14 Mid-Workflow Continuity Shield; URS-30 alerts; grace-period minimum 14 days |
| Regulator blocked from accessing data during contract dispute | High | Low | DEC-36-15 regulator account exemption; DEC-36-15-EMG emergency break-glass; DEC-36-16 planned override; DEC-36-17 retention-period read-only |
| Seat ceiling raise lags behind business growth | Medium | Medium | DEC-36-10 soft-cap alert + auto URS-13 CR; URS-30 escalation |
| Sandbox subscription mis-classified as validated | High | Low | DEC-36-07 + DEC-36-18 environment_class enforcement + `record_gxp_status` + `test_data_flag` + non-dismissable watermark + write block |
| License-state cache stale → wrong gate decision | Medium | Very low | DEC-36-27 in-transaction version bump + post-commit Redis outbox + 30s safety TTL + fail-closed on DB-verify failure |
| Invoice issued in wrong currency / FX | Medium | Low | DEC-36-23 + DEC-36-24 currency + FX lock-on-issue |
| Channel partner discount applied incorrectly | Medium | Low | Plan-level discount logic; `finance_review_authority` sign-off on contract |
| Contract documents tampered post-signature | High | Very low | URS-12 immutable doc versions; URS-06 hash chain; e-sig replay block |
| Inspection-mode override extended without need | Medium | Low | DEC-36-16 14-day default; URS-13 CR for extension; URS-22 inspection-context binding |
| Tier-downgrade mid-cycle leaves regulated records orphaned | High | Low | DEC-36-29 regulatory-impact assessment; `TIER_DOWNGRADE_IN_FLIGHT_WORKFLOW_BLOCK` |
| Termination cascade leaves data exposed | High | Very low | DEC-36-32 strict ordered cascade; final `HASH_CHAIN_SEAL_TERMINATION` |
| Read-only-with-inspection-access mis-permits regulated write | High | Very low | License Gate fails closed; `SUBSCRIPTION_EXPIRED_READ_ONLY` on every write attempt; audit on each rejected attempt |
| Multi-currency reporting incorrect at consolidation | Medium | Medium | FX lock at invoice issue; consolidation report uses lock rates; quarterly FX reconciliation |
| Mid-renewal payment failure leaves customer in ambiguous state | Medium | Medium | DEC-36-25 dunning cadence; URS-30 escalation; `subscription_on_hold` state |
| Causally-linked child workflows misused to bypass shield (incl. deep chain abuse) | High | Low | DEC-36-14 + DEC-36-38 parent + root + causal_reason + shield_depth required; depth ≤ 3 hard-capped; cycle detection on insert; >3 requires URS-13 CR + executive + final_quality_approver co-sign |
| Emergency inspector grant abused (not a real inspector) | Critical | Low | DEC-36-15-EMG credential capture mandatory; URS-30 notification within 5 min to customer executive + Verixa platform admin + RA Head + Founder; URS-22 binding via escalation; absolute 72h max |
| Emergency inspector access blocked during Friday-afternoon / holiday inspections by mechanical 24h timer | Critical | Low | DEC-36-15-EMG escalation model: 24h escalation (not revoke); 48h placeholder; 72h absolute is the only hard expiry |
| Fast-path commercial hold mistakenly applied to routine failure | High | Low | DEC-36-25 classification on `billing_events.fast_path_classification`; CFO + finance_review dual e-sig confirmation required |
| Compliance hold blocked / delayed | Critical | Very low | DEC-36-25 distinct compliance_holds state machine + compliance_hold_authority separate from commercial; full_lockout reserved for extreme cases |
| Compliance hold disclosed to customer in violation of jurisdiction-specific legal restriction | High | Low | DEC-36-25 `disclosure_class` defaults route sanctions to `restricted_pending_legal_review`; 5-business-day Legal classification window; customer-facing state genericised to `subscription_on_hold_contact_support` for all restricted classes; Legal-controlled per-order classification |
| Spec overclaims legal certainty on sanctions disclosure prohibition | Medium | Low | DEC-36-25 explicitly states spec does NOT assert universal sanctions-non-disclosure rule; defaults are starting points only; Legal classification per-order required |
| License cache invalidation race window allows write on stale entitlement | Critical | Very low | DEC-36-27 in-transaction version bump; DB `license_cache_versions` is source of truth; Redis is replica only; fail-closed on DB-stamp-verify failure; 30s safety TTL only as Redis-vs-DB safety |
| Multi-environment customer confused about which env they are in | Medium | Medium | Mandatory environment badge in frontend header; environment-specific URL routing; explicit environment selection at login |

| Risk | Severity | Likelihood | Mitigation |
|---|---|---|---|
| Causally-linked child workflows misused to bypass shield (incl. deep chain abuse) | High | Low | DEC-36-14 + DEC-36-38: parent + root + causal_reason + shield_depth required; shield_depth ≤ 3 hard-capped; cycle detection on insert; >3 requires URS-13 CR + executive + final_quality_approver co-sign; every child workflow URS-06 audited with full inheritance trail |
| Emergency inspector grant abused (not a real inspector) | Critical | Low | DEC-36-15-EMG: credential capture (badge / agency ref ID) mandatory; URS-30 notification within 5 min to customer executive + Verixa platform admin + RA Head + Founder; URS-22 binding pursued via 24h escalation → 48h platform-admin placeholder → 72h absolute expiry; manual revoke available at any point |
| Emergency inspector access blocked during Friday-afternoon / holiday inspections by mechanical 24h timer | Critical | Low | DEC-36-15-EMG escalation model: at 24h URS-22 unbinding triggers ESCALATION (URS-30 to platform admin + customer admin + Founder), NOT revocation; at 48h platform admin may auto-bind to placeholder context; 72h absolute is the only hard expiry |
| Compliance hold disclosed to customer in violation of jurisdiction-specific legal restriction | High | Low | DEC-36-25 `disclosure_class` defaults route sanctions to `restricted_pending_legal_review` (NOT automatic `legal_counsel_only`); 5-business-day Legal classification window; customer-facing state genericised to `subscription_on_hold_contact_support` for all restricted classes; Legal-controlled per-order classification |
| Spec overclaims legal certainty on sanctions disclosure prohibition | Medium | Low | DEC-36-25 explicitly states spec does NOT assert universal sanctions-non-disclosure rule; defaults are starting points only; Legal classification per-order required |
| License cache invalidation race window allows write on stale entitlement | Critical | Very low | DEC-36-27 in-transaction version bump on every state-changing write; DB `license_cache_versions` is source of truth; Redis is replica only; post-commit outbox propagates stamp; regulated writes fail closed on DB-stamp-verify failure; 30s TTL only as Redis-vs-DB inconsistency safety |
| Fast-path commercial hold mistakenly applied to routine failure | High | Low | DEC-36-25: classification on `billing_events.fast_path_classification`; CFO + finance_review dual e-sig confirmation required before transition |
| Compliance hold blocked / delayed | Critical | Very low | DEC-36-25: distinct compliance_holds state machine + compliance_hold_authority separate from commercial; full_lockout reserved for extreme sanctions |
| License cache stale during invalidation race | High | Low | DEC-36-27: versioned cache keys + 30s safety TTL + fail-closed-on-write |
| Multi-environment customer confused about which env they are in | Medium | Medium | Mandatory environment badge in frontend header; environment-specific URL routing (`aeonn-prod.verixa.com` / `aeonn-test.verixa.com`); explicit environment selection at login |

---

## 13. Records Retained

| Record | Purpose | Retention | Owner |
|---|---|---|---|
| `customer_accounts` rows + version chain | Commercial parent record | retain (long-term) | Finance / Customer Account Admin |
| `tenant_environments` rows + state history | Per-environment isolation + provisioning record | retain (long-term) | Verixa platform admin / Customer Admin |
| `subscriptions` rows + supersede chain | Contract evidence | retain (long-term; default 10 years post-termination) | Finance / Subscription Admin |
| `plans` + `plan_isolation_permissibility` rows | Plan catalogue + permissibility evidence | retain (long-term) | Super Admin |
| `module_entitlements` rows + version chain | Per-module entitlement evidence | retain (long-term) | Subscription Admin |
| `seat_allocations` rollups | Seat consumption evidence (computed) | retain (long-term per GxP audit) | Customer Admin |
| `license_assignments` rows | Per-user license evidence | retain (long-term per GxP audit retention) | Customer Admin / Subscription Admin |
| `usage_records` (hot tier) | Last 24 months usage | retain hot; migrate to cold tier after | Subscription Admin / URS-35 |
| `usage_records` (cold tier) | Historical usage | retain (long-term per audit retention) | URS-35 |
| `billing_events` rows | Provider webhook event history | retain (long-term) | Billing Admin |
| `invoices` + `payments` rows | Financial evidence | retain (long-term per finance retention; jurisdiction-specific minimums) | Finance |
| `dunning_events` | Collection-action evidence | retain (long-term) | Finance |
| `compliance_holds` rows | Compliance hold evidence | retain (long-term; platform-scoped for `internal_only` / `legal_counsel_only` classes) | Verixa Legal Counsel |
| `emergency_inspection_grants` rows | Break-glass inspector access evidence | retain (long-term) | Customer Admin / Verixa Platform Admin |
| `inspection_mode_overrides` rows | Planned override evidence | retain (long-term) | Customer Admin / Verixa Platform Admin |
| `workflow_dependency_declarations` rows | Shield permitted-child configuration history | retain (long-term) | Super Admin |
| `workflow_shield_inheritance` rows | Per-child-workflow shield-inheritance audit trail | retain (long-term) | Per workflow module |
| `license_cache_versions` rows | Version stamp registry (rolling) | retain 30 days hot; rolling archive | Engineering |
| `license_audit_events` (URS-06 shadow) | Audit shadow (canonical in URS-06) | retain (long-term) | URS-06 substrate |
| Contract documents (MSA / OF / Amendment / BYOC / On-Prem / Legal-Basis-of-Hold) | Legal evidence | retain (long-term; per URS-12 retention policy) | URS-12 |

---

## 14. Acceptance Criteria (AC-36-*)

Thirteen canonical functional ACs from the drift matrix, refined per push-back corrections:

- **AC-36-FUNC-001** — Three-entity model: customer_account / tenant_environment / subscription. `tenant_environments` unique on `(customer_account_id, environment_slug)` with multiple environments per `environment_class` permitted. `subscriptions` use PostgreSQL exclusion constraint on `(tenant_environment_id, tstzrange(effective_from, effective_to)) WITH &&` — no overlapping active contract date ranges per tenant_environment. License Gate keys on `tenant_environment_id`. Priority CRITICAL.
- **AC-36-FUNC-002** — Subscription master record per environment per term; activation blocked if tenant_environment provisioning_status != active OR validation_status < validated for validated_* classes. Priority CRITICAL.
- **AC-36-FUNC-003** — Atomic create of customer_account + initial tenant_environment + initial subscription; provisioning runs asynchronously per environment. Priority CRITICAL.
- **AC-36-FUNC-004** — License Gate at canonical pipeline position §0.5; keyed on tenant_environment_id; two-layer cache + versioned + 30s safety TTL + fail-closed-on-write. Priority CRITICAL.
- **AC-36-FUNC-005** — Module entitlement enforcement at runtime; backend authoritative. Priority HIGH.
- **AC-36-FUNC-006** — Named-user for `validated_*` environment_class regardless of plan; rationale = availability not attribution. Priority CRITICAL.
- **AC-36-FUNC-007** — Authority-Profile-tied seats with URS-28 qualification + URS-05 binding. Priority HIGH.
- **AC-36-FUNC-008** — Mid-Workflow Continuity Shield with bounded transitive child workflow exemption per DEC-36-14 / DEC-36-38: child workflows carry parent + root + causal_reason + inherited_shield_id + shield_depth (1..3); cycles blocked; depths >3 require URS-13 CR + executive + final_quality_approver override. Priority CRITICAL.
- **AC-36-FUNC-009** — Inspector access: two paths — (a) planned override (DEC-36-16; pre-bound URS-22 context); (b) emergency break-glass (DEC-36-15-EMG; credential capture; **escalation-not-revoke model**: 24h binding-overdue escalation → 48h platform-admin placeholder URS-22 context → 72h absolute expiry; access NEVER auto-revokes at 24h or 48h; inspection_grantor_authority SoD distinct from contract_signatory). Priority CRITICAL.
- **AC-36-FUNC-010** — Environment-class hard separation per DEC-36-07. Priority HIGH.
- **AC-36-FUNC-011** — License-event append-only audit per URS-06; hash-chain conditional. Priority CRITICAL.
- **AC-36-FUNC-012** — Dunning split into three paths per DEC-36-25: routine / fast-path commercial / compliance hold. Compliance hold is separate state machine + separate authority. Every hold (commercial + compliance) carries `disclosure_class` per DEC-36-25; URS-30 routing gates on disclosure_class; `restricted_pending_legal_review` classified within 5 business days; customer-facing state for restricted/internal/counsel-only classes is generic `subscription_on_hold_contact_support`. Priority HIGH.
- **AC-36-FUNC-013** — License Cache invalidation is synchronous and in-transaction per DEC-36-27. DB `license_cache_versions` table is the source of truth. Version bump occurs in the SAME database transaction as the underlying state-changing write (async invalidation prohibited). Redis cache is a replica only, updated via post-commit outbox; Redis 30s safety TTL covers only Redis-vs-DB inconsistency, never write-to-invalidation lag. Regulated writes fail closed if DB stamp cannot be verified. Priority CRITICAL.

Plus integration + negative ACs extended for: `SHIELDED_NEW_INDEPENDENT_WORKFLOW_BLOCKED`, `CAUSAL_REASON_REQUIRED`, `PARENT_WORKFLOW_NOT_IN_SHIELD_ELIGIBLE_STATE`, `SHIELD_DEPTH_EXCEEDED`, `SHIELD_CYCLE_DETECTED`, `EMERGENCY_GRANT_BINDING_OVERDUE_24H_ESCALATED`, `EMERGENCY_GRANT_PLACEHOLDER_BOUND_AT_48H`, `EMERGENCY_GRANT_ABSOLUTE_EXPIRY_72H_REACHED`, `INSPECTION_GRANTOR_SOD_VIOLATION`, `COMPLIANCE_HOLD_REQUIRES_LEGAL_AND_EXECUTIVE_CO_SIGN`, `DISCLOSURE_CLASS_PENDING_LEGAL_REVIEW_5_BUSINESS_DAY_BREACH`, `LICENSE_CACHE_VERSION_STAMP_STALE`, `LICENSE_CACHE_VERSION_VERIFICATION_FAILED`, `LICENSE_WRITE_FAIL_CLOSED_ON_DB_VERIFY_FAILURE`.

---

## 15. Regulatory Mapping

| Standard | Provision | URS-36 mapping |
|---|---|---|
| 21 CFR Part 11 §11.10(a) | System validation | All ACs in §14; provisioning IQ/OQ/PQ per tenant_environment |
| 21 CFR Part 11 §11.10(c) | Record protection | DEC-36-17 retention-period read-only; URS-35 cold storage; per-tenant_environment backup |
| 21 CFR Part 11 §11.10(d) | Access control | License Gate post-RBAC; named-user (DEC-36-06); Authority Profile (URS-05); SoD |
| 21 CFR Part 11 §11.10(e) | Audit trail | Every license event append-only audited; hash-chain claim conditional per DEC-36-26 |
| 21 CFR Part 11 §11.10(g) | Authority checks | URS-04 e-sig + URS-05 Authority Profile |
| 21 CFR Part 11 §11.50 | Signed records | Subscription contracts, tier changes, license assignments — all e-signed |
| 21 CFR Part 11 §11.100 | E-signature components | URS-04 substrate carries name + date + meaning + reason for every license-state e-sig |
| EU GMP Annex 11 §4 | Operational documentation | This URS + downstream validation pack |
| EU GMP Annex 11 §7.1 | Logical separation | Per-tenant_environment isolation per ADR-004 Options B / B+ / C / D |
| EU GMP Annex 11 §12 | Access controls | License Gate fail-closed; per-tenant DB role (B+) or dedicated DB (C) |
| EU GMP Annex 11 §16 | Incident management | Dunning workflow + URS-30 escalation chain |
| EU GMP Annex 11 §17 | Periodic review | Renewal cadence (DEC-36-33) + module-entitlement review |
| EU GMP Annex 22 (Draft) §7 | AI/ML manual continuity | ARCH-AI-001 alignment with shield + named-user |
| GAMP 5 Cat-5 | Custom software validation | Full IQ/OQ/PQ per acceptance criteria above; per-environment provisioning validation |
| MHRA ALCOA+ Attributable | Named-user enforcement for validated environments (rationale: availability not attribution) |
| MHRA ALCOA+ Contemporaneous | Server-side timestamps on every license event |
| MHRA ALCOA+ Original | Subscription supersede + URS-06 append-only + URS-35 PITR (Options C / D-dedicated) |
| MHRA ALCOA+ Available | Retention-period read-only access for 10+ years post-termination |
| ICH Q10 | Data integrity | Per-tenant_environment audit trail (B+ schema-isolated audit log) |
| ICH Q9 | Quality risk | DEC-36-28 / DEC-36-29 regulatory-impact assessment for downgrades |
| HIPAA §164.502(b) | Minimum necessary | Module entitlement + named-user |
| GDPR Art. 5(1)(c) + Art. 44 | Data minimisation + transfer | Per-tenant_environment `data_region`; KMS CMK (B+/C) |
| India DPDP Act 2023 §8 | Purpose limitation | Subscription scope + data-region binding |
| India CDSCO Schedule M | GMP | Environment-class separation; named-user |
| US OFAC / EU restrictive measures / India FEMA / UK OFSI / AML SAR-style "tipping off" | Disclosure-class jurisdictional rules | DEC-36-25 `disclosure_class` with Legal-controlled per-order classification; spec does not assert universal disclosure prohibition |

---

## 16. Cross-Module Event Contract

**Emitted by URS-36:**

- Customer account: `customer_account.created`
- Tenant environment: `tenant_environment.created`, `tenant_environment.provisioning_started`, `tenant_environment.provisioning_completed`, `tenant_environment.provisioning_failed`, `tenant_environment.validation_passed`, `tenant_environment.validation_failed`, `tenant_environment.isolation_changed`, `tenant_environment.environment_class_changed`, `tenant_environment.data_region_changed`, `tenant_environment.kms_rotated`, `tenant_environment.migration_version_advanced`, `tenant_environment.decommissioned`
- Subscription lifecycle: `subscription.created`, `subscription.quote_pending`, `subscription.countersigned_customer`, `subscription.countersigned_verixa`, `subscription.activated`, `subscription.renewing_entered`, `subscription.renewed`, `subscription.on_hold_entered`, `subscription.fast_path_hold_applied`, `subscription.grace_entered`, `subscription.shielded_expiry_pending`, `subscription.shield_extended_for_in_flight_workflow`, `subscription.expired_read_only`, `subscription.late_renewed`, `subscription.terminated`
- Tier / amendment: `subscription.tier_changed`, `subscription.amended`
- Module entitlement: `module.entitlement_toggled`
- Seat: `seat.allocated`, `seat.consumed`, `seat.released`, `seat.reallocated`, `seat.soft_cap_breached`, `seat.hard_cap_breached`
- License assignment: `license.assigned`, `license.suspended`, `license.revoked`, `license.reassigned`, `license.archived`
- Invoice + payment + dunning: `invoice.issued`, `invoice.paid`, `invoice.overdue`, `invoice.refunded`, `invoice.written_off`, `payment.posted`, `dunning.step_advanced`, `dunning.escalated`
- Billing event: `billing.webhook_received`, `billing.webhook_validated`, `billing.webhook_reconciled`
- Compliance hold: `compliance_hold.proposed`, `compliance_hold.active`, `compliance_hold.disclosure_classified`, `compliance_hold.released`
- Inspection — planned override: `inspection_override.granted`, `inspection_override.revoked`
- Inspection — emergency break-glass: `emergency_inspection_grant.created`, `emergency_inspection_grant.binding_overdue_escalated_at_24h`, `emergency_inspection_grant.placeholder_bound_at_48h`, `emergency_inspection_grant.urs_22_bound`, `emergency_inspection_grant.absolute_expired_at_72h`, `emergency_inspection_grant.manually_revoked`
- Workflow shield: `workflow_dependency_declaration.updated`, `workflow_shield_inheritance.created`, `shield_depth_override.granted`
- Usage: `usage.threshold_breached`
- License gate: `license_gate.denied` (payload: `user_id`, `tenant_environment_id`, `module_id`, `action`, `reason_code`)
- Cache: `license_cache_versions.bumped_in_transaction`, `license_cache.redis_warmed`, `license_cache.redis_evicted`
- Audit seal: `hash_chain.seal_termination`

**Consumed by URS-36:**

- `tenant.created` (URS-08) — triggers Initial Subscription requirement
- `tenant.suspended` (URS-08) — cascades to license state change
- `tenant.terminated` (URS-08) — triggers DEC-36-32 cascade
- `urs_13.cr_approved` (URS-13) — triggers tier change / amendment / isolation change execution
- `urs_28.qualified` / `urs_28.qualification_expired` (URS-28) — updates Authority-Profile seat eligibility
- `urs_22.inspection_opened` (URS-22) — eligible context for inspection-mode override request
- `urs_22.placeholder_context_reconciled` (URS-22) — closes emergency-grant 48h placeholder
- `urs_35.cold_storage_migration_complete` (URS-35) — confirms retention-period transition
- `workflow.in_flight_check` (URS-04) — input to Mid-Workflow Continuity Shield
- `billing.provider_webhook` (external) — provider payment / chargeback / fraud signal

---

## 17. Open Blockers Register

| Blocker | Description | Evidence Required | Risk if Unresolved |
|---|---|---|---|
| **BLK-36-01** | RLS conflict between architecture and ADR-004 (§0.6) | PostgreSQL policy dump; RLS-enabling migrations; cross-tenant negative tests; missing-WHERE-clause endpoint fix evidence (3 endpoints per ADR-004) | Cross-tenant data exposure; 21 CFR Part 11 §11.10(d) finding; failed validation |
| **BLK-36-02** | No code evidence of URS-36 implementation | `customer_accounts` / `tenant_environments` / `subscriptions` / `module_entitlements` / `license_assignments` migrations; `requireLicense` middleware source; route plugin registration; integration tests; audit-registry entries | URS-36 may be approved without buildable / testable implementation path |
| **BLK-36-03** | License Gate absent from current request pipeline | Backend `app.ts` hook order; route plugin registration; middleware tests proving gate runs before service handler and after RBAC | Unlicensed regulated writes possible |
| **BLK-36-04** | Tenant-environment provisioning state machine not implemented (per environment, not per tenant) | `tenant_environment_provisioning_status` table + migrations; provisioning engine source; per-schema migration runner; backup-policy binding service; KMS-binding service; data-region routing | Tenant_environments may onboard without validated isolation |
| **BLK-36-05** | Hash-chain audit claim not evidenced in URS-06 | URS-06 implementation; hash-chain schema; tamper-evidence tests | DEC-36-26 conditional; overclaim of Part 11 §11.10(e) integrity if locked |
| **BLK-36-06** | workflow_dependency_declarations + Shield child-workflow exemption requires URS-04 / URS-13 / URS-23 / URS-15 / URS-22 / URS-27 / URS-31 hook surfaces | Cross-module hook implementation evidence; declaration consumer code per shield-eligible parent module; integration tests | Shield child-workflow exemption may not function across consumer modules |

---

## 18. References

- 21 CFR Part 11 — Electronic Records; Electronic Signatures
- 21 CFR Part 211 — current Good Manufacturing Practice
- EU GMP Annex 11 — Computerised Systems
- EU GMP Annex 22 (Draft 2025) — AI/ML in Pharmaceutical Manufacturing
- EU AI Act (Regulation 2024/1689)
- FDA CSA Final Guidance (September 2025) — Computer Software Assurance
- ICH E6(R3) — Good Clinical Practice
- ICH Q9 — Quality Risk Management
- ICH Q10 — Pharmaceutical Quality System
- ISO 27001:2022 — Information security management
- ISO 22301:2019 — Business continuity management
- NIST SP 800-34 — Contingency Planning
- MHRA Data Integrity Guidance (2018) — ALCOA+ principles
- WHO Technical Report Series No. 996, Annex 5
- PIC/S PI 041 — Data integrity
- HIPAA §164.502(b) — Minimum necessary
- GDPR (Regulation 2016/679) — Article 5(1)(c) Data minimisation; Article 44 Data transfers
- India DPDP Act 2023
- India IT Act 2000
- India CDSCO Schedule M
- US OFAC sanctions program
- EU restrictive measures regulations
- India FEMA
- UK OFSI sanctions
- FinCEN advisories on SAR confidentiality (referenced for disclosure_class jurisdictional context only; no universal disclosure rule asserted)
- ADR-004 / VX-FLOW-038 — Tenant Database Architecture Options (v1.0, May 2026)
- Verixa Platform Architecture (dev-vimal-deploy branch, 2026-05-13)
- Founder push-back review (consolidated; dated 2026-05-13)
- AICPA SOC 2 Type II — Trust Services Criteria (where applicable to commercial-governance controls)
- US Sarbanes-Oxley Act §404 — Internal control over financial reporting (where applicable to revenue-cycle controls)

### Revision history

| Version | Date | Change |
|---|---|---|
| v1.0 | 2026-05-13 | Initial Target State URS lock. Locked content: three-entity model (customer_account / tenant_environment / subscription); ADR-004-aligned isolation_model + data_region + KMS + backup policy + provisioning state machine as first-class fields on tenant_environment; License Gate at canonical pipeline position keyed on tenant_environment_id; named-user enforcement by environment_class (rationale: deterministic seat availability + Annex 11 §16 + Part 11 §11.10(c)); sandbox / demo environment hard segregation; bounded transitive Mid-Workflow Shield (max depth 3 + cycle detection + override path); emergency inspector escalation-not-revoke model (24h escalation → 48h placeholder → 72h absolute expiry); compliance-hold disclosure-class with legal-controlled defaults; synchronous in-transaction cache invalidation + versioned Redis replica; subscription uniqueness via PostgreSQL exclusion constraint on date ranges; multi-environment-per-class permitted; grace-period split between tenant_environments.default_grace_period_days and subscriptions.grace_period_days_snapshot. The six open blockers BLK-36-01..BLK-36-06 in §17 carry forward as the canonical pre-validation evidence checklist; document is not validation-ready until they resolve. |

---

End of URS-36 Target State URS v1.0.
