Settle reporting delivery lifecycle and quiet rendering

This commit is contained in:
2026-10-24 02:01:59 +00:00
parent 514c4d47bb
commit a5a92c7f08

View File

@@ -1,13 +1,14 @@
# Output policy and invocation reporting
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.
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.
OD-3's failure presentation and retention boundaries are selected.
Exact API signatures and OD-4's delivery mechanics remain open.
Implementation has not started.
OD-4's delivery lifecycle, write-failure handling, and quiet-mode rendering are
selected. Exact API names, signatures, and representations remain to be
finalized. Implementation has not started.
## Purpose
@@ -155,7 +156,7 @@ error. Exact API names and signatures remain to be finalized.
Output streamed before the failure remains visible according to its selected
mode; terminal failure does not withdraw earlier bytes. Deferred messages,
cleanup writes, and delivery failures must respect the end of normal reporting.
Their finalization and late-write behavior remain OD-4 details. A terminal
Their finalization and late-write behavior follow OD-4 below. A terminal
failure may have multiple explanatory records, all belonging to that failure.
### Failure explanations and presentation ownership (OD-3)
@@ -334,22 +335,90 @@ incidental implementation steps. Use command paths, flag names, and decision
descriptions rather than raw argument or configuration-value dumps. Upstream
libraries retain ownership of their diagnostic detail and disclosure rules.
## Tentative direction
## Selected delivery lifecycle and quiet execution (OD-4)
### Streaming and failure diagnostics
### Ordering and finalization
The proposed approach applies visibility when output is emitted. A verbose or
debug run may show informational detail before subsequently failing. A run with
Progress enabled may stream updates before failing, and an ordinary run may
write part of its substantive output before failing. Previously written bytes cannot
be withdrawn. Whole-run buffering solely to make failed runs contain only error
output is not part of the proposed direction.
Use synchronous delivery. Present immediate messages and substantive writes in
submission order. After the handler returns:
1. Deliver eligible deferred messages in queue order, without sorting by severity.
2. Present any terminal failure explanation.
3. Close the invocation's reporting facility and return the final outcome.
Deferred messages remain eligible when the operation fails, subject to verbosity.
Deferral controls timing; applications queue success summaries only after the
relevant operation succeeds. Ordering governs CommandKit's writes; separate
stdout and stderr destinations may be buffered or displayed differently by the
caller.
CommandKit finalizes automatically. Consumers do not need a separate flush or
finish call. Handler cleanup, including Go `defer` functions, runs before the
handler returns and participates in normal reporting. Applications complete any
reporting goroutines before returning. After finalization, writes and message
submissions return a closed-reporter error and emit nothing.
Finalize any buffers owned by CommandKit. Caller-supplied writers remain
caller-owned; CommandKit does not automatically close them or invoke arbitrary
flushing interfaces.
Visibility applies when output is emitted. A verbose or debug run may show
informational detail before subsequently failing. Progress and substantive
output may likewise be partially delivered before a failure. Previously written
bytes cannot be withdrawn. Whole-run buffering solely to make failed runs
contain only error output is outside this implementation.
Keep errors understandable in every mode, including source locations and
related explanatory context. Unrelated warnings and informational messages
remain subject to the selected mode. Apply the selected retention boundary
without accumulating a message history.
### Write failures and execution flow
Failure to deliver requested output makes an otherwise successful invocation
unsuccessful. Apply this rule to substantive output, Warning, Info, Progress,
Debug, and terminal explanations. Intentional suppression requests no delivery
and is not a delivery failure.
Standard writer operations return write errors normally. Immediate reporting
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.
Stop writing to a destination after it fails. A substantive-output failure can
receive a terminal explanation through the diagnostic destination if it still
works. If diagnostic delivery fails, return that information to the caller.
Do not redirect diagnostics into substantive output or recursively attempt to
report the reporting failure.
A failed write does not stop application code. The handler can inspect the error
and return immediately; otherwise, CommandKit records the failure and finalizes
when the handler returns. CommandKit does not use process exit or panic to
interrupt execution. Terminal failure presentation ends normal output.
### Quiet-mode rendering and suppression
Initially, run substantive report generation normally with its managed writer
discarding output in quiet mode. This preserves report generation, validation,
and serialization failures while changing presentation. For example, a report
encoder failure still fails the invocation under `--quiet`; the handler remains
responsible for handling errors returned by an encoder it calls.
Simple suppressed messages need no formatting or destination writes. For richer
report renderers, initially render into a discard destination. Rendering may be
skipped later where doing so preserves the command's operation and failure
semantics.
Treat suppression as intentional suppression, never as failed or incomplete
delivery. Do not retain suppressed content. Delivery needs only the deferred
queue, reporting lifecycle state, and bounded delivery-failure information,
alongside the temporary parser state and returned explanations described above.
## Selected consumer reporting API direction
Provide one reporting facility per invocation for substantive output, immediate
@@ -393,10 +462,11 @@ to the presentation needs described above. Caller-selected destinations belong
at the execution boundary; the handler-facing API routes output through the
reporter instead of requiring a parallel raw-stream API.
Whether reporting methods return write errors, retain them for finalization,
or expose an explicit delivery-error accessor remains open under OD-4. Standard
writer operations remain compatible with `io.Writer`. The final API design will
consolidate these choices with the selected consumer-facing structure.
Immediate methods expose delivery errors and the reporter retains delivery
failure state for automatic finalization, as selected in OD-4. Standard writer
operations remain compatible with `io.Writer`. Exact API names, signatures, and
outcome representations will express these behaviors through the selected
consumer-facing structure.
## Upstream diagnostic ownership
@@ -419,7 +489,7 @@ rules.
## Work needed
1. Settle the open decisions with examples covering ordinary application output,
1. Specify the selected behavior in examples covering ordinary application output,
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.
@@ -429,7 +499,7 @@ rules.
writer ownership to identify the smallest shared changes. Include invocation
failures that occur before a handler receives its `Invocation`.
3. Finalize the unified reporting API and flag contracts, including interactions
with command and flag aliases, following OD-1 and OD-2 above. Replace split
with command and flag aliases, following OD-1 through OD-4 above. Replace split
handler submission paths and adapt core and integration callers. Account for
flag collisions and document changed public contracts.
4. Implement the selected behavior across core and the integrations. Preserve
@@ -445,24 +515,24 @@ rules.
context in quiet mode, independent warnings in mixed batches, already-labelled
native content, and distinct submissions with identical text. Verify the end
of normal reporting after terminal error presentation, including deferred
and late writes under the selected OD-4 behavior.
and late writes under the selected OD-4 behavior. Cover immediate and deferred
ordering on success and failure, handler cleanup, automatic finalization,
and ownership of caller-supplied writers. Verify ignored immediate write
errors and deferred delivery failures affect the final outcome, existing
failures retain their classification and status, 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.
6. Update GoDoc, the CLI reference, consumer guidance, and release documentation
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
## Remaining design work
### OD-4: Delivery lifecycle and quiet execution
How are immediate and deferred messages ordered and finalized, including when
the operation fails? How do deferred messages, cleanup writes, and attempts to
use the reporter after terminal failure respect the end of normal reporting?
How do callers observe and react to write failures? What
delivery state represents intentional suppression? Does quiet mode discard
rendered bytes or skip report rendering, and how does that choice preserve
operation semantics and failure detection? Which streaming behavior becomes
part of the public contract?
How do Progress delivery failures interact with other messages? Progress uses
the selected streamed-line presentation and shared retention boundary.
OD-1 through OD-4 are resolved. Before implementation, finalize the concrete
reporter and outcome API, including simple and structured terminal explanations,
deferred submission, and delivery-failure observations. Review complete examples
against the selected behavior and reconcile the architectural contracts noted
above.