DEV Community

mattleeee
mattleeee

Posted on Originally published at hkcode.dpdns.org

The Silent Alert Bug: When Your Instant Push Exists but Never Fires

Your alert formatter is probably fine. The problem is that nobody calls it.

The Symptom

A user reports that instant push notifications stopped working. The daily report arrives on schedule. The formatting looks correct in the report. But the moment a position opens, nothing hits their phone.

The first instinct is to blame the transport layer: the push service, the API key, the network. You check credentials. You send a test push manually. It lands. So the pipeline is alive — which means the problem is upstream, in the code that's supposed to invoke the push.

You open the file. There's a function:

def format_instant_alert(position: dict) -> str:
    """Build a single-line push message for a newly opened position."""
    side = position["side"].upper()
    symbol = position["symbol"]
    entry = position["entry_price"]
    qty = position["qty"]
    return f"[{side}] {symbol} @ {entry} x{qty}"
Enter fullscreen mode Exit fullscreen mode

It's clean, tested, and correct. It has been correct for months. Now grep for its call sites:

grep -rn "format_instant_alert" --include="*.py" .
Enter fullscreen mode Exit fullscreen mode

One hit: the definition itself. Zero call sites.

The function is dead code. The push never fires because nothing ever asks it to. The user's mental model — "pushes are broken" — is wrong. The pushes were never wired in. They exist as a well-formed corpse.

Four Paths, Four Comments, Zero Calls

The real scenario was worse than a single missing call. The system had four separate code paths for opening a position:

  1. Manual entry from the CLI.
  2. Scheduled strategy execution.
  3. Signal-driven entry from a webhook.
  4. Recovery/reconciliation after a restart.

Each path had its own block of open-position logic — copy-pasted, then diverged. And each block carried a comment like this:

# open the position, update state, push is integrated into the daily report
Enter fullscreen mode Exit fullscreen mode

Four copies of the same sentence. Four copies of the same false assumption. The author of the original block believed the push was handled during daily report generation, so they didn't call the alert formatter. Every subsequent copy inherited the comment and the omission.

This is how "handled elsewhere" comments rot. The comment is a claim about code that lives somewhere else. It has no enforcement mechanism. When the "elsewhere" changes — or when it never actually handled the case — the comment stays, confidently lying. And because it's copy-pasted into four places, the lie propagates.

The daily report did not include instant alerts. It never had. The comment was aspirational, or it referred to a design that was abandoned. Nobody re-checked it, because comments are cheap and reading them feels like understanding.

Audit for Call Sites, Not Definitions

The core discipline is simple: to find dead code, search for how a function is used, not where it's defined.

A definition search tells you the function exists. A call-site search tells you whether it matters. These are different questions, and conflating them is why dead code survives audits.

Step 1: Enumerate the suspects

Start with the functions that should be firing but aren't. In an alerting system, that's typically the formatters and senders:

# alerting.py
def format_instant_alert(position: dict) -> str: ...
def format_daily_report(positions: list) -> str: ...
def send_push(message: str) -> bool: ...
def send_email(subject: str, body: str) -> bool: ...
Enter fullscreen mode Exit fullscreen mode

Step 2: Count call sites with a script

Manual grep works for one function. For a whole module, automate it. This script counts references to each public function and flags the ones that only appear at their definition:

import ast
import subprocess
from pathlib import Path

def defined_functions(path: str) -> list[str]:
    tree = ast.parse(Path(path).read_text(encoding="utf-8"))
    return [
        node.name
        for node in ast.walk(tree)
        if isinstance(node, ast.FunctionDef) and not node.name.startswith("_")
    ]

def count_call_sites(name: str, root: str = ".") -> int:
    """Count lines mentioning `name` across the repo, excluding the definition."""
    result = subprocess.run(
        ["grep", "-rn", "--include=*.py", name, root],
        capture_output=True,
        text=True,
    )
    hits = [line for line in result.stdout.splitlines() if line.strip()]
    # A call site is any hit that is not a `def name(` line.
    calls = [h for h in hits if f"def {name}(" not in h]
    return len(calls)

for fn in defined_functions("alerting.py"):
    calls = count_call_sites(fn)
    status = "DEAD" if calls == 0 else "ok"
    print(f"{status:5} {fn:30} call_sites={calls}")
Enter fullscreen mode Exit fullscreen mode

Run it and you get something like:

DEAD  format_instant_alert           call_sites=0
ok    format_daily_report            call_sites=2
ok    send_push                      call_sites=3
ok    send_email                     call_sites=1
Enter fullscreen mode Exit fullscreen mode

format_instant_alert is the smoking gun. It's defined, it's importable, and nothing reaches it.

The grep-based approach is deliberately crude — it will count mentions in comments and strings, and it can't distinguish a real call from a reference. That's fine for a first pass. The goal is triage: find the functions with zero non-definition mentions. Those are unambiguously dead. For anything with a nonzero count, you verify by hand.

Step 3: Verify the call actually executes

Zero call sites is a clean verdict. A nonzero count is a lead, not a conclusion. A function can be "called" in a branch that never runs:

def open_position(order):
    # ... state updates ...
    if order.source == "manual":
        send_push(format_instant_alert(order))  # only fires for manual entries
Enter fullscreen mode Exit fullscreen mode

Here format_instant_alert has a call site, so the script marks it ok. But scheduled and webhook entries — the majority of real activity — never hit that branch. The function is reachable in theory and dead in practice.

To catch this, you need to know which paths call it, not just that a call exists. Trace each of the four open-position paths and confirm the push call is inside the code that actually runs for that path. If the call is guarded by a condition that your production traffic never satisfies, treat it as dead.

The Fix Discipline

The tempting fix is to add the missing call to the one path the user complained about. Don't. That leaves three paths still silent, and you'll be back here in a week when a webhook entry fails to notify.

Patch every occurrence in one pass

Find every block that contains the same logic and fix all of them together. In this codebase, that meant four separate open-position blocks. The comment was the tell:

grep -rn "push is integrated into the daily report" --include="*.py" .
Enter fullscreen mode Exit fullscreen mode

Four hits. Four blocks to patch. Each gets the same real call:

def open_position(order, state):
    # ... state updates, persistence ...
    state.add_position(order)

    # Instant alert fires here, on every path, right after state is committed.
    message = format_instant_alert(order)
    ok = send_push(message)
    if not ok:
        log.warning("instant push failed for %s", order["symbol"])
Enter fullscreen mode Exit fullscreen mode

Remove the stale comment while you're there. A comment that claims work happens elsewhere is worse than no comment — it actively suppresses the reader's suspicion.

Refactor to one path if you can

Four copies of open-position logic is the root cause. The comment rot was just a symptom. If the paths can share a single function, do it:

def open_position(order, state, *, notify: bool = True):
    validate(order)
    state.add_position(order)
    persist(state)
    if notify:
        send_push(format_instant_alert(order))
Enter fullscreen mode Exit fullscreen mode

Now there is exactly one place where the push fires, and one place to audit. The next person who adds a fifth entry path calls this function and gets the alert for free.

Verify each call site executes

After patching, re-run the audit script. format_instant_alert should show four call sites (or one, if you refactored). Then go further: prove each path actually reaches the call at runtime.

The cheapest proof is a log line at the call site and a test per path:

import logging

log = logging.getLogger(__name__)

def open_position(order, state, *, notify: bool = True):
    validate(order)
    state.add_position(order)
    persist(state)
    if notify:
        log.info("dispatching instant alert for %s", order["symbol"])
        send_push(format_instant_alert(order))
Enter fullscreen mode Exit fullscreen mode

Then exercise all four paths in tests and assert the push was dispatched:

from unittest.mock import patch

def test_all_entry_paths_dispatch_alert():
    paths = [
        {"source": "manual",   "symbol": "AAA", "side": "long", "entry_price": 10, "qty": 1},
        {"source": "schedule", "symbol": "BBB", "side": "long", "entry_price": 20, "qty": 1},
        {"source": "webhook",  "symbol": "CCC", "side": "short", "entry_price": 30, "qty": 1},
        {"source": "recovery", "symbol": "DDD", "side": "long", "entry_price": 40, "qty": 1},
    ]
    for order in paths:
        with patch("alerting.send_push") as mock_push:
            open_position(order, state=StubState())
            assert mock_push.called, f"no push for {order['source']}"
Enter fullscreen mode Exit fullscreen mode

This test would have failed on all four paths before the fix. It fails loudly if someone later reintroduces a branch that skips the alert.

The General Pattern

Dead alert code is not a push problem. It's a code-path audit problem, and it shows up anywhere a side effect is assumed to be handled by someone else:

  • Alert formatters that are never invoked.
  • Cleanup routines that only run on one error branch.
  • Metrics that are defined but never incremented.
  • Retry handlers attached to a client that isn't the one in use.

The audit recipe is the same every time:

  1. List the functions that should fire. Search for call sites, not definitions.
  2. Treat zero call sites as dead. No exceptions, no "it's probably called dynamically."
  3. Treat guarded calls as suspicious. Confirm the guard is satisfiable by real traffic.
  4. Fix every copy in one pass. If the same logic is duplicated, the bug is duplicated.
  5. Prove execution. A log line plus a per-path test beats reading the code and nodding.

The expensive part was never writing the formatter. It was the four comments that said the work was already done. Comments don't run. Call sites do.

More notes like this ship every week on this site.

Top comments (0)