Files
gaokao-volunteer-system/data/crowd_db/tests/test_crowd_db_data_quality.py
Hermes Agent 860365b04d
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): 补录浙江/四川2026分数线并同步过渡期测试
按用户提供的31省2026分数线汇总继续补充最新数据。

本次补录:
- 浙江:官方页确认 2026 分数线为 特控594 / 一段494 / 二段266
- 四川:准官方汇总源确认 2026 分数线为 本科历史455 / 物理435 / 特控历史525

落地方式:
- zhejiang.json / sichuan.json data_year -> 2026
- 更新 source_url / quality_note
- 保持现有高信任推荐内容,仅做元数据与数据年份收口,不做无依据的大幅 score_ranges 重排

同步修复:
- test_crowd_db_data_quality.py: 已确认2026省份集合扩展到8省
- test_provenance_query.py: 2025/2026 过渡期断言从 25 调整到 23
- test_risk_report.py / test_trace_cli.py: 允许 2025/2026 data_year
- check_crowd_db_consistency.py: 明确允许 2025+2026 多年份共存

验证:
- pytest crowd_db: 155 passed, 3 skipped
- consistency: high=31 usable=0 low=0 skeleton=0
- balance check: 通过
2026-06-25 19:32:14 +08:00

217 lines
7.5 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}"
)