ADR-v4-007: Language-binding registration lives in cmd/ghyll (integration layer)
Status: Accepted (2026-05-25)
Context:
registerGridBindings(reg *runner.Registry, grid *bootstrap.Grid, workdir string) error is the operation that populates the
evaluator registry from a grid’s language-bindings: declarations.
It needs:
runner.Registry(mutates the live registry).bootstrap.Grid(source of binding declarations).runner.NewBindingEvaluator(constructs the subprocess evaluator).bootstrap.BindingKeysFromStrings(parses the<concept>.<language>keys).
The natural location would be runner/, but bootstrap already
imports runner (bootstrap/init_attestations.go references
runner.AttestationRecord). Adding the inverse edge — runner → bootstrap — creates a Go import cycle. R1 of the v2 adversarial
flagged this as a critical compile-time failure.
Decision:
registerGridBindings and its sibling helpers
(requiredBindingsFromTypedGrid, requiredBindingsFromUntypedGrid,
buildRegistryOverlay, composeBootstrapOverlay) live in
cmd/ghyll/binding_register.go (package main). Rationale:
cmd/ghyllis the integration boundary — it already imports BOTHrunnerANDbootstrap.cmd/ghyllis a leaf package — no production code imports it, so the new edges cannot cycle.- The helpers are package-local; the runtime construction site
(
openEngineWithOptionsand the amendment-driven re-register callbackbuildRegistryOverlay) lives in the same package.
Alternatives considered + rejected:
- New
wiring/package: would still need to be imported bycmd/ghyllto be called. Splits the seam without resolving the cycle. RegistryInterfaceinbootstrap/: moves binding logic AWAY fromrunnerwhere theRegistrytype lives. Worse locality.- Breaking the bootstrap → runner edge (relocating
init_attestations.go’s AttestationRecord references): large structural change far beyond v4’s scope.
Consequences:
- The integration site is the single place where binding-registration
policy lives. A future refactor that wants to make this reusable
outside
cmd/ghylllifts both helpers and their tests as a unit. - The arrow-overlay conversion
(
runner.ArrowDefinition → map[string]anyfor the in-memory bootstrap.Grid overlay) ships ascmd/ghyll/arrow_marshal.gowith a round-trip test (R3 closure). - The amendment-driven re-register callback
(
AmendmentCommitter.BindingsReRegister) is a function-typed field on the committer; the integration site wires it toengineRuntime.buildRegistryOverlay.