Accept invocation reporting architecture and clarify error ownership
This commit is contained in:
@@ -4,12 +4,14 @@ Status: behavioral decisions selected through OD-4. 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, the terminal failure model, and application
|
||||
ownership of error handling are selected.
|
||||
ownership of domain-specific error decisions are selected.
|
||||
OD-3's failure presentation and retention boundaries are selected.
|
||||
OD-4's delivery lifecycle, write-failure handling, and quiet-mode rendering are
|
||||
selected. The consumer API signatures and presentation-result model below are
|
||||
also selected. Implementation has not started; architectural contract
|
||||
reconciliation and maintained implementation examples remain work to complete.
|
||||
also selected. Architectural preparation is complete:
|
||||
[ADR 0014](../adr/0014-invocation-reporting.md) is accepted, and the
|
||||
[architecture policy](../policy/architecture.md) is aligned. Implementation has
|
||||
not started; implementation, validation, and maintained consumer examples remain.
|
||||
|
||||
## Purpose
|
||||
|
||||
@@ -25,27 +27,32 @@ domain behavior, and operation outcomes.
|
||||
|
||||
## CLI presentation and error-handling ownership
|
||||
|
||||
Applications decide how to handle errors from their operations: recover, retry,
|
||||
Applications decide how to respond to domain-specific errors: 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 may provide shared helpers for carrying, inspecting, and presenting
|
||||
errors while leaving those decisions with the application. A Go `error` alone
|
||||
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.
|
||||
It may also supply an optional Go error cause for the execution caller to inspect.
|
||||
CommandKit preserves that cause and its existing `errors.Is`/`errors.As` behavior.
|
||||
Supplying a cause alone does not select an outcome, generate an operator-facing
|
||||
message, or change visibility.
|
||||
|
||||
Applications can explicitly present `err.Error()` as a Warning through the
|
||||
ordinary message API, illustrated by `report.Warn(err.Error())`. Defer a separate
|
||||
`WarnError` convenience helper; this conversion already requires little code.
|
||||
`WarnError` convenience helper pending demonstrated value; this conversion
|
||||
already requires little code.
|
||||
|
||||
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.
|
||||
Ordinary Go error returns from CommandKit APIs and writers remain available where
|
||||
appropriate.
|
||||
|
||||
## Current baseline
|
||||
|
||||
@@ -201,12 +208,12 @@ explanations. For example:
|
||||
### Retention boundary (OD-3)
|
||||
|
||||
CommandKit provides invocation-scoped CLI presentation. Logging and message
|
||||
history collection remain application concerns. Keep terminal explanations with
|
||||
the returned outcome, and keep the temporary state needed for deferred delivery,
|
||||
parser events awaiting mode selection, and delivery bookkeeping. The reporting
|
||||
facility does not collect a transcript or retain other emitted or suppressed
|
||||
messages for later inspection. No optional message-history facility is planned
|
||||
for this implementation.
|
||||
history collection remain application concerns. Keep terminal explanations and
|
||||
any supplied cause with the returned outcome, and keep the temporary state needed
|
||||
for deferred delivery, parser events awaiting mode selection, and delivery
|
||||
bookkeeping. The reporting facility does not collect a transcript or retain other
|
||||
emitted or suppressed messages for later inspection. No optional message-history
|
||||
facility is planned for this implementation.
|
||||
|
||||
## Selected flag grammar and scope
|
||||
|
||||
@@ -436,14 +443,27 @@ methods also expose delivery errors. CommandKit records bounded delivery-failure
|
||||
information so an ignored write error cannot yield a successful invocation.
|
||||
Deferred delivery failures appear in the final outcome.
|
||||
|
||||
If the application returned success, a delivery failure produces an operational
|
||||
failure. If the application already returned failure, preserve its classification,
|
||||
status, and explanation, and include the delivery failure separately. Reporting
|
||||
failures belong to CommandKit's own error-handling responsibility.
|
||||
Apply ADR 0005's outcome rules when presentation fails. For standard outcomes,
|
||||
return operational failure with status `1`, including when the original outcome
|
||||
was a usage failure. Preserve the original explanation and any supplied cause;
|
||||
record the presentation failure separately in `Presentation`.
|
||||
|
||||
Apply the same outcome rule to rendering failures from callbacks invoked by
|
||||
CommandKit. In particular, a usage failure retains its usage classification and
|
||||
status when subsequent presentation fails.
|
||||
Application-defined domain outcomes retain their domain classification. Preserve
|
||||
an already non-zero domain status. If the domain status was `0`, change the
|
||||
suggested status to `1` so presentation failure cannot yield a successful
|
||||
invocation. The application entry point retains control of process exit.
|
||||
|
||||
| Outcome before presentation fails | Final outcome |
|
||||
| --- | --- |
|
||||
| Success, status `0` | Operational failure, status `1`. |
|
||||
| Usage failure, status `2` | Operational failure, status `1`. |
|
||||
| Operational failure, status `1` | Operational failure, status `1`. |
|
||||
| Domain outcome, non-zero status | Same domain classification and status. |
|
||||
| Domain outcome, status `0` | Same domain classification, status `1`. |
|
||||
|
||||
These rules apply to both destination-write failures and rendering failures from
|
||||
callbacks invoked by CommandKit. Reporting failures remain CommandKit's own
|
||||
error-handling responsibility.
|
||||
|
||||
Stop writing to a destination after it fails. A substantive-output failure can
|
||||
receive a terminal explanation through the diagnostic destination if it still
|
||||
@@ -587,6 +607,7 @@ type Outcome struct {
|
||||
Kind OutcomeKind
|
||||
Status int
|
||||
Domain string
|
||||
Cause error
|
||||
Explanation Explanation
|
||||
Presentation PresentationResult
|
||||
}
|
||||
@@ -597,11 +618,15 @@ func Usage(message string, details ...Detail) Outcome
|
||||
func Domain(name string, status int) Outcome
|
||||
|
||||
func (o Outcome) WithExplanation(message string, details ...Detail) Outcome
|
||||
func (o Outcome) WithCause(cause error) Outcome
|
||||
```
|
||||
|
||||
`Success` returns a successful outcome with status `0`. `Failure` produces an
|
||||
operational failure with status `1`; `Usage` produces a usage failure with status
|
||||
`2`. `Domain` preserves an application-defined classification and status.
|
||||
`2`. `Domain` constructs an outcome with the supplied application-defined
|
||||
classification and status. Subsequent presentation failures follow OD-4's rules:
|
||||
domain classification is preserved, and a zero status becomes `1` if presentation
|
||||
fails.
|
||||
`OutcomeKind` retains the success, usage, operational, and domain classifications.
|
||||
|
||||
`WithExplanation` returns a modified outcome value and replaces its terminal
|
||||
@@ -626,10 +651,26 @@ The named renderers above have signature `func(io.Writer) error` and preserve th
|
||||
owning library's safe diagnostic formatting. They run during terminal delivery,
|
||||
not when constructing the outcome.
|
||||
|
||||
The target outcome has no application `Cause` field. Applications supply their
|
||||
chosen explanation; CommandKit records its own presentation failures separately.
|
||||
The returned outcome retains the terminal explanation, with other retention
|
||||
limited to the presentation needs described above.
|
||||
`Cause` is optional. `WithCause` returns a modified outcome value, replacing the
|
||||
cause without changing the classification, status, or explanation. For example:
|
||||
|
||||
```go
|
||||
return commandkit.Failure("Unable to open the configuration file.").
|
||||
WithCause(err)
|
||||
```
|
||||
|
||||
CommandKit presents the supplied explanation and carries the original error
|
||||
through to the execution caller, which can inspect it with expressions such as
|
||||
`errors.Is(outcome.Cause, fs.ErrNotExist)`. It does not automatically present
|
||||
`Cause.Error()` or use the cause to decide success, failure, or message category.
|
||||
Providing a cause is independent of choosing the terminal explanation; neither
|
||||
is inferred from the other. Warnings do not require supplying or retaining causes.
|
||||
|
||||
Outcome processing preserves supplied causes, including their existing Go error
|
||||
identity, when a subsequent rendering or delivery failure occurs. Presentation
|
||||
failures are recorded separately in `Presentation`. The returned outcome retains
|
||||
its terminal explanation and optional cause, with other retention limited to the
|
||||
presentation needs described above.
|
||||
|
||||
### Presentation observations and closed reporters
|
||||
|
||||
@@ -672,7 +713,8 @@ finalization; it is observation data, not another submission API.
|
||||
The invocation supplies the reporter. Consumers neither construct nor finalize
|
||||
it. After closure, message submissions and writer operations return
|
||||
`ErrReporterClosed`, including in quiet mode. The initial API needs no explicit
|
||||
flush method, transcript accessor, verbosity checks, or error-conversion helpers.
|
||||
flush method, transcript accessor, or verbosity checks. Error-conversion helpers
|
||||
are deferred pending demonstrated value.
|
||||
|
||||
### Application example
|
||||
|
||||
@@ -719,10 +761,9 @@ 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. 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.
|
||||
Core presents those records under the shared policy. Applications using upstream
|
||||
libraries directly choose how to respond to domain-specific errors and which
|
||||
outcomes and messages to supply, as for their other operations.
|
||||
|
||||
An integration may receive both a useful substantive report and an operation
|
||||
failure, as PromptKit smoke testing supports. Preserve the report under the
|
||||
@@ -744,7 +785,8 @@ rules.
|
||||
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.
|
||||
Include simple and structured failure construction without early emission,
|
||||
and an integration returning both a substantive report and a failure.
|
||||
optional cause transport independent of operator text, and an integration
|
||||
returning both a substantive report and a failure.
|
||||
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`.
|
||||
@@ -771,28 +813,38 @@ rules.
|
||||
placement, and ownership of caller-supplied writers. Verify concurrent reporter
|
||||
calls protect shared state and keep individual messages together, without
|
||||
requiring a predetermined order among concurrent submissions. Verify ignored
|
||||
immediate write errors and deferred delivery failures affect the final outcome,
|
||||
existing failures retain their classification and status, and failed destinations
|
||||
immediate write errors and deferred delivery failures follow the outcome table
|
||||
above, original explanations and causes are retained, and failed destinations
|
||||
receive no further writes. Cover diagnostic-destination failure without
|
||||
fallback into substantive output, quiet-mode rendering failures, and
|
||||
suppression without destination writes or incomplete-delivery status.
|
||||
Distinguish renderer failures from destination failures, including callbacks
|
||||
that fail without writing and continued terminal delivery through a healthy
|
||||
diagnostic destination. Cover usage-status preservation on presentation
|
||||
failure, all category destinations, and usage guidance under quiet mode.
|
||||
diagnostic destination. Cover usage failure becoming operational failure when
|
||||
presentation fails, domain classification and non-zero status preservation,
|
||||
and zero domain status becoming `1`. Verify all category destinations and
|
||||
usage guidance under quiet mode.
|
||||
Verify the selected API's empty-heading native rendering, ordered details,
|
||||
deferred submission errors, replacement by `WithExplanation`, and delivery
|
||||
states for each destination. Check bounded first-error observations, rendering
|
||||
through `RenderOutput`, and `ErrReporterClosed` for retained handles in quiet mode.
|
||||
6. Before changing architectural contracts, reconcile the selected error-handling
|
||||
boundary with ADR 0005's existing outcome and error-identity commitments and
|
||||
the corresponding commitments in the [architecture policy](../policy/architecture.md).
|
||||
Record architectural changes in a new ADR and align the policy. Update GoDoc,
|
||||
the CLI reference, consumer guidance, and release documentation when
|
||||
implemented. Exact reporting APIs and flag syntax remain API/CLI contracts.
|
||||
Verify `WithCause` preserves classification, status, and explanation, and
|
||||
`WithExplanation` preserves the cause. Check cause identity through outcome
|
||||
processing and subsequent presentation failures, including wrapped errors
|
||||
inspected with `errors.Is` and `errors.As`. Verify causes alone do not produce
|
||||
messages or change statuses or visibility.
|
||||
6. Update GoDoc, the CLI reference, consumer guidance, and release documentation
|
||||
when implemented. Exact reporting APIs and flag syntax remain API/CLI
|
||||
contracts.
|
||||
|
||||
## Remaining preparation
|
||||
## Architectural preparation completed
|
||||
|
||||
OD-1 through OD-4 and the consumer API signatures are selected. Reconcile the
|
||||
architectural contracts noted above before changing them, and turn the target-API
|
||||
- [x] Review and accept [ADR 0014](../adr/0014-invocation-reporting.md) as an
|
||||
extension for shared reporting, retaining ADR 0005's outcome and supplied-error
|
||||
preservation decisions.
|
||||
- [x] Align the [architecture policy](../policy/architecture.md) with the reporting
|
||||
ownership model, including application ownership of domain-specific error
|
||||
decisions and scope for useful shared error helpers.
|
||||
|
||||
OD-1 through OD-4 and the consumer API signatures are selected. Turn the target-API
|
||||
examples into maintained, executable consumers as implementation proceeds.
|
||||
|
||||
Reference in New Issue
Block a user