diff --git a/docs/roadmap/aliases.md b/docs/roadmap/aliases.md index 3ca32f3..5c9b44a 100644 --- a/docs/roadmap/aliases.md +++ b/docs/roadmap/aliases.md @@ -2,7 +2,9 @@ Status: command- and flag-alias behavior and consumer API direction accepted; implementation has not started. OD-1 through OD-6 are resolved. This roadmap -records the target and work needed before implementation. +records the target and selected behavior. The +[staged implementation plan](implementation.md) owns delivery sequencing and +stage-specific validation. [ADR 0013](../adr/0013-application-alias-routing.md) records the accepted architectural ownership and shared installation decisions. @@ -235,8 +237,8 @@ establish nontermination. With canonical group `group`, the mappings `a → grou 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. -Establish focused evidence for this validation before building the rest of -routing around the algorithm. +Termination validation must distinguish these cases without conservatively +rejecting terminating repetitions. ### Installation and collisions @@ -570,51 +572,19 @@ 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. -## Work needed from the baseline +## Delivery and compatibility -1. Prepare consumer examples for the selected declaration types and shared path handling, - covering a command shortcut, a synonym inside an integration namespace, and - a group shortcut, an application-wide help flag alias, and a command-scoped - flag alias reached through a command shortcut. -2. Establish termination-validation behavior with focused evidence for valid - repetitions, suffix-dependent cycles, and growing prefix expansions before - building the rest of routing around the algorithm. -3. Implement the selected declaration types and shared path primitives. Define - and verify installation handling for nil declarations and zero `RoutingRule` - values alongside the existing invalid-zero and explicit-absence command - contracts. Validate flag declarations as individual spellings. Extend - installation to validate aliases and commands against the complete candidate - batch, preserving retained errors and atomicity. Keep aliases - independent of optional-library dependencies and backend-specific exports. -4. Integrate command and flag alias resolution with canonical routing, help, and - invocation identity. Use canonical flag metadata and the existing parser to - preserve values and operands, and reuse typed execution machinery. Apply the - selected short-option grammar and correct explicit empty values for canonical - short spellings and aliases together. Keep metadata lookup separate from - execution and help rendering as described under future shell completion, - without implementing completion in this delivery. -5. Add focused behavioral evidence for both example mappings, group aliases, - longest matches, chains, group composition, cycles and nonterminating prefix - expansion, collisions, missing targets, same-batch - resolution, later registration, argument preservation, help without - acquisition, and a single execution lifecycle. Cover application-wide and - command-scoped flag mappings, attached and separate values, option termination, - mixed canonical/alias repetitions, flag chains and scope overrides, short - aliases, mixed clusters, attached values, explicit empty-value correction, - flag help and diagnostics, and unchanged typed binding semantics. - Include discovery-help contexts without canonical commands, longer aliases - beneath operand-taking command shortcuts, rejection of operand-bearing - targets, and canonical flag endpoints alongside inactive global mappings. - Verify rejection of `promptkit test full → promptkit test all` and - preservation of the supplied `all` operand through the valid - `smoke → promptkit test` shortcut. -6. Add maintained consumer examples and update GoDoc, the CLI reference, consumer - guidance, and internal documentation when implementation lands. Validate the - affected modules under the [developer guide](../development.md). -7. Document migration from `...Command` to `...Declaration`, including slice - conversion, and the explicit empty-value correction. Include the compatibility - impact and required consumer action in release notes under the - [release policy](../policy/release.md#versioning-and-compatibility). +The [implementation plan](implementation.md) defines the ordered work from the +current baseline, implementation choices, and evidence for the selected behavior. +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 specified by the implementation plan alongside the +existing invalid-zero and explicit-absence command contracts. This delivery is complete when consumers can declare alternate command paths and flag spellings with minimal wiring and invoke canonical behavior and help through diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md new file mode 100644 index 0000000..21074ee --- /dev/null +++ b/docs/roadmap/implementation.md @@ -0,0 +1,706 @@ +# Application-owned aliases implementation plan + +Status: ready for implementation; no stages 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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. + +## 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 |