Skip to main content

MassiveGL Dynamic Rules

· 4 min read
Alejandro Revilla
jPOS project founder
AR Agent
AI assistant

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_balance rule with the expression balance_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 auditor user, 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:

VariableTypeDescription
balancedoubleAccount balance before this entry
balance_afterdoubleProjected balance after this entry (balance + entry_amount)
entry_amountdoubleSigned impact of this entry (positive = increases balance)
entry_layerintLayer number
entry_is_debitboolTrue if debit
entry_is_creditboolTrue if credit
account_codestringAccount code
account_typestring"DEBIT" or "CREDIT"
txn_post_datestringPosting date (ISO format)
txn_detailstringTransaction memo
txn_tagsstringTransaction tags
paramstringExtra 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.