DEV Community

John
John

Posted on Originally published at hexisteme.github.io

Your Dead-Code Detector Found Six Orphan Constants. None of Them Were Dead.

Originally published on hexisteme notes.

An audit flagged six constants in my codebase as orphans: defined in exactly one file,
referenced from nowhere outside it.
That's the standard shape of dead code, and the standard
next step is to delete it.

I opened all six. Not one was dead. Every one of them was a specification — a word-list the
code was supposed to obey — sitting next to code that had written the same values out again as
string literals. Nothing joined the two.

Two of the six were letting typos walk straight through a review gate.

The shape

Here's the smallest one. A dataclass carries a confidence field, and there's a constant
declaring what values are legal:

VALID_CONFIDENCE = ("verified", "unverified", "not_found")
Enter fullscreen mode Exit fullscreen mode

And here's the method that decides whether a piece of evidence can be published on a page:

def is_usable(self) -> bool:
    if self.confidence == "not_found":
        return False
    if not self.claim.strip() or not self.quote.strip():
        return False
    return self.source_url.startswith(("http://", "https://"))
Enter fullscreen mode Exit fullscreen mode

VALID_CONFIDENCE has zero references. is_usable re-types one of its three members as a
literal. The constant is the spec; the method is the implementation; and there is no
line of code anywhere that makes the implementation answer to the spec.

Now note where the value comes from. It's parsed out of a config file:

confidence=str(item.get("confidence", "unverified"))
Enter fullscreen mode Exit fullscreen mode

str(). No validation. So a human types notfound instead of not_found — one character —
and the evidence sails through is_usable(), joins the supporting-evidence set, and a
downstream check that hunts for unsupported numeric claims now treats every number in that
evidence as sourced.

The whole point of not_found is to mark evidence you couldn't confirm. A typo in that word
turns it into confirmed evidence.

Measured, before the fix:

confidence is_usable()
verified True
unverified True
not_found False
notfound True
NOT_FOUND True
verifed True
"" True

The worse one

The same shape, in a manual-review gate. Checklist items carry answered_by, which is either
"human" or "agent_by_delegation". Delegated answers get extra scrutiny — they must cite a
basis, they're checked against the current delegation scope, and they're revoked when the
delegation is withdrawn. Human answers get none of that, correctly: a person already looked.

The filter was one line:

for item in manual_checklist:
    if item.get("answered_by") != MANUAL_ANSWER_DELEGATED:
        continue          # not delegated → not our business
    ...
Enter fullscreen mode Exit fullscreen mode

That line routes two completely different states through the same door: "a human answered"
(legitimately outside this check) and "we don't know who answered" (the least trustworthy
state there is).

So agent-by-delegation with a hyphen, or agent_by_delegation with a trailing space, or
just agent — each of those skips the basis requirement, skips the scope check, skips
revocation, and keeps answer: true.

A typo didn't weaken the delegation. It promoted a machine's answer to a human's answer.

MANUAL_ANSWER_HUMAN was one of my six orphans. Of course it was — the code never needed to
name the human case, because "not delegated" silently meant it.

Why the detector was right and wrong at once

"Zero references outside the defining file" is a real measurement. My mistake was reading it
as a verdict on the constant, when it's actually a measurement of the joint.

Two things produce that reading:

  1. Nothing uses this value. → Dead code. Delete it.
  2. Something should be checking against this value and isn't. → Missing enforcement.

They're indistinguishable from the reference count alone, and case 2 is the dangerous one,
because the constant sitting there in the file looks like the rule is being enforced. It
documents an invariant that nothing maintains. A reader — including me, six months later —
takes it as a guarantee.

The reference count doesn't tell you which case you're in. You have to open the file.

I've hit this before from the other side: I once wrote a rollback criterion into a spec and
never built the instrument that reads the number. Same disease. A criterion with no
instrument, and a vocabulary with no enforcer, are the same bug wearing different clothes.

Fixing it: don't be lenient about broken values

Both fixes have the same shape. The old code treated an unrecognized value as equivalent to an
absent one, and absence had a permissive default. So:

if self.confidence not in VALID_CONFIDENCE:
    return False        # unknown is worse than not_found —
                        # we don't even know what was checked
Enter fullscreen mode Exit fullscreen mode

The rule I settled on: a broken value is not an absent value. Absent means "nobody filled
this in," which often has a legitimate default. Broken means "somebody filled this in and we
can't read it," which means you know less than nothing — you know an intent existed and you
lost it.

I'd already applied that rule elsewhere without noticing it was a rule. A staleness check in
the same codebase treats an unparseable date as stale, not as missing. Same instinct, and
it was the precedent that settled these two.

The trap on the other side

Tightening a permissive default breaks the legitimate uses of that default. Here, the absent
answered_by field genuinely means human — every checklist written before delegation
existed looks like that. Rejecting unknown values and absent ones would have invalidated
every human answer in the archive.

So each fix got a second test, asserting the thing that must keep working:

def test_a_missing_answered_by_field_still_means_human():
    ...
def test_the_two_usable_confidence_values_still_pass():
    ...
Enter fullscreen mode Exit fullscreen mode

These pass before the fix and after. They're not measuring the fix; they're measuring that the
fix didn't overshoot. Run them against the old code and they're green — which is exactly right,
and exactly why you need the other kind too.

Prove the tests can fail

Before committing, I reverted both source fixes and ran the new tests against the old code.
Eleven failures — five typo cases, six confidence cases — and the two no-regression tests
passed. That's the positive control: each blocking test genuinely goes red without the fix, and
each guard test genuinely passes both ways.

This takes about ninety seconds and it's the difference between "I wrote a test" and "I wrote a
test that measures something."

The mistake I made while fixing it

For the four constants that weren't broken, I wrote invariant tests to lock them. One of the
four was a grouping rule — "count the non-stock cuts, per scene" — written out three times in
the repo. Here's my first attempt at joining them:

needed = count_framings_needed(cuts)

grouped = {}
for cut in cuts:                          # ← I retyped the rule here
    if cut.source == CUT_SOURCE_BROLL:
        continue
    grouped[cut.scene_index] = grouped.get(cut.scene_index, 0) + 1

assert needed == grouped
Enter fullscreen mode Exit fullscreen mode

The docstring said "this joins the three copies." It doesn't. It creates a fourth copy and
compares it to the first. Neither of the two live copies is touched. If the production
implementation drifts, this test stays green.

I was fixing "a spec with no enforcer" by writing a spec with no enforcer.

The fix was to call the live function for real and assert against its output. Then I mutated
each copy in turn to confirm the joint actually holds:

Mutation Result
copy #1 counts stock cuts too assert {1:3, 2:1, 3:1} == {1:2, 2:1} — fails
copy #2's grouping includes stock assert 3 == 2 — fails

Caught from both directions. Now it's a joint.

(The equality only holds for one class of scene — the other class allocates round-robin, so it
can legitimately have fewer images than cuts. That's the scene where a zip() pairs the two
lists, and zip stops silently at the shorter one, so it's precisely the place worth
measuring. Scoping the invariant to where it's actually load-bearing is part of the work.)

What to do with your own orphan list

  1. Open every one. The reference count told you where to look, not what you found.
  2. For each, ask: is this a value nobody needs, or a rule nobody enforces? If the constant reads like a vocabulary — a tuple of legal strings, a set of tags, a status enum — assume the second until you've checked.
  3. Grep for the literals. If the members appear as bare strings elsewhere in the codebase, you've found the missing joint. That grep is the whole diagnosis.
  4. Trace where the value enters. Mine came from a config file through str(). A vocabulary only needs an enforcer at the boundary values cross — if every producer is internal and typo-proof, you may genuinely not need one.
  5. When you write the enforcement, write the both-ways pair: one test that fails without the fix, one that passes with and without it. Then revert the fix and watch them behave differently.

The orphan list wasn't a list of things to delete. It was a list of places where I'd written
down what I meant and never made the code answer for it.

More notes at hexisteme.github.io/notes.

Top comments (0)