| 877 | |
| 878 | |
| 879 | def core_info_structure_issues(text: str) -> list[dict[str, object]]: |
| 880 | body = section_body(text, "核心信息") |
| 881 | if not body: |
| 882 | return [] |
| 883 | |
| 884 | issues: list[dict[str, object]] = [] |
| 885 | seen_fields: set[str] = set() |
| 886 | last_known_index = -1 |
| 887 | base_line = _line_number_from_offset(text, text.find("## 核心信息")) |
| 888 | |
| 889 | for offset, raw_line in enumerate(body.splitlines(), start=1): |
| 890 | stripped = raw_line.strip() |
| 891 | if not stripped: |
| 892 | continue |
| 893 | line_number = base_line + offset |
| 894 | match = re.match(r"^-\s*([^::]+)\s*[::]\s*(.*)$", stripped) |
| 895 | if not match: |
| 896 | issues.append( |
| 897 | { |
| 898 | "line_number": line_number, |
| 899 | "line": stripped, |
| 900 | "reason": "core_info_non_metadata_line", |
| 901 | } |
| 902 | ) |
| 903 | continue |
| 904 | |
| 905 | field = match.group(1).strip() |
| 906 | if field not in CORE_INFO_FIELD_INDEX: |
| 907 | issues.append( |
| 908 | { |
| 909 | "line_number": line_number, |
| 910 | "line": stripped, |
| 911 | "reason": "core_info_unknown_field", |
| 912 | "field": field, |
| 913 | } |
| 914 | ) |
| 915 | continue |
| 916 | |
| 917 | if field in seen_fields: |
| 918 | issues.append( |
| 919 | { |
| 920 | "line_number": line_number, |
| 921 | "line": stripped, |
| 922 | "reason": "core_info_duplicate_field", |
| 923 | "field": field, |
| 924 | } |
| 925 | ) |
| 926 | continue |
| 927 | |
| 928 | field_index = CORE_INFO_FIELD_INDEX[field] |
| 929 | if field_index < last_known_index: |
| 930 | issues.append( |
| 931 | { |
| 932 | "line_number": line_number, |
| 933 | "line": stripped, |
| 934 | "reason": "core_info_field_order_invalid", |
| 935 | "field": field, |
| 936 | } |