All posts
AI FDECertant StrataAgent BuilderEnterprise Agreement

Four employees below their legal minimum: the Aruma scenario end to end

A screenshot-led walk through the Aruma pay-compliance run: bind a knowledgebase, ask in plain English, approve one correction, get four names back.

Daniel Voyce··9 min read

In our test corpus, four support workers are paid below the hourly minimum their enterprise agreement sets for their classification and pay point. The agreement is real; the figure sits on pages 147 and 148 of a 155-page PDF that no payroll system had read.

This is the scenario we used to prove the AI FDE on real data, from screenshots taken on 16 and 21 July 2026, and some of it went wrong on camera.

The agreement is a published document, the Aruma DSEAV 2022-2025. The payroll is synthetic: 57 employees generated onto the agreement's own classification and pay-point codes, so the join is real rather than rigged.

How the two documents join

Schedule J is a pay table: 41 pay rows across 4 effective dates and 3 measures, 492 numbers on two pages. Our spot-check cell is DDSO 2, pay point 4, effective 1 July 2023, weekly rate $1,370.25. At the 1 July 2025 column the hourly rates run from $29.01 for a DDSO 1 at pay point 1 up to $68.10 for a DDSO 6.

The payroll export carries each employee's classification and pay point as codes, so the two documents join on classification + pay_point. Nobody typed that join anywhere: no schema file, no declared join condition. The model layer worked it out itself.

Knowledgebase wizard with agreement and payroll export indexed, FDE drawer open
The knowledgebase after ingest: the 155-page agreement and a 14 KB payroll export, FDE drawer bound and waiting. The credit badge bottom-left reads -283.223 in red. Captured 21 July 2026.

Asking it the way a payroll admin would ask

The question we put in was "which employees were paid below their EA minimum rate in FY2026? Compare the payroll payments against the EA entitlements in this knowledgebase and show me the workers and amounts." Three green chips came back for the read calls, then the agent stopped.

FDE drawer with three green tool chips, then a clarifying question with two buttons
The first turn ends in a question rather than an answer: "Which object type or view in this knowledgebase contains the EA minimum rates?", with two buttons. Captured 21 July 2026.

That stop is deliberate: a keep-momentum rule stops the agent asking to proceed with already-granted work, except a tier-3 action that must park for approval, or real ambiguity. Buttons carry the ambiguity, not free text, because a 65K-context sovereign model resumes more reliably from an option ID than a typed paragraph.

The refusal, and what it said

Pushed past the clarification, the agent refused to guess.

Drawer with six chips including a red failure, then a refusal above a raw extracted rate table
The refusal in full, with the raw DSEAV rate rows underneath it. The red chip is a real failure, a call to a tool name that does not exist; the "[object Object]" beside it is a UI defect fixed later that week. Captured 21 July 2026.

Its refusal:

I'm unable to answer the request as-is because the EA minimum-rate data you want to compare against isn't represented in the active ontology. The "DSEAV" document contains the minimum rates in a raw extracted table, but there's no governed view or object type for those rates in the knowledge base, so a query that joins PayFact to the EA minimum rates can't be constructed.

It then names the fix: add the DSEAV rates to the ontology as an object type, expose a view with the classification and FY2026 hourly-rate columns, and the comparison becomes constructible. The rows were right there; it could have guessed or averaged them instead. It said no, and named the missing step.

One correction, parked for a human

So I told it to do exactly what it had proposed.

Drawer with two red chips, an amber validator finding, and a question about EntitlementFact properties
The first attempt: two calls to tool names absent from the active mode's pack, a switch into ontology mode, a validator finding, then an honest question. "I can't create a brand-new object type via the correction tools. Would you like to add the minimum-rate columns as properties to an existing object type instead?" Captured 21 July 2026.

We'd limited the corrections ledger to binding and reclassifying properties on existing objects, not minting a new object type or link type. The agent hit the wall, said so, and offered the routes it had. We shipped add_link_type as a correction kind shortly after, with five other gaps this run surfaced.

Answering the question, it planned.

Drawer with a follow-up instruction and a one-step plan card for binding the minimum-rate columns
The one-step plan for the correction. Both documents now read "Fully indexed", which they did not two frames earlier. Captured 21 July 2026.

Applying a correction to the active model is a tier-3 action: a row in the approvals ledger, a manifest digest frozen at approval time, nothing landing until a human clicks. Self-approval is on by default, flagged in the inbox, so a lone operator isn't deadlocked.

The recorder saved three frames for that take (park, approved, done), all identical, so the approval click isn't in these stills. The program log shows what the screenshots don't: the correction chain ran park to approved to executed, reaching ontology v8 with a paid_against_schedule link type behind approval ledger led_3eab7c6ea2a9.

The answer, and the arithmetic underneath it

With the rates in the model, the governed query works.

Drawer showing hourly rates by classification and experience year, with a table and notes
Hourly rates by classification and experience year, retrieved from PayRateFact instances rather than generated. DDSO 1 pay point 1 reads 26.55 for 2022 and 28.16 for 2025. The notes underneath explain that "year" is the progression step rather than a calendar year. Captured 21 July 2026.

The below-minimum answer landed the next day and matched a ground truth I'd already computed with a raw DuckDB join: four employees.

Ground truth for the 1 July 2025 floor, computed before the agent was asked. Rates are AUD per hour.

Payroll ID Name in payroll Classification Pay point Paid Minimum Shortfall
E1001 S. Rossi DDSO 1 1 27.67 29.01 -1.34
E1017 D. Rossi DDSO 1Q 1 32.27 33.22 -0.95
E1032 L. Nguyen DDSO 2 4 34.42 38.26 -3.84
E1038 (empty) DDSO 2A 3 35.73 37.83 -2.10

The headline number people quote from this scenario is AUD 16,262.48 a year, which gets misread often, including in our own catalogue notes. The four shortfalls add up to 8.23 an hour; 38 hours a week over 52 weeks is 1,976 hours; 8.23 × 1,976 = 16,262.48, the combined exposure across all four. I would sooner correct my own marketing than have a customer check it in front of me.

Two things went wrong before that number was right, both caught only because the ground truth existed first.

The model read "year" in the rate schedule as calendar 2025 instead of the progression step it is, and returned zero rows. Worse, asked about "our Aruma staff", the resolver read the organisation's name as a division-column filter, found nothing, and reported no such staff. The fault sat in the retrieval service's resolver prompt, never told what corpus it was looking at. Injecting the knowledgebase's name and description into that prompt, read from its metadata to stay domain-agnostic, fixed it: three of three probes with the same phrasing returned the four correct employees.

The same week, a different failure: the agent's first comparison table came from a code-execution node doing a positional merge, with duplicate IDs, every pay point stuck at 2, and inconsistent minimums. It looked reasonable and was wrong, which is why code execution is now a last resort in the agent-builder mode pack, with data-transform and switch nodes preferred even with more blocks on the canvas.

From data model to working agent

Agent Builder canvas with Start and Respond nodes, FDE drawer offering the Aruma knowledgebase as a binding target
The drawer on the builder page, offering to bind to the Aruma agreement knowledgebase before it will build anything. Captured 21 July 2026.

By then the knowledgebase carried a governed model.

Data Model page showing ontology v8 and nine object-type cards with typed properties and table counts
Ontology v8 over the Aruma knowledgebase: nine object types, typed properties, backing-table counts, and a Corrections tab carrying 5. PayRate shows its composite key, classification + eff..., the join this scenario turns on. Captured 16 July 2026.

I described the agent in one sentence; the builder read the model, chose the blocks and wired them.

Agent Builder canvas mid-build with eight query-and-chart node pairs, side panel of connect_nodes chips
Eight question-and-chart branches drafted from one description, wired into a summarising node and a respond node. One chip reads "retry: upstream returned 500; retrying in 1s (1/2)", from a live run. Captured 16 July 2026.

The ninth question, I typed myself: who is paid below the pay rate for their classification and pay point. I built it in three blocks and one English sentence; the builder had already drafted the other eight.

Test Agent panel showing a generated board report with a footer reading 107620ms and 21 nodes
A live test run of the saved agent: 21 nodes, 107,620 ms wall clock. The narrative it wrote is commentary over computed numbers, read it sceptically. Captured 16 July 2026.
Dark dashboard titled Aruma Board Report FY2026, with a line chart, a payroll-by-office pie, a pay-ladder bar chart and an employment-type donut
The board: nine widgets, nine chart types, each one picked by the engine to fit the shape of its answer. Captured 16 July 2026.
Three dashboard widgets, the lowest a bar chart titled Below the 2025 floor naming four employees
The widget the ninth question produced, "Below the 2025 floor", with four named employees on it. Captured 16 July 2026.

Two product limits showed up while building that board, both still filed: an agent can't create a dashboard (no create-dashboard node, so an empty board must exist first), and publishToDashboard can only create chart widgets, one of the six types the dashboard supports.

Video poster frame for the Aruma agent builder demo
Poster frame for the 9 minute 59 second 4K narrated cut of this scenario, recorded live on 16 July 2026. The master lives under docs/videos/aruma_agent_builder_2026-07-16-v3/, gitignored and not in the repository; the narration script and subtitle sidecars are.

What these screenshots do not show

Three frames in the FDE capture set caught turns still running: the below-minimum ask, the agent-build ask and the analytics step all show "Working…" and a Stop button, so the four names, built nodes and populated board never made it in.

Analytics page with one dashboard card, an empty preview, 0 widgets and Never refreshed
The board as the FDE run left it: created, empty, waiting. The populated version above came from the separate agent-builder recording five days earlier. Captured 21 July 2026.

The two runs sit five days apart on different ontology versions. The 16 July money chart names S. Rossi, D. Rossi and L. Nguyen from the ground-truth table, plus a fourth, T. Kaur, who doesn't appear in the later, corrected four. That fits the OCR contamination below: the earlier run predates the Unlimited-OCR re-parse, so a chart built on it doesn't guarantee the same four names, only the same shape of answer.

Under GLM-OCR, the fill-down of merged classification cells crossed a class-block boundary, contaminating the DDSO 1 rows and producing five or six below-floor employees where the truth is four. Re-parsing the same PDF with Unlimited-OCR fixed the rowspans and brought DDSO 1 back to 1,008.75 weekly and 26.55 hourly, matching the printed page. One residual remains: the vision model misreads "DDSO 1Q" as "DDSO IQ" on some pages, visible in the headcount widget above.

The red credit badge: the seeding script drained the demo account's trial balance to -283.223, and the agent answered anyway. The badge reports a balance; enforcement is a separate switch, and I didn't record which mode the VM ran in, so this only shows it didn't block. A top-up to about 1.7k lands between the second and third screenshots.

I haven't timed the whole scenario as one wall-clock number. The one figure I trust from this arc covers a different task: a fresh knowledgebase to a working ontology in 274 seconds, well short of the correction and the board.

If you want to run this test on your own corpus, put in two documents that join on something nobody has declared, work out one hard question on paper first, then ask in the words the person who owns the problem would use, and see whether the system says it can't do it yet.

Build a brain for your business.

Certant turns your documents, data and processes into agents, dashboards and assistants you can actually trust.