Reject missing prepared requests
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Consolidated audit catalog
|
||||
|
||||
Status: **24 distinct open findings: two P2 and 22 P3**, consolidated from 30
|
||||
Status: **23 distinct open findings: one P2 and 22 P3**, consolidated from 30
|
||||
numbered entries in seven audit documents. Reviewed audit state:
|
||||
`db732e3a1de55c844f77870e1c6db683c2685d5d`.
|
||||
|
||||
@@ -104,6 +104,11 @@ Also noted in the [documentation cross-references](13-documentation.md#previousl
|
||||
|
||||
## F04 — P2: Prepared-request preview can succeed without a prepared result
|
||||
|
||||
**Complete.** The command rejects a missing prepared request after provider and
|
||||
cancellation checks, preserving acquired evidence. Its public-command regression
|
||||
failed against the original behavior; focused preparation tests pass with valid,
|
||||
missing, provider-error and canceled acquisitions.
|
||||
|
||||
The ckprompt prepared-request handler accepts an empty `Acquired` value with a
|
||||
nil error from `PrepareRequest`. It renders `null` and reports success despite
|
||||
having no prepared request.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Audit remediation implementation plan
|
||||
|
||||
Status: in progress; Stages 1–3 complete.
|
||||
Status: in progress; Stages 1–4 complete.
|
||||
|
||||
Baseline: `d492c7747175c01a53261206c2b4356e53453621`. Before this sprint,
|
||||
intervening changes recorded decisions and retired the completed older
|
||||
@@ -200,6 +200,12 @@ open for the remaining parsing and binding wrappers.
|
||||
|
||||
## Stage 4 — Reject missing prepared-request results
|
||||
|
||||
**Complete.** Missing prepared requests produce an operational failure while
|
||||
retaining diagnostics and explanations. The public-command regression reproduced
|
||||
the original successful null preview; focused preparation tests now pass in the
|
||||
offline aligned workspace with Go 1.27.0 and read-only module resolution, covering
|
||||
valid results, provider errors, and cancellation as well.
|
||||
|
||||
Findings: F04. Source: ckprompt `preparation.go`.
|
||||
|
||||
1. After the existing provider-error and cancellation handling in
|
||||
|
||||
@@ -100,6 +100,9 @@ func runRequestPreparation[I, S any](invocation commandkit.Invocation, suite Sui
|
||||
if err := promptKitContextError(invocation.Context); err != nil {
|
||||
return definitionFailure(fmt.Sprintf("Preparation of the PromptKit request for prompt %q was canceled.", input.promptID), acquired.Explanation, err)
|
||||
}
|
||||
if acquired.Value == nil {
|
||||
return definitionFailure("PromptKit request preparation returned no result.", acquired.Explanation, nil)
|
||||
}
|
||||
_ = invocation.Reporter().Report(commandkit.Report{Value: acquired.Value})
|
||||
return commandkit.Success()
|
||||
}
|
||||
|
||||
@@ -105,3 +105,43 @@ func TestNativePreparationBuilderAndErrorIdentity(t *testing.T) {
|
||||
t.Fatalf("native error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPreparationCommandRejectsMissingResultAndRetainsEvidence(t *testing.T) {
|
||||
cause := errors.New("provider failure")
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
providerErr error
|
||||
cancel bool
|
||||
}{
|
||||
{name: "missing result"}, {name: "provider error", providerErr: cause}, {name: "cancellation", cancel: true},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
app := newPromptTestApp(t, Command(Suite[struct{}, struct{}]{PrepareRequest: func(context.Context, PreparationRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.PreparedRun], error) {
|
||||
if tc.cancel {
|
||||
cancel()
|
||||
}
|
||||
acquired := commandkit.Acquired[*promptkit.PreparedRun]{
|
||||
Diagnostics: []commandkit.Diagnostic{{Severity: commandkit.SeverityWarning, Write: func(w io.Writer) error { _, err := io.WriteString(w, "provider diagnostic\n"); return err }}},
|
||||
Explanation: commandkit.Explanation{Message: "provider explanation"},
|
||||
}
|
||||
if tc.providerErr != nil {
|
||||
acquired.Value = &promptkit.PreparedRun{PromptID: "briefing"}
|
||||
}
|
||||
return acquired, tc.providerErr
|
||||
}}))
|
||||
var output, diagnostics bytes.Buffer
|
||||
result := app.Execute(ctx, []string{"promptkit", "show", "prepared", "briefing", "--format=json", "--verbose"}, commandkit.Streams{Out: &output, Err: &diagnostics})
|
||||
if result.Kind != commandkit.OutcomeOperational || output.Len() != 0 || !bytes.Contains(diagnostics.Bytes(), []byte("provider diagnostic")) || !bytes.Contains(diagnostics.Bytes(), []byte("provider explanation")) {
|
||||
t.Fatalf("result=%#v output=%q diagnostics=%q", result, output.String(), diagnostics.String())
|
||||
}
|
||||
if tc.providerErr != nil && !errors.Is(result.Cause, tc.providerErr) {
|
||||
t.Fatalf("provider cause = %v", result.Cause)
|
||||
}
|
||||
if tc.cancel && !errors.Is(result.Cause, context.Canceled) {
|
||||
t.Fatalf("cancellation cause = %v", result.Cause)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user