From b27cf02c0ea64caf7d15b16f458a2de22f77f725 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Mon, 12 Oct 2026 17:14:12 +0000 Subject: [PATCH] Verify PromptKit requirements command behavior --- docs/roadmap/implementation.md | 18 +- .../ckprompt/requirements_command_test.go | 465 ++++++++++++++++++ 2 files changed, 482 insertions(+), 1 deletion(-) create mode 100644 integrations/ckprompt/requirements_command_test.go diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 812b6b7..a34eec5 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,6 +1,6 @@ # Implement PromptKit requirements inspection -Status: in progress; Stages 1 through 3 are complete. +Status: in progress; Stages 1 through 4 are complete. ## Authority and working rules @@ -306,6 +306,22 @@ diagnostics for the command path and existing helper evidence for that native limitation; do not add a test-only engine injection API or claim an unavailable native warning scenario was exercised. +**Completed:** Added installed-command coverage in +`integrations/ckprompt/requirements_command_test.go` for native report +equivalence across conditional discovery, selected/default identities, +session-template discovery and bypass, and complete discovery with an +unsupplied required variable. The tests also cover captured selectors and +callback data, repeated invocation lifecycles, omitted pointer factories, +input rejection and pre-acquisition cancellation, warning diagnostics, +provider error identity, post-callback cancellation, nil results, partial report +delivery, short writes, and diagnostic writer failure. The focused command +`GOTOOLCHAIN=local go test ./integrations/ckprompt -run +'TestRequirementsCommand(MatchesNativePromptKitDiscovery|PreservesNativeSelectionErrors|KeepsLifecycleAndCapturedDeclaration|ChecksInputAndCancellationBeforeAcquisition|PreservesDiagnosticsCancellationAndDelivery)$' +-count=1` passed. `GOTOOLCHAIN=local go test ./...` from +`integrations/ckprompt` passed, including the composed example suite. Native +successful-acquisition warnings remain unavailable through PromptKit v0.14.0's +public API; custom callback diagnostics exercise the installed command path. + ## Stage 5: Demonstrate requirements in the maintained composed consumer **Outcome:** the existing consumer shows partial discovery and contextual diff --git a/integrations/ckprompt/requirements_command_test.go b/integrations/ckprompt/requirements_command_test.go new file mode 100644 index 0000000..2ccb327 --- /dev/null +++ b/integrations/ckprompt/requirements_command_test.go @@ -0,0 +1,465 @@ +package ckprompt + +import ( + "bytes" + "context" + "errors" + "io" + "reflect" + "strings" + "testing" + + commandkit "gitea.maximumdirect.net/eric/CommandKit" + "gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig" + promptkit "gitea.maximumdirect.net/eric/promptkit" + "go.yaml.in/yaml/v4" +) + +const requirementsCommandPrompt = `prompts: + briefing: + "2": + default_profile: editorial + session_id: '{{input "session-only"}} {{.session_variable}}' + messages: + - role: user + content: '{{if .mode}}{{input "notes"}}{{end}}' + output: + format: text + validation_mode: none + required-variable: + "1": + default_profile: editorial + messages: + - role: user + content: '{{.required}}' + output: + format: text + validation_mode: none + ambiguous: + "1": + default_profile: editorial + messages: + - role: user + content: "First version" + output: + format: text + validation_mode: none + "2": + default_profile: editorial + messages: + - role: user + content: "Second version" + output: + format: text + validation_mode: none +backends: + local: + endpoint: "https://example.invalid/v1" +profiles: + editorial: + backend: local + model: example + api_key_required: true +` + +func requirementsCommandEngine(t *testing.T) *promptkit.Engine { + t.Helper() + return adapterEngineFrom(t, "requirements command fixture", requirementsCommandPrompt) +} + +func executeRequirementsAgainstNative(t *testing.T, engine *promptkit.Engine, request promptkit.RequirementInspectionRequest, args []string) (*promptkit.RequirementInspection, commandkit.Outcome, map[string]any, string) { + t.Helper() + + native, err := engine.InspectRequirements(context.Background(), request) + if err != nil { + t.Fatalf("direct native inspection: %v", err) + } + expectedBytes, err := encodePromptYAMLBytes(requirementsReportFromInspection(native)) + if err != nil { + t.Fatalf("encode direct native report: %v", err) + } + var expected map[string]any + if err := yaml.Unmarshal(expectedBytes, &expected); err != nil { + t.Fatalf("decode direct native report %q: %v", expectedBytes, err) + } + + app := newPromptTestApp(t, Command(FromEngine[int, int](func(context.Context, ckconfig.Selection, int, int) (*promptkit.Engine, error) { + return engine, nil + }))) + var output, diagnostic bytes.Buffer + outcome := app.Execute(context.Background(), args, commandkit.Streams{Out: &output, Err: &diagnostic}) + if outcome.Kind != commandkit.OutcomeSuccess || outcome.Status != 0 { + t.Fatalf("requirements command outcome = %#v, report=%q diagnostics=%q", outcome, output.String(), diagnostic.String()) + } + var actual map[string]any + if err := yaml.Unmarshal(output.Bytes(), &actual); err != nil { + t.Fatalf("decode command report %q: %v", output.Bytes(), err) + } + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("command report differs from native inspection:\n got: %#v\nwant: %#v", actual, expected) + } + return native, outcome, actual, diagnostic.String() +} + +func TestRequirementsCommandMatchesNativePromptKitDiscovery(t *testing.T) { + engine := requirementsCommandEngine(t) + for _, test := range []struct { + name string + request promptkit.RequirementInspectionRequest + args []string + }{ + { + name: "partial conditional discovery", + request: promptkit.RequirementInspectionRequest{PromptID: "briefing", PromptVersion: "2", ProfileID: "editorial"}, + args: []string{"promptkit", "requirements", "show", "briefing", "--version", "2", "--profile", "editorial"}, + }, + { + name: "supplied branch variable", + request: promptkit.RequirementInspectionRequest{ + PromptID: "briefing", PromptVersion: "2", ProfileID: "editorial", Vars: map[string]string{"mode": "full"}, + }, + args: []string{"promptkit", "requirements", "show", "briefing", "--version", "2", "--profile", "editorial", "--var", "mode=full", "--format", "yaml"}, + }, + { + name: "complete with an unsupplied required variable", + request: promptkit.RequirementInspectionRequest{PromptID: "required-variable", PromptVersion: "1", ProfileID: "editorial"}, + args: []string{"promptkit", "requirements", "show", "required-variable", "--version", "1", "--profile", "editorial"}, + }, + { + name: "native version and default profile selection", + request: promptkit.RequirementInspectionRequest{PromptID: "briefing"}, + args: []string{"promptkit", "requirements", "show", "briefing"}, + }, + { + name: "session template discovery", + request: promptkit.RequirementInspectionRequest{PromptID: "briefing", ProfileID: "editorial"}, + args: []string{"promptkit", "requirements", "show", "briefing", "--profile", "editorial"}, + }, + { + name: "session ID bypasses the session template", + request: promptkit.RequirementInspectionRequest{PromptID: "briefing", ProfileID: "editorial", SessionID: "session-42"}, + args: []string{"promptkit", "requirements", "show", "briefing", "--profile", "editorial", "--session-id", "session-42"}, + }, + } { + t.Run(test.name, func(t *testing.T) { + native, outcome, _, _ := executeRequirementsAgainstNative(t, engine, test.request, test.args) + if outcome.Status != 0 { + t.Fatalf("partial or complete inspection returned status %d", outcome.Status) + } + switch test.name { + case "partial conditional discovery": + if native.Complete || len(native.Issues) == 0 || len(native.Inputs) == 0 { + t.Fatalf("partial discovery lost useful evidence: %#v", native) + } + case "supplied branch variable": + if !native.Complete || len(native.Issues) != 0 { + t.Fatalf("resolved discovery = %#v", native) + } + case "complete with an unsupplied required variable": + if !native.Complete || len(native.Variables) != 1 || native.Variables[0].Supplied { + t.Fatalf("complete discovery with unsupplied variable = %#v", native) + } + case "native version and default profile selection": + if native.PromptVersion != "2" || native.ProfileID != "editorial" { + t.Fatalf("native default selection = %#v", native) + } + case "session template discovery": + foundInput, foundVariable := false, false + for _, input := range native.Inputs { + foundInput = foundInput || input.Name == "session-only" + } + for _, variable := range native.Variables { + foundVariable = foundVariable || variable.Name == "session_variable" + } + if !foundInput || !foundVariable { + t.Fatalf("session template dependencies missing: %#v", native) + } + case "session ID bypasses the session template": + for _, input := range native.Inputs { + if input.Name == "session-only" { + t.Fatalf("session template input remained with session ID: %#v", native.Inputs) + } + } + for _, variable := range native.Variables { + if variable.Name == "session_variable" { + t.Fatalf("session template variable remained with session ID: %#v", native.Variables) + } + } + } + }) + } +} + +func TestRequirementsCommandPreservesNativeSelectionErrors(t *testing.T) { + engine := requirementsCommandEngine(t) + for _, test := range []struct { + name string + request promptkit.RequirementInspectionRequest + args []string + cause error + }{ + { + name: "missing prompt", + request: promptkit.RequirementInspectionRequest{PromptID: "missing", PromptVersion: "2", ProfileID: "editorial"}, + args: []string{"promptkit", "requirements", "show", "missing", "--version", "2", "--profile", "editorial"}, + cause: promptkit.ErrPromptNotFound, + }, + { + name: "missing profile", + request: promptkit.RequirementInspectionRequest{PromptID: "briefing", PromptVersion: "2", ProfileID: "missing"}, + args: []string{"promptkit", "requirements", "show", "briefing", "--version", "2", "--profile", "missing"}, + cause: promptkit.ErrProfileNotFound, + }, + { + name: "ambiguous prompt version", + request: promptkit.RequirementInspectionRequest{PromptID: "ambiguous", ProfileID: "editorial"}, + args: []string{"promptkit", "requirements", "show", "ambiguous", "--profile", "editorial"}, + cause: promptkit.ErrPromptLoad, + }, + } { + t.Run(test.name, func(t *testing.T) { + _, nativeErr := engine.InspectRequirements(context.Background(), test.request) + if !errors.Is(nativeErr, test.cause) { + t.Fatalf("native selection error = %v, want %v", nativeErr, test.cause) + } + app := newPromptTestApp(t, Command(FromEngine[int, int](func(context.Context, ckconfig.Selection, int, int) (*promptkit.Engine, error) { + return engine, nil + }))) + var output bytes.Buffer + outcome := app.Execute(context.Background(), test.args, commandkit.Streams{Out: &output, Err: io.Discard}) + if outcome.Kind != commandkit.OutcomeOperational || outcome.Status != 1 || !errors.Is(outcome.Cause, test.cause) || output.Len() != 0 { + t.Fatalf("native selection outcome = %#v output=%q", outcome, output.String()) + } + }) + } +} + +func TestRequirementsCommandKeepsLifecycleAndCapturedDeclaration(t *testing.T) { + type input struct{ campaign commandkit.Supplied[string] } + type state struct{ calls int } + + newCampaignFlag := func(name string) commandkit.Flag[input] { + return commandkit.ValueFlag(commandkit.FlagMeta{Name: name, Required: true}, (*string)(nil), parseDefinitionString, + func(target *input, value commandkit.Supplied[string]) { target.campaign = value }) + } + selectors := []commandkit.Flag[input]{newCampaignFlag("campaign")} + callbackData := &struct{ value string }{value: "initial"} + newInputCalls, checkInputCalls, newStateCalls, providerCalls, replacementCalls := 0, 0, 0, 0, 0 + var received []input + suite := Suite[input, state]{ + NewInput: func() input { + newInputCalls++ + return input{} + }, + NewState: func() state { + newStateCalls++ + return state{calls: newStateCalls} + }, + Selectors: selectors, + CheckInput: func(_ ckconfig.Selection, value input) error { + checkInputCalls++ + if !value.campaign.Set { + t.Errorf("selected campaign lost presence: %#v", value) + } + return nil + }, + InspectRequirements: func(_ context.Context, _ RequirementsRequest, value input, gotState state) (commandkit.Acquired[*promptkit.RequirementInspection], error) { + providerCalls++ + received = append(received, value) + if gotState.calls != providerCalls || callbackData.value != "updated" { + t.Errorf("provider state or callback-owned data = %#v/%q", gotState, callbackData.value) + } + return commandkit.Acquired[*promptkit.RequirementInspection]{Value: &promptkit.RequirementInspection{PromptID: "briefing"}}, nil + }, + } + declaration := Command(suite) + suite.Selectors[0] = newCampaignFlag("replacement") + suite.InspectRequirements = func(context.Context, RequirementsRequest, input, state) (commandkit.Acquired[*promptkit.RequirementInspection], error) { + replacementCalls++ + return commandkit.Acquired[*promptkit.RequirementInspection]{Value: &promptkit.RequirementInspection{}}, nil + } + selectors[0] = newCampaignFlag("also-replacement") + callbackData.value = "updated" + app := newPromptTestApp(t, declaration) + for _, campaign := range []string{"spring", "autumn"} { + args := []string{"promptkit", "requirements", "show", "briefing", "--campaign", campaign} + outcome := app.Execute(context.Background(), args, commandkit.Streams{Out: io.Discard, Err: io.Discard}) + if outcome.Kind != commandkit.OutcomeSuccess { + t.Fatalf("captured declaration invocation = %#v", outcome) + } + } + if newInputCalls != 2 || checkInputCalls != 2 || newStateCalls != 2 || providerCalls != 2 || replacementCalls != 0 || len(received) != 2 { + t.Fatalf("captured declaration calls = input/check/state/provider/replacement %d/%d/%d/%d/%d", newInputCalls, checkInputCalls, newStateCalls, providerCalls, replacementCalls) + } + if received[0].campaign.Value != "spring" || received[1].campaign.Value != "autumn" { + t.Fatalf("captured selector values = %#v", received) + } + + zeroValueApp := newPromptTestApp(t, Command(Suite[*input, *state]{InspectRequirements: func(_ context.Context, _ RequirementsRequest, gotInput *input, gotState *state) (commandkit.Acquired[*promptkit.RequirementInspection], error) { + if gotInput != nil || gotState != nil { + t.Errorf("omitted factories allocated pointer values: %#v/%#v", gotInput, gotState) + } + return commandkit.Acquired[*promptkit.RequirementInspection]{Value: &promptkit.RequirementInspection{}}, nil + }})) + zeroOutcome := zeroValueApp.Execute(context.Background(), []string{"promptkit", "requirements", "show", "briefing"}, commandkit.Streams{Out: io.Discard, Err: io.Discard}) + if zeroOutcome.Kind != commandkit.OutcomeSuccess { + t.Fatalf("omitted-factory zero values = %#v", zeroOutcome) + } +} + +func TestRequirementsCommandChecksInputAndCancellationBeforeAcquisition(t *testing.T) { + inputErr := errors.New("requirements input rejected") + newInputCalls, checkInputCalls, newStateCalls, providerCalls := 0, 0, 0, 0 + suite := Suite[struct{}, struct{}]{ + NewInput: func() struct{} { + newInputCalls++ + return struct{}{} + }, + CheckInput: func(ckconfig.Selection, struct{}) error { + checkInputCalls++ + return inputErr + }, + NewState: func() struct{} { + newStateCalls++ + return struct{}{} + }, + InspectRequirements: func(context.Context, RequirementsRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.RequirementInspection], error) { + providerCalls++ + return commandkit.Acquired[*promptkit.RequirementInspection]{Value: &promptkit.RequirementInspection{}}, nil + }, + } + app := newPromptTestApp(t, Command(suite)) + args := []string{"promptkit", "requirements", "show", "briefing"} + inputOutcome := app.Execute(context.Background(), args, commandkit.Streams{Out: io.Discard, Err: io.Discard}) + if inputOutcome.Kind != commandkit.OutcomeUsage || !errors.Is(inputOutcome.Cause, inputErr) || newInputCalls != 1 || checkInputCalls != 1 || newStateCalls != 0 || providerCalls != 0 { + t.Fatalf("rejected input reached state/provider: outcome=%#v counts=%d/%d/%d/%d", inputOutcome, newInputCalls, checkInputCalls, newStateCalls, providerCalls) + } + + suite.CheckInput = nil + app = newPromptTestApp(t, Command(suite)) + ctx, cancel := context.WithCancel(context.Background()) + cancel() + cancelOutcome := app.Execute(ctx, args, commandkit.Streams{Out: io.Discard, Err: io.Discard}) + if cancelOutcome.Kind != commandkit.OutcomeOperational || !errors.Is(cancelOutcome.Cause, context.Canceled) || newStateCalls != 0 || providerCalls != 0 { + t.Fatalf("pre-acquisition cancellation reached state/provider: outcome=%#v counts=%d/%d", cancelOutcome, newStateCalls, providerCalls) + } +} + +func TestRequirementsCommandPreservesDiagnosticsCancellationAndDelivery(t *testing.T) { + diagnostic := commandkit.MessageDiagnostic(commandkit.SeverityWarning, "provider warning") + issue := promptkit.RequirementIssue{Code: "native_issue", VariableName: "mode", Description: "native issue details"} + + t.Run("partial inspection succeeds and keeps issues in YAML", func(t *testing.T) { + app := newPromptTestApp(t, Command(Suite[struct{}, struct{}]{InspectRequirements: func(context.Context, RequirementsRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.RequirementInspection], error) { + return commandkit.Acquired[*promptkit.RequirementInspection]{Value: &promptkit.RequirementInspection{Issues: []promptkit.RequirementIssue{issue}}, Diagnostics: []commandkit.Diagnostic{diagnostic}}, nil + }})) + var report, diagnostics bytes.Buffer + outcome := app.Execute(context.Background(), []string{"promptkit", "requirements", "show", "briefing"}, commandkit.Streams{Out: &report, Err: &diagnostics}) + var decoded map[string]any + if err := yaml.Unmarshal(report.Bytes(), &decoded); err != nil { + t.Fatalf("decode partial report %q: %v", report.String(), err) + } + if outcome.Kind != commandkit.OutcomeSuccess || outcome.Status != 0 || len(outcome.Diagnostics) != 1 || !strings.Contains(diagnostics.String(), "provider warning") || strings.Contains(diagnostics.String(), "native issue details") { + t.Fatalf("partial inspection outcome=%#v report=%q diagnostics=%q", outcome, report.String(), diagnostics.String()) + } + issues, ok := decoded["issues"].([]any) + if !ok || len(issues) != 1 || !strings.Contains(report.String(), "native issue details") { + t.Fatalf("native issue not retained in report: %q", report.String()) + } + }) + + t.Run("provider failure retains diagnostic and cause", func(t *testing.T) { + providerErr := errors.New("requirements provider failed") + app := newPromptTestApp(t, Command(Suite[struct{}, struct{}]{InspectRequirements: func(context.Context, RequirementsRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.RequirementInspection], error) { + return commandkit.Acquired[*promptkit.RequirementInspection]{Diagnostics: []commandkit.Diagnostic{diagnostic}}, providerErr + }})) + var report, diagnostics bytes.Buffer + outcome := app.Execute(context.Background(), []string{"promptkit", "requirements", "show", "briefing"}, commandkit.Streams{Out: &report, Err: &diagnostics}) + if outcome.Kind != commandkit.OutcomeOperational || outcome.Status != 1 || !errors.Is(outcome.Cause, providerErr) || len(outcome.Diagnostics) == 0 || !strings.Contains(diagnostics.String(), "provider warning") || report.Len() != 0 { + t.Fatalf("provider failure outcome=%#v report=%q diagnostics=%q", outcome, report.String(), diagnostics.String()) + } + }) + + t.Run("cancellation after provider retains diagnostics and omits report", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + app := newPromptTestApp(t, Command(Suite[struct{}, struct{}]{InspectRequirements: func(context.Context, RequirementsRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.RequirementInspection], error) { + cancel() + return commandkit.Acquired[*promptkit.RequirementInspection]{Value: &promptkit.RequirementInspection{Complete: true}, Diagnostics: []commandkit.Diagnostic{diagnostic}}, nil + }})) + var report bytes.Buffer + outcome := app.Execute(ctx, []string{"promptkit", "requirements", "show", "briefing"}, commandkit.Streams{Out: &report, Err: io.Discard}) + if outcome.Kind != commandkit.OutcomeOperational || !errors.Is(outcome.Cause, context.Canceled) || len(outcome.Diagnostics) == 0 || report.Len() != 0 { + t.Fatalf("post-provider cancellation = %#v report=%q", outcome, report.String()) + } + }) + + t.Run("nil provider result is operational failure", func(t *testing.T) { + app := newPromptTestApp(t, Command(Suite[struct{}, struct{}]{InspectRequirements: func(context.Context, RequirementsRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.RequirementInspection], error) { + return commandkit.Acquired[*promptkit.RequirementInspection]{}, nil + }})) + outcome := app.Execute(context.Background(), []string{"promptkit", "requirements", "show", "briefing"}, commandkit.Streams{Out: io.Discard, Err: io.Discard}) + if outcome.Kind != commandkit.OutcomeOperational || outcome.Status != 1 || outcome.Cause == nil || !strings.Contains(outcome.Cause.Error(), "returned nil") { + t.Fatalf("nil provider result = %#v", outcome) + } + }) + + t.Run("report writer failure and short write preserve delivery state", func(t *testing.T) { + writeErr := errors.New("requirements report writer failed") + for _, test := range []struct { + name string + want error + }{ + {name: "writer error", want: writeErr}, + {name: "short write", want: io.ErrShortWrite}, + } { + t.Run(test.name, func(t *testing.T) { + writer := &requirementsPartialWriter{err: test.want} + if test.name == "short write" { + writer.err = nil + writer.short = true + } + app := newPromptTestApp(t, Command(Suite[struct{}, struct{}]{InspectRequirements: func(context.Context, RequirementsRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.RequirementInspection], error) { + return commandkit.Acquired[*promptkit.RequirementInspection]{Value: &promptkit.RequirementInspection{PromptID: "briefing"}, Diagnostics: []commandkit.Diagnostic{diagnostic}}, nil + }})) + outcome := app.Execute(context.Background(), []string{"promptkit", "requirements", "show", "briefing"}, commandkit.Streams{Out: writer, Err: io.Discard}) + if outcome.Kind != commandkit.OutcomeOperational || !errors.Is(outcome.Cause, test.want) || !errors.Is(outcome.DeliveryError, test.want) || !outcome.ReportIncomplete || writer.output.Len() == 0 { + t.Fatalf("report delivery = %#v, partial=%q", outcome, writer.output.String()) + } + }) + } + }) + + t.Run("diagnostic writer failure is retained", func(t *testing.T) { + diagnosticErr := errors.New("requirements diagnostic writer failed") + badDiagnostic := commandkit.Diagnostic{Severity: commandkit.SeverityWarning, Write: func(io.Writer) error { return diagnosticErr }} + app := newPromptTestApp(t, Command(Suite[struct{}, struct{}]{InspectRequirements: func(context.Context, RequirementsRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.RequirementInspection], error) { + return commandkit.Acquired[*promptkit.RequirementInspection]{Value: &promptkit.RequirementInspection{PromptID: "briefing"}, Diagnostics: []commandkit.Diagnostic{badDiagnostic}}, nil + }})) + var report bytes.Buffer + outcome := app.Execute(context.Background(), []string{"promptkit", "requirements", "show", "briefing"}, commandkit.Streams{Out: &report, Err: io.Discard}) + if outcome.Kind != commandkit.OutcomeOperational || !errors.Is(outcome.DeliveryError, diagnosticErr) || outcome.DiagnosticDelivery != commandkit.DeliveryIncomplete || len(outcome.Diagnostics) == 0 || report.Len() == 0 { + t.Fatalf("diagnostic delivery outcome = %#v report=%q", outcome, report.String()) + } + }) +} + +type requirementsPartialWriter struct { + output bytes.Buffer + err error + short bool +} + +func (writer *requirementsPartialWriter) Write(value []byte) (int, error) { + if len(value) == 0 { + return 0, writer.err + } + count := 1 + if count > len(value) { + count = len(value) + } + _, _ = writer.output.Write(value[:count]) + if writer.short { + return count, nil + } + return count, writer.err +}