Files
gaokao-volunteer-system/scripts/check_crowd_db_consistency.py
Hermes Agent 97ea07c231
Some checks failed
CI / pytest (Python 3.10) (push) Has been cancelled
CI / pytest (Python 3.11) (push) Has been cancelled
CI / pytest (Python 3.12) (push) Has been cancelled
feat(crowd_db): Phase 2 - 2026分数线接入(6省真实数据)
P2级改进:基于真实核实的2026官方分数线更新crowd_db

真实数据来源:
- 湖南:搜狐教育(本科历史类446/物理类400)
- 江苏:微博/教育在线(本科历史类484/物理类456,特控历史类532/物理类513)
- 广东:搜狐/新京报(本科历史类440/物理类425,特控历史类546/物理类539)
- 山东:高考100(一段441,特控521)
- 河北:教育在线(本科历史类485/物理类443,特控历史类542/物理类510)
- 河南:微博(本科历史类459/物理类419,特殊类型历史类534/物理类513)

实现内容:
1. 6省data_year: 2025 -> 2026
2. 更新source_url指向官方公布链接
3. 增加quality_note标注2026官方分数线已接入
4. 调整check_crowd_db_consistency.py:允许多年份共存
5. 修复测试以适应过渡期

验证: pytest 155 passed, 3 skipped; consistency check通过
2026-06-25 12:43:14 +08:00

156 lines
5.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""crowd_db 跨文档/数据一致性检查(防漂移)。
检查项:
1. 实测质量分布 vs CURRENT_STATE.md 顶部状态词一致
2. 实测 high 白名单 vs test_crowd_db_data_quality.py HIGH_TRUST_PROVINCES 一致
3. trusted_sources.kind != province_official_pending_review 当 quality_level in (high, usable)
4. 所有省份 confidence 在 [0, 1] 范围内
5. 所有 data_year 一致(当前应为 2025
退出码:
- 0: 一致
- 非 0: 发现漂移(细节打印到 stdout
用法:
python scripts/check_crowd_db_consistency.py
"""
from __future__ import annotations
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))
from data.crowd_db.loader import CrowdDBLoader # noqa: E402
from data.crowd_db.quality_summary import build_quality_summary # noqa: E402
def _extract_current_state_distribution() -> dict[str, int]:
"""从 CURRENT_STATE.md 顶部状态词解析质量分布。"""
path = ROOT / "docs" / "CURRENT_STATE.md"
text = path.read_text(encoding="utf-8")
# 匹配 "7 high / 20 usable / 0 skeleton"
match = re.search(
r"(\d+)\s*high\s*/\s*(\d+)\s*usable\s*/\s*(\d+)\s*skeleton",
text,
)
if not match:
return {"high": -1, "usable": -1, "skeleton": -1}
return {
"high": int(match.group(1)),
"usable": int(match.group(2)),
"skeleton": int(match.group(3)),
}
def _extract_test_whitelist() -> set[str]:
"""从 test_crowd_db_data_quality.py 解析 HIGH_TRUST_PROVINCES 白名单。"""
path = ROOT / "data" / "crowd_db" / "tests" / "test_crowd_db_data_quality.py"
text = path.read_text(encoding="utf-8")
match = re.search(
r"HIGH_TRUST_PROVINCES\s*=\s*frozenset\(\s*\{([^}]+)\}",
text,
)
if not match:
return set()
raw = match.group(1)
return set(re.findall(r'"([^"]+)"', raw))
def main() -> int:
issues: list[str] = []
# 实测
loader = CrowdDBLoader(warn_low_confidence=False)
summary = build_quality_summary(loader=loader)
actual_dist = summary["by_quality_level"]
actual_high = {
p["province"] for p in summary["provinces"] if p["quality_level"] == "high"
}
# 检查 1: 状态词一致性
doc_dist = _extract_current_state_distribution()
for level in ("high", "usable", "skeleton"):
if doc_dist[level] != actual_dist.get(level, 0):
issues.append(
f"[状态词漂移] CURRENT_STATE.md 声明 {level}={doc_dist[level]}, "
f"实测 {level}={actual_dist.get(level, 0)}"
)
# 检查 2: 测试白名单一致性
whitelist = _extract_test_whitelist()
if whitelist != actual_high:
missing = actual_high - whitelist
extra = whitelist - actual_high
if missing:
issues.append(f"[白名单漂移] 实测 high 但测试白名单缺失: {sorted(missing)}")
if extra:
issues.append(f"[白名单漂移] 测试白名单有但实测非 high: {sorted(extra)}")
# 检查 3: trusted_sources.kind 与 quality_level 一致性
for province in loader.list_supported_provinces():
full = loader.load_province(province)
if not full:
continue
meta = loader.load_metadata(province) or {}
normalized = _normalize_via_summary(summary, province)
if normalized in ("high", "usable"):
for ts in full.get("trusted_sources", []):
if ts.get("kind") == "province_official_pending_review":
issues.append(
f"[kind 漂移] {province} quality_level={normalized}"
f"{ts.get('name', '?')} kind=province_official_pending_review"
)
# 检查 4: confidence 范围
for province in loader.list_supported_provinces():
meta = loader.load_metadata(province) or {}
conf = meta.get("confidence")
if conf is None or not (0.0 <= conf <= 1.0):
issues.append(f"[confidence 越界] {province} confidence={conf}")
# 检查 5: data_year 一致性(放宽:允许多年份共存,部分省份已更新到 2026
years = {
(loader.load_metadata(p) or {}).get("data_year")
for p in loader.list_supported_provinces()
}
# 只有当出现异常年份(非 2025/2026才报错
invalid_years = {y for y in years if y not in {2025, 2026}}
if invalid_years:
issues.append(f"[data_year 异常] 发现非 2025/2026 年份: {invalid_years}")
elif years == {2026}:
issues.append("[data_year 注意] 已全部切到 2026确认 2026 录取数据已正式公布")
# 多年份共存2025+2026是正常的过渡期状态不报错
# 输出
if issues:
print("❌ crowd_db 一致性检查发现漂移:")
for i, issue in enumerate(issues, 1):
print(f" {i}. {issue}")
return 1
print(
f"✅ crowd_db 一致性检查通过:"
f"high={actual_dist.get('high', 0)} "
f"usable={actual_dist.get('usable', 0)} "
f"low={actual_dist.get('low', 0)} "
f"skeleton={actual_dist.get('skeleton', 0)}"
)
return 0
def _normalize_via_summary(summary: dict, province: str) -> str:
"""从已构建的 summary 中取 quality_level。"""
for p in summary["provinces"]:
if p["province"] == province:
return p["quality_level"]
return "unknown"
if __name__ == "__main__":
sys.exit(main())