A reference, not a narrative — for jumping into mid-task when something
feels like it might be one of these. Each entry: what it looks like, why
it's specifically dangerous for an editor without persistent memory of its
own past sessions, the mechanism that closes it off, and the real incident
that earned it a place here. See repoman-010-why.md for the design
principles these all trace back to.
Looks like: a search-and-replace, or a regex, applied identically to every occurrence of a string — without checking whether all of those occurrences are actually the same kind of thing. The same text can be a real identifier in one place, a string literal passed to something else entirely in another, a comment, a table cell, or plain prose — and a single substitution rule that's correct for one is often silently wrong for the rest.
Why it's dangerous here specifically: an agent doesn't have the peripheral, half-conscious sense a human maintainer builds up for "this file has SQL strings mixed with Go identifiers, be careful" — that awareness has to be made explicit and mechanical, or it isn't there at all.
Prevented by: roles classifies every occurrence by syntactic role
before any substitution is allowed to proceed; str_replace_extended's own
delimiter-integrity check refuses outright if the occurrences it's about to
touch don't all share one role, printing the real census so the split can
be done properly instead of forced through with --force-roles on a
guess.
Real incident: this is the general failure mode roles was built to
close off entirely, not a single incident — it's the class of bug that
"classify before you substitute" as a working-agreement rule exists to
prevent by hand, mechanized so it doesn't depend on remembering to apply
the rule every time.
Looks like: constructing the text to search for from memory or from context earlier in a conversation, rather than from a fresh, verified read of the file as it currently exists — and then having that anchor either not match (best case) or match somewhere unintended (worse case), or match correctly at the moment of writing but the file having changed underneath by the time the edit actually applies.
Prevented by: ed.py find returns a handle carrying the exact byte
span and a content hash; apply re-verifies that hash against the file's
current state and refuses — "stale handle, re-run find" — rather than
writing into a position whose surrounding content it can no longer vouch
for. Anchors are never hand-typed from memory; they always come from a
fresh find.
Real incident: anchors built from memory of what the text should say
are the documented root cause behind requiring find first, always — real,
confirmed damage happened more than once from exactly this: an anchor
consuming a function signature without restoring it, silently orphaning the
function body until a build finally failed on it; a separate incident
leaving a function's own closing braces dangling mid-file, caught only
because the file happened to be re-viewed afterward, not because anything
in the toolchain flagged it at the time.
Looks like: a guard or release step's output piped through head,
tail, or grep before its exit status is checked — the pipeline as a
whole reports success (or just doesn't get checked at all) even though the
step it's wrapping actually failed.
Why it's dangerous here specifically: this is the failure mode that produces the most convincing false record — a changelog entry describing a release step that never actually ran cleanly, a version bump applied on top of a build that didn't pass. It doesn't look like a failure. It looks like success, right up until someone tries to rely on what it claimed.
Prevented by: never piping an orchestrator's or a guard's own output
through anything before its exit code has been checked — the log exists for
reading afterward, the exit code is the only thing that gets trusted in the
moment. Where a guarded step feeds later steps, the whole sequence from
guard to final artifact runs as a single && chain, not as
newline-separated commands that execute regardless of what came before.
Real incident: documented as a recurring defect three separate times in this project's own history before the rule was written down explicitly — recurring specifically because debugging momentum is exactly the moment this kind of discipline is most likely to be forgotten and most needed.
Looks like: a test that exists, is even correctly specified, and simply never runs as part of the normal test invocation — gated behind a build tag, an environment variable, specific hardware, or deferred to local execution — so its own correctness (does the invariant it checks actually hold, does the code it's testing even still exist) goes unverified indefinitely.
Prevented by: every dormant guard is listed in a table with its gating condition and a last-exercised date and environment. The release gate checks that every entry has been exercised since the last tag, or that its skip is explicitly recorded — never silently assumed current because it's merely present in the codebase.
Real incident: the canonical case — a race guard shipped with its invariant precisely specified, and the invariant it encoded turned out never to have actually been implemented. Nobody caught it, because the guard sat behind a build tag the default suite never touched. Discovered a month later, the first time anyone actually ran it, and it failed instantly. A guard's specification and its execution record are different facts; only the second is evidence, and coverage of one guard is never inferred from another guard's recorded campaign.
Looks like: the register, the tracking document, or any other file a tool is supposed to keep consistent developing an internal inconsistency because of an operation the tool itself performed — not external tampering, a bug in the maintenance logic.
Prevented by: register check verifies the status table and the
per-item detail sections actually agree with each other, structurally —
not just that the file parses. This check is exercised against a
deliberately-broken fixture, not only well-formed data, specifically so it
proves it catches a real mismatch rather than merely passing when nothing
is wrong.
Real incident: register.py close's own row-capture regex once matched
only five cells of a six-cell table row, orphaning the status row on
closure — found while closing the very item that had been filed to track a
different, unrelated bug. The tool caught its own defect on its first real
use, which is the entire reason check gets run against adversarial
fixtures now rather than trusted on the strength of its own design.
Looks like: a changelog entry, a comment, or a register closure stating that something was done — a directory removed, a bug fixed — when the actual change never made it into the committed state, or got silently reverted by something later.
Why it's dangerous here specifically: a future session (with no memory of writing that changelog entry) has every reason to trust it. There's nothing internally inconsistent about a false "done" claim; it only shows up when someone happens to check the actual state against what was claimed.
Prevented by: the closure procedure requires a verification record —
what ran, where, when — not just a status flip; register check and the
release gate both verify the register's own table against its detail
sections rather than trusting either in isolation.
Real incident: a dead, actively-misleading duplicate directory was
documented as removed in one changelog entry, complete with an explanation
of how it had been silently corrupting an earlier version of selftest.
It was still sitting on disk, unchanged, several releases later — the
documented fix had simply never been committed. Found only because a later
packaging pass happened to notice it was still there. The Go translation of
this same project independently turned up the identical pattern in its own
right: a .gitignore the changelog claimed was added in a specific release
was absent from that release's actual committed tree.
Looks like: a release archive step sweeping in a file it generates itself — a manifest, a checksum file, a release log — because an earlier, now-stale copy of that same generated file happens to already be sitting in the source tree when the archive step runs, producing a duplicate or corrupted entry in the output.
Prevented by: self-generated packaging output (manifest files, release logs, state files, checkpoint zips) is excluded from archive sources by name, not merely expected to be absent.
Real incident: a release archive builtin wrote a duplicate manifest entry specifically because a stale manifest from an earlier checkpoint session was still sitting at the archive root in a downstream repository's working tree — a leftover from a prior extraction, unrelated to the release currently running, that nonetheless got swept in as an ordinary source file and then collided with the archiver's own freshly-generated copy of the same file.
Looks like: a classifier that tracks "am I inside a string / comment / code block" by counting delimiter-like characters across the whole file, rather than genuinely tracking lexical state — so a delimiter character that appears for an unrelated reason (inside a different kind of string, inside a comment, as a literal example) throws off the count without actually opening or closing anything, silently misclassifying everything after it.
Prevented by: replacing naive counts with real stateful scans that track comments, strings, and other constructs explicitly, and — critically — checking the result against an independent, external ground truth (a real compiler's or parser's own behavior, or a language's actual specification) rather than trusting that the logic looks right on inspection.
Real incident: this exact shape of bug turned up five separate times
across the role classifiers on direct audit — a Go classifier
misclassifying its own source after an unrelated backtick or block-comment
marker earlier in the file threw off a whole-file count; a Markdown fence
tracker that didn't account for delimiter length, so a shorter marker
inside a longer-delimited fence incorrectly closed it; the same tracker's
inline-code detection breaking on a single stray, unmatched backtick;
Python's triple-quote handling reading an escaped quote as a genuine
closing delimiter one character early; YAML's comment detection treating
any bare # as a comment regardless of what preceded it. All five were
confirmed against something outside the tool itself before being trusted
as real, and fixed identically everywhere the same logic was duplicated.
Looks like: a concurrency guard passing cleanly inside a sandboxed test environment, and that pass being treated as evidence the underlying race condition doesn't exist.
Why it's dangerous here specifically: a sandbox without true multi-core parallelism structurally cannot exercise most races — a clean pass there proves the code ran, not that it's safe, and the two are easy to conflate under time pressure.
Prevented by: stress tests requiring genuine multi-core parallelism are explicitly deferred to the human running real hardware, with the exact invocation to run; a sandbox pass of a concurrency test is never accepted as the evidence a dormant guard's last-exercised record requires.
Real incident: a codebase-precedent race condition survived months of routine single-core sandbox testing without ever manifesting, standing as the concrete reminder that reasoning about concurrency correctness — or a clean CI run in an environment that can't actually stress it — is not the same as verifying it.
Looks like: a ported or translated version of a tool quietly drifting from the behavior of the original it was translated from — not because anyone changed it on purpose, but because a bug in one side was never checked against the other, so neither the port nor the original is actually being validated against anything beyond its own internal logic.
Prevented by: the two implementations are tested against each other directly and continuously — identical fixtures run through both, output diffed byte-for-byte — rather than each being trusted independently on the strength of its own test suite passing. A shared bug found this way gets fixed in both together, deliberately, specifically because fixing only one side would widen the gap rather than close it.
Real incident: a Go translation of this project accumulated several
real divergences from the Python original before being checked this way —
subcommands that crashed on --help instead of showing usage where the
original didn't, an item-range format that differed for a single-item edge
case. None of these were caught by either side's own test suite passing;
all of them surfaced only once the two were run side by side on purpose.