DEV Community

Cover image for Combating AI Slop in Network Doctor
Michael Placzek
Michael Placzek

Posted on AI-assisted

Combating AI Slop in Network Doctor

I use AI heavily while developing Network Doctor.

Claude Code, Codex, and local models have all helped me find bugs, write tests, investigate weird edge cases, review code, and improve documentation.

I am not interested in pretending otherwise.

But there is a problem.

AI can produce code that looks extremely convincing while being completely unnecessary, subtly wrong, overengineered, or based on a bug that never existed in the first place.

That is what is known as AI slop.

And as I have used AI more while building Network Doctor, I have become much more interested in a different question:

How do you get the speed of AI-assisted development without slowly filling your project with garbage?

I do not think the answer is "stop using AI."

I think the answer is to make the repository hostile to unverified work.

Rule 1: prove the bug exists

This is probably the most important rule in Network Doctor's repository guidelines:

Before changing behavior, verify the reported issue against the current HEAD.

That rule exists for humans, but it is especially useful for AI.

Give a coding agent a convincing bug report and it will often happily start fixing it.

That does not mean the bug is real.

Maybe the report is outdated.

Maybe another change already fixed it.

Maybe the reproduction depends on an assumption that is false.

Maybe the proposed fix is solving the wrong layer entirely.

So before I want a fix, I want evidence.

Reproduce it.

Write a focused test.

Show me the failure.

Then fix it.

A surprising number of "bugs" become much less convincing once you require that first step.

This also changes the way I prompt coding agents. Instead of:

Fix this bug.

I increasingly want something closer to:

Investigate this report against current HEAD. Do not change anything until you can reproduce it. If it is valid, create the smallest regression test that demonstrates the problem.

That one distinction removes a lot of garbage before it ever reaches the codebase.

Rule 2: AI does not get to declare itself correct

One of the easiest traps with coding agents is this:

  1. AI writes the code.
  2. AI reads the code.
  3. AI says the code looks correct.
  4. Done.

That is not verification.

Network Doctor has a local validation command:

./scripts/check
Enter fullscreen mode Exit fullscreen mode

It runs formatting checks, go vet, builds the project with the same CGO_ENABLED=0 constraint used by releases, cross-compiles for multiple operating systems, and runs the ordinary Go test suite.

For changes where concurrency matters, there is also:

./scripts/check --race
Enter fullscreen mode Exit fullscreen mode

CI goes considerably further.

There are integration tests, fuzz tests, security analysis, platform checks, packaging checks, documentation checks, and other repository invariants.

The important part is that these checks do not care how confident an AI model sounds.

The code either satisfies the contract or it does not.

Rule 3: turn important assumptions into executable rules

Documentation saying "please don't do this" is useful.

A test that fails when somebody does it is better.

Network Doctor has accumulated tests for things that would otherwise be very easy to accidentally break.

Some protect architecture.

Some protect packaging.

Some protect documentation.

Some protect stable behavior.

And one of my favorites is extremely small:

Network Doctor rejects em dashes in tracked text files.

There is an actual test for it.

Why?

Because I kept seeing them creep back into generated text, especially from AI-assisted writing. I did not want that style in the project, so instead of repeatedly asking models not to use them, I made the repository enforce the rule.

Now it does not matter whether the text came from me, Claude, Codex, a contributor, or something else.

If an em dash comes back, the test fails.

That is a tiny example, but the principle scales:

If you keep correcting the same AI mistake manually, consider turning the correction into an invariant.

The repository starts remembering the lesson for you.

Rule 4: protect the boring contracts

AI loves improving things.

Sometimes that is exactly the problem.

A mature CLI has behavior that should remain boring.

Argument shapes.

Exit codes.

JSON fields.

Labels.

Timeout behavior.

Platform boundaries.

Output semantics.

Once users or scripts depend on those things, an "improvement" can easily become a regression.

Network Doctor has tests around many of these contracts precisely because a locally reasonable change can have consequences somewhere completely different.

This matters even more with agents because they are very good at making a modification look internally consistent.

They can update the implementation, update the nearby test, update the comment, and produce a beautifully self-consistent change that still breaks the public contract.

The defense is having tests outside the immediate implementation that say:

No. This behavior belongs to the user now.

Rule 5: fuzz the places where cleverness gets dangerous

Some areas of Network Doctor deal with messy input:

  • targets and addresses
  • sanitization and redaction
  • DNS responses
  • generated network simulations

These are exactly the kinds of places where an AI-generated implementation can look elegant while missing one horrible input nobody thought about.

So Network Doctor fuzzes them.

For example, changes to target parsing have a dedicated fuzz target. Sanitization has one too.

I like fuzzing in an AI-heavy workflow because it changes the argument.

The model can tell me why its parser is correct.

I would rather throw thousands of ugly inputs at it.

Rule 6: replay reality

Unit tests are necessary, but networking has an annoying property:

Reality is much stranger than the test cases you invent.

Network Doctor has a field-case corpus containing recorded diagnostic situations. Its diagnosis engine can replay those snapshots without performing the original network probes.

That gives me another defense against plausible-looking changes.

A modification to diagnostic reasoning might pass the test the agent just wrote while changing how an old real-world incident is interpreted.

Replay catches that class of mistake.

This is something I want to expand over time.

Every strange real-world failure can become another permanent adversary for future code.

The project gets harder to fool.

Rule 7: use AI against AI

I also do not always use the same model for implementation and review.

Sometimes one agent investigates.

Another reviews the resulting diff.

Another looks specifically for edge cases.

Sometimes I use a local model.

Sometimes Claude Code or Codex catches something another model missed.

This is not because one model is magically trustworthy.

It is because disagreement is useful.

If one agent writes 200 lines and another immediately says, "This can be 30," that is worth investigating.

If one agent claims an edge case is impossible and another produces a reproduction, even better.

AI is very good at generating hypotheses.

So I try to use multiple passes to attack those hypotheses instead of treating the first answer as truth.

Rule 8: test the actual platforms

Network Doctor supports Linux, macOS, and Windows.

Cross-compilation catches a lot.

It does not catch everything.

So I also test releases on real machines.

That has included Fedora, Windows 11, and macOS systems.

This matters because AI knows what platform APIs usually do.

The machine gets the final vote.

Networking is especially good at exposing the difference between "this should work" and "this actually works."

Rule 9: keep changes small enough to understand

Another defense against slop is simple:

Do less at once.

When an AI agent produces a giant refactor, every additional changed behavior increases the amount of trust required to review it.

A focused change is much easier to challenge.

What was broken?

How was it reproduced?

What changed?

Which test proves it?

What unrelated behavior moved?

Ideally, the answer to the last question is "none."

I would much rather merge five boring changes that I understand than one spectacular AI-generated rewrite that requires faith.

The goal is not "AI-free" code

I sometimes see the AI coding discussion reduced to two positions:

AI writes everything now.

or

Real programmers do not use AI.

Neither is particularly useful to me.

I am building an open-source project largely by myself. AI lets me investigate more ideas, test more edge cases, review more code, and move faster than I otherwise could.

I absolutely want that leverage.

What I do not want is the corresponding temptation to lower the standard for what gets merged.

So I have slowly arrived at a different model:

AI can propose almost anything.

The repository decides what survives.

Reproduce first.

Test behavior instead of confidence.

Turn repeated mistakes into invariants.

Fuzz dangerous boundaries.

Replay real failures.

Cross-check with other models.

Run on real operating systems.

Keep the changes small.

And never confuse a very convincing explanation with evidence.

AI slop is not inevitable.

But preventing it takes more than writing "please produce high-quality code" in a prompt.

You have to build a development process that assumes plausible-looking garbage will occasionally appear, then make that garbage difficult to merge.

That is what I am trying to do with Network Doctor.

And somewhat ironically, AI has helped me build many of the defenses against AI itself.


Network Doctor is an open-source cross-platform network troubleshooting TUI written in Go. It diagnoses interface, DNS, TCP, TLS, HTTP, proxy, path-MTU, and other connectivity problems and tries to tell you where the failure actually is instead of dumping raw probe output.

GitHub: https://github.com/heymaikol/network-doctor

Website: https://networkdoctor.dev/

Top comments (0)