Emmanuel Okeke

[0%] 1/7

← cd /blogAI

AI Doesn't Replace Senior Engineers. It Lets You Borrow One.

$ cat --info "senior-reviewer-on-demand.mdx"

> published: 2026-05-25 | read_time: 5 min read | category: ai


The commit that made me start

A few months ago I was shipping a phase of TinyOps — the solo guardrail product I'm building. The kind of project where the worst-case failure mode isn't a crash; it's the silent kind: a rule that should have fired didn't, and nobody knows it didn't. I pushed what I thought was a clean Phase 3. Out of habit, I asked Claude to do a senior-engineer review of the diff before I merged.

It came back with three things. One was a NIT — a small style suggestion. Two were WARNINGs. The first was a comparison bug in a tiny helper that silently fell through to a default that always returned false — the kind of bug that doesn't error, it just quietly evaluates "no" forever. The second was a missing retry on an external API call that could leave a rule execution stuck in a half-finished state with no recovery path.

I'd written the code an hour earlier and missed both. The reviewer caught them in thirty seconds. I haven't merged a PR without that loop since.

The pattern in my commit history

The rhythm is visible across any of my recent side projects. A typical pair:

feat: implement Phase 3 provider Protocol + rule_dispatcher
fix(dispatcher): self-review WARNINGs 1 and 2 — status type + DuplicateExecutionError
test(dispatcher): cover non-422 4xx paths (self-review NIT 4)

And another:

feat: implement Phase 5 orchestrator + scheduler_client + audit_log
fix(core): apply self-review W3 + NIT 5 — confirmation bail-out + audit pre-flight aborts

Every phase ships in two passes: the implementation commit, then a follow-up that names exactly which review finding it addresses. Sometimes the second commit is small. Sometimes it's a structural change I would have shipped without thinking twice if I were working alone in my head.

That follow-up commit, every time, is the work the bug doesn't get to do later.

The loop, concretely

Four steps. Fifteen minutes most cycles:

  1. Write a phase. Not a one-line fix — a unit of work with clear scope. "Implement the GitHub webhook handler." "Add rule-execution audit logging." Big enough to have judgment calls in it.

  2. Run a senior-review skill against the diff. I use one that classifies findings into BLOCKER / WARNING / NIT and writes them up the way a tech lead would — with file:line citations, the reason it matters, and a proposed fix.

  3. Triage in writing. Not every WARNING gets fixed. Some are wrong. Some are intentional. I write a one-line decision next to each — applying, deferring (reason), rejecting (reason). That's the artifact that lets me revisit decisions later.

  4. Ship the fixes in a separate commit named after the findings. fix(dispatcher): apply self-review W1, W2; defer NIT 3, 4. The history becomes legible to my future self.

The discipline is mostly in step 3. Without it, you either apply everything (and become an obedient executor of an AI's opinion) or apply nothing (and the loop is theater). Triage is where you stay in charge.

Why it works on solo projects specifically

When you're on a team, you have peers. They catch you. When you're solo, the bug ships.

The honest reason this loop matters more for me than for someone at a 50-person company is that I don't have anyone whose job it is to read my code before it runs against real users. What changed in the last two years isn't that AI got smarter about code — it's that AI got reliable enough to play a structured role in a workflow, not just answer questions. A senior reviewer on demand was always the thing solo engineers wanted. It just took until now to actually have one.

What it isn't

This is not "ask Claude to review my code." That works for small diffs and trains you to ignore review output for big ones, because a freeform "any issues?" prompt produces a mix of useful catches and noise that's exhausting to triage. The shape of the prompt — the BLOCKER / WARNING / NIT taxonomy, the requirement to cite files and lines, the explicit ask for a proposed fix — is what makes the output actionable instead of conversational.

It's also not a substitute for tests. The reviewer catches judgment issues — wrong abstractions, missing edge cases, security smells, things that compile and pass tests but will hurt. Tests catch behavior issues. Different bug class.

And it's not a substitute for actually being a senior engineer. The loop only works because I can tell when a finding is wrong. An engineer who applies every NIT without judgment is delegating their own taste to a model that doesn't have any.

What I'd do differently

The thing I keep wanting and haven't built yet: a small feedback loop on the reviewer itself. I want to mark findings as "this caught something real" or "this was wrong and wasted my time" and use that signal to tune the next review's prompts toward the categories that pay off for this codebase. Right now I get a generically excellent review every time, and most of the cost of running it is filtering out the parts that don't apply to me.

Until then: write the phase, run the review, triage in writing, commit the fixes in a separate pass. The bug doesn't get to be a bug if it gets caught in the loop.


← Previous

TinyOps Speaks MCP Now

1 of 7