Murat Can Ümit
Solutions architect and founder. I build production AI systems alone, and I know what they should refuse to claim.
Twelve years across banking, aviation, telecoms and consulting. I have designed, built and operated two AI products end to end and alone: architecture, inference, entitlement, release and on-call. Currently in Istanbul.
Tactiq
Tactiq is a live football match-analysis platform with users in 175 markets. What follows is not a feature list. It is the three decisions that were hard, where a wrong answer would not have crashed anything. It would just have been wrong for months. Then the whole system, drawn once.
Three regions, one exception
One hundred and seventy-six Lambda functions run in production behind API Gateway across three AWS regions, with latency-based routing and sixteen Route 53 health checks. Forty-three distinct functions are replicated to all three in an active-active layout; the remainder are deliberately single-region scheduled and backfill jobs, because running a cron in three regions produces three writers competing over the same state. The distribution is deliberate rather than symmetric: us-east-1 carries eighty and runs the batch, calibration and tournament workloads, while eu-central-1 and ap-northeast-1 carry forty-four and fifty-two and serve the user path. A user in Tokyo and a user in Frankfurt are served by different regions and see the same product.
Forty-one DynamoDB tables hold the state. Thirty-six of them replicate across all three regions. Five do not, and that exception is the design decision: paid entitlement and refresh tokens live in a single-region authority with one writer and atomic conditional writes, propagated outward every minute, and every region reads its verdict from there rather than replicating it. Propagation and reconciliation are two jobs, not one: propagation is event-driven and runs in minutes, while a weekly reconciliation checks that ledger against store exports, because the stores hold the truth about who has paid and drift has to be measured against the source rather than against ourselves. A replication canary runs every five minutes and alarms on cross-region latency, because a replication lag you cannot see is the same as one that is not happening.
Multi-region last-writer-wins is fine until it silently drops a tier change, and a customer losing paid access is a failure you hear about from an angry message, not an alert.
Structural constraint, not instruction
Three fail-closed checks run before a request reaches a model: app attestation, HMAC request signing and a signed short-lived token. If any of them cannot be verified, the request stops there.
After generation the output passes a server-authoritative grounding layer, schema validation and a language guard before any caching decision is made. The model cannot emit a number the server did not supply, cannot return a shape the schema does not accept, and cannot answer in a language the request did not ask for. Output that fails is thrown away, not patched.
Prompt-level guardrails fail silently and you find out from a screenshot on social media.
Measured against a live baseline
Every week the system scores its own predictions against real results and computes hit rate per confidence band. The distance between stated confidence and observed accuracy is the calibration error. Past a threshold, and only where the sample is large enough to mean something, it raises a drift alarm. The rollback itself is run by hand from a runbook. The detection is what is automated, not the response.
The comparison is against a live baseline rather than an absolute target, because an absolute target is a number you get to choose. Football supplies ground truth on a fixed schedule and does not negotiate.
I could not construct an evaluation that flattered me even if I wanted to.
The shape of the whole thing
The user path is the smallest part of this. Most of the system is what runs when nobody is looking: data synchronisation from a spread of providers, each polled at whatever rate its data actually changes, prediction engines that recompute team ratings and playing-style profiles weekly, calibration that grades its own past work, and a notification layer that has to know a user's timezone before it is allowed to wake them.
The World Cup hub was built as an isolated fleet with its own analysis, sync, live and accuracy-tracking functions. A seasonal event with unpredictable traffic should not be able to take down a product that runs all year, and when the tournament ends the fleet can be removed without touching anything else.
One person wrote all of this, and that is exactly why the boundaries are where they are.
What it takes to keep it running
Architecture diagrams flatter a system. They show the parts that were designed and hide the parts that accumulated. This is the accumulation, taken from the live account and not from memory.
Some of these numbers are the result of decisions and some are the cost of them. Eighty scheduled jobs is not a boast, it is what six data providers on different refresh cadences actually requires. Sixty-five alarms is what it takes to sleep when there is nobody on the other shift.
Five calls I would make again
I switched off features that worked
Two of the markets the language model generated carried measured negative skill once they were graded against real results. Nobody was complaining and they were among the most used features in the product. They were not deleted: they went behind a flag whose documented state is off, and a deterministic calculation over real underlying data became the default, with the displayed probabilities bounded at both ends. Revenue fell the month after and retention went up. The flag is still there, so the decision is reversible without a deploy.
The product does less now and retention improved.
I ignored an alarm
A drift alarm fired off-season on a thin sample of roughly eighty events. The high-confidence bucket held ten of them. Refitting on ten events would have taught the model the shape of a fortnight rather than the shape of the game, so I left it alone. Two weeks later, at four hundred events, calibration was healthy.
Knowing when your evaluation is not yet telling you anything matters as much as knowing what it says.
I gave one table its own architecture
All state is multi-region except one table. Paid entitlement is held in a single-region authority with one writer and atomic conditional writes, and the other regions read from it rather than replicate it. It costs a little latency on a rare path and removes an entire class of silent failure. It is also derived state rather than a system of record: the stores hold the truth about who has paid, so losing that region is a rebuild rather than a failover.
I stopped treating consistency as a uniform property of the system.
I did not use a machine learning framework
The learning layer is plain Python. Serverless rewards a small footprint and a fast cold start, and a transparent model I can correct beats an opaque one that is hard to debug when a single feed shifts. When calibration moves, I can read the reason in the code rather than infer it from a loss curve.
Choosing the cheaper, smaller, inspectable option over the more impressive one is a habit rather than a compromise.
I put a hard ceiling on my own inference spend
Two budget caps sit on the account with alarms attached: three hundred dollars a month for Bedrock inference, five hundred for everything else. A generative product without a ceiling discovers its unit economics in a billing email. Setting the ceiling first forced the two-tier model routing, the caching rules and the decision about which requests justify a stronger model. There is a daily report on token spend for the same reason.
They are not forecasts. They are alarms with a name on them.
Naryu
Naryu turns one birth record into daily personal guidance across Western astrology, Vedic astrology, numerology, Human Design, BaZi and feng shui. The reader can request thirty-five reading types, and a daily piece is generated on top of them. It is in pre-launch, with the computation layer, content pipeline and inference path complete.
The personalisation layer is deterministic, not generative. A Python engine derives planetary positions from JPL ephemeris data and produces the chart, alongside house systems, secondary progressions, solar returns, transits, Vimshottari dasha periods, the four BaZi pillars and the Kua and flying star grids. Every engine is validated against published reference charts before it ships. The generative layer runs on Amazon Bedrock and computes nothing at all: the calculated chart is handed to it as ground truth, it only interprets, and a response that does not conform to the schema is discarded rather than cached.
This is the same decision as Tactiq's server-authoritative grounding, reached twice in two unrelated domains. In both products the model is not allowed to compute the thing that can be checked.
An interpretation built on a wrong degree is wrong however well it reads.
No vector carries a reader
There are no per-user vectors. Any embedding index Naryu builds is over content we wrote, never over a reader's chart, readings, journal or feedback. A natal chart is a fingerprint: a sun sign, moon, ascendant and a few aspects narrow a person to a birth window minutes wide and a location. An embedding derived from a chart is therefore a pseudonymous identifier, one you cannot read a birth date out of but can use to match two records as the same person. Under GDPR that is personal data rather than anonymous data. And a vector store is the component where selective deletion is hardest.
statedintent
I audited my two products' documentation against their code. Six claims came back wrong. The documentation said rollback was automatic; the code had an alarm and a runbook, and the claim had already left the document for my CV and ten job applications. A gate removed eight months earlier was still described in the architecture. A package file called itself a daily cron job that no scheduled rule triggered.
Every software company has this and nobody solves it systematically. AI made generation faster and left verification where it was. Producing is cheap, checking is not, and the gap between them is the problem.
The approach is one sentence: read a codebase, derive what it does, have a person confirm that, then audit the documentation against the confirmed intent. Three levels, kept apart. Code is evidence, the existing document is a claim, the human confirmation is authority.
Neither Tactiq nor Naryu lets the model compute what can be checked. The same principle, now applied to prose: a claim has to be provable. Third time, third unrelated domain.
A tool that finds false claims cannot survive having false claims of its own.
The first codebase it audits is its own
It runs its own gates in its own CI, and it can go red there. Every gate is proved by injecting the fault it exists to catch. Fifty-seven claims from three of their documents are labelled by hand, and that set is what accuracy is measured against. An audit tool that does not measure its own accuracy is the thing it criticises.
Twelve years before this
The enterprise years started at Doğan Dağıtım, on the Yaysat and Hürriyet DPP side, where I built the corporate web applications and the PL/SQL data processing behind press distribution and media logistics across all eighty-one provinces, along with the dealer network portals and the warehouse the reporting ran on. What that software produced was not a screen. It was which vehicle went where. Then BBVA Garanti Technology, in the CRM and campaign team at one of Turkey's largest private banks, working across thirty-eight million customer records on the modern and the mainframe stacks at the same time. Then Amadeus, on the backend of customer loyalty systems in aviation technology, where correctness at volume is the entire product.
The startup. I co-founded Tosia Tech and owned product across the portfolio, from a fintech product to mobile games. When funding for the blockchain payments product was withdrawn, I ran the change: the team, the technology and the roadmap were redeployed into mobile products and a vendor delivery model. The business went on to become a studio, raise investment and pass five million users. The technical part was the easier half.
Then Orion Innovation, as a senior software developer on telecom platforms and customer onboarding. Then a unit of my own: three and a half years at BlockchainIST Center leading seven engineers across research, consultancy and product, with enterprise clients in banking, insurance and the public sector. The recurring situation was an organisation arriving with its technology already chosen and a problem it had not yet named. Most of the work was finding the problem underneath the request, and then saying so.
Then Vodafone. Solution design across initiatives spanning more than twenty engineering and business teams, worked through those teams' own architects rather than over them, and two large projects that were mine to lead. On an internal enterprise AI product I was one of its technical architects, and the identity and access management model for the entire employee base was my part of it.
I am open to conversations about architecture, principal engineering, and teams building AI systems that have to survive contact with real users.
Currently in Istanbul. No notice period.