Skip to main content
Back to writing

This record updates the project judgement / Stop That Shit

Codex Exported One File, Then Added an Unused SHA-256

An unused .sha256 file shows how coding-agent overengineering starts—and how consumers, next actions, and the Stop Ladder decide whether work belongs in the task.

In this record06
  1. 01A hash needs a consumer
  2. 02Overengineering rarely begins with a huge refactor
  3. 03Four questions create a stopping condition
  4. 04Bad Cases need matching Good Cases
  5. 05The Skill judges; the Guard checks visible actions
  6. 06The next time .sha256 appears, do not delete it on sight

I asked for one output file.

Codex exported it, then placed a .sha256 file beside it. The result looked professional: integrity checking was present and the workflow appeared more reliable. But no later command read the digest. Removing it would not break the task. Keeping it did not save a single step.

This kind of extra work is difficult to stop because it is not obviously wrong. It nearly always comes with a plausible engineering reason.

SHA-256 can verify a file. A compatibility layer can support an older version. A full test suite can add confidence. A migration framework can prepare for future data. Each argument can be valid on its own; together, they can quietly replace the task the user actually requested.

A hash needs a consumer

I now start with two questions when a digest appears:

  1. Who reads it?
  2. What changes after they read it?

A release checksum has a clear consumer. A downloader or release verifier reads the digest and rejects a mismatch. Hashing a large file can also be useful when an unchanged digest lets the system skip an expensive reread.

In both cases, the hash replaces a more expensive operation or controls the next decision.

Now consider an agent that hashes every row in two CSV files and still compares every row afterwards. The extra calculation replaces nothing. The workflow does not branch on the digest. The hashes make the process look stricter without doing any work.

The question is not whether hashing is good. The question is whether this hash has a job in the current task.

Overengineering rarely begins with a huge refactor

Task growth usually has no single dramatic moment. It arrives through a sequence of small, defensible-looking choices.

  • The user asks for one config fix; the agent extracts a general configuration interface.
  • The repository has one implementation; the agent adds a compatibility adapter.
  • The user needs a local tool; the agent introduces a cloud-sync feature flag.
  • The change touches one module; the agent runs the complete test matrix by default.
  • The user asks for review; the agent edits files to “verify” its proposed fix.

Each step can be presented as caution. The problem is that it answers “what might happen later?” rather than “what makes the current result complete?”

Agents are also very good at turning possibilities into reasons. A line such as “avoid overengineering” still leaves the agent free to explain why this abstraction, compatibility layer, or full-suite run is necessary.

The instruction has no checkable stopping condition.

Four questions create a stopping condition

I turned that decision into Stop That Shit. The memorable name matters less than the four-question Stop Ladder inside it:

Did the user request it?
Is it necessary to complete the current result?
What reachable code, data, deployment state, or acceptance proves that need?
Where would the current task fail if we omitted it?

These questions do not remove every piece of extra work. They pull “necessary” away from intuition and back toward current evidence.

If a shared interface changes, update the affected callers. If production contains old data, keep the migration. If a release pipeline consumes a checksum, generate it. The same rule applies to wider tests: expand coverage because a reachable contract or regression path requires it, not because “full suite” sounds responsible.

On the other side, if the user did not request an action, no current consumer or reachable evidence needs it, and acceptance stays unchanged without it, “might help later” should not automatically become implementation work.

Bad Cases need matching Good Cases

A library of overengineering failures can push a rule toward the opposite mistake: stop whenever it sees hash, migration, or cache.

Stop That Shit therefore pairs a Bad Case with a Good Case that changes one decisive fact.

BAD CASE
Compare two CSV files.
The agent hashes every row and still compares every row.
No operation is removed. Stop.
 
GOOD CASE
Generate the release artifact checksum.
The release verifier reads it and rejects a mismatch.
The current release requires it. Keep it.

Both cases contain SHA-256. The conclusions are opposite because the consumer and next action are different.

That is also why Stop That Shit is not a “fewer lines are always better” tool. A tiny diff can leave a task incomplete. A broad change can be the necessary consequence of a shared-contract update. The goal is not to do the least work imaginable. It is to do the work the request and result actually need.

The Skill judges; the Guard checks visible actions

The public 0.1.0 release has two layers.

The Skill handles semantic judgment: whether the task is review or change, whether additional work has evidence, and which callers, fixtures, and tests are necessary consequences.

The Guard handles actions that a Host Hook can identify clearly, including file writes during read-only review, unapproved dependencies, subagent budget overages, and identifiable new hash actions. When a release really needs a checksum, the user can grant that authority explicitly:

$stop-that-shit change hash=allow -- Generate the checksum required by the release pipeline.

The Guard does not declare a migration or cache unnecessary merely because it sees the word. It is also not a security sandbox. It handles task authority on supported Hook paths; the Host's sandbox and approval system remain responsible for security isolation.

The next time .sha256 appears, do not delete it on sight

Follow the workflow instead.

Who reads it? What changes when the value differs? Which operation does it replace? Where does current acceptance fail without it?

If the answers are concrete, keep the hash. If the only answer is “it might help later” or “it looks more complete,” the .sha256 file is already a useful stopping signal.