I have shipped bugs that crashed servers, bugs that corrupted data, bugs that woke me up because a health check went red. Every one of them announced itself. The worst bug I have shipped so far did none of that. Nothing broke. No exception was thrown. No chart moved. It just quietly turned away the exact people the whole project exists for, and it did so in a way that was invisible by construction.
Let me back up.
What I built
Skill the Gap (skillthegap.com) is a free platform that teaches AI literacy and job-readiness in English and Hindi. It is India-first but open to anyone. There are 17 courses and 114 lessons. It runs in a browser on a budget Android phone — no app to install, no fee, no ads, no investors. One person builds and runs it.
The two flagship tracks say what the platform is about. "AI ki ABCD" teaches you to understand and actually use AI, with zero jargon. "Job-Ready Basics" covers the minimum skills a first intern needs, starting from absolute zero. Six lessons each, about ten minutes a day.
The lessons are interactive with graded checks, and a finished course ends at a hard exam gate, not an automatic certificate. Clicking through the pages awards nothing. Empty or stub content awards nothing. If you pass the exam, the certificate is drawn in your browser, free, with a deterministic ID — and it is always bilingual, English and Hindi on the same document, regardless of which language you studied in. The reasoning is simple: the person who evaluates you may not share your language, and a certificate that only speaks one of them is only half a certificate.
The content is relocated, not just translated. Money is in rupees. The payments lesson teaches UPI. The interview drills rehearse the interviews people actually walk into, not the ones in imported textbooks.
The engineering constraint that shaped everything
The whole architecture answers one question: what does this cost the learner?
For on-device AI help, I use the small model the browser already ships with — Chrome's built-in Prompt API. Zero download for the learner, and where it is not available, the feature degrades in steps rather than falling over.
I seriously considered running a model fully in-browser with WebLLM, and I rejected it, because it needs roughly a 2.5 GB download before the model says its first word. That download is free for me. It is expensive for a learner on a metered connection and a cheap phone. A feature whose price is paid by the learner is not a free feature, whatever my hosting bill says.
Same logic on translation. Translated lessons are static files generated once by a batch job — no translation model runs in production, no TTS, nothing per-request. That keeps the marginal cost of a learner at approximately zero, and it is also more honest: a lesson generated on the fly is a lesson no human reviewed before the learner saw it.
There is no always-on GPU anywhere. The threshold at which renting one would actually be justified is written down in advance, so I cannot talk myself into it later on a whim.
I tell you all this because I want you to believe I was thinking carefully about learner-side cost. I was. And I still shipped the bug.
The wall
For a long time, everything on the site sat behind an email-OTP signup wall. Every course, every lesson. You could not read a single sentence of teaching without creating an account first.
This had two consequences. The first was ordinary: search engines could index nothing. The entire catalogue was one JavaScript-rendered page behind a login. Bad, but the kind of bad I would have caught eventually, because SEO problems eventually show up in numbers you look at.
The second consequence is the one I missed, and it is the one that still bothers me.
Every personal recommendation dead-ended.
Picture it — and I do mean picture it, because this failure produces no data, so a hypothetical is all anyone gets. Someone finishes a lesson. They feel that small jolt of "I can actually do this." They care enough to send the course to a friend who has been struggling with exactly this. That is the most valuable event a free education platform can generate: one learner spending their own credibility to vouch for you.
And the friend taps the link and lands on a signup form. No lesson. No sample. No evidence the thing is any good. Just a demand for their email before they have been given a single reason to hand it over.
Why this bug is worse than a crash
Here is the part that gets me: that failure generates no signal at all.
Nothing breaks. No error is logged. No chart turns red. No complaint arrives — the friend does not know you well enough to complain, and the person who shared the link never finds out it went nowhere. Those people never enter the funnel, so they are invisible in analytics by construction. You cannot see a dip in a line that was never allowed to exist.
The cost of a wall is paid entirely by the people who never get past it — which is exactly the population you cannot measure. I had instrumented everything I could instrument, and the most important failure on the site lived entirely outside the instruments.
The fix
The fix was not clever. The first lesson of every course is now an ordinary static page. Full text, both languages, no account, no wall. Anyone with the link can read it, and so can every search engine.
The interactive parts — the graded checks, the exercises, the exam gate, the certificate — stay in the app, and they become the reason to sign up, after the site has already taught you something. A shared link now teaches your friend something before it asks them for anything.
And once I had done it, I realized the wall and the 2.5 GB download were the same mistake wearing different clothes. Both of them charge a person up front — email, or bandwidth — for the privilege of finding out whether you are worth their time. I had rejected that trade instantly when the cost was measured in gigabytes, and shipped it without a second thought when the cost was measured in a signup form. The currency changed and I stopped recognizing the transaction.
Free as an architectural fact
One more thing this project taught me. "Free forever" cannot be a marketing promise, because promises get renegotiated the first month the bill hurts. It has to be an architectural fact. If the monthly cost grows with usage, "free" is just a countdown — and the people who lose access first, when the countdown ends, are precisely the ones who needed it most. Static lessons, batch translation, the browser's own model, no GPU: that is not frugality for its own sake. It is what makes the promise structural instead of rhetorical.
The same rule shaped the parts that look like decoration. Progress runs on a railway ladder — fifty XP a lesson, six ranks from Yatri to Station Master — and all of it lives on the learner's own device. No leaderboard, no profile service, no rows to store, nothing to keep paying for. It is the kind of motivation loop that usually arrives with a backend bolted to it, and it turned out not to need one.
Give first, ask later. Never charge someone — in money, megabytes, or email addresses — for the privilege of finding out whether you are any good.
If you have shipped the same class of invisible failure — something that turned people away without ever writing a line to a log — I would genuinely like to hear about it. Those are the bugs worth trading notes on, precisely because none of us can see our own.
And if you know someone who has been meaning to figure out this whole AI thing, or someone staring down their first internship with no idea where to start: the first lesson of every course on skillthegap.com is readable right now, in English and in Hindi, no account required. Send them a link. This time it will actually open.
सब सीखेंगे. Everyone will learn.




Top comments (0)