release: gate August 1 content candidates
This commit is contained in:
+40
@@ -96,6 +96,7 @@ import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -123,6 +124,10 @@ public class AihrPracticeSeedService {
|
||||
private static final List<String> GROWTH_LEVELS = List.of("初级", "中级", "高级");
|
||||
private static final Set<String> SCENARIO_REVIEW_STATUSES = Set.of("草稿", "待业务审核", "已发布", "已下线");
|
||||
private static final Set<String> SCENARIO_RISK_LEVELS = Set.of("待评估", "常规", "高风险");
|
||||
private static final List<String> PUBLICATION_PLACEHOLDER_MARKERS = List.of(
|
||||
"待补", "待提供", "待完善", "待定", "占位内容", "占位文本", "占位符", "placeholder", "示例来源", "示例内容",
|
||||
"待确认", "todo", "tbd"
|
||||
);
|
||||
private static final List<String> MANDATORY_DUAL_REVIEW_TERMS = List.of(
|
||||
"事故", "消防", "火灾", "起火", "爆炸", "燃气", "漏电", "触电", "带电",
|
||||
"高空", "困人", "受伤", "人身伤害", "摔倒", "暴力", "肢体冲突",
|
||||
@@ -7808,10 +7813,45 @@ public class AihrPracticeSeedService {
|
||||
|| scenario.rounds() == null || scenario.rounds().size() < 2) {
|
||||
throw new ServiceException("发布前请补齐业务来源/SOP、服务红线、训练目标、成功标准和至少两轮对练");
|
||||
}
|
||||
if (containsPublicationPlaceholder(
|
||||
scenario.name(), scenario.scenarioType(), scenario.customerPersona(), scenario.openingText(),
|
||||
scenario.explicitNeed(), scenario.hiddenNeed(), scenario.irritants(), scenario.delights(),
|
||||
scenario.sopRefs(), scenario.successCriteria(), scenario.strategy(), scenario.goal(),
|
||||
scenario.collaborationPositions(), scenario.curriculumVersion()
|
||||
)) {
|
||||
throw new ServiceException("发布前请移除待补、待确认或示例占位内容");
|
||||
}
|
||||
if (scenario.rounds().stream().anyMatch(round -> round == null
|
||||
|| isBlank(round.customer()) || isBlank(round.coachHint())
|
||||
|| containsPublicationPlaceholder(round.customer(), round.coachHint()))) {
|
||||
throw new ServiceException("发布前请补齐每轮业主话术和教练提示,并移除占位内容");
|
||||
}
|
||||
if (scenario.rubric() == null || scenario.rubric().dimensions() == null
|
||||
|| scenario.rubric().dimensions().size() != RUBRIC_DIMENSION_CODES.size()) {
|
||||
throw new ServiceException("发布前请配置完整的五维评分规则");
|
||||
}
|
||||
if (scenario.rubric().dimensions().stream().anyMatch(dimension -> dimension == null
|
||||
|| isBlank(dimension.name()) || isBlank(dimension.description())
|
||||
|| containsPublicationPlaceholder(dimension.name(), dimension.description()))) {
|
||||
throw new ServiceException("发布前请补齐五维评分说明,并移除占位内容");
|
||||
}
|
||||
validateRubricDimensions(scenario.rubric().dimensions());
|
||||
}
|
||||
|
||||
static boolean containsPublicationPlaceholder(String... values) {
|
||||
if (values == null) {
|
||||
return false;
|
||||
}
|
||||
for (String value : values) {
|
||||
if (value == null || value.isBlank()) {
|
||||
continue;
|
||||
}
|
||||
String normalized = value.trim().toLowerCase(Locale.ROOT);
|
||||
if (PUBLICATION_PLACEHOLDER_MARKERS.stream().anyMatch(normalized::contains)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isKnownCurriculumCapability(String position, String growthLevel, String competencyCode) {
|
||||
|
||||
+29
-1
@@ -533,6 +533,8 @@ public class AihrPracticeSeedServiceTest {
|
||||
assertTrue(source.contains("高风险场景需要另一位不同审核人复核"));
|
||||
assertTrue(source.contains("isBlank(scenario.irritants())"));
|
||||
assertTrue(source.contains("业务来源/SOP、服务红线"));
|
||||
assertTrue(source.contains("containsPublicationPlaceholder"));
|
||||
assertTrue(source.contains("发布前请移除待补、待确认或示例占位内容"));
|
||||
assertTrue(source.contains("growth_level"));
|
||||
assertTrue(source.contains("competency_code"));
|
||||
assertTrue(source.contains("risk_level"));
|
||||
@@ -612,6 +614,31 @@ public class AihrPracticeSeedServiceTest {
|
||||
assertTrue(jdbcTemplate.updateSql.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scenarioCannotPublishWithPlaceholderContent() throws Exception {
|
||||
HighRiskScenarioJdbcTemplate jdbcTemplate = new HighRiskScenarioJdbcTemplate("常规");
|
||||
jdbcTemplate.sopRefs = "待补公司收费制度";
|
||||
AihrPracticeSeedService service = new AihrPracticeSeedService(new ObjectMapper(), jdbcTemplate, null, null);
|
||||
markScenarioTableReady(service);
|
||||
|
||||
ServiceException error = assertThrows(ServiceException.class, () -> service.updateScenarioReviewStatus(
|
||||
"placeholder-scene", new ScenarioReviewStatusRequest("已发布"), 101L, "reviewer-a"));
|
||||
|
||||
assertEquals("发布前请移除待补、待确认或示例占位内容", error.getMessage());
|
||||
assertTrue(jdbcTemplate.updateSql.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicationPlaceholderDetectionDoesNotRejectOrdinaryConfirmationLanguage() {
|
||||
assertTrue(AihrPracticeSeedService.containsPublicationPlaceholder("待补正式制度"));
|
||||
assertTrue(AihrPracticeSeedService.containsPublicationPlaceholder("收费依据(待确认)"));
|
||||
assertTrue(AihrPracticeSeedService.containsPublicationPlaceholder("收费依据待确认"));
|
||||
assertTrue(AihrPracticeSeedService.containsPublicationPlaceholder("TBD"));
|
||||
assertFalse(AihrPracticeSeedService.containsPublicationPlaceholder("无依据时明确告知无法确认"));
|
||||
assertFalse(AihrPracticeSeedService.containsPublicationPlaceholder("未经核实不得承诺减免"));
|
||||
assertFalse(AihrPracticeSeedService.containsPublicationPlaceholder("车辆被占位后如何协调"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void employeeScenarioReadDoesNotExposeContentReviewerAudit() throws Exception {
|
||||
HighRiskScenarioJdbcTemplate jdbcTemplate = new HighRiskScenarioJdbcTemplate("高风险");
|
||||
@@ -2974,6 +3001,7 @@ public class AihrPracticeSeedServiceTest {
|
||||
private Long reviewerUserId;
|
||||
private String secondReviewer = "";
|
||||
private Long secondReviewerUserId;
|
||||
private String sopRefs = "收费管理SOP v1";
|
||||
private String updateSql = "";
|
||||
|
||||
private HighRiskScenarioJdbcTemplate(String riskLevel) {
|
||||
@@ -3031,7 +3059,7 @@ public class AihrPracticeSeedServiceTest {
|
||||
row.put("hidden_need", "得到清晰答复");
|
||||
row.put("irritants", "未经核实承诺减免");
|
||||
row.put("delights", "给出责任人和反馈节点");
|
||||
row.put("sop_refs", "收费管理SOP v1");
|
||||
row.put("sop_refs", sopRefs);
|
||||
row.put("success_criteria", "解释依据并完成记录");
|
||||
row.put("strategy", "先核实再答复");
|
||||
row.put("goal", "训练收费争议沟通");
|
||||
|
||||
Reference in New Issue
Block a user