Nivista stages Indian interiors from a photograph. One of its core features is vastu analysis: score a room against vastu principles, explain what is wrong, suggest remedies, and optionally constrain the generated design to comply.
The fastest way to build that is to describe the room to a language model and ask it for a vastu assessment. It works in a demo. We did not ship it, and the reasoning behind that decision turned out to be one of the more portable things we learned.
Three problems with asking the model
It is not reproducible
Ask twice, get two different scores. For a subjective creative output that is fine, even desirable. For something presented as an assessment, it destroys credibility — and a user who screenshots two different scores for the same room is entirely right to stop trusting the product.
It is not explainable
The model can produce an explanation, but that explanation is generated alongside the score rather than being the reason for it. When a user disagrees — and with vastu, users disagree, because traditions vary by region and family — you have nothing to point at. You cannot say 'this rule, this direction, this principle'. You can only say 'the model thought so'.
It cannot be tested or corrected
When a domain expert tells you rule seven is being applied wrongly for south-facing entrances, you need somewhere to go and fix rule seven. Prompt-encoded logic has no rule seven. You adjust wording, hope, and discover you have changed something unrelated.
What we built instead
The vastu engine is plain Python. It takes structured input — room function, orientation, entry direction, position of fixed elements — and returns a score, a list of findings with the specific principle each one references, and concrete remedies. It is deterministic, unit-tested, and versioned. When a rule changes, one function changes and the tests tell us what else moved.
structured room -> rule engine -> score + findings + remedies
|
+--> generation constraints -> image modelThe model's job is what only a model can do: render a photorealistic, culturally appropriate room. The rules are supplied to it as constraints. Nothing the user might argue about comes out of the model.
The general pattern
Vastu is our instance of it, but the pattern applies everywhere generative systems meet consequential domains. Split your system along one line: what is genuinely generative, and what merely looks like it could be.
- Deterministic code: eligibility, scoring, pricing, compliance, entitlements, anything with a right answer someone can appeal.
- Generative model: prose, images, summarisation, classification of messy input, anything where variation is acceptable or desirable.
A useful test: if a user could reasonably send you an email saying 'this is wrong, and here is why', that output should come from code you can point at. Loan eligibility is code. The rejection letter's wording is generation. A medical triage threshold is code. The explanation to the patient is generation. Tax computation is code. The summary of what changed is generation.
The harder part: whose rules?
Encoding a cultural tradition into software forces a decision most engineering avoids: whose version. Vastu varies by region, by school and by family. There is no canonical specification, and pretending otherwise would be its own kind of dishonesty.
Our answer was to make the rule set explicit and inspectable rather than authoritative. Users see which principles were applied. Rules are grouped so regional variants can be selected rather than assumed. And the product's language is advisory — findings and suggestions, not verdicts. That is a product decision more than a technical one, but the architecture is what made it possible. You cannot offer users a choice of rule sets if the rules are dissolved into a paragraph of prompt text.
Put the contested logic where you can point at it, argue about it, test it and change it. Let the model do the part that genuinely needs a model.