Backend engineer — Gijón, Spain · C# / .NET / SQL Server
The query returned 153 rows. The table had 286.
I work on a warehouse management platform that runs live logistics sites, where a defect stops a floor. Most of my day is transactional workflows and the data access layer — which mostly means finding the things that aren't where the documentation says they are.
The other half of what I do is testing whether AI systems actually behave. I've built tooling to measure language-model performance, run red-teaming passes to catch information leakage and tool misuse before release, and done computer-vision testing engagements for IKEA and William Hill.
It's an enterprise platform, not a public project — so there isn't much to browse here. Instead, three things I had to dig for:
A relation the documentation promised, and the database didn't have
A configuration export kept coming back empty. The direct fix was closed off — we only had the framework as compiled assemblies, no source.
So I built a custom exporter and instrumented the read model by reflection, one hypothesis at a time, until I could prove the documented entity relation did not exist in that model at all. Along the way I found a query overload silently returning 153 of 286 rows.
Five hypotheses discarded. Each wrong answer narrowed the search.
Grouping stock adjustments without inventing a new abstraction
I designed the workflow layer for a stock-adjustment uniqueness rule.
I chose a single-query fetch with in-memory grouping over a two-query seed-and-expand approach — one fewer round trip, and a narrower window for inconsistent reads. I also kept the grouping on the domain entity instead of adding an intermediate movement type.
Pure adjustments net to one quantity per article (-1, +3, -1 → +1). Transformations split their old and new sides into separate groups. It's the same shape as netting entries in a ledger.
A regression that only existed in one of two contexts
Container locking started misbehaving in production. The cause was a mapping update applied to the read context but never to the transactional one — so the same entity was two slightly different things depending on how you happened to ask for it.
Reads looked fine. Writes didn't.
zentric.pro · in development
A done-for-you system for small clinics: an AI agent connected to the official WhatsApp Business API and to Google Calendar. It reads what a patient actually wants, offers real free slots from the clinic's calendar, books the appointment, chases no-shows and fills cancellations from the waiting list.
I designed and built all of it — the agent and its grounding, both integrations, the scheduling logic and the dashboard.
The interesting part isn't the model. It's everything around it: two-way calendar sync where the human always wins, conversations that survive being resumed three days later, and knowing when the agent should stop and hand over to a person.
- OpenCode — contributing to the open-source AI coding agent: issues opened, pull requests submitted
- Neosystems Hackathon — winner. Designed and shipped something that worked, under a fixed clock
- Branching narrative editor — final degree project: a desktop editor for interactive branching stories, with a visual graph of nodes and conditional paths
Daily: C#, .NET, LINQ, Entity Framework, SQL Server Also written: Java, Python, C++, React Learning: Go, Kubernetes, Terraform
- Reading AI Engineering (Chip Huyen)
- Building out a home lab — Proxmox, k3s, Terraform
- Open to relocation. EU citizen.


