SUBSTRATE — Sagar Tailor, home

00Current location: Surface level, home

Backend & systems engineerRajasthan, India

Sagar Tailor

Builds the layer underneath. Software is strata — users touch the top, and almost nobody sees the scheduler, the lock, the migration, the trace. Those are the ones I build.

github.com/slazyverse ↗·Every claim on this site resolves to a source.

Position

I work on the partsother work depends on

Two projects, and in both of them the same job: build the substrate, then make it observable.

In deadlockd that meant a Go engine where the safety check copies system state under mutex and releases the lock before running its search, and where cycle detection uses an explicit-stack DFS instead of recursion. Correctness is the product; the visualiser exists so the correctness can be watched.

In VAYU-DRISHTI, a four-person satellite air-quality platform, it meant owning the layer everyone else built on — an application factory, async SQLAlchemy over asyncpg, Alembic migrations enabling PostGIS, structlog request tracing, a container environment, and the dashboard that turned the team’s models into something a person could read.

The habit connecting them is writing the reasoning down. Complexity bounds live in function headers. Dependencies carry a line explaining why they exist and why the alternative was rejected. The config layer refuses to start the server in a dangerous state rather than trusting that nobody will ask it to.

00SurfaceWhat software looks like from outside.
01InterfaceThe layer where behaviour becomes visible.
02EngineWhere the work is actually done.
03SubstrateBedrock. Facts, no ornament.

The descent

One request,all the way down

Keep scrolling. Every layer is a real one, and the last is four lines of Go that decide whether the whole thing is correct.

  1. 00 Surface — A process asks for a resource

    This is all a user ever sees: a request, and an answer. Granted or refused, in a few milliseconds.

    P1 requests R0 ×1. → GRANTED

    deadlockd.vercel.app

  2. 01 Interface — It becomes a frame on a socket

    The click is serialised and pushed over a WebSocket to the Go engine. The browser now waits.

    { "type": "REQUEST",. "pid": 1,. "rid": 0,. "qty": 1 }

    frontend/app/hooks/useDeadlockSocket.ts

  3. 02 Engine — The engine refuses to guess

    The allocation is applied tentatively, then tested: is there still an order in which every process can finish?

    sim.ProcessManualRequest(1, 0, 1). → tentatively allocate. → IsSafeState(state)?. → commit or rollback

    backend/engine/manager.go

  4. 03 Substrate — And it holds the lock for four lines

    The matrices are copied under the mutex and the lock is released. The O(P²·R) search runs on the snapshot, blocking nobody.

    state.Mu.Lock(). copy(need[i], state.Need[i]). copy(alloc[i], state.Allocation[i]). state.Mu.Unlock(). // the search begins here

    backend/engine/banker.go:L15–L30

01Case study

A real-time deadlock simulator and concurrency visualiser.

Sole author — 6 of 6 commits

A Go backend runs the simulation; a Next.js client renders the resource-allocation graph live over a WebSocket bridge. Processes request and release resources, the engine checks whether each request leaves the system in a safe state, and when a circular wait closes the graph locks and the cycle is recovered and displayed.

The correctness is the product. The visualiser exists so the correctness can be observed — which is the only reason the frontend is there at all.

Stack
Go · Next.js · TypeScript
Licence
MIT
Built
April 2026
backend/engine/banker.goL14 — L30
func IsSafeState(state *SystemState) (bool, []int) {	state.Mu.Lock()	np := len(state.Processes)	nr := len(state.Resources)	work := make([]int, nr)	copy(work, state.Available)	for i := 0; i < np; i++ {		copy(need[i], state.Need[i])		copy(alloc[i], state.Allocation[i])	}	state.Mu.Unlock()
This code
Held
Search runs outside the critical section
Naive version
Mutex held for the entire O(P²·R) search
Copy the allocation matrices under the lock, release it, then search the snapshot. Other goroutines keep moving while the expensive computation runs. The safety check needs a consistent view of the state — not exclusive access to it for the duration.

The safety search

Banker's Algorithm executing at your pace. Scroll to step it forward; scroll back to step it back.

IsSafeState() — executingDONE
Banker’s Algorithm state. Each process shows its remaining Need and current Allocation. The Work vector grows as processes resolve into the safe sequence.
NeedAllocation
P0743010finished
P1122200finished
P2000302finished
P3011211finished
Work1055SequenceP1 → P2 → P3 → P0

All four processes can finish. The state is safe.

What it does, and where that is proven

The safety check copies system state under mutex, then releases the lock before running its O(P²·R) search — so the expensive computation never blocks other goroutines.
backend/engine/banker.go:L15–L30(opens on GitHub in a new tab)
Cycle detection uses an explicit-stack iterative DFS with white/gray/black colouring rather than recursion, so deep process graphs carry no stack-depth risk — and it recovers the actual cycle through a parent array.
backend/engine/detection.go(opens on GitHub in a new tab)
Tests assert exact matrix state, not that the code merely ran: a granted safe request must move Available, Allocation and Need to specific expected values.
backend/engine/scenarios_test.go(opens on GitHub in a new tab)
CI runs go mod verify and the full Go test suite, plus an independent frontend production build, on every push and pull request.
.github/workflows/ci.yml(opens on GitHub in a new tab)
Commits mine
6/6
Sole contributor
Safety search
O(P²·R)
Documented in-header
CI gates
2
Go tests · frontend build
Engine modules
8

02Case study

VAYU-DRISHTI

A satellite air-quality platform for India — surface AQI, formaldehyde hotspots and active-fire monitoring.

Team of four — platform layer mine

A four-person project analysing Sentinel-5P and ERA5 observations to estimate ground-level air quality. Yeshika owns the machine-learning pipeline; Soumyadeb owns the AQI calculation and Earth Engine ingestion.

I own the platform: the API, the data layer, the observability, the container environment, and the dashboard the team's models are seen through. Three commits, roughly 11,700 lines across 116 files — the substrate everything else runs on.

Stack
FastAPI · PostGIS · Streamlit
Team
4 contributors
Built
July 2026
ML pipeline — models, feature selection, evaluationyeshika-0226 commits
AQI calculation · Earth Engine ingestion · Random Forestsoumyadeb10 commits
Streamlit dashboard · GIS map · charts · report pagesSagar1,854 lines
API v1 · schemas · services · live-data hardeningSagar2,599 lines
Config · structured logging · async data layer · Docker · testsSagar6,731 lines
Hatched layers are the team’s work, credited by contributor. Solid layers are mine. Four commits understates the share badly — those commits are roughly 11,700 lines across 116 files, and they are the platform the rest of the project runs on.

One request, descending

A single request ID threading through every layer — which is what makes an incident traceable rather than guesswork.

X-Request-ID8f3c1a7e
  1. CORS + request-ID middleware

    app/main.py

    {"event":"request.start","request_id":"8f3c1a7e","path":"/api/v1/aqi"}
  2. Versioned router

    app/api/v1/router.py

  3. Endpoint handler

    app/api/v1/endpoints/aqi.py

    {"event":"aqi.request","request_id":"8f3c1a7e","bbox":"68,8,97,37"}
  4. Service layer

    app/services/aqi_service.py

    {"event":"aqi.query","request_id":"8f3c1a7e","stations":142}
  5. Async session

    app/db/session.py

    {"event":"db.execute","request_id":"8f3c1a7e","ms":11.4}
  6. PostgreSQL + PostGIS

    asyncpg

200 OK — every log line above carries request_id 8f3c1a7e

What it does, and where that is proven

Configuration refuses to boot the server on DEBUG=True with ENVIRONMENT=production. The misconfiguration raises at import time, before the application accepts a single request.
backend/app/core/config.py(opens on GitHub in a new tab)
Request-ID middleware binds a UUID into structlog contextvars, so every log line emitted during a request carries the same trace ID — and the ID returns to the caller on the X-Request-ID header.
backend/app/main.py(opens on GitHub in a new tab)
Alembic runs migrations through asyncio.run() and create_async_engine(), so asyncpg is the only PostgreSQL driver in the project. psycopg2 is deliberately absent rather than carried as a second dependency.
backend/requirements.txt(opens on GitHub in a new tab)
The DATABASE_URL is a computed field assembled from separate components with quote_plus encoding, so special characters in credentials cannot corrupt the connection string.
backend/app/core/config.py(opens on GitHub in a new tab)
Lines, platform layer
11,700
Across 116 files
API endpoint modules
6
Pydantic schema modules
7
Commits
3
Plus repo initialisation

03How it’s built

Four things I actually do

Not values. Habits, each one pointing at the commit where it was practised.

  1. 01

    A decision that isn't written down didn't happen

    Complexity bounds live in the function header that implements them. Every production dependency carries a line explaining why it is there and why the alternative was rejected. Six months later the reasoning is still in the repository rather than in someone's memory.

    backend/requirements.txt(opens on GitHub in a new tab)
  2. 02

    Make the failure impossible, not unlikely

    Running with debug enabled in production is not a mistake to be careful about — it is a state the configuration layer refuses to construct. The validator raises at import time, so the server cannot reach the point of accepting a request in a dangerous configuration.

    backend/app/core/config.py(opens on GitHub in a new tab)
  3. 03

    Hold the lock for as short as you can

    The safety check needs a consistent view of the allocation matrices, not exclusive access for the duration of the search. So it copies them under the mutex, releases, and searches the snapshot. The critical section is a handful of copies; the O(P²·R) work happens outside it.

    backend/engine/banker.go:L15–L30(opens on GitHub in a new tab)
  4. 04

    A system you cannot observe is a system you cannot operate

    Every request carries a UUID bound into the logging context, so a single trace ID connects middleware, route handler, service and query. On the interface side the same instinct produces explicit loading, empty and error states rather than a spinner that means nothing.

    backend/app/main.py(opens on GitHub in a new tab)

04Stack

Split by whetherI have shipped it

Everything in the first tier points at a repository. Everything in the second is honest about being study rather than delivery.

Shipped in production

Used to build something that runs, and pointed at below.

Go
deadlockd — concurrency engine, WebSocket hub
Python
VAYU-DRISHTI — FastAPI backend, services
TypeScript
deadlockd — typed socket client
FastAPI
App factory, versioned router, 6 endpoint modules
PostgreSQL · PostGIS
Async SQLAlchemy 2.0, GeoAlchemy2
SQLAlchemy · Alembic
Async engine, PostGIS migrations
Pydantic v2
Settings, validation, 7 schema modules
Next.js · React
deadlockd client, React Flow graph
Tailwind CSS
deadlockd interface
Docker · Compose
Both projects, with entrypoints
GitHub Actions
Test and build gates on both repos
structlog
JSON logging, request-ID tracing
pytest · go test
Behavioural tests in both projects
Streamlit · Folium
VAYU-DRISHTI dashboard and GIS map

Working knowledge

Used in coursework and study, not yet in anything I have shipped publicly.

C · C++
Data structures, algorithms, systems coursework
scikit-learn
Classification and evaluation workflows
Pandas · NumPy
Data processing and analysis
Redis
Caching and queueing patterns
Linux
Daily driver, shell tooling, deployment

05Engineering record

What is actuallyin the repositories

Not stars or streaks. Whether there are tests, whether CI runs them, and whether the thing deploys.

Engineering practices per project: tests, continuous integration, containerisation and deployment status.
ProjectTestsCIContainerDeploy
deadlockdGo behavioural suitego mod verify · go test · frontend buildDockerfile + composeLive — deadlockd.vercel.app
VAYU-DRISHTIpytest + fixturesFeature branches, PR reviewDockerfile + compose + entrypointLocal / staging

06Now

What I’m looking for

Backend and systems work where correctness matters more than surface area.

Currently finishing a B.Tech in Computer Science and Engineering at Lovely Professional University, and extending VAYU-DRISHTI’s GIS layer from interface contracts to real raster tiles.

If you are building something where the hard part is underneath — concurrency, data layers, observability, the platform other people build on — I would like to hear about it.

Navigation

Use arrow keys to select, Enter to open, Escape to close.