The 2026 engineering job is not “write more code.” It’s decide what the model is allowed to touch

Quinn Reed

Quinn Reed

August 28, 2026

The 2026 engineering job is not “write more code.” It’s decide what the model is allowed to touch

I used to be paid to produce lines. I am now paid to draw a fence. The model will write more lines than I will. If I do not decide what it is allowed to touch, it will touch the migration, the authz helper, and the public contract, and it will do it with passing tests. The 2026 job is not “write more code.” It is the allowlist: this directory, this kind of change, this environment — and not those.

The daily rhythm of drafts versus incidents is how AI changed the day and what did not budge. This is the policy inside the day: what I let the model reach.

An allowlist is a design doc

I write it down for a repo. Not a vibe. Generated UI in this app: yes, with a human on the CSS that ships. Generated SQL migrations: draft only, never applied without a name. Auth, billing, encryption, tenancy filters: the model may suggest, it may not land. Public API fields: human owns the add and the deprecation. Tests: yes, plus one the model did not write if the change can lose money or leak a tenant.

If I do not write it, juniors will let the model “just fix CI” and the fix will pin a package we cannot explain. Seniors will let it “just clean this up” and the cleanup will rename a column. The allowlist is how I stop both without pretending we do not use the tool.

What I always let it touch

Boilerplate that has a pattern in the repo. Mappers. Test fixtures. Docs that describe what already shipped. Exploratory spikes on a branch that cannot deploy. Commit message grammar. The fifth time I write the same adapter. Those are typing. Typing is not the job anymore. I will not perform typing to feel honest.

I let it touch unfamiliar files as a tour, then I verify. Tour is not a write. I used to conflate them. A generated edit in a file I have not read is not a tour. It is a write I did not own. The allowlist says: read first, or do not apply.

Clipboard checklist beside a keyboard on an office desk

What I never let it apply

Secrets and anything that looks like a secret. I have seen a model paste an example token that was too real. The allowlist is: it does not edit .env, it does not invent keys, it does not “helpfully” log the request body in auth.

Production config that changes blast radius: replica counts, timeouts that hide a hang, feature flags that default on. It may draft a YAML. A human changes the number. Numbers are the job.

Schema and contract. A new column is a year. A new JSON field on a public API is a mobile version. The model does not get to be casual there. Casual is its style. Casual is how we get three names for one fact.

Deletes. Generated deletes scare me more than generated adds. Adds we can find. Deletes we notice when a partner yells. The allowlist says: no delete of a path, a field, or a table without a human sentence that names the consumer.

Production config files with a do-not-touch note on a dark desk

What I let it draft and I apply

This is the messy middle, and it is most of the work. A migration it drafted, I rewrote the lock strategy. A tool-calling handler it drafted, I added the authz the advisor would not know. A refactor it drafted, I kept the public names. The job is the apply step: what I kept, what I threw away, what I narrowed. If I cannot say what I narrowed, I did not do the job. I accepted a completion.

I measure myself on narrowings now, not on lines. A manager who wants lines will hate this. I would rather hate the metric than ship the wide change.

How this changes reviews

I review the fence, not only the diff. Did this PR let the model touch a forbidden path. Did we get a drive-by in a file we did not open. I have started asking for a one-line “model touched:” in the description. If the list includes auth/ and the ticket was a button color, we talk. The talk is the job.

CI is not the fence. CI will pass a wide, polite change. The fence is a person who knows the directories that page. CODEOWNERS helps. It is not enough if the owner rubber-stamps. Rubber stamps are how the allowlist dies. I would rather a slow owner than a green build with a new tenant hole.

A week I still use as a template

On a payments repo the allowlist is printed in the README: model may draft handlers and tests; model may not edit ledger/, webhooks/verify, or anything under migrations/ except as a patch I will rewrite. On a marketing site the allowlist is wider. Same company, different blast radius. People who want one policy for every repo are asking for a slogan. Slogans get us a hole in the ledger because the blog policy leaked.

I revisit the list when we add a surface. New public API? Tighten. New internal admin? Tighten on authz, loosen on UI chrome. The job is the revisit, not the first draft of the list. First drafts rot. Rot is how the model ends up in the verify function again.

When an agent tool can apply patches unattended, the allowlist has to live in the tool config too — path denies, not only a wiki. A wiki is a hope. A deny is a fence. I still want the wiki so humans know why. I will not rely on the wiki when the tool is fast.

What I do when I break my own fence

I break it. Tired, late, “just this once.” The once is always a config default or a migration lock. I write it down in the next standup: I let the model touch X, here is what I should have narrowed. That confession is not theater. It trains the team that the fence is real enough to admit crossing. If I hide the cross, they will hide theirs. Then we have no fence. We have a story about a fence.

I also break it upward: I sometimes forbid too much and the team stops using the tool on safe work. Then they type the mapper by hand and call it craft. I loosen the mapper. I do not loosen the ledger. Tight everywhere is how the policy dies of contempt.

How this changes staffing

I hire for people who can say no to a pretty diff. I train juniors on the allowlist in week one, not on a framework tour. I do not hire for “uses AI.” Everyone uses AI. I hire for “knows where AI stops.” That sentence is now the job description I wish I had written in 2024.

I will not staff a team whose only skill is prompting. Prompting without a fence is how you get more code and a worse system. The 2026 job is the fence. Write more code is what the model is for. Decide what it may touch is what I still get paid for, and what I will argue for when someone wants to replace the fence with a faster accept rate. Accept rate is not a job. It is how the job disappears, along with the system the job was keeping coherent.

If you are writing a job post, take “10x with Copilot” out. Put “can define and defend an allowlist for generated changes on a surface that pages.” If that sentence feels too long, the job is still that long. We just used to hide it inside “strong code review.” Review is the fence after the fact. The allowlist is the fence before the model runs. I want both. I will not staff only the after. The after is how we find the hole. The before is how we have fewer holes and still use the tool. That is the job I will keep hiring for, even when the tool writes almost every line I used to type. Especially then.

More articles for you