# configuration/principle/data/binding.data.json

> 285 lines of code and 0 definitions.

Tree: GovLab Context
Language: json
Layer: domain
Canonical: https://banes-lab.com/anatomy/context#file-context-configuration-principle-data-binding-data-json
Source text: https://banes-lab.com/source/context/configuration/principle/data/binding.data.json.txt

Listed in [configuration/principle/data](https://banes-lab.com/api/source/context/configuration/principle/data.md), after [configuration/principle/data/architecture.domain.data.json](https://banes-lab.com/source/context/configuration/principle/data/architecture.domain.data.json.md) and before [configuration/principle/data/causality.data.json](https://banes-lab.com/source/context/configuration/principle/data/causality.data.json.md).

## Contained in

- [configuration/principle/data](https://banes-lab.com/anatomy/context/folder-context-configuration-principle-data.md)

## Source

```json
{
    "category": "Runtime Discovery / Dynamic Binding",
    "check": {
        "population": "every binding the runtime resolves: handlers, plugins, services, formatters and policies",
        "freshness": "a verdict stands until a registered module, a discovery pattern or the configuration changes",
        "refusal": "startup validation or the composition-root test fails when a declared binding resolves to nothing",
        "observation": "the resolved bindings reported at startup, compared with the modules on disk and the configuration",
        "evidence": "none: the catalog states this check as a class, so a watched run belongs to each system that adopts it",
        "authority": "the modules on disk and the configuration, which the bindings reported at startup are compared against"
    },
    "records": [
        {
            "id": "runtime-discovery",
            "distinctFrom": [
                {
                    "id": "architecture:capability-declaration",
                    "reason": "Runtime discovery finds which components exist, while a capability declaration states what each one supports."
                },
                {
                    "id": "architecture:introspection",
                    "reason": "Runtime discovery finds components by convention or pattern, while introspection reads one object's type and members."
                },
                {
                    "id": "architecture:reflection",
                    "reason": "Runtime discovery finds and registers components, while reflection reads and acts on type metadata, which discovery may use."
                },
                {
                    "id": "architecture:service-discovery",
                    "reason": "Runtime discovery finds in-process components at startup, while service discovery resolves a service name to a network endpoint at call time."
                },
                {
                    "id": "architecture:static-analysis",
                    "reason": "Runtime discovery decides the component set as the program starts, while static analysis reasons about source that has not run."
                }
            ],
            "name": "Runtime Discovery",
            "definition": "A mechanism that finds the available handlers, plugins or services at startup by matching a naming convention, a file pattern or metadata, and registers each one it finds in place of a hand-written list.",
            "type": "mechanism",
            "aliases": [
                "Auto-Discovery",
                "Registry/Discovery Mechanism"
            ],
            "scope": [
                "runtime",
                "plugin",
                "module",
                "service"
            ],
            "requires": [
                "Metadata",
                "Convention"
            ],
            "reinforces": ["Runtime Extensibility"],
            "enables": [
                "Plugin Architecture",
                "Service Discovery",
                "Self-Registration"
            ],
            "conflicts_with": [
                "Compile-Time Binding",
                "Manual Registration"
            ],
            "tensions_with": [
                "Predictability",
                "Static Analysis",
                "Startup Cost"
            ],
            "violated_by": ["lexicon:manual-registration"],
            "detected_by": ["manual class/service lists"],
            "measured_by": ["discovery coverage"],
            "refactored_by": [
                "architecture:registry-pattern",
                "architecture:static-analysis",
                "architecture:manifest-based-design"
            ],
            "enforced_by": ["startup validation"],
            "severity": "contextual",
            "exemplar": {
                "before": "import { FooHandler } from \"./foo-handler\";\nimport { BarHandler } from \"./bar-handler\";\nconst handlers = [new FooHandler(), new BarHandler()];",
                "after": "const modules = await discover<HandlerModule>(\"./handlers/*.handler.js\");\nconst handlers = modules.map(module => module.create());",
                "lang": "ts"
            }
        },
        {
            "id": "service-discovery",
            "distinctFrom": [
                {
                    "id": "architecture:failover",
                    "reason": "Service discovery resolves a name to a healthy endpoint, while failover switches traffic to a standby when the active one fails."
                },
                {
                    "id": "architecture:health-checks",
                    "reason": "Service discovery resolves endpoints, while health checks report whether each endpoint is ready."
                },
                {
                    "id": "architecture:service-registry",
                    "reason": "Service discovery is the lookup at call time, while the service registry is the table the lookup reads."
                }
            ],
            "name": "Service Discovery",
            "definition": "A mechanism that resolves a service name to a healthy network endpoint at call time through a registry.",
            "type": "mechanism",
            "scope": [
                "service",
                "network",
                "runtime"
            ],
            "requires": [
                "Service Registry",
                "Health Checks"
            ],
            "reinforces": [
                "Scalability",
                "Resilience"
            ],
            "enables": [
                "Dynamic Routing",
                "Failover"
            ],
            "conflicts_with": ["Hardcoded Endpoints"],
            "tensions_with": ["Operational Complexity"],
            "violated_by": ["lexicon:hardcoded-endpoints"],
            "detected_by": [
                "hardcoded URLs",
                "missing registry lookup"
            ],
            "measured_by": ["dynamic resolution coverage"],
            "refactored_by": [],
            "enforced_by": [
                "config scans",
                "deployment policy"
            ],
            "severity": "contextual",
            "exemplar": {
                "before": "const fooUrl = \"http://10.0.0.14:8080\";\nawait http.get(`${fooUrl}/foo/${id}`);",
                "after": "const endpoint = await serviceDiscovery.resolve(\"foo-service\");\nawait http.get(new URL(`/foo/${id}`, endpoint));",
                "lang": "ts"
            }
        },
        {
            "id": "dynamic-binding",
            "distinctFrom": [
                {
                    "id": "architecture:capability-declaration",
                    "reason": "Dynamic binding picks an implementation at runtime, while a capability declaration lists what an implementation supports so the pick can be checked."
                },
                {
                    "id": "architecture:polymorphism",
                    "reason": "Polymorphism lets the receiver choose the implementation per call, while dynamic binding chooses it from configuration or a registry."
                },
                {
                    "id": "architecture:service-registry",
                    "reason": "Dynamic binding is the choice made at runtime, while a service registry is the keyed table it can choose from."
                }
            ],
            "name": "Dynamic Binding",
            "definition": "A mechanism that selects the implementation behind an interface at runtime, from configuration or a registry, so the choice is made at bootstrap or first use rather than fixed in code.",
            "type": "mechanism",
            "aliases": [
                "Late Binding",
                "Runtime Binding"
            ],
            "scope": [
                "runtime",
                "interface",
                "plugin",
                "module",
                "service"
            ],
            "requires": [
                "Abstraction",
                "Runtime Resolution"
            ],
            "reinforces": [
                "Polymorphism",
                "Extensibility",
                "Runtime Extensibility"
            ],
            "enables": [
                "Plugin Swap",
                "Deferred Implementation Choice"
            ],
            "conflicts_with": ["Compile-Time Binding"],
            "tensions_with": [
                "Static Safety",
                "Predictability",
                "Debugging"
            ],
            "violated_by": ["lexicon:compile-time-binding"],
            "detected_by": ["hardcoded implementation selection"],
            "measured_by": ["runtime binding coverage"],
            "refactored_by": [
                "architecture:factory-pattern",
                "lexicon:registry",
                "architecture:strategy-pattern"
            ],
            "enforced_by": ["integration tests"],
            "severity": "contextual",
            "exemplar": {
                "before": "const formatter = new JsonFooFormatter();\nformatter.format(foo);",
                "after": "const formatter = formatterRegistry.get(config.format);\nif (!formatter) throw new Error(`unknown formatter: ${config.format}`);\nformatter.format(foo);",
                "lang": "ts"
            }
        },
        {
            "id": "dynamic-dispatch",
            "name": "Dynamic Dispatch",
            "definition": "A mechanism that chooses which operation runs from the receiver or a keyed table at runtime, replacing a conditional over kinds.",
            "type": "mechanism",
            "scope": [
                "method",
                "interface",
                "runtime"
            ],
            "requires": ["Polymorphism"],
            "reinforces": ["OCP"],
            "enables": ["Replace Conditional with Polymorphism"],
            "conflicts_with": ["Type Switching"],
            "tensions_with": ["Traceability"],
            "violated_by": ["lexicon:type-switching"],
            "detected_by": ["switch/if chains on type"],
            "measured_by": ["conditional dispatch count"],
            "refactored_by": [
                "lexicon:replace-conditional-with-polymorphism",
                "architecture:strategy-pattern"
            ],
            "enforced_by": [
                "lint rules",
                "review"
            ],
            "severity": "recommended",
            "exemplar": {
                "before": "function execute(kind: string, foo: Foo) {\n  if (kind === \"save\") return saveFoo(foo);\n  if (kind === \"publish\") return publishFoo(foo);\n}",
                "after": "const commands: Record<string, (foo: Foo) => unknown> = {\n  save: saveFoo,\n  publish: publishFoo,\n};\nfunction execute(kind: string, foo: Foo) {\n  const command = commands[kind];\n  if (!command) throw new Error(`unknown command ${kind}`);\n  return command(foo);\n}",
                "lang": "ts"
            }
        },
        {
            "id": "runtime-extensibility",
            "distinctFrom": [
                {
                    "id": "architecture:stable-interfaces",
                    "reason": "Runtime extensibility adds capability through extension points, while stable interfaces keep those points unchanged across releases."
                },
                {
                    "id": "lexicon:extensibility",
                    "reason": "Extensibility is adding behavior with little change to existing code, while runtime extensibility adds it to a system that is already running."
                }
            ],
            "name": "Runtime Extensibility",
            "definition": "The degree to which new capability can be added to a running system through extension points, without modifying its core.",
            "type": "quality-attribute",
            "scope": [
                "runtime",
                "plugin",
                "system"
            ],
            "requires": [
                "Extension Points",
                "Stable Interfaces"
            ],
            "reinforces": [
                "Plugin Architecture",
                "OCP"
            ],
            "enables": ["Capability Addition without Core Modification"],
            "conflicts_with": ["Closed Static Core"],
            "tensions_with": [
                "Predictability",
                "Security"
            ],
            "violated_by": ["lexicon:closed-core"],
            "detected_by": ["repeated core changes for variants"],
            "measured_by": ["extension/core-change ratio"],
            "refactored_by": ["architecture:extension-points"],
            "enforced_by": ["extension conformance tests"],
            "severity": "contextual",
            "exemplar": {
                "before": "switch (pluginName) {\n  case \"foo\": return new FooPlugin();\n  case \"bar\": return new BarPlugin();\n}",
                "after": "export function registerPlugin(name: string, create: () => Plugin) {\n  pluginRegistry.set(name, create);\n}\nconst plugin = pluginRegistry.get(pluginName)?.();",
                "lang": "ts"
            }
        }
    ]
}
```
