Files
cobol-java-v3/docs/enhanced-test-design.md
NB-076 50995d3335 chore: SETUP.md + 测试报告脚本 + 文档更新
- SETUP.md: 完整环境搭建指南(同事用)
- SETUP_QUICK.md: 快速搭环境(4步)
- s22~s26: TNA端到端、覆盖率报告、回归检查
- procedure_grammar.lark: 实验性Lark语法

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-25 08:50:17 +08:00

24 KiB
Raw Permalink Blame History

COBOL 迁移验证平台 — 增强测试方案 v3

版本: v4.0 | 基于多角色评审(架构师/设计师/COBOL专家)发现的 3 个问题修正 融合: HINA 程序分类 × 测试基准 × 覆盖率(静态+动态) × 质量门禁 × 分层重试 基于现有管线改造,不改 runners/comparator/web/worker 等稳定模块


一、总览

1.1 现状与目标

现状:
  COPYBOOK → Agent1(解析) → Agent2(LLM盲生成) → DataWriter → Runners → Comparator → Report
  ↑ PASS 只说明 COBOL 和 Java 输出一致,不说明测试数据覆盖了全部逻辑

目标:
  同一管线 → 新增 HINA 类型判定 → 规则引擎路径覆盖 + 语义化补充
           → 质量门禁拦截覆盖率不足的数据
           → 静态+动态双重验证覆盖率
           → 报告包含覆盖率/HINA信息/质量评分

1.2 不变的部分

模块 说明
runners/* 编译执行逻辑不变(cobol_runner.py 仅新增编译参数,不改变原有流程)
comparator/* 字段比对逻辑不依赖数据来源
agents/agent1_parser.py COPYBOOK → FieldTree 逻辑不变
agents/agent3_diagnostic.py 差异诊断逻辑不变
web/* Web UI 不改变
worker.py 任务队列逻辑不变
jcl/* JCL 解析执行不变
tests/* 现有 42 个测试不受影响

1.3 成本说明

每次验证涉及 4 个 Agent 调用:Agent1($0.001) + HINA Agent($0.002) + 策略 Agent($0.002) + Agent3($0.001 仅 mismatch 时),合计约 $0.005-0.006。准确性优先,不因成本压缩 Agent 调用。

1.4 术语说明

术语 说明
HINA COBOL 程序类型分类体系(33+2 种类型)
cobol_testgen 已有纯规则引擎(5000 行),可解析 COBOL 源码、枚举路径、生成覆盖率
质量门禁 执行前检查测试数据是否满足覆盖率和边界要求
交叉验证 静态(代码分析)与动态(gcov 插桩)覆盖率比对

1.5 版本变更记录

版本 变更
v1 初版
v2 修复退回混用、分支树复用、Phase 1 保留 Agent2、补充 prompt 模板、定义评分公式
v3 修复循环体每次重跑、重试计数器竞争条件、断言公式不适用 COBOL、Phase 1 门禁维度、类型优先级顺序、decision_gaps 未定义、交叉验证差异=0、拼写错误、重试可提前实施、文件映射依赖
v4 修复 cobol_testgen 输出格式未定义(补充数据格式schema+映射函数)、固定格式 COBOL 源文件解析风险(补充格式检测逻辑)、阻断状态后用户操作路径缺失(补充操作指南+覆盖率分阶段展示规则)

二、管线流程

2.1 增强后的管线

输入:
  --copybook <文件>  → Agent1
  --cobol-src <文件> → cobol_testgen + HINA Agent

流程:

  Step 1: Agent1(COPYBOOK) → FieldTree

  Step 2: cobol_testgen.extract_structure(--cobol-src)
          → 分支树 + 结构摘要

  Step 3: HINA Agent(--cobol-src + 结构摘要)
          → HINA 类型 + 確信度 + 策略参数

  Step 4: cobol_testgen.generate_data(--cobol-src, 分支树)
          → base_test_cases (100% 路径覆盖)

  Step 5: 策略 Agent(base + HINA 类型)
          → complete_test_cases (基础数据 + 语义化补充 + 边界值)

  Step 6: 质量门禁(执行前检查)
          ├── 通过 → 继续
          └── 不通过 → 分类退回(见 2.4)

  Step 7: DataWriter(测试数据写入,不变)

  Step 8: CobolRunner + JavaRunner(编译运行)
          └── COBOL 编译加 -fprofile-arcs -ftest-coverage(可选)

  Step 9: gcov 覆盖率采集(可选)
          └── 不可用时降级为仅静态

  Step 10: 交叉验证(静态 vs 动态)

  Step 11: Comparator(字段比对,不变)

  Step 12: Agent3 差异诊断(不变)

  Step 13: 增强报告

2.2 数据流

Agent1 ── FieldTree ───────────────────────────────────────────┐
                                                               │
cobol_testgen.extract_structure() ── 分支树 ──┬──→ HINA Agent  │
                                              ├──→ generate_data│
                                              └──→ 质量门禁      │
                                                               │
HINA Agent ── 类型+策略参数 ──→ 策略 Agent ──→ complete_tests ──┤
                                                               ▼
                                                          DataWriter

关键设计: extract_structure() 输出的分支树同时传递给 HINA Agent、generate_data() 和质量门禁,避免重复解析。

extract_structure() 输出的结构摘要 schema:
{
  "paragraphs": ["100-MAIN", "200-PROCESS", ...],
  "decision_points": [
    {"id":1, "kind":"IF", "label":"TX-TYPE = 'P'", "branches":2},
    {"id":2, "kind":"EVALUATE", "label":"MEM-STATUS", "branches":4},
  ],
  "branch_tree": <BrSeq object>,     // 完整的可遍历分支树对象
  "file_count": 2,
  "open_directions": {"TRANSIN":"INPUT", "VALIDOUT":"OUTPUT"},
  "has_search_all": true,
  "has_evaluate": true,
  "total_branches": 25,
  "total_paragraphs": 12,
}

2.3 数据格式与映射层

generate_data() 的输出格式必须与 DataWriter 的输入格式兼容。两者之间的映射关系:

cobol_testgen generate_data() 输出格式:
  list[dict] — 每条记录:
    {
      "TX-CARD-NO": "6222021234567800",      // 字段名 = COBOL 变量名
      "TX-AMOUNT": "00000128050",            // 值 = 字符串(COBOL DISPLAY 格式)
      "TX-TYPE": "P",
      ...
    }

现有 TestCase (data/test_case.py) 格式:
  TestCase(id="TC-001", fields={"BR-AMT": 1500000})
    // 字段名 = 映射后的业务名, 值 = Python 原生类型

DataWriter 需要的格式(runners/data_writer.py:
  write_cobol_binary(): 接收 TestCase[] → 按 FieldTree 偏移写二进制
  write_native_json():  接收 TestCase[] → 写 JSON Lines

Phase 1 适配方式: 在 orchestrator.py 中增加一个轻量转换函数 _cobol_testgen_to_testcases(),将 cobol_testgen 的输出转换为 TestCase[]

def _cobol_testgen_to_testcases(records: list[dict]) -> list:
    """
    将 cobol_testgen 的输出(字段名→字面值)转换为 TestCase 列表。
    字段值保留为字符串(COBOL 原始格式),DataWriter 根据 PIC 类型自动解析。
    """
    from data.test_case import TestCase
    result = []
    for i, rec in enumerate(records):
        tc = TestCase(id=f"CTG-{i+1:04d}", fields=dict(rec))
        result.append(tc)
    return result

分支树复用时的 COBOL 格式检测问题:

cobol_testgen 的 preprocess() 在解析源码前需要检测文件格式(fixed/free)。大型机迁移的 COBOL 程序 99% 是固定格式(列 7-72 为代码区)。如果格式检测错误,PROCEDURE DIVISION 解析会失败或返回空分支树。

extract_structure() 的实现必须注意:

  1. 强制指定格式假设: 默认按 fixed 格式解析(大型机迁移场景)
  2. 如果解析后分支树为空,尝试另一种格式
  3. 记录格式检测结果到结构摘要中 "source_format": "fixed" | "free" | "auto"
# extract_structure() 中的格式处理逻辑
# 默认以 fixed 格式解析(大型机 COBOL 的行业惯例)
# 如果解析后无决策点,尝试 free 格式
source_format = "fixed"
proc = extract_procedure_division(preprocess(source))
tree, _ = build_branch_tree(proc)
if not has_any_decision(tree):
    source_format = "free"
    proc = extract_procedure_division(preprocess_free(source))
    tree, _ = build_branch_tree(proc)

2.4 质量门禁的循环机制

generate_data() 只执行一次,放在循环外部。 每次迭代只做增量补充,不重跑全量生成。

# 首次生成(循环外)
base_tests = cobol_testgen.generate_data(cobol_src_text, branch_tree)
complete_tests = strategy_agent.supplement(base_tests, hina_result)

# 质量门禁循环(只做增量补充,不重跑 generate_data
MAX_TOTAL_RETRIES = 4
total_retry = 0

while total_retry < MAX_TOTAL_RETRIES:
    gate_result = quality_gate.check(complete_tests, hina_result, coverage_data)

    if gate_result["passed"]:
        break

    total_retry += 1
    issues = gate_result["issues"]
    # 格式: {"decision_gaps": [1, 3], "hina_gaps": ["MT-N002", "COM-A002"]}
    made_progress = False

    if issues.get("decision_gaps"):
        # 对未覆盖的决策点增量补充
        delta = cobol_testgen.incremental_supplement(
            branch_tree, issues["decision_gaps"]
        )
        complete_tests = complete_tests + delta
        made_progress = True

    if issues.get("hina_gaps"):
        # 对未满足的 HINA 必须项增量补充
        delta = strategy_agent.supplement_only(complete_tests, issues["hina_gaps"])
        complete_tests = complete_tests + delta
        made_progress = True

    if not made_progress:
        # 没有可修复的问题 → 跳出(避免死循环)
        break

# 循环结束后检查 final 结果
if not gate_result["passed"]:
    # 经过 MAX_TOTAL_RETRIES 或无可修复项后仍未通过
    # 不阻断管道(数据可以执行),但报告标记为 QUALITY_WARN
    vr.status = "QUALITY_WARN"
    vr.debug["quality_issues"] = gate_result["issues"]

decision_gaps 的格式:

decision_gaps = [1, 3, 5]  # 未覆盖的决策点 ID(对应结构摘要中的 decision_points[].id
# cobol_testgen.incremental_supplement() 根据 ID 找到对应的分支条件,
# 生成恰好覆盖该分支的测试数据

hina_gaps 的格式:

hina_gaps = ["MT-N002", "COM-A002"]  # 未满足的 HINA 必须项 ID
# strategy_agent.supplement_only() 根据 ID 找到对应的测试场景,
# 补充必要的测试数据

2.4 不通过时的原因分类与处置

质量门禁检查结果 → 原因分类

决策点覆盖率 < 95%:
  → incremental_supplement(decision_point_ids),补充决策点覆盖
  → 不超过 4 次总循环

HINA 必须项不足(Phase 2 之后):
  → supplement_only(missing_item_ids)
  → 不超过 4 次总循环

字段覆盖不足:
  → 补字段值(数值 0 算非空,空格/空串算空,unused 字段跳过)

边界条件不足:
  → 策略 Agent 根据类型模板补充

2.5 交叉验证

交叉验证以 cobol_testgen 静态分析为计数基准,gcov 仅提供"实际执行了"的佐证。

验证方式:
  1. cobol_testgen 统计静态分支总数和已覆盖数 → 分支覆盖率(静态)
  2. gcov 统计实际运行时执行过的行/分支
  3. 对比: 静态覆盖率 ≥ 95% 且 gcov 确认了执行

注意:
  - 不要求"差异=0",因为静态和动态对分支的计数方式可能不同
  - gcov 的作用是确认测试数据确实被执行了,而不是验证数量
  - 如果 gcov 不可用,降级为仅静态分析,报告标记"仅静态"

三、阶段实施

Phase 1: cobol_testgen 集成 + Agent2 保留(P0

改动:
  cobol_testgen/__init__.py → 暴露 extract_structure()、generate_data()
  orchestrator.py → 插入 extract_structure() + generate_data()
  └── Agent2(LLM) 仍然保留,在 cobol_testgen 之后补充语义化数据

流程:
  cobol_testgen(路径覆盖) → Agent2(语义补充) → 质量门禁(初步)

Phase 1 质量门禁检查维度:
  ├── 决策点覆盖率 ≥90%?  ✅ cobol_testgen 静态分析可用
  ├── 段落覆盖率 100%?     ✅ cobol_testgen 静态分析可用
  └── 其他维度(HINA/字段/边界)→ 尚未集成,跳过

中间状态:
  - 报告包含"覆盖率(初步)"标记,注明仅含决策点和段落维度
  - 覆盖率标准 ≥90%(低于正式标准的 95%)

为什么要保留 Agent2: cobol_testgen 按 PIC 类型生成边界值,但不知道字段的业务含义("TX-MERCHANT"应该用空/超长/特殊字符)。Agent2(LLM) 至少能看到字段名,能猜出业务含义。Phase 2 上线后 Agent2 被策略 Agent 取代。

分层重试可在 Phase 1 同时部署: retry.py 部署在调用者层,不依赖其他 Phase 的组件。

Phase 2: HINA Agent + 策略 AgentP1

新增:
  hina/classifier.py    # HINA Agent 调用 (类型判定)
  hina/strategy.py      # 策略模板 + 策略 Agent 调用 (测试补充)
  hina/gate.py          # 质量门禁 (覆盖率和必须项检查)

修改:
  orchestrator.py → Agent2 替换为策略 Agent

范围:
  优先覆盖 jcl-cobol-git 中实际需要的类型(按匹配现有程序优先级排列):
  1. マッチング系(M:N)— GENDATA/CRDVAL/CRDCALC 都需要
  2. キーブレイク系(键中断)— CRDCALC/CRDRPT 需要
  3. 内部表検索 (SEARCH/SEARCH ALL) — CRDVAL/CRDCALC 需要
  4. 条件分岐系 (IF/EVALUATE) — 所有程序都有
  5. 項目チェック系(字段校验)— CRDVAL 需要

  匹配系的高级检查(多文件数据映射)包含在本阶段优先级中。

Phase 3: 动态覆盖(P2

修改:
  runners/cobol_runner.py → 编译加 -fprofile-arcs
  如果 GnuCOBOL 不支持插桩,降级为仅静态

新增:
  hina/gcov_collector.py  # gcov 解析 + 降级逻辑

修改:
  orchestrator.py → 运行后采集 gcov + 交叉验证

Phase 4: 增强报告(P2

修改:
  report/generator.py → 增加覆盖率/HINA/质量评分/重试历史

依赖:
  - 覆盖率数据 → Phase 1/3 可用
  - HINA 信息 → Phase 2 完成后可用
  - 质量评分公式 → 依赖 Phase 2 的 HINA 必须项数据

质量评分公式(COBOL 版):
  质量评分 = 覆盖质量 × 0.6 + 边界质量 × 0.4

  覆盖质量 = 段落覆盖率 × 0.5 + 分支覆盖率 × 0.5
    例: (1.0 × 0.5 + 0.92 × 0.5) = 0.96

  边界质量 = HINA 必须项覆盖率(Phase 2 之后可用,之前以"待集成"显示)
    例: 10/10 = 1.0

  总评分 = 0.96 × 0.6 + 1.0 × 0.4 = 0.976 → 98/100

四、Agent 体系

4.1 4 个 Agent 分布

Agent 职责 输入 输出 位置
Agent1 COPYBOOK → FieldTree COPYBOOK 文本 字段结构树 Phase 0 原有
HINA Agent 程序类型判定 COBOL 源码 + 结构摘要 HINA 类型 + 確信度 Phase 2 新增
策略 Agent 测试数据补充 HINA 类型 + 规则数据 语义化测试值 Phase 2 新增
Agent3 差异诊断 不匹配字段 诊断建议 Phase 0 原有

Phase 1 特殊状态: Agent2 保留,在 cobol_testgen 之后做语义补充。Phase 2 上线后 Agent2 被策略 Agent 取代。

4.2 HINA Agent 的职责和 Prompt 模板

HINA Agent 遵循 cobol-test-benchmark.md 第3部的 Agent 边界设计。

输入: COBOL 源码 + 结构摘要 输出: JSON 格式的类型判定结果

{
  "category": "マッチング",
  "subtype": "1:N",
  "confidence": 0.95,
  "method": "hybrid",
  "features": ["MATCHING paragraph", "2 INPUT files", "KEY-BREAK processing"],
  "required_tests": ["MT-N001", "MT-N002", "MT-N004", "MT-N005", "COM-N001"],
  "strategy_params": {
    "min_data_pairs": [3, 3],
    "special_boundaries": ["不平衡: 主1件从N件", "空文件"],
    "coverage_requirements": {"branch": 0.95, "paragraph": 1.0}
  }
}

4.3 策略 Agent 的职责

输入:
  - cobol_testgen 生成的基础数据(保证路径覆盖)
  - HINA 类型 + 策略参数
  - FieldTree(字段定义)

职责:
  1. 字段语义补充
     "PIC X(20) 字段名为 TX-MERCHANT"→ 商户名 → 需要空值/超长/特殊字符
     "PIC X(16) 字段名为 TX-CARD-NO"→ 卡号 → 需要 Luhn校验/全零/格式化
  
  2. 类型特有边界
     匹配系 → 不平衡比(1件 vs N件)
     键中断 → 键值变化序列
     校验系 → 异常值矩阵
  
  3. 日文数据
     检测到 PIC N → 根据字段用途选择全角/半角/外字

输出:
  complete_test_cases(向已有数据追加补充)

五、质量门禁

5.1 检查项

检查 阶段 方法 标准 不通过处置 可用阶段
决策点覆盖 执行前 cobol_testgen 静态 ≥95% 增量补充(≤4次) Phase 1
段落覆盖 执行前 cobol_testgen 静态 100% 增量补充 Phase 1
HINA 必须项 执行前 规则判定 100% 增量补充 Phase 2
字段覆盖 执行前 枚举检查 100% 补充值 Phase 2
语句覆盖 执行后 gcov 动态 佐证 记录到报告 Phase 3
分支覆盖(动态) 执行后 gcov 动态 佐证 记录到报告 Phase 3

5.2 HINA 必须项判定规则

HINA_CHECK_RULES 中的每条规则需要定义明确的判定函数和依赖:

HINA_CHECK_RULES = {
    "COM-A002": {
        "description": "全部0件",
        "depends_on": "file_mapping",  # 需要知道哪些文件是输入文件
        "check": "any(empty for each INPUT file)",
        "note": "所有类型通用"
    },
    "MT-N001": {
        "description": "1:1 主键完全匹配",
        "depends_on": "file_mapping",  # 需要文件→FD→方向映射
        "check": "len(file_a) >= 1 and len(file_b) >= 1 and all_match(...)",
        "note": "匹配系特有"
    },
    # ... 其他必须项
}

文件映射逻辑: 门禁需要知道哪些 FD 是 INPUT、哪些是 OUTPUT,才能判断"全部0件"。这个信息来自 extract_structure().open_directions

5.3 质量评分公式(COBOL 版)

质量评分 = 覆盖质量 × 0.6 + 边界质量 × 0.4

覆盖质量 = 段落覆盖率 × 0.5 + 分支覆盖率 × 0.5
  例: (1.0 × 0.5 + 0.92 × 0.5) = 0.96

边界质量 = HINA 必须项覆盖率
  例: 10/10 = 1.0

总评分 = 0.96 × 0.6 + 1.0 × 0.4 = 0.976 → 98/100

六、增强报告

字段比对(原有):
  BR-AMT:    PASS (COBOL=1500.00, Java=1500.00)

覆盖率:
  ├── 覆盖率方式: ✅ 静态+动态 / 🟡 仅静态
  ├── 段落覆盖率: 100% (12/12) ✅
  ├── 分支覆盖率(静态): 96% (24/25) → 1个未覆盖
  ├── 分支覆盖率(动态): 已执行 ✅(佐证)
  ├── 语句覆盖率(动态): 已执行 ✅(佐证/或 不可用)
  ├── 决策点覆盖率: 96% (24/25) → 1个未覆盖
  └── 交叉验证: gcov 确认执行 ✅

HINA 信息(Phase 2+):
  ├── 判定类型: マッチング(1:N) — 確信度 95%
  ├── 判定方法: Agent (关键字+混淆组)
  └── ◎必须项: 10/10 覆盖 ✅

质量评分(Phase 2+:
  ├── 覆盖质量: 96/100
  ├── 边界质量: 100/100
  └── 总评分: 97/100 ✅ PASS

重试历史:
  ├── heal_retry: 1 (编译修复)
  ├── simple_retry: 0
  ├── quality_retries: 0
  └── 最终状态: PASS

七、分层重试

7.1 部署位置

分层重试部署在 orchestrator.py 调用者层(在 main.py 和 worker.py 中),而不是在 orchestrator 内部。

worker.py:                         orchestrator.py:
  result = retry_handler.run(        run_pipeline(...)
    lambda: run_pipeline(...)               ↑ 失败时返回状态码
  )                                        
  ↑ 根据状态码决定重试策略             不负责重试

retry_handler 的责任:
  1. 匹配已知失败模式 → 修复后 heal_retry
  2. 未知原因 → simple_retry
  3. 超出上限 → FATAL

分层重试不依赖 Phase 2/3 的组件,可在 Phase 1 部署。

7.2 重试层级

失败 → 匹配已知模式?
  ├── 编译失败 (COBCPY路径/方言不匹配) → 修复后 heal_retry +1
  ├── S0C7 (数值字段含非数值) → 数据补零后 heal_retry +1
  ├── 文件 OPEN 失败 → 检查 JCL/DD 后 heal_retry +1
  ├── HINA 判定低確信度 → Agent 重判定后 heal_retry +1
  ├── gcov 数据异常 → 重新编译插桩后 heal_retry +1
  └── 其他 → simple_retry +1

累计判断:
  heal_retry > 2 → HEAL_FAILED(降级,报告标注)
  simple_retry > 3 → RETRY_EXHAUSTEDFATAL
  total_retry > 6 → FATAL

八、阻断状态与用户操作指南

8.1 阻断状态一览

条件 状态 对用户的影响 用户操作路径
gcov 不可用 ⚠️ 降级(继续) 报告标记"仅静态" 不需要操作。覆盖率以静态分析为准
质量门禁 4 次后仍未通过 ⚠️ QUALITY_WARN(继续) 报告包含未覆盖分支清单 查看报告中的未覆盖清单 → 补充测试数据覆盖缺失的分支 → 重新运行
HINA Agent 確信度 < 70% 🔴 阻断 命令行提示 "HINA 判定不确定,请指定类型"。候选类型列表随提示输出 CLI: --hina-type "マッチング" 手动指定。Web: 待实现
LLM API 超时 ⚠️ 降级(继续) Agent1/Agent3 降级。覆盖率/HINA 信息为 unknown 检查 API 连接后重试
cobol_testgen 路径枚举超 ⚠️ 降级(继续) 覆盖率标记"可能不完整" 评估是否适合此程序的大路径数。可忽略

8.2 覆盖率展示规则(Phase 1-4 分阶段)

覆盖率在报告中按可用数据分阶段展示,避免展示不准确的数据造成误导:

Phase 报告展示 示例 说明
Phase 1 总分支数 + 已生成记录数 + 不可计算 总分支: 25 / 记录: 15 / 覆盖率: ⏳ 需要 gcov 不展示百分比
Phase 2 同上 + HINA 必须项数 HINA 必须项: 10/10 ✅ 覆盖质量独立展示
Phase 3 同上 + gcov 行覆盖率 行覆盖率(gcov): 92% 只展示 gcov 实际数据
Phase 4 完整评分 总评分: 97/100 汇总所有维度

8.3 阻断后的恢复流程

HINA Agent 確信度 < 70% → 阻断
  │
  ├── CLI 用户:
  │   查看提示的候选类型列表
  │   重新运行: python main.py --cobol-src ... --hina-type "マッチング"
  │   指定后跳过 Agent 判定,直接使用指定类型
  │
  ├── Web 用户(待实现):
  │   页面显示 "类型判定失败,请选择正确的程序类型"
  │   下拉框显示候选类型 → 选择后自动继续
  │
  └── 不确定类型:
      参考 cobol-test-benchmark.md 第1部的关键字识别表
      按 PROGRAM-ID 命名规则、FILE-CONTROL 中的文件数、PROCEDURE DIVISION 中的段落名判断

QUALITY_WARN(不阻断,但覆盖率不足):
  ├── 查看报告中的未覆盖决策点清单
  ├── 针对每个未覆盖 ID,在源码中找到对应的 IF/EVALUATE 条件
  ├── 补充覆盖该条件的测试数据
  └── 重新运行验证

九、实施步骤

Phase 1 (P0): cobol_testgen 集成 + Agent2 保留 + 分层重试
  ├── 暴露 extract_structure() + generate_data()+incremental_supplement()
  ├── 修改 orchestrator.py 插入路径覆盖
  ├── Agent2 保留做语义补充
  ├── 质量门禁(初步,仅决策点+段落维度,≥90%)
  └── hina/retry.py 分层重试部署

Phase 2 (P1): HINA Agent + 策略 Agent
  ├── hina/classifier.py       (HINA Agent)
  ├── hina/strategy.py         (策略模板 + 策略 Agent)
  ├── hina/gate.py             (质量门禁 + HINA 必须项)
  ├── Agent2 替换为策略 Agent
  └── 优先覆盖: 匹配系 > 键中断 > 内部表 > 条件分支 > 校验系

Phase 3 (P2): 动态覆盖
  ├── CobolRunner 新增编译参数
  ├── hina/gcov_collector.py
  └── 交叉验证

Phase 4 (P2): 增强报告
  ├── report/generator.py 增强(覆盖率/HINA/质量评分)
  ├── 质量评分公式(依赖 Phase 2 的 HINA 数据,之前显示"待集成")
  └── 重试历史展示