I am not a software engineer. For three weeks, AI made me feel like one.

It gave me the output of a senior developer, allowing me to ship features at a pace that should not be possible for a solo operator. But I knew there was a structural flaw in this feeling. I was operating with the reach of a giant and the foundation of a novice. The code worked. The screens loaded. But the logic underneath was a black box I did not own. And in operations, if you do not own the logic, you do not own the risk.

The Setup: The “Perfect” Context

My assumption was simple: clarity in, clarity out.

I was not building in a vacuum. As established in Log 10, I had already locked my stack to the most standard, boring tools available — Python with FastAPI, Supabase, and Cursor. I chose them to avoid unusual errors. I assumed that with a standard stack and a precise Product Requirements Document, the AI would act as a perfect translator.

I spent 5 days refining the specs for the Associate Enrollment Module — a core CRUD function for onboarding new staff. I defined every field (name, ID, bank details, PF number), every validation rule, and every success state. I handed this to the AI expecting clean execution.

The Experiment: The Speed of Corruption

The first version worked. I could enter a name, hit save, and it appeared in the database.

Then I asked for one validation check: ensure the bank account number is 9 to 18 digits. Instantly, the AI rewrote the file. It added 60 lines of new code and removed 30 lines of existing logic. This happened in seconds. Why did it import three new libraries? Why did the save function now have a nested loop? Why did the error handling change from a simple alert to a complex try-except block?

The AI solved my immediate problem, but it introduced invisible weight. Over the next three bug fixes, it layered more complexity each time. The code was working, but it was becoming a patchwork. I was not an engineer building a system. I was a spectator watching a machine guess. The generation was faster than my audit. I was drowning.

The Realization: Black Box Drift

This is the trap.

When you write code yourself, you feel the pain of every new library you add. You know exactly where the problem areas are because you had to type them out. When AI writes code, there is no pain. A clean function costs the same as a bloated, dangerous one. I was building a system where Black Box Drift was inevitable. If I kept going, I would end up with a 40-module system that worked on clear days but would be impossible to debug when things broke. I could not audit the code because I had not built it — I had requested it.

The Protocol: The Three-Attempt Rule

I stopped the build. To kill this, I built a new workflow: the Three-Attempt Protocol.

Attempt 1 is about logic — the messy draft. The goal is to prove it works. I work with the AI to get the core logic functioning. I do not care about code quality, variable names, or efficiency. I need to see the data move from A to B correctly. The mindset is: make it work. The output is a working prototype with rough code.

Attempt 2 is about cleaning — the architect’s review. This is the critical step I was missing. I ask the AI to reverse-engineer its own code into a technical spec. Reading that spec forces me to see what it actually built versus what I thought I asked for. Then I edit the spec, removing what is unnecessary and adding requirements it missed. Using this rewritten spec, I rebuild the module from scratch. The output is a lean version that is 20 to 30% less code and faster.

Attempt 3 is about hardening — security and scale. I have not finished building this step. Once the clean logic is locked, I stop acting like a developer and start acting like someone responsible for the whole system. I look for standard engineering patterns, security vulnerabilities, and maintained libraries. The mindset is: make it survive.

Closing

AI is an eager generator running at speed. My job is to slow it down. Otherwise I will ship a black box I cannot debug when something breaks.