# COBOL 迁移验证平台 第二阶段设计书 > 版本: v2.0 | 日期: 2026-06-19 > 基于: cobol-test-benchmark.md 的 33+2 程序类型分类体系 > 范围: 12 个 Phase,从类型判定引擎完善到完整测试基准实现 --- ## 目录 1. [设计总则](#1-设计总则) 2. [Phase 1: extract_structure 输出扩展](#2-phase-1-extract_structure-输出扩展) 3. [Phase 2: 混淆组判定规则引擎](#3-phase-2-混淆组判定规则引擎) 4. [Phase 3: 确信度 4 因子计算](#4-phase-3-确信度-4-因子计算) 5. [Phase 4: 33+2 种程序类型 COBOL 测试样本](#5-phase-4-332-种程序类型-cobol-测试样本) 6. [Phase 5: 参数化测试数据生成引擎](#6-phase-5-参数化测试数据生成引擎) 7. [Phase 6: 日文测试数据生成查找表](#7-phase-6-日文测试数据生成查找表) 8. [Phase 7-10: 类型别测试套件](#8-phase-7-10-类型别测试套件) 9. [Phase 11: 完整类型判定管道](#9-phase-11-完整类型判定管道) 10. [Phase 12: 文档更新](#10-phase-12-文档更新) 11. [依赖关系与分工矩阵](#11-依赖关系与分工矩阵) 12. [接口变更一览](#12-接口变更一览) 13. [COBOL 覆盖率测试体系](#13-cobol-覆盖率测试体系) 14. [架构审核决议汇总](#14-架构审核决议汇总) --- ## 1. 设计总则 ### 1.1 新增 Phase 0.6: gcov 基础设施 > 在 Phase 1 之前完成,为所有类型测试提供 gcov 能力。 > 负责: F | 工作量: 3h 为覆盖率测试体系提供可自动化运行的基础设施。Phase 7-10 中所有 gcov 测试的前置条件。 | 步骤 | 内容 | 工作量 | |:-----|:-----|:------| | 1 | `cobc --coverage` 环境验证自动化 | 0.5h | | 2 | `collect_gcov()` 路径修复(含中文目录兼容)| 1h | | 3 | `Config` 追加 gcov_enabled / gcov_work_dir / gcov_threshold | 0.5h | | 4 | `test_gcov_basic.py` — gcov 全链路验证测试 | 1h | **验收**: cobc --coverage 编译 → 运行 → .gcda 生成 → collect_gcov() line_rate > 0 ```python # config/__init__.py — Config 新增字段 gcov_enabled: bool = False gcov_work_dir: str = ".gcov_output" gcov_threshold: float = 0.5 ``` ### 1.3 分层原则 ``` Layer 1: data/ — 所有模块共享的数据契约 Layer 2: 核心引擎 — cobol_testgen/ config/ jcl/ quality/ report/ preprocessor/ Layer 3: 业务引擎 — hina/ agents/ comparator/ runners/ Layer 4: 管道集成 — orchestrator/ web/ 依赖方向: Layer 1 ← Layer 2 ← Layer 3 ← Layer 4 禁止逆向依赖。 ``` ### 1.4 模块通信规则 - 所有模块间通信通过 `data/` 层的数据类进行 - 每个模块的公开 API 由 `__init__.py` 的 `__all__` 定义 - 禁止钻入模块内部(如 `from cobol_testgen.coverage import ...`) - 详见 `CONTRIBUTING.md` ### 1.5 最终模块布局(经架构审核确认) ``` 项目根目录/ ├── cobol_testgen/ ← COBOL 解析引擎 (P1扩展) │ ├── hina/ │ ├── rule_engine/ ← 混淆组规则引擎 (P2) │ ├── confidence.py ← 确信度 4 因子计算 (P3) │ └── pipeline/ ← 完整类型判定管道 (P11) │ ├── parametrized/ ← 独立模块!参数化测试数据生成引擎 (P5) │ ├── __init__.py │ ├── matching.py │ ├── division.py │ └── common.py │ ├── japanese_data.py ← 独立文件!日文测试数据查找表 (P6) │ ├── test-data/cobol/ ← 新增 33+2 种 COBOL 样本 (P4) │ ├── tests/ │ └── parametrized/ ← 类型别测试套件 (P7-10) │ └── docs/ ← 文档更新 (P12) 重要决策: ✅ classification_pipeline/ → 合并到 hina/pipeline/ ✅ parametrized/ → 独立模块(项目根目录) ✅ japanese_data.py → 独立文件(项目根目录) ``` --- ## 2. Phase 1: extract_structure 输出扩展 ### 2.1 目的 当前 `extract_structure()` 输出的结构特征不足以判定 33+2 种程序类型。需要增加以下字段。 ### 2.2 新增输出字段 在 `cobol_testgen/__init__.py` 的 `extract_structure()` 返回字典中追加: ```python # 新增字段(原有字段不变) { # ── 文件相关 ── "select_files": { # SELECT 语句列表 "INFILE": {"assign_to": "INPUT.DAT", "organization": "SEQUENTIAL"}, "OUTFILE": {"assign_to": "OUTPUT.DAT", "organization": "SEQUENTIAL"}, }, "open_directions_detail": { # OPEN 方向详情 "INFILE": "INPUT", "OUTFILE": "OUTPUT", "WORKFILE": "I-O", }, # ── DIVIDE 语句检测 ── "has_divide": False, # 是否有 DIVIDE 语句 "divide_constants": [], # DIVIDE 的被除数列表: [50, 25, 100] # ── INSPECT/STRING 语句检测 ── "has_inspect": False, # 是否有 INSPECT 语句 "has_string": False, # 是否有 STRING 语句 # ── PERFORM 模式分类 ── "perform_patterns": [ # 每个 PERFORM 的模式 {"type": "inline", "target": None, "condition": None}, # inline / paragraph / thru / varying / times {"type": "varying", "target": "WS-I", "condition": "WS-I > 100"}, {"type": "times", "times": 50}, {"type": "until", "condition": "WS-A > 5"}, {"type": "thru", "target": "PARA-A", "thru": "PARA-C"}, ], # ── 主循环定位(含 READ 语句的 PERFORM 块)── "main_loop": { # 主循环信息(None=无循环) "type": "perform_until", # perform_until / perform_varying / read_loop "read_file": "INFILE", # 在该循环中 READ 的文件 "has_at_end": True, # 是否有 AT END 处理 "at_end_action": "MOVE 'Y' TO WS-EOF", # AT END 处理内容 }, # ── IF 分支类型统计 ── "if_types": { "total": 3, # IF 总数 "comparison": 2, # 比较型 (>, <, >=, <=) "equality": 1, # 等值型 (=) "compound": 1, # 复合型 (AND/OR) "nested_depth": 2, # 最大嵌套深度 }, # ── 变量命名模式检测 ── "variable_patterns": { "has_prev_key": True, # WS-PREV-* 模式变量 "has_accumulator": True, # WS-*CNT / WS-*SUM 模式变量 "has_error_field": False, # WS-ERR* / WS-MSG* 模式变量 "has_key_field": True, # WS-*KEY 模式变量 "prev_key_fields": ["WS-PREV-KEY"], # 具体的前键值字段名 "accumulator_fields": ["WS-REC-CNT"], # 具体的累加器字段名 }, # ── OPEN 模式 ── "open_pattern": "sequential", # sequential / reopen(OPEN→CLOSE→再OPEN) } ``` ### 2.3 实现位置 | 新增特征 | 实现文件 | 实现方法 | |:---------|:---------|:---------| | SELECT 文件详情 | `read.py` 的 `parse_file_control()` 扩展 | 追加 organization 字段 | | DIVIDE/INSPECT/STRING | `core.py` `_BrParser` | 添加 IF 语句解析 | | PERFORM 模式分类 | `core.py` `_BrParser` | BrPerform 属性已存在 | | 主循环定位 | `core.py` 新函数 `locate_main_loop()` | 搜索含 READ 的 PERFORM 块 | | IF 类型统计 | `core.py` 新函数 `stat_if_types()` | 遍历 BrIf 的 condition | | 变量命名模式 | `core.py` 新函数 `detect_variable_patterns()` | 正则匹配字段名 | | OPEN 模式 | `read.py` 新函数 `detect_open_pattern()` | 检查 OPEN→CLOSE→OPEN | ### 2.4 接口变更 ```python # cobol_testgen/__init__.py — __all__ 不变 # extract_structure() 签名不变,返回字典追加新字段 # 现有调用者不受影响(dict.get() 返回 None 获得默认值) ``` --- ## 3. Phase 2: 混淆组判定规则引擎 ### 3.1 新模块 `hina/rule_engine/` 创建独立子模块,与现有的 `classifier.py` 互补: ``` hina/ ├── __init__.py # 导出 rule_engine 的 API ├── classifier.py # 现有(不变) ├── rule_engine/ # 新增 │ ├── __init__.py │ ├── confusion_groups.py # 8 混淆组的规则实现 │ ├── contradiction.py # 矛盾检测 │ └── backtrack.py # 回溯机制 ``` ### 3.2 8 混淆组规则 ```python # hina/rule_engine/confusion_groups.py def resolve_confusion_pair(features: dict, pair_name: str) -> dict: """解决一对混淆组,返回判定结果。 参数: features — extract_structure() 输出的结构特征 pair_name — 混淆对名称: "matching_vs_keybreak" "dedup_vs_nodedup" "validation_vs_keybreak" "csv_merge_vs_split" "simple_vs_two_stage" "pure_vs_mixed" "division_50_25_100" "mn_output_mode" 返回: {"resolved_type": str, "confidence": float, "evidence": list} """ # 规则实现示例 ── "matching_vs_keybreak" def _matching_vs_keybreak(features: dict) -> dict: """匹配 vs key切 判定逻辑: 1. SELECT 文件数 < 2 → 排除匹配 → key切 2. IF 类型统计中 3 路 IF(comparison) 占比 > 50% → 匹配 3. 2 路 IF(equality) 为主 + WS-PREV-KEY 存在 → key切 4. 有累加器(WS-*CNT) + WS-PREV-KEY + 2 路 IF → key切 5. 输入文件 ≥ 2 + 3 路 IF → 匹配 6. 无法确定 → 回退到 conflict_score """ file_count = len(features.get("select_files", {})) if_types = features.get("if_types", {}) var_patterns = features.get("variable_patterns", {}) evidence = [] if file_count >= 2: evidence.append("file_count>=2 → possible matching") comp_ratio = if_types.get("comparison", 0) / max(if_types.get("total", 1), 1) if comp_ratio > 0.5: evidence.append("comparison IF ratio > 50% → matching signature") if var_patterns.get("has_prev_key") and var_patterns.get("has_accumulator"): evidence.append("WS-PREV-KEY + accumulator → keybreak signature") # 综合判断 matching_score = sum(1 for e in evidence if "matching" in e) keybreak_score = sum(1 for e in evidence if "keybreak" in e) if matching_score > keybreak_score: return {"resolved_type": "マッチング", "confidence": 0.7 + matching_score * 0.1, "evidence": evidence} elif keybreak_score > matching_score: return {"resolved_type": "キーブレイク", "confidence": 0.7 + keybreak_score * 0.1, "evidence": evidence} else: return {"resolved_type": "unknown", "confidence": 0.5, "evidence": evidence} ``` ### 3.3 矛盾检测 ```python # hina/rule_engine/contradiction.py # 7 个矛盾对 CONTRADICTION_PAIRS = [ ("matching_vs_keybreak", { "type_a": "マッチング", "type_b": "キーブレイク", "rule": lambda f: f.get("variable_patterns", {}).get("has_prev_key"), "tiebreaker": "file_count", # file_count ≥ 2 → matching wins }), ("dedup_vs_nodedup", { "type_a": "項目チェック(重複含む)", "type_b": "項目チェック(重複含まず)", "rule": lambda f: f.get("variable_patterns", {}).get("has_prev_key"), "tiebreaker": "prev_key_exists", # WS-PREV-KEY → 含重复 wins }), ("validation_vs_keybreak", { "type_a": "項目チェック", "type_b": "キーブレイク", "rule": lambda f: f.get("variable_patterns", {}).get("has_error_field"), "tiebreaker": "has_error_field", # WS-ERR* → 校验 wins; WS-*CNT → key切 wins }), # ... 其余 4 个 ] def detect_contradictions(features: dict, candidates: list[str]) -> list[dict]: """检测候选类型中的矛盾对,返回矛盾列表。""" def resolve_contradiction(features: dict, contradiction: dict) -> str: """使用 tiebreaker 规则解决单个矛盾。""" ``` ### 3.4 回溯机制 ```python # hina/rule_engine/backtrack.py class BacktrackResolver: """当混淆组判定进入死胡同时,回溯到 extract_structure 重新提取特征。""" def __init__(self, structure_extractor: callable): self.extract = structure_extractor self.max_rounds = 3 def resolve(self, cobol_source: str, initial_features: dict) -> dict: """多轮判定。每轮检测矛盾→回溯→重新提取→重新判定。""" features = initial_features for round_num in range(self.max_rounds): # Step 1: 检测矛盾 contradictions = detect_contradictions(features, candidates) if not contradictions: # 无矛盾,返回最终结果 return self._finalize(features) # Step 2: 解析矛盾 for c in contradictions: resolution = resolve_contradiction(features, c) # Step 3: 如果需要更多信息,回溯重新提取 if self._needs_backtrack(contradictions): refined_source = self._refine_extraction(cobol_source, contradictions) features = self.extract(refined_source) return self._finalize_with_warning(features) ``` ### 3.5 接口变更 ```python # hina/__init__.py — __all__ 追加 "resolve_confusion_pair", # (features, pair_name) → dict "detect_contradictions", # (features, candidates) → list[dict] "BacktrackResolver", # class — 多轮判定 ``` --- ## 4. Phase 3: 确信度 4 因子计算 ### 4.1 新函数 在 `hina/classifier.py` 中新增确信度计算函数,或者创建 `hina/confidence.py`: ```python # hina/confidence.py — 新增文件 def compute_confidence_v2( keyword_result: dict, # detect_keyword() 的输出 structure_features: dict, # extract_structure() 的输出 contradictions: list[dict], # contradiction.detect_contradictions() 的输出 resolution: dict # confusion_groups 的输出 ) -> dict: """四因子确信度计算。 公式: confidence = base × context_factor × consistency_factor × structure_factor 参数: keyword_result — {matches: [(category, confidence, keyword)], ...} structure_features — extract_structure 输出的完整字典 contradictions — 矛盾列表 resolution — 混淆组解决结果 返回: { "confidence": float, # 最终确信度 (0~1) "base": float, # 基础确信度 "context_factor": float, # 上下文因子 "consistency_factor": float, # 一致性因子 "structure_factor": float, # 结构一致性因子 "judgment": str, # "auto" / "review" / "manual" / "impossible" "needs_review": bool, } """ ``` ### 4.2 因子定义 ``` 基础确信度: L1 关键字规则对应的基准确信度 (0.70~0.99) DB操作=0.95, SORT=0.95, CALL=0.90, 编辑输出=0.80, ... 上下文因子: 关键字匹配数 ≥ 3 → 1.0 关键字匹配数 = 2 → 0.95 关键字匹配数 = 1 → 0.90 需要上下文确认 → 0.50 一致性因子: 无矛盾 → 1.0 有矛盾已解决 → 0.90 有矛盾未解决 → 0.80 多重矛盾 (≥3) → 0.50 结构一致性因子: 结构完全匹配 (5/5 特征一致) → 1.0 部分一致 (3-4/5) → 0.7 少量一致 (1-2/5) → 0.5 无法确定 → 0.3 综合判定: ≥ 90% → 自动判定 ("auto") 70-89% → 自动判定 + 建议 Review ("review") 50-69% → Agent 提案 + 人工确认 ("manual") < 50% → 判定不可,全部人工 ("impossible") ``` ### 4.3 接口变更 ```python # hina/__init__.py — __all__ 追加 "compute_confidence_v2", # 四因子确信度计算 "compute_confidence", # 已有函数保持不动(旧版调用者不受影响) ``` ### 4.4 质量门禁公式更新(gcov 集成) Phase 0.6 完成后,`hina/gate.py` 的评分公式改为双模式: ``` 当前(gcov 未启用): quality_score = branch_rate×0.5 + paragraph_rate×0.5 + confidence×0.4 新增 quality_score_v2(gcov 启用时): quality_score_v2 = static_cov×0.3 + gcov_cov×0.4 + confidence×0.3 ``` - 静态覆盖率 30% — 快速参考,验证数据生成完整性 - gcov 动态覆盖率 **40%** — 权重最高,代表真实执行结果 - HINA 确信度 30% **新增文件**: `coverage/compare_coverage.py` — 对比静态与 gcov 覆盖率,定位虚假覆盖 ```python def compare_coverage(program_name: str) -> dict: """返回 {static, dynamic, gap, misleading_branches}""" ``` --- ## 5. Phase 4: 33+2 种程序类型 COBOL 测试样本 ### 5.1 目录结构 ``` test-data/cobol/ # 已有 HINA001~101 保留 ├── HINA001.cbl # 已有 ├── ... ├── HINA101.cbl # 已有 │ ├── category_matching/ # 匹配系 (10种) │ ├── MT01_1TO1.cbl │ ├── MT02_1TON.cbl │ ├── MT03_NTO1.cbl │ ├── MT16_TWO_STAGE_1TO1.cbl │ ├── MT17_TWO_STAGE_NTO1.cbl │ ├── MT18_MN_TO_M.cbl │ ├── MT19_MN_TO_N.cbl │ ├── MT20_MN_TO_MXN.cbl │ ├── MT32_MIXED_SAME_KEY.cbl │ └── MT33_MIXED_DIFF_KEY.cbl │ ├── category_sort/ # SORT/ MERGE (2种) │ ├── ST01_SORT.cbl │ └── ST02_MERGE.cbl │ ├── category_division/ # 分割系 (3种) │ ├── DV01_DIVIDE_50.cbl │ ├── DV02_DIVIDE_25.cbl │ └── DV03_DIVIDE_100.cbl │ ├── category_validation/ # 校验 (1种,补充) │ ├── VL01_CHECK_WITH_DUP.cbl │ └── VL02_CHECK_NO_DUP.cbl │ ├── category_csv/ # 文件转换 (3种) │ ├── CV01_CSV_NO_NEWLINE.cbl │ ├── CV02_CSV_WITH_NEWLINE.cbl │ └── CV03_ASCII_EBCDIC.cbl │ ├── category_cics/ # online (1种) │ └── CI01_CICS.cbl │ └── category_db/ # DB操作 (1种,补充) └── DB01_SELECT_UPDATE.cbl ``` ### 5.2 样本规范 每个 COBOL 测试样本必须: 1. **可编译** — 用 `cobc -x -std=ibm-strict` 编译通过 2. **10-50 行** — 足够表达类型特征,不要过大 3. **包含关键特征** — 每种类型独有的关键字和结构模式 4. **有注释** — 开头的星号注释说明类型编号和名称 5. **HEADER 注释**: ```cobol * ==== TYPE: MT01 マッチング(1:1) ==== * 特征: 2 输入文件 SELECT, IF KEY = 比较, 3路 IF, 无累加器 * BRANCHES: 4 (2 IFs), DECISIONS: 2 * SELECT COUNT: 2, OPEN COUNT: 2 ``` ### 5.3 实现顺序 按依赖关系分 3 批创建: ``` 第一批 (Phase 4a): 匹配系 10 种 + SORT/MERGE 2 种 依赖: 这 12 个样本是 Phase 7-8 测试的基础 第二批 (Phase 4b): 分割系 3 种 + 校验 2 种 + 文件转换 3 种 依赖: 这 8 个样本是 Phase 7 测试的基础 第三批 (Phase 4c): CICS 1 种 + DB 1 种 依赖: 需要模拟器环境,可先做代码样本,延迟测试 ``` --- ## 6. Phase 5: 参数化测试数据生成引擎 ### 6.1 独立模块 `parametrized/`(项目根目录) ``` 项目根目录/ ├── parametrized/ ← 独立!不是 cobol_testgen 的子模块 │ ├── __init__.py │ ├── matching.py # 匹配系数据生成 │ ├── sort.py # SORT 数据生成 │ ├── division.py # 分割系数据生成 │ ├── validation.py # 校验系数据生成 │ ├── csv_conversion.py # CSV→FB 数据生成 │ └── common.py # 通用工具 依赖方向: parametrized/ → cobol_testgen (需要 PIC 解析算边界值) parametrized/ → data/ (构造 Field/TestCase 对象) cobol_testgen → parametrized ❌ 禁止 ``` **理由**:parametrized/ 的输入是数值参数(记录数、匹配率、不平衡比),不是 COBOL 源码。放在 cobol_testgen/ 下会使 COBOL 解析引擎依赖测试工具。独立模块保持分层干净。 ### 6.2 类型专属参数化 ```python # cobol_testgen/parametrized/matching.py def generate_matching_data( matching_type: str, # "1:1" / "1:N" / "N:1" record_count_r01: int, record_count_r02: int, key_match_ratio: float = 1.0, # 匹配率(用于剩余件测试) imbalance_ratio: float = 1.0, # 不平衡比 ) -> tuple[list[dict], list[dict]]: """生成匹配系测试数据。 返回: (主文件记录列表, 从件记录列表) 文件间通过 KEY 字段关联。 """ def generate_keybreak_data( group_count: int, # key 组数 records_per_group: int, # 每组件数 sum_type: str = "accumulate", # "accumulate" / "aggregate" / "mark" ) -> list[dict]: """生成 key 切测试数据。 返回: 按 KEY 分组的数据,组间 KEY 值变化触发中断。 """ # cobol_testgen/parametrized/division.py def generate_division_data( division_type: int, # 50 / 25 / 100 record_count: int, # 总件数(整数倍/余数/不足) ) -> list[list[dict]]: """生成分割系测试数据。 返回: 按分割文件分组的记录列表: [[文件1的记录], [文件2的记录], ...] 文件数 = ceil(record_count / division_type) """ ``` ### 6.3 通用数据生成工具 ```python # cobol_testgen/parametrized/common.py def generate_zero_byte_file(path: str): """生成 0 字节空文件(VSAM 空 cluster 或顺序 0 字节)。""" def generate_status_35_scenario(path: str): """STATUS 35 场景:不生成文件,让 OPEN 找不到 DD。""" def generate_minimal_records(fields: list[Field]) -> list[dict]: """各文件生成 1 条正常记录。""" def generate_boundary_values(field: Field) -> dict: """从 PIC 解析 S9(7)V99 → 生成 max/min/溢出值。""" def generate_sorted_records(fields: list[Field], record_count: int) -> list[dict]: """按 ASCENDING/DESCENDING KEY 生成已排序序列。""" def generate_duplicate_keys(records: list[dict], key_field: str) -> list[dict]: """同键值追加 ≥2 件。""" ``` ### 6.4 接口变更 ```python # cobol_testgen/__init__.py — __all__ 追加(parametrized 是独立模块,非子包) from parametrized import ( generate_matching_data, # 匹配系数据 generate_keybreak_data, # key切数据 generate_division_data, # 分割系数据 generate_zero_byte_file, # 空文件 generate_boundary_values, # 边界值 ) ``` --- ## 7. Phase 6: 日文测试数据生成查找表 ### 7.1 新文件 `japanese_data.py`(项目根目录,独立文件) ```python # japanese_data.py # ── 查找表 ── FULLWIDTH_KATAKANA = "アイウエオカキクケコサシスセソタチツテト..." FULLWIDTH_HIRAGANA = "あいうえおかきくけこさしすせそたちつてと..." FULLWIDTH_DIGITS = "0123456789" FULLWIDTH_ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" HALFWIDTH_KATAKANA = "アイウエオカキクケコサシスセソタチツテト..." SJIS_5C_PROBLEM = ["ソ", "噂", "能"] # Shift-JIS 第2字节 0x5C SJIS_7C_PROBLEM = ["本", "問"] # Shift-JIS 第2字节 0x7C WAREKI_BOUNDARIES = [ # (元号, 西历开始年, 和历开始, 西历最后日, 和历最后日) ("令和", 2019, "R010501", None, None), ("平成", 1989, "H010108", "2019/04/30", "H310430"), ("昭和", 1926, "S611231", "1989/01/07", "S640107"), ("大正", 1912, "T011231", "1926/12/25", "T151225"), ("明治", 1868, "M451229", "1912/01/29", "M450129"), ] # ── 生成函数 ── def generate_fullwidth_text(field: Field) -> str: """PIC N 字段 → 全角文字填充。""" def generate_halfwidth_katakana(field: Field) -> str: """PIC X 字段 → 半角假名填充。""" def generate_sjis_5c_problem(field: Field) -> str: """生成含 5C 问题文字的字符串。""" def generate_sjis_7c_problem(field: Field) -> str: """生成含 7C 问题文字的字符串。""" def generate_wareki_date(wareki_type: str) -> str: """生成和历日期字符串。""" def generate_wareki_boundary(era: str) -> tuple[str, str]: """生成指定元号的边界日期对(末日 → 初日)。""" def generate_encoding_test_data( from_encoding: str, to_encoding: str, ) -> tuple[bytes, bytes]: """生成编码转换测试数据(EBCDIC→SJIS→UTF-8 三段)。""" def select_data_type(field: Field) -> str: """选择数据类型: PIC N → 日文 / PIC 9 → 数值 / PIC X → 半角""" ``` ### 7.2 接口变更 ```python # cobol_testgen/__init__.py — __all__ 追加 "generate_fullwidth_text", "generate_halfwidth_katakana", "generate_wareki_date", ``` --- ## 8. Phase 7-10: 类型别测试套件 ### 8.1 测试文件清单 ``` tests/ ├── parametrized/ │ ├── test_matching.py # 匹配系 ~15 测试 (Phase 7) │ ├── test_division.py # 分割系 ~9 测试 (Phase 7) │ ├── test_csv_conversion.py # 文件转换 ~8 测试 (Phase 7) │ ├── test_sort_merge.py # SORT/MERGE ~16 测试 (Phase 8) │ ├── test_call_search.py # CALL/SEARCH ~20 测试 (Phase 8) │ ├── test_crosscutting.py # 横跨功能 ~70 测试 (Phase 9) │ └── test_japanese.py # 日文处理 ~31 测试 (Phase 10) ``` ### 8.2 测试模板 ```python # tests/parametrized/test_matching.py """匹配系深度测试 — 基于 cobol-test-benchmark.md Type 01-03, 16-20, 32-33""" import pytest from cobol_testgen.parametrized import generate_matching_data @pytest.mark.parametrize("r01,r02,match_ratio", [ (10, 10, 1.0), # MT-N001: 1:1 完全匹配 (1, 100, 0.0), # MT-N009: 1:N 极端不平衡 (100, 1, 0.0), # MT-N010: N:1 极端不平衡 ]) def test_matching_basic(r01, r02, match_ratio): """MT-N001~003: 1:1 / 1:N / N:1 基本匹配""" main_recs, sub_recs = generate_matching_data( matching_type="1:1", record_count_r01=r01, record_count_r02=r02, key_match_ratio=match_ratio, ) assert len(main_recs) == r01 assert len(sub_recs) == r02 ``` ### 8.3 Phase 7 测试矩阵 | 测试文件 | 覆盖内容 | 测试项数 | 对应文档 | |:---------|:---------|:--------:|:---------| | `test_matching.py` | 1:1/1:N/N:1 + 不平衡 + 键重复 + 未排序 + 高级匹配 | 20 | MT-N001~012, AM-N001~008 | | `test_division.py` | 50/25/100 分割 + 余数 + 不足 + OPEN失败 + 命名 | 9 | S-N001~007, S-A001~002 | | `test_csv_conversion.py` | 无换行/有换行/引用符/空項目/超长 | 8 | CF-N001~006, CF-A001~002 | ### 8.4 Phase 8 测试矩阵 | 测试文件 | 覆盖内容 | 测试项数 | 对应文档 | |:---------|:---------|:--------:|:---------| | `test_sort_merge.py` | SORT升/降/多键/稳定/INPUT/OUTPUT PROCESS + MERGE | 16 | SR-N001~010, MR-N001~003 | | `test_call_search.py` | CALL字面量/动态/USING/IS INITIAL/嵌套 + SEARCH ALL | 20 | C-N001~009, T-N001~007 | ### 8.5 Phase 9 测试矩阵 (横跨功能) | 测试文件 | 覆盖内容 | 测试项数 | 对应文档 | |:---------|:---------|:--------:|:---------| | `test_crosscutting.py` | 可变长入出力(11) + 循环处理(10) + 数值精度(12) + 日期(18) + 排他(4) + RERUN(4) + 性能(4) | 63 | VL/LP/NP/D/EX/RR/PV | ### 8.6 Phase 10 测试矩阵 (日文) | 测试文件 | 覆盖内容 | 测试项数 | 对应文档 | |:---------|:---------|:--------:|:---------| | `test_japanese.py` | PIC N全角(5) + 半角假名(5) + 外字(6) + 5C/7C(4) + 编码转换(8) + 全角空格(3) | 31 | J-N/K/G/D/X/S | --- ## 9. Phase 11: 完整类型判定管道 ### 9.1 新模块 `hina/pipeline/` ``` hina/ ├── rule_engine/ # 混淆组规则 (P2) ├── confidence.py # 确信度计算 (P3) ├── pipeline/ # 完整类型判定管道 (合并自 classification_pipeline/) │ ├── __init__.py │ └── pipeline.py # 管道编排 ``` ### 9.2 管道流程 ```python # hina/pipeline/pipeline.py def classify_program(cobol_source: str) -> dict: """完整程序类型判定管道。 流程: 1. 并行执行: a. 关键字识别 (detect_keyword) — 11 类 L1 关键字 b. 结构提取 (extract_structure) — 全部特征 2. 关键字确信度 ≥ 90% → 直接输出类型 (DB操作/SORT/MERGE/online 等高确信度独占类型) 3. 关键字 50-89% → 进入混淆组判定 a. 结构解析 (PERFORM模式/主循环/IF分支) b. 8 混淆组规则引擎 c. 4 因子确信度计算 d. 矛盾检测 → 有矛盾则回溯 4. 关键字 < 50% → Agent 辅助判定 a. classify_with_llm() 调用 b. LLM 返回建议类型 c. 规则引擎验证 LLM 结果 5. 输出最终判定 JSON """ ``` ### 9.3 输出格式 ```python { "program_name": "HINA005", "category": "condition_heavy", # 混淆组 "subtype": "simple_if", # 具体类型 "type_code": "05", # 33+2 中的编号 "method": "keyword", # keyword / rule_engine / agent # ── 确信度详情 ── "confidence": 0.92, "confidence_detail": { "base": 0.95, "context_factor": 1.0, "consistency_factor": 0.9, "structure_factor": 1.0, }, # ── 判定依据 ── "evidence": [ "EXEC SQL → DB操作 (keyword, 95%)", "SELECT count=1, OPEN count=1", "IF branches=2, decisions=1", "No contradictions detected", ], # ── 是否需要 Review ── "needs_review": False, # ── 测试策略建议 ── "testing_strategy": { "required_tests": 5, "coverage_target": "branch", "supplement_strategy": "incremental", }, } ``` ### 9.4 集成到 orchestrator ```python # orchestrator.py — 替换现有的 HINA 分类步骤 def run_pipeline(cfg: Config, ...) -> VerificationRun: # ... 现有代码 ... # ── 类型判定(替换现有 HINA 步骤) ── from hina/pipeline import classify_program classification = classify_program(cobol_src_text) vr.hina_type = classification["category"] vr.hina_confidence = classification["confidence"] vr.debug["classification"] = classification # 如果确信度 < 50%,标记为人工处理 if classification["confidence"] < 0.5 and classification["needs_review"]: vr.quality_warn = f"类型判定确信度过低({classification['confidence']:.0%}),建议人工确认" # ... 后续代码不变 ... ``` --- ## 10. Phase 12: 文档更新 ### 10.1 更新文件 | 文件 | 更新内容 | |:-----|:---------| | `docs/module-interfaces.md` | 追加 hina/pipeline 模块接口;追加 parametrized 子模块接口;更新 hina 模块接口(rule_engine, confidence_v2) | | `docs/test-plan.md` → v3.0 | 追加 33+2 程序类型覆盖行;追加类型别测试矩阵;追加横跨功能测试行;追加日文测试行;更新总测试数预期(412 → 600+) | | `docs/cobol-coverage-matrix.md` | 追加程序类型覆盖行;追加测试基准覆盖行;更新覆盖率目标 | ### 10.2 测试计划 v3.0 更新内容 ```markdown ## 测试预期(更新版) | 维度 | v2.0 | v3.0 追加 | v3.0 总计 | |:-----|:----:|:---------:|:---------:| | L0 单元测试 | 280 | +50 (参数化引擎) | 330 | | L1 类型测试 | 0 | +80 (Phase 7-8) | 80 | | 横跨功能测试 | 0 | +70 (Phase 9) | 70 | | 日文测试 | 0 | +31 (Phase 10) | 31 | | 非功能测试 | 6 | +10 | 16 | | 已有回归 | 112 | — | 112 | | **总计** | **412** | **+241** | **~653** | ``` --- ## 11. 依赖关系与分工矩阵 ### 11.1 Phase 依赖图 ``` Phase 1 (特征提取) ──→ Phase 2 (规则引擎) ──→ Phase 3 (确信度) │ │ │ │ └────────┬───────────────┘ │ │ │ ▼ │ Phase 11 (hina/pipeline) │ │ ▼ ▼ Phase 5 (parametrized/) Phase 4 (COBOL样本) │ │ └────────┬──────────────────┘ │ ▼ Phase 7-10 (测试套件) │ ▼ Phase 12 (文档) ``` ### 11.2 并行执行阶段 ``` 可以完全并行: Phase 1 (A) + Phase 4 (C) + Phase 5 (A) + Phase 6 (B) Phase 2 (D) + Phase 4b (C) Phase 7-8 (F/G) + Phase 9 (F/G) + Phase 10 (B) 测试执行阶段 (所有人可并行写自己的测试) 需要串行: Phase 1 → Phase 2 → Phase 3 → Phase 11 (D 负责全链路) Phase 4 → Phase 7-8 (需要样本才能测试) Phase 5 → Phase 7-10 (需要参数化引擎才能生成测试数据) ``` ### 11.3 分工矩阵 | 开发者 | Phase | 模块 | 工作量 | |:-------|:------|:-----|:-------| | **A** | 1, 5 | cobol_testgen 扩展 + parametrized | 3 天 | | **B** | 6, 10, 12 | japanese_data + 日文测试 + 文档 | 2 天 | | **C** | 4, 7 | 33+2 COBOL 样本 + 匹配/分割测试 | 3 天 | | **D** | 2, 3, 11 | rule_engine + confidence + pipeline | 4 天 | | **E** | 6, 10 | japanese_data + 日文测试、LLM 提示词优化 | 2 天 | | **F** | 8, 9 | SORT/MERGE/CALL/SEARCH + 横跨功能 | 3 天 | | **G** | 0.6, 8 | gcov 基础设施 + SORT/MERGE/SEARCH 测试 | 3 天 | | **H** | 4c, 11 集成 | CICS/DB 样本 + orchestrator 集成 | 2 天 | ### 11.4 总工时估算 | Phase | 内容 | 人日 | |:------|:-----|:----:| | P1 | extract_structure 扩展 | 1.5 | | P2 | 混淆组规则引擎 | 2.0 | | P3 | 确信度 4 因子 | 1.0 | | P4 | 33+2 COBOL 样本 | 2.0 | | P5 | 参数化数据生成 | 2.0 | | P6 | 日文数据生成 | 1.0 | | P7 | 匹配/分割/CSV 测试 | 1.5 | | P8 | SORT/MERGE/CALL/SEARCH 测试 | 1.5 | | P9 | 横跨功能测试 | 2.5 | | P10 | 日文测试 | 1.5 | | P11 | 类型判定管道 | 2.0 | | P12 | 文档 | 1.0 | | | **总计** | **~19.5 人日** | --- ## 12. 接口变更一览 ### 12.1 向后兼容(现有代码不受影响) | 变更 | 类型 | 说明 | |:-----|:-----|:------| | `extract_structure()` 返回追加字段 | ✅ 兼容 | 现有调用用 `dict.get()`,新字段不出现时返回 None | | `compute_confidence()` 保留 | ✅ 兼容 | 新增 `compute_confidence_v2()` 并行存在 | | `orchestrator.py` 导入路径修改 | ✅ 兼容 | 已改为模块顶层导入 | | `__init__.py` 加 `__all__` | ✅ 兼容 | 只是显式声明已有接口 | ### 12.2 非兼容(需同步更新调用者) | 变更 | 类型 | 如何处理 | |:-----|:-----|:---------| | `hina/__init__.py` 新增 `__all__` | ⚠️ 通知 | 仅影响 `from hina import *` 用户(无此类代码)| | `cobol_testgen/__init__.py` 新增 `__all__` | ⚠️ 通知 | 仅影响 `from cobol_testgen import *` 用户(无此类代码)| | `orchestrator.py` 导入从 `from x.y import z` 改为 `from x import z` | ⚠️ 通知 | 已在本次修改中同步更新 | ### 12.3 新增公开 API 汇总 ```python # parametrized/ __all__(新增独立模块): "generate_matching_data" # Phase 5 "generate_keybreak_data" # Phase 5 "generate_division_data" # Phase 5 "generate_boundary_values" # Phase 5 # japanese_data.py(新增独立文件): from japanese_data import generate_fullwidth_text, generate_halfwidth_katakana, generate_wareki_date # hina __all__ 追加: "resolve_confusion_pair" # Phase 2 "detect_contradictions" # Phase 2 "BacktrackResolver" # Phase 2 "compute_confidence_v2" # Phase 3 "classify_program" # Phase 11 — hina.pipeline.pipeline.classify_program ``` --- ## 附录:快速开始指南 ### 对于 A(cobol_testgen 扩展) ```bash # 1. 扩展 read.py — 添加 SELECT organization 和 OPEN 模式检测 # 2. 扩展 core.py — 添加 DIVIDE/INSPECT/STRING 检测、PERFORM 分类、IF 统计、变量模式、主循环 # 3. 更新 __init__.py __all__ ``` ### 对于 D(规则引擎 + 确信度 + 管道) ```bash # 1. 创建 hina/rule_engine/ — 8 混淆组规则(独立命名函数) # 2. 创建 hina/confidence.py — 四因子计算 # 3. 创建 hina/pipeline/ — 完整管道编排 # 4. 修改 orchestrator.py — 替换 HINA 分类步骤 ``` ### 对于 C(COBOL 样本 + 测试) ```bash # 1. 创建 test-data/cobol/category_matching/ — 10 个匹配系样本 # 2. 创建 test-data/cobol/category_sort/ — SORT/MERGE 样本 # 3. 创建 tests/parametrized/test_matching.py # 4. 驱动测试: python -m pytest tests/parametrized/test_matching.py ``` ### 对于 B(日文处理 + 文档) ```bash # 1. 创建 japanese_data.py(项目根目录)— 查找表 + 生成函数 # 2. 创建 tests/parametrized/test_japanese.py # 3. 更新 docs/module-interfaces.md # 4. 更新 docs/test-plan.md → v3.0 ``` --- ## 13. COBOL 覆盖率测试体系 — 与各 Phase 的集成 > 覆盖率测试不是独立章节,而是贯穿多个 Phase 的基础设施。 > 已在 Phase 1.1(Phase 0.6)中新增 gcov 基础设施。 > 以下列出覆盖率的其他部分的分布位置: | 覆盖率内容 | 所在 Phase | 说明 | |:-----------|:----------|:------| | gcov 基础设施(环境验证 + collect_gcov 修复 + Config 字段 + 全链路测试)| **Phase 0.6** (1.1节) | F 负责,3h | | 质量门禁公式更新(quality_score_v2)+ 静态 vs 动态对比报告 | **Phase 3** (4.4节) | 新增 gcov 权重 40% | | 各类型 gcov 验证测试(约 15 个) | **Phase 7-10** | 每个类型群至少 1 条 gcov 测试 | | orchestrator gcov_enabled 集成 | **Phase 11** (9.5节) | 连接 Config → orchestrator → gate.py | ### 13.1 覆盖率目标 **模块覆盖率(pytest --cov):** | 模块 | 目标 | |:-----|:----:| | cobol_testgen/* | ≥ 90% | | hina/* | ≥ 85% | | comparator/* | ≥ 85% | | runners/* | ≥ 70% | | orchestrator.py | ≥ 85% | **程序覆盖率(gcov 验证,各类型群最低 line_rate):** | 类型群 | 门槛 | 理由 | |:-------|:----:|:------| | 条件分支(IF/EVALUATE) | ≥ 70% | 分支密集,应高覆盖 | | 匹配系 | ≥ 60% | 至少覆盖关键 IF 分支 | | SEARCH ALL | ≥ 60% | 命中/未命中均需覆盖 | | CALL | ≥ 60% | 主程序 + 子程序 | | SORT | ≥ 50% | 大量 I/O,代码行不多 | | 分割系 | ≥ 50% | 文件操作密集 | | 编辑输出 | ≥ 50% | WRITE 语句需要实际输出 | **静态 vs 动态差距**: 同类差距 ≤ 30%(超过说明静态分析不可靠) > 门槛说明:基于 HINA 现有 10 个程序的 gcov 预测数据。 > 纯逻辑程序(IF/EVALUATE)可达 70%+,I/O 密集程序(SORT/分割)约 50%。 > 上线后根据实测数据调整。 --- ## 14. 架构审核决议汇总 > 来源: `/plan-eng-review` | 日期: 2026-06-19 ### 14.1 审核决策 | 分类 | 决策 | 方案 | 结果 | |:-----|:-----|:-----|:-----| | 架构 | classification_pipeline/ 归属 | 合并到 hina/pipeline/ | ✅ 采纳 | | 架构 | parametrized/ 归属 | 独立模块(项目根目录) | ✅ 采纳 | | 架构 | japanese_data.py 归属 | 独立文件(项目根目录) | ✅ 采纳 | | 架构 | orchestrator 过渡 | 并行开发,一次性替换 | ✅ 采纳 | | 架构 | COBOL 样本兼容 | 不可编译类型用注释模拟关键字 | ✅ 采纳 | | 代码质量 | 矛盾判定规则 | 独立命名函数取代 lambda | ✅ 采纳 | | 测试 | 新模块单元测试 | 每个 Phase 包含自身测试 | ✅ 采纳 | | 性能 | 回溯机制 | 加 30s 超时降级 | ✅ 采纳 | ### 14.2 NOT in Scope | 项目 | 理由 | |:-----|:------| | CICS/DB 真实环境集成测试 | 需要大型机模拟器 | | PySpark 完整管道验证 | Java 兼容性问题 | | 多语言国际化(除日文外) | 33+2 类型未要求 | | CI/CD 性能基准自动化 | 不属于 12 个 Phase | ### 14.3 实现任务 - [ ] **T1 (P1, human: ~2h)** — 扩展 extract_structure 新增 8 类特征 - [ ] **T2 (P2, human: ~3h)** — hina/rule_engine/ 8 混淆组(独立函数) - [ ] **T3 (P3, human: ~1.5h)** — hina/confidence.py 4 因子确信度 - [ ] **T4 (P4, human: ~2.5h)** — test-data/cobol/ 33+2 样本 - [ ] **T5 (P5, human: ~2.5h)** — parametrized/ 数据生成引擎 - [ ] **T6 (P6, human: ~1h)** — japanese_data.py 日文查找表 - [ ] **T7 (P7-10, human: ~6h)** — 类型别测试套件 (~241 测试) - [ ] **T8 (P11, human: ~2.5h)** — hina/pipeline/ 完整管道 + orchestrator 集成 - [ ] **T9 (P12, human: ~1h)** — 文档更新 ### 14.4 总测试预期 ``` 现有: 428 测试 新增: ~60 (新模块自身单元测试) 新增: ~241 (类型别测试套件 P7-10) 总计: ~729 测试 ``` ### 14.5 并行策略 ``` Lane A: P1 (cobol_testgen 扩展) → 独立 Lane B: P4 (COBOL 样本) → 独立,需先完成 Lane C: P5 (parametrized/) → 需要 cobol_testgen 的 PIC 解析 Lane D: P6 (japanese_data) → 独立 Lane E: P2 (rule_engine) → 需要 P1 的特征 └── P3 (confidence) → 需要 P2 └── P11 (pipeline) → 需要 P2+P3 Lane F: P7-10 (测试套件) → 需要 P4+P5+P6 └── P12 (文档) → 最后 启动顺序: 第 1 批 (并行): Lane A + Lane B + Lane D 第 2 批: Lane C (P1 完成 + 已有 data/) + Lane E (P1 完成) 第 3 批: Lane F (P4+P5+P6 完成) 最后: P12 ``` --- ## 15. 验收标准 > 所有 Phase 完成后,用以下标准验证是否达标。 | 编号 | 验收项 | 验证方法 | 关联 Phase | |:-----|:-------|:---------|:-----------| ### 15.1 功能验收 | A01 | extract_structure() 返回包含全部 8 个新增字段 | pytest tests/cobol_testgen/ 全部通过 | P1 | | A02 | 8 个混淆组规则各有 ≥ 2 个测试 | pytest tests/hina/ 覆盖 | P2 | | A03 | 4 因子确信度的 4 个判定阈值各 ≥ 1 个测试 | pytest tests/hina/ 覆盖 | P3 | | A04 | 33+2 个 COBOL 样本全部在 test-data/cobol/ 下 | ls test-data/cobol/category_*/ 共 35+ 文件 | P4 | | A05 | parametrized/ 各生成函数有测试覆盖主要参数组合 | pytest tests/parametrized/ 全部通过 | P5 | | A06 | japanese_data.py 生成函数返回正确格式 | pytest tests/parametrized/test_japanese.py | P6 | | A07 | 类型测试套件 ≥ 200 个测试 | pytest --collect-only | P7-10 | | A08 | hina/pipeline/ 的 3 条判定路径各有测试覆盖 | pytest tests/hina/ 模拟三种路径 | P11 | | A09 | gcov 全链路验证测试通过 | pytest tests/test_gcov_basic.py | P0.6 | | A10 | 质量门禁 gcov 模式下 quality_score_v2 工作 | pytest tests/hina/test_gate.py 覆盖 | P3 | ### 15.2 覆盖率验收 | 验收项 | 目标 | 验证方法 | |:-------|:----:|:---------| | 模块覆盖率(pytest --cov)| ≥ 68% | pytest --cov=. | | 核心管道覆盖率 | ≥ 85% | pytest --cov=cobol_testgen --cov=hina --cov=orchestrator | | Python 测试总数 | ≥ 650 | pytest --collect-only -q | | gcov 动态验证(可编译类型)| line_rate ≥ 50% | pytest tests/test_gcov_basic.py | ### 15.3 回归验收 - [ ] 所有现有测试通过: pytest tests/ --ignore=e2e/ -q → 0 failed - [ ] 新增测试不降低现有覆盖率 - [ ] 所有 __all__ 中列出的公开函数有类型注解 --- ---