I built the whole platform for Decasonic’s Investor Day solo: an Expo mobile app, a React admin console and an Express API, about 60,000 hand-written lines of TypeScript. The part worth writing about is how it decided who should meet whom.
The model never decides who matches
The pair-scoring function is pure, unit-tested code with no LLM in it. It decides who matches. The model’s only job is to write the human-readable reason, after the decision is made.
Fair by construction
Colleagues never match each other. Per-company caps stop one fund from taking every good introduction. A starvation floor guarantees that nobody ends the day with zero introductions, which is the failure a pure “best score wins” system produces for quieter attendees.
Lunch, as an algorithm
Lunch ran as a rotation: 9 companies, 9 timed rounds, and every attendee routed so they see every company once. A state machine invalidates a live rotation rather than corrupting it if something changes mid-event.
Privacy has to reach the prompt
Some attendees chose to hide their name. Masking it in the API response is not enough: if the full record reaches the model, the generated text can still name them. So masking happens server-side before any surface sees the data, including the LLM prompt.
The API hides the name, but the model saw it, and writes “you should meet Sarah from…” in a recommendation.
The record is masked on the server first. The app, the admin console and the prompt all receive the same masked data.
Boring guarantees
- Scanning a QR code twice can’t double-count a check-in: idempotency is enforced by a database constraint, never read-then-write.
- One OpenAPI spec generates the typed client and validation, so the app and the API cannot drift apart.
- Every admin change writes to an audit log.
Use the model for what it is good at, language. Keep the decisions in code you can test.
Saad Al-Tamari