Reject missing prepared requests
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Consolidated audit catalog
|
# 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:
|
numbered entries in seven audit documents. Reviewed audit state:
|
||||||
`db732e3a1de55c844f77870e1c6db683c2685d5d`.
|
`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
|
## 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
|
The ckprompt prepared-request handler accepts an empty `Acquired` value with a
|
||||||
nil error from `PrepareRequest`. It renders `null` and reports success despite
|
nil error from `PrepareRequest`. It renders `null` and reports success despite
|
||||||
having no prepared request.
|
having no prepared request.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Audit remediation implementation plan
|
# Audit remediation implementation plan
|
||||||
|
|
||||||
Status: in progress; Stages 1–3 complete.
|
Status: in progress; Stages 1–4 complete.
|
||||||
|
|
||||||
Baseline: `d492c7747175c01a53261206c2b4356e53453621`. Before this sprint,
|
Baseline: `d492c7747175c01a53261206c2b4356e53453621`. Before this sprint,
|
||||||
intervening changes recorded decisions and retired the completed older
|
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
|
## 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`.
|
Findings: F04. Source: ckprompt `preparation.go`.
|
||||||
|
|
||||||
1. After the existing provider-error and cancellation handling in
|
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 {
|
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)
|
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})
|
_ = invocation.Reporter().Report(commandkit.Report{Value: acquired.Value})
|
||||||
return commandkit.Success()
|
return commandkit.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,3 +105,43 @@ func TestNativePreparationBuilderAndErrorIdentity(t *testing.T) {
|
|||||||
t.Fatalf("native error = %v", err)
|
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