C.W.K.
Stream
Lesson 04 of 04 · published

The Adapter Is the Seam

~13 min · firelink, adapter, seam, orchestration

Level 0Cold Ash
0 XP0/32 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"On one side of the seam, Firelink orchestrates. On the other, the sibling does the real work. The seam is where they never bleed into each other."

Where the Shrine Stops and the Flame Begins

Back in the first track, the rule was that Firelink orchestrates but never absorbs a sibling's implementation. The adapter is the precise line where that happens. When Firelink deploys a native app, it doesn't know how signing works — it invokes the deploy adapter, which fronts the tool that owns signing. When it fans out a repo tree, it invokes the tree adapter, which fronts the canonical sync tool. The adapter is the seam: Firelink's typed orchestration on one side, the sibling's owned implementation on the other, and a clean contract between them so neither reaches into the other.

An Adapter Declares a Fixed Contract

Every adapter declares a typed contract, not a loose function: a stable adapter id; the capability it supports; a canonical executable path; the member or target mapping; the required host role; the allowed peer ids; whether it supports dry-run; a timeout and an exclusivity class; and a result parser plus a postcondition verifier. That contract is what lets Firelink invoke real, dangerous work safely — it knows exactly what will run, where it's allowed to run, how long to wait, and how to confirm it worked, all without embedding the sibling's logic.

Only the Web Backend, Only From Office, Only Via a Plan

The invocation boundary is strict: the Native Launcher never calls adapters at all, and the Web backend is the only caller — invoking them only from office, only through a persisted plan. And the guardrails live in the adapter and registry, not as string checks sprinkled across routes: Mom's Mac is outside deploy scope, and Cinder stays office-only, as registry and adapter invariants. That's the payoff of centralizing the seam — a rule like 'never deploy to Mom's Mac' is declared once, in the adapter contract, instead of re-checked (and eventually forgotten) in a dozen scattered code paths.

Put the boundary between your orchestration and someone else's implementation in one typed adapter, and declare the safety rules there — not as scattered checks. A seam you can point to is a seam you can audit; a rule declared in the adapter contract holds everywhere the adapter is used, while the same rule copied into many routes fails the first place someone forgets it.

Code

The adapter contract: a typed seam, guardrails declared once·python
@dataclass(frozen=True)
class DeployAdapter:
    adapter_id: str                 # stable id, resolved from the registry
    capability: str                 # e.g. "deploy-native"
    executable: Path                # the sibling tool that owns the real work
    target_mapping: dict            # canonical member/target -> adapter args
    required_host_role: str = "office"   # invariant: runs only from office
    allowed_peers: frozenset = ...       # invariant: never yonsuk, never Cinder-fleet
    supports_dry_run: bool = True
    timeout_s: int = 600
    exclusivity: str = "per-target"
    # + result_parser and postcondition_verifier

# Only the WEB backend calls this, only from office, only via a persisted plan.
# The Native Launcher has no path to it. The 'never yonsuk' rule lives HERE,
# in the contract, not re-checked in twelve different routes that could drift.

External links

Exercise

Find two systems in your world that talk to each other where one 'drives' and the other 'does the work' (an app calling a payment processor, a CI job calling a deploy tool). Is there a single adapter seam between them, or does the calling side reach into the other's details in several places? Pick one safety rule (a spend limit, an environment restriction) and decide where it should live so it can't be bypassed by a new call site.
Hint
If the caller constructs the other system's command or arguments in more than one place, you don't have a seam — you have a leak. The fix is one adapter that owns the translation and the guardrails, so every call goes through the same audited door.

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.