Document invocation reporting contracts

This commit is contained in:
2026-10-26 03:57:11 +00:00
parent a6c0fb5b0d
commit 96aa6b5ca0
15 changed files with 345 additions and 71 deletions

View File

@@ -60,16 +60,24 @@ type deferredMessage struct {
details []Detail
}
// Reporter coordinates presentation and delivery for one invocation.
// Reporter coordinates presentation and delivery for one invocation. The
// invocation supplies it; consumers do not construct or finalize it. Reporting
// operations on one reporter are safe concurrently, although concurrent
// submissions have no predetermined order. Rendering callbacks must not
// reenter the same reporter, and their supplied writer is valid only while the
// callback runs.
//
// The invocation supplies the reporter. Consumers use Output for substantive
// command results and the reporting methods for categorized messages.
// Consumers use Output for substantive command results and the reporting
// methods for categorized messages. Delivery and rendering failures are
// retained for Outcome.Presentation even when a caller ignores an immediate
// method's returned error.
type Reporter struct {
state *reportingState
}
// DeferredReporter queues messages for delivery during invocation finalization.
// Copies share the same invocation reporting state.
// Copies share the same invocation reporting state. Submissions made after
// finalization return ErrReporterClosed.
type DeferredReporter struct {
state *reportingState
}
@@ -126,7 +134,10 @@ func (r *Reporter) applySelection(selection commandmeta.ReportingSelection) {
state.progressSet = selection.ProgressSet
}
// Output returns a managed writer for substantive command results.
// Output returns a managed writer for substantive command results. Writes are
// serialized with other operations through this reporter, and failures are
// recorded in Outcome.Presentation. The writer returns ErrReporterClosed after
// invocation finalization.
func (r *Reporter) Output() io.Writer {
if r == nil || r.state == nil {
return managedOutputWriter{}
@@ -142,6 +153,10 @@ func (w managedOutputWriter) Write(p []byte) (int, error) {
}
// RenderOutput coordinates a complete substantive report rendering operation.
// The callback receives a writer usable only during the callback and must not
// reenter this reporter. In quiet mode, the callback still runs against a
// discard destination so rendering failures are retained without writing to
// the caller's output destination.
func (r *Reporter) RenderOutput(write func(io.Writer) error) error {
if r == nil || r.state == nil {
return ErrReporterClosed
@@ -168,27 +183,33 @@ func (r *Reporter) RenderOutput(write func(io.Writer) error) error {
return finishRenderLocked(state, destinationOutput, renderErr, writer.writeError)
}
// Info submits an informational message.
// Info submits an informational message to the diagnostic destination. Its
// visibility follows the selected reporting mode.
func (r *Reporter) Info(message string, details ...Detail) error {
return r.submitMessage(categoryInfo, message, details)
}
// Warn submits a warning message.
// Warn submits a warning message to the diagnostic destination. Its visibility
// follows the selected reporting mode.
func (r *Reporter) Warn(message string, details ...Detail) error {
return r.submitMessage(categoryWarning, message, details)
}
// Debug submits a debug message.
// Debug submits a debug message to the diagnostic destination. Its visibility
// follows the selected reporting mode.
func (r *Reporter) Debug(message string, details ...Detail) error {
return r.submitMessage(categoryDebug, message, details)
}
// Progress submits a progress message.
// Progress submits a progress message to the diagnostic destination. Its
// visibility follows the selected mode and explicit progress setting.
func (r *Reporter) Progress(message string, details ...Detail) error {
return r.submitMessage(categoryProgress, message, details)
}
// AtEnd returns a view for messages delivered after the handler returns.
// AtEnd returns a view for messages delivered after the handler returns and
// before terminal explanation delivery. The deferred view shares this
// invocation's state.
func (r *Reporter) AtEnd() DeferredReporter {
if r == nil {
return DeferredReporter{}
@@ -196,17 +217,23 @@ func (r *Reporter) AtEnd() DeferredReporter {
return DeferredReporter{state: r.state}
}
// Info queues an informational message for invocation finalization.
// Info queues an informational message for invocation finalization. The
// submission error is returned immediately; rendering and delivery errors are
// reflected in the final outcome.
func (r DeferredReporter) Info(message string, details ...Detail) error {
return r.enqueue(categoryInfo, message, details)
}
// Warn queues a warning message for invocation finalization.
// Warn queues a warning message for invocation finalization. The submission
// error is returned immediately; rendering and delivery errors are reflected in
// the final outcome.
func (r DeferredReporter) Warn(message string, details ...Detail) error {
return r.enqueue(categoryWarning, message, details)
}
// Debug queues a debug message for invocation finalization.
// Debug queues a debug message for invocation finalization. The submission
// error is returned immediately; rendering and delivery errors are reflected in
// the final outcome.
func (r DeferredReporter) Debug(message string, details ...Detail) error {
return r.enqueue(categoryDebug, message, details)
}