Lessons Learned in Translating Regulatory Judgments into Software: A Record of Q-Atelier Engine Design
Real issues encountered when coding regulatory requirements as rules.
This record organizes the design of a system that conducts judgments outside the engine, which addresses reproducibility, rule versioning, and expert calibration.
Judgments Cannot Expand If They Only Reside in Human Minds
The most common question in medical device licensing practice is: "Do I need to obtain approval again for this change?" This arises when raw materials are changed, dimensions adjusted, or software patched.
The answer varies each time, and usually, only one or two individuals within the organization know the answer.
The issue is that those judgments do not remain documented.
When the primary person is absent, the same question may receive a different answer, and when asked in an audit, they have to reconstruct the reasoning for their decision.
As long as the quality of judgment remains tied to individuals, even with organizational growth, the capacity for regulatory compliance will not increase accordingly.
Q-Atelier was created to translate this judgment into software.
Initially a desktop application, it has now migrated to the cloud, allowing various organizations to utilize their own data.
Below is a record of design decisions made during this process and the reasons for those decisions.
Keeping Rules as "Data" Rather Than "Code"
The first principle established was not to implement rules in condition statements.
If regulatory judgments were coded with if statements, every time a rule changed, the code would need to be modified.
Fixing code necessitates deployment, and when deployment is required, the speed of following regulatory amendments is tied to developmental schedules.
Most importantly, it becomes unreadable for humans to know which rule was applied.
Thus, rules were separated out as data.
Risk mapping, impact areas, and judgment bases each exist as separate data structures, and the engine merely "interprets" this data.
When reinforcing rules, one modifies the data while keeping the engine code intact.
Additionally, we attached a ruleset version to it.
The outcome of a judgment retains the version of the ruleset used for that decision.
As regulations change, rules also adapt, but without a version, one cannot explain why past judgments differ from current ones.
With a version, we can say, "This judgment was made based on the rules at that time," and if necessary, we can revert to new rules to compare differences.
The Judgment Engine Must Be a Pure Function
The engine was built as a pure function that does not call on databases or networks.
Input yields output, and the same input will always produce the same output.
There are two reasons for enforcing this constraint:
First, it must be reproducible.
When an audit requires the basis of a judgment, we should be able to demonstrate that "the system gave this answer at the time" instead of just saying, "if the same input is entered now, you get the same answer."
If the engine relies on the DB state at runtime, this principle fails.
Second, it must be testable.
Regulatory judgments carry significant consequences when incorrect, and visual validation deteriorates as rules increase.
Pure functions allow for automatic verification of input-output pairs by stacking them up.
Moreover, the judgment logic itself is divided into stages.
Determine baseline risk, adjust according to combinations, reflect impacts indicated by the development department, produce necessary documents and tests as outcomes, and finally, attach warnings to points requiring attention.
Each stage is separated, allowing us to trace where judgments diverged.
Changes in Rules Must Be Noticeable
Though there are many advantages to keeping rules as data, one risk emerges:
Unintended changes occurring quietly when the data is modified, affecting judgments elsewhere.
In regulatory judgments, this risk is particularly dangerous.
Errors don’t show up on screens, there are no logs left behind, and answers may just change without notice from one day to the next.
Users have no way of realizing this.
Thus, we implemented a Golden Snapshot for the engine's output.
The current outputs for representative inputs are frozen in time; after changing rules, if the same tests yield different outputs, the tests fail.
The moment this safety net was genuinely necessary was when we shifted the judgment logic to a structure that treated rules as data.
While completely altering the internal structure, the output had to remain 100% the same, and with multiple screens and documents utilizing those judgment results, if one were to diverge quietly, it would be challenging to pinpoint.
By freezing the snapshot first and then refactoring, we ensured that we could confirm every time that the "judgment remains unchanged."
The principle is simple:
Only update the snapshot when the rules are changed "intentionally."
Any other changes are classified as incidents.
Judgment Logic Must Not Leave the Server
The ruleset itself serves as an asset.
The moment it goes down to a browser, anyone can inspect it.
Thus, a server-only marker was placed on the judgment module.
If it ever accidentally gets included in a client bundle, the build fails.
Instead of relying on people to adhere to the rules, we made it so that if the rules are violated, the build breaks.
From experience, mere promises to be cautious will inevitably leak over time.
If there are boundaries that must be upheld, it is better to include a device that automatically fails when the rules are broken.
Human Judgment Should Stay "Outside" the Engine
This point was where I pondered the longest while creating the engine.
There will always be cases where experts disagree with the engine's judgment.
This could be due to products that the rules still cannot manage or simply needing to view the same change differently based on context.
When this occurs, directly modifying the engine's rules undoes two critical aspects.
One is reproducibility;
Past judgments can no longer be run again.
The other is traceability;
It becomes impossible to differentiate whether a judgment arose from the rules or from human intervention.
Thus, we placed calibration outside the engine.
Keeping the engine as a pure function, expert-calibrated adjustments are applied in the wrapper layers located before and after the engine.
Calibration does not overturn judgments but adjusts them.
For example, it may raise or lower the risk level by one step under certain conditions.
The core concept is that what has been applied will remain recorded in the results.
When inspecting a judgment outcome, it will display both the engine-generated answer and any calibration that has been added above it.
In the future, when asked "why was this particular judgment reached," we can distinguish if it was due to rules or a human calibration.
Thanks to this structure, the engine remains a pure function while human contributions are recorded.
It took considerable time to find a method that didn't require sacrificing either.
Accumulate in Reversible Units
Schemas are continually evolving.
Regulatory requirements expand, screens increase, and flaws in initial structures emerge.
Thus, database changes were accumulated one at a time, in reversible units.
The backlog of changes to date amounts to hundreds, each with records of "when, what, and why changes were made."
More critical than the scale is the fact that this did not occur all at once.
The structure has been changed several hundred times, and it has consistently been preserved in a reversible manner.
In regulatory systems, this habit is not a choice.
When auditors ask, "Since when has this data been managed this way?" the answer needs to live in the history.
Areas Still Needing Humans
The engine is precise only within the scope of rules.
Judgments that fall outside those rules,namely, products without precedent or edge cases requiring discussion with reviewers, as well as clinical design,are still the domain of human operators.
Thus, Q-Atelier operates on a structure where the engine produces results and experts cross-validate them.
The goal is not to replace humans with the engine but rather to ensure that people don’t have to make judgments from scratch each time.
This article is not a boast but a record.
The challenges we faced while converting regulatory judgments into software will likely be similar for organizations attempting the same.
Should we separate judgments from data? Should we make them reproducible? Should we introduce measures to notice changes? Where to place human intervention?
These decisions must be made before building functionality and are the hardest to reverse later.
If you're reviewing a regulatory system suited for your organization, I've organized how to proceed with Q-Atelier Bespoke.
Frequently asked questions
How does a rules engine differ from generative AI?
A rules engine produces the same result for the same input.
Its reasoning is recorded in rules, so the basis for a decision can be reproduced during an audit.
Generative AI may answer the same question differently, making it difficult to use as the basis for a regulatory determination.
What happens to past decisions when regulations change?
The ruleset version is recorded with each result.
Even after rules change, this shows that the original decision used the rules in effect at that time.
When needed, the same case can be run against the new rules and the differences compared.
What if an expert disagrees with the engine's decision?
A separate adjustment is registered without modifying the engine.
The adjustment is applied outside the engine, and the result records which adjustment was used so it can be audited later.
Let's talk
Apply what you have read
to your product.
Tell us your product's current stage and the questions you need to review.
Discuss your questions ↗