---
id: DOM-PFM-OPS-003
title: Licence
product_area: platform
module: operations
revision: 1
status: draft
realises: CON-PFM-OPS-003
design_intent: confirmed
origin: >-
  services-platform:docs/proposals/application-access-and-entitlements.md#10 Decisions (D1 to D11, decided by
  Andrew 2026-10-11; built and accepted 2026-10-15)
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
owned_by: SVC-PFM-OPS-licensing
readable_by:
  - SVC-PFM-CSH-tenant-applications
lifecycle: STATE-PFM-OPS-004
custom_fields: none
identity: >-
  An override has its own decision identity; stored contract windows use company, application and start date
  as their key.
attributes:
  - name: licence state
    kind: computed
    required: true
    computed: true
    notes: >-
      The resolved answer distinguishes permanent access, staff grants, contract coverage, grace, expiry,
      active withholding and absence of entitlement.
  - name: override effect
    kind: enum
    required: true
    computed: false
    notes: Overrides select either a grant or a withhold.
  - name: override reason
    kind: text
    required: true
    computed: false
    notes: A retained decision needs a nonempty reason of no more than five hundred characters.
  - name: override period
    kind: date
    required: true
    computed: false
    notes: >-
      The half-open interval has a start and optional end; customer-workspace grants require an end, while
      withholding may remain open.
  - name: override revocation
    kind: reference
    required: false
    computed: false
    notes: Withdrawal stores its time and author together; the service offers no edit operation.
  - name: override author
    kind: reference
    required: true
    computed: false
    notes: The creating staff member is retained with the decision.
  - name: commercial company
    kind: reference
    required: false
    computed: false
    notes: 'Security owns the workspace’s company link, which production and sandbox workspaces can share.'
  - name: contract copy
    kind: collection
    required: false
    computed: false
    notes: 'The complete local copy retains contract status, dates, renewal choice, products and line terms.'
  - name: licence window
    kind: collection
    required: false
    computed: true
    notes: >-
      Each company-and-application window retains its coverage interval, seven-day grace boundary and
      contributing contracts.
  - name: resolution flags
    kind: collection
    required: false
    computed: true
    notes: >-
      Unrecognized statuses, unusable terms and unmapped products produce diagnostic flags without granting or
      refusing access.
  - name: company read health
    kind: enum
    required: false
    computed: false
    notes: 'Company health records attempt and success times, outcome and a sanitized failure description.'
  - name: product map
    kind: collection
    required: true
    computed: false
    notes: Release-controlled mappings associate commercial products with applications and features.
  - name: product catalogue
    kind: collection
    required: false
    computed: false
    notes: Cached product names and families support presentation without affecting entitlement.
  - name: export allowance
    kind: collection
    required: false
    computed: false
    notes: >-
      The data-export owner administers one active customer or workspace allowance and replaces it by reasoned
      withdrawal.
relationships:
  - to: DOM-PFM-OPS-004
    cardinality: one licence per workspace and application to one operational record
    ownership: The related owner maintains the link; availability combines the licence with the operational state
    cross_service: false
  - to: DOM-PFM-CSH-004
    cardinality: one licence answer to one console application entry
    ownership: The related owner maintains the link; the console presents the answer it is given
    cross_service: false
invariants:
  - id: INV-DOM-PFM-OPS-003-01
    statement: 'Override creation validates a workspace, an application, a permitted effect and a nonblank reason.'
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-platform:modules/licensing/tests/e2e/licensing.e2e.spec.js#refuses an override with no reason,
      with 400 naming the field
  - id: INV-DOM-PFM-OPS-003-02
    statement: >-
      A supplied end must follow the start; customer-workspace grants require an end through service
      validation.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-platform:modules/licensing/tests/e2e/licensing.e2e.spec.js#refuses a grant on a customer tenant
      that does not say when it ends, with 400
  - id: INV-DOM-PFM-OPS-003-03
    statement: >-
      Supported operations retain the decision and permit a single withdrawal recording author and time
      together.
    enforced_at:
      - service
    provenance: test
    source: 'services-platform:modules/licensing/services/persistence/licence-overrides.ts:revokeLicenceOverride'
  - id: INV-DOM-PFM-OPS-003-04
    statement: An unrevoked override applies from its start inclusive until its end exclusive.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-platform:modules/licensing/tests/unit/availability/application-availability.spec.ts#is not in
      force at the instant it ends, so a replacement starting there leaves no overlap
  - id: INV-DOM-PFM-OPS-003-05
    statement: Any active withhold denies the application despite other grants or contract coverage.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-platform:modules/licensing/tests/unit/availability/application-availability.spec.ts#lets a
      withhold beat always_available, which is the only way to take one of those away
  - id: INV-DOM-PFM-OPS-003-06
    statement: The resolver adds exactly seven calendar days of grace to finite windows and none to open-ended windows.
    enforced_at:
      - service
    provenance: test
    source: 'services-platform:modules/licensing/services/licences/resolve-licence-windows.ts:resolveLicenceWindows'
  - id: INV-DOM-PFM-OPS-003-07
    statement: >-
      Readable in-force contracts with mapped products supply coverage; unresolved inputs produce flags
      instead.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-platform:modules/licensing/tests/unit/licences/resolve-licence-windows.spec.ts#resolves nothing
      for a status it has never heard of, and flags it so the vocabulary can be confirmed
  - id: INV-DOM-PFM-OPS-003-08
    statement: >-
      Successful reads replace contracts, lines, windows and success health together; provider failures update
      failure health while preserving coverage.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-platform:modules/licensing/tests/integration/services/sync/sync-company-licences.integration.spec.js#changes
      no snapshot, no window and no last success
  - id: INV-DOM-PFM-OPS-003-09
    statement: 'Failed synchronization health must carry an error, which the service redacts before storage.'
    enforced_at:
      - database
      - service
    provenance: observed
    source: >-
      services-platform:modules/licensing/db/hubspot-company-syncs.table.ts
      (hubspot_company_syncs_error_check); services/sync/sync-company-licences.ts:syncCompanyLicences
  - id: INV-DOM-PFM-OPS-003-10
    statement: >-
      Unique partial indexes permit one unrevoked allowance at customer scope and one per customer-workspace
      pair.
    enforced_at:
      - database
    provenance: observed
    source: >-
      services-platform:modules/licensing/db/data-export-entitlements.table.ts
      (data_export_entitlements_customer_uidx, data_export_entitlements_tenant_uidx)
  - id: INV-DOM-PFM-OPS-003-11
    statement: Deleting a workspace retains commercial-company copies and windows for other workspaces that share them.
    enforced_at:
      - service
    provenance: observed
    source: 'services-platform:modules/licensing/services/maintenance/tenant-participant.ts:licensingParticipant'
physical:
  - licence_overrides
  - licence_windows
  - hubspot_contracts
  - hubspot_contract_lines
  - hubspot_company_syncs
  - commercial_products
  - data_export_entitlements
evidence:
  - >-
    services-platform at ad3f6a6: modules/licensing (db, catalog/product-grants.ts, hubspot,
    services/licences, services/sync, services/enablement/grant-licence-override.ts, services/persistence,
    services/maintenance/tenant-participant.ts); docs/licensing.md;
    docs/proposals/application-access-and-entitlements.md §3, §4, §10.
  - >-
    react-console at baf6dae: components/console/hq/tenant-licensing-card.tsx, licensing-dialogs.tsx;
    lib/hq/licensing.ts.
  - >-
    codex examination 2026-10-23: checked the pinned source anchors, planning references and enforcement
    boundaries; unresolved limits are recorded in module findings.
---

# Licence

## What It Models

A licence expresses whether a workspace has commercial permission for an application. It is computed from staff exceptions, company contract windows and catalogue rules. Operational readiness is evaluated separately before licensed applications become usable.

## Identity and Attributes

Each override records an author, effect, reason and period, plus any later withdrawal. Complete company reads retain contracts and line items and derive application windows through the release’s product map. Individual line boundaries replace the matching contract boundaries. Adjacent or overlapping terms merge, and the resolver adds seven calendar days of grace to finite windows. Flags identify inputs that cannot produce coverage. Synchronization health records successful, failed and unconfigured attempts.

## Relationships

One company’s coverage may serve production and sandbox workspaces. Security owns the workspace’s company link. Availability combines the derived licence with operational application state, and the console displays the resulting answer. Export allowances are stored alongside licensing but administered and consumed by the export owner.

## Invariants

Active withholds take priority. Current and grace contract coverage precede staff grants when selecting the reported source. Override periods are evaluated at read time, and withdrawal removes their effect without deleting history. A provider failure records health while retaining the last commercial snapshot. Exact grace length comes from the resolver; database checks enforce only its permitted date shape.

## How It Is Stored and Shared

Licensing owns overrides, company copies, windows, health, products and export allowances. These records have no workspace row policies because commercial coverage and authorization reads span workspaces. Staff route authority and explicit query scope protect full reads; the customer mapper removes internal commercial and personal details. No custom-field capability is declared.

## Open Design Questions

Renewal warnings remain accepted but unimplemented. Later approved entitlement directions differ from this earlier model, and concurrent company replacement has no established source-order guarantee.
