Skip to content
Tarik Hireche
Portrait of Tarik Hireche

Final-year CS at Université de Montréal, graduating December 2026.

Tarik Hireche

I work close to the machine, on processes, signals and containers, and I care about whether the thing actually comes back up.

Degree
B.Sc. Computer Science · Université de Montréal (DIRO)
Focus
Systems, containers, CI
Degree
B.Sc. Computer Science, UdeM
Available
December 2026
Strongest in
Linux · Docker · Prometheus · C++
Based in
Montréal, QC
Languages
English · French · Arabic

Experience

  1. Mar 2026 to Present

    Platform Administrator

    Mar 2026 to Present

    On-call · Remote

    I'm the only technical person the company has. I handle hosting, DNS, certificates, deploys and content releases. Six months in, nothing has gone down unexpectedly. Nobody had ever written the deploy steps down, so I wrote the runbook they work from now. I also automated the newsletter in Python and JavaScript for three languages. It used to take one to three hours. It now takes about thirty minutes, over more than ten campaigns.

    Full Stack Developer

    Mar 2026 to Jul 2026

    Contract · Hybrid

    I took the client's site off WordPress and wrote them a PHP content platform to replace it. It handles uploads safely. An append-only activity log and per-document version history make the trail reconstructable after the fact. Lossless compression on the server cut page weight by 45%. The owner isn't technical and runs the whole thing alone. The newsletter automation grew out of this work and extended the contract.

  2. Jan 2024 to Jul 2026

    Cap Campus, Université de Montréal

    Montréal, QC

    Ambassador

    On-call · On-site

    I present computer science to high-school students. Most of them have never seen code. It's good practice.

  3. May 2024 to Feb 2026

    Math Plus

    Montréal, QC

    Mathematics Tutor

    Contract · Hybrid

    I tutored mathematics on my own account, from primary school up to university level.

  4. Jan 2024 to May 2024

    Université de Montréal (DIRO)

    Montréal, QC

    Teaching Assistant, IFT1015 Programmation 1

    I ran the weekly lab for 120 first-year students. The work was reading code I had never seen and debugging it live, with a room waiting.

  5. May 2022 to Feb 2024

    Gatestone

    Montréal, QC

    Technical Support Representative

    Permanent · Full-time

    I diagnosed connectivity and account problems for enterprise clients, under time pressure. Every call started with identity verification before I could touch sensitive data.

Selected projects

5 projects

The strongest one is first. One of them runs live on this page.

containersentinelPID 1 · subreaper./appown process groupfork · execorphanadoptedreapeddocker stopSIGTERMkill(-pgid)still alive after 5s, then SIGKILLexit status: the child's own, or 128 + N
Process supervision inside a container: sentinel runs as PID 1, forks and execs the application into its own process group, forwards an incoming SIGTERM to that whole group and escalates to SIGKILL after five seconds, adopts and reaps orphaned descendants, and exits with the child's own status.

Containers & Linux

2026

sentinel

Your program runs as PID 1 in a container. The kernel drops any signal PID 1 has no handler for, so docker stop does nothing and the container gets SIGKILLed.

  • A container under sentinel exits about 3 ms after SIGTERM. The same program alone on PID 1 ignores the signal and gets SIGKILLed at the ten second deadline.
  • It restarts a dead child on a 1, 2, 4, 8, 16 second backoff, and serves restart, crash and failure counters for Prometheus to scrape.
  • 13 ctest cases and 5 CI jobs. CI stands the whole Compose stack up and fails unless Prometheus is scraping and Grafana has the dashboard.
  • C++17
  • Linux
  • POSIX signals
  • Docker Compose
  • Prometheus
  • Grafana
  • GitHub Actions
What PID 1 costs you
Shutdown after SIGTERM
2.5 to 3.1 ms

Seven runs, worker supervised by sentinel on PID 1 of a PID namespace, timed through wait() so there is no polling error. The same worker alone was still alive at the ten second deadline and needed SIGKILL.

Child that ignores SIGTERM
5.003 s

Same harness, worker in stubborn mode, three runs inside 1 ms of each other. That is the SIGKILL escalation firing on schedule.

Restart backoff
1, 2, 4, 8, 16 s

Timed from the supervisor's own log against a child that dies at once. Five restarts in forty seconds, and the pause caps at sixteen.

Test suite
13 of 13

ctest on a Release build, 33 s. CI runs build, test, shellcheck, docker and compose as separate jobs.

Supervisor footprint
3.9 MB RSS

Read from /proc while supervising, on two threads. The binary is 36 KB, or 31 KB stripped.

The kernel will not deliver a signal to PID 1 unless PID 1 installed a handler for it. So the container sits through the whole grace period and then dies by SIGKILL. sentinel takes the PID 1 slot and lets your program run as an ordinary child. It exits with the child's status code, or 128 plus the signal number if the child was killed. Exit 137 out of a container is 128 plus 9. That is the OOM killer.

The handlers go in without SA_RESTART. That matters: with the flag, the kernel restarts waitpid after a signal and the reap loop never gets a turn. Without it, waitpid returns EINTR and the loop keeps control. The handler calls kill() and nothing else. Very little is safe to call from signal context. Escalation lives under the same constraint. The SIGTERM handler arms alarm(5), and a SIGALRM handler does the killing.

There used to be a window between the fork and the line that installed the handlers. A SIGTERM landing in it killed sentinel and left the child running as an orphan. That is the exact failure sentinel exists to prevent. I marked it as a TODO and lived with it for a while. The fix is sigprocmask around the fork. It blocks SIGINT and SIGTERM before, and unblocks once the handlers are up. The child restores the original mask before exec. Otherwise everything sentinel launches starts out deaf to those signals.

The metrics server needs its own thread, because the main one sits blocked in waitpid and cannot also wait in accept. That thread blocks every signal for itself. SIGTERM has to keep landing on the main thread where the handler lives, or waitpid never gets its EINTR. The counters are atomic since both threads touch them.

One compose command brings up sentinel, a Prometheus scraping it every 5 s, and a Grafana with the dashboard already provisioned. The stack runs a child that crashes on purpose, so the graphs have something real on them. Two alert rules ship with it, one for a crashloop and one for a child that has been down two minutes. CI stands the whole thing up on every push and fails unless Prometheus reports the target up, the restart counter has moved, both rules loaded, and Grafana is serving the dashboard.

pushbuildPIT runscorevs baselinedroppedexit 1, build failsheldmerge allowed
CI quality gate: every push runs PIT mutation testing, compares the score against a committed baseline, and fails the build if it dropped.

Testing & CI

2025

Mutation Testing in CI for GraphHopper

GraphHopper's pipeline ran the test suite on every push. It never asked whether those tests were any good.

  • A PIT mutation job now fails the build when the score falls below a baseline committed in the repo.
  • The pipeline is split in two. Ordinary builds stay fast, and mutation runs on the core module only.
  • I broke a test on purpose, watched the score fall to 91%, and watched the build go red.
  • Java
  • PIT
  • Mockito
  • GitHub Actions
  • Maven
How I know the gate fails

I had never seen the gate fail, so I did not know it worked. I broke a test to push the score from 92% to 91%. The job went red. The drop signal reached the next step and fired a custom action that Rickrolls whoever caused it. That path now runs end to end.

The suite needed tests that run without loading a real routing graph. I wrote three with Mockito, in their own package. They mock PointList, DistanceCalcEarth and EdgeIteratorState. A test can then pin exact coordinates and edge attributes and check the code that consumes them.

docker composenginxfrontend · :3000Spring BootREST · JPA · :8080PostgreSQLhopital · :5432
Three-tier architecture: an Nginx frontend calls a Spring Boot REST API, which persists to PostgreSQL. All three run as Docker Compose services.

Backend & deployment

2026

Hospital Directory & Registration Platform

A staff directory and patient registration system that had to come up on any machine, including one that had never seen it.

  • One docker compose command starts three services. Nginx sits in front of a Spring Boot API, which runs over PostgreSQL.
  • The REST API sits on Spring Data JPA repositories, so persistence stays behind an interface.
  • I recorded a walkthrough that goes from the source code to the running app.
  • Java
  • Spring Boot
  • PostgreSQL
  • Docker Compose
  • Nginx
What one command has to guarantee

It started as three-tier coursework. I built it as three services, each in its own container. In an interview, I would want to be asked about the deploy. There is no README of manual steps and no start-up order to memorise. Anyone with Docker gets the same stack, in the same state, from one command.

heapusedusedusedfree listalloc = pop head · O(1), no GC
Heap layout: a free list threads through the released blocks, so allocation pops the head of that list in constant time.

Systems

2025

Three Allocators in Zig

A course asked for one heap allocator. I wrote three. Each one showed me the limit of the one before it.

  • The three are a bump allocator, a tagged allocator with per-block headers, and one that reuses freed blocks first-fit.
  • I did alignment and pointer arithmetic by hand, and there is no garbage collector anywhere in it.
  • One panic showed up on ARM after every test had passed on x86-64. I tracked it down.
  • Zig
  • GDB
The bug that appeared when I changed machines

I found this one because I switched machines. A version of the tagged allocator computed alignment from self.next, an offset into the buffer. The buffer's real address in memory never entered the calculation. It passed every test on x86-64 Linux. On macOS and ARM it hit panic: incorrect alignment. A stack-allocated [N]u8 is not guaranteed to start on an 8-byte boundary. Aligning an offset only aligns you relative to wherever the buffer begins, so an odd base address throws off every address derived from it. Aligning the absolute address fixed it.

The three build on each other. The first is a byte buffer and an index that moves forward. It has no per-block free at all, because a stack allocator releases everything or nothing. The second puts a header in front of each block, which makes free() possible as bookkeeping. A freed block gets marked and then sits there. The third walks those headers for a block big enough before it allocates at the end. It takes the first block that fits. That costs O(blocks) and wastes the tail of an oversized block. It also needs no free list and no coalescing pass.

Live inference

55,050 params · 88.97% on 10k test set

Loading model…

Machine learning

2026

Neural Network & Hyperparameter Study

I wanted to know which training choices change the result. So I built the network from scratch, one piece at a time.

  • The neurons, the layers, four activation functions and four loss functions are all mine, written in NumPy.
  • I ran nine controlled experiments, one variable at a time. The clearest result was about the loss function.
  • The trained network runs in the panel on the left, in your browser. Quantised to int8, it downloads in 55 KB.
  • Python
  • NumPy
  • PyTorch
Why MSE learns slowest where it is most wrong

When the model gets an example badly wrong, the MSE gradient is scaled by the output derivative. That derivative is near zero exactly when the error is largest. The network then learns most slowly on the examples it has most to learn from. Cross-entropy cancels the term. That is why it is the default for classification.

Skills

Reliability & operations
  • Production ownership
  • Graceful shutdown
  • Restart policy & backoff
  • Runbooks & handover docs
  • Audit logging
  • DNS & TLS
  • Incident debugging

Used in: Six months as the only technical person at Crono Design

CI/CD & deployment
  • GitHub Actions
  • Multi-job pipelines
  • Merge gating
  • Docker
  • Multi-stage builds
  • Docker Compose
  • Nginx

Used in: sentinel · Mutation Testing in CI · Hospital Directory

Observability
  • Prometheus metrics
  • Text exposition format
  • Counters & gauges
  • Alert rules
  • Grafana dashboards

Used in: sentinel, where CI fails unless the stack really scrapes

Linux & systems
  • Processes & signals
  • fork / exec / wait
  • Process supervision
  • Concurrency
  • Manual memory management

Used in: sentinel · Three Allocators in Zig · Fedora daily driver

Languages
  • C++
  • C
  • Python
  • Bash
  • Java
  • Zig
  • SQL
  • PHP

Used in: Every project here, and the Crono Design work

Backend & data
  • Spring Boot
  • Spring Data JPA
  • REST APIs
  • PostgreSQL schema design

Used in: Hospital Directory & Registration Platform

Tooling
  • Git
  • GDB
  • strace
  • CMake
  • ctest
  • Make

Used in: The alignment bug in Zig · building sentinel

Recognition

DIRO Excellence Scholarship2024
The computer science department at Université de Montréal awarded it for academic standing.
Top 30 at the NorthSec CTF2025
My team placed in the top 30 of roughly 93 teams at the largest applied-security competition in North America.

About

Montréal, QC

For six months I've been the only technical person on a client's web presence. I handle hosting, DNS, certificates and deploys. I wrote the runbook so they could stop calling me for routine changes. It's unglamorous work. I learned more about reliability from it than from any assignment.

The layer underneath keeps pulling me back. What is PID 1 in a container responsible for? Why can a test suite be green and still miss bugs? I'm looking for a first role where the hard part is the system, not the framework.

Up next

sentinel does what I set out to build. The last piece is Terraform, to stand the stack up on a cloud VM behind TLS.

Contact

What I want to work on

Systems that have to stay up: process lifecycle, containers, deployment, pipelines that catch real regressions, and the backend behind them. Intern or new grad. Available now for internships, full-time from December 2026.

tarik.hireche@umontreal.ca
Résumé
PDF