Skip to content
C.W.K.
Stream
Lesson 01 of 05 · published

The Caller Must Never Learn the Job

~12 min · boundaries, coupling, invariants, separation-of-concerns

Level 0Cold Workshop
0 XP0/35 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

A Boundary Stated as a Prohibition

Most architectural boundaries are described by what each side owns. This one is written the other way round, as a prohibition on one side: the brain must never learn video. No scenes. No beats. No speech composition. No subtitle timing. None of it, ever, regardless of how small the piece is or how convenient it would be to put it there.

Stating a boundary as a prohibition rather than an allocation is a deliberate move, and it is worth understanding why. "The workshop owns video" is true and useless — it tells you nothing when somebody proposes a tiny helper on the other side, because a tiny helper does not feel like taking ownership of video. "The caller never learns video" answers that proposal directly. The size of the piece is not a defense.

What the Caller Is Allowed to Be

The permitted surface is deliberately almost nothing: a button, a single-line text field, and one endpoint that packages a pointer into a message. Under a hundred lines total. It knows the name of a pipeline and the identifier of a thing. It does not know what a pipeline does, what stages exist, what a plate is, or that rendering involves pictures at all.

Notice what that buys. The caller can be maintained by someone who has never opened the workshop. The workshop can restructure its entire internals — rename every stage, change the render format, replace the speech provider — without the caller noticing, because the caller's model of the workshop is a single string and an identifier. That is not an accident of the design; it is the design.

The Erosion Path Is Always the Same

Boundaries like this rarely fail in one dramatic decision. They fail through a sequence where every individual step is reasonable. Someone wants a preview thumbnail on the calling side, so a little image logic lands there. Then a duration estimate, which requires knowing something about segments. Then a progress indicator, which requires knowing the stage list. Each step is defensible on its own and the destination is a caller that has quietly learned video, at which point there are two implementations of the same knowledge and they will drift.

The written prohibition exists to make step one visible, because step one is the only one anybody could have stopped. By step three the cost of reversing is high enough that the boundary is gone in practice even if the document still claims otherwise.

Code

The entire permitted surface on the calling side·python
@router.post("/api/beacon/flag")
async def flag_for_production(payload: FlagRequest) -> dict:
    """Emit a pointer. That is the whole job.

    Note what is absent: no duration estimate, no thumbnail, no
    progress field, no render status. Every one of those would
    require this file to know something about video.
    """
    send_request(
        scope="beacon",
        receiver="workshop-session",
        context={
            "pipeline": payload.pipeline,   # a name, not behavior
            "pointer": payload.pointer,     # {kind, id} - opaque here
            "why": payload.why,             # one optional line
        },
    )
    return {"ok": True}

# The caller cannot answer "is it done?" and must not grow the
# ability to. That question belongs to the thread, not to this route.
The erosion sequence, written down so step one is visible·text
step 1  "just a preview thumbnail here"      -> needs image handling
step 2  "just a rough duration estimate"      -> needs segment model
step 3  "just a progress bar"                 -> needs the stage list
step 4  "we already have most of it, so..."   -> the boundary is gone

# Every step is individually reasonable.
# Only step 1 is cheap to refuse.
# This is why the rule names the DIRECTION, not the size.

External links

Exercise

Find a boundary in your own codebase that is documented as an allocation — "the payments module owns billing logic." Rewrite it as a prohibition aimed at the side most likely to encroach, then go looking for violations. The rewrite usually finds two or three immediately, because an allocation reads as satisfied whenever the owning side still exists.
Hint
The encroaching side is almost always the one closer to the user interface, because that is where small conveniences are requested. Ask what the UI layer currently knows about the domain that it would have to be told again if the domain were replaced.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.