Governance Controls

Ledger-driven authorization, approval workflows, who holds authority, a fresh authenticator code before money moves, and the association's pinned payout bank. The enforcement layer that governs every financial decision.

10 min read Governance & Controls Published Nov 7, 2024

CommunityPay's governance layer sits below the payment layer. All production financial flows pass through enforcement controls before execution. This is not optional behavior that users can disable — it is architectural.

EnforcementDecision: The Choke Point

All production financial flows in CommunityPay — journal entries, fund transfers, bill payments, invoice creation, payment receipts, and fiscal year closures — must produce an EnforcementDecision before they can proceed.

An EnforcementDecision records:

  • The decision: ALLOW, BLOCK, OVERRIDE, or ERROR
  • Which guards evaluated: What rules were expected to run, which actually ran, and what each concluded
  • The timing: Elapsed milliseconds per guard, total evaluation time
  • The context: Which HOA, which user, which flow, what amount

This creates a complete, immutable record of every financial decision and the reasoning behind it.

Two-Event Pattern

Each enforced transaction generates two events:

  1. PRE_PERSIST (decision_seq=0): The enforcement evaluation happens before the database commit. If the decision is BLOCK, the transaction never touches the ledger.
  2. POST_PERSIST (decision_seq=1): After a successful commit, a confirmation event is recorded with the resulting journal entry foreign key.

If a commit fails after an ALLOW decision, a PERSIST_ERROR (decision_seq=2) event captures the failure. This means you can audit not just what was allowed, but whether allowed transactions actually completed.

Enforced Flows

All 10 financial flows are enforced in production:

Flow What It Covers
Journal Entry Every double-entry posting to the ledger
Fund Transfer Moving money between operating and reserve funds
Bill Payment Vendor disbursements
Invoice Creation Assessment and fee generation
Payment Receipt Recording incoming payments
Year-End Close Fiscal year finalization
Loan Origination Loan draws, fees, and resident loan origination
Loan Payment Loan payments, payoffs, and prepayment penalties
Loan Accrual Interest accrual, rate resets, and financing-cost amortization
Trust Transaction Trust deposits, disbursements, fee withdrawals, and interest allocation

Blocking is on for every flow in production. A shadow setting and one switch per flow exist as deploy-time settings; the shadow setting is off and every flow switch is on in production, and no user can change them.

Approval Workflows

Every bill opens an approval request when it is submitted, at any amount. A board member approves it before it can be paid, and that approval is the record the payment spends.

How a bill finds its approvers

A board sets approval tiers: bands of amounts, each naming the levels that must approve a bill in that band. The bands cover every amount and a bill belongs to exactly one, so no two tiers compete for the same bill. Where a board has set no tier, one system default applies — one level, any board member or admin.

Bills are the only document type an approval request is opened for. A workflow recorded against payments, budgets, journal entries or payee changes is marked "Not enforced" on the workflow pages and is never consulted. Fund transfers carry their own approval, on the transfer record itself, at any amount.

Multi-Level Approval

A tier can name more than one level, and each level names who may approve it:

  • Approver type: a specific member, a role (treasurer, president, board member, admin), or any board member or admin
  • Required approvals: how many approvers are needed at this level

Levels are fixed when the request opens, so changing a tier afterwards does not re-judge a bill already submitted. One person gives at most one approval per request. Authority comes from an accepted membership in that association: a platform staff account with no membership there approves nothing and pays nothing.

Two settings per association govern who may act:

  • Self-approval: whether the person who submitted a bill or transfer may also approve it. On by default.
  • Separate payer: whether the person who pays must be someone other than the submitter and the approvers. Off by default, and judged when the payment happens.

Each change to a tier or to either setting writes an immutable record naming who made it, and the board is notified. The settings in force are part of the policy snapshot on every enforcement decision.

Status Lifecycle

Approval requests follow a strict state machine:

PENDING → IN_PROGRESS → APPROVED
PENDING → REJECTED
IN_PROGRESS → REJECTED
PENDING/IN_PROGRESS → CANCELLED

No backward transitions. A rejected request cannot be re-opened — a new request must be created.

Authority

Who may act is a property of the association, not of the platform.

  • Only the association's admin changes, demotes, or removes a member who holds authority. Platform staff cannot. Staff set up new associations and nothing more, and a staff account with no membership in an association approves nothing and pays nothing there.
  • Granting or removing authority takes a fresh authenticator code, and both are emailed to the board.
  • Money abilities start off, except for an association's first officer. Paying vendors, vendor bank details, the transfer limit, top-ups, and the payout bank are granted per admin, only by someone who already holds the ability, with a fresh code and an email to the board. An ability that is off is refused on the server, not hidden in the interface. Approving bills, managing members, and changing rules start on, and an admin can be made read-only.
  • A resident account holds no ability. No admin role, no seat, no title: nothing to grant and nothing to steal.
  • A new association connects a bank only after its signup is approved.
  • Assessment schedules leave an audit record on every create and edit, the board is told of any change, and billing every unit takes a fresh code.

Governance → Controls shows how an association is set up, on one page.

A Fresh Code Before Money Moves

Signing in proves who someone was when they signed in. For the actions that send money or decide where it goes, and for the actions that change who holds authority, the person confirms again with the authenticator app, or a recovery code, within the last ten minutes. The list includes paying a vendor by transfer, changing a vendor's bank, changing the transfer limit, pulling money from the association's bank, approving a bill, writing an override, changing a fund policy or the approval workflow, adding or changing the payout bank, changing the bank PIN, giving or removing authority, and billing every unit. Paying several bills in a row needs one confirmation.

  • A text-message code never confirms one of these actions.
  • A person with no second factor is sent to enroll first.
  • A new authenticator cannot confirm a money action until the account's owner approves it from an email sent to the account's address. Rejecting it from that email removes it and locks the account.

The Association's Bank

An association's dues settle into its own connected account at the processor and sweep to its bank. Which bank that is, and who may change it, is controlled.

  • One pinned payout bank. Every bank on the association's processor account is recorded with a fixed role, and exactly one is pinned as the payout bank. A vendor's bank can never be the pin; the database refuses it.
  • The pin is checked against the processor every hour and on every bank and payout event. If the processor's default bank is not the pin, automatic payouts pause until a person restores the default and releases them.
  • A bank PIN that belongs to the association, not to a login. It is checked on the server. Changing it takes the current PIN and a fresh code, five wrong tries lock it, and staff cannot set it.
  • Changing the payout bank takes two board members. One asks; a different one confirms with the PIN and a fresh code. The board is emailed, and the first payout to the new bank is held until a person releases it.
  • The first payout bank needs payment authority in the association and an authenticator code. A bank that matches a vendor's bank on file is refused.

The controls on a vendor's bank, and on every payment, are in Disbursement Authorization Controls.

Overrides

A guard that can be overridden accepts a recorded board override instead of a block. An override names its scope and is recorded with the resulting enforcement decision. An override of a payment check is bound to the bill and the amount it authorizes and is used up by one posting. Writing one takes the Change rules ability and a fresh authenticator code, and the person who wrote it is judged again when it is spent: someone who no longer holds the ability, or who is barred by the association's own settings from authorizing their own payment, does not authorize it. Overrides appear in audit logs and in evidence packs.

Integrity Findings

The nightly integrity scan reports findings by severity: INFO, WARNING, and CRITICAL. Findings appear in the integrity views and in evidence packs. A finding does not by itself stop a payment. What stops a payment is the guard chain above, and the controls on authority and on the association's bank.

Policy Snapshots

Every governance evaluation references a frozen snapshot of the policy that was active at decision time.

PolicySnapshot captures the exact fund policy configuration (rules, thresholds, constraints) that was evaluated. Each snapshot includes a rules_hash and snapshot_hash for integrity verification.

GovernancePolicySnapshot captures the complete governance policy configuration at the time of the snapshot. Every governance artifact references one.

This prevents "policy ex post facto" arguments — no one can claim a different policy was in effect. The snapshot proves exactly which version of which policy governed each decision.

Each snapshot carries a SHA-256 hash of its content. The fund policy snapshot's verify_integrity() recomputes the hashes and compares them against the stored values, detecting any tampering after creation.

EligibilityRule Evaluation

Declarative eligibility rules can be evaluated for an association on request, through the eligibility API and a backfill command. Nothing in the posting path calls the evaluator: an evaluation reaches the enforcement chain only through exclusions, which the l5_exclusion guard reads. The framework defines nine rules, and 0 are in force in production today.

Rules are:

  • Versioned: Multiple versions of the same rule can exist. Only ACTIVE versions are evaluated.
  • Immutable once active: Once a rule moves from DRAFT to ACTIVE, its criteria cannot be modified. Changes require a new version.
  • Categorized: Rules cover GOVERNANCE, FINANCIAL, COMPLIANCE, VOLUME, TENURE, and COMPOSITE categories.
  • Deterministic: Each rule evaluates to ALLOW, DENY, or REFER (manual review required).

An evaluation run on January 15 can be reproduced exactly, using the rule versions that were active on January 15.

Definitions

Term Meaning
EnforcementDecision An immutable record of a financial authorization decision, including the outcome, guards evaluated, and timing
IntegrityFinding A detected discrepancy in ledger data, categorized by severity (INFO, WARNING, CRITICAL)
Evidence snapshot A frozen JSON document containing all relevant financial and governance data at a specific point in time

CARI Integration

Governance control effectiveness is one of five CARI score components, carrying a 25% weight in the composite score. The governance coefficient, which is derived from the telemetry the enforcement layer described here produces, is the primary input to the CARI Governance sub-score.

For published methodology and component weights, see CARI Methodology and Scoring Framework.


This describes production controls as o

How CommunityPay Enforces This
  • EnforcementDecision required for all production financial flows
  • 10 enforced flows: journal entries, fund transfers, bill payments, invoices, receipts, year-end close, loan origination, loan payments, loan accrual, trust transactions
  • Board-set bill approval tiers covering every amount, with a system default of one board approval where no tier applies
  • Only the association's admin changes, demotes, or removes a member who holds authority; staff cannot, and grants and removals are emailed to the board
  • A fresh authenticator code, within the last ten minutes, before money moves or authority changes; a text-message code never confirms a money action
  • One pinned payout bank per association, which a vendor's bank can never be; changing it takes two board members and the association's bank PIN, and the first payout to the new bank is held until a person releases it
  • Money abilities start off for every admin after an association's first officer and are granted only by someone who holds them, with a fresh code and an email to the board
Login