Resolve unused binding validation for empty integration suites

This commit is contained in:
2026-10-10 23:33:23 +00:00
parent 3b69cf85e7
commit 336d489727

View File

@@ -2,8 +2,8 @@
Status: proposed internal design for the finalized consumer API; no implementation Status: proposed internal design for the finalized consumer API; no implementation
has begun. Runnable-command children and scope-error attachment are selected API has begun. Runnable-command children and scope-error attachment are selected API
additions to incorporate into the registration API document. OQ-1 remains open additions to incorporate into the registration API document. Both composition
for later discussion before the staged implementation plan is finalized. questions below are resolved; the staged implementation plan remains to be written.
## Purpose and authority ## Purpose and authority
@@ -192,8 +192,10 @@ do not add a global intern table, reflection-driven compiler, or mutable
Core name/short-name/help-reservation rules also check the combined standard and Core name/short-name/help-reservation rules also check the combined standard and
selector flags on generated commands. Integration code should not reproduce selector flags on generated commands. Integration code should not reproduce
those rules with handwritten reserved-name lists. Error checking for selectors those rules with handwritten reserved-name lists. Validate bindings used by
in an absent definition family is the unresolved seam described below. generated commands; unused selector bindings in an absent family are ignored,
as clarified in the OQ-1 resolution below. Retained adapter-construction errors
still reach installation.
## One typed conversion and application mechanism ## One typed conversion and application mechanism
@@ -453,52 +455,45 @@ and permits application-created adapters to supply errors directly. It expands
mutable public representation and requires defining preservation/combination of mutable public representation and requires defining preservation/combination of
multiple errors; the opaque attachment operation keeps those details private. multiple errors; the opaque attachment operation keeps those details private.
## Open Questions ## Resolved unused-binding validation (OQ-1)
OQ-1 remains unresolved; its recommendation and alternatives below are retained **Selected:** empty definition suites contribute no commands, and unused selector
for later discussion. The selected API additions above need to be reflected in bindings are ignored. Generate commands for the supplied capabilities and validate
the registration API document before implementation planning is finalized. Do not the bindings needed by those commands. When neither definition-inspection
resolve the remaining question with private-module imports, dummy providers, capability is enabled, the family contributes no namespace, help entry, or handler.
reflection, or hidden global state. There is no need to construct validation-only commands or a temporary application
for selector bindings that will not be installed.
### OQ-1: Retaining core binding errors when a family is absent This follows the capability-driven assembly model: selecting no capabilities
naturally produces no commands. Rejecting unused bindings would report defects
that cannot affect routing, parsing, or execution. This clarifies the validation
boundary while preserving ADR 0011's selected empty-suite behavior; it does not
promise exhaustive validation of unused metadata.
The API says suite validation precedes absence and invalid wiring must not be An explicitly invalid adapter construction remains distinct from an omitted
swallowed. It does not explicitly define the validation boundary for selector capability. Retain errors such as a nil loader supplied to an adapter even when
bindings when both definition capabilities are absent. If those bindings must its capabilities are subsequently cleared. Return ordinary `NoCommand()` for an
still be validated, `ckprompt` can retain its own adapter errors, but `Flag` empty definition suite, attaching any retained construction errors through the
validation state is private to the core. An integration can construct a temporary existing `WithError`. Installation checks those errors before skipping absence.
command containing its selector bindings, yet the finalized API offers no way to No validation-bearing `NoCommand` overload or public declaration-validation helper
transfer that is needed.
command's retained errors to `NoCommand()`. Discarding it loses evidence;
installing it adds a command that should be absent. Validating through a temporary
`App` would work mechanically but construct built-ins, routing ownership, and a
registry merely to inspect metadata.
**Recommendation:** approve a narrow extension of the existing absence factory, The binding rule also applies to configuration selectors unused by any generated
schematically `NoCommand(validation ...Command) Command`. A no-op can retain inspection command. Existing configuration-suite semantics remain unchanged:
local construction/structural errors from eagerly captured validation declarations zero named scopes is an error, while named metadata-only scopes supply the real
without installing their commands or claiming their namespaces. The empty `config scopes` discovery command and remain valid. Integration scope identifiers,
definition factory builds a metadata-only validation declaration using the same applicability references, and enabled-provider wiring retain their own validation;
generated flag assembly, then returns absence carrying that evidence. ignoring unused bindings does not erase retained adapter errors or bypass checks
on commands that are generated.
This reuses the common declaration validator and keeps one installation-time This construction-time rule does not skip invocation-time conversion of a supplied
error boundary. Validation sources are captured data, not preparation callbacks; flag on an installed command merely because it is inapplicable to the selected
they do not acquire providers or introduce registry collision checks for roots scope. Conversion and scope-specific application remain separate as described
that will not be installed. Specify the evidence-only behavior explicitly before above.
changing the API. Plain `NoCommand()` retains its current meaning.
**Alternative:** add a core declaration-validation function returning `error` for **Alternatives considered:** rejecting empty definition suites could catch an
local metadata/structure, and attach its result through the existing `WithError`. accidental omission, but would make an empty capability selection an error without
That also avoids a temporary app and duplicated flag policy. It adds a public a demonstrated need. Validating all unused bindings, through either an extended
validation entry point and a second observation point for errors; ensure it uses absence factory or an explicit validation helper, would catch latent defects but
the same validator rather than evolving independent rules. It is viable if add public API and validation machinery for commands that do not exist. Neither
explicit validation is useful beyond absent families. alternative is selected.
**Alternative requiring a contract clarification:** validate only the bindings of
actual generated commands. An absent family has no installed bindings, so unused
selectors would not undergo core validation; retained adapter errors still fail.
This needs no new API and is proportionate to installed behavior, but limits the
meaning of suite validation before absence to integration metadata and retained
adapter issues rather than all unused bindings. Choose it deliberately,
rather than silently making empty capabilities swallow invalid declarations.