Quartet / Quintet

2026-09-05  ·  programming · python · webdev · softwaredevelopment

Write the Same Decision in Two Places and Only One of Them Gets Fixed

There are two storefronts, one domestic and one international, and the international one is not open yet.

So I made a rule: if the international store is not open, send the reader to the domestic one. It has an English interface and takes international cards. Being sent somewhere you can actually buy beats being sent nowhere.

I wrote that rule into the function that generates the footer of each article.

if store.get("gumroad"):
    parts.append(f"The full kit is available here.\n\n{store['gumroad']}")
elif store.get("booth"):
    # until the international store opens, send readers to the domestic one
    parts.append(f"The full kit is on BOOTH ...\n\n{store['booth']}")

It went out to 24 articles. All of them say you can buy it.

The function that rewrites the button on the product page lives somewhere else.

url = store.get("booth") if name == "index.html" else store.get("gumroad")
new_btn = off if not url else f'<a class="btn" href="{url}">{label}</a>'

The English button only looks at gumroad. It is not open, so that is None.

<a class="btn" href="#" aria-disabled="true">Purchase Quintet (Coming soon)</a>

Which left the site saying this:

24 articles   "you can buy it here" -> link to the product page
product page  "Coming soon"

Readers arrive at the product page from the articles. The order could not be worse. Only the people who read a whole article, got interested, and clicked were told to come back later. The readers most likely to buy were the only ones turned away.

I did not recognize it as the same decision

In hindsight the two pieces of code decide the same thing:

Which storefront do we send a reader of this language to?

So why did it not register? Because one builds a paragraph of text and the other rewrites an HTML attribute.

def buy_line(store, lang) -> str:      # returns a Markdown paragraph
def rewrite_lp(store) -> int:          # regex-replaces HTML

Different arguments, different return types, different output formats. When code does not look alike, the fact that it implements the same policy does not surface.

Duplication is usually described as the same code written twice. The dangerous kind is the same decision written twice in two different shapes. The first kind you can grep for. The second kind you cannot.

What caught it was reading the diff before pushing

Not a test. I read the diff before pushing.

-<a class="btn" href="https://quartet-dev.booth.pm/items/...">Purchase Quintet</a>
+<a class="btn" href="#" aria-disabled="true">Purchase Quintet (Coming soon)</a>

The generated site is committed to a repository, so regenerating it produces a diff. Checking that nothing came along besides the change you meant is what works against this class of bug.

What I meant to do was add a fifteenth article. A button had no business being disabled. The mismatch between intent and diff is the only signal there was. A workflow that does not read diffs ships this.

One place for the decision, separate places for the presentation

There is a range of possible fixes. Merging the two functions is too far. One returns Markdown, the other rewrites HTML. Merging them only moves the branching inside.

Share the decision, nothing else.

def destination(store: dict, lang: str) -> str | None:
    """Which storefront this language's readers go to, or None if none is open.

    This used to be written in two places. A fallback was added to the article
    footer and not to the landing page, so the articles said "you can buy it"
    while the page they linked to said "coming soon". The destination is decided
    here; how it is presented is up to the caller.
    """
    order = ("booth",) if lang == "ja" else ("gumroad", "booth")
    for key in order:
        if store.get(key):
            return key
    return None

It returns the name of the store, not the URL. The callers do not need to know where to send people so much as which store ended up being chosen:

The presentation stays different. Only the decision is shared.

# article
where = destination(store, "en")
if where == "gumroad":
    ...
elif where == "booth":
    ...

# landing page
where = destination(store, "ja" if name == "index.html" else "en")
url = store[where] if where else None

Run every combination

Two stores, each open or not, is four cases. I ran all four and checked that the articles and the landing pages say the same thing.

booth=no  gumroad=no  -> EN page=#        JA page=#        EN article=none
booth=yes gumroad=no  -> EN page=BOOTH    JA page=BOOTH    EN article=booth
booth=no  gumroad=yes -> EN page=Gumroad  JA page=#        EN article=gumroad
booth=yes gumroad=yes -> EN page=Gumroad  JA page=BOOTH    EN article=gumroad

The second row is the bug. Before the fix, the English page was # there.

Four cases is few enough to run all of them. While the combinations are still countable, running all of them is faster than arguing about which one is representative.

I also checked that restoring the original settings produces a zero diff. The test rewrites configuration, and forgetting to restore it breaks the live links.

Takeaways


Related


I publish the configuration for splitting Claude Code into separate personas — Architect, Coder, Reviewer, Conflict Resolver — under MIT. Copy it, run ./setup.sh, and it works. It does not depend on your tech stack.

https://github.com/quintetkit/quartet

I built one real tool using nothing but this workflow. Every Issue, PR, review and merge is still there. The parts that went wrong were not deleted.

https://github.com/quintetkit/mdlinkcheck

The version that adds a UI Designer persona, review criteria, a per-Issue parallel execution script and a 10-chapter guide is on the product page.

The full kit — five personas, the scripts and the complete guide in English and Japanese — is on BOOTH, a Japanese store with an English interface that takes international cards.

https://quartet-dev.booth.pm/items/8807156

The workflow itself is available

Quartet, the four-persona version, is published free under MIT. Quintet adds a UI Designer persona, review criteria, a per-Issue parallel execution script, and a 10-chapter guide.

See the free version Product page