feat(t214): persist candidate observation identities

This commit is contained in:
QiuSW
2026-07-28 12:21:55 +08:00
parent acd3c85b5b
commit 56e7a2be33
29 changed files with 622 additions and 94 deletions
@@ -90,14 +90,18 @@ type CandidateHardConstraintEvaluation struct {
}
type ExecutionCandidate struct {
Ordinal int `json:"ordinal"`
Title string `json:"title"`
SKUText string `json:"sku_text"`
Price string `json:"price"`
ProductURL string `json:"product_url"`
ImageURL string `json:"image_url"`
EvidenceAssetIDs []string `json:"evidence_asset_ids"`
Evaluation *CandidateEvaluation `json:"evaluation"`
Ordinal int `json:"ordinal"`
Title string `json:"title"`
SKUText string `json:"sku_text"`
Price string `json:"price"`
ProductURL string `json:"product_url"`
ImageURL string `json:"image_url"`
CardSignature string `json:"card_signature"`
DetailSignature string `json:"detail_signature"`
DetailEvidenceSHA256 string `json:"detail_evidence_sha256"`
SpecificationEvidenceSHA256 string `json:"specification_evidence_sha256"`
EvidenceAssetIDs []string `json:"evidence_asset_ids"`
Evaluation *CandidateEvaluation `json:"evaluation"`
}
type CandidateRecommendation struct {
@@ -603,7 +607,11 @@ func validCandidate(candidate ExecutionCandidate, mode string) bool {
!validOptionalAuditText(candidate.Price, 64) ||
!validObservationURL(candidate.ProductURL) ||
!validObservationURL(candidate.ImageURL) ||
len(candidate.EvidenceAssetIDs) > 5 {
!sha256Pattern.MatchString(candidate.CardSignature) ||
!sha256Pattern.MatchString(candidate.DetailSignature) ||
!sha256Pattern.MatchString(candidate.DetailEvidenceSHA256) ||
!sha256Pattern.MatchString(candidate.SpecificationEvidenceSHA256) ||
len(candidate.EvidenceAssetIDs) != 2 {
return false
}
for _, id := range candidate.EvidenceAssetIDs {
@@ -611,6 +619,9 @@ func validCandidate(candidate ExecutionCandidate, mode string) bool {
return false
}
}
if candidate.EvidenceAssetIDs[0] == candidate.EvidenceAssetIDs[1] {
return false
}
if mode == manualFirstMode {
return candidate.Evaluation == nil
}
@@ -98,8 +98,16 @@ func validAIExecutionCandidateCommand() StoreExecutionCandidatesCommand {
},
Candidates: []ExecutionCandidate{
{
Ordinal: 1,
Title: "拼多多图片候选 1",
Ordinal: 1,
Title: "拼多多图片候选 1",
CardSignature: strings.Repeat("b", 64),
DetailSignature: strings.Repeat("c", 64),
DetailEvidenceSHA256: strings.Repeat("d", 64),
SpecificationEvidenceSHA256: strings.Repeat("e", 64),
EvidenceAssetIDs: []string{
"00000000-0000-4000-8000-000000000001",
"00000000-0000-4000-8000-000000000002",
},
Evaluation: &CandidateEvaluation{
Decision: "REVIEW",
Score: 0.9,
@@ -129,3 +137,13 @@ func validAIExecutionCandidateCommand() StoreExecutionCandidatesCommand {
},
}
}
func TestStoreCandidatesRejectsDuplicateEvidenceReferences(t *testing.T) {
command := validAIExecutionCandidateCommand()
command.Candidates[0].EvidenceAssetIDs[1] =
command.Candidates[0].EvidenceAssetIDs[0]
if err := validateCandidateCommand(command); err == nil {
t.Fatal("expected duplicate evidence references to be rejected")
}
}