Remove completed alias planning and remediation documents

This commit is contained in:
2026-10-20 00:33:38 +00:00
parent f42aefe02d
commit 08ad7427e2
4 changed files with 7 additions and 1771 deletions

View File

@@ -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 <TAB>` suggests canonical commands. With `pk → promptkit`,
`app pk <TAB>` 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.

View File

@@ -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 |

View File

@@ -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.