From 71d2f6d4ee00508286291a21c6304b3d6a8b3878 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Wed, 7 Oct 2026 18:24:31 +0000 Subject: [PATCH] Reconcile completed CLI planning and deferred work --- docs/roadmap/01-cli-plan.md | 941 ++++-------------------------------- docs/roadmap/remediation.md | 32 +- 2 files changed, 123 insertions(+), 850 deletions(-) diff --git a/docs/roadmap/01-cli-plan.md b/docs/roadmap/01-cli-plan.md index 5f33170..66b1940 100644 --- a/docs/roadmap/01-cli-plan.md +++ b/docs/roadmap/01-cli-plan.md @@ -1,92 +1,114 @@ -# CommandKit CLI standard proposal +# CommandKit CLI planning record -Status: proposed; no commands in this document are implemented by CommandKit. +Status: initial CLI planning complete; remaining proposals deferred. -Date: 2026-10-06. +Original review: 2026-10-06. Reconciled: 2026-10-07. -This proposal defines the command suite, operator behavior, and ownership boundary -recommended for CommandKit. Audita, Narratio, Notarius, and Scriptorium provide -evidence, rather than compatibility requirements. Adoption is expected to produce -breaking changes. The decisions recorded below are accepted; other recommendations -remain proposed. Implementation details and exact Go API declarations remain -future work. +## Purpose and current owners -The ADRs record architectural choices and their rationale. Detailed selection, -acquisition coordination, report formatting, and diagnostic-delivery mechanics -below remain proposals unless explicitly marked accepted. Their presence here -does not establish additional contracts in the ADRs. +This document preserves the initial command-suite review and identifies remaining +future work. Its completed implementation tasks and obsolete contract drafts +have been retired. The [initial feature target](initial.md) and +[completed implementation plan](implementation.md) record delivery scope and +execution history. -### Accepted planning decisions +The [CLI reference](../cli.md) owns implemented commands, syntax, formats, and +outcomes. Go declarations and GoDoc own exact exported APIs; the +[consumer guide](../consumers/guide.md) explains integration. Accepted ADRs own +architectural rationale, and the [architecture policy](../policy/architecture.md) +owns responsibility boundaries. This planning record does not define a second +current command contract. -- Use namespace/resource first: `app config show` and `app promptkit show`. - Whether the first noun describes a resource or a library namespace does not - change the command grammar or its ownership boundary. -- Assemble families from declared capabilities. Each family defines its own - supported verbs; configuration scopes expose their available operations. -- Keep ordinary version output focused on the application. Explicit - `version --scope commandkit` reports embedded CommandKit identity. -- Govern CommandKit's own behavior and provider contracts. Shared loading and - callback organization are consumer guidance. -- Put PromptKit definition inspection under the single `promptkit` family. - CommandKit does not reserve the root `prompt` and `profile` names. -- Support `config show --scope all`, with the application configuration followed - by the PromptKit configuration when registered, as separate YAML documents. -- Defer JSON output from the initial implementation. YAML supports automated - consumption as well as operator inspection; JSON may never be needed and is - not a promised later milestone. JSON Pointer remains the configuration path - syntax and is independent of report format. +## Completed initial scope -## 1. Purpose and ownership - -**Recommendation:** CommandKit owns the entire `config` command family, root help, -and version reporting. It also offers the standard `promptkit` inspection family -for applications that integrate PromptKit. Applications own commands -outside these families, such as `narratio session restore`, `narratio publish`, -`audita process`, and `scriptorium serve`. - -Ownership includes command names, accepted flags and arguments, defaults, help, -report shapes, diagnostic presentation, streams, and exit behavior. Applications -provide configuration schemas, source acquisition, domain resolution, validation, -build metadata, and PromptKit engine construction. These collaborators supply data -and perform domain work; they do not replace CommandKit's handlers or renderers. - -CommandKit assembles standard families from registered capabilities and preserves -its contracts for enabled operations. It rejects replacement standard handlers -and private operations under its reserved families. Each family defines its own -operation set; providers can supply supported subsets. Help and discovery expose -that availability. New shared operations enter through versioned library changes. -[ADR 0001](../adr/0001-command-dispatch-and-inputs.md) owns this decision. - -Applications may register context selectors and typed configuration overrides -through the extension mechanism described in section 5. This is a defined input -extension, not permission to alter standard operations or output. - -**Alternatives:** - -- **Share helpers while applications own their handlers.** Easy to integrate, - but permits the same naming, scope, and output drift that motivates CommandKit. -- **Allow arbitrary subcommands beneath standard families.** Convenient initially, - but makes the standard unpredictable and creates future name collisions. -- **Own every command in every application.** Unnecessary for the stated goals; - domain operations have responsibilities that a shared inspection library cannot - usefully prescribe. CommandKit can supply common parsing and help machinery - without owning their business semantics. - -## 2. Evidence and conclusions - -The current checkouts demonstrate both reuse opportunities and choices that need -to be replaced rather than preserved. - -| Evidence | Conclusion for the standard | +| Planning area | Delivered boundary and current reference | | --- | --- | -| Audita uses `config print-effective`; Notarius uses `config effective`; Narratio and Scriptorium use `config show`. | Select one verb: `show`. | -| Audita combines settings, selected profiles, and provenance under `--view`; Notarius uses `--scope`; Scriptorium has a separate framework configuration family. | Separate the operation from the inspected configuration scope. | -| Narratio's `config sources` reports field ownership; Scriptorium lists acquired source records. | Give source inventory and field explanation distinct contracts. | -| Scriptorium's application and framework handlers repeat parsing, loading, warnings, dispatch, and output handling. | CommandKit should implement one inspection command family. | -| Notarius and Scriptorium inspect named PromptKit profiles; Scriptorium also inspects prompts. | Definition inspection is another demonstrated shared capability. | -| Narratio compares resolved overlays, rather than YAML file text. | Include semantic comparison of effective configuration. | -| Help, flag placement, validation success output, and error statuses differ. | Specify those behaviors centrally. | -| Narratio invokes the other applications and interprets Scriptorium's status `2` as output validation failure. | Breaking adoption requires coordinated consumer updates. | +| Discovery and identity | Generated [help](../cli.md#help) and [version reporting](../cli.md#version). | +| Configuration inspection | [Scope discovery](../cli.md#configuration-scopes), validation, native display including aggregate display, sources, and path explanation. | +| PromptKit integration | Engine configuration scope and optional [named prompt/profile inspection](../cli.md#promptkit-definition-inspection), registered independently. | +| Common command infrastructure | Instance registry, typed inputs, presence, routing, and outcomes; see the [consumer guide](../consumers/guide.md) and [internal overview](../internal/overview.md). | + +CommandKit owns its standard families. Applications retain custom commands, +source selection, schema/domain work, acquisition callbacks, and executable +lifecycle. Migration of existing applications remains separate work; the +maintained [simple](../../examples/simple/README.md) and +[composed](../../examples/composed/README.md) consumers demonstrate library usage. + +## Superseded proposal choices + +The following entries are historical reconciliation notes. They summarize why +older drafts no longer describe the selected implementation; use the linked +owner for the complete current contract. + +| Earlier proposal, now superseded | Selected result and owner | +| --- | --- | +| Bare validation defaults to every scope | Configuration operations default to `app`; aggregate validation/display is explicit. See [configuration scopes](../cli.md#configuration-scopes). | +| Reject repeated singleton flags | Last occurrence supplies the value; every supplied occurrence is converted. See [registered syntax](../cli.md#registered-command-syntax). | +| Prompt inspection uses `--prompt-version` | It uses `--version`. See [definition inspection](../cli.md#promptkit-definition-inspection). | +| Rich profile reports await an upstream provider-parameter redaction API | Current public inspection supplies effective `ExtraParams`, included without additional redaction requirements. See [profile reports](../cli.md#promptkit-definition-inspection). | +| Fix application root/overlay interpretation in CommandKit, reject empty config values, and derive PromptKit selection from one prescribed root | Values and presence are passed to application callbacks, which interpret them. See [scope integration](../consumers/guide.md#a-configuration-scope) and [selection declarations](../../config.go). | +| Validation failure always emits no success report | Completed scope records can precede a later failure. See [validation](../cli.md#validate-configuration). | +| Native display has no format flag | `config show --format yaml` is accepted. See [effective display](../cli.md#show-effective-configuration) for syntax and framing. | +| Scope inventory includes description/default fields; sources use a prescribed table | The selected report shapes are defined in [scope discovery](../cli.md#configuration-scopes) and [source inventory](../cli.md#list-configuration-sources). | +| Root `app --version` is a standard entry point | The delivered entry point is `app version`; text can include revision and YAML has explicit identity fields. See [version reporting](../cli.md#version). | +| Blank definition IDs are usage failures | Missing operands are usage failures; explicitly blank values reach owning inspection and produce operational results. See [definition inspection](../cli.md#promptkit-definition-inspection). | +| CommandKit automatically coordinates shared loads and dependencies | Applications compose acquisition and may use invocation-local caches. See [consumer integration](../consumers/guide.md) and the composed example. | + +The selected namespace/resource-first grammar, capability-based family assembly, +application-focused default version, native aggregate YAML, and initial JSON +deferral remain reflected in the accepted ADRs and delivered target. The earlier +alternatives are review history, not unresolved implementation choices. + +## Deferred work and remaining proposals + +### `config diff` + +Semantic comparison is deferred pending supported upstream safe snapshot APIs. +[ADR 0008](../adr/0008-semantic-configuration-diff.md) owns its accepted comparison +and sensitivity-gap decisions. The [deferred capability target](initial.md#deferred-capability-targets) +records dependencies. + +Exact comparison selection syntax and report layout remain future design work. +The original proposal considered separate right-side root/overlay selection, +shared versus independent domain context, and an optional assertion mode. None +of those flags or modes is installed or promised by the initial implementation. +CommandKit should use owning public APIs rather than compare rendered YAML or +implement another configuration engine. + +### PromptKit catalogs + +Prompt/profile listing is deferred pending public catalog APIs. Catalog resource +names and enumeration/report details can be specified when supported APIs exist; +CommandKit does not enumerate by reparsing PromptKit configuration YAML. See the +[deferred capability target](initial.md#deferred-capability-targets). + +### Other proposals outside the initial delivery + +Configuration mutation, reloadable export, credential diagnostics, live provider +probes, shell completion, exhaustive field-origin inventories, generic value +assignment, additional component identity registration, and domain artifact +catalogs remain outside the initial scope. Their inclusion requires a concrete +operator purpose and an appropriate ownership/behavior decision. JSON remains +deferred without a commitment to add it. + +Execution, rendering, serving, and session operations remain application-owned. +Shared vocabulary is guidance under [ADR 0006](../adr/0006-command-grammar.md), +not a reserved implementation contract for every consumer. + +Application migrations should replace divergent standard paths and update +subprocess consumers and documentation for intentional breaking changes. The +original review considered Scriptorium/Notarius followed by Audita/Narratio; +that ordering is historical evidence, not a completed migration or mandatory +adoption sequence. Future capabilities can be adopted independently. + +## Historical review evidence + +The initial review on 2026-10-06 compared Audita's `print-effective`, Notarius's +`effective`, and Narratio/Scriptorium's `show`; inconsistent scope/source reports; +repeated dispatch/loading/report plumbing; and differing help, syntax, and status +conventions. Those differences informed the shared standard, rather than imposing +compatibility requirements. Narratio's subprocess interpretation of application +statuses also demonstrated the need to coordinate consumer adoption. Evidence sources, relative to this roadmap in the sibling workspace checkouts: @@ -106,757 +128,6 @@ Evidence sources, relative to this roadmap in the sibling workspace checkouts: - [PromptKit configuration inspection](../../../promptkit/configuration_inspection.go) and [consumer guide](../../../promptkit/docs/consumers/pkg-promptkit.md). -These links document review evidence; they are not build dependencies. When the -standard becomes implemented behavior, its durable reference should be owned by -CommandKit rather than relying on sibling checkout links. - -## 3. Recommended command inventory - -### Standard configuration operation inventory - -| Command | Operator question or task | -| --- | --- | -| `app help [COMMAND ...]` | How do I use this command? | -| `app version` | Which application build am I running? | -| `app config scopes` | Which configuration scopes can I inspect? | -| `app config validate` | Is the selected configuration valid? | -| `app config show [--scope app\|promptkit\|all]` | What effective configuration will the application use? | -| `app config sources` | Which inputs contributed to this configuration? | -| `app config explain --path POINTER` | Why does this path have this value, or why was it removed? | -| `app config diff --against-config PATH` or `--against-overlay NAME` | How do two effective configurations differ? | - -`app` is a placeholder for the application's executable name. Section 4 defines -scope defaults; section 5 defines selectors shared by configuration operations. - -### Optional PromptKit suite - -| Command | Operator question or task | -| --- | --- | -| `app promptkit list prompts` | Which prompt IDs and versions are available? | -| `app promptkit list profiles` | Which execution profiles are available? | -| `app promptkit show prompt ID [--prompt-version VERSION]` | What is the selected prompt's definition metadata? | -| `app promptkit show profile ID` | What execution target does this named profile resolve to? | - -**Accepted:** put this suite under `promptkit`, using the same namespace/resource -first pattern as `config`. The root names `prompt` and `profile` remain available -to applications. - -**Recommendation:** use explicit resource operands after `list` and `show`. -Plural collection names select catalogs; singular names select one definition. -This keeps prompt IDs and execution profile IDs unambiguous even when they overlap. -Registration reserves the `promptkit` family and supplies handlers for its -declared definition capabilities. Its configuration scope is a separate capability; -definition operations and configuration inspection can be integrated independently. -Configuration inspection remains `config show --scope promptkit`; the definition -commands report metadata and resolved execution targets, not a second configuration -display path. - -Definition catalogs require upstream API work; their absence today is an -implementation dependency, not evidence against a useful command standard. - -**Alternatives:** - -- **Bare `promptkit list`.** Could display a combined catalog with resource type, - ID, and prompt version. Useful for discovery, but potentially noisy. An explicit - resource gives each catalog a clear report shape; a combined listing can be - considered as an additional operation later. -- **`promptkit show ID --type profile`.** Explicit and compact, but places the - resource identity partly in a flag. Prefer the resource operand. -- **`promptkit show ID`.** Requires cross-collection lookup and ambiguity rules. - Do not make inspection depend on prompt and profile IDs being globally unique. -- **`promptkit profiles list/show`.** Retains the accepted namespace boundary and - is viable, but adds another resource grouping before the operation. The proposed - `promptkit list/show RESOURCE` layout puts the operation immediately after its - owning namespace, as in `config show`. -- **Put definitions under `config`, such as `config profile`.** Mixes source - configuration with backend-completed execution settings and gives `config` an - unrelated resource vocabulary. -- **Include only the core suite initially.** A reasonable delivery phase. Keep - individual PromptKit capabilities pending until their public APIs are available; - their absence leaves existing inspection capabilities available. - -`run`, `execute`, `render`, `serve`, `session`, and artifact catalogs are not -CommandKit-owned commands in this proposal. Recommend `run` for a new application's -principal execution operation, but retain application ownership of that choice. - -## 4. Configuration scopes - -**Recommendation:** use `--scope NAME` on configuration operations, with these -standard identifiers: - -- `app`: the application's effective configuration, including defaults, - imports, the selected overlay, explicit overrides, and recorded domain - resolution. Each application's configuration schema remains its own. -- `promptkit`: the captured configuration of the PromptKit engine assembled - from that application's selected inputs and registered assets, when integrated. -- `all`: a selector available to `config validate` and `config show`, meaning every - registered scope. It is not itself a configuration scope or a merged document. - -`show`, `sources`, `explain`, and `diff` default to `app`. `validate` defaults to -`all`: a bare validation command should establish that the configured application -and its integrated framework definitions are valid. `--scope app` provides the -explicit narrower check without constructing PromptKit. A non-PromptKit -application's `all` selection consists only of `app`. `show --scope all` is an -explicit request for a YAML stream of all selected scopes. `sources`, `explain`, -and `diff` continue to select one scope and reject `all` in this proposal. - -The differing default for validation is intentional: routine inspection starts -with the application configuration, while general validation performs a complete -configuration check. An operator can request the combined inspection explicitly. -Help must state these defaults prominently. - -`config scopes` lists scope ID, description, and whether it is the default for -inspection, together with supported operations. It uses registration metadata, -so it works when files are missing or -configuration is invalid. List `app` first, `promptkit` second when registered, -then additional scopes sorted by ID; use this same order for `show --scope all`. -It accepts `--format text|yaml` and no loading selectors. Unsupported scope names -are usage errors, with the -available names in the diagnostic; there is no fallback to `app`. - -Scopes use stable semantic names rather than executable names such as `notarius`. -Additional independently meaningful configuration scopes declare their supported -inspection operations and applicable providers. CommandKit validates declared -wiring. This roadmap proposes coordinating explicit dependencies and reusing -compatible provider results within an invocation; the coordination contract -remains API design work. Scope inventory and help report the supported operations. -An unsupported scope-operation selection receives a usage diagnostic before -acquisition. `all` retains its all-scope meaning and checks coverage for the -requested operation. [ADR 0009](../adr/0009-configuration-scopes.md) owns the model. - -A configuration scope targets configuration, while a command family targets its -own resources. A future FeedKit family could supply `list` and `show`; FeedKit -configuration inspection could separately register a configuration scope. - -**Alternatives:** - -- **Default every operation to `app`, requiring `validate --scope all`.** Very - uniform syntax, but easy to mistake application-only validation for validation - of all definitions needed by the application. -- **Separate paths, such as `config promptkit show`.** Makes the scope visible in - the command path; produces duplicated operation trees and complicates adding - scopes. This remains a viable alternative if scope flags feel too indirect. -- **A scope-keyed wrapper for `show --scope all`.** Scope identity survives parsing - in one document, but requires additional presentation work and indentation of - the native reports. The accepted initial approach keeps separate native YAML - documents; its output and ordering contract are defined below. -- **Require every inspection operation per scope.** Gives a uniform inventory. - A missing upstream operation then blocks useful existing capabilities. The - selected approach exposes operation availability explicitly. - -## 5. Shared inputs and command syntax - -### Configuration selection and overrides - -**Recommendation:** register selection inputs according to provider applicability. -`--scope NAME` selects the configuration. Providers using an application root -accept `--config PATH`; ConfigKit overlay integrations accept `--overlay NAME`. -These names retain the same meanings wherever applicable. Additional source models -can declare their own selectors through the standard input extension mechanism. - -`--config` selects the application root configuration even for `promptkit` scope; -the application constructs the selected framework inputs from that root and its -other explicit selectors. A supplied empty path is a usage error. A supplied -missing or invalid file is a load failure and never triggers discovery fallback. -Relative CLI paths use the invocation working directory. File-relative resources -retain the owning library's source-context semantics. - -When `--config` is omitted, CommandKit invokes the registered acquisition callback -with that absence preserved. It exposes supplied discovery, environment, and -default-only metadata in help. Sharing acquisition code with ordinary execution is -recommended consumer practice; execution loading and filesystem discovery remain -application choices. The detailed selection and propagation rules in this section -remain proposals for integration API design. - -`--overlay` always selects a configuration overlay, never a PromptKit execution -profile. Follow ConfigKit's naming and resolution semantics: omission, an empty -name, and the exact name `default` select the base; other names select one overlay. -An overlay name is not a file path. Replace `--config-overlay` with this standard -spelling rather than silently maintaining two conventions. - -The registration API accepts domain context selectors, such as Narratio's -`--campaign` and `--campaign-file`, and typed configuration overrides. CommandKit -parses them, exposes their declared applicability in help, and passes values to -the selected callback. Field mapping and domain checks remain callback behavior. -CommandKit validates declared combinations and applicability before loading and -reports collisions with standard flags. Shared selector names keep their defined -meaning on the operations where they are registered. - -CommandKit preserves explicit flag presence. Omission, an empty string, false, -zero, and null retain their registered meanings. Using ConfigKit's recorded -overrides and domain resolution is recommended for coherent values and provenance; -CommandKit passes typed inputs to the registered integration callback. -Execution-only controls such as resume, output directories for generated artifacts, -or lane execution do not belong on generic configuration commands. - -**Alternatives:** - -- **Require `--config` on every operation.** Simple and explicit, but makes - inspection use a different entry path from normal execution and limits - defaults-only applications. -- **Prescribe one global discovery sequence now.** Could improve consistency, - but expands this command proposal into deployment and configuration discovery - policy. Evaluate that separately rather than preserving current differences - by assumption or inventing paths without deployment evidence. -- **Only expose root, overlay, and scope flags.** Keeps the surface small but - cannot inspect Narratio's resolved campaign contributions or explicit settings - used by execution. A controlled registration mechanism is more effective. -- **Offer a generic `--set path=value`.** Convenient for advanced operators, but - requires a new value syntax and typing contract and makes overrides harder to - discover. Defer until typed, documented flags prove insufficient. - -### Flag placement and repeated flags - -**Recommendation:** put the complete command path before its options; allow flags -and operands to be interspersed within the selected leaf command. For example: - -```sh -app config show --config ./config.yml --scope promptkit -app promptkit show profile team.summary --config ./config.yml -app promptkit show profile --config ./config.yml team.summary -``` - -Standard flags use `--long-name`; `-h` is the standard help shorthand. Accept -`--name value` and `--name=value`; boolean false uses `--name=false`. `--` ends -option parsing and makes subsequent tokens operands. Standard configuration -operations reject positional operands; `promptkit list` accepts a collection name, -and `promptkit show` accepts a resource name and its one documented ID. Flags may -appear before or after these operands. `help` accepts command-path operands. - -Singleton flags reject repeated occurrences, including mixed `--name value` and -`--name=value` spellings. Repeatable source or domain flags combine in documented -order. Do not infer singleton presence from its parsed value. Unknown flags are -usage errors. New names use hyphens rather than underscores. - -This is the contract for CommandKit-owned commands. Recommend the same grammar -for application commands and supply reusable parsing machinery, while leaving -their operand counts and domain rules application-owned. - -**Alternatives:** - -- **Verb first, such as `app show config`.** Considered and not selected. It groups - operations by action but spreads one namespace across root verb families and - requires ownership at individual routes. Namespace/resource first gives each - standard family a clear ownership boundary. -- **Require flags before all operands.** Fits Go's `flag` parser directly but - retains the ordering burden the user wants to remove. -- **Allow common flags before or between command-path components.** Familiar - in some command frameworks; increases command routing complexity. A single - documented position after the complete path is sufficient initially. -- **Let the last singleton occurrence win.** Convenient for argument assembly, - but conceals conflicting operator instructions. Applications already have - useful repeatable inputs; declare those explicitly instead. - -Go's [standard flag parser](https://pkg.go.dev/flag#hdr-Command_line_flag_syntax) -stops at the first operand; [pflag](https://github.com/spf13/pflag#command-line-flag-syntax) -supports interspersed options. The accepted [backend decision](03-backend.md) -selects Cobra with pflag for the initial implementation. Any required adaptation must use -registered flag metadata, honor `--`, and correctly handle values beginning with -`-`; do not replicate Notarius's hand-maintained flag-name lists in every consumer. - -## 6. Configuration command contracts - -### `config validate` - -**Recommendation:** invoke each selected scope's declared validation capability. -CommandKit checks support and coordinates required provider calls. The provider -implements acquisition, composition, defaults, decoding, and domain resolution -according to its public result contract. The PromptKit adapter requests upstream -configuration validation with all-definition coverage. Missing upstream support -is a dependency of that capability, rather than the entire integration. -The acquisition lifecycle and dependency coordination described here remain -proposals for provider API design. - -CommandKit's validation handler requests the declared configuration-validation -operation and writes its result. Request preparation, execution, and operational -preflight belong to custom domain handlers, such as `session validate`. Source -acquisition and effects inside callbacks remain provider behavior. Registered -input applicability determines the selectors used by standard validation. - -Default text output is one concise success line identifying the validated scopes. -`--format yaml` returns a structured success report containing the scope IDs. -Warnings go to stderr and do not alone make configuration invalid. Failure emits -no success report and returns status `1`. Complete each scope's dependency loading -once; stop on a fatal loading failure rather than promising a report of every -possible defect across invalid inputs. - -Credential requirements follow the genuine configuration lifecycle: ConfigKit -loads can resolve typed secret references and therefore require the referenced -environment values, whereas PromptKit inspection does not itself resolve provider -credentials. Describe these requirements in scope help. Offline means no provider -or remote execution; it does not promise credential-independent loading. Existing -explicit credential-file bootstrap may run as part of acquisition, with its safe -report through the supplied diagnostic channel. Callback effects and bootstrap -policy remain application-owned; focused acquisition is recommended practice. - -**Alternatives:** - -- **Only check decoding/schema validity.** Useful as a distinct lower-level - operation, but too weak for an unqualified application validation command. -- **Validate only definitions selected by a planned run.** Audita provides useful - evidence for selected-profile checks, but a generic configuration command should - find invalid configured definitions before a later selection reaches them. -- **Silent success.** Scriptorium demonstrates this and scripts can use the exit - status. A short scope summary is clearer for interactive use; structured output - supports automation without parsing prose. -- **Skip secret resolution by default.** Valuable for inspection without runtime - credentials, but requires an explicit upstream ConfigKit lifecycle design. Do - not simulate credentials or bypass native validation to deliver it. - -### `config show` - -**Recommendation:** show the complete final effective configuration for the selected -scope, or each registered scope when `--scope all` is supplied. -Use the captured inspection snapshot, including recorded resolution, rather than -raw file text, an application-selected subset, or a fresh marshal of mutable -runtime structs. Loading necessarily performs the validation required to obtain -a usable snapshot. Single-scope display loads only that scope and its dependencies; -`all` loads every registered scope and reuses their shared dependencies. - -Output is native redacted YAML without a status line. A single-scope report has no -heading or document marker added by CommandKit. Preserve ConfigKit's distinction -between null, empty containers, and absent values, its -stable mapping order, and sequence order. This is an inspection document, not a -guaranteed reloadable configuration file. - -**Accepted:** `--scope all` writes the application configuration followed by the -PromptKit configuration when registered, then any additional scopes in the order -reported by `config scopes`. Each scope is a separate document, introduced by -`---` and a `# scope: NAME` comment. CommandKit adds those separators and labels -around the native writer output without merging mappings or serializing runtime -structs. Even a one-scope `all` report uses this labeled document form. - -```yaml ---- -# scope: app -server: - addr: localhost:8080 ---- -# scope: promptkit -profiles: {} -``` - -The stream provides a complete inspection in one invocation, preserves native -rendering and redaction, and avoids collisions between scopes' mapping keys. -Its tradeoffs are larger output and the need for automated consumers to decode -multiple documents. Comments are human labels, not parsed metadata; scope identity -for automated consumers follows the documented order. This is suitable YAML for -automation, but it is not one configuration document or a reloadable combined file. - -Check operation availability, acquire all selected views, and complete validation -required by their provider contracts before starting output. A scope load failure -returns `1` without a partial successful report. Writer failures can still leave -partial output. A broken PromptKit configuration can therefore prevent `--scope all` -from displaying otherwise usable application settings; `--scope app` remains -available for that narrower inspection. - -`config show` has one initial report format, YAML, and does not need a `--format` -selector. JSON is deferred without a delivery commitment. The combined display -uses existing native writers and does not require a new structured effective -snapshot API solely for formatting. - -**Alternatives:** - -- **A scope-keyed single YAML document.** Scope names become machine-readable keys, - but the renderer must wrap and indent each native document. This could replace - comment/order identification if consumers need scope identity in parsed data. -- **Emit each scope as soon as it loads.** Reduces waiting before output, but a - later load failure would leave an incomplete combined report. Prefer loading - all scopes first. -- **Raw composed input.** Shows directives and authored values, but omits defaults - and resolution and therefore answers a different question. -- **Application-defined compact views.** Audita's selected-profile summary is - useful domain reporting, but does not replace a complete effective snapshot. -- **A reloadable export command.** Potential future feature with a different - contract; do not imply that inspection output supports round trips. - -### `config sources` - -**Recommendation:** list the acquired and synthetic input sources for the selected -scope in the owning library's recorded order. Preserve every source's ID, label, -path when available, layer, kind, underlay index, and import parent location. -Do not sort sources alphabetically or flatten them into one winning file per -field. Composite and inheritance provenance belongs to explanation records. - -Default text output is a readable table; `--format yaml` returns the common source -report with an ordered `sources` sequence. Defaults-only loading may legitimately -produce an empty sequence. Defaults and domain derivations are not fabricated file -sources. Both application and PromptKit scopes use the same complete record -shape, replacing Scriptorium's differing source projections. - -**Alternatives:** - -- **Field ownership under `sources`.** Narratio's report is useful but answers - why a field has its value. Use `config explain` for that task. -- **Only list filenames.** Short, but loses underlays, non-file sources, import - relationships, and CLI contributions that help diagnose configuration. -- **YAML by default.** Suitable for automation and consistent with native - configuration reports. Prefer a table for interactive discovery and an explicit - YAML format for structured consumption. Scriptorium's current JSON default is - evidence to evaluate, not a format requirement for CommandKit. - -### `config explain` - -**Recommendation:** require `--path POINTER`; an explicitly supplied empty string -selects the root. Use ConfigKit JSON Pointer semantics, including `~0` and `~1` -escaping, mapping keys containing dots, and effective or historical paths. Omitted -path and malformed pointer are usage errors; a well-formed unknown path is a -command failure. Do not impose additional canonical-spelling restrictions beyond -the owning library's supported path contract without a demonstrated need. - -Default text output delegates to the native safe explanation writer. It includes -the effective value and presence, effective origin, composite source locations, -inheritance, chronological before/after values, resolution reasons and dependencies, -and safe secret-reference metadata when available. Historical deleted paths remain -explainable. Values receive native historical redaction. - -`--format yaml` projects the native structured explanation into CommandKit's -structured report. Keep value snapshots as records with `present`, `redacted`, and -`yaml` fields, matching the upstream representation rather than inventing a typed -value model for historical values. The `yaml` field holds native snapshot text -as a string rather than decoding it into a new value. History remains chronological. - -```sh -app config explain --path /server/addr -app config explain --scope promptkit --path '/profiles/team~1summary/model' -app config explain --path '' -``` - -**Alternatives:** - -- **One positional pointer.** Notarius demonstrates this and it is concise, but - a named flag makes the required empty root explicit and allows a future distinct - operand without ambiguity. Either convention could work if used everywhere. -- **Value-free provenance only.** Audita and Narratio demonstrate useful compact - reports; native redacted history gives a more complete explanation. A future - summary format could omit values without changing this command's meaning. -- **`explain --all` listing every field.** Useful for audits but potentially very - large and expensive. Root explanation provides a starting point; defer exhaustive - field-origin reporting until its traversal and summary contract are designed. - -### `config diff` - -**Recommendation:** compare two independently resolved effective configurations in -the same scope. The ordinary selectors define the left side. At least one of -`--against-config PATH` or `--against-overlay NAME` explicitly defines the right -side; together they can change both root and overlay. Unspecified selectors are -copied from the resolved left selection, rather than running discovery again. -An omitted right overlay inherits the left overlay; `--against-overlay default` -explicitly selects the base. Domain context selectors and typed overrides apply -identically to both sides in this version. - -```sh -app config diff --config ./config.yml --overlay staging --against-overlay production -app config diff --config ./old.yml --against-config ./new.yml --against-overlay default -``` - -For a scope declaring safe comparison support, acquire both views through the -registered provider's loading/validation contract. Compare effective values, including -defaults and recorded domain resolution, rather than YAML formatting, source IDs, -file order, or overlay names. Recursively compare mappings; keep sequences atomic, -preserving their order. Distinguish absence, null, empty mappings, and empty -sequences. Sort differences by JSON Pointer and report `added`, `removed`, and -`changed` with safe before/after snapshots. Root or container replacement must not -produce redundant descendant differences. - -Default text output is a readable change report, or `no differences` when -appropriate. `--format yaml` supplies a structured report with selection metadata, -an ordered differences sequence, and explicit information about redacted comparison -gaps. Successful comparison returns `0` whether differences exist or not. - -Compare only values that the owning library makes available for inspection. -Secret bytes must never be fetched to improve a comparison. A masked value is -not an ordinary literal string and identical masks do not prove secret equality. -Apply the union of both sides' sensitivity classifications to before/after -values so a value classified on either side cannot leak from the other report. -When sensitivity prevents comparison, identify the path as not comparable; do -not print `no differences` as an unqualified equality claim. This needs upstream -structured sensitivity metadata, not string matching on `[REDACTED]`. - -**Alternatives:** - -- **Two positional overlay names.** Narratio demonstrates a simple interface, - but it cannot also compare different root files without another syntax. -- **Fully separate left/right domain selector sets.** More flexible for campaign - comparisons; adds substantial flag duplication. Shared context covers the - existing overlay use case. Add independent contexts later if needed. -- **Diff rendered YAML lines.** Easy to implement, but formatting changes obscure - meaningful changes and identical masks conceal comparison gaps. -- **Return a special nonzero status for differences.** Useful for CI assertions, - but makes a successful inspection look like a failed command. Consider an - explicit future check mode; keep ordinary comparison successful. - -## 7. PromptKit definition inspection - -**Recommendation:** optional definition commands use the same application root, -overlay, and registered framework source selectors as `config --scope promptkit`. -They always target PromptKit, so they do not accept `--scope`. They load the engine -once and use its captured definitions without provider calls, capacity admission, -request preparation, artifact loading, or credential lookup by PromptKit. - -`promptkit list prompts` reports available `(ID, version)` pairs sorted by ID then -version; `promptkit list profiles` reports exact profile IDs sorted lexically. -IDs are identifiers, not filesystem paths, and prompt versions need not be semantic -versions. - -`promptkit show prompt ID` uses PromptKit's existing version-selection rules: -omission of `--prompt-version` works only when that ID has one available version. -Show the definition ID, selected -version, opaque equality hash, declared default profile, declared inputs, and -output contract. It does not resolve the declared default profile or render -request-specific message templates. A command to show fully rendered requests -would need inputs and belongs to application preparation such as `render`. - -`promptkit show profile ID` reports the backend-completed named execution target: -profile ID, backend, endpoint, model, configured provider controls, credential -reference name, -and whether a direct credential will be required. Do not suggest that a named -profile is the profile selected by every request, that zero indicates a provider -default, or that credential references establish credential availability. - -All four commands default to readable text and accept `--format yaml`. Report -fields and their structured YAML shapes are defined by CommandKit; arbitrary -public Go structs are not an output contract. Unknown IDs or unavailable versions -return `1`; missing -or empty required IDs and invalid argument counts return `2`. - -Provider parameter redaction belongs upstream in PromptKit. Notarius's curated -profile report is useful evidence, while Scriptorium's profile output does not -share configuration inspection's redaction contract. Establish a supported safe -profile reporting API before adding arbitrary provider parameters to the standard -report. Do not duplicate credential-name heuristics in CommandKit or assume that -raw `InspectProfile` results have native configuration redaction. - -**Alternatives:** - -- **Inspect definitions only through `config show/explain`.** Adequate for source - presence and history, but does not clearly expose backend-completed targets or - catalog discovery. -- **Show raw prompt message content by default.** Can help authors, but the current - public prompt inspection reports metadata, and request rendering is a different - operation. Add content inspection deliberately upstream if needed. -- **List definitions by parsing effective YAML in CommandKit.** Avoids new APIs, - but takes ownership of PromptKit's schema and version model. Public catalog - methods are the better boundary. - -## 8. Help and version - -### Help - -**Recommendation:** `app`, `app help`, `app --help`, and `app -h` print root help -and succeed. A command group with no execution handler, such as `app config`, -prints group help on bare invocation and succeeds. Runnable commands follow their -registered handler and operand requirements, including when they also have -subcommands. [ADR 0006](../adr/0006-command-grammar.md) records this distinction. -`app help config explain` and -`app config explain --help` print the same leaf help with status `0`. - -Help never acquires configuration, constructs PromptKit, resolves credentials, -or allocates runtime state. Generate it from registered commands and flags, -including application-owned commands, available scopes, selector applicability, -format choices, and examples. An unknown command path is a usage error. A help -request bypasses missing required operands; it does not make an otherwise unknown -command or unknown flag valid. - -**Alternatives:** - -- **Only root help.** Notarius's current leaf help errors demonstrate why this is - insufficient for an operator trying to discover arguments. -- **Error on a bare root or family.** Narratio and Scriptorium do this in some - cases. Printing help successfully makes exploration consistent; an explicitly - malformed leaf invocation still fails. -- **Maintain separate help strings.** Straightforward, but they drift from - parsing definitions. Registration should be the shared source. - -### Version - -**Accepted:** `app version` prints `app VERSION` and a newline; root -`app --version` reports the same application identity. The version command defaults -to `--scope app`. `app version --scope commandkit` explicitly reports the embedded -CommandKit release version. `--format yaml` changes presentation of the selected -identity. Version subjects are separate from configuration scopes. CommandKit -uses build metadata with acquisition callbacks left uninvoked. - -Registration of future component identities remains an API design proposal. -[ADR 0004](../adr/0004-standard-inspection-surface.md) records version subjects; -this roadmap retains the selected command syntax. - -Applications supply build identity, with tagged Go build information usable when -available. An unversioned development build reports `dev`; unknown revision or -build time stays absent rather than being invented. The CommandKit release version -identifies the library and its standard CLI contracts. Compatibility changes -follow the [release policy](../policy/release.md#versioning-and-compatibility). - -**Alternatives:** - -- **Only the command or only the flag.** Either could be consistent; supporting - both familiar discovery paths costs little and gives them one implementation. -- **Emit all build and dependency information by default.** Helpful for debugging, - but unnecessarily verbose and unstable for a simple identity check. Structured - output should expose the selected fields. -- **List dependency versions alongside application version by default.** Adds - diagnostic detail to an identity check. Explicit subject selection keeps each - report focused. -- **Use a combined dependency-version option.** Useful for a broad inventory. - Scoped selection also supports querying one embedded component. -- **Add a separate integer CLI standard revision.** Rejected during ADR review. - The tagged CommandKit release version provides the shared compatibility identity. - -## 9. Output, diagnostics, and failures - -**Recommendation:** successful reports go to stdout; warnings, loading diagnostics, -bootstrap reports, and errors go to stderr. Emit each diagnostic once, retain -library source coordinates and source-ID legends, and use library-safe messages. -No progress messages or banners may enter report output. - -| Operation | Default | Other initial format | -| --- | --- | --- | -| `help` | text | none | -| `version` | text | YAML | -| `config scopes`, `validate`, `sources`, `explain`, `diff` | text | YAML | -| `config show` (one scope or `all`) | YAML | none | -| `promptkit list/show` | text | YAML | - -Format names are lowercase. Unsupported formats are usage errors. Use `--format` -consistently for commands that offer text and YAML; do not add a selector to -YAML-only `config show`. Structured reports other than the native `config show` -documents use a defined operation-specific schema and the applicable scope or -selection metadata. Define their exact YAML field shapes before implementation; -do not make native explanation prose or Go struct field spelling a machine -contract. Structured YAML reports contain one document with a trailing newline; -`config show --scope all` deliberately uses a multi-document stream. - -**Accepted:** defer JSON output for the initial implementation across the suite. -YAML is suitable for automated consumption, and the native inspection writers -already preserve its value semantics. There are no initial JSON format flags, -JSON-specific report schemas, or JSON-driven upstream API requirements. Adding -JSON is optional future work only if a concrete need emerges; it may never be -needed. JSON Pointer paths remain supported independently of output format. - -Inspection formats use upstream secret classification; there is no unredacted -output option in this standard. Redaction does not classify every sensitive prompt -or arbitrary application value. The proposal preserves library confidentiality -semantics rather than promising that every report is safe for public disclosure. - -Default to stdout and shell redirection; do not initially add `--out` or `--output` -to standard reports. Ordinary writer failures may leave partial output and return -`1`; checking status before decoding is recommended caller practice. This avoids adding filesystem -creation, replacement, and retention behavior to inspection. - -| Status | CommandKit-owned command meaning | -| --- | --- | -| `0` | Successful operation, including help, valid configuration, or comparison that found differences. | -| `1` | Loading, validation, lookup, explanation, comparison, cancellation, diagnostics delivery, or output failed after valid syntax. | -| `2` | Unknown command/flag/scope, invalid format, missing or malformed argument, repeated singleton, or invalid flag combination. | - -Applications retain domain result statuses for their own commands. CommandKit must -not globally reinterpret Scriptorium's execution validation status or Notarius's -artifact rejection semantics. Common usage errors can use the shared status `2`, -but business outcomes remain explicit application mappings. - -**Alternatives:** - -- **Structured YAML everywhere by default.** Works for automation, but text help, - tables, and native explanations are useful for interactive inspection. Offer - YAML explicitly where the default is text. -- **JSON as an additional output format.** Deferred by the accepted decision. - It would add serializers, report contracts, and possible representation issues - without a demonstrated benefit over the initial YAML reports. -- **An output-file flag on every command.** Convenient but duplicates shell - redirection and introduces file semantics. Add it later if concrete consumers - need behavior beyond redirection. -- **One nonzero status for every failure.** Narratio and Scriptorium demonstrate - simplicity, but distinguishing malformed invocation from a failed valid command - is useful and already demonstrated by Notarius. -- **One exit policy for all application execution outcomes.** Would exceed the - ownership boundary. Coordinate changes to owned commands without claiming domain - statuses for unrelated commands. - -## 10. Implementation dependencies and delivery - -**Recommendation:** implement the common command behavior against narrow inspection -providers, with ConfigKit and PromptKit retaining ownership of configuration -semantics. Publish upstream API improvements before adopting them in CommandKit -and the applications. Do not import sibling `internal` packages or turn source -checkout proximity into an architectural dependency. - -Existing public APIs already support native YAML, native explanation text, -structured explanation records, source records, and named definition inspection. -They do not yet provide everything recommended here: - -| Needed capability | Implementation work for that capability | -| --- | --- | -| Semantic diff | A safe structured effective snapshot from ConfigKit, preserving value semantics and per-path sensitivity; expose it through PromptKit inspection. This serves comparison rather than JSON output. | -| Combined configuration display | Compose native writers as labeled separate YAML documents after all selected scopes load; no new snapshot API is needed just to concatenate these reports. | -| Prompt/profile catalogs | Public PromptKit methods enumerating captured IDs and prompt versions without reparsing source YAML. | -| Safe rich profile reports | PromptKit-owned redacted inspection data for provider parameters. | -| Narratio's final application snapshot | Adapt its configuration boundary so campaign-derived effective values and provenance are recorded in the inspected result; avoid an unrelated typed-struct dump. | -| Cross-scope validation | Registered validation capabilities and dependencies, with their actual acquisition and credential requirements exposed in help. | - -Suggested sequence: - -1. Resolve the remaining proposed command contracts and alternatives, preserving - the accepted planning decisions above. -2. Define the structured YAML report schemas and minimal upstream inspection - additions. Record accepted ownership decisions in durable architecture - documentation. -3. Implement core dispatch, syntax, help, version, scopes, validation, native - display (including `show --scope all`), source inventory, and explanation using - existing APIs. -4. Integrate Scriptorium and Notarius to exercise both scopes and remove duplicated - handlers. Register and report the supported capabilities; additional upstream - features can be integrated independently. -5. Add safe semantic comparison and additional PromptKit definition capabilities - as their upstream APIs are released. -6. Integrate Audita and Narratio, moving domain reports outside reserved families - and aligning their standard operations. Update consumer adapters and docs for - the intentional breaking releases. - -CommandKit installs supported operations with their standard meanings and exposes -actual capabilities in help and scope metadata. Missing comparison or catalog -support leaves other operations available. Each family's resources determine its -supported verb set. Initial ConfigKit/PromptKit reports retain their chosen formats; -future families define suitable report contracts for their own resources. - -Later implementation validation should exercise genuine contract risks: help with -invalid configuration, leaf flag placement and `--`, explicit empty/false/zero -overrides, source order, historical paths, independent diff selections, sensitivity -changes between sides, multi-document scope order, all-scope load failures before -output, warning delivery and failed writers, and Narratio's subprocess consumers. - -Breaking adoption replaces divergent spellings and behavior. Compatibility aliases -are not required; introduce one only for a concrete transition need with an explicit -retirement decision. Application execution commands outside the reserved suite -remain independently owned, even when their implementations use CommandKit helpers. - -**Alternatives:** - -- **Extract one existing application's command family unchanged.** Fast, but - carries its omissions and incidental decisions into the standard. Use existing - implementations to inform and exercise the selected contract instead. -- **Build one universal runtime/application framework.** Could absorb more code, - but would expand ownership into lifecycle and domain execution without improving - the demonstrated inspection boundary. -- **Implement missing upstream semantics inside CommandKit.** Avoids release - coordination, but duplicates configuration projection, redaction, and definition - knowledge. Those responsibilities should remain with the libraries that own them. - -## 11. Explicitly deferred commands - -**Recommendation:** defer configuration mutation (`set`, `edit`, `init`, `migrate`), -reloadable export, credential diagnostics, live provider probes, completion -installation, exhaustive field-origin inventories, request preparation, and domain -artifact catalogs from this standard. Their semantics are not established by the -repeated inspection code under review. Add a shared command when its operator -purpose and ownership can be specified as clearly as the suite above. - -JSON output is also deferred, with no assumption that it will eventually be added. - -**Alternatives:** - -- **Add a generic `doctor` command now.** Attractive for troubleshooting, but - mixes offline configuration, credentials, network health, and domain resources. - Specify those checks before choosing a shared name and success meaning. -- **Standardize `run` in this first suite.** Could further improve vocabulary, - but requires comparing execution semantics and their consumer contracts. A - recommended verb is useful now; reserving its complete contract is separate work. +These links identify sibling-checkout evidence from that review. They are not +build dependencies, permanent implementation references, or claims about the +applications' present adoption status. Current contracts are owned in CommandKit. diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md index ae16b4f..4161416 100644 --- a/docs/roadmap/remediation.md +++ b/docs/roadmap/remediation.md @@ -1,6 +1,6 @@ # Documentation reconciliation work -Status: required updates recorded; reconciliation pending. +Status: reconciliation in progress. Date: 2026-10-07. @@ -26,48 +26,50 @@ Check each item when its documentation changes and review are complete. Owner: [01-cli-plan.md](01-cli-plan.md). -- [ ] Replace the status claiming that no commands are implemented. Identify +- [x] Replace the status claiming that no commands are implemented. Identify implemented operations, superseded proposals, and deferred features. -- [ ] Reconcile configuration scope defaults: every implemented configuration +- [x] Reconcile configuration scope defaults: every implemented configuration operation defaults to `app`; aggregate validation/display requires explicit `--scope all`. Retire the recommendation and rationale for validation defaulting to `all`. -- [ ] Replace singleton-repetition rejection with the selected last-occurrence +- [x] Replace singleton-repetition rejection with the selected last-occurrence rule, including conversion of every supplied occurrence. Remove repetition from the list of usage failures and label the old alternative as superseded. -- [ ] Replace obsolete `--prompt-version` examples and descriptions with the +- [x] Replace obsolete `--prompt-version` examples and descriptions with the implemented `--version` spelling. -- [ ] Retire the upstream redaction prerequisite for rich profile reports. +- [x] Retire the upstream redaction prerequisite for rich profile reports. Record that effective `ExtraParams` is included using the current public PromptKit API, without introducing additional redaction requirements. -- [ ] Remove CommandKit mandates for application root paths, rejection of empty +- [x] Remove CommandKit mandates for application root paths, rejection of empty config values, overlay interpretation, and propagation from one application root into PromptKit. Values and presence reach application callbacks; those callbacks own their interpretation and acquisition paths. -- [ ] Reconcile aggregate validation output: completed scope records may already +- [x] Reconcile aggregate validation output: completed scope records may already have been written when a later acquisition or output fails. Retire the claim that failure always produces no success report. -- [ ] Reconcile native display syntax: `config show --format yaml` is accepted. +- [x] Reconcile native display syntax: `config show --format yaml` is accepted. Link to the current framing contract rather than maintaining another report reference. -- [ ] Retire the proposed scope inventory fields for descriptions/default +- [x] Retire the proposed scope inventory fields for descriptions/default indicators and the proposed source-table presentation as current expectations. Link to implemented scope/source report shapes in the CLI reference. -- [ ] Remove the claim that root `app --version` is supported. Reconcile identity +- [x] Remove the claim that root `app --version` is supported. Reconcile identity presentation with the implemented version command, optional text revision, and explicit YAML fields. -- [ ] Distinguish a missing definition ID operand from an explicitly blank ID: +- [x] Distinguish a missing definition ID operand from an explicitly blank ID: missing is usage failure; blank values reach the owning inspection API and produce operational results. -- [ ] Remove promises of automatic shared dependency reuse or mandatory +- [x] Remove promises of automatic shared dependency reuse or mandatory acquisition coordination. Describe application-composed loading and optional invocation-local caching as consumer integration patterns. -- [ ] Keep diff and PromptKit catalogs explicitly deferred. Retire completed +- [x] Keep diff and PromptKit catalogs explicitly deferred. Retire completed dispatch/report implementation tasks and the obsolete profile-report upstream dependency. Keep consumer migrations separate from library implementation. -- [ ] Label superseded alternatives and dated sibling-checkout evidence clearly. +- [x] Label superseded alternatives and dated sibling-checkout evidence clearly. Replace duplicated current contracts with concise summaries and canonical links. +**Completion:** Retired completed CLI work and reconciled obsolete choices; current contracts link to their owners and future work remains explicit. + ## D-02: reconcile dispatcher planning Owner: [02-dispatch.md](02-dispatch.md).