POC exploration
The Model Interprets; Code Computes: The Decision That Keeps Disha Honest
21 engine tests · Gemini never computes carbon
The tempting version of Disha was one prompt: describe a trip, ask Gemini for the carbon, cost, and time, then put the answer in a polished card. It would have made a convincing demo. It also would have produced numbers that changed with the wording and gave the user no way to tell where they came from.
I drew the boundary in a different place. Gemini reads the messy part. It turns a sentence, voice transcript, or booking screenshot into a typed intent and a set of candidate options. A plain function does the carbon math from a versioned factor table. If a carbon number comes directly from the model, the architecture has failed.
That split made the system less magical and much easier to test. Text, speech, and screenshots all end at the same contract. The engine gets the same input shape and returns the same result for the same factors. The core tests check repeatability and direction, so the greener option cannot accidentally score worse after an unrelated prompt change. The factors are India-specific, including the local grid and rail assumptions, rather than defaults copied from a different market.
Screenshots needed another boundary. Text inside an image is untrusted data, not an instruction to the model. The parser extracts route, mode, quantity, and price, then the same engine takes over. Structured output is validated and rejected when it misses the contract. If Disha falls back to an estimated factor, the UI labels it as estimated instead of placing it beside a verified number with the same visual confidence.
Deterministic does not mean maintenance-free. Someone has to own factor updates, effective dates, and source history. The screenshot path needs adversarial tests as model behavior changes. A third-party calculation API could reduce some of that work, but it would add an availability dependency and might not carry the Indian factors the product needs. I chose local, inspectable math because this is one of those products where a boring function is more trustworthy than a fluent answer.
The decision
Let Gemini extract intent and candidate options. Run every carbon calculation through a deterministic, tested engine backed by explicit factors.
Alternatives considered
- ·Ask the model for the final carbon estimate. Fast to demo, but the number has no stable provenance and can change with phrasing.
- ·Depend entirely on an external calculator API. Easier factor maintenance, but weaker India coverage and another availability boundary.
- ·Use a static form instead of a model. Predictable, but it loses the text, speech, and screenshot entry points that make the product useful.
Tech stack
The challenge
Turn a sentence, voice note, or booking screenshot into an India-specific comparison without allowing a fluent model to invent a carbon number that looks authoritative.
Architecture approach
- ·Normalized text, speech, and screenshots into one typed intent contract.
- ·Restricted Gemini to interpretation; a pure function computes from the versioned India factor table.
- ·Rejected malformed structured output and treated screenshot text as data rather than instructions.
- ·Exposed factor sources and marked estimates so a fallback could not masquerade as a verified value.
Results
- One calculation path across all three input modes
- 21 deterministic engine tests covering direction and repeatability
- A live end-to-end deployment on Vercel, Cloud Run, Vertex AI, and Firestore
What I'd do differently at production scale
- ·The factor table becomes a maintained product dependency. Values need owners, effective dates, and a visible update history.
- ·Screenshot ingestion needs continuing adversarial tests because an image can contain both booking data and hostile instructions.
- ·Source confidence must survive the full UI path so estimated and verified numbers never look interchangeable.