diff --git a/docs/roadmap/registration-backend.md b/docs/roadmap/registration-backend.md index 6c32a26..17c2e4a 100644 --- a/docs/roadmap/registration-backend.md +++ b/docs/roadmap/registration-backend.md @@ -2,8 +2,8 @@ Status: proposed internal design for the finalized consumer API; no implementation has begun. Runnable-command children and scope-error attachment are selected API -additions to incorporate into the registration API document. OQ-1 remains open -for later discussion before the staged implementation plan is finalized. +additions to incorporate into the registration API document. Both composition +questions below are resolved; the staged implementation plan remains to be written. ## 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 selector flags on generated commands. Integration code should not reproduce -those rules with handwritten reserved-name lists. Error checking for selectors -in an absent definition family is the unresolved seam described below. +those rules with handwritten reserved-name lists. Validate bindings used by +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 @@ -453,52 +455,45 @@ and permits application-created adapters to supply errors directly. It expands mutable public representation and requires defining preservation/combination of 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 -for later discussion. The selected API additions above need to be reflected in -the registration API document before implementation planning is finalized. Do not -resolve the remaining question with private-module imports, dummy providers, -reflection, or hidden global state. +**Selected:** empty definition suites contribute no commands, and unused selector +bindings are ignored. Generate commands for the supplied capabilities and validate +the bindings needed by those commands. When neither definition-inspection +capability is enabled, the family contributes no namespace, help entry, or handler. +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 -swallowed. It does not explicitly define the validation boundary for selector -bindings when both definition capabilities are absent. If those bindings must -still be validated, `ckprompt` can retain its own adapter errors, but `Flag` -validation state is private to the core. An integration can construct a temporary -command containing its selector bindings, yet the finalized API offers no way to -transfer that -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. +An explicitly invalid adapter construction remains distinct from an omitted +capability. Retain errors such as a nil loader supplied to an adapter even when +its capabilities are subsequently cleared. Return ordinary `NoCommand()` for an +empty definition suite, attaching any retained construction errors through the +existing `WithError`. Installation checks those errors before skipping absence. +No validation-bearing `NoCommand` overload or public declaration-validation helper +is needed. -**Recommendation:** approve a narrow extension of the existing absence factory, -schematically `NoCommand(validation ...Command) Command`. A no-op can retain -local construction/structural errors from eagerly captured validation declarations -without installing their commands or claiming their namespaces. The empty -definition factory builds a metadata-only validation declaration using the same -generated flag assembly, then returns absence carrying that evidence. +The binding rule also applies to configuration selectors unused by any generated +inspection command. Existing configuration-suite semantics remain unchanged: +zero named scopes is an error, while named metadata-only scopes supply the real +`config scopes` discovery command and remain valid. Integration scope identifiers, +applicability references, and enabled-provider wiring retain their own validation; +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 -error boundary. Validation sources are captured data, not preparation callbacks; -they do not acquire providers or introduce registry collision checks for roots -that will not be installed. Specify the evidence-only behavior explicitly before -changing the API. Plain `NoCommand()` retains its current meaning. +This construction-time rule does not skip invocation-time conversion of a supplied +flag on an installed command merely because it is inapplicable to the selected +scope. Conversion and scope-specific application remain separate as described +above. -**Alternative:** add a core declaration-validation function returning `error` for -local metadata/structure, and attach its result through the existing `WithError`. -That also avoids a temporary app and duplicated flag policy. It adds a public -validation entry point and a second observation point for errors; ensure it uses -the same validator rather than evolving independent rules. It is viable if -explicit validation is useful beyond absent families. - -**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. +**Alternatives considered:** rejecting empty definition suites could catch an +accidental omission, but would make an empty capability selection an error without +a demonstrated need. Validating all unused bindings, through either an extended +absence factory or an explicit validation helper, would catch latent defects but +add public API and validation machinery for commands that do not exist. Neither +alternative is selected.