Files
cgalo5758 24cb2e66f0 Support boolean entitlement rule authoring
Classify resource keys as boolean or numeric, adapt the operator form to
the selected key, and derive rule types server-side to prevent
wrong-shape rules.
2026-07-22 00:42:01 -05:00

8.2 KiB

entitlement-sets

Purpose

Defines the entitlement set abstraction that decouples capability specification from commercial packaging. Entitlement sets are named, reusable collections of entitlement rules that products and grants reference to declare what capabilities they confer.

Requirements

Requirement: Entitlement sets as named capability collections

The system SHALL maintain an entitlement_sets table where each row represents a named, reusable collection of entitlement rules. Each entitlement set SHALL have a set_id (UUID), name (VARCHAR(255)), description (TEXT), and is_active (BOOLEAN). Entitlement sets decouple capability specification from commercial packaging, but conferral SHALL flow exclusively through products: an entitlement set SHALL be reference-able only by a product's entitlement_set_id, including an internal wrap product minted solely to confer the set (see product-management, entitlement-conferral), and SHALL NOT be referenced directly by a grant. An entitlement set with is_active = false SHALL NOT be assignable to new products, but existing references SHALL remain valid.

Scenario: Create an entitlement set

  • WHEN an operator creates an entitlement set with name "FedWiki Capabilities"
  • THEN the system SHALL create an entitlement_sets record with is_active = true
  • AND the set SHALL be available for reference by products, including internal wrap products minted solely to confer the set

Scenario: Deactivated set remains valid for existing references

  • WHEN an entitlement set is deactivated (is_active = false)
  • THEN existing products referencing that set SHALL continue to function
  • AND existing pool provisions resolved to that set SHALL continue to materialize

Requirement: Entitlement set rules define capabilities within a set

The system SHALL maintain an entitlement_set_rules table where each row defines a single capability within an entitlement set. Each rule SHALL reference a set_id (FK to entitlement_sets) and have a rule_type discriminator. rule_type = 'limit' and rule_type = 'boolean' are supported; quota and credit remain unmaterialized. Each limit rule SHALL have a resource_key (FK to resource_keys), resource_value (BIGINT), resource_per_unit (BOOLEAN), and stacking_policy (one of additive, maximum, replace). Each boolean rule SHALL have a resource_key and NULL resource_value, resource_per_unit, and stacking_policy.

Scenario: Limit rule within a set

  • WHEN an entitlement set has a limit rule with resource_key = 'sites', resource_value = 5, resource_per_unit = false, stacking_policy = 'additive'
  • THEN any pool provision resolved to this set SHALL contribute 5 sites to the pool's numeric entitlements

Scenario: Per-unit limit rule within a set

  • WHEN an entitlement set has a limit rule with resource_key = 'sites', resource_value = 1, resource_per_unit = true, stacking_policy = 'additive'
  • AND a pool provision resolved to this set has quantity = 3
  • THEN the contributed value SHALL be 3 (1 x 3)

Scenario: Boolean rule within a set

  • WHEN an entitlement set has a boolean rule with resource_key = 'discourse_posting'
  • THEN any active pool provision resolved to this set SHALL cause the pool's boolean_entitlements row for that key to be granted = true

Scenario: Rule type CHECK constraint

  • WHEN a limit rule is inserted into entitlement_set_rules
  • THEN resource_key and resource_value SHALL NOT be NULL
  • AND credit_amount and credit_currency SHALL be NULL

Scenario: Boolean rule CHECK constraint

  • WHEN a boolean rule is inserted into entitlement_set_rules
  • THEN resource_key SHALL NOT be NULL
  • AND resource_value, stacking_policy, resource_per_unit, credit_amount, and credit_currency SHALL be NULL

Requirement: Seed entitlement sets for existing products

The system SHALL seed entitlement sets via migration corresponding to each seed product:

  1. A "FedWiki Capabilities" set with a limit rule for resource_key = 'sites', resource_value = 5, resource_per_unit = false, stacking_policy = 'additive'.
  2. A "Site Credit Capabilities" set with a limit rule for resource_key = 'sites', resource_value = 1, resource_per_unit = true, stacking_policy = 'additive'.

Scenario: Fresh database has seed entitlement sets

  • WHEN migrations have run on a fresh database
  • THEN the entitlement_sets table SHALL contain a "FedWiki Capabilities" set with is_active = true
  • AND the entitlement_sets table SHALL contain a "Site Credit Capabilities" set with is_active = true
  • AND each set SHALL have its corresponding entitlement_set_rules rows

Requirement: Every pool provision resolves to exactly one entitlement set

The system SHALL require that every pool_provisions record has a non-NULL entitlement_set_id (FK to entitlement_sets). The entitlement_set_id SHALL be resolved at provision-creation time and SHALL NOT change after creation. The materialization pipeline SHALL use pool_provisions.entitlement_set_id as the sole key for looking up rules. Entitlement sets decouple capability specification from commercial packaging, but conferral flows exclusively through products: a grant SHALL NOT reference an entitlement set directly, and pool_provisions.entitlement_set_id SHALL always be resolved from the conferring product's entitlement_set_id (see entitlement-conferral). Ad hoc conferral of a raw entitlement set, with no ordinary commercial product behind it, SHALL be accomplished by minting an internal wrap product whose entitlement_set_id names the set — never by a grant naming the set directly (see product-management, entitlement-conferral).

Scenario: Provision from a product-based grant

  • WHEN a grant references a product with entitlement_set_id = X
  • THEN the pool provision created for this grant SHALL have entitlement_set_id = X

Scenario: Ad hoc set conferral is mediated by a wrap product

  • WHEN an operator needs to confer a raw entitlement set that has no ordinary commercial product behind it
  • THEN the operator SHALL mint an internal wrap product (is_public = FALSE, published, priceless) whose entitlement_set_id names the set
  • AND the grant SHALL name that wrap product's product_id
  • AND the pool provision created for the grant SHALL have entitlement_set_id resolved from the wrap product, exactly as for any other product-backed conferral

Scenario: A grant SHALL NOT reference an entitlement set directly

  • WHEN a grant is created
  • THEN the grant SHALL name a product_id
  • AND the grant SHALL NOT carry an entitlement_set_id column
  • AND no code path SHALL resolve a pool provision's entitlement_set_id from a grant-supplied set reference rather than from the conferring product

Scenario: Provision entitlement_set_id is immutable after creation

  • WHEN a pool provision exists with entitlement_set_id = X
  • AND the referenced product's entitlement_set_id is changed to Z
  • THEN the pool provision's entitlement_set_id SHALL remain X

Requirement: Resource keys declare a kind

The system SHALL record a shape discriminator on core.resource_keys: kind VARCHAR(20) NOT NULL DEFAULT 'numeric' with CHECK (kind IN ('boolean', 'numeric')). boolean keys are conferred by boolean rules and consumed via boolean_entitlements; numeric keys are conferred by limit (and, when materialized, quota) rules and consumed via numeric_entitlements. Migrations and seeds that create resource-key rows SHALL declare kind explicitly.

Scenario: Boolean key is marked boolean

  • WHEN migrations have run on a fresh database with the discourse stream enabled
  • THEN the core.resource_keys row for discourse_posting SHALL have kind = 'boolean'

Scenario: Numeric key defaults to numeric

  • WHEN migrations have run on a fresh database
  • THEN the core.resource_keys row for fedwiki_sites SHALL have kind = 'numeric'

Scenario: Invalid kind is rejected

  • WHEN a row is inserted into core.resource_keys with kind = 'quota'
  • THEN the insert SHALL fail with a CHECK constraint violation