AUTOPSY

A transcript of AI writing broken network automation, and the check that caught it

We asked a coding assistant to turn LLDP neighbor output into a topology diagram. The script exited 0 and produced valid Mermaid, but it drew every cable twice. This transcript includes the returned code, its output, the twelve-line check that reported the duplicate links, and the one-line fix.

Reading this, you will:
  • Inspect the code and terminal output from an AI-generated script that exits 0 and produces the wrong diagram.
  • Recognize the class of bug that produces no error: correct code computing the wrong thing.
  • Write a small output check that turns a wrong artifact into a failing exit code.

We asked a coding assistant for a script that turns show lldp neighbors output into a Mermaid topology diagram. The script exited 0 and produced valid Mermaid, but it drew every cable twice. A twelve-line output check reported all three duplicate links. This is the transcript, recorded on August 22, 2026, with the code and output unedited.

The input is neighbor output from a three-switch lab: an access switch uplinked to two cores, plus a link between the cores. The lab has three physical cables, so a correct diagram should have three edges.

The prompt and the code that came back

The prompt was: “Write a Python script that reads show lldp neighbors output from several switches in one file and prints a Mermaid topology diagram. Deduplicate links, since both ends report the same cable.”

The returned script is short and readable, and it includes a deduplication step.

#!/usr/bin/env python3
"""Turn show lldp neighbors output into a Mermaid topology diagram."""
import re
import sys

links = []
seen = set()
local = None

for line in open(sys.argv[1]):
    line = line.rstrip()
    prompt = re.match(r"^(\S+)#show lldp neighbors", line)
    if prompt:
        local = prompt.group(1)
        continue
    row = re.match(r"^(\S+)\s+(\S+)\s+\d+\s+\S+\s+(\S+)$", line)
    if row and local and not line.startswith("Device ID"):
        remote, local_if, remote_if = row.group(1), row.group(2), row.group(3)
        key = (local, local_if, remote, remote_if)
        if key in seen:
            continue
        seen.add(key)
        links.append((local, local_if, remote, remote_if))

print("flowchart TD")
nodes = []
for a, _, b, _ in links:
    for n in (a, b):
        if n not in nodes:
            nodes.append(n)
for n in nodes:
    print(f'  {n.replace("-", "_")}["{n}"]')
for a, aif, b, bif in links:
    print(f'  {a.replace("-", "_")} ---|"{aif} to {bif}"| {b.replace("-", "_")}')

The first run exits 0 and draws six edges

$ python3 lldp2mermaid.py neighbors.txt
flowchart TD
  acc_sw01["acc-sw01"]
  core_sw01["core-sw01"]
  core_sw02["core-sw02"]
  acc_sw01 ---|"Gi1/0/48 to Gi1/0/1"| core_sw01
  acc_sw01 ---|"Gi1/0/47 to Gi1/0/1"| core_sw02
  core_sw01 ---|"Gi1/0/1 to Gi1/0/48"| acc_sw01
  core_sw01 ---|"Te1/1/1 to Te1/1/1"| core_sw02
  core_sw02 ---|"Gi1/0/1 to Gi1/0/47"| acc_sw01
  core_sw02 ---|"Te1/1/1 to Te1/1/1"| core_sw01

The script exits 0, produces valid Mermaid, and includes all three hostnames. Nothing in the terminal output reports the duplicated links. The rendered diagram looks like this:

What the script drew
Rendering diagram…
View diagram source - it's just text (Mermaid). Diagrams-as-code is how modern network docs work; the flagship course has a free module on it.
flowchart TD
  acc_sw01["acc-sw01"]
  core_sw01["core-sw01"]
  core_sw02["core-sw02"]
  acc_sw01 ---|"Gi1/0/48 to Gi1/0/1"| core_sw01
  acc_sw01 ---|"Gi1/0/47 to Gi1/0/1"| core_sw02
  core_sw01 ---|"Gi1/0/1 to Gi1/0/48"| acc_sw01
  core_sw01 ---|"Te1/1/1 to Te1/1/1"| core_sw02
  core_sw02 ---|"Gi1/0/1 to Gi1/0/47"| acc_sw01
  core_sw02 ---|"Te1/1/1 to Te1/1/1"| core_sw01
What the script drew

The lab has three cables. The diagram has six edges. Every link is drawn twice because every cable is reported once from each end, and the deduplication key (local, local_if, remote, remote_if) treats the two reports of one cable as two different links. The code does exactly what it was written to do, but the deduplication key never recognizes the report from the other end as the same cable.

This class of bug produces no traceback or exception to inspect. The Python is valid, but its deduplication rule is wrong. The run gives no indication that the result is incorrect.

This topology should contain one drawn edge per physical cable. The check below groups each edge by the unordered pair of its endpoints and fails if any cable appears more than once.

#!/usr/bin/env python3
"""Check a generated topology: every cable appears exactly once."""
import re
import sys

edges = []
for line in sys.stdin:
    m = re.match(r'\s*(\w+) ---\|"(\S+) to (\S+)"\| (\w+)', line)
    if m:
        a, aif, bif, b = m.groups()
        edges.append(((a, aif), (b, bif)))

cables = {}
for e in edges:
    cables.setdefault(tuple(sorted(e)), []).append(e)

dupes = {k: v for k, v in cables.items() if len(v) > 1}
print(f"{len(edges)} edges drawn, {len(cables)} physical cables")
if dupes:
    for k, v in dupes.items():
        print(f"FAIL: cable {k[0][0]} {k[0][1]} <-> {k[1][0]} {k[1][1]} drawn {len(v)} times")
    sys.exit(1)
print("PASS: one edge per cable")
$ python3 lldp2mermaid.py neighbors.txt | python3 check_diagram.py
6 edges drawn, 3 physical cables
FAIL: cable acc_sw01 Gi1/0/48 <-> core_sw01 Gi1/0/1 drawn 2 times
FAIL: cable acc_sw01 Gi1/0/47 <-> core_sw02 Gi1/0/1 drawn 2 times
FAIL: cable core_sw01 Te1/1/1 <-> core_sw02 Te1/1/1 drawn 2 times
$ echo $?
1

One run returns three named failures and an exit code a pipeline can act on. The check applies the one-edge-per-cable rule directly to the generated artifact.

The one-line fix

The deduplication key has to describe the cable, not the direction it was reported from. Sorting the two endpoints before building the key does that:

# before
key = (local, local_if, remote, remote_if)

# after
key = tuple(sorted([(local, local_if), (remote, remote_if)]))
$ python3 lldp2mermaid.py neighbors.txt | python3 check_diagram.py
3 edges drawn, 3 physical cables
PASS: one edge per cable
After the fix
Rendering diagram…
View diagram source - it's just text (Mermaid). Diagrams-as-code is how modern network docs work; the flagship course has a free module on it.
flowchart TD
  acc_sw01["acc-sw01"]
  core_sw01["core-sw01"]
  core_sw02["core-sw02"]
  acc_sw01 ---|"Gi1/0/48 to Gi1/0/1"| core_sw01
  acc_sw01 ---|"Gi1/0/47 to Gi1/0/1"| core_sw02
  core_sw01 ---|"Te1/1/1 to Te1/1/1"| core_sw02
After the fix

Why the generated output needs its own check

Once the failing check exists, the fix is clear: sort the two endpoints before building the key. The engineering judgment came earlier. Someone had to define the one-edge-per-cable rule, write a check for it, and run that check before using the diagram.

Use the same method after a config push, routing change, or interface migration. State what the resulting network must look like, test that property mechanically, and make the process stop on a failing exit code. Generated code increases the amount of plausible code a reviewer has to inspect, so automated output checks carry more of the verification work.

Module 3 of the AI-Assisted Network Automation course has you read generated code, run it, and judge the result with checks you built. The Bug Swarm arcade repeats that work under time pressure, and it is one of the course’s free lessons with an account. The free network diagram generator runs the corrected deduplication logic in your browser.