Files
gaokao-volunteer-system/data/crowd_db/tests/test_crowd_db_data_quality.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

208 lines
7.4 KiB
Python
Raw 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.
"""crowd_db 数据质量契约测试 (6/20 Q-A 闭环).
CROWD_DB_DATA_QUALITY.md §7 承诺的锁死文件, 实际仓库中缺失。
本测试锁住以下契约:
- 31 省总数 (23 省 + 4 直辖市 + 4 自治区, 不含港澳台)
- high 白名单显式枚举(当前为 湖南/广东/江苏/山东/河北)
- 其余省份可以是 usable 或 skeleton但非白名单省份不得进入 high
- 高考生源大省中仍未进入白名单者不得高于 usable
- 新增 high 省份必须显式更新本测试, 避免"小变化悄悄升级"
Q-A 审计依据: reports/QA_CROWD_DB_NON_HUNAN_DENSITY_AUDIT.md (6/20)
"""
from __future__ import annotations
import pytest
from data.crowd_db.quality_summary import build_quality_summary
from data.crowd_db.loader import CrowdDBLoader
# 高信任白名单(当前 controller 允许进入 high 的省份)
# 任何新增/移除 high 省份都必须显式更新本测试,避免"静默升级"。
# 6/25 Stage 1: 新增河南/四川/湖北/北京/上海5 省从 usable 升 high
# 6/25 Stage 2: 27 省全部达 high15 省批量扩容完毕)
# 6/25 Stage 4: 新增 4 自治区,全国 31 省全部达 high
HIGH_TRUST_PROVINCES = frozenset({
"湖南",
"广东",
"江苏",
"山东",
"河北",
"浙江",
"福建",
"河南",
"四川",
"湖北",
"北京",
"上海",
"安徽",
"重庆",
"甘肃",
"贵州",
"海南",
"黑龙江",
"江西",
"吉林",
"辽宁",
"青海",
"陕西",
"山西",
"天津",
"新疆",
"云南",
"内蒙古",
"广西",
"西藏",
"宁夏",
})
# 仍不允许进入 high 的高考生源大省(除已进入白名单者外)
# 6/25 Stage 1 后:四川/河南/湖北/北京/上海 已升 high其余高考生源大省仍非 high
HIGH_POPULATION_PROVINCES_NOT_YET_HIGH: frozenset[str] = frozenset({
# 当前 27 个 high 已覆盖主要高考生源大省,此处保留为约束锚点
# 如未来有新高考生源大省进入 31 省范围,需重新评估
})
@pytest.fixture(scope="module")
def summary():
return build_quality_summary(CrowdDBLoader(warn_low_confidence=False))
def test_total_provinces_is_31(summary):
"""6/20 真相: 31 个 JSON (23 省 + 4 直辖市), 不含 5 自治区/港澳台。"""
assert summary["total_provinces"] == 31
assert len(summary["provinces"]) == 31
def test_high_quality_province_whitelist(summary):
"""高信任省份必须显式落在白名单中,避免静默升级。"""
high_provinces = {
p["province"] for p in summary["provinces"] if p["quality_level"] == "high"
}
assert high_provinces == HIGH_TRUST_PROVINCES, (
f"预期 high 白名单为 {sorted(HIGH_TRUST_PROVINCES)},实际: {sorted(high_provinces)}"
"新增/移除 high 省份必须显式更新本测试。"
)
def test_hunan_confidence_meets_high_threshold(summary):
"""湖南 confidence 必须 >= 0.8 (high 入门门槛, 见 quality_summary.py)。"""
hunan = next(p for p in summary["provinces"] if p["province"] == "湖南")
assert hunan["confidence"] >= 0.8, (
f"湖南 confidence={hunan['confidence']} 不满足 high 门槛 >= 0.8"
)
assert hunan["quality_level"] == "high"
def test_non_whitelist_provinces_not_high(summary):
"""不在 high 白名单中的省份不能被判为 high。"""
non_whitelist = [
p for p in summary["provinces"] if p["province"] not in HIGH_TRUST_PROVINCES
]
assert len(non_whitelist) == 31 - len(HIGH_TRUST_PROVINCES)
leaked = [p["province"] for p in non_whitelist if p["quality_level"] == "high"]
assert leaked == [], (
f"以下省份被错标为 high不在白名单: {leaked}"
"如需新增 high, 必须同步更新 HIGH_TRUST_PROVINCES。"
)
def test_shandong_is_high_quality_province(summary):
"""山东已进入 high 白名单。"""
by_name = {p["province"]: p for p in summary["provinces"]}
shandong = by_name["山东"]
assert shandong["quality_level"] == "high"
assert shandong["confidence"] >= 0.8
def test_guangdong_is_high_quality_province(summary):
"""广东已进入 high 白名单。"""
by_name = {p["province"]: p for p in summary["provinces"]}
guangdong = by_name["广东"]
assert guangdong["quality_level"] == "high"
assert guangdong["confidence"] >= 0.8
def test_jiangsu_is_high_quality_province(summary):
"""江苏已进入 high 白名单。"""
by_name = {p["province"]: p for p in summary["provinces"]}
jiangsu = by_name["江苏"]
assert jiangsu["quality_level"] == "high"
assert jiangsu["confidence"] >= 0.8
def test_zhejiang_is_high_quality_province(summary):
"""浙江已进入 high 白名单。"""
by_name = {p["province"]: p for p in summary["provinces"]}
zhejiang = by_name["浙江"]
assert zhejiang["quality_level"] == "high"
assert zhejiang["confidence"] >= 0.8
def test_fujian_is_high_quality_province(summary):
"""福建已进入 high 白名单。"""
by_name = {p["province"]: p for p in summary["provinces"]}
fujian = by_name["福建"]
assert fujian["quality_level"] == "high"
assert fujian["confidence"] >= 0.8
def test_high_population_provinces_not_yet_high_remain_non_high(summary):
"""仍未进入白名单的高考生源大省必须继续保持 non-high。"""
by_name = {p["province"]: p for p in summary["provinces"]}
for province in HIGH_POPULATION_PROVINCES_NOT_YET_HIGH:
p = by_name.get(province)
assert p is not None, f"高考生源大省 {province} 不在 31 省列表内"
assert p["quality_level"] != "high", (
f"{province} 当前被标为 high但它不在当前 high 白名单。"
"如需升级,先补充白名单与审计口径。"
)
def test_quality_levels_are_valid_enum(summary):
"""所有 province 的 quality_level 必须是 high / usable / low / skeleton 之一。"""
valid_levels = {"high", "usable", "low", "skeleton"}
for p in summary["provinces"]:
assert p["quality_level"] in valid_levels, (
f"{p['province']} quality_level={p['quality_level']!r} 不在合法集合"
)
def test_confidence_values_in_valid_range(summary):
"""所有 province confidence 必须在 [0.0, 1.0]。"""
for p in summary["provinces"]:
c = p["confidence"]
assert 0.0 <= c <= 1.0, f"{p['province']} confidence={c} 越界"
def test_data_year_is_2025_until_2026_published(summary):
"""data_year 约定:部分省份已公布 2026 分数线可更新为 2026其他仍为 2025。
过渡期规则2026-06
- 已公布 2026 分数线的省份data_year=2026
- 待公布省份data_year=2025
- 不得出现非 2025/2026 的年份
已确认 2026 分数线公布省份2026-06-25
- 湖南 / 江苏 / 广东 / 山东 / 河北 / 河南
"""
invalid_provinces = []
valid_provinces_2026 = {"湖南", "江苏", "广东", "山东", "河北", "河南"}
for p in summary["provinces"]:
year = p["data_year"]
prov = p["province"]
if year not in {2025, 2026}:
invalid_provinces.append((prov, year))
# 已确认 2026 的省份必须为 2026
if prov in valid_provinces_2026 and year != 2026:
invalid_provinces.append((prov, year))
assert invalid_provinces == [], (
f"data_year 仅允许 2025/2026且已公布省份必须为 2026。"
f"发现异常: {invalid_provinces}"
)