fix(chat): reject conflicting card update responses
This commit is contained in:
@@ -131,9 +131,19 @@ func observeCardUpdateMap(value map[string]any, observation *cardUpdateObservati
|
||||
}
|
||||
}
|
||||
}
|
||||
errorCode, hasErrorCode := value["errorCode"]
|
||||
errorCodeEmpty := hasErrorCode && cardUpdateErrorCodeEmpty(errorCode)
|
||||
if hasErrorCode && !errorCodeEmpty {
|
||||
setNegativeCardUpdateEvidence(observation, "errorCode=non-empty")
|
||||
}
|
||||
if success, ok := value["success"].(bool); ok {
|
||||
if success {
|
||||
setPositiveCardUpdateEvidence(observation, "success=true")
|
||||
// Record success=true only when the same response envelope explicitly
|
||||
// includes its business-error field. A non-empty code is already
|
||||
// negative evidence above, so the two signals reject the conflict.
|
||||
if hasErrorCode {
|
||||
setPositiveCardUpdateEvidence(observation, "success=true")
|
||||
}
|
||||
} else {
|
||||
setNegativeCardUpdateEvidence(observation, "success=false")
|
||||
}
|
||||
@@ -149,6 +159,14 @@ func observeCardUpdateMap(value map[string]any, observation *cardUpdateObservati
|
||||
}
|
||||
}
|
||||
|
||||
func cardUpdateErrorCodeEmpty(value any) bool {
|
||||
if value == nil {
|
||||
return true
|
||||
}
|
||||
code, ok := value.(string)
|
||||
return ok && strings.TrimSpace(code) == ""
|
||||
}
|
||||
|
||||
func setPositiveCardUpdateEvidence(observation *cardUpdateObservation, evidence string) {
|
||||
if observation.positiveEvidence == "" {
|
||||
observation.positiveEvidence = evidence
|
||||
|
||||
@@ -63,6 +63,11 @@ func TestCrossPlatformCoverageVerifyStreamingCardUpdate(t *testing.T) {
|
||||
{name: "conflicting evidence", response: map[string]any{"updated": true, "applied": false}, wantErrIs: ErrCardUpdateUnverified},
|
||||
{name: "zero affected", response: map[string]any{"affectedCount": 0}, wantErrIs: ErrCardUpdateNotApplied},
|
||||
{name: "success acknowledgement", response: map[string]any{"success": true, "errorCode": nil}, wantProof: "success=true"},
|
||||
{name: "success acknowledgement with empty error code", response: map[string]any{"success": true, "errorCode": " "}, wantProof: "success=true"},
|
||||
{name: "success without explicit error code", response: map[string]any{"success": true}, wantErrIs: ErrCardUpdateUnverified},
|
||||
{name: "success conflicts with error code", response: map[string]any{"success": true, "errorCode": "InternalError"}, wantErrIs: ErrCardUpdateUnverified},
|
||||
{name: "success conflicts with numeric error code", response: map[string]any{"success": true, "errorCode": float64(500)}, wantErrIs: ErrCardUpdateUnverified},
|
||||
{name: "error code without success", response: map[string]any{"errorCode": "InternalError"}, wantErrIs: ErrCardUpdateNotApplied},
|
||||
{name: "failed acknowledgement", response: map[string]any{"success": false}, wantErrIs: ErrCardUpdateNotApplied},
|
||||
{name: "explicitly not updated", response: map[string]any{"result": map[string]any{"updated": false}}, wantErrIs: ErrCardUpdateNotApplied},
|
||||
{name: "mismatched id", response: map[string]any{"result": map[string]any{"bizId": "biz-2", "updated": true}}, wantErrIs: ErrCardUpdateBizIDDrift},
|
||||
|
||||
Reference in New Issue
Block a user