feat: 实现 AI 规格候选匹配与审计 (#201)
This commit is contained in:
@@ -985,6 +985,51 @@ func TestMySQLV20_AI配置首建重放与唯一启用(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMySQLV21_AI规格来源升级重放与约束(t *testing.T) {
|
||||
db := openMySQLMigrationTestDB(t)
|
||||
defer db.Close()
|
||||
cleanMySQLTestSchema(t, db)
|
||||
defer cleanMySQLTestSchema(t, db)
|
||||
if err := MigrateMySQL(db); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// 在隔离库中还原成 v20 形状,验证存量人工映射升级后仍是 manual。
|
||||
mustExec(t, db, `ALTER TABLE spec_mappings DROP CHECK chk_spec_mappings_source`)
|
||||
mustExec(t, db, `ALTER TABLE spec_mappings DROP CHECK chk_spec_mappings_confidence`)
|
||||
for _, column := range []string{"context_version", "source_version", "source_reason", "confidence_bps", "source_model", "source_provider_id", "source"} {
|
||||
mustExec(t, db, `ALTER TABLE spec_mappings DROP COLUMN `+column)
|
||||
}
|
||||
mustExec(t, db, `DROP TABLE ai_spec_match_decisions`)
|
||||
mustExec(t, db, `DELETE FROM schema_migrations WHERE version=21`)
|
||||
mustExec(t, db, `INSERT INTO spec_mappings(shopee_goods_id,spec_key,pdd_goods_id,pdd_option_key,
|
||||
pdd_options,spec_raw,mapped_at,mapped_by) VALUES('S','黑色,M','P','{}','{}','黑色,M','2026-08-14T00:00:00Z','U')`)
|
||||
if err := MigrateMySQL(db); err != nil {
|
||||
t.Fatalf("v20→v21 失败: %v", err)
|
||||
}
|
||||
if err := MigrateMySQL(db); err != nil {
|
||||
t.Fatalf("v21 重放失败: %v", err)
|
||||
}
|
||||
var source string
|
||||
if err := db.QueryRow(`SELECT source FROM spec_mappings WHERE shopee_goods_id='S'`).Scan(&source); err != nil || source != "manual" {
|
||||
t.Fatalf("存量映射来源=%q err=%v", source, err)
|
||||
}
|
||||
if _, err := db.Exec(`UPDATE spec_mappings SET source='unknown' WHERE shopee_goods_id='S'`); err == nil {
|
||||
t.Fatal("映射来源 CHECK 必须拒绝未知值")
|
||||
}
|
||||
mustExec(t, db, `INSERT INTO users(user_id,username,password_hash,role,status,password_changed_at,created_at,updated_at)
|
||||
VALUES('U-AI','u-ai','hash','purchaser','active','2026-08-14T00:00:00Z','2026-08-14T00:00:00Z','2026-08-14T00:00:00Z')`)
|
||||
mustExec(t, db, `INSERT INTO ai_spec_match_decisions(shopee_goods_id,spec_key,pdd_goods_id,
|
||||
context_version,rules_version,prompt_version,candidates_json,confidence_bps,outcome,
|
||||
conflict_dimensions_json,missing_dimensions_json,decided_by,decided_at)
|
||||
VALUES('S','黑色,M','P',REPEAT('a',64),'rules_v1','spec_prompt_v1','[]',9000,'ai_saved','[]','[]','U-AI','2026-08-14T00:00:00Z')`)
|
||||
if _, err := db.Exec(`UPDATE ai_spec_match_decisions SET outcome='unknown'`); err == nil {
|
||||
t.Fatal("AI 决策 outcome CHECK 必须拒绝未知值")
|
||||
}
|
||||
if err := CheckMySQLSchema(db); err != nil {
|
||||
t.Fatalf("v21 自检失败: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func prepareMySQLV2(t *testing.T, db *sql.DB) {
|
||||
t.Helper()
|
||||
mustExec(t, db, `CREATE TABLE schema_migrations (version INT PRIMARY KEY, applied_at VARCHAR(35) NOT NULL) ENGINE=InnoDB`)
|
||||
|
||||
Reference in New Issue
Block a user