Skip to content

Rules About Many Things Tutorial

Most rules ask one question about a document: was it signed?, what is the total? This tutorial is about the other kind — rules about the several things a document describes. A credit memo lists loans. A vendor review lists suppliers. An incident report lists affected systems. A rule like "no loan may exceed $950,000" is not one question about the memo; it is one question about each loan, and the memo does not say how many there are.

You will build a ruleset that gets that right, watch it fail on a document that a single-answer version would have passed, and see why.

Prerequisites

Access to a running Jaxon platform instance, and the SOX Compliance Tutorial or equivalent familiarity with creating a ruleset and using the Ruleset Studio's test panel. The concept behind this tutorial is One thing, or several?.


Step 1: Set Up Your Project

  1. Click the Project dropdown in the top header bar.
  2. Select New Project.
  3. Name it Loan Portfolio Tutorial and click Create Project.

Step 2: Write the Rule the Wrong Way First

This step is worth doing rather than skipping. The failure it produces is quiet, and seeing it once is what makes the correct version obvious.

  1. Navigate to Rulesets in the sidebar and click Create Ruleset.
  2. Name it Loan Portfolio Caps, and choose to author rules directly rather than extracting them from a policy document.
  3. Add a rule named Loan cap with this DSAIL:

    declare loan_amount as numeric;
    
    assert cap [pessimistic] { loan_amount <= 950000 "USD" };
    
  4. In the test panel, paste this credit memo:

    Loan L-101 was originated in March with a principal of $400,000.
    It is fully secured by collateral.
    
    Loan L-207 carries a principal of $1,200,000 and is unsecured.
    
  5. Click Run Test.

Look at the Claims section of the result. loan_amount has one value, because the ruleset asked for one. The memo describes two loans, one of which breaches the cap by a quarter of a million dollars — and depending on which figure the extractor settled on, this rule may well report YES.

Nothing errored. No warning appeared. That is the whole problem: a rule that asks a single-answer question about a multi-answer document produces a confident verdict about the wrong subject.


Step 3: Name the Kind of Thing

Now tell the ruleset that the document describes loans, and that each one has its own amount.

Edit the rule's DSAIL to:

declare Loan as entity;
declare amount as numeric of Loan;
declare is_secured as boolean of Loan;

assert cap [pessimistic] { ForAll(l in Loan, amount[l] <= 950000 "USD") };

Three things changed:

  • declare Loan as entity; names a kind of thing. You never say how many — that is discovered from each document.
  • of Loan binds a claim to that kind, so amount is extracted once per loan instead of once per document.
  • ForAll(l in Loan, …) says the constraint applies to each loan. Inside it, l is a handle and amount[l] reads that loan's amount.

Check the Claims section for each claim's extraction question. amount should ask about a single loan ("What is this loan's principal amount?"), not about the document ("What are the loan amounts?") — the platform asks it once per loan, so a question phrased in the plural will confuse the extractor.

Run the test again on the same memo. cap now resolves NO, attributed to the sentence stating the $1,200,000 principal.


Step 4: Ask Questions Only an Entity Can Answer

The reason to name a kind — rather than just quantifying over amounts — is that claims of the same instance stay tied to each other. Add these rules:

assert any_secured [pessimistic] { Exists(l in Loan, is_secured[l]) };

assert big_loans_secured [pessimistic] {
    ForAll(l in Loan, Implies(amount[l] > 500000 "USD", is_secured[l]))
};

Run the test again on the memo from Step 2:

Rule Verdict Why
cap NO L-207 breaches the cap. One counterexample refutes every.
any_secured YES L-101 is secured. One witness satisfies some.
big_loans_secured NO L-207 is both the large one and the unsecured one.

big_loans_secured is the one that could not be written without an entity. It does not ask whether some loan is large and some loan is unsecured — it asks whether the same loan is both, which is only a question you can pose once the amount and the securedness belong to a shared instance.

Note that cap and any_secured disagree on the same document. That is correct, and it is the signature of a rule about many things: every and some are different questions.


Step 5: Count Things

Cardinality rules — "no more than one defaulted loan" — use the counting quantifiers. Add a status claim and a rule:

declare status as enum ["performing", "watch", "default"] of Loan;

assert few_defaults [pessimistic] {
    AtMost(1 "", l in Loan, status[l] == "default")
};

AtLeast, AtMost, ExactlyOne, and CountWhere all range over an entity scope. Use them rather than trying to take the length of the scope: the number of loans is not known until the document has been read, so there is no collection whose length you could ask for.

Test it with a memo describing three loans, two of them in default, and few_defaults resolves NO.


Step 6: Understand Unknown

Run the ruleset against a document that mentions no loans at all — a cover letter, say. Every rule resolves Unknown, not YES.

This is deliberate, and it is the opposite of what a naive reading of "every loan complies" would give you. Extracting no loans does not establish that the document describes none; it may be the wrong document, an unreadable scan, or a page that got truncated. A clean pass on a document nobody could read is worth less than no answer at all, so the platform declines to give one.

The same applies per claim. If a loan is described but its amount is never stated, a rule about amounts is Unknown for that loan — though a different loan that plainly breaches the cap still resolves the rule NO, because one counterexample is enough regardless of what else is unknown.


Step 7: Publish and Run a Batch

  1. Click Save, then Publish to create a version.
  2. Build a dataset of credit memos — vary the loan counts, and include at least one document with no loans and one where the same loan is described twice.
  3. Navigate to Runs, create a Batch run against your ruleset and dataset, and check Evaluate.

In the results, expand a document to see the per-loan claim values: each claim shows one entry per discovered instance ("2 answers: 400000 USD; 1200000 USD"), so you can check that instance discovery matched what the document actually describes before you trust the verdicts.

If a document describes the same loan twice with conflicting figures, the rule reports Ambiguous rather than picking one. That is a distinct outcome from Unknown: Unknown means the document did not say, Ambiguous means it said two things and they disagree. They need different fixes, so the platform keeps them apart.


Next Steps