Heartbyte

Heartbyte

AI & Industry · · 9 min read

AI Slop: We Named It After Pig Food for a Reason

A 1,400-line pull request lands twenty minutes after the ticket. It compiles, CI is green, and nobody, including the author, can tell you why it works. That's slop, and it turns into technical debt that nobody ever decided to take on.

H

Heartbyte Team

Engineering & Strategy

AI Slop: We Named It After Pig Food for a Reason

You know what the pull request is before you open it. 1,400 lines across 23 files, raised twenty minutes after the ticket was assigned. The description is three bullets that restate the title. CI is green. Somewhere in that diff is the actual change, maybe forty lines of it, and the rest is renames, reformatting, defensive null checks and a helper class you've never needed.

There's a word for this now, and it arrived fast. Slop. It started out describing AI-written articles and six-fingered stock images, then engineers borrowed it within months, because we all recognised it. Slop is in our repos, our test suites, our tickets and our docs. It's worth knowing where the word came from, because the origin tells you exactly what someone means when they use it on your branch.

"Slop compiles. That's the whole problem. A syntax error costs you a minute. Slop you maintain for three years."

The word is older than the internet

Slop is a farm word. It's the watery leftovers from the kitchen, peelings, gravy, stale bread and dishwater, mixed in a bucket and tipped into a trough for the pigs. It isn't poison. The pigs eat it and get fat. But nobody cooks slop. There's no recipe, no tasting, no plating. You tip the bucket and walk away.

The same root gives us "sloppy" for careless work and "slopped together" for something thrown at a wall. English has carried that sense for centuries: cheap, watery, made without attention, produced in volume for something that won't complain.

That last part is why it fits our industry so well. A code review queue doesn't complain. Neither does a wiki, a Jira board or a repo. You can pour a hundred thousand lines into all four and nothing pushes back until a human opens one of them, and by then it's merged.

Why "spam" wasn't the right word

We already had a word for junk. Spam has done the job since the nineties, and when the AI wave hit a lot of people reached for it. It didn't fit, which is why "slop" got pitched as the AI-era counterpart and stuck.

The difference is where it comes from. Spam arrives from a stranger, uninvited, usually selling something, and a filter catches most of it before you see it. Slop comes through your own pipeline. Your teammate opened the PR. Your own branch has the generated migration in it. The docs came from the repo. It's already inside the trust boundary, so there's no filter to write. The only filter is a reviewer, and the reviewer has four other PRs open and a standup in ten minutes.

What slop looks like in a real codebase

Forget the internet version for a moment. This is the version that shows up in a sprint, and every engineer reading this has reviewed at least three of them.

Slop, as it appears in a diff

  • A 1,400-line PR for a 40-line change, with renames and reformatting mixed in so the real edit is impossible to find.
  • Tests that mock the thing under test and then assert the mock got called. Green tick, nothing covered.
  • A third HTTP client, a second date helper, another validation layer, because nobody searched the repo before generating.
  • try/catch around everything, logging "something went wrong" and swallowing the one exception you needed to see.
  • Magic numbers with confident names. Retries set to 3, TTL set to 300, timeout at 30 seconds, and no reason recorded anywhere.
  • Docblocks that restate the method name in a full sentence, plus a README describing endpoints that were never built.
  • Null checks for states that can't happen, which quietly hide the states that can.

A generated test that tests nothing

public function test_creates_invoice(): void
{
    $service = Mockery::mock(InvoiceService::class);
    $service->shouldReceive('create')->once()->andReturn(new Invoice);

    $service->create($this->payload);   // calls the mock, not the code

    $this->assertTrue(true);
}

Passes forever. Would keep passing if you deleted the entire invoice service.

Green CI used to mean something

A passing build was never proof of correctness, but it was weak evidence that a person had thought about the change. Someone wrote the test, so someone had an opinion about what the code should do.

That link is broken now. When the same tool writes the implementation and the tests from the same misunderstanding of the requirement, both sides of the check agree with each other and neither of them agrees with reality. The suite passes because it was generated from the code, not from the behaviour anybody asked for. We've written about the shipping version of this problem before: it looks like it works, so they commit. Slop is that same failure spread across the whole repo instead of one feature.

Slop is technical debt nobody agreed to take on

Real technical debt is a decision. You knew the clean way, you took the shortcut because the deadline was Friday, and you left a trail: a comment, a ticket, a line in an ADR, a TODO with a name on it. Debt like that is payable. You can see the shape of the loan, work out what it's costing you, and pay it down when the interest gets annoying. We've argued elsewhere that unmanaged debt is a business problem, not a coding style problem, and that's still true.

Slop has no decision inside it. Nobody chose the retry count. Nobody weighed the extra service against reusing the one you have. There's no reasoning to find because none was ever formed, so you can't refactor toward the original intent. You either reverse-engineer intent out of behaviour, which is slow and often wrong, or you delete it and wait to see what breaks in production.

Interest still accrues either way. Every future change has to work around code that no living engineer understands, and every estimate on that module comes back higher because nobody can tell you what depends on what.

"A shortcut somebody chose has terms you can read. Slop has no author, no reasoning, and no safe way to tell what you're allowed to delete."

The arithmetic of review

Generating that PR took twenty minutes. Reviewing it properly, actually reading 1,400 lines, checking the tests assert something real, verifying the migration against the live schema, takes most of two days. Nobody has two days. So it becomes a scan, an LGTM and a merge.

The work didn't disappear, it moved. The author saved an afternoon and spent a week of other people's attention: the reviewer, the next developer in that file, and whoever gets paged when the swallowed exception matters. Reviewing carefully is slower, more tiring and much harder to measure than producing, and nobody gets promoted for the slop they caught.

This is a big part of why "we're three times faster with AI" almost never shows up in delivery. Typing was never the constraint. Code got cheap and software didn't, and coding was always the easy part. Speeding up the easy part while dumping the hard part on the next person in line just relocates the cost.

Who actually pays

  • The reviewer, handed 1,400 lines instead of 40 and no credit for reading them.
  • The next engineer in that file, who has to work out what the code was meant to do before changing a line of it.
  • Whoever is on call, debugging a stack trace that got caught, logged as a warning and thrown away.
  • The business, paying once to generate it and again in six months when a two-day feature is quoted at three weeks.

How it compounds in a system

One sloppy PR is annoying. A quarter of them changes the shape of the codebase. You end up with four ways to make an HTTP call, three date utilities, two competing validation styles and no convention anyone can point to. Now every new feature touches three of the four, and every developer has to guess which one is the blessed path. There isn't one.

Then come the leftovers. Feature flags nobody turned off, tables nothing writes to, a queue worker consuming a topic that stopped existing in March, config keys read by no code at all. All of it looks deliberate, so nobody dares remove it, and the safest move is always to add another layer on top.

The loop that should really bother you is what this does to the AI itself. These tools work from the context you give them, and the biggest source of context is your existing code. A repo full of slop is a prompt full of slop. Ask for a new integration and the model reads your three HTTP clients, picks the worst one and gives you a fourth in the same style. Your codebase gets harder for the AI to work in, which is the exact opposite of what you bought it for. That's the honest end state of shipping code nobody understands: eventually even the machine can't help you.

The symptoms are measurable

You can see slop in the numbers before anyone admits it out loud. Average PR size climbs. Minutes of review per hundred lines falls off a cliff. Change failure rate goes up while commit counts look healthy. Bugs get reopened because the first fix addressed a symptom. Onboarding takes longer because there's no pattern to teach. And small requests start getting large estimates, because nobody can say what a change will break.

Meanwhile the velocity chart looks great. That's the part that keeps this alive in management reporting for a year or more before the delivery pain gets loud enough to trace back.

"Slop doesn't get you caught in code review. It gets you rewritten in two years, by people cursing a decision nobody made."

Using AI hard without shipping slop

None of this is an argument for typing everything by hand. We'd be poor liars if we made it, because AI is all through how we build. The line has nothing to do with how much AI you use. What matters is whether an engineer owns the diff when it leaves the branch.

The rules we hold ourselves to:

  • The author walks the diff. Every hunk, out loud, without opening a chat window. If they can't explain why a line exists, the line goes.
  • Cap the PR size. A 1,400-line review is theatre no matter who wrote the code. Split it, or split the ticket.
  • Tests go red first. If a generated test never failed, you've proven nothing about the code, only that the file parses.
  • Search the repo before you generate. Most slop is a duplicate of something that already exists two folders away.
  • Delete generously. Generated code you didn't need isn't free. It's surface area you'll be maintaining in 2029.
  • Write down the real decisions. Why the retry is 3, why this service exists, why you took the shortcut. A recorded reason is what turns slop into debt you can actually repay.
  • Make review count for something. If catching problems is invisible work on your team, you've already decided slop is acceptable.

There's a one-question version of all that. Before you request review, ask whether you could sit with the on-call engineer at 3am and explain any line in the diff. If yes, ship it. If the honest answer is "I hope nobody looks too closely," you've produced slop, and the AI didn't do that part of it, you did.

The honest version

The word stuck because it's accurate, and because it isn't really about AI. Copy-paste code, padded pull requests and comments that explain nothing have been in our repos since long before any of this. AI didn't invent the habit. It removed the last bit of friction that limited how much of it one developer could produce in an afternoon.

So the standard has to move with it. When code was expensive to write, the fact that it existed was weak evidence somebody had thought about it. That signal is gone and it isn't coming back. What's left is whether an engineer read it, understands it, and will answer for it when it breaks at 3am. That's the difference between a system and a trough, and it always was.

"Anyone can generate 1,400 lines now. Being the engineer who can defend forty of them is the rare part."

Inherited a codebase nobody can explain?

We use AI heavily and a human still owns every diff that leaves the branch. If you're maintaining a system full of code nobody decided on, we can help you work out what's worth keeping.

Talk to Us About Your Project
H

Heartbyte Team

Heartbyte is a bespoke software development company based in Malaysia. We build and maintain web, mobile and custom systems for ambitious businesses, using AI heavily and keeping a human on the hook for every line that ships.

Free Consultation

Ready to Build Something Great?

Get a free consultation with our team — no pressure, no obligations. Just honest advice on how we can help your business grow with bespoke software built the right way.