Skip to main content

Runbook — wa_hold_settlement enablement toggle (BIF-8740)

As-built (2026-07-22). Deduction V2 hold/settlement is gated by Services::Billing::FeatureFlag, a company-scoped billing feature flag. This supersedes the two-tier design the RFC's Decision 6 described (a global Services::Preference flag ∨ a per-org organization_packages.extras['wa_hold_settlement'] jsonb boolean) — that design was never shipped. extras['wa_hold_settlement'] is not read by any code; setting it does nothing. Enable orgs only via the mechanism below.

An org is on the hold/settlement path when the flag is enabled for its company:

# Repositories::Billings::Helpers#wa_hold_settlement_enabled? (hub_core, added in T1)
def wa_hold_settlement_enabled?(organization_package)
Services::Billing::FeatureFlag.new.enabled?(
:wa_hold_settlement,
unique_id: organization_package&.company_id
)
end

Services::Billing::FeatureFlag (hub_core/app/core/domains/services/billing/feature_flag.rb) is read-only in hub_core. It resolves the flag from the billing DB + a Redis cache (REDIS_BILLING_R, keys preference:wa_hold_settlement:{state,global,<company_id>:unique}), mirroring qontak-preferences. Its logic (#enabled?(feature, unique_id:)):

  1. state == false (or the preference row is absent) → false (fail-safe, default OFF).
  2. is_global == truetrue for every company (fleet-wide GA / short-circuits the per-company check).
  3. otherwise → true iff a preference_unique_ids row exists for (preference, unique_id = company_id) (per-company pilot opt-in).

So there are two enablement levers, both on the billing preferences / preference_unique_ids tables for the wa_hold_settlement feature — not Services::Preference and not extras:

  • Global (GA / kill switch): preferences.state = true, is_global = true → all companies on.
  • Per-company (pilot opt-in): preferences.state = true, is_global = false + one preference_unique_ids row per pilot company_id → only those companies on.

Who writes the flag

hub_core only reads it. Seeding the wa_hold_settlement preference row and managing its per-company preference_unique_ids allow-list live in the billing-preferences managing service (qontak-preferences / the billing preferences admin surface), not in this repo and not in hub_core's Services::Preference (a different, non-billing flag system). Use that service's admin tooling to:

  1. Register the wa_hold_settlement billing preference once per environment, state = false, is_global = false (default OFF).
  2. Pilot — add each pilot company_id to the wa_hold_settlement unique-id allow-list (leave is_global = false). Roll back a single org by removing its company_id from the allow-list.
  3. GA — set is_global = true (every company on at once). Kill switch — set state = false (instant fleet-wide revert regardless of the allow-list).

The exact admin command belongs to the billing-preferences service and is out of scope for this repo; confirm it there. Whatever the surface, the effect must be one of the three table states above — the Redis cache is populated from the DB on read (cold-miss), so after an admin change the next enabled? call reflects it.

Consumer check (T2–T6, M1)

All gated branches call the single shared predicate — never the flag directly. Repositories::Billings::Helpers is a module (mixin); include it (interactors/repos on the deduction path already do):

include Repositories::Billings::Helpers
wa_hold_settlement_enabled?(organization_package) # company-scoped Services::Billing::FeatureFlag read

moderator-be replicates the same reader (M1b, BIF-8958) as Core::Services::Billing::FeatureFlag against the same billing tables + Redis, and hub_core exposes the boolean on billing_info as is_wa_hold_settlement_enabled (M1a, BIF-8883) for the client FE.

Sources (grounded against hub_core)

  • Reader: hub_core/app/core/domains/services/billing/feature_flag.rb (#enabled?(feature, unique_id:), REDIS_BILLING_R cache; comment: "hub-core only reads flags; seeding and unique-id management live in the managing repo").
  • Backing models: Models::Billing::Preference (table preferences) + Models::Billing::PreferenceUniqueId (table preference_unique_ids).
  • Predicate: Repositories::Billings::Helpers#wa_hold_settlement_enabled? (hub_core/app/core/domains/repositories/billings/helpers.rb:61-63) → delegates to Services::Billing::FeatureFlag with unique_id: organization_package&.company_id; truth-table spec in feature_flag_spec.rb.