MassiveGL Dynamic Rules
Most ledger enforcement is hardcoded. If the business needs a new limit—a maximum account balance, a cap on transaction size, a rule that blocks weekend postings—someone files a ticket, a developer writes a check, the code ships in the next release. That cycle takes days or weeks, and the logic lives in application code rather than in the ledger where it belongs.
MGL solves this with Dynamic Rules. A dynamic rule is a CEL expression that the system evaluates on every posting, in real time, before the transaction is committed. If the expression returns false, the transaction is denied. No code change required. No deployment.
What the demo shows
The video walks through the full dynamic rules lifecycle from scratch:
- create an entity, journal, and three accounts (Cash, Bank, Opening Balance)
- post opening balances to establish a starting position
- navigate to Admin → Rules and create a
max_balancerule with the expressionbalance_after <= 100000.00 - watch the expression validated in real time as you type; the Save button only enables when syntax is correct
- observe the rule in DRAFT status—it cannot be enforced until certified by a second user
- create an
auditoruser, log in as them, and certify the rule; the system verifies the certifier is not the author and computes a cryptographic hash of the expression - log back in as admin, assign the rule at the journal level so it covers every account and every layer
- post a transaction that stays under the limit—it clears the rule and is tagged with the rule identity
- attempt a posting that would push Cash to 110,000—it is denied with an error showing the rule name, the current balance, the projected balance after, and the expression that failed
- browse the built-in help documentation, available in five languages
The Clark-Wilson model
The most important design decision in dynamic rules is the separation between authoring and certification. A rule in DRAFT status is visible but inert—it cannot be assigned or enforced. Only a different user can certify it.
This is the Clark-Wilson integrity model applied to ledger rules: the person who writes a rule cannot activate it. Certifying a rule transitions it to CERTIFIED status, computes a cryptographic hash of the expression, and permanently records who approved it and when. Any subsequent tampering with the stored expression—directly in the database—is detected at evaluation time by comparing the hash, and the rule is refused.
The practical effect is that no single person can introduce a posting rule without review. This is the same control you apply to payment approvals and journal entries; it applies equally to the rules that govern them.
The expression language
Rules are written in CEL (Common Expression Language), a safe, statically-typed expression language developed at Google. CEL expressions cannot access the network, the filesystem, or any state outside the activation context—they are pure functions of their inputs.
Every expression receives these variables:
| Variable | Type | Description |
|---|---|---|
balance | double | Account balance before this entry |
balance_after | double | Projected balance after this entry (balance + entry_amount) |
entry_amount | double | Signed impact of this entry (positive = increases balance) |
entry_layer | int | Layer number |
entry_is_debit | bool | True if debit |
entry_is_credit | bool | True if credit |
account_code | string | Account code |
account_type | string | "DEBIT" or "CREDIT" |
txn_post_date | string | Posting date (ISO format) |
txn_detail | string | Transaction memo |
txn_tags | string | Transaction tags |
param | string | Extra parameter from the rule assignment |
The param variable is particularly useful for reuse. A single entry_amount <= double(param) rule can be assigned to different accounts with different thresholds—one assignment might carry "5000", another "50000".
Assignment scope
A certified rule does nothing until it is assigned. Assignments can be scoped at three levels:
- Final account—applies to postings on that specific account
- Composite account—applies to every final account under that composite, recursively
- Journal—applies to every posting in the journal, regardless of account
Layer filtering is also available: you can restrict an assignment to specific layers, leaving others unchecked.
One rule can have multiple assignments. Assignments can be removed without modifying or re-certifying the rule.
What the error looks like
When a transaction is denied, the error message includes everything needed to understand why:
Rule 'max_balance:1' denied transaction on account 1111
balance=40000.00, balance_after=110000.00
expression: balance_after <= 100000.00
The rule code, its version, both balances, and the expression are all present. No digging through logs.

