22 KiB
COBOL→Java/Spark 迁移验证平台 v3 理解文档
1. 系统概述
COBOL→Java/Spark 迁移验证平台。核心使命:给定 COBOL 源码及其迁移后的 Java/Spark 实现,自动生成覆盖所有分支路径的测试数据,分别运行两个版本,逐字段比对输出,判定迁移正确性并生成验证报告。
系统并非单一测试数据生成器,而是一条包含静态分析 → 测试数据生成 → 程序分类 → 编译运行 → 结果比对 → 诊断报告的完整自动化验证管道。
2. 架构总览
CLI (main.py) / Web (api.py)
│
▼
orchestrator.py ────────── 管道调度中枢
│
┌─────┼─────────┬──────────────┬──────────────┐
▼ ▼ ▼ ▼ ▼
cobol_testgen hina agents runners comparator
(测试数据生成) (分类/门禁) (LLM智能体) (编译运行引擎) (比对引擎)
│ │
▼ ▼
storage/report data/ (模型层)
(存储/报告) config/ (配置层)
关键设计决策: 系统有两套平行的数据产出路径——
cobol_testgen用规则引擎/Lark 语法解析生成覆盖全分支的测试数据(确定性)agents/Agent2Data用 LLM 从 FieldTree 生成测试数据设计(AI 辅助) 最终在orchestrator.py:110-112处以complete_tests(cobol_testgen + hina 输出)覆盖 Agent2Data 的suite.test_cases。
3. 目录结构
cobol-java-v3/
├── main.py ← CLI 入口(argparse → run_pipeline)
├── orchestrator.py ← 管道编排(核心调度器,~200 行)
├── preprocessor.py ← COPYBOOK 展开工具(独立类)
├── japanese_data.py ← 日文测试数据生成(全角/半角/和历日期)
│
├── cobol_testgen/ ← COBOL 测试数据生成引擎
│ ├── __init__.py ← 入口: main() + extract_structure/generate_data/incremental_supplement
│ ├── __main__.py ← python -m 入口
│ ├── read.py ← INPUT层: 预处理/COPYBOOK解决/DATA DIVISION解析/Lark
│ ├── core.py ← CORE层: PROCEDURE DIVISION解析→分支树→数据流追踪(~2000行)
│ ├── cond.py ← COND层: 条件解析+MC/DC枚举+约束合并
│ ├── design.py ← DESIGN层: 路径枚举+约束应用+值生成(~1350行)
│ ├── design_mcdc.py ← MC/DC 路径枚举变体
│ ├── coverage.py ← 覆盖率: 决策点收集+标记+中文HTML报告(~1300行)
│ ├── output.py ← 输出层: JSON(按FD分组入/出力+WS)
│ ├── models.py ← 共享数据模型
│ ├── pipeline_bridge.py ← 新旧解析器桥接(新 parser 主+旧 parser 超时回退)
│ ├── procedure_parser.py ← 新 PROCEDURE DIVISION 解析器(快速确定性)
│ ├── grammar.lark ← DATA DIVISION Lark 语法
│ ├── procedure_grammar.lark ← PROCEDURE DIVISION Lark 语法
│ ├── flatfile.py ← 平面文件工具
│ └── gcov.py ← gcov 覆盖率采集
│
├── hina/ ← 程序分类与质量门禁
│ ├── pipeline/pipeline.py ← 完整类型判定管道(关键词/规则/LLM 三路)
│ ├── classifier.py
│ ├── confidence.py
│ ├── gate.py ← 质量门禁判定
│ ├── strategy.py ← 策略补充
│ ├── retry.py ← 分层重试
│ └── gcov_collector.py
│
├── agents/ ← LLM 智能体
│ ├── llm.py ← LLMClient(httpx + 磁盘缓存 + 重试)
│ ├── agent1_parser.py ← COPYBOOK → FieldTree(LLM json)
│ ├── agent2_data.py ← FieldTree → TestSuite(LLM json)
│ └── agent3_diagnostic.py ← FieldResult → 诊断建议(LLM json)
│
├── comparator/ ← 对比引擎
│ ├── aligner.py ← COBOL↔Java 记录对齐(CUST-ID 键)
│ ├── field_compare.py ← 字段级比较(decimal/string)
│ ├── cobol_binary_reader.py ← 二进制 COBOL 输出解析
│ ├── normalizer.py ← COMP-3/EBCDIC 解码
│ └── rounding_detect.py ← 舍入检测
│
├── runners/ ← 编译运行引擎
│ ├── runner.py ← 抽象基类 Runner + BuildResult/RunResult
│ ├── cobol_runner.py ← cobc 编译+运行
│ ├── native_java_runner.py ← mvn + java -jar
│ ├── spark_java_runner.py ← spark-submit
│ └── data_writer.py ← 测试数据写入(二进制/JSON)
│
├── data/ ← 数据模型层
│ ├── field_tree.py ← Field / FieldTree
│ ├── test_case.py ← TestCase / TestSuite / SparkConfig
│ └── diff_result.py ← FieldResult / VerificationRun
│
├── config/ ← 配置
│ ├── __init__.py ← Config dataclass(Toml 加载)
│ └── mapping.py ← MappingConfig / FieldMapping
│
├── report/
│ └── generator.py ← JSON / HTML / machine JSON 报告
│
├── storage/
│ ├── bundle.py ← TestDataBundle 路径管理
│ └── store.py
│
├── web/ ← Web 接口
│ ├── api.py ← FastAPI(202+ polling)
│ ├── worker.py ← 后台 worker
│ ├── static/
│ └── templates/
│
├── tests/ ← 测试套件
├── test-data/ ← 测试数据
├── benchmark-programs/ ← 58 电信基准程序
├── data/ ← 运行时数据
├── config/ ← 运行时配置
│
├── pyproject.toml ← 项目元数据(verify-cli 0.1.0)
├── requirements.txt ← Python 依赖
├── DESIGN.md ← Web UI 设计规范
├── CLAUDE.md ← 项目指令
└── AGENTS.md ← AI Agent 指令(含修复历史)
4. 核心管道流程
4.1 CLI 入口 (main.py)
main.py --copybook <cpy> --cobol-src <cbl> --java-src <dir> --mapping <yaml>
[--runner native|spark] [--coverage boundary|branch]
[--tolerance 0.01] [--quality-gate-mode warn|off] [--gcov]
必选参数 4 个:copybook、cobol 源码、java 源码目录、映射文件。支持 --dry-run 前置校验路径存在性。
4.2 管道调度 (orchestrator.py:run_pipeline)
Phase 0 — 前置解析
copybook.cpy ─→ Agent1Parser (LLM) ─→ FieldTree(字段树)
Phase 1 — COBOL 测试数据生成 (cobol_testgen)
cobol.cbl ─→ preprocess() → resolve_copybooks() → parse_data_division()
─→ parse_procedure_division() → build_branch_tree()
─→ enum_paths() → generate_records() → base_records[]
Phase 2 — HINA 分类 + 策略补充 + 质量门禁
base_records[] ─→ classify_program() → category/confidence
─→ strategy supplement → 追加标记记录
─→ quality gate loop (最多 4 次 retry):
check_coverage() → gate_check()
if gaps: incremental_supplement() → 补充数据 → recheck
Phase 3 — LLM 测试数据设计 (Agent2Data)
FieldTree + complete_tests[] → Agent2Data (LLM) → TestSuite
注意: suite.test_cases 被 complete_tests 覆盖替换(行 112)
Phase 4 — 编译运行
TestSuite ─→ DataWriter → cobol_input.bin / spark_input.json
COBOL: cobol_runner.compile() → cobol_runner.run() → cobol_out.bin
Java: native/spark_runner.compile() → runner.run() → java_out records
Phase 5 — 对比 & 报告
cobol_out.bin ─→ CobolBinaryReader → dict[]
java_out ─→ JSON → dict[]
align_records(key="CUST-ID") → compare_field() → FieldResult[]
Agent3Diagnostic (LLM) → suggestion for MISMATCH
ReportGenerator → result.json / report.html / machine.json
4.3 数据流全图
copybook.cpy
│ Agent1Parser (LLM)
▼
FieldTree ────────────────────────┐
│ │
│ Agent2Data (LLM) │ cobol_testgen
▼ ▼
TestSuite (被覆盖) structure + base_records[]
│ │
│ DataWriter │ HINA classify + quality gate
▼ ▼
cobol_input.bin / json complete_tests[]
│
├── CobolRunner ──→ cobol_out.bin ──┐
└── JavaRunner ──→ java_out ──────┤
▼
align_records()
│
▼
compare_field() ──→ FieldResult[]
│
▼
Agent3Diagnostic (LLM) → suggestion
│
▼
ReportGenerator → result.json/html
5. 核心模块详解
5.1 cobol_testgen(测试数据生成引擎)
Layer 架构(4 层独立,每层单一职责):
| 层 | 文件 | 职责 |
|---|---|---|
| INPUT | read.py |
预处理器(固定/自由格式检测、COPYBOOK 展开、SQL/CICS EXEC 剥离)、Lark 语法解析 DATA DIVISION |
| CORE | core.py |
解析 PROCEDURE DIVISION 为分支树(BrIf/BrEval/BrPerform/Assign/CallNode/GoTo/ExitNode)、数据流追踪(trace_to_root/propagate_assignments) |
| COND | cond.py |
COBOL 条件解析(parse_single_condition/parse_compound_condition)、MC/DC 枚举(mcdc_sets)、约束合并(merge_field_constraints)、边界值求解(satisfying_value) |
| DESIGN | design.py |
路径枚举(enum_paths,LLM 优先 → 规则引擎回退)、记录生成(generate_records,约束应用到字段值) |
| OUTPUT | output.py |
JSON 输出(输入/期望输出/工作存储区,按 FD 分组) |
| COVERAGE | coverage.py |
决策点收集(collect_decision_points)→ 标记覆盖(mark_coverage)→ 中文 HTML 报告 |
关键数据模型 (models.py):
BrSeq— 序列容器BrIf— IF 分支(condition + cond_tree + true_seq + false_seq)BrEval— EVALUATE(subjects + when_list + other_seq)BrPerform— PERFORM(perf_type + condition + body_seq)BrSearch— SEARCH(at_end_seq + when_list)Assign— 赋值节点(target + source_info)CondLeaf/CondAnd/CondOr/CondNot— 条件树
路径枚举策略:
- 尝试 LLM 生成路径(
DEEPSEEK_API_KEY) - LLM 失败/无 key 则回退规则引擎(
_cap_paths限制 10000 条) - MC/DC 变体(
design_mcdc.py:enum_paths)用于generate_data()入口
基于旧 parser 的路径去重:_filter_stop 处理哨兵标记(__STOP__/__ABEND__),与覆盖率标记中的 _is_eof_path 过滤配合使用。
OCCURS 展开机制 (expand_occurs):
- 递归展开
occurs > 0的字段,生成WS-CELL(1)、WS-CELL(1,1)等下标签记副本 - 88-level 的
parent也会跟随展开
PREV 连锁机制 (_chain_prev):
- 多 WRITE 场景下的跨记录约束满足
- 处理
WRK-PREV-xxx前值比较的字段传递 - 判断 W02(正常)或 overlap(重疊)路径
5.2 hina(程序分类与质量门禁)
分类管道(三路径并行):
- 关键词匹配 — 从源码中识别对应银行业务模式的关键词
- 规则引擎 — 基于 IF 类型统计、变量命名模式、OPEN/CLOSE 模式的规则判定
- LLM 辅助 — 低确信度时调用 LLM 二次确认
质量门禁 (gate.py:check):
- 检查决策点覆盖率、段落覆盖率是否达到阈值(Config 中
quality_gate_decision_threshold默认 0.90) - 未通过时触发
incremental_supplement补充未覆盖决策点的数据 - 最大尝试次数:
max_quality_retries = 4
5.3 agents(LLM 智能体)
三个 Agent 定位清晰:
| Agent | 输入 | 处理 | 输出 |
|---|---|---|---|
| Agent1Parser | COPYBOOK 源码文本 | LLM 解析为 JSON | FieldTree |
| Agent2Data | FieldTree 字段列表 | LLM 生成边界测试用例 | TestSuite |
| Agent3Diagnostic | FieldResult (field_name + 双方值) | LLM 诊断 mismatch 原因 | suggestion 文本 |
LLMClient (agents/llm.py):
- 通用 HTTP 客户端(httpx),兼容 OpenAI API / DeepSeek
- 磁盘缓存(SHA256 散列键值,
.cache/llm/{hash}.json) - 1 次重试 + 异常冒泡
- 环境变量:
LLM_API_KEY/OPENAI_API_KEY,LLM_API_BASE
5.4 comparator(对比引擎)
CobolBinaryReader → dict[] java JSON → dict[]
│
▼
align_records(key_field="CUST-ID")
│
▼
(cobol_rec, java_rec, status) tuples
│
▼
compare_field(name, c_val, j_val, type, tolerance)
│
▼
FieldResult(PASS/TOLERATED/MISMATCH/NOT_SET)
- 对齐策略:基于
CUST-ID字段做记录级别匹配 - 比较模式:decimal 用容忍度比较,string 用精确字符串比较
- 字段类型判定:
tree.get_by_name(k).usage != "COMP-3" → string(不合理:COMP-3 是数值存储格式,但此处用!=判断,DISPLAY 和 COMP 等也会被归为 decimal)
5.5 runners(编译运行引擎)
| Runner | 编译 | 运行 | 输入格式 |
|---|---|---|---|
| CobolRunner | cobc -x |
直接执行二进制 | input.bin (二进制) |
| NativeJavaRunner | mvn package |
java -jar |
input.json |
| SparkJavaRunner | mvn package |
spark-submit |
spark input/ |
5.6 web(Web 接口)
- FastAPI + 202 Accepted 异步轮询模式
- 文件上传 →
uploads/{task_id}/→tasks/{task_id}.json状态文件 - 无数据库,纯文件系统状态管理
worker.py后台轮询处理队列- HTML 模板使用字符串替换(因 Jinja2 兼容性考虑)
6. 数据模型关系
FieldDef (cobol_testgen/models.py) ← Lark grammar 解析 DATA DIVISION 的结果
│
▼
FieldTree + Field (data/field_tree.py) ← Agent1Parser LLM 解析 COPYBOOK 的结果
│
├───▶ TestCase + TestSuite (data/test_case.py) ← 测试数据载体
│
└───▶ VerificationRun + FieldResult (data/diff_result.py) ← 管道运行结果
两套字段定义体系并存:
cobol_testgen/models.py:FieldDef— 带pic_info(PicInfo 对象)、occurs_count、is_88、redefines等 COBOL 细节data/field_tree.py:Field— 简洁版,含pic字符串、offset、length、children嵌套结构- 两者在 orchestrator 中互不交换数据(Agent1Parser 产生 FieldTree → Agent2Data,cobol_testgen 产生自己的 fields_dict)
7. 依赖关系
外部 Python 库
| 依赖 | 版本 | 用途 |
|---|---|---|
httpx |
>=0.27 | LLM API HTTP 调用 |
pyyaml |
>=6.0 | 映射文件解析 |
lark |
>=1.1.0 | DATA DIVISION 语法解析(Earley + dynamic lexer) |
fastapi / uvicorn |
— | Web API |
python-multipart |
— | 文件上传解析 |
pytest |
— | 测试框架 |
外部非 Python 工具
| 工具 | 用途 |
|---|---|
cobc (GnuCOBOL) |
COBOL 编译运行 |
java + mvn |
Java 编译运行 |
spark-submit |
Spark 模式运行(可选) |
gcov |
覆盖率采集(可选) |
外部 API
| API | 用途 | 环境变量 |
|---|---|---|
| OpenAI / LLM API | Agent 智能体调用 | LLM_API_KEY / OPENAI_API_KEY |
| DeepSeek API | cobol_testgen LLM 路径生成 | DEEPSEEK_API_KEY |
8. 关键注意事项
8.1 设计层面的注意事项
-
两套配置系统割裂 —
cobol_testgen/__init__.py:CONFIG(含abend_programs列表)与config/__init__.py:Config(从aurak.toml加载)完全不互通。修改Config参数不会影响cobol_testgen的行为。 -
两套字段定义体系并存 —
cobol_testgen内部使用FieldDef+fields_dict(list of dict),orchestrator 上层使用data/field_tree.py:Field+FieldTree。两者不共享,debug["field_tree"]从 FieldTree 取,cobol_testgen 的数据从 fields_dict 取。 -
LLM 同步阻塞且无流控 —
LLMClient.call()同步调用且超时仅 15s,大 COPYBOOK 易超时。Agent1Parser和Agent2Data无降级路径(JSON 解析失败则返回空结构)。 -
Web 模式的响应式任务模型脆弱 — 使用文件
tasks/{task_id}.json做状态管理,重启丢失所有未完成任务。worker 轮询无锁机制,并发安全未保证。 -
新旧 parser 并存隐患 —
pipeline_bridge.py中旧 parser 的 3s 超时用threading.Thread.daemon=True+join(3.0),超时后线程仍在后台运行(daemon 虽会在主进程退出时终止,但 3s 内可能已占用大量资源)。
8.2 代码层面的不合理之处(只标注,不修改)
-
字段类型判断逻辑有疑 —
orchestrator.py:163处:ft = "string" if m and m.usage != "COMP-3" else "decimal"COMP-3(压缩十进制)是 decimal 类型,但此逻辑意味着所有非 COMP-3 字段都被视为 string,包括 COMP、BINARY、PACKED-DECIMAL 等数值类型。
-
Agent2Data 的输出被无条件覆盖 —
orchestrator.py:112:suite.test_cases = complete_testsAgent2Data.design()的 LLM 调用结果被complete_tests完全替换,该 LLM 调用除了产生spark_config外没有实际用途。LLM 费用被浪费。 -
硬编码 LLM 成本 —
orchestrator.py:30,111:vr.llm_cost += 0.002(固定 $0.002/次),与实际模型(Config 中gpt-4o-mini)的 token 计费无关。 -
cobol_testgen/generate_data()中的条件值强制相等 —cobol_testgen/__init__.py:1069-1077:for m in re.finditer(r'IF\s+(\w[\w-]*)\s*[=<>]\s*(\w[\w-]*)', proc_upper): ... rec[rhs] = rec[lhs] # 强制 rhs 等于 lhs对所有形如
IF A > B的字段对比较,前一半记录的 rhs 被强制为 lhs 的值。这会破坏原有路径约束生成的精确值,且仅影响前一半记录——逻辑意图不明。 -
generate_data()中_resolve_field()的字段匹配逻辑 — 路径过滤时使用解析后的字段名去匹配_fdict_names。对形如WS-PLAN-CODE(WS-PLAN-IDX)的字段,解析为WS-PLAN-CODE后只检查 base 名是否存在,忽略了实际有下标的字段名(如WS-PLAN-CODE(1))已存在于 fields_dict 中。 -
COBOL_SCOPE_ENDERS硬编码列表 —core.py:12-16中的 scope enders 列表缺少END-ACCEPT、END-DISPLAY等,可能导致非预期解析提前结束。 -
cobol_testgen/core.py:29-60段落扫描中的空白处理 — 第 37 行re.match(r'^([A-Z0-9][A-Z0-9-]*)\.\s*$', line)要求段落名后紧跟.且只有空白,但 COBOL 允许在段落名后跟多语句,如PARA-A. MOVE A TO B。
8.3 边界情况与隐藏假设
-
假设
CUST-ID是对齐键 —align_records()硬编码key_field="CUST-ID",非此字段名的 FD 无法正确对齐。 -
假设 COPYBOOK 不含 88-level VALUE — AGENTS.md 明确指出目标程序不应有 88-level VALUE 子句,解析器对 88-level 值的依赖微乎其微。
-
假设 target 程序不含 INSPECT/STRING/UNSTRING —
extract_structure虽然检测has_inspect和has_string,但整个管道没有对这些语句做特殊处理或断言。 -
覆盖率补充依赖
branch_tree_obj—orchestrator.py:86质量门禁 gap 补充要求structure.get("branch_tree_obj")存在,但extract_structure成功执行且proc_div存在时才可能有。 -
--gcov模式需要运行二进制 COBOL — gcov 覆盖率采集依赖真实执行 COBOL 二进制文件,需要编译环境和实际运行平台(GnuCOBOL),在仅做静态分析时不可用。
9. 修复历史总结(AGENTS.md)
| Fix | 内容 | 涉及模块 |
|---|---|---|
| 1 | COMPUTE ROUNDED 正则修复 | core.py |
| 2 | OCCURS 下标 MOVE 目标保持 | core.py |
| 3 | DIVIDE REMAINDER 支持 | core.py |
| 4 | EVALUATE ALSO 多主体 | core.py, design.py |
| 5 | READ AT END 跳过 | core.py |
| 6 | WRITE/REWRITE 无 FROM | core.py |
| 7 | PERFORM UNTIL 复合条件路径 | design.py |
| 8 | IF 复合条件覆盖率标记修复 | coverage.py |
| 9 | pi_map 用未解析 key 查询 | design.py |
| 10 | 变量下标约束应用 | design.py |
| 11 | 多行 COMPUTE 表达式 | core.py |
| 12 | 多行 PERFORM VARYING | core.py |
| 13 | _mark_perform 复合条件标记 |
coverage.py |
| 14 | EVALUATE TRUE prior_false 笛卡尔积 |
coverage.py |
| 15 | SEARCH _non_match_for 下标匹配 |
coverage.py |
| 16 | 移除 _infer_implied 桩函数 |
coverage.py |
| 17 | PERFORM VARYING 末次 + 字母数字边界 + 零保护 | design.py, cond.py |
文档版本: v1.0 | 生成日期: 2026-06-27