Clarify application error handling and reporting ownership

This commit is contained in:
2026-10-24 01:50:38 +00:00
parent 085c296d89
commit ec29d658b7

View File

@@ -3,7 +3,8 @@
Status: initial planning. Message categories, all four output modes, uniform
treatment of help and version, message prefixes, and OD-1's flag grammar and
scope (including independent Progress control) are selected.
OD-2's unified reporting direction and the terminal failure model are selected.
OD-2's unified reporting direction, the terminal failure model, and application
ownership of error handling are selected.
Exact API signatures, failure explanation details, retention, and delivery
mechanics remain open. Implementation has not started.
@@ -19,6 +20,30 @@ straightforward. Design reporting conveniences around the shared output policy
and invocation lifecycle. Applications continue to own their report content,
domain behavior, and operation outcomes.
## CLI presentation and error-handling ownership
Applications decide how to handle errors from their operations: recover, retry,
continue silently, report a Warning, or end the invocation with a failure.
A Go `error` does not determine a CLI message category. Warnings may describe
issues with or without an underlying Go error, and handling an error does not
require emitting a message.
CommandKit handles the presentation the application requests: message category,
visibility, formatting, timing, and delivery. For terminal application failures,
the application supplies a non-zero outcome and an operator-facing explanation.
Reporting does not require the underlying Go error or undertake its tracking,
recovery, or identity preservation.
A convenience helper that explicitly presents `err.Error()` as a Warning could
fit this boundary. Such a helper would only convert the supplied error to a
message at the application's request; its inclusion and signature remain open.
CommandKit retains responsibility for handling its own errors, including
routing, parsing, and reporting failures. Integration-owned commands similarly
adapt their upstream APIs into deliberate command outcomes and presentations.
This boundary governs application error handling; ordinary Go error returns
from CommandKit APIs and writers remain available where appropriate.
## Current baseline
[`Streams` and `Invocation`](../../identity.go) expose caller-selected output
@@ -49,7 +74,7 @@ Distinguish substantive application output from diagnostic message categories:
- **Error:** Terminal presentation of an unrecoverable invocation failure,
resulting in a non-zero status code.
- **Warning:** Something went wrong or deserves attention, but the invocation
can still succeed. A recovered problem is a warning.
can still succeed. The application chooses whether to report such an issue.
- **Info:** Informational context and useful explanation, such as which profile
was selected or a final operation summary.
- **Progress:** Streaming updates about work underway, such as items processed.
@@ -77,9 +102,8 @@ Applications and integrations are not required to generate messages in any
category. Enabling a category adds no output when there are no messages in it;
other output remains subject to its own visibility rules.
Error presentation follows the terminal failure model below. Problems from
which the invocation recovers are warnings, even when an attempted operation
failed internally.
Error presentation follows the terminal failure model below. An application
may report a recovered problem as a Warning or continue without a message.
Apply the same policy to help and version. There are no command-specific
exceptions for successful output:
@@ -120,15 +144,12 @@ The same boundary applies to core routing and parsing failures that prevent
handler execution. The application entry point retains ownership of process
exit; CommandKit ends the invocation and returns its outcome.
For example, a handler returns immediately on an unrecoverable failure:
```go
result, err := performOperation()
if err != nil {
return commandkit.Failure(err)
}
// Continue normal reporting only after successful operation.
```
For example, if an export operation fails and the application decides it cannot
continue, the handler returns a non-zero outcome with an explicit explanation
such as "Unable to export the requested report." The application can choose to
include detail from a Go error in that explanation. CommandKit presents the
supplied explanation without automatically deriving text from an application
error. The exact failure-construction API remains open under OD-3.
Output streamed before the failure remains visible according to its selected
mode; terminal failure does not withdraw earlier bytes. Deferred messages,
@@ -295,9 +316,9 @@ output is not part of the proposed direction.
Keep errors understandable in every mode, including source locations and
related explanatory context. Unrelated warnings and informational messages
remain subject to the selected mode. Retain suppressed diagnostics for
programmatic inspection rather than equating suppression with loss of evidence.
The exact representation of retained and delivered diagnostics remains open.
remain subject to the selected mode. Whether to retain submitted messages for
programmatic inspection, including suppressed messages, remains open under
OD-3. This concerns presentation records, not application error tracking.
## Selected consumer reporting API direction
@@ -332,7 +353,8 @@ application domain classification. CommandKit presents a failed outcome through
the same reporting facility as the terminal step. Error explanations belong to
that returned failure, including rich upstream explanations. Typed diagnostic
submission must preserve this relationship instead of permitting independently
emitted Error messages during normal execution.
emitted Error messages during normal execution. Application failures carry
explicit status and presentation content; they do not require a Go error cause.
Use the reporter as the common diagnostic submission path, replacing the earlier
proposal to split submission between a reporter and `Outcome.Diagnostics`.
@@ -354,9 +376,12 @@ those capabilities through the shared CommandKit presentation policy.
Support consistent reporting of ConfigKit errors and warnings as its adopted
public API evolves. This roadmap does not assume that a future warning API
already exists or prescribe its upstream shape. Preserve useful native
diagnostic detail and supported error identity, and coordinate returned errors
with diagnostics that already explain them.
already exists or prescribe its upstream shape. Integration-owned commands
select the outcome and submit useful native diagnostic detail for presentation.
Core presents those records under the shared policy; it does not infer an
application's recovery decisions or classify arbitrary Go errors. Applications
using upstream libraries directly retain the same choice over outcomes and
messages as for their other operations.
Debug output follows the same upstream disclosure and safe-rendering contracts.
Enabling debug does not authorize secret disclosure or bypass owning-library
@@ -368,6 +393,8 @@ rules.
immediate and deferred diagnostics, failure after partial output, help and
version, and integration diagnostics in every mode. Include applications that
emit no Progress messages and the distinction between Info and Progress.
Cover silent recovery, an explicit Warning with or without a Go error, and a
terminal failure with an explicit explanation and no Go error cause.
2. Review current diagnostic batching, parsing, help, outcome presentation, and
writer ownership to identify the smallest shared changes. Include invocation
failures that occur before a handler receives its `Invocation`.
@@ -388,23 +415,33 @@ rules.
reporting after terminal error presentation, including deferred and late
writes under the selected OD-4 behavior.
6. Update GoDoc, the CLI reference, consumer guidance, and release documentation
when implemented. Review whether any resulting architectural change needs an
ADR; exact reporting APIs and flag syntax remain API/CLI contracts.
when implemented. Reconcile the selected error-handling boundary with
ADR 0005's existing outcome and error-identity commitments before changing
those contracts. Record any resulting architectural change in a new ADR;
exact reporting APIs and flag syntax remain API/CLI contracts.
## Open Decisions
### OD-3: Failure presentation and diagnostic retention
The terminal failure model is selected above. How are detailed explanations
attached to the returned failure, including application domain failures? How
are recovered upstream problems represented as warnings while preserving their
native context? Which contextual records belong to a terminal error explanation?
How are mixed upstream
diagnostic batches filtered while preserving useful native rendering? What is
retained when presentation is suppressed, and how is duplicate presentation
prevented without hiding unrelated failures?
How do adapters apply the selected prefixes to mixed or already-labelled native
diagnostics? What presentation should streaming Progress use?
The terminal failure model and application error-handling boundary are selected
above. The remaining questions concern explicit presentation content:
- How does a handler supply a non-zero outcome with a simple explanation or
multiple structured explanatory records, including application domain failures?
- How do callers and integration adapters identify the context belonging to a
terminal explanation, and present mixed diagnostic batches while preserving
useful native rendering and applying visibility to independent messages?
- Which submitted messages, if any, are retained for programmatic inspection,
including when suppressed? How is that observation exposed separately from
message submission?
- How is duplicate presentation avoided, and how do adapters apply prefixes to
mixed or already-labelled native diagnostics?
- What presentation should streaming Progress use? Is a convenience helper for
explicitly presenting `err.Error()` as a Warning useful enough to include?
Application error classification, recovery, and cause tracking are outside
these questions. Delivery failures produced by reporting remain under OD-4.
### OD-4: Delivery lifecycle and quiet execution