The AI Dependency Check
Four questions about any code the assistant helped with: could you explain it without the tool, recreate its core idea, describe its failure modes, and debug it yourself? Where the answer is no, go one layer deeper — that layer is yours now, whether you understand it or not.
The situation, the reflex, and why it stalls
Every lesson starts where being stuck starts: someone has a problem, and the first move that comes to mind feels like progress.
Code the assistant wrote is in your system and it works. How do you find out whether you understand it well enough to own it, and what do you do about the parts you do not?
The store's checkout has a retry-with-backoff wrapper around the payment call, generated last month. It has never failed. Today the provider had an outage and the wrapper retried a charge that had actually succeeded; a customer was charged twice. You open the wrapper and realise you cannot say what it does when the provider times out.
Ask the assistant to explain the wrapper, and then to fix it. It wrote it; it can explain it. The explanation is clear, the fix is applied, and the double charge is handled. The next outage will find the next thing you cannot explain.
The explanation is understood while it is on screen and gone when it is closed. Nothing in reading an explanation produces the ability to reproduce the idea; that comes from reproducing it (Build From Memory).
- The explanation is understood while it is on screen and gone when it is closed. Nothing in reading an explanation produces the ability to reproduce the idea; that comes from reproducing it (Build From Memory).
- The fix is another piece of code you did not write and cannot explain, sitting next to the first. The dependency has not been reduced; it has been extended by one layer.
- The failure modes were never enumerated, so this outage found one and the next will find another. A wrapper whose failure modes you cannot list is a wrapper whose behaviour under failure you are discovering from customers.
- The team's ability to debug the checkout is now bounded by the assistant's availability and by how well you can describe a problem you do not understand to it.
The move
Precisely enough to apply it to a problem you have never seen — not a slogan.
- Run four questions over any piece of code the assistant had a hand in: Could I explain this without the tool? Could I recreate its core idea from scratch? Do I understand its failure modes — what it does when the thing it calls times out, errors, succeeds late, succeeds twice? Could I debug it myself if it misbehaved? Each is answered yes or no, honestly, and the noes are the map of your dependency.
- For each no, go one layer deeper — not "learn everything about retries" but "understand the one mechanism this code relies on that I cannot currently explain". For the wrapper, that layer is idempotency: what makes a retried charge safe, and what this wrapper does or does not do to make it so. One layer is usually enough to turn the no into a yes; the next layer is optional (Going One Layer Deeper).
- Prefer recreating to reading. The test of understanding is producing the core idea with the tool closed — a retry loop with a backoff and an idempotency key, in pseudocode, from memory. If you can, the explanation will follow; if you cannot, no amount of re-reading substitutes.
- Run the check before the incident, at the moment the code is accepted, and record the result. "Accepted with a no on failure modes" is a debt entry with a name; it can be paid on a quiet afternoon instead of during the outage (The Complexity Ledger).
The check, as a board about your own understanding
The dependency check is an unknowns board pointed at yourself: what you know about this code, what you have been assuming, and what you do not know — each unknown sharpened into a question and an experiment that would answer it. The board below is the retry wrapper after the check and before the afternoon of depth.
- ✓It loops up to a fixed count with increasing delays between attempts.
- ✓It catches network errors and retries; it re-raises other errors.
- ✓It has never failed in a way anyone noticed, until the outage.
- ~A retried charge is safe. It was never checked; the outage showed it was false.
- ~The provider distinguishes a timeout from a failure. Unverified.
? What it does on timeout.
becomes When the charge request times out after the provider has actually charged, what does the wrapper do next, and what does the provider do with the second request?
experiment In test mode, make a charge whose response is dropped (a proxy that swallows the reply), let the wrapper retry, and read the provider's ledger for that customer.
? Idempotency.
becomes Does the provider accept a client-supplied key that makes a repeated charge return the first result, and does the wrapper send one?
experiment Read the provider's idempotency documentation; grep the wrapper for any key; send two charges with the same key in test mode and count charges.
? Whether I could debug it.
becomes Given a double charge, what would I look at first, and does the wrapper log enough to look at?
experiment Write the three log lines you would want, check whether they exist, and add them if not — with the tool closed.
All three unknowns sit on one layer — what makes a retry of a payment safe — and one afternoon on that layer closes them. The board makes the layer visible; without it, "I do not understand the wrapper" is a feeling, not a plan.
Which no to pay first
Not every no deserves an afternoon. The order below is one way to spend depth: by blast radius and by how soon the no will cost something. The alternative order is for a different situation, and the device says which.
- 1Failure modes on anything touching money, stock or an external system
because These noes become customer-visible incidents, and they arrive during outages when there is no time to learn.
- 2Debuggability on the same code
because If the failure-mode understanding is right, the logs and probes that make it debuggable follow directly, while it is fresh.
- 3Recreation of the core idea for anything you will change soon
because Code about to be modified has to be understood well enough to predict the modification's effect; recreating it is the fastest route.
- 4Explanation for anything others will read
because A comment or a design note written in your words is the cheapest form of ownership, and it is checked every time someone reads it.
- 5Everything else: recorded, carried, revisited when it changes
because A no on a formatting helper is a debt with no interest; the record is enough.
How the check goes wrong
The failures are of the check itself: run on everything, run on nothing, or run dishonestly. Each row is a way of appearing to own the code while the dependency is unchanged.
| Trigger | Symptom | Cause | Response |
|---|---|---|---|
| Yes by default | Every piece of generated code is "understood"; the outage finds otherwise. | The answers were about reading, not producing; nothing was tried with the tool closed. | Recreate the core idea on paper before writing yes. |
| Rabbit hole | A week on distributed consensus; the wrapper still has no idempotency key. | "One layer deeper" became "every layer". | Name the one mechanism this code relies on; stop when it is explained. |
| Check on everything | Merges take days; helpers get failure-mode analyses. | No blast-radius ordering. | Record the noes on low-risk code and move on. |
| Fix not re-checked | The fix for the double charge has a bug the wrapper never had. | The fix was new generated code, accepted without four answers. | Run the check on every fix; it is the same code path with a new author. |
How to do it
Most important first.
- When accepting generated code, write the four answers next to it — in the pull request, the notebook, or a comment — before merging. A no is allowed; an unrecorded no is not.
- For each no, name the one layer beneath it: the mechanism, the guarantee or the protocol the code depends on. "Idempotency keys" is a layer; "retries" is a topic.
- Spend the depth on the noes in order of blast radius: failure modes first for anything that touches money, inventory or external systems; explanation first for anything that will be read by others.
- Turn each no into a recreation exercise: close the tool, write the core of the code from your understanding, then compare. The differences are the next questions (The Feynman Check).
- Re-run the check on anything the assistant fixes, because a fix is new code and has its own four answers.
Worked on a concrete problem
The move has to produce something. This is what it produced.
- The retry wrapper, checked. Explain without the tool: partly — the loop and the delays, not what happens on timeout. Recreate the core idea: the loop yes, the idempotency no; you did not know a key was involved because there is none. Failure modes: no — you cannot say what happens when the provider succeeds but the response is lost. Debug it yourself: no, as the outage showed. Three noes, and they all point at the same layer: what makes a retry of a payment safe. One afternoon on idempotency keys and the provider's retry semantics turns all three into yeses, and the fix you then write is one you can explain.
- The search endpoint for "search products by name", checked. The assistant wrote a query with a trigram index. Explain: yes, roughly. Recreate: yes — a lowercase prefix match would be your version, and the trigram is an improvement you can see the reason for. Failure modes: partly — what happens with a very short query? Debug: yes. One partial, on a piece with no blast radius. Recorded, not acted on; this is a fine place to carry a small dependency.
- The file-upload service's presigned-URL flow, checked. Explain: no. Recreate: no. Failure modes: no. Debug: no. Four noes on the path every customer image takes. The layer beneath is the object store's signed-request model, and the assistant's code cannot be owned until that layer is understood — so it is not merged until it is, and the understanding takes a morning.
How you know it worked
What now exists that did not before, and what question you can now ask.
- Every piece of accepted generated code has four recorded answers, and the noes have a named layer beneath them.
- You can reproduce the core idea of the code that matters most — payment, inventory, upload — with the tool closed.
- You can list what each critical piece does under timeout, error, late success and duplicate, and the list came from you.
- Incidents in generated code are debugged from evidence, and the tool is a partner in them rather than the only reader.
The questions you can now ask
The field this whole domain exists for. After this lesson, these are the questions to put to an unfamiliar problem.
- ?With the tool closed, could I explain this, recreate its core idea, list its failure modes and debug it?
- ?For each no: what is the one mechanism beneath this code that I cannot currently explain?
- ?Which of these noes sits on a path with real blast radius, and which can I carry as a recorded debt?
- ?When the tool fixes something, have I run the four questions on the fix?
What can go wrong
- The check becomes a gate on everything. A generated string-formatting helper does not need a failure-mode analysis. Spend the depth where blast radius lives.
- "One layer deeper" becomes a rabbit hole: idempotency leads to distributed consensus leads to a week. The layer is the one mechanism this code relies on; stop when the no is a yes.
- The four answers are recorded as yes by default. The honest answer is what you can produce with the tool closed, and "I read the explanation" is not it.
- The check is run only after incidents, which is the reflex with a form attached. It belongs at acceptance time.
- Going one layer deeper costs the time the assistant saved, sometimes all of it. On code with no blast radius that is a bad trade, and the check is what tells you which code that is.
- Recording noes makes your dependence visible to reviewers and to yourself, and visibility is uncomfortable. The alternative is dependence that is discovered during an outage.
- Recreating from memory is slow and often produces a worse version than the generated one. The worse version is the point; the comparison is where understanding is made.
- "So I should not use generated code I cannot fully explain." You should not *carry* it unrecorded on a path that matters. Recorded noes on low-risk code are a normal, sane debt.
- "The four questions are a test of whether the code is good." They are a test of whether you own it. Good code you cannot debug is still a liability on the checkout path.
- "Reading the explanation counts." The check is what you can produce with the tool closed. Reading is how you start; recreating is how you know.
Where this applies
Problem-solving advice is stated as universal far more often than it is. These labels say what each method is specific to — and where CONTESTED appears, the note gives the strongest form of the opposing view.
- GENERALThe four questions apply to any code you did not write — a library, a colleague's module, a snippet from a forum — and the assistant is only the case where the code arrived fastest and with the least friction.
- DOMAIN-SPECIFICOn a payment or inventory path the failure-modes question is the one that must be a yes before merging; on an internal dashboard the explain question matters more, because the code will be read more than it will fail.
- ILLUSTRATIVEThe retry wrapper, the double charge, the trigram index and the presigned-URL flow are invented to show the check producing answers; no real incident is described.
Where the depth lives
This domain asks the question and hands the answer off by name.
- — The manifesto's layers at /manifesto/layers are the "one layer deeper" this check sends you to: pick the layer the code depends on, not the whole ladder.