On this page

The final fix was three lines:

_SHORTCODE_LANG = ""
if languages:
    _SHORTCODE_LANG = lang

Getting there took 34 closed tickets, 3 regressions, 88 broken links on a customer site, and a complete rewrite of how Wire develops software.

The Customer's Problem

Helm & Nagel runs a multi-language site: English and German. When they built their site, every link inside a :::cards shortcode pointed to /build/ai-agents/ instead of /en/build/ai-agents/. The pages lived under /en/, but shortcodes didn't know that.

80 broken links. Every card, every CTA, every pricing button: dead.

The First Fix (That Worked)

Ticket #73. The build system already had a _prefix_link() function that prepends /{lang}/ to internal URLs. Config links (header CTA, footer, sidebar) went through it. Shortcodes didn't.

The fix: call _prefix_link() from every shortcode renderer. Cards, CTAs, pricing, FAQ, steps. 17 tests. Customer build passed. Shipped.

The Second Fix (That Broke Something Else)

The shortcode renderers don't have access to the current language at render time. They run during markdown parsing, before the template engine. So we needed a module-level variable: _SHORTCODE_LANG.

An agent wrote:

_SHORTCODE_LANG = lang if languages else ""

Correct. One line. The if languages guard means single-language sites get an empty string, so no prefix. Multi-language sites get the current language code.

But then the agent also wrote, in a different part of the same function:

if languages:
    _SHORTCODE_LANG = lang

Two code paths for the same variable. The first was already correct. The second was redundant. On single-language sites, lang was "de" (from wire.yml's lang: de) but languages was empty (no languages: config). The ternary returned "". Correct.

Until someone read the code and thought: "This variable is set in two places. Let me simplify." They removed the ternary and kept the if block. Now _SHORTCODE_LANG was never set for single-language sites. It fell through to whatever value it had from the previous build. Or it was "". Or it was "de".

wise-relations.com: 88 broken links. Every shortcode link got /de/ prepended on a site where pages live at root.

The Regression That Tests Didn't Catch

All tests passed. Every single one. The test suite ran 2,130 tests in 2 minutes. Green.

The problem: tests used mock sites with mock languages. No test said "on a single-language German site, shortcode links must NOT be prefixed." That test didn't exist because the agent wrote tests after the code, not before. The tests confirmed the code worked as written. They didn't confirm the code was correct for all site configurations.

Three More Regressions From the Same Session

The shortcode bug wasn't alone. In the same session, 34 tickets were closed. Three introduced regressions:

  1. #90: _prefix_config_links() ran on single-language sites. 88 broken links.
  2. #100: News file warning suppression checked for /news/ in paths. Windows uses \news\. The check failed on the actual machine.
  3. #101: A shared function returned {"impressions": N} but the caller read m["total_impressions"]. Tests mocked the data and didn't catch the mismatch.

All three passed the test suite. All three broke on real customer sites.

What Changed

Wire rewrote its development protocol. Every fix now goes through a four-layer verification loop:

         PASS              PASS                PASS
1. CODE ───────▶ 2. TESTS ────────▶ 3. WIRE BUILD ────────▶ 4. CUSTOMER BUILD
  ▲                │                    │                       │
  │     FAIL       │         FAIL       │            FAIL       │
  └────────────────┘                    │                       │
  ▲                                     │                       │
  └─────────────────────────────────────┘                       │
  ▲                                                             │
  └─────────────────────────────────────────────────────────────┘

Every failure goes back to step 1. Then the fix must pass all four layers again. Layer 3 can reject work that Layer 4 approved last round, because the fix changed the work.

Layer 4 is the one that would have caught all three regressions: build a real customer site on the real machine. wise-relations.com is single-language German, runs on Windows, has real GSC data. If it builds clean, the fix is probably correct. If it doesn't, back to Layer 1.

New Rules

Three rules were added to Wire's development protocol:

TDD gate. No production code may be edited before tests exist. The first edit to any file in wire/ must happen after failing tests are printed. If you catch yourself editing wire/*.py before you have a failing test, stop.

One code path rule. If a ternary already handles the logic, do not add a second if block elsewhere that sets the same variable. Two code paths for the same value equals a guaranteed future regression. One expression. One place. One truth.

Clean plate rule. Commit, push, and close after every single ticket. Do not accumulate. If the session dies with unpushed commits, the work is invisible.

One More Bug in the Same Block

While fixing the language prefix, we found another violation of Wire's philosophy sitting right next to it:

_SHORTCODE_LOGO = config.get("logo", "")

Wire requires logo in wire.yml. It's in the docs. The build refuses without it. But this line silently falls back to an empty string if logo is missing. A customer with a broken config would get a site with no logo and no error. That's exactly the kind of silent degradation Wire exists to prevent.

The pattern .get("key", "default") on required config is a footgun. It looks defensive. It's actually hiding a broken setup from the customer. Compare:

# BAD: customer never knows logo is missing
_SHORTCODE_LOGO = config.get("logo", "")

# GOOD: crash loud on missing, respect false (text-only sites)
logo = config.get("logo")
_SHORTCODE_LOGO = logo if logo and logo is not False else ""

# GOOD: site_name is required — KeyError if missing
_SHORTCODE_SITE_NAME = config["site_name"]

This wasn't in any ticket. Nobody reported it. We found it because the three-line fix was right next to it.

The Final Fix

After all of that, the fix was four lines:

# URL prefix: only multi-language builds prefix shortcode links
_SHORTCODE_LANG = ""
if languages:
    _SHORTCODE_LANG = lang

Empty by default. Only set when the site actually has multiple languages. Not a ternary that looks clever but invites a second code path. Not a .get() that hides missing config. Just an explicit default and an explicit override.

Four lines that took a full engineering process overhaul to get right.

What Wire Learned

The customer didn't care about our process. They cared that their links worked. The 88 broken links cost them a day of debugging before they found the regression. That's the real cost, not the 3 regressions in our test suite.

Wire is opinionated. We refuse to build when something is wrong. We don't serve stale content. We don't fall back silently. But being opinionated about output means nothing if the development process that produces the output is sloppy. And being opinionated about config means nothing if the code uses .get("key", "") to silently swallow what should be a crash.

The four lines were always the right fix. The process changes are what make sure the next four lines are right too.

Source: SearchPilot A/B testing.