From ae4835eeabbdcd517f0271649cac8b9df73bfd69 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Tue, 16 Jun 2026 18:14:41 +0800 Subject: [PATCH] feat(rules): add phase1 truth source loader and rules cli --- data/rules/__init__.py | 5 + data/rules/audit_engine.py | 39 +++++ data/rules/cli.py | 76 ++++++++++ data/rules/loader.py | 120 +++++++++++++++ data/rules/models.py | 26 ++++ docs/DESIGN_RULES_TRUSTED_CLI_2026-06-16.md | 6 +- ...PROJECT_PLANNING_REALIGNMENT_2026-06-16.md | 12 +- docs/RULES_SOURCE_OF_TRUTH.md | 10 +- rules/_truth/README.md | 13 ++ rules/_truth/national.yaml | 12 ++ rules/_truth/province/anhui.yaml | 94 ++++++++++++ rules/_truth/province/beijing.yaml | 94 ++++++++++++ rules/_truth/province/chongqing.yaml | 94 ++++++++++++ rules/_truth/province/fujian.yaml | 94 ++++++++++++ rules/_truth/province/gansu.yaml | 94 ++++++++++++ rules/_truth/province/guangdong.yaml | 94 ++++++++++++ rules/_truth/province/guangxi.yaml | 94 ++++++++++++ rules/_truth/province/guizhou.yaml | 94 ++++++++++++ rules/_truth/province/hainan.yaml | 94 ++++++++++++ rules/_truth/province/hebei.yaml | 94 ++++++++++++ rules/_truth/province/heilongjiang.yaml | 94 ++++++++++++ rules/_truth/province/henan.yaml | 94 ++++++++++++ rules/_truth/province/hubei.yaml | 94 ++++++++++++ rules/_truth/province/hunan.yaml | 94 ++++++++++++ rules/_truth/province/jiangsu.yaml | 94 ++++++++++++ rules/_truth/province/jiangxi.yaml | 94 ++++++++++++ rules/_truth/province/jilin.yaml | 94 ++++++++++++ rules/_truth/province/liaoning.yaml | 94 ++++++++++++ rules/_truth/province/qinghai.yaml | 94 ++++++++++++ rules/_truth/province/shandong.yaml | 94 ++++++++++++ rules/_truth/province/shanghai.yaml | 94 ++++++++++++ rules/_truth/province/sichuan.yaml | 94 ++++++++++++ rules/_truth/province/tianjin.yaml | 94 ++++++++++++ rules/_truth/province/xinjiang.yaml | 94 ++++++++++++ rules/_truth/province/xizang.yaml | 94 ++++++++++++ rules/_truth/province/yunnan.yaml | 94 ++++++++++++ rules/_truth/province/zhejiang.yaml | 94 ++++++++++++ scripts/__init__.py | 1 + scripts/gaokao-cli | 15 ++ scripts/migrate_province_rules_to_truth.py | 117 ++++++++++++++ tests/test_rules_cli_phase1.py | 47 ++++++ tests/test_rules_truth_phase1.py | 143 ++++++++++++++++++ 42 files changed, 3166 insertions(+), 14 deletions(-) create mode 100644 data/rules/__init__.py create mode 100644 data/rules/audit_engine.py create mode 100644 data/rules/cli.py create mode 100644 data/rules/loader.py create mode 100644 data/rules/models.py create mode 100644 rules/_truth/README.md create mode 100644 rules/_truth/national.yaml create mode 100644 rules/_truth/province/anhui.yaml create mode 100644 rules/_truth/province/beijing.yaml create mode 100644 rules/_truth/province/chongqing.yaml create mode 100644 rules/_truth/province/fujian.yaml create mode 100644 rules/_truth/province/gansu.yaml create mode 100644 rules/_truth/province/guangdong.yaml create mode 100644 rules/_truth/province/guangxi.yaml create mode 100644 rules/_truth/province/guizhou.yaml create mode 100644 rules/_truth/province/hainan.yaml create mode 100644 rules/_truth/province/hebei.yaml create mode 100644 rules/_truth/province/heilongjiang.yaml create mode 100644 rules/_truth/province/henan.yaml create mode 100644 rules/_truth/province/hubei.yaml create mode 100644 rules/_truth/province/hunan.yaml create mode 100644 rules/_truth/province/jiangsu.yaml create mode 100644 rules/_truth/province/jiangxi.yaml create mode 100644 rules/_truth/province/jilin.yaml create mode 100644 rules/_truth/province/liaoning.yaml create mode 100644 rules/_truth/province/qinghai.yaml create mode 100644 rules/_truth/province/shandong.yaml create mode 100644 rules/_truth/province/shanghai.yaml create mode 100644 rules/_truth/province/sichuan.yaml create mode 100644 rules/_truth/province/tianjin.yaml create mode 100644 rules/_truth/province/xinjiang.yaml create mode 100644 rules/_truth/province/xizang.yaml create mode 100644 rules/_truth/province/yunnan.yaml create mode 100644 rules/_truth/province/zhejiang.yaml create mode 100644 scripts/__init__.py create mode 100644 scripts/gaokao-cli create mode 100644 scripts/migrate_province_rules_to_truth.py create mode 100644 tests/test_rules_cli_phase1.py create mode 100644 tests/test_rules_truth_phase1.py diff --git a/data/rules/__init__.py b/data/rules/__init__.py new file mode 100644 index 0000000..39e31f5 --- /dev/null +++ b/data/rules/__init__.py @@ -0,0 +1,5 @@ +from .audit_engine import AuditEngine +from .loader import RuleLoader +from .models import LoadedRule, RulesStatus + +__all__ = ["AuditEngine", "RuleLoader", "LoadedRule", "RulesStatus"] diff --git a/data/rules/audit_engine.py b/data/rules/audit_engine.py new file mode 100644 index 0000000..3a53322 --- /dev/null +++ b/data/rules/audit_engine.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +from dataclasses import dataclass + +from .loader import RuleLoader +from .models import LoadedRule + + +@dataclass(frozen=True) +class ProvinceRuleSnapshot: + province: str + mode: str | None + max_volunteers: int | None + retrieval_rule: str | None + rule_count: int + rules: list[LoadedRule] + + +class AuditEngine: + def __init__(self, loader: RuleLoader) -> None: + self._loader = loader + + def get_province_snapshot(self, province: str) -> ProvinceRuleSnapshot: + rules = self._loader.list_province_rules(province) + as_map = {rule.rule_id.split(".", 1)[1]: rule for rule in rules} + return ProvinceRuleSnapshot( + province=province, + mode=_scalar(as_map.get("mode"), "mode"), + max_volunteers=_scalar(as_map.get("max_volunteers"), "max_volunteers"), + retrieval_rule=_scalar(as_map.get("retrieval_rule"), "retrieval_rule"), + rule_count=len(rules), + rules=rules, + ) + + +def _scalar(rule: LoadedRule | None, key: str): + if rule is None: + return None + return rule.value.get(key) diff --git a/data/rules/cli.py b/data/rules/cli.py new file mode 100644 index 0000000..efb9fe6 --- /dev/null +++ b/data/rules/cli.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +import argparse +import json +from pathlib import Path + +from data.rules.loader import RuleLoader + + +def _build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(prog="gaokao-cli") + subparsers = parser.add_subparsers(dest="command", required=True) + + rules_parser = subparsers.add_parser("rules", help="rules truth source commands") + rules_sub = rules_parser.add_subparsers(dest="rules_command", required=True) + + status_parser = rules_sub.add_parser("status", help="show rules truth status") + status_parser.add_argument("--truth-root", required=True) + status_parser.add_argument("--json", action="store_true") + + verify_parser = rules_sub.add_parser("verify", help="verify rules truth tree") + verify_parser.add_argument("--truth-root", required=True) + verify_parser.add_argument("--json", action="store_true") + + return parser + + +def _emit(payload: dict, json_output: bool) -> int: + if json_output: + print(json.dumps(payload, ensure_ascii=False)) + else: + print(payload) + return 0 if payload.get("ok", True) else 1 + + +def main(argv: list[str] | None = None) -> int: + parser = _build_parser() + args = parser.parse_args(argv) + + if args.command == "rules" and args.rules_command == "status": + loader = RuleLoader.from_truth_root(Path(args.truth_root)) + status = loader.build_status() + return _emit( + { + "ok": True, + "province_count": status.province_count, + "national_rule_count": status.national_rule_count, + "active_provinces": status.active_provinces, + }, + args.json, + ) + + if args.command == "rules" and args.rules_command == "verify": + loader = RuleLoader.from_truth_root(Path(args.truth_root)) + status = loader.build_status() + missing_required_files: list[str] = [] + if not (Path(args.truth_root) / "national.yaml").is_file(): + missing_required_files.append("national.yaml") + if not (Path(args.truth_root) / "province").is_dir(): + missing_required_files.append("province/") + return _emit( + { + "ok": not missing_required_files, + "province_count": status.province_count, + "national_rule_count": status.national_rule_count, + "missing_required_files": missing_required_files, + }, + args.json, + ) + + parser.error("unsupported command") + return 2 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/data/rules/loader.py b/data/rules/loader.py new file mode 100644 index 0000000..6acd1ab --- /dev/null +++ b/data/rules/loader.py @@ -0,0 +1,120 @@ +from __future__ import annotations + +from pathlib import Path +from typing import Any + +import yaml # type: ignore[import-untyped] + +from .models import LoadedRule, RulesStatus + + +PROVINCE_SLUGS = { + "安徽": "anhui", + "北京": "beijing", + "重庆": "chongqing", + "福建": "fujian", + "甘肃": "gansu", + "广东": "guangdong", + "广西": "guangxi", + "贵州": "guizhou", + "海南": "hainan", + "河北": "hebei", + "黑龙江": "heilongjiang", + "河南": "henan", + "湖北": "hubei", + "湖南": "hunan", + "吉林": "jilin", + "江苏": "jiangsu", + "江西": "jiangxi", + "辽宁": "liaoning", + "青海": "qinghai", + "山东": "shandong", + "山西": "shanxi", + "上海": "shanghai", + "四川": "sichuan", + "天津": "tianjin", + "西藏": "xizang", + "新疆": "xinjiang", + "云南": "yunnan", + "浙江": "zhejiang", +} + +SLUG_TO_PROVINCE = {value: key for key, value in PROVINCE_SLUGS.items()} + + +class RuleLoader: + def __init__(self, truth_root: Path) -> None: + self._truth_root = Path(truth_root) + self._national_doc = self._read_yaml(self._truth_root / "national.yaml") + self._province_docs = self._load_province_docs(self._truth_root / "province") + + @classmethod + def from_truth_root(cls, truth_root: Path | str) -> "RuleLoader": + return cls(Path(truth_root)) + + def list_national_rules(self) -> list[LoadedRule]: + return self._convert_rules(self._national_doc, scope="national", province=None) + + def list_province_rules(self, province: str) -> list[LoadedRule]: + doc = self._province_docs[province] + return self._convert_rules(doc, scope="province", province=province) + + def active_provinces(self) -> list[str]: + return sorted( + province + for province, doc in self._province_docs.items() + if doc.get("status", "active") == "active" + ) + + def build_status(self) -> RulesStatus: + return RulesStatus( + province_count=len(self.active_provinces()), + national_rule_count=len(self._national_doc.get("rules", {})), + active_provinces=self.active_provinces(), + ) + + def _load_province_docs(self, province_dir: Path) -> dict[str, dict[str, Any]]: + docs: dict[str, dict[str, Any]] = {} + for path in sorted(province_dir.glob("*.yaml")): + doc = self._read_yaml(path) + province = doc.get("province") or SLUG_TO_PROVINCE.get(path.stem) + if not province: + raise ValueError(f"cannot resolve province for truth file: {path}") + docs[province] = doc + return docs + + def _convert_rules( + self, doc: dict[str, Any], *, scope: str, province: str | None + ) -> list[LoadedRule]: + rules: list[LoadedRule] = [] + prefix = "NATIONAL" if scope == "national" else self._province_prefix(province) + for rule_key, payload in doc.get("rules", {}).items(): + rules.append( + LoadedRule( + rule_id=f"{prefix}.{rule_key}", + title=payload["title"], + severity=payload["severity"], + value=payload["value"], + source_evidence_id=payload["source_evidence_id"], + effective_date=payload["effective_date"], + status=payload.get("status", "active"), + scope=scope, + province=province, + year=doc.get("year", 2026), + version=doc.get("version", "2026.1"), + ) + ) + return rules + + @staticmethod + def _read_yaml(path: Path) -> dict[str, Any]: + return yaml.safe_load(path.read_text(encoding="utf-8")) or {} + + @staticmethod + def _province_prefix(province: str | None) -> str: + if not province: + return "PROVINCE" + slug = PROVINCE_SLUGS.get(province) + if slug: + return slug.upper() + return province.upper() diff --git a/data/rules/models.py b/data/rules/models.py new file mode 100644 index 0000000..ad218f9 --- /dev/null +++ b/data/rules/models.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + + +@dataclass(frozen=True) +class LoadedRule: + rule_id: str + title: str + severity: str + value: dict[str, Any] + source_evidence_id: str + effective_date: str + status: str + scope: str + province: str | None = None + year: int = 2026 + version: str = "2026.1" + + +@dataclass(frozen=True) +class RulesStatus: + province_count: int + national_rule_count: int + active_provinces: list[str] diff --git a/docs/DESIGN_RULES_TRUSTED_CLI_2026-06-16.md b/docs/DESIGN_RULES_TRUSTED_CLI_2026-06-16.md index 3866775..dc1514d 100644 --- a/docs/DESIGN_RULES_TRUSTED_CLI_2026-06-16.md +++ b/docs/DESIGN_RULES_TRUSTED_CLI_2026-06-16.md @@ -162,7 +162,7 @@ class AuditIssue: - 输出 `rules/_truth/province/*.yaml` - 保留 `gaokao-checker` 旧 API,但内部委托给 `audit_engine` -不破坏现有 28 省的覆盖。迁移后: +不破坏现有 27 省的覆盖。迁移后: - `PROVINCE_RULES` 作为"过渡期镜像"保留 - 新代码只读 `data/rules/loader.py` @@ -831,7 +831,7 @@ SQLite / 文件存储 任务: -1. 落 `rules/_truth/national.yaml` + `province/.yaml`(28 省) +1. 落 `rules/_truth/national.yaml` + `province/.yaml`(27 省) 2. 写迁移脚本 `scripts/migrate_province_rules_to_truth.py` 3. 落 `data/rules/loader.py` + `audit_engine.py` 最小可用版 4. 保留 `scripts/gaokao-checker` 与 SKILL 行为 @@ -841,7 +841,7 @@ SQLite / 文件存储 - `gaokao-cli rules status` 可用 - `gaokao-cli audit run` 行为与旧 `gaokao-checker` 一致 -- 28 省规则 100% 迁移 +- 27 省规则 100% 迁移 --- diff --git a/docs/PROJECT_PLANNING_REALIGNMENT_2026-06-16.md b/docs/PROJECT_PLANNING_REALIGNMENT_2026-06-16.md index 83af624..7e53896 100644 --- a/docs/PROJECT_PLANNING_REALIGNMENT_2026-06-16.md +++ b/docs/PROJECT_PLANNING_REALIGNMENT_2026-06-16.md @@ -29,15 +29,15 @@ - 传统模式 5 省 - 合计 27 省 - `skills/gaokao-spec-checker/SKILL.md` frontmatter: - - 列名包含 28 省(含广西) - - 摘要中按 14/8/6 描述,与 provinces.md 传统模式数量不同(5 vs 6) + - 列名宣称支持 27 省 + - 摘要中按 14/8/6 描述,与 `rules/provinces.md` 的传统模式数量(5) 不一致 - `scripts/gaokao-checker` 的 `PROVINCE_RULES`: - - 实际定义 28 省(含广西、山西) - - 但不包含陕西 + - 实际定义 27 省 + - 与 `rules/provinces.md` 的 27 省口径一致 - 真实差距: - 文档对外宣称 27 省 - - 实际规则 28 省 - - SKILL.md 与 provinces.md 的传统模式数对不上(6 vs 5) + - 实际规则也是 27 省 + - 但 `gaokao-spec-checker` 摘要里的传统模式数仍写成 6,与 `rules/provinces.md` 的 5 不一致 - 风险: - 客服/智能体在文档与脚本之间会获得不同省份覆盖承诺 - 后续任何"加省/删省"都会在三个真相源之间产生连锁漂移 diff --git a/docs/RULES_SOURCE_OF_TRUTH.md b/docs/RULES_SOURCE_OF_TRUTH.md index f588d66..34d9dde 100644 --- a/docs/RULES_SOURCE_OF_TRUTH.md +++ b/docs/RULES_SOURCE_OF_TRUTH.md @@ -81,15 +81,15 @@ Rule: | 河南 | 传统 | ✅ | ✅ | | | 四川 | 传统 | ✅ | ✅ | | | 云南 | 传统 | ✅ | ✅ | | -| 山西 | 传统 | ❌(SKILL.md 漏) | ✅(checker 有) | SKILL.md frontmatter 漂移待修 | -| 陕西 | — | ❌(SKILL.md 含) | ❌(checker 无) | checker 漂移待修 | +| 山西 | — | ❌(SKILL.md 漏) | ❌(checker 无) | SKILL.md frontmatter 漂移待修 | +| 陕西 | — | ❌(SKILL.md 含) | ❌(checker 无) | SKILL.md / checker 漂移待修 | --- ## 5. 文档漂移清单(已识别) -- D1: `rules/provinces.md` 描述 27 省,实际 28 省 -- D2: `skills/gaokao-spec-checker/SKILL.md` 含山西漏陕西 +- D1: `rules/provinces.md` 与 `scripts/gaokao-checker` 口径一致为 27 省 +- D2: `skills/gaokao-spec-checker/SKILL.md` frontmatter 与实际 checker 省份集仍有漂移 - D3: 传统模式数 provinces.md 写 5,SKILL.md 写 6 - D4: 文档与代码都没有 source_evidence_id 链 @@ -97,7 +97,7 @@ Rule: ## 6. Phase 1 必须收口 -- 28 省全部有 `province/.yaml` +- 27 省全部有 `province/.yaml` - 至少 1 条全国通用规则有 `national.yaml` - 1-2 个规则有真实 `source_evidence_id` 链路(湖南优先) - `gaokao-cli rules status` 可用 diff --git a/rules/_truth/README.md b/rules/_truth/README.md new file mode 100644 index 0000000..d08fd33 --- /dev/null +++ b/rules/_truth/README.md @@ -0,0 +1,13 @@ +# rules/\_truth + +本目录由 `python -m scripts.migrate_province_rules_to_truth` 生成并作为 Phase 1 的规则真相源基线。 + +结构: + +- `national.yaml` — 全国通用规则基线 +- `province/*.yaml` — 各省 2026 规则基线 + +当前策略: + +- 先从旧 `scripts/gaokao-checker` 的 `PROVINCE_RULES` 一次性迁移 +- 后续每次规则更新都必须同步 `source_evidence_id`、`last_verified_at` 与版本号 diff --git a/rules/_truth/national.yaml b/rules/_truth/national.yaml new file mode 100644 index 0000000..7fb537e --- /dev/null +++ b/rules/_truth/national.yaml @@ -0,0 +1,12 @@ +scope: national +year: 2026 +version: '2026.1' +rules: + parallel_volunteer_principle: + title: 平行志愿原则 + severity: info + value: + rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: national-2026-parallel-volunteer-principle + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/anhui.yaml b/rules/_truth/province/anhui.yaml new file mode 100644 index 0000000..ad3aca1 --- /dev/null +++ b/rules/_truth/province/anhui.yaml @@ -0,0 +1,94 @@ +scope: province +province: 安徽 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: anhui-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: anhui-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 45 + source_evidence_id: anhui-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: anhui-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: anhui-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: anhui-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: anhui-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 2 + source_evidence_id: anhui-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: anhui-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.ahzsks.cn/ + source_evidence_id: anhui-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: anhui-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/beijing.yaml b/rules/_truth/province/beijing.yaml new file mode 100644 index 0000000..d3b6924 --- /dev/null +++ b/rules/_truth/province/beijing.yaml @@ -0,0 +1,94 @@ +scope: province +province: 北京 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: beijing-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: beijing-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 30 + source_evidence_id: beijing-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: beijing-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: beijing-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: beijing-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: beijing-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: beijing-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+3 + source_evidence_id: beijing-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.bjeea.cn/ + source_evidence_id: beijing-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: beijing-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/chongqing.yaml b/rules/_truth/province/chongqing.yaml new file mode 100644 index 0000000..2259d9f --- /dev/null +++ b/rules/_truth/province/chongqing.yaml @@ -0,0 +1,94 @@ +scope: province +province: 重庆 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 专业+学校 + source_evidence_id: chongqing-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 普通批 + source_evidence_id: chongqing-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 96 + source_evidence_id: chongqing-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 1 + source_evidence_id: chongqing-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: false + source_evidence_id: chongqing-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 无 + source_evidence_id: chongqing-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: chongqing-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: chongqing-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: chongqing-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.cqksy.cn/ + source_evidence_id: chongqing-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: chongqing-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/fujian.yaml b/rules/_truth/province/fujian.yaml new file mode 100644 index 0000000..9102cb2 --- /dev/null +++ b/rules/_truth/province/fujian.yaml @@ -0,0 +1,94 @@ +scope: province +province: 福建 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: fujian-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: fujian-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 40 + source_evidence_id: fujian-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: fujian-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: fujian-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: fujian-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: fujian-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: fujian-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: fujian-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.eeafj.cn/ + source_evidence_id: fujian-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: fujian-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/gansu.yaml b/rules/_truth/province/gansu.yaml new file mode 100644 index 0000000..1763fa4 --- /dev/null +++ b/rules/_truth/province/gansu.yaml @@ -0,0 +1,94 @@ +scope: province +province: 甘肃 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: gansu-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: gansu-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 45 + source_evidence_id: gansu-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: gansu-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: gansu-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: gansu-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: gansu-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 2 + source_evidence_id: gansu-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: gansu-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.ganseea.cn/ + source_evidence_id: gansu-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: gansu-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/guangdong.yaml b/rules/_truth/province/guangdong.yaml new file mode 100644 index 0000000..e2aba23 --- /dev/null +++ b/rules/_truth/province/guangdong.yaml @@ -0,0 +1,94 @@ +scope: province +province: 广东 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: guangdong-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: guangdong-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 45 + source_evidence_id: guangdong-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: guangdong-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: guangdong-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: guangdong-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: guangdong-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 2 + source_evidence_id: guangdong-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: guangdong-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: http://eea.gd.gov.cn/ + source_evidence_id: guangdong-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: guangdong-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/guangxi.yaml b/rules/_truth/province/guangxi.yaml new file mode 100644 index 0000000..b26d230 --- /dev/null +++ b/rules/_truth/province/guangxi.yaml @@ -0,0 +1,94 @@ +scope: province +province: 广西 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: guangxi-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: guangxi-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 40 + source_evidence_id: guangxi-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: guangxi-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: guangxi-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: guangxi-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: guangxi-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 2 + source_evidence_id: guangxi-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: guangxi-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.gxeea.cn/ + source_evidence_id: guangxi-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: guangxi-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/guizhou.yaml b/rules/_truth/province/guizhou.yaml new file mode 100644 index 0000000..248fc52 --- /dev/null +++ b/rules/_truth/province/guizhou.yaml @@ -0,0 +1,94 @@ +scope: province +province: 贵州 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 专业+学校 + source_evidence_id: guizhou-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 普通批 + source_evidence_id: guizhou-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 96 + source_evidence_id: guizhou-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 1 + source_evidence_id: guizhou-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: false + source_evidence_id: guizhou-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 无 + source_evidence_id: guizhou-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: guizhou-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: guizhou-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: guizhou-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://zsksy.guizhou.gov.cn/ + source_evidence_id: guizhou-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: guizhou-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/hainan.yaml b/rules/_truth/province/hainan.yaml new file mode 100644 index 0000000..b293392 --- /dev/null +++ b/rules/_truth/province/hainan.yaml @@ -0,0 +1,94 @@ +scope: province +province: 海南 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: hainan-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: hainan-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 24 + source_evidence_id: hainan-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: hainan-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: hainan-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: hainan-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: hainan-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: hainan-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+3 + source_evidence_id: hainan-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://ea.hainan.gov.cn/ + source_evidence_id: hainan-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 900 + source_evidence_id: hainan-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/hebei.yaml b/rules/_truth/province/hebei.yaml new file mode 100644 index 0000000..43db1a9 --- /dev/null +++ b/rules/_truth/province/hebei.yaml @@ -0,0 +1,94 @@ +scope: province +province: 河北 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 专业+学校 + source_evidence_id: hebei-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 普通批 + source_evidence_id: hebei-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 96 + source_evidence_id: hebei-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 1 + source_evidence_id: hebei-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: false + source_evidence_id: hebei-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 无 + source_evidence_id: hebei-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: hebei-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: hebei-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: hebei-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.hebeea.edu.cn/ + source_evidence_id: hebei-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: hebei-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/heilongjiang.yaml b/rules/_truth/province/heilongjiang.yaml new file mode 100644 index 0000000..8bd80e1 --- /dev/null +++ b/rules/_truth/province/heilongjiang.yaml @@ -0,0 +1,94 @@ +scope: province +province: 黑龙江 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: heilongjiang-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: heilongjiang-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 45 + source_evidence_id: heilongjiang-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: heilongjiang-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: heilongjiang-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: heilongjiang-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: heilongjiang-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 2 + source_evidence_id: heilongjiang-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: heilongjiang-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.lzk.hl.cn/ + source_evidence_id: heilongjiang-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: heilongjiang-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/henan.yaml b/rules/_truth/province/henan.yaml new file mode 100644 index 0000000..6b2e1ad --- /dev/null +++ b/rules/_truth/province/henan.yaml @@ -0,0 +1,94 @@ +scope: province +province: 河南 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 传统 + source_evidence_id: henan-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科一批 + source_evidence_id: henan-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 6 + source_evidence_id: henan-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 5 + source_evidence_id: henan-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: henan-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 全部专业 + source_evidence_id: henan-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: henan-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: henan-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 传统 + source_evidence_id: henan-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.haeea.cn/ + source_evidence_id: henan-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: henan-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/hubei.yaml b/rules/_truth/province/hubei.yaml new file mode 100644 index 0000000..1f697bd --- /dev/null +++ b/rules/_truth/province/hubei.yaml @@ -0,0 +1,94 @@ +scope: province +province: 湖北 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: hubei-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: hubei-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 45 + source_evidence_id: hubei-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: hubei-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: hubei-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: hubei-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: hubei-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 2 + source_evidence_id: hubei-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: hubei-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: http://www.hbea.edu.cn/ + source_evidence_id: hubei-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: hubei-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/hunan.yaml b/rules/_truth/province/hunan.yaml new file mode 100644 index 0000000..50259eb --- /dev/null +++ b/rules/_truth/province/hunan.yaml @@ -0,0 +1,94 @@ +scope: province +province: 湖南 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: hunan-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: hunan-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 45 + source_evidence_id: hunan-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: hunan-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: hunan-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: hunan-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: hunan-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 2 + source_evidence_id: hunan-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: hunan-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: http://jyt.hunan.gov.cn/jyt/sjyt/hnsjyksy/ + source_evidence_id: hunan-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: hunan-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/jiangsu.yaml b/rules/_truth/province/jiangsu.yaml new file mode 100644 index 0000000..7f4c815 --- /dev/null +++ b/rules/_truth/province/jiangsu.yaml @@ -0,0 +1,94 @@ +scope: province +province: 江苏 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: jiangsu-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: jiangsu-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 40 + source_evidence_id: jiangsu-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: jiangsu-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: jiangsu-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: jiangsu-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: jiangsu-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: jiangsu-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: jiangsu-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: http://www.jseea.cn/ + source_evidence_id: jiangsu-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: jiangsu-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/jiangxi.yaml b/rules/_truth/province/jiangxi.yaml new file mode 100644 index 0000000..3495505 --- /dev/null +++ b/rules/_truth/province/jiangxi.yaml @@ -0,0 +1,94 @@ +scope: province +province: 江西 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: jiangxi-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: jiangxi-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 45 + source_evidence_id: jiangxi-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: jiangxi-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: jiangxi-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: jiangxi-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: jiangxi-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 2 + source_evidence_id: jiangxi-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: jiangxi-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: http://www.jxeea.cn/ + source_evidence_id: jiangxi-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: jiangxi-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/jilin.yaml b/rules/_truth/province/jilin.yaml new file mode 100644 index 0000000..68d71cb --- /dev/null +++ b/rules/_truth/province/jilin.yaml @@ -0,0 +1,94 @@ +scope: province +province: 吉林 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 专业+学校 + source_evidence_id: jilin-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 普通批 + source_evidence_id: jilin-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 50 + source_evidence_id: jilin-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 1 + source_evidence_id: jilin-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: false + source_evidence_id: jilin-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 无 + source_evidence_id: jilin-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: jilin-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: jilin-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: jilin-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.jleea.com.cn/ + source_evidence_id: jilin-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: jilin-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/liaoning.yaml b/rules/_truth/province/liaoning.yaml new file mode 100644 index 0000000..bb4b5c0 --- /dev/null +++ b/rules/_truth/province/liaoning.yaml @@ -0,0 +1,94 @@ +scope: province +province: 辽宁 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 专业+学校 + source_evidence_id: liaoning-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 普通批 + source_evidence_id: liaoning-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 112 + source_evidence_id: liaoning-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 1 + source_evidence_id: liaoning-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: false + source_evidence_id: liaoning-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 无 + source_evidence_id: liaoning-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: liaoning-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: liaoning-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: liaoning-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.lnzsks.com/ + source_evidence_id: liaoning-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: liaoning-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/qinghai.yaml b/rules/_truth/province/qinghai.yaml new file mode 100644 index 0000000..7dd38d0 --- /dev/null +++ b/rules/_truth/province/qinghai.yaml @@ -0,0 +1,94 @@ +scope: province +province: 青海 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 专业+学校 + source_evidence_id: qinghai-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 普通批 + source_evidence_id: qinghai-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 96 + source_evidence_id: qinghai-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 1 + source_evidence_id: qinghai-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: false + source_evidence_id: qinghai-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 无 + source_evidence_id: qinghai-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: qinghai-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: qinghai-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+1+2 + source_evidence_id: qinghai-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: http://www.qhzk.com/ + source_evidence_id: qinghai-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: qinghai-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/shandong.yaml b/rules/_truth/province/shandong.yaml new file mode 100644 index 0000000..3622cad --- /dev/null +++ b/rules/_truth/province/shandong.yaml @@ -0,0 +1,94 @@ +scope: province +province: 山东 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 专业+学校 + source_evidence_id: shandong-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 普通批 + source_evidence_id: shandong-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 96 + source_evidence_id: shandong-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 1 + source_evidence_id: shandong-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: false + source_evidence_id: shandong-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 无 + source_evidence_id: shandong-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: shandong-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: shandong-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+3 + source_evidence_id: shandong-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.sdzk.cn/ + source_evidence_id: shandong-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: shandong-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/shanghai.yaml b/rules/_truth/province/shanghai.yaml new file mode 100644 index 0000000..8a81dd8 --- /dev/null +++ b/rules/_truth/province/shanghai.yaml @@ -0,0 +1,94 @@ +scope: province +province: 上海 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: shanghai-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: shanghai-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 24 + source_evidence_id: shanghai-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 4 + source_evidence_id: shanghai-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: shanghai-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: shanghai-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: shanghai-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: shanghai-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+3 + source_evidence_id: shanghai-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.shmeea.edu.cn/ + source_evidence_id: shanghai-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 660 + source_evidence_id: shanghai-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/sichuan.yaml b/rules/_truth/province/sichuan.yaml new file mode 100644 index 0000000..dbd34bf --- /dev/null +++ b/rules/_truth/province/sichuan.yaml @@ -0,0 +1,94 @@ +scope: province +province: 四川 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 传统 + source_evidence_id: sichuan-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科一批 + source_evidence_id: sichuan-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 9 + source_evidence_id: sichuan-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: sichuan-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: sichuan-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 全部专业 + source_evidence_id: sichuan-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: sichuan-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: sichuan-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 传统 + source_evidence_id: sichuan-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.sceea.cn/ + source_evidence_id: sichuan-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: sichuan-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/tianjin.yaml b/rules/_truth/province/tianjin.yaml new file mode 100644 index 0000000..06c7015 --- /dev/null +++ b/rules/_truth/province/tianjin.yaml @@ -0,0 +1,94 @@ +scope: province +province: 天津 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 院校专业组 + source_evidence_id: tianjin-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科批 + source_evidence_id: tianjin-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 50 + source_evidence_id: tianjin-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: tianjin-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: tianjin-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 组内专业 + source_evidence_id: tianjin-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: tianjin-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: tianjin-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+3 + source_evidence_id: tianjin-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: http://www.zhaoban.tjzhaokao.com/ + source_evidence_id: tianjin-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: tianjin-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/xinjiang.yaml b/rules/_truth/province/xinjiang.yaml new file mode 100644 index 0000000..965b63e --- /dev/null +++ b/rules/_truth/province/xinjiang.yaml @@ -0,0 +1,94 @@ +scope: province +province: 新疆 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 传统 + source_evidence_id: xinjiang-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科一批 + source_evidence_id: xinjiang-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 9 + source_evidence_id: xinjiang-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 6 + source_evidence_id: xinjiang-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: xinjiang-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 全部专业 + source_evidence_id: xinjiang-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 志愿优先、遵循志愿 + source_evidence_id: xinjiang-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: xinjiang-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 传统 + source_evidence_id: xinjiang-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: http://www.xjzk.gov.cn/ + source_evidence_id: xinjiang-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: xinjiang-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/xizang.yaml b/rules/_truth/province/xizang.yaml new file mode 100644 index 0000000..f8b1ea4 --- /dev/null +++ b/rules/_truth/province/xizang.yaml @@ -0,0 +1,94 @@ +scope: province +province: 西藏 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 传统 + source_evidence_id: xizang-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科二批 + source_evidence_id: xizang-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 10 + source_evidence_id: xizang-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 4 + source_evidence_id: xizang-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: xizang-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 全部专业 + source_evidence_id: xizang-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿 + source_evidence_id: xizang-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: xizang-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 传统 + source_evidence_id: xizang-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: http://zsks.edu.xizang.gov.cn/ + source_evidence_id: xizang-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: xizang-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/yunnan.yaml b/rules/_truth/province/yunnan.yaml new file mode 100644 index 0000000..e3e1886 --- /dev/null +++ b/rules/_truth/province/yunnan.yaml @@ -0,0 +1,94 @@ +scope: province +province: 云南 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 传统 + source_evidence_id: yunnan-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 本科一批 + source_evidence_id: yunnan-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 5 + source_evidence_id: yunnan-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 5 + source_evidence_id: yunnan-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: true + source_evidence_id: yunnan-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 全部专业 + source_evidence_id: yunnan-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿 + source_evidence_id: yunnan-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: yunnan-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 传统 + source_evidence_id: yunnan-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.ynzs.cn/ + source_evidence_id: yunnan-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: yunnan-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/rules/_truth/province/zhejiang.yaml b/rules/_truth/province/zhejiang.yaml new file mode 100644 index 0000000..9689f6e --- /dev/null +++ b/rules/_truth/province/zhejiang.yaml @@ -0,0 +1,94 @@ +scope: province +province: 浙江 +year: 2026 +version: '2026.1' +status: active +rules: + mode: + title: 志愿模式 + severity: fatal + value: + mode: 专业+学校 + source_evidence_id: zhejiang-2026-mode + effective_date: '2026-01-01' + status: active + batch: + title: 批次名称 + severity: info + value: + batch: 普通批 + source_evidence_id: zhejiang-2026-batch + effective_date: '2026-01-01' + status: active + max_volunteers: + title: 志愿上限 + severity: fatal + value: + max_volunteers: 80 + source_evidence_id: zhejiang-2026-max_volunteers + effective_date: '2026-01-01' + status: active + max_majors_per_group: + title: 每组专业上限 + severity: warning + value: + max_majors_per_group: 1 + source_evidence_id: zhejiang-2026-max_majors_per_group + effective_date: '2026-01-01' + status: active + has_adjustment: + title: 是否允许调剂 + severity: warning + value: + has_adjustment: false + source_evidence_id: zhejiang-2026-has_adjustment + effective_date: '2026-01-01' + status: active + adjustment_scope: + title: 调剂范围 + severity: fatal + value: + adjustment_scope: 无 + source_evidence_id: zhejiang-2026-adjustment_scope + effective_date: '2026-01-01' + status: active + retrieval_rule: + title: 投档原则 + severity: critical + value: + retrieval_rule: 分数优先、遵循志愿、一次投档 + source_evidence_id: zhejiang-2026-retrieval_rule + effective_date: '2026-01-01' + status: active + collection_count: + title: 征集志愿次数 + severity: warning + value: + collection_count: 1 + source_evidence_id: zhejiang-2026-collection_count + effective_date: '2026-01-01' + status: active + subject_mode: + title: 选科模式 + severity: warning + value: + subject_mode: 3+3 + source_evidence_id: zhejiang-2026-subject_mode + effective_date: '2026-01-01' + status: active + official_url: + title: 官方来源链接 + severity: info + value: + official_url: https://www.zjzs.net/ + source_evidence_id: zhejiang-2026-official_url + effective_date: '2026-01-01' + status: active + exam_subject_total: + title: 总分 + severity: info + value: + exam_subject_total: 750 + source_evidence_id: zhejiang-2026-exam_subject_total + effective_date: '2026-01-01' + status: active diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 0000000..cfa1227 --- /dev/null +++ b/scripts/__init__.py @@ -0,0 +1 @@ +"""Project scripts package for importable migration/helpers tests.""" diff --git a/scripts/gaokao-cli b/scripts/gaokao-cli new file mode 100644 index 0000000..52fdabf --- /dev/null +++ b/scripts/gaokao-cli @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import sys +from pathlib import Path + +PROJECT_ROOT = Path(__file__).resolve().parent.parent +if str(PROJECT_ROOT) not in sys.path: + sys.path.insert(0, str(PROJECT_ROOT)) + +from data.rules.cli import main # noqa: E402 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/migrate_province_rules_to_truth.py b/scripts/migrate_province_rules_to_truth.py new file mode 100644 index 0000000..a74f84f --- /dev/null +++ b/scripts/migrate_province_rules_to_truth.py @@ -0,0 +1,117 @@ +from __future__ import annotations + +import importlib.util +from importlib.machinery import SourceFileLoader +from pathlib import Path +from typing import Any + +import yaml # type: ignore[import-untyped] + +from data.rules.loader import PROVINCE_SLUGS + + +PROJECT_ROOT = Path(__file__).resolve().parent.parent +LEGACY_CHECKER_PATH = PROJECT_ROOT / "scripts" / "gaokao-checker" + +RULE_FIELD_METADATA = { + "mode": ("志愿模式", "fatal"), + "batch": ("批次名称", "info"), + "max_volunteers": ("志愿上限", "fatal"), + "max_majors_per_group": ("每组专业上限", "warning"), + "has_adjustment": ("是否允许调剂", "warning"), + "adjustment_scope": ("调剂范围", "fatal"), + "retrieval_rule": ("投档原则", "critical"), + "collection_count": ("征集志愿次数", "warning"), + "subject_mode": ("选科模式", "warning"), + "official_url": ("官方来源链接", "info"), + "exam_subject_total": ("总分", "info"), +} + + +def _load_legacy_checker_module(): + loader = SourceFileLoader("legacy_gaokao_checker", str(LEGACY_CHECKER_PATH)) + spec = importlib.util.spec_from_loader(loader.name, loader) + if spec is None or spec.loader is None: + raise RuntimeError(f"failed to load legacy checker from {LEGACY_CHECKER_PATH}") + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +def _build_national_truth() -> dict[str, Any]: + return { + "scope": "national", + "year": 2026, + "version": "2026.1", + "rules": { + "parallel_volunteer_principle": { + "title": "平行志愿原则", + "severity": "info", + "value": {"rule": "分数优先、遵循志愿、一次投档"}, + "source_evidence_id": "national-2026-parallel-volunteer-principle", + "effective_date": "2026-01-01", + "status": "active", + } + }, + } + + +def _build_province_truth(province: str, payload: dict[str, Any]) -> dict[str, Any]: + rules: dict[str, Any] = {} + for key, value in payload.items(): + title, severity = RULE_FIELD_METADATA.get(key, (key, "info")) + rules[key] = { + "title": title, + "severity": severity, + "value": {key: value}, + "source_evidence_id": f"{PROVINCE_SLUGS[province]}-2026-{key}", + "effective_date": "2026-01-01", + "status": "active", + } + return { + "scope": "province", + "province": province, + "year": 2026, + "version": "2026.1", + "status": "active", + "rules": rules, + } + + +def migrate_legacy_rules_to_truth(output_root: Path | str) -> dict[str, int]: + legacy = _load_legacy_checker_module() + target_root = Path(output_root) + province_dir = target_root / "province" + province_dir.mkdir(parents=True, exist_ok=True) + + national_truth = _build_national_truth() + (target_root / "national.yaml").write_text( + yaml.safe_dump(national_truth, allow_unicode=True, sort_keys=False), + encoding="utf-8", + ) + + for province, payload in sorted(legacy.PROVINCE_RULES.items()): + slug = PROVINCE_SLUGS.get(province) + if not slug: + raise KeyError(f"missing province slug mapping for {province}") + truth_doc = _build_province_truth(province, payload) + (province_dir / f"{slug}.yaml").write_text( + yaml.safe_dump(truth_doc, allow_unicode=True, sort_keys=False), + encoding="utf-8", + ) + + return { + "province_count": len(legacy.PROVINCE_RULES), + "national_rule_count": len(national_truth["rules"]), + } + + +def main() -> int: + output_root = PROJECT_ROOT / "rules" / "_truth" + summary = migrate_legacy_rules_to_truth(output_root=output_root) + print(summary) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/test_rules_cli_phase1.py b/tests/test_rules_cli_phase1.py new file mode 100644 index 0000000..9e49540 --- /dev/null +++ b/tests/test_rules_cli_phase1.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +import json +import subprocess +import sys +from pathlib import Path + + +PROJECT_ROOT = Path(__file__).resolve().parents[1] +SCRIPT_PATH = PROJECT_ROOT / "scripts" / "gaokao-cli" + + +def _run_cli(*args: str) -> subprocess.CompletedProcess[str]: + return subprocess.run( + [sys.executable, str(SCRIPT_PATH), *args], + cwd=PROJECT_ROOT, + capture_output=True, + text=True, + ) + + +def test_rules_status_cli_reports_truth_root_summary(tmp_path: Path) -> None: + from scripts.migrate_province_rules_to_truth import migrate_legacy_rules_to_truth + + migrate_legacy_rules_to_truth(output_root=tmp_path) + + result = _run_cli("rules", "status", "--truth-root", str(tmp_path), "--json") + + assert result.returncode == 0, result.stderr + payload = json.loads(result.stdout) + assert payload["province_count"] == 27 + assert payload["national_rule_count"] == 1 + assert "湖南" in payload["active_provinces"] + + +def test_rules_verify_cli_confirms_truth_tree_is_valid(tmp_path: Path) -> None: + from scripts.migrate_province_rules_to_truth import migrate_legacy_rules_to_truth + + migrate_legacy_rules_to_truth(output_root=tmp_path) + + result = _run_cli("rules", "verify", "--truth-root", str(tmp_path), "--json") + + assert result.returncode == 0, result.stderr + payload = json.loads(result.stdout) + assert payload["ok"] is True + assert payload["province_count"] == 27 + assert payload["missing_required_files"] == [] diff --git a/tests/test_rules_truth_phase1.py b/tests/test_rules_truth_phase1.py new file mode 100644 index 0000000..add7df1 --- /dev/null +++ b/tests/test_rules_truth_phase1.py @@ -0,0 +1,143 @@ +from __future__ import annotations + +import importlib.util +from importlib.machinery import SourceFileLoader +from pathlib import Path + +import yaml # type: ignore[import-untyped] + + +PROJECT_ROOT = Path(__file__).resolve().parents[1] +LEGACY_CHECKER_PATH = PROJECT_ROOT / "scripts" / "gaokao-checker" + + +def _load_legacy_checker_module(): + loader = SourceFileLoader("legacy_gaokao_checker", str(LEGACY_CHECKER_PATH)) + spec = importlib.util.spec_from_loader(loader.name, loader) + assert spec is not None and spec.loader is not None + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +def test_migrate_province_rules_to_truth_exports_all_legacy_provinces( + tmp_path: Path, +) -> None: + legacy = _load_legacy_checker_module() + + from scripts.migrate_province_rules_to_truth import migrate_legacy_rules_to_truth + + summary = migrate_legacy_rules_to_truth(output_root=tmp_path) + + province_dir = tmp_path / "province" + province_files = sorted(province_dir.glob("*.yaml")) + + assert summary["province_count"] == len(legacy.PROVINCE_RULES) + assert len(province_files) == len(legacy.PROVINCE_RULES) + assert (tmp_path / "national.yaml").is_file() + + hunan_truth = yaml.safe_load( + (province_dir / "hunan.yaml").read_text(encoding="utf-8") + ) + assert hunan_truth["province"] == "湖南" + assert hunan_truth["year"] == 2026 + assert hunan_truth["status"] == "active" + assert hunan_truth["rules"]["max_volunteers"]["value"] == {"max_volunteers": 45} + assert hunan_truth["rules"]["max_volunteers"]["source_evidence_id"] + + +def test_rule_loader_reads_national_and_province_truth_tree(tmp_path: Path) -> None: + truth_root = tmp_path + (truth_root / "province").mkdir(parents=True, exist_ok=True) + + (truth_root / "national.yaml").write_text( + yaml.safe_dump( + { + "scope": "national", + "year": 2026, + "version": "2026.1", + "rules": { + "parallel_volunteer_principle": { + "title": "平行志愿原则", + "severity": "info", + "value": {"rule": "分数优先、遵循志愿、一次投档"}, + "source_evidence_id": "national-2026-parallel-rule", + "effective_date": "2026-01-01", + "status": "active", + } + }, + }, + allow_unicode=True, + sort_keys=False, + ), + encoding="utf-8", + ) + + (truth_root / "province" / "hunan.yaml").write_text( + yaml.safe_dump( + { + "scope": "province", + "province": "湖南", + "year": 2026, + "version": "2026.1", + "status": "active", + "rules": { + "max_volunteers": { + "title": "本科批志愿上限", + "severity": "fatal", + "value": {"max_volunteers": 45}, + "source_evidence_id": "hunan-2026-max-volunteers", + "effective_date": "2026-01-01", + "status": "active", + } + }, + }, + allow_unicode=True, + sort_keys=False, + ), + encoding="utf-8", + ) + + from data.rules.loader import RuleLoader + + loader = RuleLoader.from_truth_root(truth_root) + status = loader.build_status() + rules = loader.list_province_rules("湖南") + national = loader.list_national_rules() + + assert status.province_count == 1 + assert status.national_rule_count == 1 + assert status.active_provinces == ["湖南"] + assert rules[0].rule_id == "HUNAN.max_volunteers" + assert rules[0].value["max_volunteers"] == 45 + assert national[0].rule_id == "NATIONAL.parallel_volunteer_principle" + + +def test_migrated_truth_set_matches_legacy_checker_provinces(tmp_path: Path) -> None: + legacy = _load_legacy_checker_module() + + from scripts.migrate_province_rules_to_truth import migrate_legacy_rules_to_truth + from data.rules.loader import RuleLoader + + migrate_legacy_rules_to_truth(output_root=tmp_path) + loader = RuleLoader.from_truth_root(tmp_path) + + assert set(loader.active_provinces()) == set(legacy.PROVINCE_RULES.keys()) + + +def test_audit_engine_exposes_province_snapshot_from_truth(tmp_path: Path) -> None: + from data.rules.audit_engine import AuditEngine + from data.rules.loader import RuleLoader + from scripts.migrate_province_rules_to_truth import migrate_legacy_rules_to_truth + + migrate_legacy_rules_to_truth(output_root=tmp_path) + loader = RuleLoader.from_truth_root(tmp_path) + engine = AuditEngine(loader) + + snapshot = engine.get_province_snapshot("湖南") + + assert snapshot.province == "湖南" + assert snapshot.mode == "院校专业组" + assert snapshot.max_volunteers == 45 + assert snapshot.retrieval_rule == "分数优先、遵循志愿、一次投档" + assert snapshot.rule_count >= 5