From a5a92c7f0826348ad9ed5b8a57f03bbdad619867 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sat, 24 Oct 2026 02:01:59 +0000 Subject: [PATCH] Settle reporting delivery lifecycle and quiet rendering --- docs/roadmap/reporting.md | 138 ++++++++++++++++++++++++++++---------- 1 file changed, 104 insertions(+), 34 deletions(-) diff --git a/docs/roadmap/reporting.md b/docs/roadmap/reporting.md index fd4cdd8..96f8ad3 100644 --- a/docs/roadmap/reporting.md +++ b/docs/roadmap/reporting.md @@ -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.