Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

38. No auto-detect/re-exec: a project's custom binary is invoked explicitly, via a generated wrapper

  • Status: Accepted
  • Date: 2026-09-05

Context

ADR 0037 settled that a project depending on a native module gets its own custom-built korrin binary, distinct from whatever generic korrin is installed on $PATH. That leaves one question genuinely open: how does a developer actually end up running the right one?

Two real designs, and this is the one place in Milestone 6's design this project's own plan was genuinely torn on.

Decision

No magic. korrin pkg build prints the custom binary's path on success and writes a small, gitignored, project-root wrapper script (./korrin on Unix, ./korrin.cmd on Windows) that forwards argv to it. The generic korrin run needs no new mechanism for the failure path at all — it already, today, raises the ordinary E0314 ImportError the moment a program imports a name only a native-module registry (which the generic binary was never given) would satisfy.

Consequences

  • A developer working on a project with a native-module dependency must remember to invoke the generated wrapper (or the custom binary directly) instead of whatever generic korrin happens to be on $PATH. This is a real, accepted cost — directly comparable to a C project needing its own custom-built toolchain rather than the system compiler — named plainly here rather than hidden behind implicit re-exec magic.
  • Running korrin run game.kor with the wrong (generic) binary fails loudly and immediately with a diagnostic already fully explained by existing behavior (E0314, "no built-in module and no installed package/native module named ..."), not silently or confusingly.
  • No platform-specific process-spawning code is needed for this milestone — a real re-exec (spawning a child, forwarding stdio and exit code by hand, since Windows has no execve) is deferred until, if ever, it's actually wanted.

Alternatives considered

  • Auto-detect and re-exec. The generic korrin binary notices a project has a native-module dependency, checks a freshness marker, and transparently spawns the project's custom binary in its place. Rejected: it needs real, fiddly, platform-specific process-spawning code (Windows has no execve) for a first cut that doesn't need it, and it is exactly the kind of implicit magic this project has already rejected once on identical grounds — ADR 0019 refused a filesystem probe for import resolution specifically because "an import line's meaning would depend on which files exist." Which binary runs a program is at least as consequential a question as which module an import resolves to, and deserves no less explicitness. A silent delegation to a separately-built, possibly-stale, possibly differently-versioned binary is also a materially worse debugging experience than a loud, immediate failure.