All posts

Where I Deliberately Don't Use AI

September 29, 2026Michał Woliński13 min read
Where I Deliberately Don't Use AI

I ship agentic retrieval pipelines for a living. I have written more prompt code this year than SQL. And there is a list of things I deliberately do not let a model do, even when it demonstrably could — not because the technology is not ready, but because on those specific tasks the trade is bad, and I have run the numbers on the trade enough times to know the shape of it.

This is that list, with the reasoning. It is not a warning about AI, and it is not a prediction that any of these will stay off-limits forever. Three of them I have already moved, and I say where below. It is an argument that "can it do this" and "do I want it doing this" are separate questions, and that the second one is the one most discussions never get to.

One clarification that matters, because it is the most common way this conversation goes wrong. A refusal on this list is almost never about capability. Modern models write competent SQL, competent prose, and competent incident summaries. The reasons I refuse are verifiability, reversibility, accountability, and what happens to my own judgment over the next five years. Those are engineering and craft considerations, and they do not disappear when the model gets better — some of them get worse, because a more capable model produces more plausible output, and plausible output is harder to verify than obviously wrong output.

Capability is not the question

Separate the two axes and most of the argument dissolves. On one axis: can the model produce an acceptable output for this task. On the other: is having the model produce it the right move. The first axis is a moving target that is mostly out of my hands. The second is a decision I make, and it depends on costs that have nothing to do with model quality.

Four of those costs come up again and again in my own decisions.

  • Verification cost. If checking the output costs as much as producing it, the model bought me nothing — and it cost me tokens, latency, and an illusion of progress. This is the single most useful heuristic I have, and it explains most of the refusals below.
  • Reversibility. A wrong output I can undo in a minute is a different object from a wrong output that is already in a customer's inbox or a production table. Automation belongs where the blast radius is small.
  • Accountability. Something with my name on it has to be something I can defend line by line, in a room, without hedging. That is not a moral position; it is a description of what signing something means.
  • Judgment maintenance. The skill I get paid for is the ability to look at a system and know where it will break. That skill is built by doing the work. Delegating the work delegates the practice, and the loss is invisible for a year and expensive in year three.

None of those four show up in a benchmark. That is why "the model scores 94 percent" does not move my boundary by itself.

Where I do use it

Worth stating plainly, so the rest does not read as a posture. The places I use models heavily, with a gate that matches the risk:

  • Retrieval and ranking pipelines. The whole point of the system. Embeddings, rerankers, query decomposition.
  • Code I am going to read anyway. Scaffolding a repository, writing the boring adapter layer, generating the first draft of a test file. I read every line that ships, which is what makes the verification cost acceptable.
  • Refactors with a verifier. Mechanical changes across many files, where the compiler and the test suite are the gate. The model proposes; the toolchain disposes.
  • Draft prose, translation, and naming candidates. I want ten options to react against, not one.
  • Log and trace triage. Cluster a hundred thousand error lines into something I can read. The output is a summary I then verify against the raw data, not a conclusion.
  • Explaining unfamiliar code. A model is a fast, confident, sometimes wrong guide to a codebase — good enough to orient me before I read the actual source, which is where the truth is.

Notice the pattern: the failures are all recoverable, and the verification is cheaper than the generation. Where that stops being true, the list below starts.

The gate matters as much as the permission. When I let a model scaffold an adapter layer, the gate is that I read the whole diff before it lands. When I let it cluster error logs, the gate is that I check its summary against the raw counts. When I let it propose a refactor across forty files, the gate is a compiler and a test suite. In each case the permission is generous and the gate is named. Permission without a named gate is not delegation, it is optimism.

Arithmetic and money

Anything where the answer is a number that has to be right, I compute. Not "prompt the model and check the arithmetic" — I compute it, and the model's role, if any, is to write the code that computes it or to explain the formula I hand it.

The reasoning is not that models are bad at arithmetic. It is that the failure mode is silent and the cost is asymmetric. A wrong digit in a ledger, an invoice, a capacity estimate, or a tax figure does not announce itself. It sits there, consistent with everything around it, until someone reconciles six months later. Compare that to a wrong paragraph, which a reader notices in seconds. Same nominal error rate, completely different exposure.

This is the same argument that governs hallucination generally — that the machinery which fabricates is the machinery that generalizes, and what matters is aligning the system's willingness to assert with the cost of being wrong. Here the cost of being wrong is the highest it gets, so the answer is a deterministic engine. The companion piece on hallucinations and context problems works through the general case; finance is where it is least negotiable.

Security, and anything irreversible

No model in the decision path for actions that cannot be undone: granting a credential, changing IAM, deleting data, moving money, touching DNS or a production database, sending something to a customer that a customer can act on. The model may propose. Something deterministic, and usually someone accountable, disposes.

The reason is not model error, and this is the part that gets misread. If the only risk were a model occasionally being wrong, you could handle it with a good verifier. The actual risk is that the input is attacker-controlled. The moment a model reads a document, a web page, an email, or a tool result, that content shares a context window with its instructions — and the security literature is consistent that there is no reliable way to detect a malicious instruction inside arbitrary natural language at the prompt level. A system that can be steered by the data it reads must not also hold the trigger for irreversible actions.

That is an architectural constraint, not a capability one, which is why it does not move as models improve. The permissions piece on guardrails for LLM agents is the long version of this argument; the short version is that I will happily let a model draft a Terraform change and never let it apply one.

Anything that carries my name

This is the least comfortable item on the list, so I will state it without decorating it. Architecture proposals, incident postmortems, performance reviews, design documents that other people will build against, anything sent as my assessment — I write those myself. Not the words only; the thinking.

The tempting version of this is to have a model produce the draft and then edit it heavily, and I have done that and I know the trap. Editing a competent draft is not the same cognitive act as producing it. The draft sets the frame, picks the options you consider, and quietly decides which parts of the problem you will not look at. You end up with a document that reads well and reflects the model's framing of the problem rather than yours, which is fine for a summary and wrong for a judgment.

For an incident postmortem specifically, the whole deliverable is the reasoning: the causal chain, the counterfactual, the decision about what to change. There is no version of that where the artifact matters and the thinking does not.

Things I don't understand yet

I will use a model to go faster on something I already understand. I will not use one to substitute for understanding, and the distinction is sharp once you test yourself honestly: could I debug this at three in the morning without the model.

If the answer is no, the thing is not done — it is borrowed. You have taken on a component whose failure modes you cannot reason about, and the bill arrives in the least convenient form: an outage at an hour when the person who prompted it is the only one who can reconstruct anything, and reconstruction means reading generated code they never understood. The speed you bought was real; so is the maintenance you owe.

There is research on this that matches the intuition. A CHI 2025 survey of 319 knowledge workers — self-reported, so treat it as a signal rather than a measurement — found that higher confidence in generative AI was associated with less critical thinking effort, while higher confidence in one's own skills was associated with more. The mechanism it describes is exactly the one I am guarding against: when the tool seems reliable, you stop checking it, and the checking was where the learning happened.

The practical rule I use: models are for acceleration on familiar ground and for orientation on unfamiliar ground. They are not a substitute for the phase where the mental model gets built, because that phase is the deliverable in disguise.

That rule is calibrated to me, though, and it is worth saying where it misfires. It assumes a baseline of understanding to accelerate from, and someone early in their career does not have one yet. Applied literally, it becomes advice to refuse the most patient and most available teacher they have — which is not the intent, and not the outcome I want. What survives the translation is the principle underneath: do not confuse fluency with understanding, and never ship an artefact you cannot reason about. The shape that follows for a junior is different. Use the model to build the mental model rather than to replace it: have it explain, argue with the explanation, then check the claim against the source or by running something. The failure to watch for is identical and arrives sooner — orientation feels like comprehension right up until the first incident, at which point only one of them is worth anything.

One-off decisions and taste

Some things have a cost that is mostly in their consequences, and a "correct" answer that depends on context no prompt contains. Naming a service. Choosing an API shape. Picking a library you will maintain for five years. Sequencing a quarter. Deciding who to hire.

These are not hard because of volume — they are hard because the answer is a function of everything you know and nothing you can write down. A model will give you a defensible option, and the defensible option is exactly the problem: it is the option that looks right to someone with no stake in it. For a decision you will live with, the value is in having a position, not in having an option.

There is also an arithmetic point that people skip. For a genuinely one-off task, writing the prompt, checking the output, and fixing what it got wrong frequently costs more than doing the thing. I use roughly a fifteen-minute rule: if the task is small and I already know how to do it, prompting is the slower path, and the honest thing is to notice that and just do the work.

Human communication

Difficult conversations, feedback, apologies, bad news, anything where the recipient matters more than the message. I write those myself.

Two reasons, and the second is the real one. First, a model-drafted apology or piece of feedback is detectable at close range by almost everyone who receives it, and being caught outsourcing sincerity damages the relationship more than the original offence. Second, and worse: the message and the relationship are the same object. Writing it is the act of taking the other person seriously. Delegating it is a small, efficient way of saying you did not have the time.

The two questions

Strip all of it down and my boundary is drawn by two questions asked about each action, not about the tool.

What does verification cost, relative to just doing it? If checking is as expensive as producing, the automation is theatre. This is why I let a model scaffold tests and do not let it summarize a contract I am about to sign.

What happens if it is wrong, and how quickly would I know? Reversible and visible is automation territory. Irreversible, or silent, or with a signature on it, is not.

I keep the answers in a file, because the boundary drifts and drift is invisible. Nobody wakes up deciding to hand over judgment; it happens one convenient exception at a time, each one individually reasonable.

# boundary.yml - committed, reviewed, and updated on purpose. # Scope: what a model may do ON MY BEHALF, not what I build with it. # On top of every entry below sits one standing condition: if I could # not debug it without the model, the work is borrowed, not done. boundary: # Reversible, verifiable, and the cost of being wrong is paid in minutes. ai_may_decide: - draft_text - draft_documentation - review_diff - scaffold_tests - suggest_refactor - triage_logs - summarize_document - explain_unfamiliar_code # The model produces a candidate; a verifier or a person disposes. ai_may_propose_only: - schema_change - production_config - dependency_upgrade - public_communication - architecture_decision # No model in the decision path. Not a capability statement - a # threat-model, reversibility, and error-detection statement. never_automated: # Distinct from money_movement below: the risk here is not an # irreversible transfer, it is a silent wrong digit that nothing # downstream will flag. - numeric_computation - money_movement - credential_and_iam_changes - destructive_operations - customer_facing_sends - anything_signed_with_my_name - incident_postmortems - hiring_and_performance gate: # The two questions the line is drawn with, action by action. verification_cost: "must be materially lower than doing it by hand" effect_if_wrong: "reversible, or visible, or countersigned"

The file is the point. An unwritten boundary is a vibe, and vibes move without telling you.

My line versus the team's line

The list above is mine, and I would not impose it. It falls out of my risk tolerance and out of what I happen to verify quickly, and a colleague who reads generated Kubernetes manifests faster than she writes them should let the model write them. A team policy built on one person's preferences is arbitrary, and arbitrary policy gets ignored — correctly.

What I do argue for at team level is narrower, and none of it is about taste:

  • Nothing irreversible without a verifier or a signature. This is architecture, not preference — the same argument whether the actor is a model or a junior engineer on their first week.
  • Whatever you present, you must be able to defend. If you cannot reconstruct the causal chain of an incident without asking the model, it is not your postmortem yet.
  • Generated code in a critical path needs tests its author understands. Not tests that pass — tests the author can explain when they fail at two in the morning.
  • Secrets and customer data do not go into a model that has not been approved to receive them. This one is legal before it is technical, and it is the rule most often broken by accident.

The reason to keep the two lines separate is that a personal boundary and a team boundary do different jobs. Mine keeps my judgment intact and is nobody else's business. The team's has to be arguable, because a rule you can argue with is a rule people follow, and a rule that is really just someone's taste produces compliance theatre and a shadow process. Written down, a colleague can tell me my rule about X is costing us Y and we can have that conversation. Unwritten, the same rule just makes me difficult to work with.

Where I changed my mind

A boundary list without this section is a manifesto, so here is what moved and why.

Code review. I was sure that having a model review a diff would be noise. It caught real things — not the architectural calls, which is where I expected it to be useless, but the boring ones: a missing null check, an error path that swallowed the cause, a test that asserted the mock instead of the behaviour. It is now part of my routine, as a first pass that makes my own review better than it would have been, with the rule that a clean model review means nothing and a flagged item is worth a look.

Test scaffolding. I held out because I thought generated tests would encode the implementation rather than the intent, and they often do. But a bad first draft of a test file is faster to fix than an empty file, and the cases it misses are easier to see than the cases you have not thought of. Moved.

Documentation and changelogs. I assumed the output would be bland and generic and would erode the writing. For internal docs whose job is to be accurate rather than good, it is fine, and the time saved goes into the parts where judgment is the product.

All three are in the file above — review_diff, scaffold_tests, draft_documentation — because that is the only way a boundary file stays true. A change of mind that does not update the file within the week turns the file into fiction, and a fictional boundary is worse than none, since it is the artefact you would have trusted.

Two things I have not moved and do not expect to: money, and anything with my name on it. And one honest cost: refusing has a price. Some of the things above take me longer than they take colleagues who delegate them, and I have decided that is a trade worth making — but it is a trade, not a moral high ground, and pretending otherwise would make this list useless to anyone deciding their own.

How to find your own line

Do not copy this list. It comes out of my risk tolerance, my role, and what I happen to be good at, and yours will differ in both directions — I am more conservative than some engineers on prose and less conservative than others on generated code, purely because of what I can verify quickly.

One variable moves your line faster than any other, and naming it explains most of the disagreement in this debate: the boundary is a function of verification cost, so it moves first and furthest where verification is mechanised. A refactor in a language with a real type system and a real test suite is cheap to check, which is exactly why I let a model do it. A proof in a dependently typed language is checked by the language itself — the thing that produced the term and the thing that checks it are separate, and the checker does not care where the term came from. That is not a difference of degree: where output is mechanically verifiable at near-zero marginal cost, the line should sit much further out than in a domain whose correctness is settled by reading carefully and hoping. With one honest caveat, and it is the same caveat as a test that asserts the wrong thing: a verified proof is a proof of the theorem you stated, and stating the right theorem is the part no checker helps with. The guarantee is only ever as strong as the specification.

Build yours from the two questions, and then do the thing that is easy to skip: write it down and look at it again in six months. A boundary that exists only as a feeling cannot be argued with, reviewed, or noticed drifting. And the drift is one-directional under pressure: verification gets a little faster, the next model is a little better, the deadline is real, and each individual exception is defensible. The file is what makes the tenth exception visible as a pattern.

Two things to check when you review it. Which of your refusals were about capability — those may have expired, and if you have not revisited them you are paying a tax for nothing. And which of your acceptances were about convenience rather than verification — those are the ones that quietly became load-bearing while you were not looking.

Summary

I use models aggressively for retrieval, for code I will read line by line, for refactors with a verifier, and for drafts I intend to rewrite. I do not let them compute numbers I have to be right about, hold the trigger for irreversible actions, produce anything I am accountable for, substitute for understanding something I cannot debug, make decisions whose value is the position rather than the option, or speak to people on my behalf about difficult things.

None of those refusals is a claim about what the model can do today. Each is a claim about verification cost, reversibility, accountability, and the slow compounding of judgment — four costs that a better model does not remove and, in the case of verification, can make worse by producing better-disguised mistakes.

The list has moved three times, and it will move again. What I want is for it to move because verification got cheaper, and not because I got used to it.