Mahdi Rizk

Mahdi Rizk

Software engineer at Teli.ai, Michigan CS class of 2026. Every project on this page is something you can run: type into the database, assemble a program, step the CPU, shoot a zombie, fly the rocket.

Portrait of Mahdi Rizk

Loan data, out and back

Teli.ai · Software Engineer · September 2026 to now

I'm the sole engineer on an in-house loan origination system that replaces a third-party vendor on an AI mortgage platform. Part of that is a production MISMO 3.4 exporter and importer, built in TypeScript from Fannie Mae's public specifications. 9 of 9 test loans validate against the DU schema and round-trip with zero differences.

This does the same loop in miniature: edit the loan, it serializes to XML, then the XML is parsed back and compared field by field.

  • Audited 162 vendor API operations; migration plan approved by the CTO and leadership
  • 39-table PostgreSQL schema with row-level security, field-level audit logging, and SSN masking; all 433 Fannie Mae DU data points mapped
  • Two vendor-replacement slices in production, backed by 436 pgTAP assertions
  • Found a vendor bug that misstated debt-to-income by 100x on rental-property loans; fixed a path-traversal hole in the vendor API proxy
mismo-roundtrip.ts
LoanPurposeType
Purchase
Refinance
<MESSAGE>
<DEAL_SETS><DEAL_SET><DEALS><DEAL>
<LOANS>
<LOAN LoanRoleType="SubjectLoan">
<TERMS_OF_LOAN>
<BaseLoanAmount>350000</BaseLoanAmount>
<LoanPurposeType>Purchase</LoanPurposeType>
</TERMS_OF_LOAN>
</LOAN>
</LOANS>
<PARTIES><PARTY>
<INDIVIDUAL><NAME>
<FirstName>Jordan</FirstName>
<LastName>Haddad</LastName>
</NAME></INDIVIDUAL>
<TAXPAYER_IDENTIFIER>
<TaxpayerIdentifierValue>•••-••-6789</TaxpayerIdentifierValue>
</TAXPAYER_IDENTIFIER>
</PARTY></PARTIES>
</DEAL></DEALS></DEAL_SET></DEAL_SETS>
</MESSAGE>
parse → compare5 of 5 fields match · 0 differences

SillyQL

EECS 281 · Winter 2025 · C++

An in-memory relational database engine with typed columns and a small SQL-like command language. Dual indexing with hash maps and BSTs cut conditional queries from O(n) scans to O(1) and O(log n) lookups, and ranked in the top 10 for runtime among 1000+ submissions.

A JavaScript port of the command set, so the class code stays private. Click a line to run it, or type your own.

./sillyql↑ ↓ history
SillyQL demo. Type HELP for commands.

Pipelined CPU

EECS 370 · Spring 2025 · C

A cycle-accurate 5-stage LC-2K pipeline with explicit pipeline registers, forwarding paths, load-use stall control, and branch-not-taken prediction, plus a configurable write-back cache with LRU replacement.

Step through seven instructions. Turn forwarding off and watch the stalls pile up behind every read-after-write.

13 cycles · 2 stalls · CPI 1.29

cycle 0 / 13

LC-2K assembler

EECS 370 · Spring 2025 · C99

A two-pass assembler that turns LC-2K assembly into 32-bit machine code, an instruction-level simulator that executes it, and a 15-bit multiplier written in LC-2K using only add and nor.

Edit the program. Pass one builds the label table; pass two encodes each line as you type. Try an undefined label or register 9 to see the errors.

8 words · 4 labels · no errors

countdown.as → countdown.mclabel · opcode · regA regB dest/offset
addrlabelhexop · regA · regB · dest/offset · dec
00x0081000601000000100000000000001108454150
10x0082000701000001000000000000001118519687
2loop0x01080002100001000000000000000001017301506
30x000a00010000010100000000000000001655361
40x0100fffd100000000111111111111110116842749
5done0x01800000110000000000000000000000025165824
6n0x00000003.fill00000000 00000000 00000000 000000113
7neg10xffffffff.fill11111111 11111111 11111111 11111111-1

Zoo routing

EECS 281 · Winter 2025 · C++17

Graph algorithms over 2D cage coordinates: Prim's minimum spanning tree in O(n²), a nearest-neighbor tour refined by 2-opt swaps, and an exact tour by branch and bound.

Click the field to add cages. Build a tour, then let 2-opt untangle it one swap at a time.

Add cages, then build a tour.

16 cages

Priority queues

EECS 281 · Winter 2025 · C++17

Four interchangeable priority queue containers behind one abstract interface: unordered, sorted, binary heap, and pairing heap. The binary heap uses fixUp, fixDown, and bottom-up heapify; the pairing heap melds in O(1) and does two-pass pairwise merging on pop.

This is the binary max-heap. Push a value and watch fixUp carry it toward the root one swap at a time. Heapify rebuilds from the bottom up.

Push a value and watch fixUp.

BinaryPQ<int> · size 6
42
29
18
14
7
11
data[]42291814711

Zombie defense

EECS 281 · Winter 2025 · C++17

A round-based simulation where a player with a limited quiver shoots approaching zombies in priority order: ETA (distance / speed), then health, then name. Zombies live in a std::deque so pointers stay stable; a priority_queue of pointers orders them. A max-heap and min-heap pair tracks the running median of lifetimes with O(log n) inserts and O(1) reads.

Spawn a few, then shoot. Each shot is a round: survivors advance, the kill's lifetime drops into one of the two heaps, and the median updates.

Spawn zombies, then shoot the one with the lowest ETA.

round 1 · 0 alive
by prioritydistspdhpETA

Quiet. Spawn some.

median lifetime
—
max-heap (low)
min-heap (high)

Roots are highlighted. Sizes stay within one of each other, so the median is a root or the mean of both.

BST and Map

EECS 280 · Fall 2024 · C++17

A templated binary search tree with a custom comparator and in-order iterator, wrapped into an associative Map<Key, Value>. operator[] inserts a default value on a miss; 27 unit tests under AddressSanitizer and UBSan.

Type a course number. The find path lights up as you type; Enter inserts it the way operator[] would.

Type a number. Enter inserts it.

size 7 · height 5
183
203
280
281
370
376
485

Linked list text buffer

EECS 280 · Fall 2024 · C++17

A templated doubly linked List<T> with the Big Three and a bidirectional iterator, used as storage for a cursor-based TextBuffer that tracks row, column, and index as the cursor moves and text is inserted or removed.

Type in the editor. Each character is a node; the cursor is an iterator sitting between two of them.

cursor at index 5 · row 0, column 5

TextBuffer over List<char>11 nodes

Static site generator

EECS 485 · Fall 2025 · Python, Jinja2, Click

A Click CLI that reads config.json, renders each listed Jinja2 template with its context into url/index.html, and copies static assets into the output tree, with clear non-zero exits for a missing config, malformed JSON, or template errors.

A tiny template engine that handles variables, for loops, and if blocks. Edit either side; break the JSON to see the error path.

exit 0 · html/index.html written

insta485generator buildtemplates/index.html · config.json → html/index.html

SQL queries

EECS 484 · Fall 2025 · Oracle SQL

Twelve queries and a view over a bookstore schema and a university schema: conditional aggregation with COUNT DISTINCT CASE, relational division written as NOT EXISTS over a MINUS, and a self-join view of student pairs. Full marks on the autograder.

Three of the patterns, evaluated live over a small bookstore. Rows that feed the answer are highlighted.

SELECT a.name FROM authors a
WHERE NOT EXISTS (
  SELECT b.subject FROM books b JOIN authors r ON r.id = b.author_id
  WHERE r.name = 'J. K. Rowling'
  MINUS
  SELECT b2.subject FROM books b2 WHERE b2.author_id = a.id
);
books ⋈ authors
Philosopher's StoneRowlingFantasy
The Cuckoo's CallingRowlingMystery
The HobbitTolkienFantasy
Murder on the Orient ExpressChristieMystery
CoralineGaimanFantasy
The SandmanGaimanHorror
Anansi BoysGaimanMystery
KindredButlerScience Fiction
Parable of the SowerButlerScience Fiction
result · 2 rows
J. K. Rowling
Neil Gaiman

Naive Bayes classifier

EECS 298 · Fall 2024 · C++

Bag-of-words classifiers trained on 10,000 IMDB reviews with add-one smoothing, scored against a vocabulary-count baseline and a null classifier on 1,000 held-out reviews, then extended to multi-class emotion labels with argmax over log posteriors.

Write a review. Each known word pulls the log-odds one way or the other; the bars are the per-word evidence. The lexicon here is 32 words, so it's a toy.

positivelog P(pos|x) -21.76 · log P(neg|x) -23.05 · 79%
a
unseen
charming
+1.87
and
unseen
clever
+1.69
film
+0.08
with
unseen
a
unseen
dull
-2.01
second
-0.11
half
-0.22

Two-sample statistics

EECS 280 · Fall 2024 · C++17

A command-line tool that splits a CSV column into two groups, prints descriptive statistics for each, and estimates a 95% confidence interval for the difference in means from 1,000 bootstrap resamples, with an Excel-style interpolated percentile.

Edit the two groups, then resample. The histogram is the sampling distribution of the mean difference; the dashed lines are the 2.5th and 97.5th percentiles.

mean A 13.50 · mean B 17.00 · difference 3.50

Asteroids

EECS 493 · Fall 2025 · JavaScript, jQuery

A dodge-the-asteroids game with a landing page, settings panel, tutorial, levels through portals, shield pickups, pause, and game over. setInterval timers drive the loop; keydown and keyup flags give smooth diagonal motion; collisions are axis-aligned bounding boxes.

This is the real build. Click into it, then use the arrow keys. Portals level you up; shields absorb one hit.

This is the real build. Tap into it, then drag your finger to fly. Portals level you up; shields absorb one hit.

/demos/asteroids/needs a keyboard

Artist search

EECS 493 · Fall 2025 · Vue 3, Bootstrap 5

A single-page app that searches the iTunes API by artist and lets you filter by genre, sort, favorite, and play 30-second previews. Genre buttons are derived from the result set; the audio player has random next, repeat, volume, and a progress bar fed by timeupdate events.

The built app, embedded. It hits the real iTunes catalog, so results are live.

/demos/artist-search/live iTunes API
loading Artist Search…

EarnedIt

EECS 497 capstone · Winter 2026 · iOS · Team of 4

An iOS app for impulsive shoppers that turns purchases into rewards: save items to a wishlist from the Amazon share sheet, finish tasks in easy, medium, and difficult tiers to earn points, and unlock an item with a "You've Earned It" screen that links back to buy it. Grounded in user research and personas.

The core loop, in a phone. Check off tasks until the keyboard unlocks.

Final demo video ↗
Wishlist · 1 item
Mechanical keyboard120 pts
0 earned120 to go
Today's tasks

Snap-Shot

MHacks 2025 · Lens Studio, TypeScript, Gemini, Google Maps Platform · Team of 4

Voice-guided campus navigation on Snap Spectacles for blind and visually impaired students. Say a destination and the glasses give continuous step-by-step directions from Google Places data, while on-device computer vision watches for obstacles. I owned testing, logistics, and the presentation.

Pick two buildings and press speak. The route is schematic; the voice is your browser's.

Demo video from MHacks ↗
Beyster Building
Duderstadt Center
Pierpont Commons
EECS Building
FXB Building
G. G. Brown
Lurie Tower
Beyster Building
Duderstadt Center
Pierpont Commons
EECS Building
FXB Building
G. G. Brown
Lurie Tower
BBB
Duderstadt
Pierpont
EECS
FXB
GG Brown
Lurie
  1. 1Face east. Walk 260 meters along the path.
  2. 2Turn right to face south. Walk 40 meters.
  3. 3Duderstadt Center is directly ahead. The entrance is at street level.
Schematic north campus, not to scale. Speech uses your browser’s voice.

PySurfers

Hack Dearborn 3 · October 2024 · Python, OpenCV · Team of 3

Play Subway Surfers with your whole body: a webcam tracks your movements with OpenCV and maps them to the game's controls, Kinect-style. Tuning movement sensitivity was the main technical challenge. I playtested, recorded test data for debugging, supplied the hardware, and presented.

A three-lane runner. Arrow keys work; turn on the webcam and lean left or right instead. Motion is detected by frame differencing, in the browser, and nothing leaves your machine.

Arrow keys move. The webcam is optional.

score 0

NeuroScanAI

Hack Dearborn 2 · October 2023 · PyTorch, YOLOv8, Flask, SvelteKit · Team of 4

A deep learning model that detects and classifies brain tumors in MRI scans. We started training with EfficientNet, hit hardware limits, and switched to YOLOv8 on a mentor's advice, using transfer learning on a brain MRI dataset. I found and vetted the datasets and helped design the desktop and mobile site.

The one project here without a live demo. The trained weights aren't published, and a fake detector would be worse than none.

Devpost ↗
training log, abridged36 hours
  1. hr 0Pick the problem: tumor detection and classification on MRI. Find and vet public brain MRI datasets.
  2. hr 6Start training EfficientNet. Laptops run out of memory.
  3. hr 12A mentor suggests YOLOv8. Switch to transfer learning from pretrained weights.
  4. hr 24Flask serves the model; SvelteKit front end for desktop and mobile.
  5. hr 36Deploying the model was new to all of us. It shipped.

This website

Procrastination 101 · 2026 to present · Astro, TypeScript

Started as a vanilla HTML, CSS, and JS single page, then rebuilt as a multi-page Astro site with per-page SEO. All content lives in JSON data files, and a theme switcher supports 13 color schemes through CSS custom properties, including a L33T mode for the aesthetically adventurous.

Yes, this site is listed as a project on itself. The recursion was intentional. Pick a theme; it sticks.

theme: Bench

src/data/themes.json13 schemes