Our AI Doesn't Decide Whether You Should Buy. It Only Explains the Decision.
Design trade-offs in the OOtira decision engine
By OOtira Team
The first design question we faced when building OOtira's purchase decision feature was whether a language model could be trusted to judge, on its own, whether a user should buy a given garment.
We concluded that it could not, and split the system into two layers as a result: a deterministic decision layer, and a language layer responsible for explanation. This post sets out the reasoning and the implementation.
Why the model does not decide
Handing the user's wardrobe and the candidate item to a language model and asking for a recommendation is the cheapest thing to build. We rejected it for three reasons.
Verdicts were not reproducible. Given the same wardrobe and the same item, the model could return different conclusions across calls. For a tool whose entire premise is that the user can rely on it, unstable output is a structural defect rather than a rough edge.
The basis for a verdict could not be audited. When a user disagrees with a conclusion, we need to be able to state which specific facts produced it. A model's internal reasoning does not give us that.
There was a factual risk. The model could cite garments the user does not own. One such error is enough to end a user's trust in the whole system.
Four deterministic signals
We decomposed the purchase decision into four computable signals, all derived from structured data, none of them involving model judgement.
Redundancy measures overlap between the candidate item and garments the user already owns, comparing category, colour, material, and warmth. We set a deliberately high threshold here: the signal fires only when several dimensions align closely. This is intentional. Wrongly blocking a reasonable purchase damages the user's experience more than occasionally letting a redundant one through.
Gap determines whether the item fills a genuine absence, based on how the user's existing garments are distributed across categories and warmth bands.
Weather evaluates whether the item has a wearable window within the next eight days of forecast for the user's city. This signal addresses a specific and common failure: buying seasonally wrong clothes during a transition, for weather that is not actually coming.
Pairability reuses the outfit rules engine already in the system to count the combinations the item forms with garments the user owns.
The four signals are composed by priority into a final verdict of Skip, Wait, or Buy. The process is deterministic: identical inputs produce identical outputs, and every verdict can be traced back to specific signal values.
Where the structured fields come from
Computing those signals requires structured garment attributes. That is the part Gemma 4 handles.
Uploaded images are processed through Cloudflare AI Gateway to Workers AI for edge inference. The model returns category, subtype, primary and secondary colours, material, a warmth rating from one to five, applicable seasons, and style tags.
The distinction worth drawing out: in this step the model performs perception, not judgement. It answers what the garment is, not whether it should be bought. Once perception is written to the database, every subsequent decision computation runs on those fixed fields without calling a model again.
Recognition results are cached by image content hash, so the same garment is never processed twice.
The language layer, and its constraints
Only after the verdict is settled does the system call a language model to generate the written reason. The input to this layer is the verdict and the signal values that produced it. The output is a short explanation for the user.
We constrain this layer strictly: the generated reason is validated against the user's actual wardrobe, and a reason citing garments the user does not own is rejected.
The point of the constraint is containment. It confines whatever errors the model makes to the level of phrasing. A phrasing error costs the user one awkward sentence. A judgement error costs us their trust in the system.
On cost
Because decision computation does not depend on a model, model calls occur in only two places: garment recognition and reason generation. The first is cached by image hash, so a garment is recognised once. The second runs once per verdict.
Weather data is cached in KV; daily recommendations are cached per user per day. Together these keep external calls for an active user in the single digits per day.
Where this design stops applying
We do not hold that determinism is generally preferable to model judgement. This trade-off works because purchase decisions for clothing can be decomposed into a finite set of dimensions, and because those dimensions can be extracted from an image reliably.
Where the dimensions cannot be enumerated, or where structured extraction is itself unreliable, the same architecture would not carry over.
For OOtira, the design produces one concrete property: every verdict can be explained to the user, and traced back to its basis when they disagree. For a tool that has to earn long-term trust, we think that property is worth the architectural cost.
OOtira is a weather-aware closet assistant for the North American market, currently in closed beta.
https://style.ootira.com