diff --git a/docs/development.md b/docs/development.md index abadc25..a249a1e 100644 --- a/docs/development.md +++ b/docs/development.md @@ -11,10 +11,10 @@ The [README](../README.md) provides project orientation; the [documentation policy](policy/documentation.md#canonical-ownership) assigns canonical documentation owners. -For application-owned alias scope, implementation history, and accepted -decisions, use its -[feature roadmap](roadmap/aliases.md), [implementation sequence](roadmap/implementation.md), -and [ADR 0013](adr/0013-application-alias-routing.md). Keep deferred capabilities in +For application-owned aliases, use the +[CLI reference](cli.md#application-owned-aliases), +[Go declarations and GoDoc](../command.go), and +[ADR 0013](adr/0013-application-alias-routing.md). Keep deferred capabilities in [deferred work](roadmap/deferred.md). ## Initial orientation @@ -53,7 +53,7 @@ and [ADR 0013](adr/0013-application-alias-routing.md). Keep deferred capabilitie | Task | Read | | --- | --- | | Implemented CLI behavior | [CLI reference](cli.md) | -| Application-owned aliases | [Feature roadmap](roadmap/aliases.md), [implementation plan](roadmap/implementation.md), and [ADR 0013](adr/0013-application-alias-routing.md) | +| Application-owned aliases | [CLI reference](cli.md#application-owned-aliases), [Go declarations and GoDoc](../command.go), [consumer guide](consumers/guide.md#application-owned-aliases), and [ADR 0013](adr/0013-application-alias-routing.md) | | Public API usage and standard-suite wiring | [Consumer guide](consumers/guide.md), [ckconfig package](../integrations/ckconfig/doc.go), [ckprompt package](../integrations/ckprompt/doc.go), and applicable ADRs | | Dispatcher, registration, or typed inputs | [Command declarations](../command.go), [bindings](../binding.go), [invocation](../execute.go), and [ADR 0001](adr/0001-command-dispatch-and-inputs.md), refined by [ADR 0011](adr/0011-captured-declarations-and-installation.md) | | Backend integration | [Internal overview](internal/overview.md), [adapter implementation](../internal/cobra/parse.go), and [ADR 0002](adr/0002-cobra-backend.md) | @@ -70,7 +70,8 @@ Read all applicable rows for cross-cutting work. Go declarations and GoDoc own current exported contracts; the CLI reference owns operator behavior. The [maintainer release procedure](release.md) owns current release operations. Completed roadmaps and implementation evidence remain available in Git history, -including [PromptKit requirements implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/40499a43608bf60d1104cd8ee24caf18ac0e9e66/docs/roadmap). +including [application-owned alias planning, implementation, and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/f42aefe02d84e154855ac922173e6f367180929f/docs/roadmap) +and [PromptKit requirements implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/40499a43608bf60d1104cd8ee24caf18ac0e9e66/docs/roadmap). These records are not assignments to restart completed work. The [deferred-work record](roadmap/deferred.md) preserves future capability targets and unselected proposals separately from current contracts. diff --git a/docs/roadmap/aliases.md b/docs/roadmap/aliases.md deleted file mode 100644 index dcf3b73..0000000 --- a/docs/roadmap/aliases.md +++ /dev/null @@ -1,598 +0,0 @@ -# Application-owned aliases - -Status: implementation and [review remediation](remediation.md) complete; -core v0.3.0 release note prepared and publication pending. OD-1 through OD-6 -are resolved. This roadmap records the target and selected behavior. The -[completed implementation plan](implementation.md) preserves delivery sequencing -and stage-specific validation. Current contracts belong to the -[Go declarations and GoDoc](../../command.go) and -[CLI reference](../cli.md#application-owned-aliases). -[ADR 0013](../adr/0013-application-alias-routing.md) records the accepted -architectural ownership and shared installation decisions. - -## Purpose and ownership - -Make alternate command paths and flag spellings simple for consuming -applications to declare. CommandKit core owns alias registration, resolution, -and integration with routing and help. Applications choose their aliases. -Integrated libraries continue to own their canonical command behavior. - -Aliases occupy a separate application routing layer above installed canonical -commands: - -```text -CLI argument tokens - → command-path alias resolution - → canonical command or discovery-help context selection - → applicable flag-alias resolution using that context's flag metadata - → input parsing - → ordinary invocation lifecycle or discovery help -``` - -Alias declarations do not install new handlers or modify the canonical command -tree. An alias spelled inside `promptkit` therefore does not add an -application-owned operation to the integration's namespace. The ownership and -placement rules in [ADR 0011](../adr/0011-captured-declarations-and-installation.md) -and the [architecture policy](../policy/architecture.md) continue to govern -canonical command installation. - -Flag aliases likewise leave canonical flag definitions and typed bindings -unchanged. This is one conceptual routing layer; its internal implementation -cooperates with the existing parser to preserve token interpretation. - -## Preimplementation baseline - -At the planning baseline, core captured reusable `Command` declarations and -installed them through `New` and `App.Register`. Installation validated a batch -before registry mutation. Optional standard families owned their installed root -namespaces. Core routing and the internal backend coordinated parsing, help, -and execution through one invocation lifecycle. - -That public model had no application alias layer. PromptKit already exposed -the collection catalog and smoke-test command used in the examples below. -`promptkit test` took a `KIND` operand, including `all`; those values were not -registered child commands. The examples illustrate alternate routes to existing -capabilities; they do not introduce new PromptKit operations. - -The [CLI reference](../cli.md) owns current grammar. Options follow the complete -command path, can be interspersed with operands, and use `--` to terminate -option parsing. Aliasing preserves the target's grammar and typed binding -contracts. - -## Selected declaration and registration conventions - -Commands and aliases use the same installation boundary through `New` and -`App.Register`. Core validates the complete batch together while retaining -aliases as separate routing records internally. No separate alias-registration -API is needed. - -### Installation types and composition - -The delivered API has a common `Declaration` interface with an unexported marker -method. CommandKit supplies its implementations through public factories. `Command` -represents canonical commands; a separate opaque `RoutingRule` represents -aliases. Both satisfy `Declaration`: - -```text -Declaration -├── Command → canonical command tree -└── RoutingRule → alias routing layer -``` - -The selected installation signatures are: - -```go -func New(identity Identity, declarations ...Declaration) (*App, error) -func (a *App) Register(declarations ...Declaration) error -``` - -`NewCommand`, `Group`, and integration command factories return `Command`. -`Alias`, `FlagAlias`, and `FlagAliasFor` return `RoutingRule`. The common -installation boundary validates relationships across the layers atomically; -installation directs each declaration to its corresponding registry. Routing -rules reference canonical commands without becoming command nodes or owning -handlers. Preserve eager capture and retained construction errors for both -declaration kinds, without introducing deferred installation callbacks. - -`Group`, `RootGroup`, and command children continue to accept only `Command`. -Install routing rules alongside the completed canonical tree through `New` or -`Register`. Alias paths remain relative to the application root; moving a -command beneath a group does not silently rebase an alias. - -Use ordinary `[]Declaration` slices for reusable collections containing commands -and routing rules. Command-only helpers may return `Command` or `[]Command`. -Go does not allow expanding `[]Command` into `...Declaration`; callers assembling -installation collections should use `[]Declaration` or convert their elements. -No additional bundle abstraction is selected. - -### Consumer declarations - -Use space-separated strings for command paths, interpreted as sequences of -command names without shell quoting or expansion. Application-wide flag aliases -use `FlagAlias`; command-scoped aliases use `FlagAliasFor` with an explicit -canonical command path. The selected consumer-facing shape is: - -```go -app, err := commandkit.New( - identity, - ckprompt.Command(suite), - commandkit.Alias("list collections", "promptkit list collections"), - commandkit.FlagAlias("--hlep", "--help"), - commandkit.FlagAliasFor("promptkit show prompt", "--fmt", "--format"), -) -``` - -These APIs are implemented. Later registration uses the same model and validation. - -Accept identical duplicate alias mappings as harmless, including when reusable -helpers contribute them. Identity includes the alias kind, source, target, and -scope where applicable. Different-target command mappings for the same source -remain errors; flag scope precedence is specified below. - -Alias support lives entirely in core and works with built-in commands, -application commands, optional integrations, or any combination. Validation -uses the commands and flags installed in that application. No integration -dependency is required for alias support. Core continues to supply help and -version automatically, including for applications whose other commands are -entirely application-defined. - -### Shared path handling - -Centralize path parsing, component validation, comparison, and formatting in -shared internal helpers with a common structured path representation. Alias -validation, routing, help lookup, and invocation metadata use those primitives. -Keep the routing and canonical command models distinct while sharing path -operations. - -Declaration factories tokenize command-path strings on whitespace, accepting -leading, trailing, and repeated whitespace, then validate each component using -the canonical command-name rules. Reject empty paths and invalid components. -Normalize equivalent paths before duplicate detection. Quotes and backslashes -receive no shell interpretation; paths cannot contain flag assignments or -operand templates. Capture parsed paths once when constructing declarations. - -CLI arguments are already tokenized. Preserve those boundaries: an argument -containing `list collections` is one argument, not two command components. -Do not trim or split incoming operands or flag values. Invocation routing -identifies the command portion of the supplied tokens and carries structured -paths through alias resolution and canonical selection. Format paths for -presentation when needed, avoiding repeated string joining and parsing through -alias chains. - -Convert inputs at their appropriate boundaries and reuse the result where -practical. Parsing once per query is an implementation objective, not a permanent -allocation or parsing guarantee. Use an internal path package if sharing across -core and the backend adapter warrants it; otherwise private core helpers and a -path type suffice. No additional public path package is selected. - -## Selected command-alias behavior - -### Paths and resolution - -Declare mappings between command paths relative to the application root. The -executable name is not part of either path: - -| Alias path | Target path | -| --- | --- | -| `list collections` | `promptkit list collections` | -| `promptkit list bundles` | `promptkit list collections` | -| `list` | `promptkit list` | - -Aliases can target individual commands or groups. A group alias preserves -remaining subcommand tokens. For example, `list collections` can reach -`promptkit list collections` through the `list` group alias. - -Match exact, complete argument tokens at the beginning of the command path; -`list` does not match `listing`. Resolve overlapping alias paths using the -longest matching path, measured by the number of command-path tokens, not -character count. This rule applies at each command-alias lookup and is -independent of registration order. Sorting by descending token count and taking -the first matching prefix is one possible implementation; the algorithm remains -an implementation choice. - -For example, with `list → promptkit list` and -`list collections → application collections`, the more specific mapping wins -for `list collections`, while `list prompts` uses the `list` mapping. - -Once a matching alias is selected, resolve that route and apply canonical -validation. A validation failure reports an error; it does not retry a shorter -alias that could invoke a different command. - -Preserve trailing arguments, -including flags, operands, explicit empty values, and `--`, for canonical -parsing. Values and operands are not searched for alias text. - -The initial command-alias feature maps command paths. Preset flags, operand -transformation, and arbitrary argument rewriting are outside this delivery. - -### Chains and group composition - -Support alias chains and resolve them to their canonical target. At each lookup, -select the longest matching command-path prefix, replace it with its target, -and preserve the remaining tokens. Repeat command-path resolution until the -canonical route is reached, then parse its inputs normally. Flags, flag values, -and operands remain outside command-alias matching under the command/operand -boundary rules below. - -A group shortcut provides access to routes beneath its target, including aliases: - -```text -pk → promptkit -promptkit list bundles → promptkit list collections -``` - -Here, `pk list bundles` resolves through `promptkit list bundles` to -`promptkit list collections`. An explicitly declared `pk list bundles` alias -would take precedence over `pk` at the initial lookup. Ordinary chains follow the same -rules, for example `collections → list collections → promptkit list collections`. - -Validate composition during installation and reject cycles and nonterminating -prefix expansion with diagnostics identifying the participating mappings. -Checking only for repeated complete paths is insufficient: `a → b extra` and -`b → a` continually expand the path without repeating it. Analyze prefix -composition so these configuration errors are caught before invocation. An -arbitrary runtime hop limit is not a substitute for installation validation -and must not reject an otherwise valid long chain. - -A dependency-graph cycle or repeated use of a declaration does not by itself -establish nontermination. With canonical group `group`, the mappings `a → group` -and `group again → a` allow `a again again` to terminate: each round consumes -an `again` token. Validate actual prefix-resolution behavior, including -terminating repetitions, suffix-dependent cycles, and growing expansions. -Termination validation must distinguish these cases without conservatively -rejecting terminating repetitions. - -### Installation and collisions - -Use the shared declaration and installation conventions above for aliases, -application commands, and integration commands. - -An alias target may already be installed or be supplied in the same installation -batch. Declaration order within that batch does not affect resolution. Missing -targets, collisions, and cycles produce installation errors with useful path -context. Failed installation preserves the existing application registry and -alias mappings under the existing batch-atomicity model. - -A declared target must resolve entirely to a canonical command or group, -without leftover operand tokens. For example, reject -`Alias("fast", "run production")` when canonical `run` takes `production` as -an operand. Command aliases do not inject fixed operands. - -Likewise, `promptkit test full → promptkit test all` is invalid: `all` is an -operand of canonical `promptkit test KIND`, and the source would intercept -that command's operand space. A command-path shortcut such as -`smoke → promptkit test` is valid; `smoke all` preserves the operator-supplied -`all` operand. Synonyms for operand values require a separate capability and -are outside this delivery. - -An alias cannot conflict with or overload a canonical command path. Reject such -a declaration during installation as invalid application configuration. Apply -the same protection when later registration adds a canonical command conflicting -with an existing alias. Reject competing mappings from the same source path to -different targets; registration order must not select a winner. Identical -duplicate mappings are accepted under the shared registration conventions. - -Aliases do not create canonical parent groups, merge integration trees, or -replace handlers. - -### Prefix interactions and canonical reachability - -Alias paths may share prefixes with canonical paths when they introduce a -distinct route. Preserve existing canonical invocations, including the declared -operand space of runnable commands. - -| Canonical declaration | Proposed alias | Result | -| --- | --- | --- | -| `promptkit list collections` | `promptkit list bundles` → `promptkit list collections` | Allow the distinct route beneath the shared prefix. | -| `list projects` | `list collections` → `promptkit list collections` | Allow the distinct route beneath the shared prefix. | -| `list` group | `list` → `promptkit list` | Reject replacement of the canonical group path. | -| `run` accepts an operand | `run full` → another command | Reject interception of `full` in the canonical command's operand space. | - -Determine command and operand boundaries from declared command structure and -argument metadata, without executing handlers or application validation. -Longest-path matching chooses among valid aliases; it does not authorize -consumption of canonical operands. Sharing a runnable ancestor alone does not -establish a conflict: check whether the proposed route intercepts that -ancestor's operands or an existing canonical child route. - -Explicit longer aliases beneath an alternate spelling still use longest-match -precedence. With canonical `run TARGET`, `r → run`, and `r full → inspect`, -`r full` invokes canonical `inspect`; canonical `run full` retains its operand -meaning. If only `r → run` exists, `r full` reaches `run` with operand `full`, -which is not searched for aliases after the route resolves. Canonical operand -protection does not reserve the operand space of every alternate spelling. - -Check these conflicts against the complete candidate registry when adding -either aliases or canonical commands, including later registration. Report the -conflicting paths and preserve batch atomicity. Apply the chain and group -composition rules above when validating resolved routes. - -### Execution and help - -An invocation through an alias uses the canonical target's flags, operands, -defaults, typed bindings, input preparation, providers, diagnostics, and -outcomes. Execute the ordinary lifecycle once. Alias registration, resolution, -and help do not invoke application input/state factories or acquisition callbacks. - -Expose the original entered command path and final resolved canonical command -path as read-only invocation metadata. Both paths exclude the executable name, -flags, and operands. For a direct canonical invocation the paths are equal; -for `app pk list bundles`, they can be `pk list bundles` and -`promptkit list collections`. -Retain the endpoints through a chain; intermediate rewrites are not part of -the selected public metadata. - -Consumers can use the canonical path to identify the operation consistently -and the entered path for logging and diagnostics. CommandKit dispatch and -bindings continue to use the canonical target. Expose the paths through these -accessors, returning normalized, space-separated strings: - -```go -func (inv Invocation) EnteredPath() string -func (inv Invocation) CanonicalPath() string -``` - -Strings provide read-only values and match the declaration path representation. - -Support both help forms: - -```text -scriptorium help list collections -scriptorium list collections --help -``` - -Alias help describes the canonical target's inputs using the alias invocation -path and identifies the canonical command. Root help lists explicitly declared -command aliases separately from canonical commands, showing their resolved -canonical targets. Ordinary help need not show intermediate chain mappings or -enumerate every route reachable through group shortcuts. - -Group help includes relevant aliases separately from canonical children. For -example, `help promptkit list` shows `bundles → promptkit list collections`. -Help reached through a group alias uses that spelling in usage examples and presents the -routes available through it, including applicable aliases beneath the target. -Account for more-specific mappings so displayed destinations match routing. - -Provide discovery help for alias-only prefixes. If `list collections` and -`list prompts` are declared without a canonical `list` group, both `help list` -and `list --help` display the available routes. This help view is derived from -alias declarations and creates no canonical group or namespace ownership. -Bare `list` reports an incomplete command and points to that help. - -Routing can select this discovery-help context without selecting a canonical -command. It uses core's help metadata and applicable application-wide flag -aliases, so `list --hlep` can request the same help. It neither inherits flags -from descendant commands nor creates a canonical command node. - -Usage errors use the entered path and identify the canonical target when one -has been resolved, while preserving the canonical command's diagnostic content: - -```text -Usage: scriptorium list collections [flags] -Alias for: scriptorium promptkit list collections -``` - -If resolution fails before identifying a target, report the entered route -without assigning a canonical identity. - -## Selected flag-alias behavior - -### Spellings and scopes - -Applications can declare alternate spellings for canonical flags, including -`--hlep` mapping to `--help`. Declaring a flag alias should be as simple as -declaring a command alias, using the shared registration conventions above. -Validate each source and target as an individual flag spelling; declarations -do not accept clusters, attached values, or other argument expressions. - -Support application-wide mappings and mappings scoped to a canonical command. -The selected canonical command determines the applicable flag aliases, so a -command-scoped mapping works through every command alias that reaches that -target. A command-scoped mapping takes precedence over an application-wide -mapping for the same alias spelling. Reject different-target mappings within -the same scope; identical duplicates are harmless. Registration order does not -choose a winner, and neither scope may overload an applicable canonical flag. - -An application-wide mapping is available wherever its target flag exists and -contributes nothing elsewhere. For example, `--colour → --color` need not require -every command to define `--color`. On a command without that target, `--colour` -receives the ordinary unknown-flag error. Reusable application-wide declarations -are valid even when no currently installed command has their target flag. - -A command-scoped mapping requires its named canonical command and target flag -to exist in the complete candidate installation batch. An unavailable explicit -destination is invalid configuration. - -Application-wide mappings also apply to built-in flags at the application root -and on groups. In particular, `--hlep → --help` works wherever canonical -`--help` works, including help for alias-only prefixes. - -Later registration repeats validation against the candidate registry. Newly -installed commands gain applicable application-wide aliases automatically; -canonical spelling collisions reject the batch under the collision rules below. - -### Token interpretation - -Resolve command aliases and select the canonical command or discovery-help -context before applying its flag aliases. Use that context's flag metadata to -distinguish flag names from values. Preserve the existing grammar, including -flags interspersed with operands. - -| Input | Effect | -| --- | --- | -| `list collections --hlep` | Resolve the command path and route `--hlep` to canonical help. | -| `foo --colour=blue` | With `--colour` mapped to `--color`, preserve `blue` as the value. | -| `foo --message=--hlep` | Preserve the value `--hlep`. | -| `foo --message --hlep` | When `--message` consumes a value, preserve `--hlep` as that value. | -| `foo -- --hlep` | Preserve the operand `--hlep` after the option terminator. | - -Only tokens interpreted as flag names participate in flag aliasing. Preserve -values, explicit empty strings, and operands. The routing layer cooperates with -the existing parser rather than maintaining a separate interpretation of flag -arity, boolean syntax, or option termination. - -Match the complete flag name. Length precedence does not apply: `--out` and -`--output` are different names, and only `--out` participates in alias lookup in -`--out=value`. Use the scope precedence selected above. Resolution must -be deterministic and must not depend on registration order. - -### Canonical flag collisions - -An alias cannot conflict with or overload an applicable canonical flag spelling. -Reject conflicts during installation as invalid application configuration. -Check a command-scoped alias against that command's canonical flags, and an -application-wide alias across the commands where it applies. Apply the same -checks when later registration adds canonical declarations. Failed batches -preserve existing commands and alias mappings. - -### Canonical binding behavior - -An alias feeds the same typed binding as its canonical flag. The target retains -its value conversion, defaults, required-value checks, presence tracking, -repetition rules, and behavior. Mixed spellings retain invocation order: - -```text -foo --color red --colour blue -``` - -With `--colour` mapped to singleton `--color`, the normal last-occurrence rule -selects `blue`. Earlier invalid occurrences remain errors under the existing -conversion contract. For a repeatable target, occurrences through either -spelling accumulate in order. Alias resolution adds no second conversion or -input-preparation lifecycle. - -Flag aliases do not change canonical flag ownership or add new provider -capabilities. - -### Chains and short spellings - -Support flag-alias chains, such as `--colour → --hue → --color`. When resolving -a target, an existing canonical flag spelling terminates the chain. Otherwise, -look up the next alias using the selected context's effective mappings, with -command-scoped mappings taking precedence over application-wide mappings. -Resolve to the final canonical flag and use its binding. Validate applicable -alias-source collisions separately; a canonical endpoint does not excuse a -conflicting source declaration. - -For example, given canonical `--color` and global mappings -`--color → --missing` and `--colour → --color`, the first mapping contributes -nothing while `--missing` is unavailable. The second still reaches canonical -`--color`. If later registration makes `--missing` available in that context, -the first mapping becomes a canonical spelling collision and the batch fails. - -Apply target-availability rules to the final destination. An application-wide -chain contributes nothing where its final canonical flag is unavailable. A -command-scoped declaration must resolve to an available canonical flag. Reject -cycles during installation, identify the participating spellings in diagnostics, -and revalidate composition after later registration. - -Support individual short alias spellings, such as `-c → --color`, alongside -long aliases. Canonical short spellings and aliases use the same cluster and -attached-value grammar and may mix freely within a cluster. Resolve each alias -to its final canonical flag before determining whether it consumes a value. - -Process short spellings left to right. Boolean flags use presence as true; -explicit boolean values require `=`. The first value-taking flag consumes the -remaining suffix, removing a separating `=` when present, or consumes the next -argument if there is no suffix. Consumed values are never searched for aliases. -Unknown spellings within a cluster produce a usage error. Preserve occurrence -order for repeatable bindings and singleton last-occurrence behavior. - -With boolean aliases `-v → --verbose` and `-q → --quiet`, and value-taking -`-c → --color`: - -| Input | Interpretation | -| --- | --- | -| `-vq` | `--verbose --quiet` | -| `-c blue`, `-c=blue`, or `-cblue` | `--color=blue` | -| `-vqcblue` or `-vqc blue` | `--verbose --quiet --color=blue` | -| `-cvq` | `--color=vq` | -| `-v=false` | `--verbose=false` | -| `-qv=false` | `--quiet --verbose=false` | - -`-vfalse` is a cluster beginning with `-v`, not an explicit false value. -A spelling such as `-color` follows short-option parsing; long aliases use -the `--` prefix. Options still follow the complete command path, and `--` -ends option parsing. - -Explicit empty-value handling was corrected for both canonical short spellings -and aliases: `-c=` supplies an empty string, consistently with `--color=` and -`-c ""`. The preimplementation backend passed the literal string `"="` for `-c=`; -the delivered implementation corrects that behavior. Likewise, `-v=` supplies an -empty value to boolean conversion and fails conversion. This correction preserves the -distinction between an omitted value and an explicitly supplied empty value. - -### Flag help and diagnostics - -Present aliases alongside their canonical flags in help. Show only mappings -effective in the current scope, resolve chains to their final targets, and -document each canonical input once. For example: - -```text ---color VALUE - Output color. - Aliases: --colour, -c -``` - -When identifying an invalid occurrence in diagnostics, retain the spelling -the operator supplied and identify the canonical flag where helpful. Conversion, -required-value checks, and repetition behavior continue to come from the -canonical binding. - -## Future shell completion - -The direction for future shell completion is canonical suggestions with -alias-aware interpretation. Suggest canonical command and flag names rather -than enumerating aliases. Resolve aliases the operator has already entered so -completion can continue using the target's command structure and input metadata. - -For example, `app ` suggests canonical commands. With `pk → promptkit`, -`app pk ` can suggest canonical children available through that route. -After a complete command alias, use the target's flags and operands as the -basis for completion. Recognize manually entered flag aliases when identifying -the canonical binding whose value is being completed. Suggestions beneath a -group alias must account for more-specific mappings so their interpretation -agrees with execution routing. - -Keep validated canonical metadata and alias relationships available internally -for metadata-only lookup independently of execution and help rendering. Future -completion can reuse those records and shared path operations without parsing -rendered help or invoking application input factories and acquisition callbacks -just to discover command and flag names. This does not select a lifecycle or -provider API for future dynamic operand or value suggestions. - -Completion requests contain partial tokens and cursor context. A future -completion lookup must accommodate incomplete input without relaxing exact -matching for execution or requiring partial input to pass execution validation. -Preserve the distinction between structured paths and supplied argument tokens; -shell-specific tokenization and quoting belong to that future work. - -Shell completion itself is outside this implementation. Do not add completion -APIs, shell scripts, partial-input lookup machinery, or completion-specific -tests in this delivery. Internal lookup separation supports the current routing -and help responsibilities; it does not require a public metadata API or a -general completion framework. Shell selection, candidate presentation, and -dynamic value completion remain future design work. - -## Delivery and compatibility - -The [completed implementation plan](implementation.md) records the ordered work -from the planning baseline, implementation choices, and stage evidence for the -selected behavior. The [review remediation](remediation.md) records subsequent -findings, corrections, and validation without restarting those stages. -The delivered feature includes maintained consumer examples, GoDoc, CLI and -consumer guidance, and internal documentation matching the implemented owners. - -Consumer guidance and release notes explain migration from `...Command` to -`...Declaration`, including slice conversion, and the explicit short-option -empty-value correction under the -[release policy](../policy/release.md#versioning-and-compatibility). Nil and zero -declaration handling is documented in the -[Go declarations and GoDoc](../../command.go) alongside the invalid-zero and -explicit-absence command contracts. - -The delivery goal was to let consumers declare alternate command paths -and flag spellings with minimal wiring and invoke canonical behavior and help -through them while canonical ownership and binding semantics stay intact. Installation -rejects conflicts with canonical commands and applicable flags in either -registration order. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md deleted file mode 100644 index c2ab21e..0000000 --- a/docs/roadmap/implementation.md +++ /dev/null @@ -1,847 +0,0 @@ -# Application-owned aliases implementation plan - -Status: complete; Stages 1–17 completed. - -## Authority, baseline, and scope - -Implement [Application-owned aliases](aliases.md), governed by -[ADR 0013](../adr/0013-application-alias-routing.md), -[ADR 0011](../adr/0011-captured-declarations-and-installation.md), and the -[architecture policy](../policy/architecture.md). The feature roadmap owns the -selected behavior; this document owns the work sequence and implementation -choices. Follow the [agent](../policy/agents.md), -[testing](../policy/testing.md), and [documentation](../policy/documentation.md) -policies. Read [the developer guide](../development.md) first. - -The inspected baseline is commit `f3b8a129d99d04230f998d0327ffad05f6002d7a`. -Core v0.2.0, ckconfig v0.1.0, and ckprompt v0.1.0 have been published. -`New` and `Register` currently accept `...Command`; there are no routing-rule -declarations. `Invocation` currently contains context and streams only. -The Cobra adapter selects canonical commands, parses their flags, and renders -help. Core owns typed conversion, input construction, dispatch, and outcomes. - -This sprint delivers command and flag alias declarations, joint installation, -resolution, invocation identity, help, diagnostics, examples, and documentation. -It includes the selected canonical short-option empty-value correction. -It does not implement operand synonyms, preset arguments, shell completion, -new upstream operations, a replacement backend, or release publication. - -## How to execute the plan - -- Perform Stage 1 through Stage 17 in order. Each stage is sized as a separate - Luna implementation prompt. Add its completion evidence here and commit each - completed nonempty unit under the agent policy. -- Inspect the current tree before editing; preserve unrelated work. Prefer the - code knowledge graph for code discovery, falling back when it is insufficient. -- Reuse current behavior and tests where they express accepted contracts. - Replace mechanics when needed; do not add compatibility wrappers around the - old installation signatures or a second application parsing lifecycle. -- Stages include the focused tests needed for their work. Run those during - implementation, not during this planning pass. Do not make later stages - depend on unverified termination or token-interpretation assumptions. -- Keep tests about CommandKit adaptation, presentation, and lifetimes. Upstream - libraries own their domain tests. Use local callbacks and fixtures; no live - providers or credentials are needed. -- Preserve eager declaration capture, reusable declarations, namespace ownership, - binding identity, presence, wrapped causes, and existing outcome delivery. - Do not add concurrent-dispatch, arbitrary deep-copy, performance, or public - ordering guarantees. -- New private records and helpers described below are implementation choices. - Their names and exact organization can change without altering public behavior. - Do not expose them through the facade or add backend selection APIs. -- Keep published release records unchanged. Local source verification does not - authorize creating tags, pushing, or publishing another release. - -## Implementation decisions used by the stages - -### Owners and data flow - -| Owner | Work | -| --- | --- | -| Root `commandkit` package | Public declarations, retained errors, candidate installation, alias records, routing coordination, invocation identity, typed conversion, and outcome presentation. | -| New `internal/commandpath` package | Shared path representation and token/path operations used by core, neutral metadata, and the adapter. It has no backend or optional-library imports. | -| New `internal/alias` package | Private command-prefix lookup and termination analysis over paths; no handlers, application factories, or backend types. Keep its model limited to the selected routing rules. | -| `internal/commandmeta` | Neutral canonical metadata and the routing, spelling-provenance, and help-view records actually needed across the adapter boundary. | -| `internal/cobra` | Canonical backend sessions, alias-aware flag interpretation, and rendering selected help views without installing alias command nodes. | -| Optional integrations | Continue returning canonical `Command` declarations and owning their providers. Only source migrations, focused composition evidence, and maintained consumer changes are needed here. | - -Core retains canonical commands and routing rules separately. A candidate -installation compiles relationships against the complete prospective registry, -then publishes them together. Derived lookup metadata is reusable within an App; -parse state and entered-route provenance remain invocation-local. - -Use the same private route lookup for execution, explicit help-target lookup, -and discovery-help views. It returns a canonical command identity or a distinct -alias-prefix discovery context, plus entered/canonical paths and remaining -arguments. Keep lookup independent of execution and rendering. This is current -routing/help machinery, not a completion API. - -### Public declarations and invalid values - -Implement the roadmap's signatures: - -```go -type Declaration interface { commandkitDeclaration() } - -func New(identity Identity, declarations ...Declaration) (*App, error) -func (a *App) Register(declarations ...Declaration) error - -func Alias(path, target string) RoutingRule -func FlagAlias(spelling, target string) RoutingRule -func FlagAliasFor(commandPath, spelling, target string) RoutingRule - -func (inv Invocation) EnteredPath() string -func (inv Invocation) CanonicalPath() string -``` - -`Command` and opaque `RoutingRule` implement the private marker. Their factories -capture values and retain errors; alias factories do not return errors or run -callbacks. Keep `Group`, `RootGroup`, and `CommandSpec.Children` command-only. -`WithError` and `NoCommand` keep their current command contracts; do not add an -absence rule or a general extension/plugin declaration kind. - -A nil declaration, invalid zero `Command`, and zero `RoutingRule` are -installation errors, not no-ops. Handle nil pointers without panics; normalize -non-nil pointers to the supplied opaque declaration types to their values. -Dispatch only the supported CommandKit declaration kinds, without reflection or -calling application-defined assembly callbacks. `NoCommand` remains the explicit -absence case, with retained errors checked before it is skipped. - -An identical normalized routing rule can be contributed repeatedly. It is -idempotent, including across calls to `Register`. Do not extend that exception -to duplicate canonical command declarations. Identity uses declared kind, -source, target, and scope, not merely the final resolved endpoint: different -declared targets remain competing mappings even if they reach the same command -or binding. Invalid later registration leaves both registries and derived -metadata intact. - -Store invocation paths privately as normalized strings, populated by dispatch. -Accessors on an otherwise caller-created zero invocation return empty strings. -The original context and stream fields remain usable in keyed literals. - -### Paths and provenance - -Parse declaration paths on whitespace once at capture. Reuse canonical -one-token name validation; do not introduce a stricter name alphabet. Path -rendering, prefix comparison, normalized keys, and exact backend lookup use -shared helpers. Never split or trim already-tokenized argv elements. - -Route tokens retain their association with the original argv prefix as aliases -replace command-path components. This is needed to identify the entered path -without guessing from the length of the final canonical path. For -`smoke all` with `smoke → promptkit test`, the entered command path is `smoke`, -the canonical path is `promptkit test`, and `all` is still an operand. -For `pk list bundles`, both original `list` and `bundles` belong to the entered -path when its resolved command is `promptkit list collections`. - -Only the leading command portion participates in command rewriting. A flag or -`--` stops command-path lookup. Canonical command structure and operand metadata -establish where trailing non-option tokens become operands. Longest explicit -rules beneath an alternate spelling still take precedence as selected in the -roadmap; do not reserve all operand space beneath an alternate spelling. - -### Exact termination analysis - -Use a finite pushdown analysis of the deterministic longest-prefix rewriter. -This is private installation machinery. It avoids rejecting valid consuming -repetitions or accepting a growing loop that never repeats an entire path. -Keep it isolated so its correctness can be established before dispatch uses it. - -The implementation has two parts, split across Stages 2 and 3: - -1. Compile a prefix trie into a finite-state stack machine. The top of the - stack is the beginning of the unresolved path. Lookup remembers the deepest - matching rule, inspects only the finite source-prefix length, and restores - any inspected suffix when replacing that source with its target. A failed - longer match selects the saved shorter match; it does not invent a route. - No match halts rewriting. End-of-path and the boundary before flags are - terminal markers, never command components that a rule can consume. -2. The finite stack alphabet contains literal tokens used by rules, an `OTHER` - equivalence class for tokens not used by any rule, and an end marker. - Preserve original arbitrary tokens in the runtime resolver; this quotient - is only for proving termination. All alias sources are nonempty. -3. Normalize transitions to `(p,A) → (q,w)` with `w` of length zero, one, or two, - using finite helper states for longer pushes. Remember which original rules - participate so an error can identify mappings. The compiler's lookup and - restoration phases must be acyclic; only completing a rule can return to - the lookup start. The bottom/end marker is never popped or duplicated. -4. Compute the finite least fixed point `Pop(p,A,q)`: starting in control `p` - with top `A`, the machine can remove that symbol and finish in `q` without - inspecting the stack below it. Seed pop transitions. A one-symbol push uses - one existing pop summary; a two-symbol push composes two summaries in - left-to-right order. Retain witness information, not copies of arbitrary - stack contents. -5. Build a graph of heads `(control, top-symbol)`. A transition pushing `B` - gives an edge to `(q,B)`. One pushing `BC` gives an edge to `(q,B)` and, - for every `Pop(q,B,r)`, to `(r,C)`. A pop transition alone gives no edge. - These edges summarize nonempty paths that never pop below their starting - stack level. A directed cycle, including a self-edge, witnesses a repeatable - computation and hence nontermination. -6. Check the model's scope explicitly: installation is checking all finite - command-token suffixes, not just each bare source or target. For this - compiler, helper phases cannot run forever without returning to the lookup - start, and every finite token stack at that start is a possible input. - Therefore a repeatable computation must correspond to a possible alias - invocation; do not reject an abstract cycle introduced only by an invalid - end-marker configuration. Restrict marker transitions accordingly and - record this reasoning with the implementation tests. - -For the fixed-point step, a rule `(p,A) → (r,BC)` adds `Pop(p,A,q)` only when -both `Pop(r,B,s)` and `Pop(s,C,q)` hold for some `s`. This distinction matters: -the head-graph edge to `(s,C)` requires only the first summary and represents -continuing at `C`, rather than having removed it. - -Do not substitute an ordinary graph of alias declarations, a decreasing-length -rule, a maximum chain length, a fixed suffix-enumeration depth, or a timeout -for this analysis. Use a straightforward finite fixed point and cycle detector; -no external model-checker dependency or public automaton abstraction is needed. -Bounded examples are regression evidence, not the proof of universal termination. -If implementation exposes a flaw in the compiler or analysis, correct that -isolated stage before proceeding; do not weaken the selected alias contract. - -After termination succeeds, resolve each declared target through the same -longest-prefix semantics and require an exact canonical command/group endpoint, -with no injected operand tokens. Validate literal canonical reachability using -the complete candidate command tree and its argument bounds, without invoking -value parsers or application checks. Follow canonical child selection before -treating unmatched tokens as operands. Do not reject a route solely because a -runnable ancestor exists: it must actually intercept that command's declared -operand space or a canonical route. - -### Flag resolution and parsing - -Normalize a flag declaration into a long or individual one-byte short spelling, -without a value. Reuse the existing canonical spelling rules, allowing built-in -help as a destination. Do not interpret clusters or attached values in a rule -declaration. A command-scoped path must be an exact canonical path, not an alias -or an operand-bearing invocation. - -For each canonical command/group and the application root, form effective -mappings from application-wide rules plus command-local overrides. Include -canonical `--help` and `-h`. Resolve chains with canonical spellings as endpoints, -apply availability to the final endpoint, and validate active source collisions -separately. Application-wide missing destinations stay inactive; explicit scoped -missing destinations are errors. Detect mapping cycles, including in reusable -global chains, and recompute relationships when registration changes the context. -Discovery-help contexts have core help flags and global rules only. - -Keep the flag-name/value interpretation in the internal adapter. Use one -metadata-driven token pass for canonical and alias spellings, including mixed -short clusters. Normalize reached spellings to canonical backend flags, retain -their original occurrence spellings, and pass values/operands unchanged. -Cobra/pflag remain the backend; this pass adapts the selected token grammar and -does not convert typed application values. Do not independently scan or rewrite -tokens in core as a second flag parser. - -Once a value-taking flag consumes an attached suffix or the next token, neither -that value nor anything following `--` is searched for aliases. Explicit -boolean values require `=`; a bare boolean contributes `true`. Normalize -`-c=` as an explicitly empty value, and `-v=` as an empty value for boolean -conversion, including when these are canonical short spellings. Keep occurrence -order within each canonical binding and raw values available for the existing -typed converter; do not add a cross-binding converter-order guarantee. - -Retain private per-occurrence spelling provenance through conversion. An -internal conversion error can carry a canonical binding/occurrence index and -wrap the original cause so presentation can identify the entered spelling. -Do not rerun converters or stringify and replace their errors. Preserve -`CaptureFlags`/`FlagValues` binding identity and application-input semantics. - -## Stage 1: Introduce shared command-path primitives - -**Work** - -1. Add `internal/commandpath` with capture parsing, component validation, - equality/prefix operations, normalized keys, formatting, and owned token copies - at capture boundaries. Distinguish a root lookup path from a declaration - path: root lookup is valid; an empty alias declaration path is invalid. -2. Move or delegate the existing command-name check to the shared validator. - Migrate canonical bridge paths, exact help lookup, and core path formatting - where they currently join/split the same paths repeatedly. -3. Keep argv as tokens throughout. Do not change canonical routing, public API, - command names, or name restrictions in this refactor. - -**Evidence:** focused path tests for whitespace-normalized declarations, -literal quotes/backslashes, invalid option components, empty declarations, -root lookup, and a single argv token containing whitespace. Existing routing -and help tests remain green. - -**Completed:** Added shared command-path parsing, validation, relations, keys, -formatting, and token-copy helpers. Core command validation and path diagnostics, -plus adapter route comparison and exact help lookup, now use the shared package. -Verified with `go test ./internal/commandpath ./internal/cobra .`. - -## Stage 2: Model deterministic prefix rewriting - -**Work** - -1. Add private normalized command-rule records and longest-prefix lookup under - `internal/alias`, using Stage 1 paths. A simple trie is sufficient. -2. Implement the finite stack-machine compiler described above, including saved - shorter matches, mismatch restoration, token equivalence classes, end-marker - handling, and normalized short push transitions. -3. Add a small test interpreter for the compiled machine and compare finite - cases with the direct longest-prefix resolver. Do not expose this interpreter - or use a test step bound as the production validity decision. -4. Keep compiler phase transitions explicit so lookup/restoration cannot create - an internal loop unrelated to completing alias rewrites. - -**Evidence:** chains; overlap chosen by token count rather than character -count; target expansion; group suffix preservation; shorter fallback after -a failed longer token match; unknown tokens; empty suffixes. The compiler -and direct resolver agree on these terminating cases. - -**Completed:** Added the independent longest-prefix resolver and compiled its -trie into a finite stack machine with literal and `OTHER` symbols, end and -flag-boundary markers, shorter-match fallback, restoration, and normalized -pushes. A test-only interpreter matches direct resolution for the recorded -finite cases. Verified with `go test ./internal/alias`. - -## Stage 3: Prove and test termination validation - -**Work** - -1. Implement pop-summary saturation, head-graph construction, and cycle - detection from the implementation decisions. Return useful participating - rule context for a rejection. Document why the abstraction neither misses - growing loops nor invents invalid marker loops. -2. Cover direct cycles and `a → b extra`, `b → a`, whose paths grow without - repeating. Cover a suffix-dependent cycle using `a → b`, `b → group`, - `b x → a x`: bare `a` terminates but `a x` does not. -3. Accept consuming repetitions: with canonical group `group`, `a → group` - and `group again → a` must accept `a again again` and consume both suffix - tokens before ending at `group`. -4. Cover longest-match suppression of a potential shorter-rule loop: with - `a → b x`, `b → a`, `b x → group`, actual resolution terminates. A naive - rule-dependency cycle detector would incorrectly reject it. -5. Include a valid chain longer than any tempting small fixed hop limit and - vary rule registration order. Keep no artificial public alias-count limit. - -**Complete when:** the exact finite analysis is justified and the focused -cases distinguish it from conservative declaration-cycle or bounded simulation -checks. Do not integrate an approximate validator and defer correctness. - -**Completed:** Added worklist saturation for finite pop summaries, head-graph -construction, cycle detection, and errors naming participating mappings. -Terminal-marker transitions preserve the unique bottom marker, and tests verify -markers cannot be popped. Direct, growing, and suffix-dependent loops are -rejected; consuming repetition, longest-match suppression, and 80-rule chains -in either registration order are accepted. Verified with -`go test ./internal/alias -count=1`. - -## Stage 4: Add captured declaration types and factories - -**Work** - -1. Add `Declaration`, opaque `RoutingRule`, the three alias factories, and - private captured rule records with retained construction errors. -2. Capture and normalize command paths and flag spellings immediately. Preserve - the existing `Command` capture, `WithError`, and absence behavior. -3. Change `New`/`Register` to `...Declaration`, normalizing supported values and - pointers at the installation boundary. Keep group children command-only. -4. Convert internal `[]Command` expansions used for installation into explicit - declaration slices where necessary, including built-in assembly and affected - consumers/tests. Do not add a bundle API or generalize `Group`. - -**Evidence:** a core-only public consumer can capture mixed declarations; -invalid paths/spellings are reported at installation; nil and zero declarations -are handled as selected; canonical command-only calls continue to work. No -factories, loaders, or handlers run during capture. - -**Completed:** Added the opaque `Declaration` and `RoutingRule` types, command -and flag alias factories, eager normalized capture with retained issues, and -value/pointer normalization at `New` and `Register`. Built-in and consumer -installation slices now use declarations explicitly. Verified with root and -both integration module suites under the local workspace. - -## Stage 5: Install canonical commands and command aliases atomically - -**Work** - -1. Replace the current root-command-only pending map with a candidate containing - existing/new canonical commands and separate normalized routing records. - Reuse existing canonical placement and namespace checks. -2. Validate retained errors, exact canonical-source collisions, competing rule - mappings, prefix termination, exact resolved targets, and canonical operand - interception before publishing the candidate. Same-batch target order is - irrelevant. Missing targets and operand-bearing destinations are errors. -3. Accept identical normalized mappings, including repeated contributions across - registration calls. Revalidate existing aliases when a new canonical batch - changes reachability. Invalidate derived snapshots only on accepted changes. -4. Preserve old registry/help behavior after every failed batch. Aliases inside - an installed standard-family spelling remain routing records and never - bypass canonical root-only placement or merge command trees. - -**Evidence:** both registration orders; retained wrapped errors; duplicates; -missing/forward targets; existing and same-batch collisions; canonical children -versus runnable operand space; valid longer aliases beneath `r → run`; failed -registration after a snapshot was used. Explicitly reject -`promptkit test full → promptkit test all` under a `test KIND` fixture. - -**Completed:** Replaced direct registry mutation with a candidate that validates -the complete canonical tree and normalized routing rules before publishing. -Alias chains and termination, missing or operand-bearing targets, canonical -source and operand collisions, duplicate idempotence, later command conflicts, -and failed-batch preservation are covered. Verified with -`go test ./... -count=1`. - -## Stage 6: Compile effective flag aliases during installation - -**Work** - -1. Extend the candidate with global and canonical-command-scoped flag rules. - Build effective mappings from neutral canonical flag metadata and core help - spellings, without preparing application inputs. -2. Resolve chains, apply scoped precedence, check final availability and active - canonical-source collisions, and reject cycles. Handle long-to-short, - short-to-long, and canonical short endpoints consistently. -3. Accept globals whose destinations are currently absent. Recompute all - affected contexts when later commands arrive; reject the whole batch if a - newly active global now overloads a canonical spelling. -4. Add the root and group contexts; support the restricted help context for - alias-only prefixes. Keep command-scoped aliases local to their canonical - command rather than implicitly inheriting through descendants. - -**Evidence:** different-target duplicates versus identical duplicates; explicit -unknown scopes; inactive globals; scoped overrides inside a chain; cycles; -`--colour → --color` terminating at canonical `--color` even with an inactive -global `--color → --missing`; collision after `--missing` becomes available; -root/group help targets and failed-batch preservation. - -**Completed:** Installation candidates now compile effective global and -canonical-command-scoped flag aliases from captured canonical metadata and -built-in help spellings. Chain resolution applies scope precedence, tracks -inactive global destinations, detects cycles, and rejects newly active -canonical-source collisions without publishing failed candidates. Root, group, -command, and alias-prefix discovery contexts retain only their applicable -spellings. Verified with root and both integration module suites using the -local workspace. - -## Stage 7: Resolve entered routes to canonical commands - -**Work** - -1. Add alias lookup records to the App snapshot without adding alias nodes or - runners to the canonical command tree. Reuse the validated longest-prefix - semantics and Stage 1 paths. -2. Implement command/group rewriting with token provenance, remaining argv, - canonical selection, and a distinct discovery-prefix result. Stop path - matching at flag/terminator boundaries and canonical operands. -3. Retain the original entered endpoint and final canonical endpoint, not - intermediate chain names. Do not use the final path length to slice original - argv. Unknown paths retain the entered route without a fabricated target. -4. Ensure a failed longer explicit mapping never retries a shorter mapping. - Centralize this lookup for execution and help consumers in later stages. - -**Evidence:** `collections → list collections → promptkit list collections`; -`pk → promptkit` composed with `promptkit list bundles`; longest explicit -`pk list bundles` override; `smoke all` retaining its operand; `r full` choosing -an explicit longer route while canonical `run full` remains unchanged; -flags/values/space-containing argv tokens never becoming command components. - -**Completed:** Routing snapshots now retain canonical path metadata and the -separate command-alias resolver. Execution resolves command prefixes before -parsing, tracks the original input-token origins through alias chains, and -preserves the remaining argv. Canonical operands, flags, terminators, unknown -paths, and alias-only discovery prefixes receive distinct route results. -Verified with root and both integration module suites using the local workspace. - -## Stage 8: Integrate parser-aware flag aliasing and short grammar - -**Work** - -1. Pass the selected canonical/discovery context's effective spellings to the - internal adapter through neutral records. Keep Cobra/pflag imports internal. -2. Implement the single alias-aware token interpretation pass described above. - Canonical and aliased short flags use the same cluster logic. Preserve raw - values, explicit empties, `--`, and interspersed operands. -3. Feed canonical backend flags without invoking a typed parser twice. Collect - original spelling provenance per occurrence alongside canonical raw values. -4. Correct canonical `-c=` and boolean `-v=` at this same boundary; do not patch - aliases alone or pre-rewrite every token beginning with a dash in core. - -**Evidence:** every token example in the roadmap's flag sections; mixed -canonical/alias clusters; `-cvq` consuming `vq`; `-qv=false`; explicit empty -values for long, short, and aliased spellings; missing values; unknown cluster -members; `--message --hlep` as a value; `--message=--hlep`; post-`--` operands. - -**Completed:** The routed flag context now reaches the adapter through neutral -flag-alias records. One adapter pass interprets canonical and alternate long -and short spellings, preserves option values and terminator operands, and feeds -only canonical flags to pflag. Raw values retain per-occurrence source -spellings. Canonical short empty values now follow the same long-form boundary. -Verified with root and both integration module suites using the local workspace. - -## Stage 9: Wire execution and invocation identity - -**Work** - -1. Use the route result to select the existing canonical payload and its input - preparation. Populate both Invocation accessors for ordinary and alias - invocations, including callbacks reached by private built-in plumbing. -2. Replace the current directly constructed Invocation in the typed runner with - the coordinated context so metadata reaches handlers without changing their - signature. Retain caller context and streams. -3. Keep canonical parsing/conversion, required checks, input/state lifetimes, - `CaptureFlags`, provider acquisition, and domain outcome classification on - their existing paths. No handler delegates to another alias handler. -4. Keep failed routing, invalid flags, and help from constructing application - input or running acquisition. Preserve the existing distinction that help - still converts supplied values but skips execution-required checks. - -**Evidence:** a canonical handler observes equal endpoints directly and distinct -endpoints through aliases; operands are absent from both path strings; alias -and canonical forms reach the same binding/callback once; repeated calls and -declaration reuse do not leak invocation values; zero Invocation accessors -are empty. Existing cancellation and domain outcome checks remain green. - -**Completed:** Invocation now retains the entered and canonical route paths -alongside the caller's context and streams. Public typed handlers and private -callbacks receive the same resolved identity. Tests cover canonical and alias -calls with operands, repeated calls, declaration reuse across Apps, private -callback plumbing, and zero-value accessors. Verified with the root, ckconfig, -and ckprompt suites under the local workspace. - -## Stage 10: Add alias-aware help and discovery views - -**Work** - -1. Route `help COMMAND...` targets through the shared metadata lookup, despite - those tokens being operands of the built-in help command. Do not globally - rewrite arbitrary operands to obtain this special help-target behavior. - Keep the help command's invocation identity separate from its requested - view: `help list collections` invokes canonical `help`, while rendering the - entered target `list collections` and its resolved canonical command. -2. Coordinate `ALIAS --help`, bare canonical groups, and aliases to groups with - the same help selection. Render canonical inputs with entered usage paths - and a canonical-target annotation when the paths differ. -3. List explicit root aliases separately from canonical commands. Group views - include relevant aliases separately from children, accounting for more-specific - overrides. Do not enumerate every possible composed shortcut or chain hop. -4. Implement help for alias-only prefixes without canonical nodes or namespaces. - Bare incomplete prefixes are usage failures pointing to help. Global help - flag aliases work on these views; descendant flags do not become available. -5. Add only effective flag aliases to each canonical input's help, resolving - chains to endpoints and describing the canonical input once. Keep lookup - records independent of rendering and provider callbacks. - -**Evidence:** root/group/alias/discovery help; `help list collections` and -`list collections --hlep`; `help promptkit list` showing `bundles`; group -shortcut help with a more-specific destination override; inactive/scoped flag -visibility; no input/state factories or providers called. Preserve existing -help output-delivery handling. - -**Completed:** Help targets and `--help` routes now use shared command-alias -resolution. Canonical help views render entered usage paths with canonical -target annotations; root and group views list applicable declared aliases and -effective flag aliases. Alias-only prefixes render discovery help through -`help PREFIX` or global help spellings, while bare incomplete prefixes return a -usage failure pointing to help. Verified help selection, scoped/global -visibility, more-specific group overrides, and input/run callback lifetimes -with root and both integration module suites under the local workspace. - -## Stage 11: Preserve entered spellings in errors and delivery outcomes - -**Work** - -1. Thread flag occurrence provenance into private conversion-error context. - Identify the actual failing occurrence, including an earlier invalid value - followed by a valid overwrite. Wrap rather than replace application causes. -2. Update usage presentation to use entered command paths, identify a resolved - canonical target, and preserve the target's diagnostic content. An unresolved - route does not acquire an invented canonical label. -3. Use existing usage/operational/domain classifications and diagnostic-delivery - ownership. Route aliases must not duplicate already delivered diagnostics. - Preserve writer errors, short writes, cause identity, and incomplete reports. -4. Check alias-related help/usage presentation against failed and successful - registration so a stale snapshot does not mislabel the selected operation. - -**Evidence:** malformed aliased scalar and repeatable occurrences; mixed -spellings; wrapped `errors.Is`/`errors.As`; usage paths with canonical annotation; -unknown routes and flags; cancellation; output and diagnostic failures. Assert -semantic fragments and identities, not entire backend wording snapshots. - -**Completed:** Flag conversion failures now retain the binding, entered -spelling, occurrence number, and original wrapped cause. Usage diagnostics use -entered alias paths and identify resolved canonical commands; unresolved routes -receive no invented canonical label. Successful and failed registration during -execution preserve the selected route. Verified with root, ckconfig, and -ckprompt suites under the local workspace, including existing cancellation, -diagnostic deduplication, writer failure, short-write, and incomplete-report -coverage. - -## Stage 12: Verify registration and routing interactions end to end - -**Work** - -1. Extend public external-package tests with command-only and simulated - root-only family fixtures. Exercise construction, later registration, - retained declaration errors, reuse across Apps, and failed-batch recovery. -2. Verify canonical invocations retain their declared operand space in both - installation orders, while longer mappings beneath alternate spellings work. - Cover optional, required, and repeated operand metadata without calling - domain value converters at installation. -3. Verify same-batch alias chains and globals see the entire candidate, and - later command additions trigger full relationship validation. Check cached - lookup/help before and after successful and failed registration. -4. Include a core-only consumer proving alias infrastructure needs no optional - integration imports. Keep alias records out of the canonical handler tree. - -**Evidence:** run the focused external registration, routing, and help suites. -Fill missing cross-boundary cases rather than duplicating the private algorithm -test inventory. No concurrent-dispatch contract is introduced. - -**Completed:** External-package tests now exercise command-only and root-group -consumers using only the core import. They cover declaration ordering, alias -chains and global flags in one installation batch, canonical operand retention, -optional/required/repeated operands without installation-time conversion, -declaration reuse, retained construction errors, later registration, failed -relationship validation, failed-batch recovery, and refreshed help. The root -suite passes with `go test ./... -count=1`. - -## Stage 13: Verify typed bindings and integration composition - -**Work** - -1. Cover singleton last-occurrence behavior, conversion of every supplied - occurrence, repeatable ordering, explicit false/zero/empty presence, required - checks, and fresh invocation state with mixed flag spellings. -2. Verify captured selector bindings still reach selected typed integration - inputs. Test a command-scoped flag alias reached through a command shortcut, - and global help on standard families, without rechecking upstream semantics. -3. Add focused ckprompt composition cases for actual installed collection and - named-inspection commands, plus the valid `smoke → promptkit test` shortcut. - Use local callbacks; smoke tests should assert forwarded kind and returned - report/outcome, not perform network requests. -4. Reject the invalid smoke operand-synonym mapping against the actual - `promptkit test KIND` declaration. Preserve ordinary canonical calls in the - same application. Use a small ckconfig alias case for selector forwarding. - -**Evidence:** root binding suites and affected integration suites under the -local workspace. Do not claim nested modules' pinned core v0.2.0 graph validates -new alias APIs. See Stage 17 for independent local-source graph verification. - -**Completed:** Root binding coverage now verifies every singleton occurrence -is converted, the last value wins, repeated values retain order, explicit -false/zero/empty values remain present, required selectors are checked, and -each invocation receives fresh defaults and input state across canonical and -alternate spellings. Integration tests exercise scoped selector aliases on -installed PromptKit collection and prompt-inspection commands, the `smoke` -shortcut and returned report, failed operand-alias registration with later -canonical and shortcut calls, and global help aliases for both standard -families. Verified with the root, ckconfig, and ckprompt suites under the local -three-module workspace. - -## Stage 14: Update maintained consumer examples - -**Work** - -1. Extend `examples/core` with application command shortcuts, a group shortcut, - a global help typo alias, and a scoped flag alias. Demonstrate a mixed - `[]Declaration` collection and the two Invocation path accessors with small - application-owned behavior. -2. Extend the composed ckprompt consumer with - `list collections → promptkit list collections`, - `promptkit list bundles → promptkit list collections`, and `pk → promptkit`. - Add scoped `--fmt → --format` for named prompt inspection and - `--hlep → --help` globally. Keep canonical suite loading and domain commands - unchanged; install aliases alongside the complete canonical declarations. -3. Add the valid smoke command-path shortcut if useful for the existing local - smoke fixture. Do not represent `all` as a child command or alias target. -4. Update example tests to show aliases reaching canonical operations, help - without acquisition, and ordinary canonical commands still working. Keep - outputs local and deterministic. - -**Evidence:** root and composed-example tests pass against the new local core; -the examples remain complete, copyable artifacts. Explain local source testing -and forthcoming core dependency adoption in their developer-facing guidance; -do not claim published core v0.2.0 has alias support. - -**Completed:** The core example now installs command and group shortcuts, -global and scoped flag aliases in a mixed declaration slice, and prints entered -and canonical invocation paths. The composed example installs collection, -PromptKit group, bundle, smoke, scoped format, and global help aliases alongside -its complete canonical declarations. Example tests cover shortcut and -canonical operations, help with zero PromptKit engine loads, and local smoke -report delivery. Both example READMEs explain local-source use and that -published core v0.2.0 lacks alias support. Verified with `go test ./... -count=1` -at the root and the complete ckprompt module suite under the local workspace; -all newly documented alias commands also ran successfully. - -## Stage 15: Reconcile public and internal documentation - -**Work** - -1. Add GoDoc for `Declaration`, `RoutingRule`, factories, installation changes, - and Invocation accessors. Explain eager capture, factory errors retained for - installation, nil/zero handling, duplicate rules, and canonical scope paths. -2. Update `docs/cli.md` with implemented alias routing, command/operand - boundaries, flag scope/availability, short grammar and empty-value correction, - entered-path diagnostics, and help/discovery behavior. Preserve canonical - upstream command and report contracts. -3. Update the consumer guide and example READMEs for `[]Declaration`, direct - `Command` calls, slice conversion, and explicit root installation of rules. - Include a minimal real integration composition example and links to the - maintained complete consumers. -4. Update the internal overview and applicable architecture provisions for the - separate canonical/routing layers and joint installation. ADR 0013 already - authorizes this architecture; do not rewrite accepted decisions or add an ADR - for incidental algorithm or presentation details. -5. Update developer navigation to the roadmap/plan while work is active and - preserve `deferred.md`. Keep shell completion as future direction only. - -**Evidence:** local links and fragments resolve; volatile behavior has its -canonical owner; no future alias APIs are described as existing before their -implementation is present. Prose checks and relevant examples agree. - -**Completed:** GoDoc now distinguishes canonical `Command` declarations from -root-installed routing rules and documents captured errors, invalid nil/zero -values, idempotent duplicates, canonical flag scopes, and invocation paths. The -CLI reference, consumer guide, maintained example READMEs, internal overview, -architecture policy, and active developer navigation describe the implemented -contracts and integration wiring. Local Markdown links and fragments resolved; -`git diff --check -- '*.md' COPYRIGHT` and the cached equivalent passed. The -deferred-work record and accepted ADR were left unchanged. - -## Stage 16: Record compatibility impact for the next core release - -**Work** - -1. Prepare the next core minor release note, `docs/releases/v0.3.0.md`, with - the product title, short summary, migration guidance, and required immutable - licensing footer under the release procedure. Do not edit published notes. -2. Explain the `...Command` to `...Declaration` change, especially `[]Command` - expansion and function-value signature changes; command/group factories - still return `Command`. Note private Invocation path storage's impact on - positional struct literals and recommend keyed construction when needed. -3. Explain command/flag aliases and the explicit short-option empty-value - correction. Go 1.26.0 and the current upstream/backend selections need not - change for this feature. -4. Keep publication and real integration dependency bumps separate. The next - core must be published before dependent module release preparation downloads - that version and records actual sums, as required by `docs/release.md`. - Do not invent core v0.3.0 sums, commit local replacements, or rewrite the - integrations' existing v0.1.0 release notes. Report this release-preparation - dependency in the final implementation handoff. - -**Evidence:** note explains consumer action and candidate-local link paths and -footer are correct. No release launcher, remote push, or tag operation occurs -as part of implementing this plan. - -**Completed:** Added `docs/releases/v0.3.0.md` with the `...Declaration` -migration, command-slice conversion, function-value signature impact, -positional `Invocation` guidance, alias behavior, and `-c=` empty-value -correction. The note retains Go 1.26.0 and maintainer Go 1.26.8 and includes -candidate-tag links plus the required immutable licensing footer. No published -release note, dependency version, sum file, tag, or remote was changed. Prepare -integration dependency adoption only after core v0.3.0 is published. - -## Stage 17: Verify the complete target and finish - -**Work** - -1. Format changed Go sources and run the complete deterministic root suite and - both integration suites using the local three-module workspace described by - the developer guide. Use the documented Go 1.26.8 maintainer toolchain; this - feature does not raise the consumer minimum. -2. Root independent validation uses `GOWORK=off` and its actual module graph. - For nested modules needing unpublished local core APIs in tests/examples, - use disposable copies of each `go.mod`/`go.sum` through `-modfile`, with a - local core replacement; replace ckconfig with its local source for composed - verification where needed. Run `GOWORK=off` module suites against those - copies. Permit only disposable metadata to change and inspect it separately. - This verifies local source composition, not published-version availability. -3. Leave committed dependency constraints and genuine sums intact until their - separately authorized release preparation. Do not run nested suites against - old published core and count failures as feature failures or count old code's - success as evidence for new aliases. Do not publish dependencies to make - this implementation sprint's checks pass. -4. Confirm core still has no optional-library dependency, backend imports stay - internal, integration factories remain canonical `Command` factories, and - alias lookup requires no application/provider initialization. -5. Audit every roadmap behavior against the evidence index below. Verify - metadata paths, help views, errors, and failed-registration recovery, not - only successful alias execution. Reuse existing focused evidence rather - than creating an additional redundant test framework or release gate. -6. Run prose whitespace and local-link checks; inspect all diffs and intended - files. Mark stages complete with actual evidence, update the feature - roadmap's status, commit remaining intended work, and report validation plus - any release-preparation steps still required. Preserve completed planning - records until cleanup is requested. - -After selecting the documented toolchain and preparing the existing dependency -cache, the independent graph checks can be performed from the repository root -as follows. The workspace checks above are still needed; these commands exercise -each module's own metadata with only the indicated local source substitutions. -The temporary-file updates accommodate unpublished source without changing -tracked version requirements or synthesizing published checksums. - -```sh -( - set -eu - commandkit_alias_repo=$(pwd) - commandkit_alias_verify=$(mktemp -d /tmp/commandkit-alias-verify.XXXXXX) - trap 'rm -rf "$commandkit_alias_verify"' EXIT - export GOTOOLCHAIN=local GOWORK=off - export GOPROXY=off GONOPROXY=none GOSUMDB=off - - go test -mod=readonly ./... - - cp integrations/ckconfig/go.mod "$commandkit_alias_verify/ckconfig.mod" - cp integrations/ckconfig/go.sum "$commandkit_alias_verify/ckconfig.sum" - go mod edit -modfile="$commandkit_alias_verify/ckconfig.mod" \ - -replace="gitea.maximumdirect.net/eric/CommandKit=$commandkit_alias_repo" - (cd integrations/ckconfig && - go test -mod=mod -modfile="$commandkit_alias_verify/ckconfig.mod" ./...) - - cp integrations/ckprompt/go.mod "$commandkit_alias_verify/ckprompt.mod" - cp integrations/ckprompt/go.sum "$commandkit_alias_verify/ckprompt.sum" - go mod edit -modfile="$commandkit_alias_verify/ckprompt.mod" \ - -replace="gitea.maximumdirect.net/eric/CommandKit=$commandkit_alias_repo" - go mod edit -modfile="$commandkit_alias_verify/ckprompt.mod" \ - -replace="gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig=$commandkit_alias_repo/integrations/ckconfig" - (cd integrations/ckprompt && - go test -mod=mod -modfile="$commandkit_alias_verify/ckprompt.mod" ./...) -) -``` - -If an offline command reports an absent dependency, prepare that dependency -separately and rerun the affected check. Do not turn an offline suite into a -network-enabled test run or silently substitute older published implementation. -These local-source graph checks do not add a permanent release gate. - -**Complete when:** the accepted feature works through the public consumer -boundary, the selected checks pass against local source, documentation matches -the implementation, and no unresolved feature decisions or implementation work -remain. Publishing and dependent-version availability are separate operations. - -**Completed:** All workspace suites passed on Go 1.26.8: root, ckconfig, and -ckprompt, including maintained examples. Independent `GOWORK=off` checks also -passed for all three modules using the root module graph and disposable local -source replacements; only replacement directives changed in temporary module -files, with no sum changes. The final review confirmed core has no optional -integration dependency, backend imports remain internal, integration factories -return canonical commands, and alias composition is covered without provider -loads during help. Routing, flag interpretation, help, diagnostics, identity, -installation recovery, typed bindings, and consumer composition are covered by -the focused evidence recorded in Stages 1–14. Documentation links and -candidate-note paths resolve; prose whitespace checks passed. The alias feature -roadmap now records completed implementation while leaving core publication -and dependent integration release preparation separate. - -## Target evidence index - -| Accepted behavior | Primary stages | -| --- | --- | -| Public factories, capture, absence/zero/nil handling, slices | 1, 4, 5, 12, 15, 16 | -| Exact chains, longest matches, group composition, universal termination | 2, 3, 5, 7, 12 | -| Canonical ownership, operand boundaries, no preset operands | 5, 7, 12, 13 | -| Same-batch and later installation, duplicates, rollback | 5, 6, 12 | -| Global/scoped flag aliases, chains, endpoints, availability, collisions | 6, 8, 12, 13 | -| Values, operands, clusters, empty values, presence, repeat order | 8, 9, 11, 13 | -| Entered/canonical identity and ordinary lifecycle | 7, 9, 11, 13 | -| Root/group/alias-prefix help, effective flag help, target-aware usage | 7, 10, 11, 12 | -| Error identity, cancellation, report/diagnostic delivery | 9, 11, 13 | -| Real consumer composition and module boundaries | 12, 13, 14, 17 | -| Future-completion lookup separation without completion delivery | 7, 10, 15 | -| Migration, current references, release-note preparation | 14, 15, 16, 17 | diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md deleted file mode 100644 index 0f3e159..0000000 --- a/docs/roadmap/remediation.md +++ /dev/null @@ -1,320 +0,0 @@ -# Alias implementation review remediation - -Status: complete; R-1 through R-8 are addressed and marked individually below. - -## Review scope and evidence - -Reviewed commit `a54a9354b1a563849c31dfda906c602950016b02` against the accepted -[alias roadmap](aliases.md), [implementation plan](implementation.md), -[ADR 0013](../adr/0013-application-alias-routing.md), and applicable architecture, -testing, and documentation policies. The implementation range is -`d7cc12a..a54a935`. - -The root module's default suite passed independently with `GOWORK=off`. -Both integration default suites, including their maintained examples, passed -in the existing three-module workspace against the current local core. -These checks used Go 1.26.8 with network resolution disabled. Passing suites -do not cover the reproductions below: those failures were confirmed separately -through the public API using a disposable consumer outside the repository. -No production code or tracked tests were changed during review. - -Unless stated otherwise, reproduction commands below assume an application -named `demo`, ordinary string operand conversion, and local success callbacks. -They describe fixtures to construct through the public API, not commands -already installed by the example applications. Use semantic assertions and -supported causes when adding regression tests; do not freeze diagnostic prose -or private representations unnecessarily. - -## R-1: Protect prefixes of canonical operand space during installation - -Status: complete. Priority: P1. Category: canonical command reachability. - -**Evidence:** [traceCanonicalPath](../../registry.go#L318) uses -[acceptsOperandCount](../../registry.go#L337), which requires the source's entire -remaining token count to meet the command's minimum. This misses an alias -source that becomes a prefix of a valid invocation when more operands follow. - -With canonical `run ARG{2..2}` and a separate runnable `inspect` accepting an -optional repeated operand, installation accepts: - -```go -commandkit.Alias("run first", "inspect") -``` - -`demo run first second` then runs `inspect`, passing `second` as its operand; -the original valid `run` invocation is no longer reachable with that input. -The public probe returned status 0 from the wrong handler. - -**Required work:** Check whether a source can intercept a valid canonical -invocation, including prefixes completed by later operands, after normal -canonical child selection. Do not require that the alias source already -satisfy the command's minimum operand count. Apply this against the complete -candidate in both registration orders and preserve failed-batch atomicity. -Keep the selected distinction between canonical operand space and explicit -longer aliases beneath alternate spellings such as `r → run`. - -**Completion evidence:** Reject the example at construction and when either -side is added later; preserve the preexisting registry on rejection. Include -multi-required and repeated operands and a valid distinct child/shortcut case -so the correction does not reserve every route beneath any runnable ancestor. - -**Completed:** Installation now protects operand prefixes that can be completed -by later arguments without requiring the minimum count immediately. New -regressions failed before the correction and pass for fixed/repeated operands, -construction, both later registration orders, and rollback. Existing child and -longer-shortcut cases and the complete offline root suite passed on Go 1.26.8. - -## R-2: Select canonical routing context before validating operand counts - -Status: complete. Priority: P2. Category: unintended parsing restriction and identity. - -**Evidence:** [resolveEnteredRoute](../../route.go#L25) also uses the complete -operand-count predicate from R-1, but it examines only tokens before the first -flag. This is not enough information to determine execution arity when flags -and operands are interspersed. A known canonical command can therefore become -`routeUnknown`, disabling its aliases and discarding its identity. - -With canonical `run ARG{2..2}`, `r → run`, and scoped -`--fmt → --format`: - -| Invocation | Observed result | -| --- | --- | -| `demo r first --fmt=yaml second` | Status 2: unknown `--fmt`, although both operands are supplied. | -| `demo r first --format=yaml second` | Handler succeeds but sees `EnteredPath() == "r first"` and `CanonicalPath() == ""`. | -| `demo r first --help` | Status 0 with application-root help instead of `run` help. | - -This introduces an unrequested prerequisite: enough operands must appear -before the first option for routing metadata and flag aliases to work. -It also contradicts the selected exclusion of operands from invocation paths. - -**Required work:** Separate structural canonical selection from execution -operand-cardinality validation and from installation's operand-interception -check. Retain the selected command, its spelling context, and the actual -entered command span even when execution operands are incomplete or invalid. -Let the existing parser/input-preparation boundary validate operands after all -tokens are interpreted. Help must continue to skip missing execution-required -operands without constructing application inputs. - -**Completion evidence:** The valid interspersed invocation succeeds with -entered path `r` and canonical path `run`; partial-operand help describes that -command and recognizes its applicable aliases. Test canonical and shortcut -forms, and ensure genuinely invalid execution arity still produces usage errors. - -**Completed:** Canonical tracing now selects runnable commands structurally; -installation alone applies the operand-prefix capacity check. Runtime routing -keeps command identity and applicable flag aliases for partial or excess -operands, while input preparation retains arity validation. Regressions cover -interspersed canonical/alias flags, incomplete help, invalid arity, path metadata, -and discovery beneath a zero-operand runnable command. The excess-operand -regression failed before this change; the full offline root suite and the -additional discovery check passed on Go 1.26.8. - -## R-3: Preserve exact target lookup for the explicit help command - -Status: complete. Priority: P2. Category: help grammar regression. - -**Evidence:** [renderHelpTargets](../../execute.go#L155) reuses execution lookup -and accepts `routeCanonical` results even when remaining target tokens are -ordinary operands. It then renders the canonical view and drops those tokens. -For the `run` fixture above: - -```text -demo help r first second -``` - -returns status 0 and the help for `run`. `first second` are not registered -command components. This contradicts the [exact help-path contract](../cli.md#help) -and conflates execution operands with a help target's command path. - -**Required work:** Use an exact-target mode or explicit consumed-token result -for help lookup. After alias resolution, all target tokens must identify a -canonical command/group or a supported alias-prefix discovery view. Do not -silently accept execution operands as part of an explicit help path. Preserve -ordinary `r first second --help` behavior and help for commands whose execution -requires operands. - -**Completion evidence:** Canonical and aliased operand-bearing explicit help -targets fail with usage status 2; exact aliases, group shortcuts, and discovery -prefixes still render help without application initialization. - -**Completed:** Explicit help now requires all resolved target tokens to form -the selected path; execution operands no longer disappear into a help view. -New public-boundary regressions failed before the fix and now reject canonical -and aliased operand-bearing targets while preserving exact command/group aliases, -discovery help, and ordinary execution-form help without input initialization. -The complete offline root suite passed on Go 1.26.8. - -## R-4: Resolve discovery-help contexts through group shortcuts - -Status: complete. Priority: P2. Category: incomplete alias composition. - -**Evidence:** Discovery contexts are indexed by declared source prefixes in -[discoverFlagContexts](../../flag_aliases.go#L157), while -[resolveEnteredRoute](../../route.go#L49) searches them using the original entered -path only. A group shortcut can reach a valid alias-only prefix whose entered -spelling has no separate context entry. - -With canonical group `box`, canonical `inspect`, and: - -```text -pk → box -box admin pick → inspect -``` - -`demo box admin --help` succeeds and lists `pick → inspect`, but both -`demo pk admin --help` and `demo help pk admin` fail with status 2. -The complete `pk admin pick` route remains available through composition. - -**Required work:** Select discovery metadata through resolved group-prefix -composition while retaining the entered spelling for presentation. Reuse the -same rule precedence as execution, including more-specific mappings. Keep -discovery contexts separate from canonical command nodes and restrict their -flags to core help plus applicable global aliases. - -**Completion evidence:** Both help forms work through the group shortcut, -show `pk admin` in usage, and list the routes actually reachable there. -Cover the global help alias and a more-specific route override; do not add -canonical groups or inherit descendant flags to make discovery work. - -**Completed:** Discovery selection now checks the resolved prefix and retains -the entered route; help merges applicable entered/resolved routes and resolves -each destination through actual shortcut precedence. Regressions first failed -for the missing composed context and omitted inherited routes. Both help forms, -global help aliases, more-specific overrides, entered-only prefixes, expanded -group paths, bare-prefix usage, and descendant-flag exclusion now pass. No -canonical nodes were added. The full offline root suite and added path cases -passed on Go 1.26.8. - -## R-5: Include alias routes in help for groups without canonical children - -Status: complete. Priority: P2. Category: help discovery gap. - -**Evidence:** [routeHelpAliases](../../help_view.go#L48) returns immediately when -the selected canonical node has no canonical children. Alias records are -separate from those children, so this suppresses valid routes beneath an -otherwise empty group. - -With `Group("box", "Box group.")`, canonical `inspect`, and -`box pick → inspect`, `demo box pick` is available, but `demo box --help` -lists no `pick` route. The same problem affects help through `pk → box`. - -**Required work:** Determine relevant help aliases independently of whether the -canonical group has children. Preserve the separate display of canonical -commands and routing records; do not install fake children to fill the view. - -**Completion evidence:** Canonical and shortcut help for an empty group list -its explicit alias routes and their resolved destinations, while groups with -no such routes retain their ordinary help behavior. - -**Completed:** Group alias discovery no longer depends on canonical child -count. A new regression failed for canonical and shortcut help before the -correction, and now both help forms list the separate alias route. An unrelated -empty group's help remains unchanged and the complete route still executes. -No synthetic command children were introduced. The complete offline root suite -passed on Go 1.26.8. - -## R-6: Keep the flag interpretation pass consistent with value consumption - -Status: complete. Priority: P2. Category: canonical/alias parsing divergence. - -**Evidence:** [interpretFlagTokens](../../internal/cobra/flags.go#L28) refuses to -consume a following `--` as the value of a value-taking flag in both the long -and short branches. It subsequently treats that token as the option terminator -and stops resolving aliases. The backend still consumes `--` as the pending -flag's value, so subsequent tokens are interpreted differently by the two passes. - -For value flag `--format` and alias `--fmt → --format`: - -```text -demo show --format -- --fmt red # status 2: unknown --fmt -demo show --format -- --format red # status 0 -``` - -The canonical and aliased second occurrences should feed the same binding. - -**Required work:** Preserve value-taking arity consistently between alias -interpretation and backend parsing, including when the consumed value is `--`. -Treat a token as an option terminator only when it occupies that grammatical -role. Do not address this by banning a previously accepted flag value or by -introducing a different operand/option convention. - -**Completion evidence:** The paired invocations have equivalent outcomes and -values. Cover canonical and aliased long/short spellings, and preserve ordinary -termination when `--` occurs after a completed value or boolean flag. - -**Completed:** The alias interpretation pass now consumes the next token for -value-taking long and short flags even when that value is `--`, matching backend -arity. All four canonical/alias long/short regressions failed before the fix and -now retain the value, later alias occurrences, original spellings, and genuine -post-value terminators. Boolean/value termination cases also pass. No accepted -value was prohibited. The complete offline root suite passed on Go 1.26.8. - -## R-7: Retain entered flag spellings in parser-level usage failures - -Status: complete. Priority: P3. Category: incomplete diagnostic adaptation. - -**Evidence:** Typed flag conversion uses occurrence provenance, but -[Session.Parse](../../internal/cobra/parse.go#L89) returns normalized backend -failure text directly, and [rawValue.lastBool](../../internal/cobra/parse.go#L474) -hardcodes `--help`. Verified examples: - -- Through `r → run`, a missing value for `--fmt → --format` reports only - `flag needs an argument: --format`, omitting the entered flag spelling. -- With `--hlep → --help`, `demo show --hlep=bad` reports an invalid value for - `--help`, omitting `--hlep`; canonical short `-h=bad` likewise loses `-h`. - -The roadmap and [CLI reference](../cli.md#application-owned-aliases) require -usage diagnostics to retain the entered spelling, not only for the later -typed-conversion path. - -**Required work:** Carry the relevant occurrence context through missing-value -and built-in-help conversion failures. Retain the entered spelling, optionally -identifying the canonical target, using neutral adapter records rather than -exposing backend error types or making brittle whole-message substitutions. -Keep the existing usage classification and delivery behavior. - -**Completion evidence:** Check entered spellings for missing long/short alias -values and invalid help values, including an earlier invalid occurrence followed -by a valid overwrite. Assert the identifying fragments and existing causes -where supported; no new exact diagnostic format is required. - -**Completed:** Missing-value failures now carry the entered long/short spelling -through a neutral adapter record; earlier backend failures retain precedence. -Built-in help conversion uses the failing occurrence's original spelling, -including when a later valid value follows it. Adapter and public-boundary -regressions failed before the fix and now cover alias values, clusters, help -occurrences, entered usage paths, and input-initialization avoidance. Existing -usage classification is unchanged. The complete offline root suite passed on -Go 1.26.8. - -## R-8: Reconcile the completed feature roadmap's historical descriptions - -Status: complete. Priority: P3. Category: documentation drift. - -**Evidence:** [aliases.md](aliases.md) now declares implementation complete -but still has a `Current baseline` section saying the public model has no alias -layer, calls the implemented declarations `planned APIs`, and describes the -old `-c=` behavior as current. The consumer guide also calls the temporary -roadmap the routing-contract record despite linking the maintained CLI reference -next to it. - -**Required work:** Label the preimplementation baseline and old behavior as -historical, distinguish delivered implementation from this open review work, -and describe the now-implemented APIs accurately. Point consumer contract -navigation to GoDoc/CLI owners; retain the roadmap as planning/history, not a -second contract owner. Keep completed stage evidence historical and do not -restart completed implementation stages or rewrite published release notes. - -**Completion evidence:** Roadmap status, baseline, and API wording agree; -consumer navigation identifies the canonical owners and the open remediation -work is discoverable without claiming that these findings are already fixed. - -**Completed:** The feature roadmap now labels its preimplementation baseline -and former short-option behavior as historical, identifies the APIs as -implemented, and links this completed review separately from the completed -implementation stages. Consumer navigation points to GoDoc and the maintained -CLI contract. Published release records and completed stage evidence were left -unchanged. Local links and fragment destinations in all three affected documents -resolve, and whitespace checks pass. Final uncached offline suites passed on -Go 1.26.8: root with the workspace disabled, plus both integration modules and -their maintained examples in the existing workspace against the local core.