From dd601c3482413a2770d81bd4501d6af8e96a1acc Mon Sep 17 00:00:00 2001 From: let5sne Date: Tue, 14 Jul 2026 13:06:54 +0800 Subject: [PATCH] test(aihr): gate missing core practice flows --- docs/BRD_IMPLEMENTATION_AUDIT.md | 1 + scripts/demo-check.sh | 9 +++++++-- scripts/tests/demo-check-pilot-gates.test.sh | 9 +++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index 810a4744..b7db017a 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -255,3 +255,4 @@ - 2026-07-14 线上只读核对:生产根站、`/h5/` 和 `/prod-api/auth/tenant/list` 均返回 `200`,线上仍加载管理端 `index-CJZ3Ax3Z.js` 与 H5 `index-D4-NrEpb.js`;本轮 `aa7e1508`、`5d85d63c` 两个 BRD 修复提交尚未发布。未执行生产同步、重启或业务数据写入。 - 2026-07-14 发布证据链复核:`release-preflight.sh` 原先只检查构建产物存在和 hash,旧产物可能被误当成当前提交发布;现增加跨 macOS/Linux 的产物时间门禁,管理端、H5 入口/主资源和后端 jar 必须不早于当前 `HEAD`,否则明确要求重建。该修复只收紧本地发布前检查,未修改生产环境。 - 2026-07-14 BRD 发布边界复核:基于当前 `HEAD=0433250b` 重新构建管理端、`mobile-uni` H5 和后端 jar 后,`release-preflight.sh` 的产物新鲜度检查通过;线上根站与 `/h5/` 仍返回 `200`,但线上仍加载管理端 `assets/index-CJZ3Ax3Z.js`、H5 `assets/index-D4-NrEpb.js`,本地当前产物分别为 `assets/index-ClaGy0E5.js`、`assets/index-C5pwI-WO.js`。预检随后因两份用户未提交的 Figma 文档停止;本轮未修改、暂存或提交这两份文档,也未执行生产同步、后端重启或业务数据写入,因此当前 BRD 修复仍未被证明在线上生效。 +- 2026-07-14 BRD 4.3.4 门禁补强:严格试点预检不再只按启用场景数量判断覆盖,新增“服务推介/增值”和“日常服务”场景存在性统计;当前仅增加事实检查,不臆造场景内容,场景成功条件、SOP 适用范围和正式质量仍需内容负责人确认。行为测试夹具已覆盖两类统计,严格门禁会在缺任一核心流程时明确失败。 diff --git a/scripts/demo-check.sh b/scripts/demo-check.sh index ce034c60..a8c02176 100755 --- a/scripts/demo-check.sh +++ b/scripts/demo-check.sh @@ -81,7 +81,7 @@ check_pilot_samples() { [[ "$(pilot_sql_scalar "SELECT DATE('$pilot_end') IS NOT NULL")" == "1" ]] || fail "invalid AIHR_PILOT_END_DATE: $pilot_end" [[ "$pilot_start" > "$pilot_end" ]] && fail "pilot start date must not be after end date" - local scenario_count completed_people pilot_people org_active org_phone_linked org_pilot_people org_pilot_projects org_completed_people audio_table_count prompt_version_schema_count sop_document_count case_stored_count case_unmasked_count + local scenario_count scenario_service_promotion_count scenario_daily_service_count completed_people pilot_people org_active org_phone_linked org_pilot_people org_pilot_projects org_completed_people audio_table_count prompt_version_schema_count sop_document_count case_stored_count case_unmasked_count local calibration_stats calibration_count calibration_matched sop_total sop_usable sop_pending satisfaction_count satisfaction_average local org_identity_cte=" WITH active_org AS ( @@ -124,6 +124,9 @@ check_pilot_samples() { HAVING COUNT(DISTINCT ext_party_id) = 1 )" scenario_count="$(pilot_sql_scalar "SELECT COUNT(*) FROM aihr_practice_scenario WHERE tenant_id = '$pilot_tenant' AND position = '生活顾问' AND enabled = 1")" + # ponytail: presence-only core-flow gate; content quality and SOP applicability still require HR review. + scenario_service_promotion_count="$(pilot_sql_scalar "SELECT COUNT(*) FROM aihr_practice_scenario WHERE tenant_id = '$pilot_tenant' AND position = '生活顾问' AND enabled = 1 AND (scenario_type LIKE '%推介%' OR scenario_type LIKE '%增值%' OR scenario_name LIKE '%推介%' OR scenario_name LIKE '%增值%')")" + scenario_daily_service_count="$(pilot_sql_scalar "SELECT COUNT(*) FROM aihr_practice_scenario WHERE tenant_id = '$pilot_tenant' AND position = '生活顾问' AND enabled = 1 AND (scenario_type LIKE '%日常%' OR scenario_name LIKE '%日常%')")" audio_table_count="$(pilot_sql_scalar "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'aihr_practice_audio'")" prompt_version_schema_count="$(pilot_sql_scalar "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'aihr_sop_answer_review' AND column_name = 'prompt_version'")" sop_document_count="$(pilot_sql_scalar "SELECT COUNT(*) FROM aihr_knowledge_attach WHERE tenant_id = '$pilot_tenant' AND type = 'sop' AND status = 2")" @@ -270,10 +273,12 @@ check_pilot_samples() { AND s.finished_time < DATE_ADD('${pilot_end}', INTERVAL 1 DAY) ) SELECT COALESCE(ROUND(AVG(satisfaction_score), 1), 0) FROM formal_sessions WHERE satisfaction_score IS NOT NULL")" - echo "OK: pilot gates window=${pilot_start}..${pilot_end} scenarios=${scenario_count}/12 sop_docs=${sop_document_count}/5 stored_cases=${case_stored_count}/20 case_unmasked=${case_unmasked_count} ten_sessions=${completed_people}/${pilot_people} org_identity=${org_phone_linked}/${org_active} org_pilot=${org_pilot_people}/20 projects=${org_pilot_projects}/1-2 org_ten_sessions=${org_completed_people}/${org_pilot_people} calibration=${calibration_count}/20 consistency=${calibration_matched}/${calibration_count} sop_usable=${sop_usable}/${sop_total} sop_pending=${sop_pending} satisfaction=${satisfaction_average}/5 responses=${satisfaction_count} audio_schema=${audio_table_count} prompt_version_schema=${prompt_version_schema_count}" + echo "OK: pilot gates window=${pilot_start}..${pilot_end} scenarios=${scenario_count}/12 core_flow=service_promotion:${scenario_service_promotion_count} daily_service:${scenario_daily_service_count} sop_docs=${sop_document_count}/5 stored_cases=${case_stored_count}/20 case_unmasked=${case_unmasked_count} ten_sessions=${completed_people}/${pilot_people} org_identity=${org_phone_linked}/${org_active} org_pilot=${org_pilot_people}/20 projects=${org_pilot_projects}/1-2 org_ten_sessions=${org_completed_people}/${org_pilot_people} calibration=${calibration_count}/20 consistency=${calibration_matched}/${calibration_count} sop_usable=${sop_usable}/${sop_total} sop_pending=${sop_pending} satisfaction=${satisfaction_average}/5 responses=${satisfaction_count} audio_schema=${audio_table_count} prompt_version_schema=${prompt_version_schema_count}" [[ "${AIHR_PILOT_STRICT:-false}" != "true" ]] || { (( scenario_count >= 12 )) || fail "pilot enabled scenarios ${scenario_count}/12" + (( scenario_service_promotion_count > 0 )) || fail "pilot service-promotion scenarios missing" + (( scenario_daily_service_count > 0 )) || fail "pilot daily-service scenarios missing" (( sop_document_count >= 5 )) || fail "pilot residential SOP documents ${sop_document_count}/5" (( case_stored_count >= 20 )) || fail "pilot stored cases ${case_stored_count}/20" (( case_unmasked_count == 0 )) || fail "pilot stored cases contain unmasked known PII (${case_unmasked_count})" diff --git a/scripts/tests/demo-check-pilot-gates.test.sh b/scripts/tests/demo-check-pilot-gates.test.sh index bc6055ab..6944b34c 100644 --- a/scripts/tests/demo-check-pilot-gates.test.sh +++ b/scripts/tests/demo-check-pilot-gates.test.sh @@ -56,7 +56,7 @@ trap cleanup EXIT docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 </dev/null CREATE DATABASE \`$TEST_DB\` CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; USE \`$TEST_DB\`; -CREATE TABLE aihr_practice_scenario (tenant_id varchar(20), position varchar(80), enabled tinyint); +CREATE TABLE aihr_practice_scenario (tenant_id varchar(20), position varchar(80), scenario_type varchar(80), scenario_name varchar(120), enabled tinyint); CREATE TABLE aihr_knowledge_attach (tenant_id varchar(20), type varchar(50), status tinyint); CREATE TABLE aihr_case_record ( tenant_id varchar(20), status varchar(30), title varchar(120), transcript text, summary varchar(1000) @@ -77,7 +77,11 @@ CREATE TABLE aihr_sop_answer_review ( ); INSERT INTO aihr_practice_scenario -SELECT '000000','生活顾问',1 FROM ( +SELECT '000000','生活顾问', CASE + WHEN n = 1 THEN '服务推介(增值)' + WHEN n = 2 THEN '日常服务' + ELSE '投诉处理' +END, CONCAT('scenario-', n), 1 FROM ( SELECT 1 n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12 ) n; @@ -144,6 +148,7 @@ SQL export AIHR_PILOT_DB="$TEST_DB" pilot_output="$(AIHR_PILOT_START_DATE=2026-07-07 AIHR_PILOT_END_DATE=2026-07-10 check_pilot_samples)" [[ "$pilot_output" == *'ten_sessions=1/5'* ]] || { echo "FAIL: 9/10 boundary or raw window count: $pilot_output" >&2; exit 1; } +[[ "$pilot_output" == *'core_flow=service_promotion:1 daily_service:1'* ]] || { echo "FAIL: BRD core-flow coverage counts: $pilot_output" >&2; exit 1; } [[ "$pilot_output" == *'org_identity=2/6'* ]] || { echo "FAIL: unsafe org identities were not excluded: $pilot_output" >&2; exit 1; } [[ "$pilot_output" == *'org_pilot=2/20'* ]] || { echo "FAIL: collision or dual-key identity was miscounted: $pilot_output" >&2; exit 1; } [[ "$pilot_output" == *'projects=1/1-2'* ]] || { echo "FAIL: safe pilot project count: $pilot_output" >&2; exit 1; }