将AI代码转换为债务的五个沉默假设

2026年9月4日1 次浏览来源:Dev.to阅读原文

正文保留英文原文(机翻易破坏代码与排版),标题/摘要已提供中文

Generated code looks cheap until the assumptions land.

You own every invented config, schema, and side effect.

I now treat silent model assumptions as merge blockers.

Did the model ask about your auth scheme?

Did it confirm the table names you actually have?

If not, you did not get a patch.

You got a guess.

This is a catalog, not a pep talk.

Each anti-pattern has a symptom, a root cause, and a replacement.

Then I give you a constraint file and a gate script you can run on a staged diff.

Why this catalog exists Agents fill gaps because that is their job.

Gap filling helps during a short spike.

It becomes poison inside a brownfield service.

Cheap tokens make the guesses faster.

They do not make the guesses true.

Technical debt arrives as confident Python.

I keep a constraints file next to the repo.

The model must read it before it writes.

A small gate fails the patch when it invents facts.

The catalog

1.

Phantom Config Symptom The patch reads on boot.

Your secrets manager has never heard of it.

Staging dies inside .

Root cause The model completed a typical tutorial shape.

Tutorials always hide one missing env var.

Nobody listed the real allowlist.

Replacement Publish an env allowlist in the repo.

Reject new keys unless a human adds them.

Ask yourself: who named that variable?

If the answer is "the model," delete it.

2.

Unapproved Dependency Symptom gains or .

Sometimes the name does not even exist.

CI installs it, or CI cannot install it.

Root cause The model optimized for a blog-post stack.

It did not read your lockfile.

Convenience beat your supply-chain rules.

Replacement Diff imports against the lockfile.

Unknown import roots fail the gate.

Humans add libraries on purpose.

Would you merge a mystery wheel from the internet?

Then do not merge a mystery import either.

3.

Happy-Path Auth Symptom The new endpoint has no auth decorator.

Or it checks a header the gateway never sets.

Or it trusts from the JSON body.

Root cause Demos skip auth to keep the snippet small.

The model learned those demos.

Your threat model never traveled in the prompt.

Replacement State the auth contract in constraints.

Every HTTP handler must match one pattern.

No pattern, no merge.

Can an anonymous caller hit this route?

If you cannot answer, the patch is incomplete.

4.

Invented Schema Symptom The query selects .

Your table has .

Or the patch adds JSON nobody migrated.

Root cause Language models remember popular schemas.

They do not remember yours.

A plausible column is still a lie.

Replacement Check identifiers against a schema dump.

I keep generated from migrations.

Unknown columns fail the same way unknown env fails.

Did you run the migration, or did the model imagine it?

Imagination is not a migration.

5.

Invisible Side Effect Symptom The helper writes .

It shells out to .

It logs access tokens at INFO.

Root cause The model "finished" the function.

Finishing is not the same as isolating.

Side effects feel like completeness.

Replacement Ban whole families of calls in generated diffs.

Allow them only in named modules.

Keep the blast radius tiny.

If a spike needs , put it in .

Do not let it ride into .

A worked failing diff Here is a compact patch I would reject on sight.

It looks helpful.

It is five anti-patterns in one function.

What did the model invent?

A secret name.

A new HTTP client.

Identity from the body.

A column you do not have.

A world-readable temp log.

The gate below should print failures, not a green check.

If it passes this diff, your allowlists are too wide.

The artifact: an assumption gate Here is a small checker you can copy.

It is a heuristic, not a full program analysis.

Label it as a merge gate, not a proof.

Save at the repo root.

Save this script as .

Feed it a unified diff from the model.

Run it like this: No staged diff?

Pipe the model output through .

The gate still sees every added line.

That is enough to catch the five patterns above.

Expected output on the refunds example: If that list is empty, the gate is not wired.

Fix the constraints before you blame the model.

Decision table If the diff...

Treat it as Human action Adds an env key Phantom config Add to allowlist or delete Adds an import root Unapproved dependency Lockfile first, then code Adds a route, no decorator Happy-path auth Wrap or reject Uses unknown Invented schema Dump schema, then rewrite Touches or Invisible side effect Move to or drop Print this table in the PR template.

Reviewers stop arguing taste.

They argue facts.

Prompt the model against the contract Do not ask for "a refunds endpoint." Ask for a diff that obeys the file.

Keep the prompt boring and strict.

Then paste the gate failures back.

The second turn should shrink, not sprawl.

If it sprawls, the model is still filling gaps.

Stop and edit by hand.

Where a free model lab fits I want the model to propose code.

I do not want it to propose reality.

Those are different jobs.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

I run the generate-then-gate loop on MonkeyCode's free models and free server.

The server is a lab for the checker, not a factory for production traffic.

The loop is boring on purpose: Paste the constraints file into the prompt.

Ask for a unified diff, not a novel.

Save the diff.

Run .

Send failures back as the next prompt.

Merge only when the gate is quiet.

Free model access makes the retries cheap.

The gate makes the retries honest.

Without the gate, cheap retries just multiply debt.

Limitations This gate reads text.

It does not run tests.

It will miss a renamed import alias.

It will miss SQL built with f-strings.

Object attributes look like columns. can false-positive when is real.

Keep the schema file on table names, not on instance names.

Review those hits instead of auto-fixing them.

It can also nag on legitimate new columns.

That is the point of a human allowlist.

A noisy fail is better than a silent schema lie.

Do not call this a security audit.

Do not skip unit tests because the gate passed.

Do not point the lab server at production databases.

Regex will rot as your framework changes.

Budget an hour when you upgrade the web layer.

Update the decorator name.

Update the import roots.

Who should not use this Skip this if you have no lockfile.

Skip this if you cannot dump schema.

Skip this if the repo is a throwaway spike.

Also skip it for generated front-end CSS churn.

The patterns above target service code.

A linter war on class names helps nobody.

If you cannot review the allowlists, stop.

An outdated allowlist becomes a rubber stamp.

Rubber stamps are how assumptions sneak back.

What I actually want from the model I want candidate diffs.

I want them small.

I want every new fact to be named.

Ask the model: which constraints did you use?

Ask it: which facts did you invent anyway?

If it cannot list them, distrust the patch.

Cheap code is a throughput trick.

Assumption control is the actual engineering.

Keep the catalog next to the gate, not in a wiki.

分享