DEV Community

Cover image for FirstStep: The coding practice tool that makes you state your first move, then hands you the smallest input that breaks your code
Meena
Meena

Posted on Edited on

FirstStep: The coding practice tool that makes you state your first move, then hands you the smallest input that breaks your code

Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle Submission 💸

This is a submission for the Hacktoberfest Open-Source AI Challenge: Side Hustle

What I Built

I can solve a problem I have seen before. Change it slightly and I freeze.

That is how I learned competitive programming: watch a tutorial, copy the idea, pass the samples. It feels like progress until a new problem shows up in a different shape and I have no idea how to begin. The missing skill is not syntax. It is choosing a first concrete move, then debugging against an input you can trace by hand.

Every tool I tried fails at exactly that. LeetCode and HackerRank give volume and a green checkmark. ChatGPT gives the whole solution, which is the one thing that makes the freeze worse.

FirstStep is a practice tool built around the missing skill:

  1. Pick a problem.
  2. Write one sentence about how you would start. "I will think about it and solve the problem" is rejected. "I would try a list with one negative number by hand" unlocks the editor.

  3. Write your code. If it is wrong, FirstStep does not show the solution. It finds the smallest input that breaks your program and gives you a short plain-language reason.

  4. At the end of a session, see which failure shapes keep beating you (all-negative input, a self-pair trap, a single element) and when to retry the problem (spaced reviews at 1, 3, 7 and 21 days).

Here is a real run. This program passes every positive sample:

n = int(input()); a = list(map(int, input().split()))
b = c = 0
for x in a:
    c = max(0, c + x); b = max(b, c)
print(b)
Enter fullscreen mode Exit fullscreen mode

FirstStep answers:

Found a failing input (smallest I could reduce it to, 4 runs):
1
-5
Expected: -5      Your program: 0

Your program was run on numbers that are all below zero.
Check what it does when no choice is positive.
Enter fullscreen mode Exit fullscreen mode

One number exposed the bug, and I still had to find the fix myself. That is the whole idea.

Who would pay (the side-hustle angle)

Students and career-switchers already pay for LeetCode Premium, coaching and courses. FirstStep sells something those do not: the habit of starting concretely, and a private report of how you fail.

  • Free: six beginner problems, graded hints, your mistake profile, a shareable report.
  • Paid: harder level 3 problems, each with the same four-step hint ladder, plus a full learning report (week-by-week trend, the first steps you actually wrote, and a practice plan ranked by your recurring mistakes).

Nothing in the paid tier needs a person in the loop, and serving it costs almost nothing. The real cost is writing good problems, not running models. A friend who grinds competitive-programming problems said they would pay for more problems and pattern filters (more under "My First User").

Demo

The video shows the gate rejecting a vague sentence and accepting a concrete one, a failing input found in seconds, and the session report.

Code

GitHub logo meenanoolu / firststep

Practice tool that forces a concrete first step before coding, then returns the smallest failing input you can trace by hand. Open-weight optional, rules always work.

FirstStep

A practice tool for people who keep solving the same coding problems by memory and then freeze on anything new.

Live demo: https://hacktoberfeste6c4p8.tech
Also on Render: https://firststep-jtuf.onrender.com
Repo: https://github.com/meenanoolu/firststep

Before you write any code you must state one concrete first move.
If your code is wrong, the tool returns a tiny input you can trace by hand that breaks it, plus a short plain-language reason.
It does not dump a full solution.


Why this exists

Many beginners (and some of us who already know the patterns) pass samples by recognition, then blank when the same idea appears in a slightly different shape.

FirstStep forces the starting move and shows the smallest counterexample instead of a green checkmark or a full answer. The goal is a habit: start with something concrete, then debug against a hand-traceable input.


What it does

  1. First-step gate
    You write one sentence about how you would…

How I Built It

first-step sentence ──► gate (fine-tuned model on Tinker, rules as fallback)
                              │ viable?
learner's code ──► sandboxed runner ──► oracle + budgeted search ──► shrinker
                                                                        │
                      leak-checked explanation ◄── failure features ◄───┘
                              │
              SQLite: failure profile + spaced reviews ──► report
Enter fullscreen mode Exit fullscreen mode
  • FastAPI + SQLite for sessions, failure profiles and review schedules.
  • A sandboxed Python runner: AST-restricted, with time and memory caps and a cap on concurrent runs.
  • A counterexample finder: every problem ships with a correct solver and a brute-force oracle. The finder tries hand-written edge cases first, then random tests under a budget, then shrinks the failing input until it is small enough to trace on paper.
  • A leak checker that every hint and model reply must pass: no code, no "the answer is", no copy of the reference solution, no spoiler terms before their hint level.
  • One static page for the front end, Docker for packaging, a Render Blueprint for deployment, and 101 tests.

Does the finder actually find bugs? I measured it

The hard bugs are the ones that pass the samples, so I tested against exactly those. I generated 511 mutants (small deliberate bugs) of the correct solutions, kept the 27 that are really wrong but pass every public sample, and compared strategies:

Strategy Wrong-but-pass-samples bugs found
Random tests x30 63%
Random tests x150 96%
FirstStep finder (edge cases + random x150) 100%

The shrinker reduced failing inputs from 2.3 to 2.0 elements on average. On 17 classic hand-written pitfalls it found 17 of 17.

The honest caveats: mutants are not real student mistakes, and I wrote the edge cases, so that arm is partly tuned to my problems. Plain random testing is already strong. The finder's real value is that it returns the smallest failing input and names the failure shape. You can reproduce the numbers with python -m eval.mutation_eval.

Partner technology

Tinker: a fine-tuned first-step classifier, running live

The gate has to judge one sentence: is it a restate, a small_example, a brute_force, an observation, or too_vague? My keyword rules score only 40% on this. I used Tinker to fine-tune Qwen3-8B (LoRA, rank 16) on 250 labelled sentences.

Run What changed Test set Rules Base Qwen3-8B Tuned
1 Pilot: 60 train examples 20 n/a 20% 55%
2 250 train examples 50 40% 56% 70%
3 Re-run to verify 50 40% 56% 72%
4 Minibatches: 48 optimizer steps 50 40% 56% 100%
4 Same checkpoint, problems never seen in training 40 40% not run 100% (40/40, 95% CI 91-100%)

What I learned from Run 3 to Run 4. At 72% the obvious fix is more data. The real problem was my training loop: it made one optimizer step per epoch, 4 steps in total. Switching to minibatches of 16 gave 48 steps, and accuracy jumped from 72% to 100% with the same data.

What the 100% does and does not mean. The labelled sentences are synthetic, not collected from real learners. The second test uses two problems (balanced-brackets, range-sum-queries) that never appear in training, but the sentences are still cleaner than real learner text. I read this as strong evidence that fine-tuning works for this task, not as a claim that the live classifier is 100% accurate. The next step is scoring real first steps from the live app. The app already stores them (it can be turned off with one setting) and tinker_ft/export_real.py exports them for labelling.

Serving it from Render. The tuned checkpoint is saved on Tinker, and the app calls it through Tinker's OpenAI-compatible endpoint. One bug I avoided: the model was fine-tuned on a raw prompt format, so calling the usual /chat/completions endpoint (with a chat template and a tutor prompt) would have fed it text it never saw. The app calls /completions with the exact training prompt, and a test pins that prompt string.

Honest operations notes:

  • A call takes about 6 to 7 seconds, so the UI shows "Checking your first step with the fine-tuned model..." while it waits.
  • Tinker's endpoint is beta and meant for low traffic. So the model is never a single point of failure: any timeout, error or unexpected output falls back to the rules and the learner is never blocked.
  • The model does one job. It never grades code and never writes solutions or hints. Code does that.
  • /api/health shows which backend is active, and /api/stats counts model calls accepted versus rejected. The UI labels each result "checked by the fine-tuned model" or "checked by rules".

Render: the runtime for the whole AI path

FirstStep runs on Render as a Docker web service defined by a Blueprint (render.yaml). Render is not just the place the page lives. It runs the pipeline:

  • the call to the fine-tuned model, with a timeout and rule fallback,
  • the leak check on anything a model says,
  • the sandboxed execution of learners' code, with a concurrency cap and per-address limits,
  • the SQLite database on a persistent disk (/data), so sessions, mistake profiles and review dates survive restarts.

Setup details: the Tinker key and model path live only as dashboard secrets, a health check gates each deploy, and the .tech domain points at the service.

One trade-off I chose knowingly: a Render service with a disk cannot do zero-downtime deploys or scale to several instances. A deploy causes a brief restart. For one small service that is fine. To scale out, the next step is moving SQLite to Render Postgres.

Gemma and Ollama (local path)

The same code can use a local Gemma2:2b through Ollama to reword hints and explain counterexamples, behind the same leak check. This is the offline option. The live site does not use it.

.tech domain

The live app is on a .tech domain claimed through Hacktoberfest: https://hacktoberfeste6c4p8.tech

What Is Still Limited

  • Eight problems (six free, two paid). The product is only as good as its problem bank.
  • One real user so far. One user is not a market.
  • The classifier was trained and tested on synthetic sentences. Real learner text will be messier, and I expect lower accuracy until I retrain on it.
  • The finder and the leak checker are tuned to my own problems. A held-out set of real wrong submissions is the honest test, and I do not have one yet.
  • Latency: a 6-second wait for the gate is long. I would trade some accuracy for a smaller or faster model if learners complain.

Why Does Open Innovation Matter?

  • No closed API on the critical path. The base model is open-weight Qwen3-8B, and the LoRA adapter I trained is mine. If a provider changes its pricing or goes down, the app drops to rules, and the app also supports a local Ollama model or any OpenAI-compatible host through environment variables.
  • The free tier does not depend on anyone's quota. Everything except the gate is plain code, and if Tinker is unavailable the gate falls back to rules.
  • Learners' data stays minimal. First steps are stored without a name, a setting turns that off, and a local model keeps text off third-party servers.
  • Checkable behavior. The prompts, the data, the training script, every run's predictions and the evaluation code are in the repo, so anyone can reproduce or criticize the numbers.

My First User

I showed the live site to a friend who grinds competitive-programming problems. They said the first-step gate stops the "I already know this, I'll just write it" reflex, which is what leaves them blank on a new variant. They said they would pay for more problems and for filters by pattern and difficulty. They also asked for a way to check an approach while writing code, not only at the end. That is on my roadmap, and it is deliberately not the identity of the tool yet.

One session from one friend is not proof, but it is the first sign the problem is real for someone besides me.

Prize Categories

  • Best Use of Render: the Blueprint-defined Docker service runs the whole AI path (model call, fallback, leak check, sandboxed runner) with a persistent disk for state.
  • Best Use of Tinker: I fine-tuned Qwen3-8B for a specific task, measured it against a rules baseline and the base model (40% / 56% / 100%), evaluated it on problems it never saw (40/40), and run it live in production with a fallback.
  • Best Use of a .tech Domain: https://hacktoberfeste6c4p8.tech
  • Best Use of Gemma: the local Ollama path with Gemma2:2b (not the live site).

Try it and tell me which failure shape beat you first.

Top comments (1)

Collapse
 
meena_n profile image
Meena •

Try it and tell me: what was the first bug FirstStep caught in your code?