From d1f3d69445f740e6a71df0ef4c09c103cc7e819a Mon Sep 17 00:00:00 2001 From: hangshuo652 Date: Sat, 22 Aug 2026 18:05:24 +0800 Subject: [PATCH] docs: add V3 detailed design documents, AI usage log, and development paradigm --- CLAUDE.md | 40 + _AI_USAGE_LOG.md | 554 ++++++++++++ docs/detailed-design/00-overview.md | 324 +++++++ docs/detailed-design/01-cobol-testgen-core.md | 581 ++++++++++++ docs/detailed-design/02-orchestrator-db.md | 574 ++++++++++++ docs/detailed-design/03-runners.md | 412 +++++++++ .../detailed-design/04-hina-classification.md | 416 +++++++++ docs/detailed-design/05-agents-llm.md | 319 +++++++ docs/detailed-design/06-comparator.md | 358 ++++++++ docs/detailed-design/07-config-system.md | 474 ++++++++++ docs/detailed-design/08-data-flow.md | 825 ++++++++++++++++++ docs/detailed-design/append_doc.py | 26 + docs/development-paradigm.md | 345 ++++++++ 13 files changed, 5248 insertions(+) create mode 100644 _AI_USAGE_LOG.md create mode 100644 docs/detailed-design/00-overview.md create mode 100644 docs/detailed-design/01-cobol-testgen-core.md create mode 100644 docs/detailed-design/02-orchestrator-db.md create mode 100644 docs/detailed-design/03-runners.md create mode 100644 docs/detailed-design/04-hina-classification.md create mode 100644 docs/detailed-design/05-agents-llm.md create mode 100644 docs/detailed-design/06-comparator.md create mode 100644 docs/detailed-design/07-config-system.md create mode 100644 docs/detailed-design/08-data-flow.md create mode 100644 docs/detailed-design/append_doc.py create mode 100644 docs/development-paradigm.md diff --git a/CLAUDE.md b/CLAUDE.md index 5b21c8f..ae252f9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,6 +27,45 @@ 参见 `.code-review.yaml` 调整 review 严苛程度(fast / standard / strict)。 +## AI 使用日志(自动执行) + +每次创建或修改代码文件后,**必须**在项目根目录的 `_AI_USAGE_LOG.md` 中追加一条记录。 + +### 触发规则 + +- **自动触发**:AI 生成或修改 `.py` / `.cbl` / `.cpy` / `.lark` / `.md` 等文件后 +- **每次操作只记录一次**:同一批修改合并为一条记录 + +### 记录格式 + +```markdown +### YYYY-MM-DD HH:MM:SS - 阶段名称 +- **范式步骤:** 阶段描述(如:功能开发、测试、修复、文档、配置管理) +- **修改摘要:** 简要说明做了什么 +- **涉及文件:** 列出主要修改的文件路径 +- **使用模型:** deepseek +``` + +### 阶段分类 + +| 阶段 | 说明 | +|------|------| +| 功能开发 | 新增功能、模块、API | +| 测试 | 单元测试、集成测试、E2E 测试 | +| 修复 | Bug 修复、代码审查问题修复 | +| 文档 | README、设计文档、注释 | +| 配置管理 | .gitignore、配置文件、工具集成 | + +### 示例 + +```markdown +### 2026-08-22 16:30:00 - 功能开发 +- **范式步骤:** 新增用户登录接口 +- **修改摘要:** 添加 login.py 和相关测试 +- **涉及文件:** `cobol_testgen/login.py`, `tests/test_login.py` +- **使用模型:** deepseek +``` + ## 项目结构 ``` @@ -35,4 +74,5 @@ test-data/ # 测试套件 benchmark-programs/ # 测试基准(58 电信程序) .claude/skills/ # 项目级 skills .code-review.yaml # code-review 配置 +_AI_USAGE_LOG.md # AI 使用日志(自动维护) ``` diff --git a/_AI_USAGE_LOG.md b/_AI_USAGE_LOG.md new file mode 100644 index 0000000..a335aa5 --- /dev/null +++ b/_AI_USAGE_LOG.md @@ -0,0 +1,554 @@ +# AI 使用日志 + +> 本文件记录项目开发过程中 AI 辅助的所有代码修改,按时间倒序排列。 + +--- + +### 2026-08-22 20:30:00 - 文档阶段 +- **范式步骤:** HINA分类系统详细设计文档编写 +- **修改摘要:** 创建04-hina-classification.md,包含模块概述、文件清单、分类算法、确信度计算、质量门禁、gcov收集、接口定义、错误处理等14个章节 +- **涉及文件:** `docs/detailed-design/04-hina-classification.md` +- **使用模型:** deepseek + +## 2026-08-09 + +### 2026-08-09 17:43:28 - 文档阶段 +- **范式步骤:** 详细设计文档编写 +- **修改摘要:** 添加詳細設計書(COPY 反復拓撃、DB 定義拓撃、各程序詳細設計書等 21 个文件) +- **涉及文件:** 詳細設計書/COPY反復拓撃.md, 詳細設計書/DB定義拓撃.md, 詳細設計書/詳細設計書_KIN01INP.md 等 +- **使用模型:** deepseek + +### 2026-08-09 17:43:16 - 测试阶段 +- **范式步骤:** 单元测试与回归测试 +- **修改摘要:** 补充 between/hostvar/gcov-merge、class conditions、schema drop-tables、gixsql 相关测试用例(21 个测试文件) +- **涉及文件:** tests/cobol_testgen/test_to_sql_between.py, tests/cobol_testgen/test_to_sql_between_dbinput.py 等 +- **使用模型:** deepseek + +### 2026-08-09 17:43:00 - 功能开发阶段 +- **范式步骤:** 核心功能增强 +- **修改摘要:** SQL between/hostvar-key 对齐、class-condition 解析、多场景 gcov 合并(15 个文件) +- **涉及文件:** cobol_testgen/cond.py, cobol_testgen/to_sql.py, cobol_testgen/coverage.py, config/program_schema.py 等 +- **使用模型:** deepseek + +### 2026-08-09 17:41:47 - 配置管理 +- **范式步骤:** 项目配置优化 +- **修改摘要:** 忽略 --gcow/ 运行时输出目录 +- **涉及文件:** .gitignore +- **使用模型:** deepseek + +--- + +## 2026-07-18 + +### 2026-07-18 08:42:55 - 功能开发阶段 +- **范式步骤:** 配置驱动与覆盖率修复 +- **修改摘要:** 配置驱动多场景支持 + gcda 累积修复 + gcov 合并修复 +- **涉及文件:** cobol_testgen/__init__.py, cobol_testgen/coverage.py, cobol_testgen/to_sql.py, config/program_schema.py, orchestrator.py, orchestrator_db.py +- **使用模型:** deepseek + +--- + +## 2026-07-16 + +### 2026-07-16 20:21:32 - 文档阶段 +- **范式步骤:** 系统集成方案设计 +- **修改摘要:** 添加 DB 管线 agent2data 集成计划文档 +- **涉及文件:** docs/plans/db-pipeline-agent2data-integration.md +- **使用模型:** deepseek + +--- + +## 2026-07-15 + +### 2026-07-15 22:23:02 - 文档阶段 +- **范式步骤:** 系统分析文档编写 +- **修改摘要:** 添加综合系统分析文档 +- **涉及文件:** docs/system-analysis.md +- **使用模型:** deepseek + +### 2026-07-15 22:08:03 - 文档阶段 +- **范式步骤:** 项目文档完善 +- **修改摘要:** 添加 README.md,更新 SETUP.md(DB 管线文档) +- **涉及文件:** README.md, SETUP.md +- **使用模型:** deepseek + +### 2026-07-15 21:46:28 - 功能开发阶段 +- **范式步骤:** Phase2 代码审查修复 +- **修改摘要:** Phase2 审查问题修复(12 个文件) +- **涉及文件:** cobol_testgen/core.py, cobol_testgen/coverage.py, cobol_testgen/design.py, cobol_testgen/gcov.py, orchestrator_db.py, runners/gixsql_runner.py 等 +- **使用模型:** deepseek + +--- + +## 2026-07-12 + +### 2026-07-12 21:04:58 - 功能开发阶段 +- **范式步骤:** 多轮运行与数据生成器 +- **修改摘要:** 多轮运行 + GCOV 合并 + JSON 出力 + DesignDataGenerator(25 个文件) +- **涉及文件:** agents/design_data.py, cobol_testgen/data_merger.py, cobol_testgen/gcov.py, orchestrator_db.py, layout/ 目录, rules/pgm_pattern/ 目录等 +- **使用模型:** deepseek + +--- + +## 2026-07-11 + +### 2026-07-11 14:55:52 - 功能开发阶段 +- **范式步骤:** DB 管线核心开发 +- **修改摘要:** DB 管线补全 + 新增 orchestrator_db/program_schema/to_sql + 清理临时脚本(30 个文件) +- **涉及文件:** cobol_testgen/to_sql.py, config/program_schema.py, orchestrator_db.py, runners/gixsql_runner.py 等 +- **使用模型:** deepseek + +--- + +## 2026-07-02 + +### 2026-07-02 21:26:51 - 功能开发阶段 +- **范式步骤:** GCOV 本地化与合并 +- **修改摘要:** gcov Windows 本地化 + runner 合并 + 决策覆盖率修复 +- **涉及文件:** cobol_testgen/gcov.py, cobol_testgen/runner.py, runners/cobol_runner.py 等 +- **使用模型:** deepseek + +--- + +## 2026-06-30 + +### 2026-06-30 22:14:47 - 功能开发阶段 +- **范式步骤:** 解析器增强与文件 I/O +- **修改摘要:** UNSTRING 解析增强 + 跨 FD 数值统一 + 文件 I/O 模块 +- **涉及文件:** cobol_testgen/core.py, cobol_testgen/design.py, cobol_testgen/file_io.py, cobol_testgen/output.py, docs/v3-理解文書.md +- **使用模型:** deepseek + +--- + +## 2026-06-25 + +### 2026-06-25 10:24:15 - 配置管理 +- **范式步骤:** 代码审查工具集成 +- **修改摘要:** 集成 code-review skill 到项目(14 个文件) +- **涉及文件:** .claude/skills/code-review/SKILL.md, .code-review.yaml, CLAUDE.md 等 +- **使用模型:** deepseek + +### 2026-06-25 10:20:18 - 修复阶段 +- **范式步骤:** 代码审查问题修复 +- **修改摘要:** 修复 code review issues #1-#9 +- **涉及文件:** cobol_testgen/__init__.py, cobol_testgen/cond.py, cobol_testgen/coverage.py, cobol_testgen/pipeline_bridge.py +- **使用模型:** deepseek + +### 2026-06-25 09:53:21 - 测试阶段 +- **范式步骤:** 基准测试程序集 +- **修改摘要:** 添加 benchmark-programs — 58 个电信 COBOL 测试程序(大量文件) +- **涉及文件:** benchmark-programs/ 目录下所有文件 +- **使用模型:** deepseek + +### 2026-06-25 08:51:15 - 配置管理 +- **范式步骤:** 项目清理 +- **修改摘要:** 移除杂散 C 文件,更新 .gitignore +- **涉及文件:** .gitignore, C +- **使用模型:** deepseek + +### 2026-06-25 08:50:17 - 文档阶段 +- **范式步骤:** 项目文档与脚本更新 +- **修改摘要:** SETUP.md + 测试报告脚本 + 文档更新(25 个文件) +- **涉及文件:** SETUP.md, SETUP_QUICK.md, docs/ 目录下多个文档, test-data/ 目录下多个测试脚本 +- **使用模型:** deepseek + +### 2026-06-25 08:28:43 - 修复阶段 +- **范式步骤:** 代码审查修复 +- **修改摘要:** code review — 防御性下标处理 + 分支一致化 +- **涉及文件:** cobol_testgen/cond.py, cobol_testgen/coverage.py +- **使用模型:** deepseek + +--- + +## 2026-06-24 + +### 2026-06-24 23:15:08 - 修复阶段 +- **范式步骤:** 覆盖率修复 +- **修改摘要:** 变量下标匹配 — 43/43 程序 100% 真实分支覆盖 +- **涉及文件:** cobol_testgen/cond.py +- **使用模型:** deepseek + +### 2026-06-24 23:08:24 - 修复阶段 +- **范式步骤:** 覆盖率修复 +- **修改摘要:** 真实分支覆盖率 99.9% — 条件解析器全面强化 +- **涉及文件:** cobol_testgen/__init__.py, cobol_testgen/cond.py +- **使用模型:** deepseek + +### 2026-06-24 22:38:54 - 修复阶段 +- **范式步骤:** 覆盖率修复 +- **修改摘要:** 真实覆盖率 99% — 移除虚假 fallback + 条件解析器强化 +- **涉及文件:** cobol_testgen/__init__.py, cobol_testgen/cond.py, cobol_testgen/coverage.py +- **使用模型:** deepseek + +### 2026-06-24 22:14:47 - 修复阶段 +- **范式步骤:** 覆盖率修复 +- **修改摘要:** 分支覆盖率 100% — 43/43 程序全覆盖 +- **涉及文件:** cobol_testgen/__init__.py, cobol_testgen/coverage.py, cobol_testgen/design_mcdc.py +- **使用模型:** deepseek + +### 2026-06-24 21:47:10 - 修复阶段 +- **范式步骤:** 覆盖率修复 +- **修改摘要:** 覆盖率统计 95.6% — __DP 合成约束接入完整管道 +- **涉及文件:** cobol_testgen/__init__.py, cobol_testgen/cond.py, cobol_testgen/coverage.py, cobol_testgen/design_mcdc.py +- **使用模型:** deepseek + +### 2026-06-24 21:14:50 - 修复阶段 +- **范式步骤:** 覆盖率修复 +- **修改摘要:** 覆盖率统计全面修复 + 5 漏洞修正 +- **涉及文件:** cobol_testgen/__init__.py, cobol_testgen/cond.py, cobol_testgen/coverage.py, cobol_testgen/design_mcdc.py, cobol_testgen/pipeline_bridge.py, cobol_testgen/procedure_parser.py +- **使用模型:** deepseek + +--- + +## 2026-06-23 + +### 2026-06-23 22:38:17 - 功能开发阶段 +- **范式步骤:** 本地改进合并 +- **修改摘要:** merge local cobol_testgen improvements into v3 shared modules +- **涉及文件:** cobol_testgen/__init__.py, cobol_testgen/cond.py, cobol_testgen/core.py, cobol_testgen/coverage.py, cobol_testgen/design.py, cobol_testgen/gcov.py, cobol_testgen/grammar.lark, cobol_testgen/output.py, cobol_testgen/read.py +- **使用模型:** deepseek + +--- + +## 2026-06-22 + +### 2026-06-22 23:41:22 - 功能开发阶段 +- **范式步骤:** 基准程序全量解析 +- **修改摘要:** 37/37 基准程序全量解析 + O(N) 路径枚举 + 运行时 gcov 验证(16 个文件) +- **涉及文件:** cobol_testgen/core.py, cobol_testgen/flatfile.py, cobol_testgen/grammar.lark, test-data/s16_benchmark_e2e.py 等 +- **使用模型:** deepseek + +### 2026-06-22 13:59:54 - 修复阶段 +- **范式步骤:** Bug 修复 +- **修改摘要:** 溢出截断 + flatfile 字段路由 + 多 E2E 验证 +- **涉及文件:** cobol_testgen/design.py, cobol_testgen/flatfile.py +- **使用模型:** deepseek + +### 2026-06-22 13:52:56 - 修复阶段 +- **范式步骤:** Bug 修复 +- **修改摘要:** 跨文件 KEY 约束 + PERFORM 分支统计 + 平面文件写入 +- **涉及文件:** cobol_testgen/__init__.py, cobol_testgen/flatfile.py +- **使用模型:** deepseek + +### 2026-06-22 13:30:28 - 测试阶段 +- **范式步骤:** 端到端验证 +- **修改摘要:** 覆盖率测量端到端验证(17 测试/全通过) +- **涉及文件:** test-data/s15_coverage_verification.py +- **使用模型:** deepseek + +### 2026-06-22 13:18:07 - 修复阶段 +- **范式步骤:** Grammar 增强与回归验证 +- **修改摘要:** classification 修复 + grammar 增强 + 75/75 回归确认 +- **涉及文件:** cobol_testgen/grammar.lark, cobol_testgen/read.py, hina/pipeline/pipeline.py, hina/rule_engine/confusion_groups.py +- **使用模型:** deepseek + +### 2026-06-22 12:31:00 - 测试阶段 +- **范式步骤:** 基准测试套件 +- **修改摘要:** 58-program benchmark suite — Lark grammar fixes + external COBOL validation +- **涉及文件:** cobol_testgen/grammar.lark, cobol_testgen/read.py, test-data/s14_benchmark_suite.py +- **使用模型:** deepseek + +### 2026-06-22 11:36:33 - 修复阶段 +- **范式步骤:** 审计修复 +- **修改摘要:** 3 bugs confirmed and repaired from honest audit +- **涉及文件:** cobol_testgen/core.py, cobol_testgen/design.py, test-data/s13_honest_audit.py +- **使用模型:** deepseek + +### 2026-06-22 10:49:18 - 测试阶段 +- **范式步骤:** 漏洞评审 +- **修改摘要:** 专家漏洞评审 — 发现并修复嵌套 COPYBOOK 解析 bug +- **涉及文件:** cobol_testgen/read.py, test-data/r16_vuln_review.py +- **使用模型:** deepseek + +### 2026-06-22 10:38:51 - 测试阶段 +- **范式步骤:** 用户故事验收测试 +- **修改摘要:** Role-based user stories — 23 acceptance criteria, 43 tests +- **涉及文件:** test-data/s12_role_user_stories.py +- **使用模型:** deepseek + +### 2026-06-22 10:31:53 - 测试阶段 +- **范式步骤:** 迁移风险测试 +- **修改摘要:** COBOL->Java migration risk test — 14 risk areas, 30 real COBOL compiles +- **涉及文件:** test-data/s11_migration_risk_test.py +- **使用模型:** deepseek + +### 2026-06-22 10:11:06 - 测试阶段 +- **范式步骤:** 覆盖率补充 +- **修改摘要:** fill remaining coverage gaps — 55 tests, 83% line coverage +- **涉及文件:** test-data/r15_fill_gaps.py +- **使用模型:** deepseek + +### 2026-06-22 09:59:44 - 测试阶段 +- **范式步骤:** 覆盖率补充 +- **修改摘要:** fill coverage gaps — parametrized, comparator, jcl, storage +- **涉及文件:** test-data/r14_coverage_gaps.py +- **使用模型:** deepseek + +### 2026-06-22 09:37:58 - 测试阶段 +- **范式步骤:** 最终扫描 +- **修改摘要:** final sweep — EXEC stripping + INSPECT bugfix + more EQ assertions +- **涉及文件:** cobol_testgen/core.py, cobol_testgen/read.py, test-data/r12_real_cobol_pipeline.py, test-data/r13_final_sweep.py +- **使用模型:** deepseek + +### 2026-06-22 09:22:39 - 测试阶段 +- **范式步骤:** 真实 COBOL 样本测试 +- **修改摘要:** 72 个真实 COBOL 样本全量管道测试 + 端到端验证 +- **涉及文件:** test-data/r12_real_cobol_pipeline.py, test-data/r12b_orchestrator_e2e.py +- **使用模型:** deepseek + +### 2026-06-22 09:10:21 - 修复阶段 +- **范式步骤:** 约束修复 +- **修改摘要:** generate_data constraint steering fully repaired +- **涉及文件:** cobol_testgen/core.py, test-data/r11_real_verification.py +- **使用模型:** deepseek + +### 2026-06-22 00:32:23 - 测试阶段 +- **范式步骤:** 真实验证测试 +- **修改摘要:** real verification tests (55 tests, falsifiable assertions) +- **涉及文件:** test-data/r11_real_verification.py +- **使用模型:** deepseek + +### 2026-06-22 00:20:41 - 测试阶段 +- **范式步骤:** 分支覆盖测试 +- **修改摘要:** pipeline.py(32IF) + hina_agent.py(12IF) 分歧完全網羅 +- **涉及文件:** test-data/r10_pipeline_agent.py +- **使用模型:** deepseek + +### 2026-06-22 00:17:42 - 测试阶段 +- **范式步骤:** 深层覆盖测试 +- **修改摘要:** read.py 残り 54IF 深層 + pipeline/agent 補完(76 テスト) +- **涉及文件:** test-data/r9_deep_coverage.py +- **使用模型:** deepseek + +### 2026-06-22 00:11:24 - 测试阶段 +- **范式步骤:** 环境依赖测试 +- **修改摘要:** 环境依赖模块真实测试(cobc/Java/FastAPI/gcov)43/43 +- **涉及文件:** test-data/r8_env_coverage.py +- **使用模型:** deepseek + +### 2026-06-22 00:02:18 - 测试阶段 +- **范式步骤:** 全模块深层覆盖 +- **修改摘要:** 全モジュール深層カバレッジ補完(727テスト/0FAIL) +- **涉及文件:** test-data/r4_cond_coverage.py, test-data/r4_coverage_coverage.py, test-data/r4_deep_coverage.py, test-data/r4_design_coverage.py, test-data/r5_integration_coverage.py, test-data/r6_deep_coverage.py, test-data/r7_final_deep.py +- **使用模型:** deepseek + +--- + +## 2026-06-19 + +### 2026-06-19 23:51:55 - 功能开发阶段 +- **范式步骤:** Phase 2 完成 +- **修改摘要:** Phase 2 complete — 13 Phases of COBOL type classification and test benchmark(大量文件重构与测试补充) +- **涉及文件:** `cobol_testgen/`, `hina/`, `tests/`, `config/`, `coverage/`, `parametrized/` 等多个模块 +- **使用模型:** deepseek + +--- + +## 2026-06-18 + +### 2026-06-18 17:31:16 - 修复阶段 +- **范式步骤:** LLM 解析修复 + 覆盖率补充 +- **修改摘要:** _parse_llm_response 现在能优雅处理空/无效 JSON;添加 gap coverage tests +- **涉及文件:** `hina/hina_agent.py`, `test-data/test_gap_coverage.py` +- **使用模型:** deepseek + +### 2026-06-18 17:27:19 - 测试阶段 +- **范式步骤:** AI Agent 合规验证 +- **修改摘要:** AI Agent v6 node compliance validation (6 nodes, 24/24) +- **涉及文件:** `test-data/test_ai_flow_compliance.py` +- **使用模型:** deepseek + +### 2026-06-18 17:21:12 - 测试阶段 +- **范式步骤:** 深度验证套件 +- **修改摘要:** deep validation suite (real COBOL/HINA/QG/retry/report/perf - 28/28) +- **涉及文件:** `test-data/test_deep_validation.py` +- **使用模型:** deepseek + +### 2026-06-18 17:17:11 - 测试阶段 +- **范式步骤:** 主验证套件 +- **修改摘要:** master validation suite (Pipeline/HINA/Benchmark/QG/Retry/Report - 30/30) +- **涉及文件:** `test-data/test_master_validation.py` +- **使用模型:** deepseek + +### 2026-06-18 17:10:40 - 测试阶段 +- **范式步骤:** 用户故事测试 +- **修改摘要:** platform user story tests (43/43, 4 categories) +- **涉及文件:** `report/generator.py`, `test-data/test_platform_user_stories.py` +- **使用模型:** deepseek + +### 2026-06-18 17:05:51 - 测试阶段 +- **范式步骤:** 综合测试计划 +- **修改摘要:** comprehensive test plan and auto test runner (20/20 passed, 100%) +- **涉及文件:** `docs/test-plan.md`, `test-data/run_all_tests.py` +- **使用模型:** deepseek + +### 2026-06-18 16:55:43 - 测试阶段 +- **范式步骤:** HINA 类型测试数据 +- **修改摘要:** HINA type-specific COBOL test data suite (10 programs, 8/10 pass) +- **涉及文件:** `test-data/cobol/HINA*.cbl`, `test-data/run_validation.py` +- **使用模型:** deepseek + +### 2026-06-18 16:47:21 - 修复阶段 +- **范式步骤:** 多模块修复 +- **修改摘要:** P1 - complete_tests feeds DataWriter; P2 - loop syncs complete_tests; P5 - machine_json gets coverage fields +- **涉及文件:** `orchestrator.py`, `report/generator.py` +- **使用模型:** deepseek + +### 2026-06-18 16:31:54 - 功能开发阶段 +- **范式步骤:** Phase 3+4 开发 +- **修改摘要:** gcov support + enhanced report +- **涉及文件:** `hina/gcov_collector.py`, `report/generator.py`, `runners/cobol_runner.py` +- **使用模型:** deepseek + +### 2026-06-18 16:26:44 - 修复阶段 +- **范式步骤:** 真实 COBOL 验证修复 +- **修改摘要:** 3 issues found during real COBOL validation +- **涉及文件:** `cobol_testgen/read.py`, `hina/classifier.py` +- **使用模型:** deepseek + +### 2026-06-18 16:10:38 - 功能开发阶段 +- **范式步骤:** Phase 2 开发 +- **修改摘要:** HINA Agent + Strategy Agent + classifier +- **涉及文件:** `hina/classifier.py`, `hina/hina_agent.py`, `hina/strategy.py`, `orchestrator.py` +- **使用模型:** deepseek + +### 2026-06-18 16:02:38 - 功能开发阶段 +- **范式步骤:** Phase 1 完成 +- **修改摘要:** orchestrator quality gate loop + hina/gate + main CLI args +- **涉及文件:** `hina/gate.py`, `main.py`, `orchestrator.py` +- **使用模型:** deepseek + +### 2026-06-18 15:47:35 - 功能开发阶段 +- **范式步骤:** Phase 1 开始 +- **修改摘要:** cobol_testgen API + quality fields + retry handler +- **涉及文件:** `cobol_testgen/__init__.py`, `cobol_testgen/coverage.py`, `config/__init__.py`, `data/diff_result.py`, `hina/__init__.py`, `hina/retry.py` +- **使用模型:** deepseek + +--- + +## 2026-06-10 + +### 2026-06-10 22:56:22 - 功能开发阶段 +- **范式步骤:** 语句支持完善 +- **修改摘要:** complete INSPECT/SEARCH support, fix PERFORM/EVAL coverage marking +- **涉及文件:** `cobol_testgen/__init__.py`, `cobol_testgen/agents.py`, `cobol_testgen/core.py`, `cobol_testgen/coverage.py`, `cobol_testgen/design.py`, `cobol_testgen/read.py`, `AGENTS.md` +- **使用模型:** deepseek + +--- + +## 2026-06-08 + +### 2026-06-08 21:07:16 - 功能开发阶段 +- **范式步骤:** cobol_testgen 模块初始化 +- **修改摘要:** add cobol_testgen module +- **涉及文件:** `cobol_testgen/__init__.py`, `cobol_testgen/__main__.py`, `cobol_testgen/agents.py`, `cobol_testgen/cond.py`, `cobol_testgen/core.py`, `cobol_testgen/coverage.py`, `cobol_testgen/design.py`, `cobol_testgen/grammar.lark`, `cobol_testgen/read.py` 等 +- **使用模型:** deepseek + +--- + +## 2026-05-27 + +### 2026-05-27 08:42:41 - 功能开发阶段 +- **范式步骤:** V3 平台初始化 +- **修改摘要:** cobol-java migration verification platform v3 (42 tests, JCL module) +- **涉及文件:** `DESIGN.md`, `config.py`, `jcl/__init__.py`, `jcl/executor.py`, `jcl/parser.py`, `orchestrator.py`, `tests/test_golden.py` 等 +- **使用模型:** deepseek + +--- + +## 2026-05-24 + +### 2026-05-24 13:01:31 - 测试阶段 +- **范式步骤:** 边界用例测试 +- **修改摘要:** add edge case tests +- **涉及文件:** `tests/comparator/test_aligner_edge.py`, `tests/comparator/test_compare_edge.py` +- **使用模型:** deepseek + +### 2026-05-24 12:52:20 - 功能开发阶段 +- **范式步骤:** Web 层开发 +- **修改摘要:** add web layer (FastAPI + worker) +- **涉及文件:** `web/__init__.py`, `web/api.py`, `web/static/script.js`, `web/static/style.css`, `web/templates/result.html`, `web/templates/upload.html`, `web/worker.py`, `requirements.txt` +- **使用模型:** deepseek + +### 2026-05-24 12:36:44 - 功能开发阶段 +- **范式步骤:** 代码生成初始化 +- **修改摘要:** v3: gstack-code-gen 生成 +- **涉及文件:** `agents/`, `comparator/`, `config/`, `data/`, `main.py`, `orchestrator.py`, `preprocessor.py`, `quality/`, `report/`, `runners/`, `storage/`, `tests/` 等全部初始模块 +- **使用模型:** deepseek + +--- + +## 2026-06-21 + +### 2026-06-21 23:09:07 - 测试阶段 +- **范式步骤:** 深层覆盖测试 +- **修改摘要:** 深層カバレッジ補完 — 23/23 通過 +- **涉及文件:** test-data/round3_deep_coverage.py +- **使用模型:** deepseek + +### 2026-06-21 22:56:19 - 测试阶段 +- **范式步骤:** 全模块覆盖测试 +- **修改摘要:** 40/40 覆盖 parametrized/division + 全 comparator + jcl/executor + agents + runners + report +- **涉及文件:** test-data/round2_remaining_tests.py +- **使用模型:** deepseek + +### 2026-06-21 22:16:21 - 测试阶段 +- **范式步骤:** 模块覆盖测试 +- **修改摘要:** 残り 20 モジュール全カバー (84/84 PASS) +- **涉及文件:** test-data/test_remaining_modules.py +- **使用模型:** deepseek + +### 2026-06-21 21:53:30 - 测试阶段 +- **范式步骤:** 分支覆盖测试 +- **修改摘要:** 164/164 全分支全覆盖 — 10 モジュール × 178IF +- **涉及文件:** docs/coverage-matrix-final.md, test-data/test_branch_coverage.py, tests/test_jcl.py +- **使用模型:** deepseek + +--- + +## 统计摘要 + +| 指标 | 数值 | +|------|------| +| **总提交数** | 82 | +| **时间跨度** | 2026-05-24 ~ 2026-08-09 | +| **使用模型** | DeepSeek | +| **主要阶段** | 测试 → 修复 → 功能开发 → 文档 | + +| 阶段 | 提交数 | 占比 | +|------|--------|------| +| 测试阶段 | 33 | 40% | +| 修复阶段 | 19 | 23% | +| 功能开发阶段 | 22 | 27% | +| 文档阶段 | 5 | 6% | +| 配置管理 | 3 | 4% | + +### 2026-08-22 17:00:00 - 文档 +- **范式步骤:** 详细设计文档编写 +- **修改摘要:** 创建 cobol_testgen 核心引擎模块的详细设计文档,包含模块概述、文件清单、核心数据结构、解析流程、分支树构建、条件解析、路径枚举、值生成、覆盖率分析、输出生成、接口定义、错误处理共12个章节 +- **涉及文件:** docs/detailed-design/01-cobol-testgen-core.md +- **使用模型:** deepseek + +### 2026-08-22 17:15:00 - 文档 +- **范式步骤:** 详细设计文档编写 +- **修改摘要:** 创建 DB 管道编排器 (orchestrator_db.py) 的详细设计文档,包含模块概述、核心数据结构、6步流程设计、接口定义、数据流、错误处理、性能设计共8个章节 +- **涉及文件:** docs/detailed-design/02-orchestrator-db.md +- **使用模型:** deepseek + +### 2026-08-22 17:30:00 - 文档 +- **范式步骤:** 详细设计文档编写 +- **修改摘要:** 创建编译运行引擎 (runners) 的详细设计文档,包含模块概述、文件清单、接口定义(3个Runner+DataWriter)、编译流程(COBOL/DB COBOL/Java)、运行流程(stdin管道/文件I/O/Spark)、错误处理、设计特点、依赖关系共8个章节 +- **涉及文件:** docs/detailed-design/03-runners.md +- **使用模型:** deepseek + +### 2026-08-22 21:00:00 - 文档阶段 +- **范式步骤:** LLM代理模块、比对模块、配置系统详细设计文档编写 +- **修改摘要:** 创建三个详细设计文档:05-agents-llm.md(LLM代理模块,包含Agent1/2/3、DesignDataGenerator、LLMClient等6个组件)、06-comparator.md(比对模块,包含记录对齐、二进制读取、数据标准化、字段比对、舍入检测5个组件)、07-config-system.md(配置系统,包含两级配置体系、TOML/YAML加载、程序Schema定义) +- **涉及文件:** `docs/detailed-design/05-agents-llm.md`, `docs/detailed-design/06-comparator.md`, `docs/detailed-design/07-config-system.md` +- **使用模型:** deepseek + +### 2026-08-22 20:00:00 - 文档 +- **范式步骤:** 编写详细设计文档 08-data-flow.md +- **修改摘要:** 创建 COBOL 迁移验证平台 V3 数据流设计文档,覆盖非DB管道和DB管道的完整数据流、核心数据结构、Mermaid 流程图、跨模块数据传递关系 +- **涉及文件:** docs/detailed-design/08-data-flow.md +- **使用模型:** deepseek diff --git a/docs/detailed-design/00-overview.md b/docs/detailed-design/00-overview.md new file mode 100644 index 0000000..520026d --- /dev/null +++ b/docs/detailed-design/00-overview.md @@ -0,0 +1,324 @@ +# V3系统总体设计 + +> 版本: v1.0 | 日期: 2026-08-22 +> 本文档描述COBOL迁移验证平台V3的总体架构和模块设计。 + +--- + +## 一、系统概述 + +### 1.1 系统定位 + +COBOL迁移验证平台V3是一个AI辅助的自动化测试工具,用于验证COBOL程序向Java/Spark迁移的正确性。 + +### 1.2 核心能力 + +| 能力 | 说明 | +|------|------| +| COBOL源码解析 | 自动解析DATA DIVISION和PROCEDURE DIVISION | +| 测试数据生成 | 基于分支覆盖的测试数据自动生成 | +| 双管道验证 | 支持非DB(flat file)和DB(SQLite)两种验证模式 | +| 覆盖率分析 | 静态分支覆盖 + 动态gcov覆盖 | +| AI辅助 | LLM驱动的程序分类和测试策略生成 | + +### 1.3 技术栈 + +| 组件 | 技术 | +|------|------| +| 语言 | Python 3.12+ | +| 解析器 | Lark (Earley parser) | +| COBOL编译 | GnuCOBOL 3.2.0 | +| DB管道 | gixsql + SQLite | +| AI模型 | DeepSeek | +| 测试框架 | pytest | + +--- + +## 二、系统架构 + +### 2.1 架构图 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ V3系统架构 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ CLI入口 │ │ Web界面 │ │ API接口 │ │ +│ │ main.py │ │ web/ │ │ __init__ │ │ +│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ +│ │ │ │ │ +│ └────────────────────┼────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ 编排层 (Orchestrator) │ │ +│ │ orchestrator.py (非DB) orchestrator_db.py (DB) │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌────────────────────┼────────────────────┐ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ 核心引擎 │ │ 运行引擎 │ │ AI代理 │ │ +│ │ cobol_testgen│ │ runners/ │ │ agents/ │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ │ │ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ 比对模块 │ │ 报告模块 │ │ 配置模块 │ │ +│ │ comparator/ │ │ report/ │ │ config/ │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 2.2 分层架构 + +| 层级 | 模块 | 职责 | +|------|------|------| +| **L1 数据层** | data/ | 共享数据模型 | +| **L2 核心层** | cobol_testgen/, config/ | COBOL解析、配置管理 | +| **L3 业务层** | hina/, agents/, comparator/ | 分类、AI代理、比对 | +| **L4 编排层** | orchestrator*, runners/ | 流程编排、执行 | +| **L5 接口层** | main.py, web/, __init__.py | 用户接口 | + +--- + +## 三、模块清单 + +### 3.1 核心模块 + +| 模块 | 文件数 | 行数 | 职责 | +|------|--------|------|------| +| cobol_testgen/ | 22 | ~8000 | COBOL解析、测试数据生成 | +| orchestrator_db.py | 1 | 1334 | DB管道6步编排 | +| runners/ | 8 | ~600 | 编译运行引擎 | +| hina/ | 11 | ~2000 | HINA程序分类 | +| agents/ | 6 | ~800 | LLM代理 | +| comparator/ | 6 | ~400 | 字段比对 | +| config/ | 5 | ~300 | 配置管理 | +| report/ | 1 | ~200 | 报告生成 | + +### 3.2 模块依赖关系 + +``` +models.py (零依赖) + │ + ├── read.py (lark) + ├── cond.py (stdlib) + ├── core.py (cond) + ├── design.py (models, cond, core) + ├── coverage.py (models, cond) + ├── output.py (file_io) + ├── to_sql.py (stdlib) + ├── runner.py (file_io) + ├── flatfile.py (read, file_io) + │ + └── __init__.py (所有上层模块) +``` + +--- + +## 四、数据流 + +### 4.1 非DB管道数据流 + +``` +COBOL源码 + │ + ▼ +read.py: preprocess() + parse_data_division() + │ + ▼ +core.py: build_branch_tree() + │ + ▼ +design.py: enum_paths() + generate_records() + │ + ▼ +output.py: output_json() + output_input_files() + │ + ▼ +runners/cobol_runner.py: compile() + run() + │ + ▼ +comparator/: compare_field() + │ + ▼ +report/generator.py: generate_report() +``` + +### 4.2 DB管道数据流 + +``` +COBOL源码 (含EXEC SQL) + │ + ▼ +gixsql_runner.py: preprocess() + compile() + │ + ▼ +orchestrator_db.py: step2_generate_inputs() + │ + ├── cobol_testgen: extract_structure + generate_data + ├── to_sql.py: build_db_input() + └── flatfile.py: write_all_files() + │ + ▼ +orchestrator_db.py: step3_run_cobol() + │ + ▼ +orchestrator_db.py: step4_extract_intermediate() + │ + ▼ +orchestrator_db.py: step5_run_java() (可选) + │ + ▼ +orchestrator_db.py: step6_verify() +``` + +--- + +## 五、接口设计 + +### 5.1 公开API + +```python +# cobol_testgen/__init__.py + +def extract_structure( + cobol_source: str, + copybook_dirs: list[str] = None +) -> dict: + """解析COBOL源码,返回结构信息""" + pass + +def generate_data( + cobol_source: str, + structure: dict, + copybook_dirs: list[str] = None +) -> list[dict]: + """生成分支覆盖测试数据""" + pass + +def main(): + """CLI入口""" + pass +``` + +### 5.2 配置接口 + +```python +# config/__init__.py + +@dataclass +class Config: + """全局配置""" + project_name: str + copybook_paths: list[str] + dialect: str + llm_model: str + gcov_enabled: bool + # ... 更多字段 +``` + +--- + +## 六、错误处理 + +### 6.1 错误分类 + +| 类别 | 示例 | 处理策略 | +|------|------|----------| +| 解析错误 | COBOL语法不合法 | 抛出异常,返回错误信息 | +| 编译错误 | cobc编译失败 | 记录日志,跳过该程序 | +| 运行错误 | 程序执行异常 | 捕获异常,标记失败 | +| 超时错误 | 执行超时 | 强制终止,记录超时 | + +### 6.2 容错机制 + +- **解析器超时**:pipeline_bridge 3秒超时回退 +- **LLM失败**:回退到规则引擎 +- **gcov失败**:跳过覆盖率收集 +- **DB连接失败**:重试或跳过 + +--- + +## 七、性能设计 + +### 7.1 性能指标 + +| 指标 | 目标 | +|------|------| +| 单程序解析 | < 5秒 | +| 测试数据生成 | < 30秒 | +| 编译运行 | < 60秒 | +| 覆盖率报告 | < 10秒 | + +### 7.2 优化策略 + +- **路径枚举**:O(N)线性算法替代O(2^N) +- **并行执行**:多场景gcov并行收集 +- **缓存机制**:LLM结果缓存 +- **增量补充**:质量门循环最多4次 + +--- + +## 八、安全设计 + +### 8.1 输入验证 + +- COBOL源码:长度限制、编码检查 +- 配置文件:YAML schema验证 +- 文件路径:路径遍历防护 + +### 8.2 资源限制 + +- LLM调用:最大成本限制 +- 执行时间:超时强制终止 +- 内存使用:大文件分块处理 + +--- + +## 九、测试策略 + +### 9.1 测试层次 + +| 层次 | 覆盖率目标 | 工具 | +|------|------------|------| +| 单元测试 | ≥ 90% | pytest | +| 集成测试 | ≥ 80% | pytest | +| 端到端测试 | 100%通过 | 自定义脚本 | + +### 9.2 测试数据 + +- 43个COBOL基准程序 +- 33+2种程序类型 +- 58个电信测试程序 + +--- + +## 十、部署设计 + +### 10.1 运行环境 + +| 组件 | 要求 | +|------|------| +| OS | Windows 10/11 | +| Python | 3.12+ | +| GnuCOBOL | 3.2.0 | +| 磁盘 | ≥ 500MB | + +### 10.2 安装步骤 + +```bash +# 1. 安装Python依赖 +pip install lark pathlib pyyaml + +# 2. 安装GnuCOBOL +# 下载GC32-BDB-SP1,添加到PATH + +# 3. 验证安装 +python -c "from cobol_testgen import extract_structure; print('OK')" +``` diff --git a/docs/detailed-design/01-cobol-testgen-core.md b/docs/detailed-design/01-cobol-testgen-core.md new file mode 100644 index 0000000..b73250a --- /dev/null +++ b/docs/detailed-design/01-cobol-testgen-core.md @@ -0,0 +1,581 @@ +# cobol_testgen 核心引擎模块 - 详细设计文档 + +> 模块路径: `cobol_testgen/` +> 版本: V3 (2026技术大赛) +> 依赖: Python 3.13+, `lark>=1.1.0` + +--- + +## 1. 模块概述 + +### 1.1 职责 + +`cobol_testgen` 是 COBOL 迁移验证平台 V3 的核心引擎, 负责: + +1. **解析** COBOL 源码 (DATA DIVISION + PROCEDURE DIVISION) +2. **构建** 分支控制流树 (Branch Tree) +3. **枚举** 所有可达路径 (路径级约束) +4. **生成** 满足路径约束的测试数据记录 +5. **输出** JSON 格式测试数据 + HTML 覆盖率报告 + +### 1.2 边界 + +| 在范围内 | 不在范围内 | +|---------|-----------| +| COBOL 源码静态分析 | COBOL 程序动态执行 (由 runner.py 调用 GnuCOBOL) | +| 分支树构建 + 路径枚举 | LLM 推理 (由外部 deepseek API 调用) | +| 测试数据值生成 | SQL 数据库操作 (to_sql.py 辅助生成 DB 输入行) | +| JSON/HTML 输出 | IDE 集成、CI/CD 管道 | + +### 1.3 依赖关系 + +``` +cobol_testgen/ + __init__.py <- 公开 API 入口 (main) + models.py <- 共享数据模型 (零外部依赖) + read.py <- INPUT 层: 预处理 + DATA DIVISION 解析 + core.py <- CORE 层: PROCEDURE DIVISION 分支树构建 + procedure_parser.py <- CORE 层: 行级状态机解析器 (新) + pipeline_bridge.py <- CORE 层: 新旧解析器桥接 + cond.py <- CONDITION 层: 条件解析 + MC/DC + design.py <- DESIGN 层: 路径枚举 + 值生成 + design_mcdc.py <- DESIGN 层: O(N) 非爆炸路径枚举 + coverage.py <- COVERAGE 层: 分支覆盖标记 + HTML 报告 + output.py <- OUTPUT 层: JSON 输出 + to_sql.py <- SQL 辅助: WHERE 约束解析 + DB 输入行生成 + flatfile.py <- I/O 辅助: 固定长度平面文件读写 + file_io.py <- I/O 辅助: DISPLAY/COMP/COMP-3 二进制编解码 + runner.py <- 执行层: 编译-执行-验证 (调用 GnuCOBOL) + gcov.py <- 覆盖率辅助: gcov 数据解析 + data_merger.py <- 数据整合: 白盒+机能+策略数据合并 + grammar.lark <- Lark 语法: DATA DIVISION 解析 + procedure_grammar.lark <- Lark 语法: PROCEDURE DIVISION 解析 + __main__.py <- 入口: python -m cobol_testgen +``` + +**外部依赖:** + +| 依赖 | 用途 | +|------|------| +| lark>=1.1.0 | Lark 解析器框架 (Earley parser, dynamic lexer) | +| deepseek API | LLM 路径生成 (可选, 回退到规则引擎) | +| GnuCOBOL (cobc) | COBOL 编译-执行 (runner.py 调用) | +| gcov | 代码覆盖率采集 (gcov.py 调用) | + +--- + +## 2. 文件清单 + +| 文件 | 行数 | 职责 | +|------|------|------| +| `__init__.py` | 2189 | 公开 API 入口、OCCURS 展开、PREV 连锁、跨文件键值协调、MERGE/SORT/LINAGE 注入、子程序输入供给 | +| `__main__.py` | 3 | python -m cobol_testgen 入口 | +| `models.py` | 118 | 共享数据模型: PicInfo, FieldDef, BrSeq, BrIf, BrEval, BrPerform, BrSearch, CondLeaf, Assign, CallNode, ExitNode, GoTo, ParseError, ProcParseResult | +| `read.py` | 644 | COBOL 源码预处理 (fixed/free format)、COPYBOOK 展开、DATA DIVISION 解析 (Lark grammar.lark)、FILE-CONTROL 解析、OPEN 语句扫描 | +| `core.py` | 2137 | PROCEDURE DIVISION 分支树构建 (_BrParser 类)、段落扫描、赋值追踪、SQL 虚拟字段注册、算术表达式解析、EVALUATE/PERFORM/SEARCH/READ/WRITE 解析 | +| `procedure_parser.py` | 527 | 新版行级状态机解析器 (Tier 1: 状态机提取嵌套结构, Tier 2: 规则条件解析) | +| `pipeline_bridge.py` | 225 | 新旧解析器桥接: 新解析器优先, 旧解析器 3s 超时回退 | +| `cond.py` | 497 | COBOL 条件表达式解析 (AND/OR/NOT/括号)、MC/DC 约束集生成 (mcdc_sets)、满足值计算 (satisfying_value) | +| `design.py` | 2014 | 路径枚举 (enum_paths)、基础记录生成 (make_base_record)、约束应用 (apply_constraint)、赋值传播 (propagate_assignments)、链追溯 (trace_to_root) | +| `design_mcdc.py` | 409 | O(N) 非爆炸路径枚举: 每个决策点生成 T/F 两条路径, 保证全覆盖无指数爆炸 | +| `coverage.py` | 1451 | 决策点收集 (collect_decision_points)、分支覆盖标记 (mark_coverage)、中文 HTML 报告生成 | +| `output.py` | 184 | JSON 输出: 按 FD 分组 input/expected_output/working_storage | +| `to_sql.py` | 948 | SQL 元数据提取 (collect_sql_meta)、WHERE 宿主变量 MOVE 链解析、DB 输入行生成 (build_db_input) | +| `flatfile.py` | 309 | 平面文件 I/O: FD 布局分析 (analyze_fd_layout)、固定长度记录读写 | +| `file_io.py` | 234 | 二进制编解码: DISPLAY/COMP/COMP-3 pack/unpack、RECORDING MODE V 处理 | +| `runner.py` | 516 | 编译-执行-验证: GnuCOBOL cobc 调用、字段对比、分组执行 | +| `gcov.py` | 165 | gcov 覆盖率数据解析 (.cbl.gcov -> {行号: 执行次数}) | +| `data_merger.py` | 130 | 数据整合: 白盒 (MC/DC) + 机能 (LLM) + 策略 (HINA 分类) 数据合并去重 | +| `grammar.lark` | 40 | Lark 语法: DATA DIVISION 解析 | +| `procedure_grammar.lark` | 203 | Lark 语法: PROCEDURE DIVISION 解析 | + +--- +--- + +## 3. 核心数据结构 + +所有模型定义在 `models.py` (118 行), 无外部依赖。 + +### 3.1 字段定义 + +```python +@dataclass +class PicInfo: + type: str = 'unknown' # "numeric" | "alphanumeric" | "alphabetic" + digits: int = 0 # 整数位数 (如 9(7) -> 7) + decimal: int = 0 # 小数位数 (如 V99 -> 2) + length: int = 0 # 总长度 (alphanumeric 用) + signed: bool = False # 是否有符号 + +@dataclass +class FieldDef: + name: str # 字段名 (大写) + level: int # 层号 (01, 05, 77, 88 等) + pic: str | None = None # PIC 子句原始文本 + pic_info: PicInfo | None = None + is_filler: bool = False + occurs_count: int = 0 + occurs_depending: str | None = None + redefines: str | None = None + usage: str | None = None # "COMP" | "COMP-3" | "BINARY" | "DISPLAY" + value: str | None = None + values: list[str] | None = None # 88 级多值 + is_88: bool = False + parent: str | None = None + section: str | None = None +``` + +### 3.2 分支树节点 + +```python +class BrSeq: # 顺序语句序列 (容器节点) + children = [] # BrIf | BrEval | BrPerform | BrSearch | Assign | ... + +class BrIf: # IF 条件分支 + condition # 条件原文 + cond_tree = None # 条件树 (core.py 解析时赋值) + true_seq # THEN 分支 + false_seq # ELSE 分支 + +class BrEval: # EVALUATE 多分支 + subject # 主体 + subjects = [] # ALSO 多主体 + when_list = [] # [(condition_text, BrSeq)] + other_seq # WHEN OTHER + has_other = False + +class BrPerform: # PERFORM 循环/调用 + perf_type # "until" | "varying" | "times" | "para" | "sort" + condition # UNTIL 条件 + body_seq # 循环体 + +class BrSearch: # SEARCH 表查找 + table_name, is_all, at_end_seq, when_list, has_at_end +``` + +### 3.3 条件树 + +```python +class CondLeaf: field, op, value # 叶条件 +class CondNot: child # NOT 取反 +class CondAnd: left, right # AND +class CondOr: left, right # OR +``` + +### 3.4 其他节点 + +```python +class Assign: target, source_info # 赋值 (MOVE/COMPUTE/READ INTO/WRITE FROM) +class CallNode: program_name, using_params # CALL 子程序 +class GoTo: target, body_seq # GO TO 跳转 +class ExitNode: exit_type # EXIT 退出 +``` + +### 3.5 约束与路径 + +```python +Constraint = tuple # (field, op, value, want_true) +Path = list[Constraint] + +class ParseError: line, message, severity +class ProcParseResult: tree, assignments, errors, fallback_to_ai +``` + +--- + +## 4. 解析流程 + +### 4.1 源码预处理 (read.py) + +入口: `preprocess(source, extra_search_paths)` + +1. COPYBOOK 展开 -> EXEC SQL/CICS 移除 -> VALUE 逗号清理 +2. & 连接行合并 -> PIC 小数点转换 -> 格式检测 (fixed/free) +3. 注释移除 -> 续行合并 + +### 4.2 DATA DIVISION 解析 (read.py) + +使用 `grammar.lark` (Lark Earley parser)。关键: Earley parser 处理歧义语法, 命名终端 USAGE_VAL 避免 Lark 过滤 tree children。 + +### 4.3 PROCEDURE DIVISION 分支树 (core.py) + +入口: `build_branch_tree(proc_text, fields, full_source)` + +段落扫描 (`scan_paragraphs`) -> 分支解析 (`_BrParser` 递归下降) -> 赋值追踪 (`assignments` 字典)。 + +### 4.4 新版解析器 (procedure_parser.py + pipeline_bridge.py) + +Tier 1: 行级状态机提取嵌套结构 -> Tier 2: 规则条件解析。桥接: 新解析器优先, 旧解析器 3s 超时回退。 + +--- + +## 5. 分支树构建细节 (core.py) + +### 5.1 流程 + +``` +输入: proc_text, fields +1. raw_lines = proc_text.split('\n') +2. blocked_names = 收集数据名, 阻止误匹配段落名 +3. paragraphs = scan_paragraphs(raw_lines, blocked_names) +4. parser = _BrParser(filtered, paragraphs, raw_lines, assignments, fields) +5. tree = parser.parse_seq(terminators={'GOBACK', 'STOP RUN', 'EXIT PROGRAM'}) +``` + +### 5.2 _BrParser 支持的语句 + +IF -> EVALUATE -> PERFORM -> SEARCH -> READ/WRITE -> CALL -> GO TO -> MOVE/COMPUTE/ADD/SUBTRACT/MULTIPLY/DIVIDE -> SORT/MERGE -> EXEC SQL -> INITIALIZE -> STRING/UNSTRING + +### 5.3 IF 解析 + +提取条件 -> parse_compound_condition -> 递归 parse_seq (THEN) -> 递归 parse_seq (ELSE) -> 消费 END-IF -> 返回 BrIf + cond_tree + +### 5.4 EVALUATE 解析 + +提取主体 -> 检测 ALSO -> 循环解析 WHEN (条件 + 递归体) -> WHEN OTHER -> 返回 BrEval + +--- + +## 6. 条件解析 (cond.py) + +### 6.1 单条件 (parse_single_condition) + +| 模式 | 示例 | 返回 | +|------|------|------| +| 标准比较 | `AMOUNT > 1000` | `('AMOUNT', '>', '1000')` | +| 88 级 | `STATUS-APPROVED` | `(parent, '=', value)` | +| NOT | `X NOT = 5` | `('X', '<>', '5')` | +| 裸字段 | `WS-EOF` | `('WS-EOF', '=', 'Y')` | +| SQLCODE | `SQLCODE = 100` | `('SQLCODE', '=', '100')` | +| Class | `WS-KEY IS NUMERIC` | `('WS-KEY', 'IS', 'NUMERIC', True)` | +| FUNCTION | `FUNCTION MOD(X,2) NOT = 0` | `('_FUNC_MOD', '<>', '0')` | + +### 6.2 复合条件 (parse_compound_condition) + +构建 CondAnd/CondOr/CondNot/CondLeaf 树。优先级: AND > OR。 + +### 6.3 MC/DC (mcdc_sets) + +为复合条件生成 Modified Condition/Decision Coverage 约束集。每个条件独立影响决策。 + +### 6.4 满足值 (satisfying_value) + +数值: 边界值 (val-1, val, val+1)。字母数字: 字符级增减。Class: 匹配/不匹配类型值。 +--- + +## 7. 路径枚举 (design.py) + +### 7.1 核心算法 (enum_paths) + +入口: `enum_paths(node, fields)` -> `list[(constraints, assignments)]` + +| 节点类型 | 路径生成 | +|---------|---------| +| Assign | 单路径, 空约束 + 赋值 | +| BrSeq | 子路径笛卡尔积 + 去重 | +| BrIf | True 分支 + False 分支 两组路径 | +| BrEval | 每个 WHEN 一条路径 + OTHER (EVALUATE TRUE 用 MC/DC) | +| BrPerform | Enter + Skip 两条路径 | +| BrSearch | 每个 WHEN + AT END | +| CallNode | 黑盒: 单路径 | + +**BrIf 简单条件:** +``` +true_sub = enum_paths(true_seq) +false_sub = enum_paths(false_seq) +result = [(field, op, val, True) + sp for sp in true_sub] + + [(field, op, val, False) + sp for sp in false_sub] +``` + +**BrIf 复合条件:** +``` +sets = mcdc_sets(cond_tree, fields) +for constraints, decision in sets: + body = enum_paths(true_seq if decision else false_seq) + result.append(constraints + body) +``` + +### 7.2 路径截断 (_cap_paths) + +最大 50,000 条路径 (`_MAX_PATHS`)。公平截断: +- Phase 1: 每个前置路径至少保留一条子路径 +- Phase 2: 用剩余配额填充未覆盖分支 +- 哨兵路径 (STOP/ABEND) 始终保留 + +### 7.3 EVALUATE TRUE 特殊处理 (eval_true_branch_constraints) + +- 每个 WHEN 解析为复合条件 +- MC/DC 集合为每个 WHEN 生成 +- `prior_false` 累积所有前序 WHEN 的 false 集 (笛卡尔积) +- 每个 True 路径与所有可能的 prior-false 组合配对 + +--- + +## 8. 值生成 (design.py) + +### 8.1 基础记录生成 (make_base_record) + +入口: `make_base_record(seq_num, fields)` -> `dict` + +1. 遍历所有字段: + - VALUE 子句 -> `_apply_value` 初始值 + - 数值字段 -> `_make_numeric_value` 序列值 + - 字母字段 -> `_make_alpha_value` 序列值 + - 日期字段 -> `seq_date` +2. REDEFINES: 父字段值复制到重定义字段 +3. 组 REDEFINES: 按位置递归复制子字段 +4. 跨 FD 字段对齐: 同名不同前缀的数值字段共享 index + +### 8.2 约束应用 (apply_constraint) + +入口: `apply_constraint(rec, field, op, value, want_true, fields, ...)` + +处理管线: +1. 变量下标解析: `WS-FIXED-VALUE(WS-IDX)` -> 具体下标 +2. 下标传播: 裸字段名应用到所有下标变体 +3. REDEFINES 重定向: 约束转到父字段 (共享存储) +4. 组字段展开: 组比较分解为子字段约束 +5. Class 条件: `IS NUMERIC/ALPHABETIC` 通过 satisfying_value 处理 +6. 字母比较: 字符级边界值 +7. 数值比较: 整数边界值 +8. 算术表达式: 启发式 steering +9. 零保护: 防止零值字段在 False 分支取最小值 +10. 字段间协调: `WS-A >= WS-B` 同时设置两个字段 + +### 8.3 赋值传播 (propagate_assignments) + +模拟程序数据流到每个决策点: + +| Pass | 操作 | +|------|------| +| 1 | MOVE 传播 (源复制到目标) | +| 2 | COMPUTE 求值 (算术表达式) | +| 3 | ADD/SUBTRACT/MULTIPLY/DIVIDE | +| 3.5 | READ INTO (文件读到工作存储) | +| 4 | UNSTRING 分割 | +| 5 | INITIALIZE (填充零/空格) | +| 6 | STRING 拼接 | +| 7 | SET TO FALSE (88 级条件名) | + +### 8.4 链追溯 (trace_to_root) + +沿 MOVE/COMPUTE 链回溯到源字段。返回 `(root_field, chain_of_assignments)`。用于检测不可能路径 (字面量 MOVE 与约束矛盾)。 + +--- + +## 9. 覆盖率分析 (coverage.py) + +### 9.1 决策点收集 (collect_decision_points) + +| 节点 | 决策点 | +|------|-------| +| BrIf | kind="IF", branches=["T", "F"], label=条件 | +| BrEval | kind="EVALUATE", branches=["WHEN ...", "OTHER"] | +| BrPerform | kind="PERFORM", branches=["Enter", "Skip"] | +| BrSearch | kind="SEARCH", branches=["WHEN ...", "AT END"] | + +每个决策点包含: +- `id`: 自增编号 +- `cond_tree`: 复合条件树 (用于 evaluate_tree) +- `cond_leaves`: 叶条件列表 (用于 _match_leaf) +- `active_branches`: 已覆盖的分支集合 +- `implied_branches`: 推断的覆盖分支 + +### 9.2 分支覆盖标记 (mark_coverage) + +对每条路径的约束列表, 逐个决策点匹配: + +**IF 标记** (`_mark_if`): +- 简单条件: 匹配 (field, op, value) 确定 T/F 分支 +- 复合条件: 构建 leaf->bool assignment, 用 evaluate_tree 求值 +- 合成函数 (_FUNC_*): 全部标记覆盖 + +**EVALUATE 标记** (`_mark_eval`): +- 简单: 匹配 subject 值确定 WHEN 分支 +- EVALUATE TRUE: prior_false 累积 + 逐 WHEN 匹配 + +**PERFORM 标记** (`_mark_perform`): +- 条件为真 -> Enter, 条件为假 -> Skip + +**叶条件标记** (`_match_leaf`): +- 去除下标后匹配 field + op + value +- covered_true / covered_false 独立追踪 + +### 9.3 HTML 报告生成 + +`generate_coverage_index()`: 中文 HTML 报告, 包含: +- 覆盖率统计 (总分支数 / 已覆盖 / 未覆盖) +- 每个决策点的覆盖状态 (badge: 覆盖/未覆盖) +- 叶条件级别的 MC/DC 覆盖详情 +--- + +## 10. 输出生成 (output.py) + +### 10.1 JSON 输出 (output_json) + +入口: `output_json(records, outpath, roles, fd_fields, field_to_fd, open_dir, term_types, db_input, data_fields)` + +**输出格式:** + +```json +{ + "program": "程序名", + "records": [ + { + "input": { "R01EMP-ID": "A0000001", ... }, + "expected_output": { "W01RESULT": "PASS", ... }, + "working_storage": { "WS-COUNT": "003", ... }, + "termination": "normal" + } + ], + "db_input": { ... } +} +``` + +**字段分组逻辑:** +- `input`: 方向为 INPUT/I-O 的 FD, 角色为 input/inout 的字段 +- `expected_output`: 方向为 OUTPUT/I-O 的 FD, 角色为 output/inout 的字段 +- `working_storage`: 不属于任何 FD 的字段 +- 未分配字段 (`_assigned_fields` 集合) 的归属判定 + +### 10.2 平面文件输出 (output_input_files) + +将 JSON 记录写入 COBOL 输入文件 (固定长度/行顺序)。支持: +- DISPLAY 格式 (文本) +- COMP/COMP-3 格式 (二进制打包) +- RECORDING MODE V (变长记录, 4 字节 RDW 前缀) + +--- + +## 11. 接口定义 + +### 11.1 公开 API (__init__.py) + +```python +def extract_structure(source: str, ...) -> dict: + """解析 COBOL 控制流 -> dict (字段定义、分支树、赋值)""" + +def generate_data(source: str, ...) -> list[dict]: + """生成测试数据 -> list[dict] (每条路径一条记录)""" + +def incremental_supplement(...) -> list[dict]: + """差分补充数据 -> list[dict]""" +``` + +### 11.2 核心模块 API + +**read.py:** +```python +def preprocess(source: str, extra_search_paths: list[str] = None) -> str +def extract_data_division(source: str) -> str +def extract_procedure_division(source: str) -> str +def parse_data_division(dd_text: str) -> list[FieldDef] +def parse_file_section(source: str) -> dict +def parse_file_control(source: str) -> dict +def scan_open_statements(source: str) -> dict +def scan_all_file_directions(source: str) -> dict +def resolve_copybooks(source: str, base_dir: str, ...) -> str +def resolve_sql_includes(source: str) -> str +``` + +**core.py:** +```python +def build_branch_tree(proc_text: str, fields: list, full_source: str = None) -> (BrSeq, dict) +def scan_paragraphs(raw_lines: list, blocked_names: set = None) -> dict +def sql_register_virtual_fields(fields_dict: list[dict]) -> list[dict] +def classify_field_roles(fields, assignments, file_sec, ...) -> dict +``` + +**cond.py:** +```python +def parse_single_condition(text: str, fields: list = None) -> tuple | None +def parse_compound_condition(text: str, fields: list = None) -> CondAnd | CondOr | CondLeaf | CondNot | None +def collect_leaves(tree) -> list[CondLeaf] +def evaluate_tree(tree, assignment: dict) -> bool +def is_field(name: str, fields: list) -> bool +def mcdc_sets(tree, fields: list = None) -> list | None +def satisfying_value(pic_info: dict, op: str, value: str, want_true: bool) -> str +def merge_field_constraints(cons_list: list) -> list +``` + +**design.py:** +```python +def enum_paths(node, fields: list) -> list[(list, dict)] +def make_base_record(seq_num: int, fields: list) -> dict +def apply_constraint(rec: dict, field_name: str, op: str, value: str, want_true: bool, fields: list, ...) -> None +def propagate_assignments(rec: dict, assignments: dict, fields: list, ...) -> None +def trace_to_root(field: str, assignments: dict, fields: list, path_assign: dict) -> (str, list) +def generate_records(path_infos: list, data_fields: list, ...) -> (list, list, list) +def get_term_type(cons: list) -> (list, str) +def extend_abend_programs(names: list[str]) -> None +``` + +**coverage.py:** +```python +def collect_decision_points(node, fields: list) -> (list[DecisionPoint], list[LeafStat]) +def mark_coverage(decision_points: list, leaf_stats: list, branch_paths: list, fields: list) -> None +def run_coverage(source: str, records: list, ...) -> dict +def generate_coverage_index(...) -> str # HTML string +``` + +**output.py:** +```python +def output_json(records: list, outpath: Path, ...) -> None +def output_input_files(records: list, outpath: Path, ...) -> None +``` + +**to_sql.py:** +```python +def collect_sql_meta(source: str, fields: list) -> list[dict] +def build_db_input(sql_meta: list, records: list, ...) -> dict +``` + +**flatfile.py:** +```python +def analyze_fd_layout(source_text: str, ...) -> dict[str, dict] +def write_flat_file(records: list, layout: dict, outpath: Path) -> None +``` + +--- + +## 12. 错误处理 + +### 12.1 解析错误 (ParseError) + +`models.py` 定义 `ParseError` 数据类: +- `line: int` -- 错误所在行号 +- `message: str` -- 错误描述 +- `severity: str` -- 'warning' 或 'error' + +`ProcParseResult.errors` 收集解析过程中产生的所有错误。 + +### 12.2 处理策略 + +| 错误类型 | 处理方式 | +|---------|---------| +| COPYBOOK 找不到 | 跳过该 COPY, 继续解析, 记录 warning | +| Lark 语法不匹配 | 回退到规则引擎, 标记 `fallback_to_ai=True` | +| 未知 COBOL 语句 | 跳过该行, 不中断解析 | +| 字段未找到 | 使用默认值, 记录 debug 日志 | +| 条件解析失败 | 返回 None, 由上层决定回退策略 | +| 路径枚举超过上限 | `_cap_paths` 公平截断到 50,000 条 | +| 新解析器超时/失败 | `pipeline_bridge` 回退到旧解析器 (3s 超时) | +| 旧解析器超时/失败 | 返回空 BrSeq + 空 assignments | +| gcov 执行失败 | 返回空 dict, 跳过覆盖率标记 | +| 外部调用异常 | try/except 捕获, logger.warning 记录, 不中断主流程 | + +### 12.3 日志策略 + +所有模块使用 Python `logging`: +- `logger.info()` -- 关键流程节点 (解析开始/结束, 路径数, 记录数) +- `logger.debug()` -- 详细调试信息 (约束应用, 赋值传播) +- `logger.warning()` -- 非致命错误 (解析失败, 回退) +- `logger.error()` -- 致命错误 (不应发生) + +### 12.4 已知限制 + +1. **MC/DC 复合 IF bug**: `merge_field_constraints` 合并同字段约束会破坏 `_match_leaf` 匹配 +2. **OCCURS DEPENDING ON**: 捕获但未用于记录生成 +3. **88 级 VALUE**: 目标程序无 88 级 VALUE 子句, 解析器不依赖此特性 +4. **路径多样性丢失**: 规则引擎 100 路径限制 (LLM 模式 50000 路径不受影响) +5. **合成函数字段**: `_FUNC_MOD` 等合成名 is_field 返回 False, 叶条件不可匹配 diff --git a/docs/detailed-design/02-orchestrator-db.md b/docs/detailed-design/02-orchestrator-db.md new file mode 100644 index 0000000..741c9ab --- /dev/null +++ b/docs/detailed-design/02-orchestrator-db.md @@ -0,0 +1,574 @@ +# DB 管道编排器 - 详细设计文档 + +> 模块路径: `orchestrator_db.py` +> 版本: V3 (2026技术大赛) +> 行数: 1973 +> 核心类: `GixsqlOrchestrator` + +--- + +## 1. 模块概述 + +### 1.1 职责 + +`orchestrator_db.py` 是 DB 型 COBOL 程序的 6 步端到端测试管道编排器,负责: + +1. **环境整备** - gixpp 预处理 + cobc 编译(Step 1) +2. **输入数据生成** - 测试数据生成 + 平面文件输出 + DB 初始化(Step 2) +3. **COBOL 执行** - 调用编译后的 COBOL 程序(Step 3) +4. **中间数据提取** - SQLite DB → Java 中介 JSON(Step 4) +5. **Java 执行** - 调用 Java 转换程序(Step 5) +6. **结果验证** - Java 输出与 COBOL 期望值比较(Step 6) + +### 1.2 边界 + +| 在范围内 | 不在范围内 | +|---------|-----------| +| DB 型 COBOL 程序 6 步管道编排 | Flat-file 型 COBOL 程序处理 | +| SQLite 数据库初始化与种子注入 | 分支树构建(由 cobol_testgen/ 处理) | +| 多场景(多轮)执行调度 | 覆盖率报告生成(可选附件,非管道核心) | +| 测试数据合成与 PK 冲突注入 | Java 程序内部逻辑 | + +### 1.3 依赖关系 + +``` +orchestrator_db.py + +-- config.py <- 项目配置 + +-- config/program_schema.py <- YAML 程序定义 + +-- cobol_testgen/ <- 核心引擎 + +-- data/diff_result.py <- 验证结果数据模型 + +-- runners/gixsql_runner.py <- GnuCOBOL 编译-执行运行器 + +-- agents/llm.py <- LLM 客户端(可选) +``` + +--- + +## 2. 核心数据结构 + +### 2.1 GixsqlOrchestrator + +```python +class GixsqlOrchestrator: + def __init__(self, config: Config, program_id: str, + cobol_src_dir: str | Path, + copybook_dirs: list[str | Path] | None = None, + work_dir: str | Path | None = None, + skip_jvm: bool = True): +``` + +**关键属性:** + +| 属性 | 类型 | 说明 | +|------|------|------| +| config | Config | 项目配置 | +| program_id | str | COBOL 程序标识符 | +| cobol_src_dir | Path | COBOL 源码目录 | +| copybook_dirs | list[Path] | COPYBOOK 搜索路径 | +| work_dir | Path | 构建产物目录(ASCII 路径) | +| runtime_dir | Path | 运行时数据目录 | +| schema | ProgramSchema | YAML 程序定义 | +| runner | GixsqlCobolRunner | GnuCOBOL 运行器 | +| db_path | Path | 默认 SQLite DB 路径 | +| skip_jvm | bool | 是否跳过 Step 5/6 | + +**管道状态:** + +| 状态属性 | 类型 | 说明 | +|----------|------|------| +| src_path | Path | 预处理后源码路径 | +| pp_path | Path | gixpp 预处理输出路径 | +| exe_path | Path | 编译后可执行文件路径 | +| java_input_path | Path | Java 中介数据路径 | +| java_output_path | Path | Java 输出路径 | +| _current_db_path | Path | 当前场景的 DB 路径 | +| _multi_run_gcov_data | dict | 多轮合并后的 gcov 数据 | +| generated_records | list[dict] | 生成的测试数据记录 | +| generated_structure | dict | 解析后的程序结构 | + +### 2.2 DbPipelineResult + +```python +@dataclass +class DbPipelineResult: + program_id: str + step: int | float + success: bool + message: str = "" + data: dict = field(default_factory=dict) +``` + +--- + +## 3. 6 步流程设计 + +### 3.1 Step 1: 环境整备 (step1_setup_environment) + +**职责:** gixpp 预处理 → cobc 编译 + +**执行流程:** + +``` +1. _copy_sources_to_workdir() + |-- 复制主源码 {program_id}.cbl → work_dir/src/ + |-- 复制 COPYBOOK (*.cpy) → work_dir/src/ + |-- 复制子程序 (SUB*.cbl) → work_dir/src/ + (搜索: cobol_src_dir, sub/, production/sub/, cobol-tna-system/sub/) + +2. runner.preprocess(src, preprocessed/, copybook_dirs) + |-- gixpp 预处理 + CONNECT TO 路径修补 + | gixpp 错误转换: 'data/kin.db' → 'sqlite://localhost/kin' + | 修补为: 'sqlite:///{db_path}' + +3. runner.compile(pp, exe, copybook_dirs, extra_srcs) + |-- cobc 编译 → work_dir/bin/{program_id}.exe + |-- 编译日志写入 runtime_dir/logs/compile/ + +4. 返回 DbPipelineResult(step=1, success, data={exe_path, log}) +``` + +**关键逻辑:** +- 源码必须复制到 ASCII-only 路径(gixpp 不支持中文路径) +- CONNECT TO 字符串修补: gixpp 输出的 `sqlite://localhost/kin` 需替换为绝对路径 +- 子程序从多个候选目录搜索,未找到仅 warning 不阻断 + +**输入:** cobol_src_dir, copybook_dirs, schema.subprograms +**输出:** src_path, pp_path, exe_path + +### 3.2 Step 2: 输入数据生成 (step2_generate_inputs) + +**职责:** COBOL 解析 → 测试数据生成 → DB 初始化 → 平面文件输出 + +**执行流程:** + +``` +1. COBOL 解析 + |-- extract_structure(src_text) → 分支树 + 赋值表 + |-- generate_all_data() → 测试数据记录(白盒+机能+策略) + |-- 后处理: R02APPL-ID 链接 R01APPL-ID + +2. DB 初始化 + |-- 确定 DB 路径(场景分离: {program_id}_{scenario_id}.db) + |-- 清理旧 DB → _init_database(db_path) + | |-- _create_tables(): 按 YAML schema 创建表 + 主键 + |-- _populate_database(): 注入种子行 + | |-- 解析 COBOL → 分支树 → 路径枚举 + | |-- build_db_input(): 生成 DB 输入行 + | |-- 覆盖率驱动数据补充(日期、假期等) + | |-- 区间协调(INSURANCE-RATES / EMP-MASTER) + | |-- INSERT OR IGNORE 写入 DB + |-- _inject_extra_seed_rows(): 大结果集注入 + |-- _inject_sql_error_rows(): PK 冲突行注入 + +3. 记录修补 + |-- records[0].R01EMP-ID = SPACE(触发空社员路径) + |-- 全零 EMP-ID → SPACE 清洗 + |-- R01LINE 与 EMP-ID 一致性修补 + |-- 注入重复 EMP-ID(AGG UPDATE 路径) + |-- _deduplicate_r01_pk(): PK 去重 + |-- _inject_aggregation_boundaries(): 聚合边界数据 + +4. 场景驱动修改 + |-- collision 场景: INSERT 重复、OVT-MONTHLY 匹配、COMMIT 阈值 + |-- abnormal 场景: orphan cancel ABEND + +5. 平面文件输出 + |-- write_all_files(): 全 FD 平面文件 + |-- write_sysin_file(): SYSIN 配置 + |-- _seed_matching_monthly_rows(): MONTHLY_ABSENCE 匹配行预填 + +6. JSON 输出(可选) + |-- 解析 DATA DIVISION → 字段字典 + |-- 分支树 + MC/DC 路径枚举 + |-- output_json(): 写入 json/{program_id}.json + +7. 返回 DbPipelineResult(step=2, data={records, flat_files, db_path}) +``` + +**关键逻辑:** +- 多场景时 DB 路径分离: `{program_id}_{scenario_id}.db` +- PK 冲突行必须与运行时 INSERT 实际值一致(基于输入记录而非合成值) +- 聚合边界注入: overflow(同月累加溢出)+ table-full(>=110 个不同月) +- 日期值统一为 YYYYMMDD 格式 + +**输入:** src_path, pp_path, schema, scenario +**输出:** generated_records, generated_structure, db_path, 平面文件 + +### 3.3 Step 3: COBOL 执行 (step3_run_cobol) + +**职责:** 调用编译后的 COBOL 程序并收集 gcov 覆盖率数据 + +**执行流程:** + +``` +1. 环境准备 + |-- 创建 runtime/run_{id}/main/{input,output}/ 目录 + |-- 复制生成的平面文件 → input/ + |-- 复制 JSON → json/ + +2. 文件方向映射 (_scan_assign_to) + |-- 正则扫描 SELECT/ASSIGN-TO → {文件名: 方向} + |-- OPEN 语句解析 → INPUT/OUTPUT 方向确定 + +3. DB 路径准备 + |-- 场景 DB → 复制到默认 DB 路径 + |-- CWD/data/kin.db(CONNECT TO 路径) + |-- CWD/kin(gixsql regex 路径) + +4. 执行 + |-- 清理前次 .gcda 文件 + |-- runner.run(exe, cwd, db_path, env_overrides, command_args) + |-- 日志写入 runtime_dir/logs/ + +5. gcov 数据收集 + |-- .gcda 从 CWD + exe_dir 复制到 gcov/run_{id}/ + |-- .gcno 同步(共享 .gcno,COPY 不 MOVE) + +6. 返回 DbPipelineResult(step=3, data={returncode, log, ...}) +``` + +**关键逻辑:** +- GIXSQL_DB_PATH 环境变量不生效,需通过 CWD/data/kin.db 传递 +- GnuCOBOL 的 .gcda 写入编译时 CWD,多场景需 COPY 到各自 gcov 目录 +- subprogram 的 .gcno 必须同步到每个 run 目录 + +**输入:** exe_path, schema, scenario +**输出:** 运行日志、gcov 数据、返回码 + +### 3.4 Step 4: 中间数据提取 (step4_extract_intermediate) + +**职责:** 从 SQLite DB 导出 Java 程序所需的 JSON 中介数据 + +**执行流程:** + +``` +1. 打开 DB(_current_db_path 或 db_path) +2. 遍历 schema.db_tables,对每张表执行 SELECT * FROM [table] +3. 构建 meta = {program_id, tables: {table_name: [rows]}} +4. 写入 work_dir/intermediate/{program_id}_W01.json +5. 返回 DbPipelineResult(step=4, data={tables, w01_path}) +``` + +**关键逻辑:** +- 使用 sql_name 或 name 查询表名 +- 即使表不存在也不报错(空列表),允许部分执行 +- 输出 JSON 包含所有表的全量行数据 + +**输入:** _current_db_path, schema.db_tables +**输出:** java_input_path(W01 JSON) + +### 3.5 Step 5: Java 执行 (step5_run_java) + +**职责:** 调用 Java 转换程序处理 COBOL 输出数据 + +**执行流程:** + +``` +1. 创建 java_output 目录 +2. 构建命令: java -jar {java_jar} -i {java_input_path} -o {java_out} +3. subprocess.run(cmd, capture_output=True, timeout=60) +4. 返回 DbPipelineResult(step=5, data={returncode, log}) +``` + +**关键逻辑:** +- 超时限制 60 秒 +- 若未指定 java_jar,仅执行 java -version 检测环境 +- 依赖 Step 4 的输出作为输入 + +**输入:** java_input_path, java_jar +**输出:** java_output_path, 执行日志 + +### 3.6 Step 6: 结果验证 (step6_verify) + +**职责:** 比较 Java 输出与 COBOL 期望值 + +**执行流程:** + +``` +1. 构建 VerificationRun 结果对象 +2. 读取 DB 各表行数(调试信息) +3. 扫描 java_output_path 下的 .txt/.json 文件 +4. 设置 exit_code 和 status(PASS/MISMATCH) +5. 返回 VerificationRun +``` + +**关键逻辑:** +- fields_mismatched == 0 时判定为 PASS +- 输出 Java 输出文件列表作为调试信息 +- 返回 VerificationRun 而非 DbPipelineResult + +**输入:** java_output_path, _current_db_path, schema.db_tables +**输出:** VerificationRun(status, exit_code, debug) + +--- + +## 4. 接口定义 + +### 4.1 主入口: run_all() + +```python +def run_all(self, skip_steps: set[int] | None = None, + generate_coverage: bool = True) -> VerificationRun: +``` + +**参数:** + +| 参数 | 类型 | 说明 | +|------|------|------| +| skip_steps | set[int] | 要跳过的步骤编号集合(如 {5, 6}) | +| generate_coverage | bool | 是否生成覆盖率报告(默认 True) | + +**返回:** VerificationRun(最终验证结果) + +**行为:** +- skip_jvm=True 时自动将 {5, 6} 加入 skip_steps +- 多场景执行: schema.runs 非空时循环执行 Step 2-3 +- 每个场景失败即返回 BLOCKED(不继续后续步骤) +- Step 1 只执行一次(编译共享) +- 多场景执行后自动合并 gcov 数据 + +### 4.2 单步接口 + +| 方法 | 签名 | 返回 | +|------|------|------| +| step1_setup_environment | () -> DbPipelineResult | 编译结果 | +| step2_generate_inputs | (scenario: ScenarioDef?) -> DbPipelineResult | 数据生成结果 | +| step3_run_cobol | (scenario: ScenarioDef?) -> DbPipelineResult | 执行结果 | +| step4_extract_intermediate | () -> DbPipelineResult | 提取结果 | +| step5_run_java | (java_cmd, java_jar) -> DbPipelineResult | Java 执行结果 | +| step6_verify | () -> VerificationRun | 验证结果 | +| generate_coverage_report | (output_dir?) -> DbPipelineResult | 覆盖率报告 | + +### 4.3 内部辅助接口 + +| 方法 | 职责 | +|------|------| +| _copy_sources_to_workdir | 源码 + COPYBOOK + 子程序复制到 ASCII 工作目录 | +| _scan_assign_to | 扫描 SELECT/ASSIGN-TO + OPEN 确定文件方向 | +| _init_database / _create_tables | 按 YAML schema 创建 SQLite 表结构 | +| _populate_database | 从测试记录生成 DB 种子行 | +| _inject_sql_error_rows | 注入 PK 冲突行触发 SQL 错误路径 | +| _inject_extra_seed_rows | 为 SELECT 型程序注入大结果集 | +| _inject_aggregation_boundaries | 注入聚合边界数据(溢出 + 表满) | +| _deduplicate_r01_pk | 确保 R01 记录 PK 唯一性 | +| _seed_matching_monthly_rows | 预填 MONTHLY_ABSENCE 匹配行 | +| _merge_multi_run_gcov | 多轮场景 gcov 数据合并 | +| _merge_schema_columns | YAML schema 列型合并到 declared_columns | +| _insert_pk_map | 构建 SQL 表 → PK 列名映射 | +| _coordinate_db_rule_matching | DB 属性区间对齐(AGE/DEPENDENTS/REGION) | +| _coordinate_seed_numeric_types | DB 种子值数字化(PIC 9 对齐) | +| _make_synthetic_error_rows | 构建合成 PK 冲突行 | + +--- + +## 5. 数据流 + +### 5.1 管道级数据流 + +``` +cobol_src_dir/{program_id}.cbl + | + v +[Step 1: 环境整备] + |-- src_path (预处理源码) + |-- pp_path (gixpp 输出) + |-- exe_path (编译产物) + | + v +[Step 2: 输入数据生成] + |-- generated_records (测试数据) + |-- generated_structure (分支树 + 赋值表) + |-- db_path (SQLite DB with seeds) + |-- 平面文件 (input/) + |-- JSON (json/{program_id}.json) + | + v +[Step 3: COBOL 执行] + |-- 运行日志 + |-- 输出文件 (output/) + |-- gcov 数据 (gcov/) + | + v +[Step 4: 中间数据提取] + |-- java_input_path (W01 JSON) + | + v +[Step 5: Java 执行] + |-- java_output_path + | + v +[Step 6: 结果验证] + |-- VerificationRun (PASS/MISMATCH) +``` + +### 5.2 每步输入输出明细 + +| 步骤 | 输入 | 输出 | 依赖 | +|------|------|------|------| +| Step 1 | cobol_src_dir, copybook_dirs, schema | src_path, pp_path, exe_path | 无 | +| Step 2 | src_path, pp_path, schema, scenario | records, structure, db_path, flat files | Step 1 | +| Step 3 | exe_path, records, db_path, scenario | logs, output files, gcov data | Step 1, 2 | +| Step 4 | db_path, schema.db_tables | java_input_path | Step 2, 3 | +| Step 5 | java_input_path, java_jar | java_output_path | Step 4 | +| Step 6 | java_output_path, db_path | VerificationRun | Step 4, 5 | + +### 5.3 多场景数据流 + +``` +schema.runs = [scenario_A, scenario_B, ...] + | + v +[Step 1] 编译一次(共享 exe_path) + | + v +[Step 2-A] scenario_A → db_A, records_A, flat_A +[Step 3-A] 运行 A → gcov_A + | + v +[Step 2-B] scenario_B → db_B, records_B, flat_B +[Step 3-B] 运行 B → gcov_B + | + v +[_merge_multi_run_gcov] gcov_A + gcov_B → merged_gcov + | + v +[Step 4] 提取最后一个场景的 DB +[Step 5-6] Java 执行 + 验证 +``` + +--- + +## 6. 错误处理 + +### 6.1 步骤级容错 + +每个 Step 方法内部用 try-except 包裹,返回 DbPipelineResult(success=False) 而非抛出异常: + +```python +def step1_setup_environment(self) -> DbPipelineResult: + try: + # ... 编译逻辑 ... + return DbPipelineResult(self.program_id, 1, result.success, ...) + except Exception as e: + return DbPipelineResult(self.program_id, 1, False, str(e)) +``` + +### 6.2 管道级中断 + +run_all() 中每个 Step 后检查 success,失败则立即返回 BLOCKED: + +```python +r1 = self.step1_setup_environment() +if not r1.success: + return VerificationRun(status="BLOCKED", step_reached=1) + +r2 = self.step2_generate_inputs(scenario) +if not r2.success: + return VerificationRun(status="BLOCKED", step_reached=2) +``` + +### 6.3 异常分类 + +| 异常场景 | 处理方式 | 影响 | +|----------|----------|------| +| gixpp 预处理失败 | Step 1 返回 success=False | 管道终止 | +| cobc 编译失败 | Step 1 返回 success=False | 管道终止 | +| COBOL 运行崩溃 | Step 3 返回 success=False | 管道终止 | +| DB 表不存在 | OperationalError 捕获,空列表 | 不阻断 | +| Java 超时 | subprocess.TimeoutExpired | Step 5 返回 False | +| gcov 文件缺失 | PermissionError 捕获,跳过 | 不阻断 | +| COPYBOOK 未找到 | logger.warning | 不阻断 | +| 子程序未找到 | logger.warning | 不阻断 | +| JSON 输出失败 | logger.warning | 不阻断,继续执行 | + +### 6.4 数据一致性保障 + +- **PK 去重:** `_deduplicate_r01_pk` 确保所有 R01 记录的 (EMP_ID, DATE) 唯一 +- **EMP-ID 清洗:** 全零 '00000000' → SPACE,避免 PK 冲突导致 ABEND +- **日期格式统一:** 所有日期值统一为 YYYYMMDD 8 位格式 +- **DB 列型匹配:** INSERT 前按 PRAGMA table_info 转换值类型(INTEGER/DECIMAL) + +--- + +## 7. 性能设计 + +### 7.1 编译复用 + +Step 1 只执行一次,所有场景共享编译产物(exe_path)。 + +### 7.2 多场景顺序执行 + +Step 2-3 对每个场景顺序执行,避免 DB 并发写入冲突。每个场景有独立的: +- DB 文件: `{program_id}_{scenario_id}.db` +- 工作目录: `work_dir/run_{scenario_id}/` +- 运行目录: `runtime_dir/run_{scenario_id}/` + +### 7.3 gcov 数据合并 + +多场景执行后调用 `_merge_multi_run_gcov()`,对每行取 max(count) 合并: +```python +merged[line] = max(merged.get(line, 0), cnt) +``` +子程序 gcov 单独存储(`_sub_gcov_data`),避免行号冲突。 + +### 7.4 文件复制策略 + +- 构建产物放在 TEMP 目录(ASCII 路径),避免 gixpp 中文路径问题 +- 运行时数据放在项目 runtime/ 目录 +- DB 文件在多场景间通过 shutil.copy2 复制,而非共享 +- .gcda/.gcno 使用 COPY 而非 MOVE(GnuCOBOL 累积写入特性) + +### 7.5 已执行步骤跳过 + +run_all() 支持 skip_steps 参数,允许跳过已执行的步骤: +```python +orch.run_all(skip_steps={1, 2, 3}) # 仅执行 Step 4-6 +``` + +### 7.6 覆盖率报告可选 + +覆盖率报告生成由 generate_coverage 控制,默认开启但非管道核心路径: +```python +if '--coverage' in cv_flags and generate_coverage: + self.generate_coverage_report() +``` + +### 7.7 LLM 可选 + +Step 2 的 LLM 客户端仅在 config.llm_model 配置时初始化,未配置时回退到规则引擎: +```python +llm = None +if hasattr(self.config, 'llm_model') and self.config.llm_model: + llm = LLMClient(model=self.config.llm_model, timeout=self.config.llm_timeout) +recs = generate_all_data(..., llm_client=llm, ...) +``` + +--- + +## 8. 目录结构 + +``` +runtime/{program_id}/ + +-- main/ + | +-- input/ <- 平面输入文件 + | +-- output/ <- COBOL 输出文件 + | +-- json/ <- JSON 输出 + +-- logs/ + | +-- compile/ <- 编译日志 + | +-- {program_id}.log <- 运行日志 + +-- gcov/ + | +-- run_{scenario}/ <- 各场景 gcov 数据 + +-- run_{scenario}/ <- 多场景隔离目录 + +-- main/input/ + +-- main/output/ + +work_dir/{program_id}/ + +-- src/ <- ASCII 源码副本 + +-- preprocessed/ <- gixpp 输出 + +-- bin/ <- 编译产物 (.exe, .gcno) + +-- main/ + | +-- input/ <- 生成的平面文件 + | +-- json/ <- JSON 输出 + +-- intermediate/ <- W01 JSON(Java 中介数据) + +-- java_output/ <- Java 输出 + +-- run_{scenario}/ <- 多场景隔离目录 +``` diff --git a/docs/detailed-design/03-runners.md b/docs/detailed-design/03-runners.md new file mode 100644 index 0000000..438a711 --- /dev/null +++ b/docs/detailed-design/03-runners.md @@ -0,0 +1,412 @@ +# 03 - runners 编译运行引擎 + +## 1. 模块概述 + +`runners` 模块负责 COBOL 程序与 Java 程序的**编译、运行、覆盖率采集**全流程。模块采用策略模式,通过抽象基类 `Runner` 统一不同语言运行时的接口,对外暴露一致的 `compile -> run -> get_coverage` 三阶段管线。 + +核心职责: + +| 职责 | 说明 | +|------|------| +| COBOL 编译 | 调用 `cobc`(COBOL 编译器)将 `.cbl` 源码编译为可执行文件 | +| Java 编译 | 调用 `mvn package` 将 Maven 项目打包为 `.jar` | +| 运行执行 | 通过 `subprocess` 启动编译产物,捕获 stdout/stderr 和返回码 | +| 测试数据写入 | 将 `TestCase` 列表序列化为 COBOL 二进制 / JSON 格式 | +| 覆盖率报告 | 采集分支覆盖数据(gcov / JaCoCo)并返回量化报告 | + +--- + +## 2. 文件清单 + +``` +runners/ + __init__.py # 包导出:公开 API 声明 + runner.py # 抽象基类 Runner + 数据类 BuildResult / RunResult / CoverageReport + cobol_runner.py # COBOL 编译·执行器(cobc 管线) + gixsql_runner.py # DB COBOL 程序编译·执行器(gixpp + cobc + gixsql 链接) + native_java_runner.py # Java 本地运行器(mvn + java -jar) + spark_java_runner.py # Spark 运行器(spark-submit) + data_writer.py # 测试数据序列化(COBOL 二进制 / Spark JSON / Native JSON) +``` + +--- + +## 3. 接口定义 + +### 3.1 数据类(runner.py) + +```python +@dataclass +class BuildResult: + success: bool # 编译是否成功 + artifact_path: str = "" # 编译产物路径(.exe / .jar) + log: str = "" # 编译日志(stdout + stderr) + +@dataclass +class RunResult: + success: bool # 运行是否成功(returncode == 0) + records: list[dict] # 运行输出记录(JSON 格式) + log: str = "" # 运行日志 + coverage_exec: str = "" # 覆盖率执行文件路径 + +@dataclass +class CoverageReport: + branch_rate: float = 0.0 # 分支覆盖率(0.0 ~ 1.0) + covered_branches: int = 0 # 已覆盖分支数 + total_branches: int = 0 # 总分支数 + verdict: str = "PASS" # 判定结果(PASS / FAIL) +``` + +### 3.2 抽象基类(runner.py) + +```python +class Runner(ABC): + @abstractmethod + def compile(self, source_dir: str) -> BuildResult: ... + + @abstractmethod + def run(self, artifact: str, input_path: str, output_path: str) -> RunResult: ... + + @abstractmethod + def get_coverage(self, artifact: str, run_id: str) -> CoverageReport: ... +``` + +### 3.3 CobolRunner(cobol_runner.py) + +| 方法 | 签名 | 说明 | +|------|------|------| +| `compile` | `(src, dialect="ibm", gcov=False) -> BuildResult` | 旧式编译,`-std=ibm-strict`,供 orchestrator.py 使用 | +| `run` | `(binary, input_path, output_path) -> RunResult` | 旧式执行,stdin 管道 stdout | +| `compile_with_links` | `(src, work_dir, copybook_dirs, sub_objects, gcov) -> BuildResult` | 新式编译:主程序 + 链接 SUB.o,支持 COPYBOOK 搜索路径和 gcov | +| `run_file_based` | `(binary, run_dir, input_files, timeout) -> RunResult` | 新式执行:基于文件的 I/O,将输入文件复制到运行目录后启动程序 | + +### 3.4 GixsqlCobolRunner(gixsql_runner.py) + +| 方法 | 签名 | 说明 | +|------|------|------| +| `preprocess` | `(src_path, out_dir, copybook_dirs) -> str` | gixpp 预处理:COPY 展开、SQL 归一化、格式修正 | +| `compile` | `(pp_path, exe_path, copybook_dirs, extra_srcs) -> GixsqlBuildResult` | cobc 编译,链接 gixsql 库 | +| `run` | `(exe_path, work_dir, db_path, ...) -> GixsqlRunResult` | 执行 DB 程序,设置 SQLite 数据库路径 | +| `read_db_tables` | `(db_path, table_names) -> list[GixsqlTableData]` | 读取 SQLite 数据库表内容 | + +### 3.5 NativeJavaRunner(native_java_runner.py) + +| 方法 | 签名 | 说明 | +|------|------|------| +| `compile` | `(source_dir) -> BuildResult` | Maven 打包,输出 target/program.jar | +| `run` | `(artifact, input_path, output_path) -> RunResult` | java -jar 执行,解析 stdout JSON 行 | +| `get_coverage` | `(artifact, run_id) -> CoverageReport` | 检查 jacoco.exec 是否存在,返回覆盖率 | + +### 3.6 SparkJavaRunner(spark_java_runner.py) + +| 方法 | 签名 | 说明 | +|------|------|------| +| `compile` | `(source_dir) -> BuildResult` | Maven 打包,输出 target/program.jar | +| `run` | `(artifact, input_path, output_path) -> RunResult` | spark-submit 执行,读取 part-\* 输出文件 | +| `get_coverage` | `(artifact, run_id) -> CoverageReport` | 返回固定 0.80 覆盖率(Spark 无原生覆盖率集成) | + +### 3.7 DataWriter(data_writer.py) + +| 方法 | 签名 | 说明 | +|------|------|------| +| `write_cobol_binary` | `(cases, out)` | 将 TestCase 列表写为 COBOL 二进制格式(大端序 int64 / float64 / ASCII) | +| `write_spark_json` | `(cases, cfg, d)` | 写 Spark 输入 JSON(part-00000.json),key 字段加序号后缀 | +| `write_native_json` | `(cases, out)` | 写 Native JSON(每行一个 JSON 对象) | + +--- + +## 4. 编译流程 + +### 4.1 COBOL 编译(cobol_runner.py) + +#### 旧式编译流程 + +``` +.cbl 源文件 + | + v +cobc -x -std=ibm-strict [-o 输出路径] [-g] [--coverage] 源文件 + | + v +BuildResult(success, artifact_path, log) +``` + +- 默认超时 30 秒 +- `gcov=True` 时追加 `--coverage` 参数生成 `.gcno` 文件 + +#### 新式编译流程(带链接) + +``` +.cbl 源文件 + SUB*.o 对象文件 + | + v +cobc -x -g [--coverage] [-I COPYBOOK路径...] -o 输出.exe 源文件 SUB1.o SUB2.o ... + | + v +BuildResult(success, exe_path, log) +``` + +- 默认超时 120 秒 +- 工作目录切换至 `work_dir`(确保 `.gcno` 产出位置正确) +- 不使用 `-std=ibm-strict`,依赖默认方言 + +### 4.2 DB COBOL 编译(gixsql_runner.py) + +DB 程序编译采用 gixpp + cobc 两阶段管线: + +``` +原始 .cbl 源文件 + | + v -- _normalize_source() + | 1. 剥离注释行(避免日文注释中的 EXEC SQL 被误匹配) + | 2. EXEC SQL INCLUDE SQLCA -> COPY SQLCA + | 3. EXEC SQL CONNECT TO 'literal' -> CONNECT TO :WS-GIX-CONN USER :WS-GIX-USR + | 4. COPY REPLACING 内联展开(Python 侧) + | 5. ALL COPY 展开(替代 cobc -E) + | 6. 关键字间多空格压缩 + | 7. DIVISION/SECTION 头部列位置修正(Area A,列 8 起) + | 8. SELECT ... FROM ... INTO -> SELECT ... INTO ... FROM(gixpp 要求 INTO 在前) + | 9. CURRENT TIMESTAMP -> CURRENT_TIMESTAMP(SQLite 后端兼容) + | 10. DB2 schema 限定表名去限定(SCHEMA.TABLE -> TABLE) + v +_norm.cbl(规范源文件) + | + v -- preprocess() + | gixpp -i _norm.cbl -o _pp.cbl -e [-I COPYBOOK路径...] + | 将 EXEC SQL 块转换为 GIXSQL 调用序列 + v +_pp.cbl(预处理后源文件) + | + v -- compile() + | 1. _patch_sql_identifiers():DB2 连字符标识符 -> 下划线(SQLite 兼容) + | 2. _patch_sqlcode_normalize():SQLite 约束错误码映射为 DB2 标准码 + | 3. cobc -x -L gixsql库路径 -K GIXSQL*函数 -l gixsql [-I COPYBOOK...] -o exe pp.cbl + v +GixsqlBuildResult(success, exe_path, log) +``` + +### 4.3 Java 编译(native_java_runner.py / spark_java_runner.py) + +两个 Java Runner 共享相同的 Maven 编译流程: + +``` +source_dir/pom.xml + | + v +mvn -B package -f pom.xml + | + v +source_dir/target/program.jar + | + v +BuildResult(success, artifact_path, log) +``` + +- 默认超时 120 秒 +- 使用 `-B`(batch mode)避免交互式提示 +- 产物固定为 `target/program.jar` + +--- + +## 5. 运行流程 + +### 5.1 COBOL 执行 + +#### 旧式执行(stdin 到 stdout) + +``` +input_path(二进制数据) + | + v subprocess.run([binary], input=data, capture_output=True) + | + v stdout 写入 output_path + | + v RunResult(success) +``` + +- 超时 30 秒 +- 无输出记录解析(仅写入文件) + +#### 新式执行(基于文件) + +``` +input_files: {assign_name: source_path} + | + v 复制输入文件到 run_dir + | + v subprocess.run([binary], cwd=run_dir, capture_output=True) + | + v RunResult(success, log) +``` + +- 超时 60 秒(可配置) +- 工作目录为 `run_dir`,程序通过 ASSIGN 名读取文件 +- 日志截断至 2000 字符 + +### 5.2 DB COBOL 执行(gixsql_runner.py) + +``` +exe_path + db_path(SQLite 数据库) + | + v 部署 DLL 到 exe_dir(libgixsql.dll, libgixsql-sqlite.dll 等) + | + v 复制输入文件到 work_dir + | + v subprocess.run([exe], cwd=work_dir, env={GIXSQL_DB_PATH: db_path}) + | + v GixsqlRunResult(success, returncode, db_path, log) + | + v read_db_tables(db_path, table_names) -> 读取数据库输出 +``` + +- 超时 30 秒(可配置) +- 环境变量 `GIXSQL_DB_PATH` 指向 SQLite 数据库 +- DLL 部署策略:优先 lib_path,回退到 gixpp bin 目录 +- returncode 0 或 1 均视为成功(COBOL STOP RUN 返回码差异) + +### 5.3 Java 执行 + +#### NativeJavaRunner + +``` +input_path(JSON 文件) + | + v java -jar artifact(stdin 输入) + | + v 解析 stdout JSON 行 -> records 列表 + | + v RunResult(success, records, log) +``` + +- 超时 60 秒 +- 每行一个 JSON 对象 + +#### SparkJavaRunner + +``` +input_path(JSON 文件) + | + v spark-submit --class Main --master local[*] + | --conf spark.input.path=... + | --conf spark.output.path=... + | --conf spark.input.format=json + | --conf spark.output.format=json + | artifact + | + v 读取 output_path/part-* 文件 -> records 列表 + | + v RunResult(success, records, log) +``` + +- 超时 300 秒(5 分钟) +- 输入输出格式通过 spark conf 配置 +- 输出文件自动 glob 匹配 `part-*` + +--- + +## 6. 错误处理 + +### 6.1 编译失败 + +| 场景 | 处理方式 | 返回值 | +|------|----------|--------| +| cobc 编译错误 | 捕获 returncode != 0 | `BuildResult(success=False, log=stdout+stderr)` | +| cobc 超时 | 捕获 TimeoutExpired | `BuildResult(success=False, log="Compile timeout")` | +| gixpp 预处理失败 | 捕获 returncode != 0,抛出 RuntimeError | `raise RuntimeError("gixpp failed")` | +| Maven 编译错误 | 捕获 returncode != 0 | `BuildResult(success=False, log=stdout+stderr)` | + +### 6.2 运行时异常 + +| 场景 | 处理方式 | 返回值 | +|------|----------|--------| +| COBOL 程序异常终止 | 捕获 returncode != 0 | `RunResult(success=False, log=stdout+stderr)` | +| COBOL 程序超时 | 捕获 TimeoutExpired | `RunResult(success=False, log="Run timeout")` | +| DB 程序 returncode 1 | 视为成功(COBOL 语义差异) | `GixsqlRunResult(success=True)` | +| Java 程序异常 | 捕获 returncode != 0 | `RunResult(success=False, log=stdout+stderr)` | +| Spark 程序超时 | 捕获 TimeoutExpired(300s) | `RunResult(success=False, log="Run timeout")` | +| DLL 未找到 | 运行时加载失败,日志记录 | `GixsqlRunResult(success=False, log=...)` | + +### 6.3 Gixsql 专用处理 + +| 机制 | 说明 | +|------|------| +| SQL 标识符归一化 | DB2 连字符标识符自动转换为下划线(`EMP-MASTER` -> `EMP_MASTER`) | +| SQLCODE 映射 | SQLite 约束错误码(-1555/-2067/-19)映射为 DB2 标准码(-803) | +| Schema 限定去限定 | `SCHEMA.TABLE` -> `TABLE`(SQLite 无 schema 概念) | +| CURRENT TIMESTAMP | DB2 `CURRENT TIMESTAMP` -> SQLite `CURRENT_TIMESTAMP` | +| DLL 自动部署 | 运行前将 gixsql DLL 复制到 exe_dir 确保加载器找到 | + +### 6.4 日志截断 + +所有 Runner 的日志均截断至固定长度以避免内存溢出: + +| Runner | 日志截断长度 | +|--------|-------------| +| CobolRunner(旧式) | 无截断(完整 stdout+stderr) | +| CobolRunner(新式) | 2000 字符 | +| GixsqlCobolRunner | 500-1000 字符 | +| NativeJavaRunner | 无截断(完整 stdout+stderr) | +| SparkJavaRunner | 无截断(完整 stdout+stderr) | + +--- + +## 7. 设计特点 + +### 7.1 双轨架构 + +CobolRunner 维护两套接口: + +- **旧式接口**(`compile` + `run`):供 `orchestrator.py` 使用,兼容现有调用链 +- **新式接口**(`compile_with_links` + `run_file_based`):支持非 DB 程序的文件 I/O 和 SUB.o 链接 + +两套接口互不干扰,通过不同方法名区分。 + +### 7.2 Gixsql 预处理管线 + +GixsqlCobolRunner 的预处理是模块中最复杂的部分: + +1. **Python 侧 COPY 展开**:替代 `cobc -E`,解决 gixpp ESQL 解析器对 COPY REPLACING 伪文本的兼容问题 +2. **SQL 归一化**:处理 DB2 与 SQLite 的语法差异(标识符、时间函数、schema 限定符) +3. **SQLCODE 映射**:注入代码将 SQLite 特定错误码转换为 DB2 标准码,确保 `IF SQLCODE = -803` 分支可达 + +### 7.3 DLL 部署策略 + +gixsql 运行时需要多个 DLL(libgixsql.dll, libgixsql-sqlite.dll 等)。部署策略: + +1. 优先从 `lib_path` 复制 +2. 若不存在,回退到 `gixpp` bin 目录 +3. 检查文件大小避免重复复制 + +### 7.4 DataWriter 格式 + +| 格式 | 字节序 | 数值类型 | 字符串处理 | +|------|--------|----------|------------| +| COBOL 二进制 | 大端序(Network Byte Order) | int64 (`>q`) / float64 (`>d`) | ASCII,右补空格至 10 字节 | +| Spark JSON | N/A | JSON 数字 | UTF-8,key 字段加序号后缀 | +| Native JSON | N/A | JSON 数字 | UTF-8,每行一个 JSON 对象 | + +--- + +## 8. 依赖关系 + +``` +runners/ + runner.py -> 无外部依赖 + cobol_runner.py -> runners.runner, subprocess, pathlib + gixsql_runner.py -> runners.runner(仅类型引用),subprocess, sqlite3, pathlib, logging + native_java_runner.py -> runners.runner, subprocess, json, shutil, pathlib + spark_java_runner.py -> runners.runner, subprocess, json, shutil, pathlib + data_writer.py -> data.test_case.TestCase, struct, json, pathlib +``` + +外部工具依赖: + +| 工具 | 用途 | 使用者 | +|------|------|--------| +| `cobc` | COBOL 编译器 | CobolRunner, GixsqlCobolRunner | +| `gixpp` | COBOL EXEC SQL 预处理器 | GixsqlCobolRunner | +| `mvn` | Java 构建工具 | NativeJavaRunner, SparkJavaRunner | +| `java` | Java 运行时 | NativeJavaRunner | +| `spark-submit` | Spark 提交工具 | SparkJavaRunner | +| `libgixsql.dll` | gixsql 运行时库 | GixsqlCobolRunner(运行时链接) | +| `libgixsql-sqlite.dll` | SQLite 后端驱动 | GixsqlCobolRunner(运行时加载) | diff --git a/docs/detailed-design/04-hina-classification.md b/docs/detailed-design/04-hina-classification.md new file mode 100644 index 0000000..bd9daf1 --- /dev/null +++ b/docs/detailed-design/04-hina-classification.md @@ -0,0 +1,416 @@ +# HINA 程序分类模块 - 详细设计文档 + +> 模块路径: `hina/` +> 版本: V3 (2026技术大赛) + +--- + +## 1. 模块概述 + +### 1.1 职责 + +`hina` 模块是 COBOL 迁移验证平台 V3 的程序分类与质量门禁系统,负责: + +1. **程序分类** - 根据 COBOL 源码特征,将程序归类到预定义类型 +2. **确信度评估** - 多因子计算分类结果的可信度 +3. **质量门禁** - 测试数据生成前检查覆盖率和边界条件 +4. **策略匹配** - 根据分类结果选择测试策略模板 +5. **gcov 覆盖率收集** - 编译运行后采集动态代码覆盖率 +6. **分层重试** - 处理编译/运行错误的自愈和重试机制 + +### 1.2 依赖关系 + +``` +hina/ + __init__.py <- 公开 API 入口 + classifier.py <- L1 关键字规则匹配 + 结构性匹配检测 + confidence.py <- 4 因子确信度计算 + gate.py <- 质量门禁检查 + gcov_collector.py <- gcov 覆盖率采集 + hina_agent.py <- LLM 混淆组分类代理 + retry.py <- 分层重试处理器 + strategy.py <- 策略模板 + 必须项补充 + pipeline/pipeline.py <- 完整分类管道 + rule_engine/confusion_groups.py <- 8 个混淆对解析函数 + rule_engine/contradiction.py <- 矛盾检测与解决 + rule_engine/backtrack.py <- 多轮回溯判定 +``` + +--- + +## 2. 文件清单 + +| 文件 | 行数 | 职责 | +|------|------|------| +| `__init__.py` | 25 | 公开 API 入口,导出 classify_program | +| `classifier.py` | 304 | L1 关键字规则(14条)、注释剥离、KEY比较检测、结构性匹配检测 | +| `confidence.py` | 120 | 4 因子确信度计算 | +| `gate.py` | 106 | 质量门禁检查、双模式质量评分 | +| `gcov_collector.py` | 58 | gcov 覆盖率采集 | +| `hina_agent.py` | 283 | LLM 混淆组分类、规则兜底 | +| `retry.py` | 82 | 分层重试: 自愈修复 + 朴素重试 | +| `strategy.py` | 103 | 策略模板(5个类型) + 补充 | +| `pipeline/pipeline.py` | 698 | 完整分类管道: 3条路径 | +| `rule_engine/confusion_groups.py` | 287 | 8个混淆对解析函数 | +| `rule_engine/contradiction.py` | 163 | 矛盾检测与解决 | +| `rule_engine/backtrack.py` | 96 | 多轮回溯判定 | + +--- + +## 3. 分类算法 + +### 3.1 分类管道总览 + +`classify_program()` 流程: + +``` +COBOL 源码 + -> 并行: detect_keyword() + extract_structure() + -> 根据最高关键字确信度选择路径: + >= 90% -> 路径 A: keyword 直接输出 + 50-89% -> 路径 B: 规则引擎 + 确信度计算 + < 50% -> 路径 C: LLM 辅助 + 规则验证 + -> 匹配子类型区分(仅对匹配/键中断程序) + -> 输出最终 JSON +``` + +### 3.2 L1 关键字规则 (classifier.py) + +定义在 `L1_RULES` 中,共 14 条规则,格式 `(分类名称, [关键字列表], 置信度阈值)`: + +| 分类 | 关键字 | 置信度 | +|------|--------|--------| +| DB操作 | EXEC SQL | 0.95 | +| 子程序调用 | CALL, LINKAGE SECTION | 0.90 | +| IS INITIAL | IS INITIAL | 0.99 | +| SYSIN | ACCEPT ... FROM SYSIN | 0.90 | +| 编码转换 | ALPHABETIC, ASCII, EBCDIC | 0.85 | +| online | DFHCOMMAREA | 0.95 | +| SORT | SORT ... ON ... KEY | 0.95 | +| MERGE | MERGE ... ON ... KEY | 0.95 | +| 替代索引 | ALTERNATE RECORD KEY | 0.99 | +| 编辑输出 | WRITE ... AFTER/BEFORE | 0.80 | +| 文件编成 | ORGANIZATION IS | 0.99 | +| マッチング | WS-[*]KEY* 变量模式(3条) | 0.55-0.65 | + +`re:` 前缀表示正则表达式匹配,无前缀表示字面量包含匹配。 + +### 3.3 结构性匹配检测 + +`_detect_matching_structure` 不依赖 KEY 变量名,通过 6 个信号判断匹配程序: + +| 信号 | 检测内容 | +|------|---------| +| 1 | READ ... AT END | +| 1b | 2+ 个 READ 语句 | +| 2 | PERFORM UNTIL ... = 'Y'/'N' | +| 3 | ELSE ... READ (条件性读取) | +| 4 | IF A = B (跨文件字段比较) | +| 5 | 2+ 个 OPEN INPUT | + +信号 >= 5: 0.55, = 4: 0.50, = 3: 0.40, < 3: 0.0 + +### 3.4 KEY 变量比较检测 + +`_matches_key_comparison` 确认 KEY 变量在比较上下文中实际使用: +- 模式 1: WS-KEY = / > / < (排除 Figurative Constant) +- 模式 2: 非 WS- 前缀 KEY +- 模式 3: READ INTO ... KEY + +--- + +## 4. 确信度计算 (confidence.py) + +### 4.1 4 因子公式 + +``` +confidence = base x context_factor x consistency_factor x structure_factor +``` + +### 4.2 因子定义 + +**上下文因子:** +| match_count | 值 | +|-------------|-----| +| >= 3 | 1.0 | +| 2 | 0.95 | +| 1 | 0.90 | +| 0 | 0.50 | +| 共识奖励 | +0.15 (上限 1.0) | + +**一致性因子:** +| 矛盾情况 | 值 | +|----------|-----| +| 无矛盾 | 1.0 | +| 全部已解决 | 0.90 | +| 未解决 < 3个 | 0.80 | +| 未解决 >= 3个 | 0.50 | + +**结构一致性因子:** +| score | 值 | +|-------|-----| +| 5 | 1.0 | +| >= 3 | 0.7 | +| >= 1 | 0.5 | +| 0 | 0.3 | + +### 4.3 判定结果 + +| 确信度范围 | 判定 | 需人工审核 | +|-----------|------|-----------| +| >= 0.90 | auto | 否 | +| 0.70-0.89 | review | 是 | +| 0.50-0.69 | manual | 是 | +| < 0.50 | impossible | 是 | + +--- + +## 5. 规则引擎 (rule_engine/) + +### 5.1 混淆组判定 (confusion_groups.py) + +8 个混淆对解析函数: + +| 混淆对 | 区分逻辑 | 置信度 | +|--------|---------|--------| +| matching_vs_keybreak | 三路IF+多文件->マッチング; WS-PREV-KEY+累加器->キーブレイク | 0.75-0.90 | +| dedup_vs_nodedup | WS-PREV-KEY存在->含重复; 不存在->不含重复 | 0.50-0.90 | +| validation_vs_keybreak | WS-ERR*字段->校验; WS-*CNT计数器->キーブレイク | 0.55-0.85 | +| csv_merge_vs_split | STRING+逗号->合并; INSPECT REPLACING+逗号->拆分 | 0.85 | +| simple_vs_two_stage | OPEN-CLOSE-再OPEN->二段階; 其他->単純 | 0.50-0.90 | +| pure_vs_mixed | has_switch+has_counter+IF>=3->混合 | 0.70 | +| division_50_25_100 | DIVIDE被除数常量匹配 | 0.95 | +| mn_output_mode | SELECT>=3+分支>=3->M:N | 0.55-0.65 | + +### 5.2 特征注入 (pipeline.py) + +从 COBOL 源码注入额外特征: + +| 特征名 | 检测方式 | 用途 | +|--------|---------|------| +| has_key_var | 正则匹配KEY变量比较 | 防止计数器比较误触发 | +| has_structural_match | IF+跨文件字段比较+循环/读取 | 结构性匹配信号 | +| has_cross_file_cmp | IF A = B | 跨文件比较 | +| has_csv_merge | STRING ... ',' ... INTO | CSV合并信号 | +| has_csv_split | INSPECT ... REPLACING ... ',' | CSV拆分信号 | + +### 5.3 矛盾检测与解决 (contradiction.py) + +**矛盾对定义** (CONTRADICTION_PAIRS): 10 对可能冲突的分类类型。 + +**解决策略**: +1. 优先级比较 (TYPE_PRIORITY): マッチング(10) > キーブレイク(9) > 項目チェック(8) > ... +2. 优先级相同时,调用混淆对解析器重判定 (置信度 >= 0.80 则采纳) +3. 最终回退: 取 type_a + +### 5.4 多轮回溯 (backtrack.py) + +`BacktrackResolver` 封装多轮判定: +- 最大轮次: 3 +- 超时: 30 秒 +- 超时/超轮次: 标记 `backtrack_degraded = True`,降级返回 + +--- + +## 6. LLM 辅助分类 (hina_agent.py) + +### 6.1 混淆组分类 Prompt + +`CONFUSION_PROMPT` 包含 7 个混淆组定义: +1. simple_sequential - 极少决策点 +2. condition_heavy - IF语句占比高 +3. evaluate_driven - EVALUATE主导 +4. data_file_centric - 文件操作密集 +5. search_intensive - SEARCH ALL +6. call_based - CALL语句 +7. mixed_complex - 多种复杂特征 + +### 6.2 规则兜底分类 + +LLM 失败时 `_fallback_classification` 基于结构特征优先级: + +| 优先级 | 条件 | 分类 | +|--------|------|------| +| 1 | total_decisions == 0 | simple_sequential | +| 2 | has_search_all | search_intensive | +| 3 | has_call | call_based | +| 4 | evaluate > if 且 >= 2 | evaluate_driven | +| 5 | file_count >= 2 | data_file_centric | +| 6 | if >= 5 或 decisions >= 8 | condition_heavy/nested_if | +| 7 | if >= 2 | condition_heavy/simple_if | + +复杂度升级: >= 3 个复杂度标志 -> mixed_complex + +--- + +## 7. 匹配子类型区分 + +仅对 マッチング/キーブレイク/項目チェック 执行子类型区分。 + +### 7.1 分层策略 + +**第 1 层 - 静态规则:** + +| 条件 | 子类型 | +|------|--------| +| 二段階 in category | 二段階 | +| file_count >= 3 + WS-SAVE-KEY | M:N->MxN | +| WS-PREV-KEY | 混合 | +| WS-MAST-KEY + WS-TRAN-KEY | 1:N | +| WS-KEY-M + WS-KEY-T | N:1 | +| WS-KEY-M + WS-KEY-N | M:N | + +**第 2 层 - LLM 推理**: 多键变量+多文件时调用 LLM 判断子类型 + +**第 3 层 - 回退**: 多键+多文件->M:N; 对称键名->1:1 + +--- + +## 8. 策略模板 (strategy.py) + +### 8.1 策略模板定义 + +| 分类 | 必须项 | 边界项 | +|------|--------|--------| +| マッチング | COM-N001~A003, MT-N001~N006 | MT-B001, MT-B002 | +| キーブレイク | COM-N001, A002, KB-N001~N005, A001 | KB-B001, KB-B002 | +| 条件分岐 | B-N001, N003, N006, N009 | - | +| 内部表検索 | T-N001, N002, A001, A002 | - | +| 項目チェック | VF-N001, N002, N004, A001 | - | + +### 8.2 补充函数 + +- `supplement()`: 从模板追加全部必须项和边界项 +- `supplement_only()`: 增量补充指定必须项 + +--- + +## 9. 质量门禁 (gate.py) + +### 9.1 门禁检查 + +| 检查项 | 条件 | 输出 | +|--------|------|------| +| 决策点覆盖率 | branch_rate < 0.90 | decision_gaps | +| 段落覆盖率 | paragraph_rate < 1.0 | paragraph_gaps | +| 测试数据为空 | not complete_tests | no_data | + +### 9.2 双模式质量评分 + +``` +gcov 未启用: branch_rate*0.5 + paragraph_rate*0.5 + confidence*0.4 +gcov 启用: static_cov*0.3 + gcov_cov*0.4 + confidence*0.3 +``` + +--- + +## 10. gcov 覆盖率收集 (gcov_collector.py) + +### 10.1 采集流程 + +1. 检查 .gcda 文件是否存在 +2. 执行 gcov 命令 (30s 超时) +3. 查找 .gcov 输出文件 +4. 解析行覆盖率 + +### 10.2 降级策略 + +所有 gcov 失败降级为仅静态分析。 + +--- + +## 11. 分层重试 (retry.py) + +### 11.1 重试机制 + +`RetryHandler(max_heal=2, max_simple=3)`: +- PASS/QUALITY_WARN -> 返回结果 +- BLOCKED/ERROR -> 自愈修复或朴素重试 +- 总次数 >= 5 -> 标记 FATAL + +### 11.2 自愈修复 + +| 错误 | 检测 | 修复 | +|------|------|------| +| compile_error | 日志含 "not found" | 设置 COB_LIBRARY_PATH | +| s0c7 | 日志含 "S0C7" | 记录警告 | + +--- + +## 12. 接口定义 + +### 12.1 公开 API + +```python +def classify_program(cobol_source: str, llm=None) -> dict: + """返回: {category, confidence, needs_review, method, source, + judgment, matches, contradictions, v2_confidence, structure}""" +``` + +### 12.2 内部模块 API + +- `classifier.detect_keyword(source)` -> list[tuple[str, float, str]] +- `confidence.compute_confidence_v2(keyword_result, structure_features, ...)` -> dict +- `gate.check(complete_tests, hina_result, coverage, ...)` -> dict +- `gate.compute_quality_score(static_coverage, gcov_coverage, confidence)` -> float +- `strategy.get_strategy(hina_type)` -> dict +- `strategy.supplement(base_tests, hina_result)` -> list[dict] +- `gcov_collector.collect_gcov(cobol_src, work_dir)` -> dict +- `RetryHandler(max_heal, max_simple).run(pipeline_fn)` -> VerificationRun +- `hina_agent.classify_with_llm(structure, llm)` -> dict +- `rule_engine.resolve_confusion_pair(features, pair_name)` -> dict +- `rule_engine.detect_contradictions(features)` -> list[dict] +- `rule_engine.resolve_contradiction(features, contradiction)` -> str +- `BacktrackResolver(structure_extractor).resolve(source, features)` -> dict + +--- + +## 13. 错误处理 + +### 13.1 错误分类 + +| 类别 | 示例 | 处理 | +|------|------|------| +| L1解析错误 | 正则匹配失败 | 跳过该规则 | +| LLM调用失败 | API超时/网络错误 | 回退到规则引擎 | +| LLM响应解析 | 无效JSON | 返回unknown | +| gcov失败 | 命令未找到/超时 | 降级为静态分析 | +| 回溯超时 | > 30s | 标记降级返回 | +| 矛盾不可解 | 优先级相同 | 取type_a回退 | +| 空源码 | cobol_source为空 | 返回impossible | + +### 13.2 日志策略 + +- `logger.info()`: 关键流程节点 +- `logger.debug()`: 规则引擎特征、矛盾详情 +- `logger.warning()`: LLM失败、回溯降级、gcov失败 + +--- + +## 14. 数据流总结 + +``` +Input: cobol_source (str), llm (optional) + | + v +[Parallel] detect_keyword + extract_structure + | + v +Route by max keyword confidence: + >= 0.90 -> Path A: keyword direct + 0.50-0.89 -> Path B: rule engine + < 0.50 -> Path C: LLM assisted / rule fallback + | + v +_resolve_matching_subtype (for matching/keybreak programs) + | + v +Output: {category, confidence, needs_review, method, source, + judgment, matches, contradictions, v2_confidence, structure} +``` + +下游集成: +1. orchestrator_db.py: 根据category选择测试策略 +2. strategy.py: 获取必须项 +3. gate.py: 用confidence计算质量评分 +4. data_merger.py: 合并策略数据到测试记录 diff --git a/docs/detailed-design/05-agents-llm.md b/docs/detailed-design/05-agents-llm.md new file mode 100644 index 0000000..3bd4d07 --- /dev/null +++ b/docs/detailed-design/05-agents-llm.md @@ -0,0 +1,319 @@ +# 05 - LLM 代理模块详细设计 + +## 1. 模块概述 + +LLM 代理模块(`agents/`)是 COBOL 迁移验证平台 V3 的智能分析层,负责通过大语言模型(LLM)完成三项核心任务: + +1. **COPYBOOK 解析**(Agent1):将 COBOL COPYBOOK 源码解析为结构化字段树(`FieldTree`) +2. **测试数据设计**(Agent2):基于字段树生成边界测试用例(`TestSuite`) +3. **差异诊断**(Agent3):对 COBOL/Java 字段比对不一致项进行根因分析与建议 + +此外,模块还包含一个**式样书驱动测试数据生成器**(`DesignDataGenerator`),通过解析日文详细设计书,结合 LLM 生成有业务意义的机能测试数据。 + +模块底层封装了统一的 `LLMClient`,提供缓存、重试、多模型兼容能力。 + +## 2. 文件清单 + +| 文件 | 职责 | 依赖 | +|------|------|------| +| `__init__.py` | 包入口,公开 API 导出 | 所有子模块 | +| `llm.py` | LLM API 客户端(缓存 + 重试) | `httpx` | +| `agent1_parser.py` | COPYBOOK → FieldTree 解析代理 | `llm.py`, `data.field_tree` | +| `agent2_data.py` | FieldTree → TestSuite 测试数据设计代理 | `llm.py`, `data.field_tree`, `data.test_case` | +| `agent3_diagnostic.py` | FieldResult → 诊断建议文本代理 | `llm.py`, `data.diff_result` | +| `design_data.py` | 式样书驱动测试数据生成器 | `llm.py`, `design_data_input_parser` | +| `design_data_input_parser.py` | 式样书 .md 解析器 | 标准库 `re`, `dataclasses` | + +## 3. Agent1 解析代理(Agent1Parser) + +### 3.1 职责 + +将 COBOL COPYBOOK 源码文本发送给 LLM,由 LLM 输出结构化 JSON,再转换为 `FieldTree` 对象。这是整个流水线的第一步——只有正确解析字段结构,后续测试生成和比对才有基础。 + +### 3.2 数据流 + +``` +COPYBOOK 源码文本 + ↓ (LLM call) +JSON: {"fields": [{name, level, pic, usage, offset, length, decimal, signed, occurs, redefines, conditions, children}]} + ↓ (_load / _fields 递归) +FieldTree +``` + +### 3.3 核心类 + +```python +class Agent1Parser: + def __init__(self, llm: LLMClient) + def parse(self, text: str) -> FieldTree + def _load(self, d: dict) -> FieldTree + def _fields(self, raw: list[dict], off: int) -> list[Field] +``` + +### 3.4 LLM 提示词 + +系统提示词(P1)要求 LLM 扮演 COBOL COPYBOOK 解析器角色,输出严格 JSON 格式,包含字段的名称、层级、PIC 子句、USAGE 类型、偏移量、长度、小数位、符号、OCCURS、REDEFINES、88-level 条件及子字段嵌套。 + +### 3.5 字段偏移量计算 + +`_fields` 方法递归遍历 JSON 字段列表,逐字段计算字节偏移量(`cur += f.length`),确保每个字段在记录中的物理位置准确。子字段通过递归调用 `_fields` 处理嵌套层级。 + +### 3.6 错误处理 + +- LLM 返回非法 JSON 时,`parse` 捕获异常,返回一个 `FieldTree(copybook_name="parse_error")` 空树 +- 使用 bare `except` 捕获所有解析异常,保证流水线不中断 + +## 4. Agent2 数据生成代理(Agent2Data) + +### 4.1 职责 + +基于 `FieldTree` 结构,通过 LLM 生成边界测试用例集合(`TestSuite`)。每个测试用例指定字段值和覆盖目标决策点。 + +### 4.2 数据流 + +``` +FieldTree + ↓ (flatten → JSON) +{"fields": [{name, pic, usage, length, decimal, signed}]} + ↓ (LLM call) +{"test_cases": [{id, fields: {FIELD: value}, coverage_targets: [DP-001]}]} + ↓ (构造 TestCase) +TestSuite +``` + +### 4.3 核心类 + +```python +class Agent2Data: + def __init__(self, llm: LLMClient) + def design(self, tree: FieldTree, target="boundary", spark_mode=False) -> TestSuite +``` + +### 4.4 LLM 提示词 + +系统提示词(P2)要求 LLM 扮演 COBOL 测试数据设计师角色,根据字段树生成边界测试用例,输出严格 JSON 格式。 + +### 4.5 Spark 模式 + +当 `spark_mode=True` 时,生成的 `TestSuite` 附带 `SparkConfig(num_records=1000)`,用于大数据量测试场景。 + +### 4.6 错误处理 + +- LLM 调用失败或返回非法 JSON 时,生成一条兜底用例 `TestCase(id="TC-FALLBACK", fields={"BR-AMT": 0})` +- 使用 bare `except` 捕获反序列化异常 + +## 5. Agent3 诊断代理(Agent3Diagnostic) + +### 5.1 职责 + +对单个字段比对结果(`FieldResult`)进行根因分析,输出包含问题类型、置信度、原因和建议的 JSON 诊断文本。 + +### 5.2 数据流 + +``` +FieldResult (field_name, cobol_value, java_value, status) + ↓ (格式化 prompt) +LLM call + ↓ +JSON: {"issue_type": "...", "confidence": 0.5, "reason": "...", "suggestion": "..."} +``` + +### 5.3 核心类 + +```python +class Agent3Diagnostic: + def __init__(self, llm: LLMClient) + def analyze(self, fr: FieldResult) -> str +``` + +### 5.4 LLM 提示词 + +系统提示词(P3)明确要求 LLM **不做 PASS/FAIL 判定**,仅提供诊断分析。这是设计上的重要约束——Agent3 只是辅助分析工具,最终判定由比对引擎完成。 + +### 5.5 错误处理 + +- 依赖 `LLMClient.call()` 的重试机制 +- 返回原始 LLM 响应字符串,调用方负责解析 + +## 6. 式样书驱动测试数据生成器(DesignDataGenerator) + +### 6.1 职责 + +从日文详细设计书(.md)中提取程序元信息(`ProgramMeta`),结合 COBOL 源码、COPYBOOK 结构和 DB 定义,通过 LLM 生成有业务意义的机能测试数据。 + +### 6.2 数据流 + +``` +设计书 .md + COBOL 源码 + ↓ (DesignDataInputParser.parse) +ProgramMeta (program_id, pgm_pattern, files, keys, process_detail, ...) + ↓ (加载规则 + 构建 prompt) +LLM call + ↓ +JSON: {"records": [{field_name: value}]} + ↓ (_resolve_field_names 字段名映射) +list[dict] +``` + +### 6.3 核心类 + +```python +class DesignDataGenerator: + def __init__(self, llm_client: LLMClient, cpy_dirs: list, rules_dir: str = "rules") + def generate(self, design_md_text, source_text, file_db_md_text=None, + db_md_text=None, replacing_rules=None, v3_field_names=None) -> list[dict] +``` + +### 6.4 式样书解析器(DesignDataInputParser) + +解析日文详细设计书 Markdown 文档,提取以下结构化信息: + +| 数据类 | 内容 | +|--------|------| +| `ProgramMeta` | 程序ID、程序名、系统名、PGM类型、PGM模式、功能概要 | +| `FileInfo` | 文件编号、文件/DB名、标识符、DD名、I/O类型、COPY群、记录格式、记录长度、媒体 | +| `KeyInfo` | 键文件名、排序条件、键条件 | +| `ModuleInfo` | 模块编号、功能、程序ID、COPY名 | +| `TableInfo` | 表名、DB ID、列定义、主键列 | + +解析通过 Markdown 标题匹配(`## 基本情報`、`## 使用ファイル一覧` 等)和表格解析实现,不依赖外部 Markdown 解析库。 + +### 6.5 输入类型自动判定 + +`_determine_input_type` 根据输入文件的媒体类型自动判定: + +| 媒体类型 | input_type | +|----------|------------| +| 仅 PS(顺序文件) | `file` | +| 仅 DB(数据库) | `db` | +| 混合或无输入 | `mixed` / `file` | + +### 6.6 字段名映射(_resolve_field_names) + +外部 Agent 生成的字段名可能与 V3 内部字段名不一致,映射规则: + +1. **REPLACING 展开**:`(A)` → `R01` 等 +2. **前缀连字符处理**:`R01-EMP-ID` → `R01EMP-ID` +3. **直接匹配**:精确匹配 V3 字段名 +4. **去连字符匹配**:`R01EMP-ID` → `R01EMPID` +5. **去下划线匹配**:`R01_EMP_ID` → `R01EMPID` +6. **无法映射的字段丢弃** + +### 6.7 规则加载 + +`_load_rules` 从 `rules/pgm_pattern/` 和 `rules/special_feature/` 目录加载所有 `.md` 规则文件,作为 LLM 上下文的一部分。 + +### 6.8 记录去重(_dedup) + +支持按指定键字段去重,`additional_records` 优先保留。 + +## 7. LLM 接口封装(LLMClient) + +### 7.1 职责 + +封装 LLM API 调用,提供文件缓存、自动重试、多模型兼容能力。所有 Agent 通过此客户端与 LLM 交互。 + +### 7.2 核心类 + +```python +class LLMClient: + def __init__(self, model="gpt-4o-mini", timeout=15, cache_dir=".cache/llm") + def call(self, messages: list[dict], retries=1) -> str + def _key(self, msgs: list[dict]) -> str # SHA256 哈希键 + def _get(self, k: str) -> str | None # 缓存读取 + def _set(self, k: str, v: str) -> None # 缓存写入 +``` + +### 7.3 缓存机制 + +- **键生成**:对消息列表进行 JSON 序列化后取 SHA256 哈希 +- **存储**:以 `{hash}.json` 文件存储在 `.cache/llm/` 目录 +- **格式**:`{"response": "..."}` +- **效果**:相同输入直接返回缓存结果,避免重复调用 LLM + +### 7.4 重试机制 + +- 默认重试 1 次(共 2 次尝试) +- 使用 `httpx.post` 发送 HTTP 请求 +- 重试时捕获所有异常,仅在最后一次失败时抛出 + +### 7.5 环境变量配置 + +| 环境变量 | 说明 | 默认值 | +|----------|------|--------| +| `LLM_API_KEY` | API 密钥 | 空字符串 | +| `OPENAI_API_KEY` | 备用 API 密钥 | 空字符串 | +| `LLM_API_BASE` | API 基础 URL | `https://api.openai.com/v1` | + +### 7.6 API 调用格式 + +```json +POST {base}/chat/completions +{ + "model": "{model}", + "messages": [...] +} +Header: Authorization: Bearer {key} +``` + +响应解析路径:`response["choices"][0]["message"]["content"]` + +## 8. 接口定义 + +### 8.1 模块公开 API + +```python +# agents/__init__.py +LLMClient # LLM API 客户端(含缓存 + 重试) +Agent1Parser # COPYBOOK → FieldTree +DesignDataGenerator # 式样书 → 机能测试数据 +Agent2Data # FieldTree → TestSuite(测试数据设计) +Agent3Diagnostic # FieldResult → 诊断建议文本 +``` + +### 8.2 典型调用链 + +``` +Agent1Parser.parse(copybook_text) → FieldTree +Agent2Data.design(field_tree) → TestSuite +DesignDataGenerator.generate(design_md, source_text) → list[dict] +Agent3Diagnostic.analyze(field_result) → str (JSON) +``` + +### 8.3 数据模型依赖 + +| 模型 | 定义位置 | 用途 | +|------|----------|------| +| `FieldTree` | `data.field_tree` | 字段树结构 | +| `Field` | `data.field_tree` | 单个字段定义 | +| `TestCase` | `data.test_case` | 单条测试用例 | +| `TestSuite` | `data.test_case` | 测试用例集合 | +| `SparkConfig` | `data.test_case` | Spark 生成配置 | +| `FieldResult` | `data.diff_result` | 字段比对结果 | + +## 9. 错误处理 + +### 9.1 错误策略 + +模块采用**宽容降级**策略: + +| 异常场景 | 处理方式 | 影响 | +|----------|----------|------| +| LLM 返回非法 JSON | 返回空/兜底结果 | 流水线继续 | +| LLM API 调用失败 | 重试后抛出异常 | 上层捕获 | +| 式样书解析失败 | 返回空列表 | 跳过数据生成 | +| 字段名映射失败 | 丢弃无法映射的字段 | 部分数据丢失 | +| 缓存文件损坏 | 跳过缓存,重新调用 | 无功能影响 | + +### 9.2 日志策略 + +- 使用 Python `logging` 模块 +- 关键步骤记录 INFO 级别日志(解析开始、LLM 响应、记录数) +- 异常记录 WARNING 级别日志 +- 字段映射丢弃记录 DEBUG 级别日志 + +### 9.3 已知局限 + +1. Agent1/Agent2/Agent3 的 bare `except` 可能掩盖非预期异常 +2. 缓存键基于消息内容哈希,模型变更不会自动失效旧缓存 +3. `DesignDataGenerator` 的 LLM prompt 包含截断(`process_detail[:2000]`),超长设计书可能丢失信息 diff --git a/docs/detailed-design/06-comparator.md b/docs/detailed-design/06-comparator.md new file mode 100644 index 0000000..7f27e88 --- /dev/null +++ b/docs/detailed-design/06-comparator.md @@ -0,0 +1,358 @@ +# 06 - 比对模块详细设计 + +## 1. 模块概述 + +比对模块(`comparator/`)是 COBOL 迁移验证平台 V3 的核心验证引擎,负责将 COBOL 原始输出与 Java(Spark)迁移后输出进行逐字段对比,判断迁移正确性。 + +模块提供五项核心能力: + +1. **记录对齐**(aligner):按主键将 COBOL 记录集与 Java 记录集配对 +2. **二进制读取**(cobol_binary_reader):解析 COBOL 二进制输出文件为字典 +3. **数据标准化**(normalizer):处理 EBCDIC 编码、COMP-3 压缩十进制、日期格式 +4. **字段比对**(field_compare):按类型(数值/日期/字符串)进行字段级比较 +5. **舍入检测**(rounding_detect):判断数值差异是否由 COBOL ROUNDED 子句引起 + +## 2. 文件清单 + +| 文件 | 职责 | 依赖 | +|------|------|------| +| `__init__.py` | 包入口,公开 API 导出 | 所有子模块 | +| `aligner.py` | COBOL 与 Java 记录对齐 | 无 | +| `cobol_binary_reader.py` | 二进制 COBOL 输出解析 | `data.field_tree` | +| `field_compare.py` | 字段级比较(decimal/string/date) | `data.diff_result` | +| `normalizer.py` | COMP-3/EBCDIC 解码、IR 记录构造 | 无 | +| `rounding_detect.py` | 舍入差异检测 | `decimal` | + +## 3. 记录对齐算法(aligner.py) + +### 3.1 职责 + +将 COBOL 输出记录集和 Java 输出记录集按主键字段进行配对,输出对齐的记录对列表及匹配状态。 + +### 3.2 函数签名 + +```python +def align_records( + cobol_records: list[dict], + java_records: list[dict], + key_field: str = "CUST-ID" +) -> list[tuple] +``` + +### 3.3 算法描述 + +1. **分组**:分别按 `key_field` 对 COBOL 和 Java 记录建立 `{key: [records]}` 索引 +2. **合并键集**:取两侧键的并集,按字符串排序 +3. **逐键配对**:对每个键,取两侧记录列表的对应位置进行配对 +4. **状态标记**: + +| 状态 | 含义 | +|------|------| +| `MATCHED` | 两侧均有记录,成功配对 | +| `MISSING_IN_SPARK` | COBOL 有记录,Java 侧缺失 | +| `EXTRA_IN_SPARK` | Java 有记录,COBOL 侧缺失 | + +### 3.4 返回值 + +```python +list[tuple[dict | None, dict | None, str]] +# (cobol_record, java_record, status) +``` + +### 3.5 设计要点 + +- 使用 `setdefault` 聚合同键多记录,支持一对多场景 +- 排序保证输出顺序稳定 +- 键值转为字符串处理,兼容数值键和字符串键 +- 空记录集直接返回空列表 + +## 4. 二进制读取器(cobol_binary_reader.py) + +### 4.1 职责 + +读取 COBOL 程序生成的二进制输出文件,根据 `FieldTree` 定义的字段布局逐记录解析为字典。 + +### 4.2 核心类 + +```python +class CobolBinaryReader: + def read(self, path: str, tree: FieldTree) -> list[dict] + def _record_size(self, tree: FieldTree) -> int + def _parse(self, record_bytes: bytes, tree: FieldTree) -> dict + def _comp3(self, raw: bytes, signed: bool, decimal: int) -> str +``` + +### 4.3 记录大小计算 + +```python +def _record_size(self, tree): + return max((f.offset + f.length for f in tree.fields), default=0) +``` + +取所有顶层字段的最大 `offset + length` 作为记录大小。 + +### 4.4 字段解析策略 + +| USAGE 类型 | 解析方式 | +|-----------|----------| +| `COMP-3` | 半字节解码 + 符号位处理 + 小数点定位 | +| `COMP` / `COMP-5` | `int.from_bytes(raw, "big", signed=...)` | +| 其他(DISPLAY 等) | ASCII 解码 + 去尾空格 | + +### 4.5 COMP-3 解码算法 + +``` +输入: N 字节压缩十进制数据 +1. 将每字节拆为两个半字节(高4位 + 低4位) +2. 弹出最后一个半字节作为符号位 +3. 逐半字节累加为数值(权值 = 10^(len-1-i)) +4. 符号位 0xD/0xB -> 取反 +5. 按 decimal 定位小数点 +输出: 字符串形式数值(如 "1234.56") +``` + +### 4.6 错误处理 + +- 文件为空或记录大小为 0 -> 返回空列表 +- 记录不完整(字节数 < record_size)-> 跳过该记录 +- COMP-3 空数据 -> 返回 "0" +- 非 ASCII 字符 -> `errors="replace"` 替换为 `?` + +## 5. 数据标准化器(normalizer.py) + +### 5.1 职责 + +提供 COBOL 数据到中间表示(IR)的标准化转换,包括 EBCDIC 解码、COMP-3 解码、日期格式统一、IR 记录构造。 + +### 5.2 核心类 + +```python +class Normalizer: + def normalize_encoding(self, raw: bytes, encoding: str) -> str + def normalize_comp3(self, raw: bytes) -> str + def normalize_date(self, s: str) -> str + def to_ir_record(self, name, hex_, val, enc, ft, length=0, scale=0, signed=False) -> IRRecord + def to_null_ir(self, name: str, side: str = "java") -> IRRecord +``` + +### 5.3 EBCDIC 编码转换 + +内置 EBCDIC 037 代码页映射表(`EBCDIC_037`),覆盖: +- 空格、标点、运算符 +- 小写 a-z(0x81-0xA9) +- 大写 A-Z(0xC1-0xE9) +- 数字 0-9(0xF0-0xF9) + +不可映射字符处理: +- 可打印 ASCII(32-126)-> 保留原字符 +- 其他 -> 替换为 `?` + +### 5.4 COMP-3 标准化 + +与 `CobolBinaryReader._comp3` 算法一致,但返回整数字符串(无小数点处理),适用于无需小数定位的场景。 + +### 5.5 日期标准化 + +- 8 位纯数字字符串(如 `20260822`)-> 格式化为 `YYYY-MM-DD` +- 其他格式 -> 原样返回 + +### 5.6 中间表示(IR)模型 + +```python +@dataclass +class CobolIRField: + raw_hex: str # 原始十六进制 + decoded_value: str # 解码后值 + encoding: str # 编码类型(EBCDIC/ASCII) + field_type: str # 字段类型 + length: int # 字节长度 + scale: int # 小数位数 + signed: bool # 是否带符号 + +@dataclass +class JavaIRField: + raw_value: str # 原始值 + decoded_value: str # 解码后值 + field_type: str # 字段类型 + nullable: bool # 是否可空 + +@dataclass +class IRRecord: + field_name: str + cobol: CobolIRField | None + java: JavaIRField | None +``` + +### 5.7 空值 IR 构造 + +`to_null_ir` 为缺失侧构造空 IR 记录(`JavaIRField("", "", "null", True)`),用于只有一侧有数据的场景。 + +## 6. 字段比对算法(field_compare.py) + +### 6.1 职责 + +对单个字段的 COBOL 值和 Java 值进行类型感知的比较,返回结构化的比对结果。 + +### 6.2 函数签名 + +```python +def compare_field( + name: str, + c: str, # COBOL 值 + j: str, # Java 值 + field_type: str = "decimal", # 字段类型 + tolerance: float = 0.01 # 容忍度 +) -> FieldResult +``` + +### 6.3 比对策略 + +| 字段类型 | 比对方式 | 说明 | +|----------|----------|------| +| `decimal` / `numeric` | 数值差 <= tolerance -> TOLERATED | 使用 `Decimal` 精确计算 | +| `date` | 8 位数字 -> `YYYY-MM-DD` 格式化后比较 | 统一格式消除表示差异 | +| `string` | strip 后直接比较 | 去除首尾空白 | +| 其他 | 字符串直接比较 | 兜底策略 | + +### 6.4 状态判定 + +| 状态 | 条件 | +|------|------| +| `PASS` | 完全一致 | +| `TOLERATED` | 数值差在容忍度范围内 | +| `MISMATCH` | 不一致 | +| `NOT_SET` | 两侧均为空/None | + +### 6.5 数值解析(_num) + +```python +def _num(v) -> Decimal | None +``` + +- `None` / `"None"` -> `None` +- 空字符串 -> `Decimal("0")` +- 含 `\x00` -> 去除后解析 +- 非数字字符串 -> `None` + +使用 Python `Decimal` 进行精确十进制运算,避免浮点精度问题。 + +### 6.6 默认容忍度 + +```python +DEFAULT_TOLERANCE = 0.01 +``` + +可通过 `Config.tolerance` 全局配置调整。 + +## 7. 舍入检测(rounding_detect.py) + +### 7.1 职责 + +判断两个数值之间的差异是否由 COBOL `ROUNDED` 子句引起,识别舍入模式并给出置信度。 + +### 7.2 函数签名 + +```python +def detect_rounding(c: str, j: str) -> RoundingResult +``` + +### 7.3 RoundingResult 数据类 + +```python +@dataclass +class RoundingResult: + mode: str = "EXACT" # 舍入模式 + confidence: float = 1.0 # 置信度(0-1) + suggestion: str = "" # 建议文本 +``` + +### 7.4 检测算法 + +``` +1. 解析 COBOL 值 (cv) 和 Java 值 (jv) 为 Decimal +2. 任一解析失败 -> UNKNOWN (confidence=0) +3. cv == jv -> EXACT (confidence=1.0) +4. 计算绝对差 diff = |cv - jv| +5. 判定模式: + - diff < 2 -> TRUNCATE (confidence=0.6) + - diff < 100 -> ROUNDING (confidence=0.4) + - diff >= 100 -> SIGNIFICANT (confidence=0.9) +``` + +### 7.5 舍入模式说明 + +| 模式 | 含义 | 置信度 | 建议 | +|------|------|--------|------| +| `EXACT` | 完全一致 | 1.0 | 无 | +| `TRUNCATE` | 截断差异(diff < 2) | 0.6 | 可能是 COBOL 截断行为 | +| `ROUNDING` | 舍入差异(diff < 100) | 0.4 | 可能存在舍入方式差异 | +| `SIGNIFICANT` | 显著差异(diff >= 100) | 0.9 | 需要关注的较大差异 | + +### 7.6 数值解析(_d) + +```python +def _d(v) -> Decimal | None +``` + +- 使用 `Decimal(str(v).strip())` 解析 +- 异常时返回 `None` + +## 8. 接口定义 + +### 8.1 模块公开 API + +```python +# comparator/__init__.py +align_records(cobol_records, java_records, key_field) -> list[tuple] +compare_field(name, c, j, field_type, tolerance) -> FieldResult +CobolBinaryReader # class +Normalizer # class +detect_rounding(c, j) -> RoundingResult +``` + +### 8.2 典型调用流程 + +``` +cobol_binary_reader.read(path, field_tree) -> list[dict] + | + v +align_records(cobol_records, java_records, key_field) -> list[tuple] + | + v (对每个 MATCHED 对) +compare_field(name, cobol_val, java_val, field_type, tolerance) -> FieldResult + | + v (可选) +detect_rounding(cobol_val, java_val) -> RoundingResult +``` + +### 8.3 数据模型依赖 + +| 模型 | 定义位置 | 用途 | +|------|----------|------| +| `FieldTree` / `Field` | `data.field_tree` | 字段布局定义 | +| `FieldResult` | `data.diff_result` | 字段比对结果 | +| `IRRecord` / `CobolIRField` / `JavaIRField` | `comparator.normalizer` | 中间表示 | +| `RoundingResult` | `comparator.rounding_detect` | 舍入检测结果 | + +## 9. 错误处理 + +### 9.1 错误策略 + +模块采用**严格解析 + 宽容比对**策略: + +| 异常场景 | 处理方式 | 影响 | +|----------|----------|------| +| 二进制文件为空 | 返回空列表 | 无记录可比 | +| 记录不完整 | 跳过该记录 | 部分数据丢失 | +| COMP-3 空数据 | 返回 "0" | 默认零值 | +| EBCDIC 未知字符 | 替换为 `?` | 可能导致 MISMATCH | +| 数值解析失败 | 返回 `None` | NOT_SET 状态 | +| 两侧均无值 | NOT_SET | 不计入匹配统计 | + +### 9.2 已知局限 + +1. `aligner.py` 仅支持单一主键,不支持复合主键 +2. `CobolBinaryReader` 假定所有记录等长,不支持变长记录 +3. `Normalizer.normalize_comp3` 不处理小数位(与 `CobolBinaryReader._comp3` 重复实现) +4. `detect_rounding` 的阈值(2/100)为经验值,未基于统计分析 +5. `field_compare` 的字符串比较未处理 EBCDIC 与 ASCII 的编码差异 diff --git a/docs/detailed-design/07-config-system.md b/docs/detailed-design/07-config-system.md new file mode 100644 index 0000000..576981d --- /dev/null +++ b/docs/detailed-design/07-config-system.md @@ -0,0 +1,474 @@ +# 07 - 配置系统详细设计 + +## 1. 模块概述 + +配置系统(`config/`)是 COBOL 迁移验证平台 V3 的全局管理模块,提供两级配置体系: + +1. **全局配置**(`Config`):项目级参数,包括 LLM 模型、超时、容忍度、Spark 配置、质量门限等 +2. **程序级配置**(`ProgramSchema`):每个 COBOL 程序的 DB 表定义、子程序列表、运行场景 + +此外,`MappingConfig` 提供 COBOL 字段到 Java 字段的映射配置,支持多种转换策略。 + +配置来源包括 TOML 文件(全局)、YAML 文件(程序级 schema 和字段映射)。 + +## 2. 文件清单 + +| 文件 | 职责 | 依赖 | +|------|------|------| +| `__init__.py` | 包入口,公开 API 导出 | `mapping`, `dataclasses` | +| `mapping.py` | COBOL-Java 字段映射配置 | `yaml`, `dataclasses` | +| `program_schema.py` | 程序级 DB schema + 运行场景定义 | `yaml`, `dataclasses` | +| `programs/*.yaml` | 58 个电信程序的 YAML schema 文件 | 无 | + +## 3. 两级配置体系 + +### 3.1 架构图 + +``` +全局配置 (Config) + |-- from_toml("aurak.toml") + |-- LLM 模型/超时/缓存 + |-- Spark 配置 + |-- 质量门限 + |-- gixsql 配置 + | + +-- 程序级配置 (ProgramSchema) + |-- load_schema("KYU04CAL") + |-- db_tables: [TableDef, ...] + |-- subprograms: [str, ...] + |-- runs: [ScenarioDef, ...] + | + +-- 字段映射 (MappingConfig) + |-- from_yaml("KYU04CAL.yaml") + |-- field_mappings: [FieldMapping, ...] + |-- redefines_strategy: dict +``` + +### 3.2 配置优先级 + +1. 命令行参数(最高) +2. 环境变量 +3. TOML 配置文件 +4. YAML schema 文件 +5. 代码默认值(最低) + +## 4. 全局配置(Config) + +### 4.1 数据类定义 + +```python +@dataclass +class Config: + project_name: str = "" + copybook_paths: list = ["./copybooks"] + dialect: str = "ibm" + llm_model: str = "deepseek-v4-flash" + llm_timeout: int = 120 + llm_cache_dir: str = ".cache/llm" + coverage_default: str = "boundary" + rounding_mode: str = "TRUNCATE" + tolerance: float = 0.01 + runner_mode: str = "native" + spark_master: str = "local[*]" + spark_input_format: str = "json" + num_records: int = 1000 + branch_pass: float = 0.80 + max_llm_cost: float = 0.50 + quality_gate_mode: str = "warn" + quality_gate_decision_threshold: float = 0.90 + quality_gate_paragraph_threshold: float = 1.0 + gcov_enabled: bool = False + gcov_work_dir: str = ".gcov_output" + gcov_threshold: float = 0.5 + max_quality_retries: int = 4 + gixsql_path: str = "gixsql/bin/gixpp.exe" + gixsql_lib_path: str = "gixsql/lib" + gixsql_db_path: str = ".db/gixsql" + gixsql_compile_flags: str = "-fixed -ext cpy --coverage" +``` + +### 4.2 配置分组 + +| 分组 | 配置项 | 说明 | +|------|--------|------| +| 项目基础 | `project_name`, `copybook_paths`, `dialect` | 项目标识、COPYBOOK 路径、COBOL 方言 | +| LLM | `llm_model`, `llm_timeout`, `llm_cache_dir`, `max_llm_cost` | 模型选择、超时、缓存、成本控制 | +| 覆盖率 | `coverage_default`, `branch_pass`, `gcov_*` | 覆盖率目标、分支通过率、gcov 集成 | +| 比对 | `rounding_mode`, `tolerance` | 舍入模式、数值容忍度 | +| 运行器 | `runner_mode`, `spark_*`, `num_records` | native/spark 模式、Spark 参数 | +| 质量门限 | `quality_gate_*`, `max_quality_retries` | 决策阈值、段落阈值、重试次数 | +| gixsql | `gixsql_*` | DB 程序编译路径、库路径、编译标志 | + +### 4.3 TOML 加载 + +```python +@classmethod +def from_toml(cls, path="aurak.toml") -> Config +``` + +TOML 文件结构: + +```toml +[project] +name = "..." +copybook_paths = ["./copybooks"] +dialect = "ibm" + +[llm] +model = "deepseek-v4-flash" + +[coverage] +default_target = "boundary" + +[comparison] +rounding_mode = "TRUNCATE" +default_tolerance = 0.01 + +[runner] +mode = "native" + +[spark] +master = "local[*]" +num_records = 1000 + +[gixsql] +path = "gixsql/bin/gixpp.exe" +lib_path = "gixsql/lib" +db_path = ".db/gixsql" +compile_flags = "-fixed -ext cpy --coverage" +``` + +### 4.4 错误处理 + +- TOML 文件不存在或解析失败 -> 返回默认 `Config()` 实例 +- 缺失字段使用默认值填充 + +## 5. 字段映射配置(mapping.py) + +### 5.1 数据类定义 + +```python +@dataclass +class FieldMapping: + cobol_field: str # COBOL 字段名 + java_field: str # Java 字段名 + field_type: str = "string" # 字段类型 + precision: int = 0 # 精度(小数位) + trim: bool = False # 是否去空格 + format: str = "" # 格式化规则 + init_strategy: str = "auto" # 初始化策略 + +@dataclass +class MappingConfig: + program: str = "" # 程序 ID + dialect: str = "ibm" # COBOL 方言 + field_mappings: list[FieldMapping] # 字段映射列表 + redefines_strategy: dict # REDEFINES 处理策略 +``` + +### 5.2 YAML 加载 + +```python +@classmethod +def from_yaml(cls, path: str) -> MappingConfig +``` + +YAML 文件结构: + +```yaml +program: KYU04CAL +dialect: ibm +field_mapping: + - cobol_field: "BR-AMT" + java_field: "billAmount" + field_type: "decimal" + precision: 2 + - cobol_field: "CUST-ID" + java_field: "customerId" + field_type: "string" + trim: true +redefines_strategy: + WS-BLOCK: "overlay" +``` + +### 5.3 字段查询 + +```python +def get_java_field(self, cobol_name: str) -> str +``` + +按 COBOL 字段名查找对应的 Java 字段名,未找到时返回原始 COBOL 字段名。 + +### 5.4 模块级断言 + +```python +_m = FieldMapping(cobol_field="BR-AMT", java_field="billAmount", + field_type="decimal", precision=2) +assert _m.cobol_field == "BR-AMT" +``` + +导入时自动执行结构验证。 + +## 6. 程序级 Schema 配置(program_schema.py) + +### 6.1 数据类定义 + +```python +@dataclass +class ColumnDef: + name: str # 列名 + type: str # SQL 类型(CHAR(6), NUMERIC(4), VARCHAR(30)) + primary_key: bool = False # 是否主键 + nullable: bool = False # 是否可空 + default: Optional[str] = None # 默认值 + cobol_field: Optional[str] = None # 对应 COBOL 字段名 + +@dataclass +class TableDef: + name: str # 表名 + columns: list[ColumnDef] # 列定义列表 + create_if_missing: bool = True # 缺失时自动创建 + sql_name: Optional[str] = None # COBOL SQL 中的表名(可能与 YAML 名不同) + +@dataclass +class SysinDef: + period: str | None = "202607" # 处理期间 + include_invalid_period: bool = False # 是否包含无效期间 + modes: list[str] = ["NORMAL"] # 运行模式列表 + final_mode: str = "RESET" # 最终模式 + +@dataclass +class ScenarioDef: + id: str # 场景 ID + sysin: SysinDef # SYSIN 卡片配置 + inject_duplicate_pk: bool = False # 是否注入重复主键 + row_overrides: dict[str, dict[str, str]] # 行级覆盖 + delete_all_rows: bool = False # 是否清空所有行 + drop_tables: list[str] = [] # 需要删除的表列表 + command_line: str | None = None # 自定义命令行 + seed_extra_rows: dict[str, int] = {} # 额外种子行数 + +@dataclass +class ProgramSchema: + program_id: str # 程序 ID + db_tables: list[TableDef] # DB 表定义列表 + subprograms: list[str] # 子程序列表 + db_type: str = "SQLite" # 数据库类型 + db_name: str = "OVERTIME.DB" # 数据库文件名 + runs: list[ScenarioDef] # 运行场景列表 + coverage_dates: dict[str, list[dict]] # 覆盖率日期配置 + command_line: str | None = None # 全局命令行 +``` + +### 6.2 YAML 加载 + +```python +@classmethod +def from_yaml(cls, path: str | Path) -> ProgramSchema +``` + +### 6.3 Schema 查找 + +```python +def load_schema(program_id: str, search_dirs: list[str | Path] | None = None) -> ProgramSchema +``` + +在 `config/programs/` 目录下按 `{program_id}.yaml` 查找,未找到时抛出 `FileNotFoundError`。 + +## 7. YAML Schema 配置 + +### 7.1 文件结构 + +每个程序对应一个 YAML 文件,位于 `config/programs/` 目录: + +``` +config/programs/ + KYU04CAL.yaml + KYU05DED.yaml + KYU06UPD.yaml + KIN02UPD.yaml + KIN03EXP.yaml + KIN06CLD.yaml + KIN08DBU.yaml + KIN09CSV.yaml + SHA02MNC.yaml + SHA03MNP.yaml + SHA04TWO.yaml + SHA06TWM.yaml + SHA07KBR.yaml + ZAN06UPD.yaml + ... +``` + +### 7.2 YAML Schema 模板 + +```yaml +program_id: {PROGRAM_ID} +db_type: SQLite +db_name: {DB_NAME} + +db_tables: + - name: {COBOL_TABLE_NAME} + sql_name: {SQL_TABLE_NAME} # 可选,COBOL SQL 中的表名 + columns: + - name: {COL_NAME} + type: {SQL_TYPE} # CHAR(N), NUMERIC(N,M), VARCHAR(N), DECIMAL(N,M), TIMESTAMP + primary_key: true/false + nullable: true/false + cobol_field: {COBOL_FIELD} # 可选,对应 COBOL 字段名 + +subprograms: + - {SUB_PROGRAM_ID} + +runs: + - id: {SCENARIO_ID} + sysin: + period: "{YYYYMM}" + modes: ["NORMAL"] + inject_duplicate_pk: true/false + row_overrides: + {TABLE_NAME}: + {COL_NAME}: "{VALUE}" + delete_all_rows: true/false + drop_tables: + - {TABLE_NAME} + command_line: "{COMMAND}" # 可选 + seed_extra_rows: + {TABLE_NAME}: {COUNT} +``` + +### 7.3 SQL 类型映射 + +| YAML 类型 | SQL 类型 | 说明 | +|-----------|----------|------| +| `CHAR(N)` | 定长字符 | COBOL DISPLAY 类型 | +| `VARCHAR(N)` | 变长字符 | COBOL X(n) 类型 | +| `NUMERIC(N)` | 整数 | 无小数位 | +| `NUMERIC(N,M)` | 定点数 | N 位总长,M 位小数 | +| `DECIMAL(N,M)` | 定点数 | 同 NUMERIC | +| `TIMESTAMP` | 时间戳 | 日期时间 | + +### 7.4 运行场景(ScenarioDef) + +每个程序可定义多个运行场景,用于覆盖不同测试路径: + +| 场景类型 | 典型配置 | 说明 | +|----------|----------|------| +| `normal` | 默认 SYSIN | 正常路径测试 | +| `collision` | `inject_duplicate_pk: true` | 主键冲突测试 | +| `abnormal` | 自定义 row_overrides | 异常路径测试 | +| 自定义 | `command_line` | 特殊命令行参数 | + +### 7.5 SYSIN 卡片配置 + +SYSIN 卡片是 COBOL 程序的运行时输入,通过 `SysinDef` 配置: + +- `period`:处理期间(如 `"202607"`),用于时间相关逻辑 +- `modes`:运行模式列表(如 `["NORMAL"]`),影响程序分支 +- `include_invalid_period`:是否包含无效期间测试 +- `final_mode`:最终模式(如 `"RESET"`) + +## 8. 配置加载机制 + +### 8.1 加载流程 + +``` +1. 读取 aurak.toml -> Config.from_toml() +2. 根据 program_id 查找 programs/{id}.yaml -> load_schema() +3. 可选: 读取字段映射 YAML -> MappingConfig.from_yaml() +4. 合并全局配置 + 程序级配置 -> 运行时参数 +``` + +### 8.2 默认值策略 + +- 所有配置项均有代码级默认值 +- TOML/YAML 仅覆盖显式指定的字段 +- 缺失字段回退到 dataclass 默认值 + +### 8.3 已有程序 Schema 统计 + +截至当前,`config/programs/` 目录包含 14 个程序的 YAML schema: + +| 程序 ID | DB 表数 | 子程序数 | 运行场景数 | +|---------|---------|----------|------------| +| KYU04CAL | - | - | - | +| KYU05DED | - | - | - | +| KYU06UPD | - | - | - | +| KIN02UPD | - | - | - | +| KIN03EXP | - | - | - | +| KIN06CLD | - | - | - | +| KIN08DBU | - | - | - | +| KIN09CSV | - | - | - | +| SHA02MNC | - | - | - | +| SHA03MNP | - | - | - | +| SHA04TWO | - | - | - | +| SHA06TWM | - | - | - | +| SHA07KBR | 2 | 2 | 0 | +| ZAN06UPD | 2 | 5 | 3 | + +## 9. 接口定义 + +### 9.1 模块公开 API + +```python +# config/__init__.py +Config # 全局配置 dataclass +MappingConfig # 字段映射配置 +FieldMapping # 单个字段映射 + +# config/mapping.py +MappingConfig.from_yaml(path) -> MappingConfig +MappingConfig.get_java_field(cobol_name) -> str + +# config/program_schema.py +ProgramSchema.from_yaml(path) -> ProgramSchema +load_schema(program_id, search_dirs) -> ProgramSchema +``` + +### 9.2 典型使用模式 + +```python +from config import Config +from config.program_schema import load_schema +from config.mapping import MappingConfig + +# 加载全局配置 +config = Config.from_toml("aurak.toml") + +# 加载程序 schema +schema = load_schema("KYU04CAL") + +# 加载字段映射(如果存在) +mapping = MappingConfig.from_yaml("mappings/KYU04CAL.yaml") +java_field = mapping.get_java_field("BR-AMT") + +# 使用配置 +for table in schema.db_tables: + print(f"Table: {table.name}, SQL: {table.sql_name}") + for col in table.columns: + print(f" {col.name}: {col.type} (PK={col.primary_key})") + +for scenario in schema.runs: + print(f"Scenario: {scenario.id}, Period: {scenario.sysin.period}") +``` + +## 10. 错误处理 + +### 10.1 错误策略 + +| 异常场景 | 处理方式 | 影响 | +|----------|----------|------| +| TOML 文件不存在 | 返回默认 Config | 使用代码默认值 | +| TOML 解析失败 | 返回默认 Config | 使用代码默认值 | +| YAML schema 不存在 | 抛出 FileNotFoundError | 流水线中断 | +| YAML 字段缺失 | 使用默认值填充 | 可能不完整 | +| SQL 类型无法识别 | 原样传递 | 下游处理 | + +### 10.2 已知局限 + +1. `Config.from_toml` 吞掉所有异常,配置错误静默降级 +2. `load_schema` 搜索路径硬编码为 `config/programs/` +3. `MappingConfig` 的 `redefines_strategy` 仅存储字典,无验证逻辑 +4. `ProgramSchema` 的 `coverage_dates` 类型定义为 `dict[str, list[dict[str, str]]]`,缺乏 schema 验证 +5. `SysinDef` 的 `period` 字段无格式校验,允许非法期间值 +6. 程序级 YAML 无统一 schema 验证,依赖调用方保证格式正确 diff --git a/docs/detailed-design/08-data-flow.md b/docs/detailed-design/08-data-flow.md new file mode 100644 index 0000000..07fb5dc --- /dev/null +++ b/docs/detailed-design/08-data-flow.md @@ -0,0 +1,825 @@ +# 数据流设计文档 + +> 版本: v1.0 | 日期: 2026-08-22 +> 本文档描述 COBOL 迁移验证平台 V3 的完整数据流,覆盖非 DB(flat file)管道和 DB(SQL/SQLite)管道。 + +--- + +## 1. 数据流概述 + +### 1.1 设计目标 + +| 目标 | 说明 | 实现方式 | +|------|------|----------| +| **可追溯性** | 每条测试数据可追溯到源码决策点 | 路径约束 (field, op, value, want_true) 记录决策分支选择 | +| **一致性** | 非 DB 与 DB 管道共享同一套解析/生成引擎 | cobol_testgen/ 统一提供 extract_structure + generate_data | +| **容错性** | 单步失败不中断整体管道 | 每步返回 DbPipelineResult(success, data),失败立即终止后续 | +| **可观测性** | 全流程可监控、可调试 | 覆盖率报告、gcov 数据、JSON 中间产物、运行日志 | + +### 1.2 管道对比 + +| 维度 | 非 DB 管道 | DB 管道 | +|------|-----------|---------| +| 编排器 | orchestrator.py | orchestrator_db.py | +| 运行器 | runners/cobol_runner.py | runners/gixsql_runner.py | +| 输入格式 | 固定长度平面文件 | 平面文件 + SQLite DB 种子 | +| 输出格式 | 平面文件 | 平面文件 + SQLite DB | +| 验证方式 | comparator/ 逐字段比对 | Step 6 验证 COBOL/Java 输出一致性 | +| 步骤数 | 4 步(生成-运行-比对-报告) | 6 步(环境-生成-运行-提取-Java-验证) | +--- + +## 2. 非 DB 管道数据流 + +### 2.1 总体流程 + + COBOL 源码 (.cbl) + | + v [输入阶段] + read.py: preprocess() + parse_data_division() + | + v [生成阶段] + core.py: build_branch_tree() -> branch_tree + assignments + | + v + design.py: enum_paths() -> path_infos + | + v + design.py: make_base_record() -> base_record + | + v + design.py: apply_constraint() -> records (测试数据) + | + v [运行阶段] + output.py: output_json() -> 测试数据 JSON + output.py: output_input_files() -> 固定长度平面文件 + | + v + runners/cobol_runner.py: compile() + run() -> 输出文件 + | + v [比对阶段] + comparator/aligner.py: 按主键对齐 COBOL/Java 记录 + comparator/field_compare.py: 逐字段比较 + comparator/normalizer.py: EBCDIC/COMP-3 标准化 + | + v + report/generator.py: 生成 HTML 报告 + +### 2.2 输入阶段 + +**COBOL 源码 -> read.py 预处理 -> DATA DIVISION 解析 -> fields 结构信息** + + COBOL 源码 (fixed/free format) + | + v read.preprocess() + +-- resolve_copybooks(): 展开 COPY 语句 + +-- _is_fixed_format(): 自动检测 fixed/free 格式 + +-- 展开至每行 <=72 字符 (fixed) 或保持原样 (free) + +-- 去除 EXEC CICS/SQL 块、逗号、ALL 关键字 + | + v 预处理后源码 (preprocessed) + | + v read.extract_data_division() + +-- 提取 DATA DIVISION 文本块 + | + v read.parse_data_division() + +-- Lark grammar.lark 解析 (Earley parser, dynamic lexer) + +-- 逐行解析 FieldDef: level, name, PIC, USAGE, VALUE, REDEFINES, OCCURS + +-- PIC 子句解析 -> PicInfo (type, digits, decimal, length, signed) + +-- 返回 list[FieldDef] + | + v expand_occurs() + +-- OCCURS 展开为下标副本: WS-CELL(1), WS-CELL(2), ... + +**输出数据结构:** + + # fields: list[dict] -- 每个字段一个 dict + { + 'name': 'R01EMP-ID', # 字段名 (大写) + 'level': 1, # 层号 (01, 05, 77, 88) + 'pic': 'X(8)', # PIC 子句原始文本 + 'pic_info': { # PIC 解析结果 + 'type': 'alphanumeric', # numeric | alphanumeric | alphabetic + 'digits': 0, # 整数位数 (numeric) + 'decimal': 0, # 小数位数 (numeric) + 'length': 8, # 总长度 (alphanumeric) + 'signed': False, + }, + 'section': 'FILE', # DATA DIVISION 节 + 'occurs': 0, # OCCURS 次数 + 'redefines': None, # REDEFINES 目标 + 'usage': None, # COMP | COMP-3 | BINARY | DISPLAY + 'is_88': False, # 是否 88 级条件 + 'parent': None, # 88 级父字段名 + 'value': None, # VALUE 子句 + 'values': None, # 88 级多值列表 + 'is_filler': False, + } +### 2.3 生成阶段 + +**fields -> core.py build_branch_tree -> design.py enum_paths -> make_base_record -> apply_constraint -> 测试数据** + +#### 2.3.1 分支树构建 + + PROCEDURE DIVISION 文本 + | + v core.build_branch_tree_fallback() + +-- pipeline_bridge: 3秒超时桥接 + | +-- 优先: procedure_parser.py (新解析器, 行级状态机) + | +-- 回退: core._BrParser (旧解析器, 正则驱动) + | + +-- 段落扫描: scan_paragraphs() -> {name: (start, end)} + +-- 逐段解析 IF / EVALUATE / PERFORM / READ / WRITE / MOVE / COMPUTE + +-- 返回 (branch_tree: BrSeq, assignments: dict) + +**分支树节点类型:** + +| 节点 | 类 | 属性 | 说明 | +|------|----|------|------| +| 序列 | BrSeq | children: list | 顺序执行的语句序列 | +| 条件 | BrIf | condition, cond_tree, true_seq, false_seq | IF-ELSE 分支 | +| 评估 | BrEval | subject, subjects, when_list, other_seq | EVALUATE 多分支 | +| 循环 | BrPerform | perf_type, condition, body_seq | PERFORM UNTIL/VARYING | +| 查找 | BrSearch | table_name, is_all, when_list | SEARCH/SEARCH ALL | +| 赋值 | Assign | target, source_info | MOVE/COMPUTE/ADD/SUBTRACT/MULTIPLY/DIVIDE | +| 调用 | CallNode | program_name, using_params | CALL 子程序 | +| 跳转 | GoTo | target, body_seq | GO TO | +| 退出 | ExitNode | exit_type | EXIT PARAGRAPH/PERFORM/PROGRAM | + +#### 2.3.2 路径枚举 + + branch_tree + assignments + | + v design_mcdc.enum_paths() / design.enum_paths() + +-- 遍历分支树,收集每个决策点 (BrIf/BrEval/BrPerform) + +-- 对每个决策点生成 True/False 或 WHEN 分支路径 + +-- MC/DC 约束集: cond.mcdc_sets() -> 每个叶条件的 T/F 独立约束 + +-- 路径约束合并: prior_false 累积(EVALUATE WHEN 入口条件) + +-- PERFORM VARYING: 最后一次迭代约束 (last-iteration) + +-- SEARCH: 表索引约束 + AT END 分支 + +-- 返回 path_infos: list[(constraints, path_assignments, term_type)] + +**路径约束格式:** + + # path_infos 的每个元素 + ( + # constraints: Path = list[Constraint] + [ + ('WRK-MONTH', '>', '0', True), # (field, op, value, want_true) + ('WRK-MONTH', '<', '13', True), + ('R01EMP-ID', '<>', '00000000', True), + ], + # path_assignments: dict -- 赋值表 + { + 'WRK-PREV-EMP-ID': [{'type': 'move', 'source_vars': ['R01EMP-ID']}], + 'DBV-EMP-ID': [{'type': 'move_literal', 'literal': 'A0000001'}], + }, + # term_type: str + 'normal' # 或 'abend' + ) + +#### 2.3.3 测试数据记录生成 + + path_infos + data_fields + | + v design.generate_records() + | + +-- 遍历每条路径 (seq=1,2,3...): + | | + | +-- make_base_record(seq, data_fields) + | | +-- 按 VALUE 子句设置初始值 + | | +-- 按 PIC 类型生成默认值: + | | | +-- numeric: _make_numeric_value(idx, seq, total_digits) + | | | +-- alphanumeric: _make_alpha_value(idx, seq, length) + | | | +-- date: seq_date(record_num) -> YYYYMMDD + | | +-- 返回 base_record: dict {field_name: value} + | | + | +-- Pass A: propagate_assignments(rec, path_assign, data_fields) + | | +-- 模拟赋值传播: MOVE/COMPUTE/READ INTO 等 + | | + | +-- Pass B: apply_constraint(rec, field, op, val, want, ...) + | | +-- trace_to_root(): 沿 MOVE 链追溯到根字段 + | | +-- invert_through_chain(): 反向求解约束值 + | | +-- satisfying_value(): 满足约束的值计算 + | | | +-- numeric: 边界值 +/-1 + | | | +-- alphanumeric: 字典序边界 + | | | +-- date: YYYYMMDD 格式边界 + | | +-- 递归写入 base_record[field] = 满足值 + | | + | +-- Pass B.5: forward propagate (变量间 MOVE 一致性) + | +-- Pass B.75: COMPUTE 重算 (约束修改源字段后) + | +-- get_term_type(path_cons) -> (filtered_cons, term_type) + | + +-- 返回 (records, kept_path_cons, term_types) + +**测试数据记录格式:** + + # records: list[dict] -- 每条记录一个 dict + [ + { + 'R01EMP-ID': 'A0000001', + 'R01DATE': '20250101', + 'R01LINE': '0001', + 'WRK-PREV-EMP-ID': '', + 'WRK-MONTH': '06', + 'DBV-EMP-ID': 'A0000001', + '_assigned_fields': {'R01EMP-ID', 'R01DATE'}, # 内部标记 + '_w02_path': True, # PREV 连锁标记 + }, + # ... 更多记录 + ] +### 2.4 运行阶段 + +**测试数据 -> output.py -> cobol_runner compile/run -> 输出文件** + + records + fd_fields + open_dir + | + v output.output_json() + +-- 按 FD 分组: field_to_fd 映射字段到 FD + +-- 按 open_dir 确定方向: INPUT/OUTPUT/I-O + +-- 按 roles 分类: input/inout -> input 块, output/inout -> expected_output 块 + +-- 不属于任何 FD 的字段 -> working_storage 块 + +-- 输出 JSON: {program, records: [{input, expected_output, working_storage, termination}]} + | + v output.output_input_files() + +-- 仅处理 INPUT/I-O 方向的 FD + +-- 按 FD 分组,每 FD 输出一个 JSON: {stem}_{fd_name}.json + +-- abend 记录单独输出: {stem}_abend_{fd_name}.json + +-- 二进制模式: 按 field offsets 打包为固定长度二进制文件 + | + v flatfile.write_all_files() + +-- analyze_fd_layout(): 解析 FD 记录布局 (字段名/PIC/offset/length) + +-- 按 FD 布局序列化每条记录为固定长度字节 + +-- write_flat_file(): 输出到 outdir/{assign_name} + | + v runners/cobol_runner.compile() + +-- cobc -std=ibm -free -x src.cbl -o exe + | + v runners/cobol_runner.run() + +-- 设置 CWD,复制输入文件到 input/ + +-- subprocess.run(exe) 执行 + +-- 捕获 stdout/stderr,收集输出文件 + +-- 返回 RunResult(success, records, log) + +### 2.5 比对阶段 + +**输出文件 -> aligner.py -> field_compare.py -> normalizer.py -> report/generator.py -> HTML 报告** + + COBOL 输出文件 + Java 输出文件 + | + v comparator/aligner.py: align_records() + +-- 按主键字段 (如 CUST-ID) 分组 + +-- 取两侧键的并集,按字符串排序 + +-- 逐键配对: MATCHED / MISSING_IN_SPARK / EXTRA_IN_SPARK + +-- 返回 list[(cobol_record, java_record, status)] + | + v comparator/normalizer.py: normalize_encoding() + +-- EBCDIC -> ASCII 解码 (EBCDIC_037 映射表) + +-- COMP-3 压缩十进制解码 (nibble -> decimal) + +-- 日期格式标准化 (YYYYMMDD -> YYYY-MM-DD) + | + v comparator/field_compare.py: compare_field() + +-- 按字段类型选择比较策略: + | +-- numeric: Decimal 精度比较 + 容差 (tolerance=0.01) + | +-- date: YYYYMMDD 格式归一化后比较 + | +-- string: strip 后直接比较 + +-- 返回 FieldResult(field_name, status, cobol_value, java_value) + +-- status: PASS / MISMATCH / TOLERATED / NOT_SET + | + v comparator/rounding_detect.py: detect_rounding() + +-- 判断数值差异是否由 COBOL ROUNDED 子句引起 + +-- 计算舍入误差范围 + | + v report/generator.py: ReportGenerator + +-- generate_json(): 输出 JSON 报告 (VerificationRun 数据) + +-- generate_html(): 输出 HTML 报告 + | +-- 覆盖率卡片: 段落覆盖率、分支覆盖率、决策点覆盖率 + | +-- HINA 卡片: 判定类型、确信度 + | +-- 质量评分卡片: quality_score + | +-- 重试历史卡片: heal_retry, simple_retry + | +-- 字段比对表格: PASS/MISMATCH 高亮 + +-- 返回报告文件路径 +--- + +## 3. DB 管道数据流 + +### 3.1 总体 6 步流程 + + COBOL 源码 (含 EXEC SQL) + | + v [Step 1: 环境整备] + step1_setup_environment() + +-- 复制源码到 ASCII 工作目录 + +-- gixpp 预处理 + CONNECT TO 路径修补 + +-- cobc 编译 -> exe_path + | + v [Step 2: 输入数据生成] + step2_generate_inputs(scenario) + +-- extract_structure() -> 分支树 + 赋值表 + +-- generate_all_data() -> 测试数据记录 + +-- _init_database() + _populate_database() -> SQLite DB 种子 + +-- flatfile.write_all_files() -> 平面文件 + | + v [Step 3: COBOL 执行] + step3_run_cobol(scenario) + +-- runner.run() -> 输出文件 + gcov 数据 + | + v [Step 4: 中间数据提取] + step4_extract_intermediate() + +-- SELECT * FROM each table -> W01 JSON + | + v [Step 5: Java 执行] (可选) + step5_run_java() + +-- java -jar migration.jar -i W01.json -o output/ + | + v [Step 6: 验证] + step6_verify() + +-- 比较 Java 输出与 COBOL 期望值 + +-- 返回 VerificationRun (PASS/MISMATCH) + +### 3.2 Step 1: 环境整备 (step1_setup_environment) + +**职责:** gixpp 预处理 + cobc 编译 + + cobol_src_dir/{program_id}.cbl + | + v _copy_sources_to_workdir() + +-- 复制主源码 {program_id}.cbl -> work_dir/src/ + +-- 复制 COPYBOOK (*.cpy) -> work_dir/src/ + +-- 复制子程序 (SUB*.cbl) -> work_dir/src/ + (搜索: cobol_src_dir, sub/, production/sub/, cobol-tna-system/sub/) + | + v runner.preprocess(src, preprocessed/, copybook_dirs) + +-- gixpp 预处理 + CONNECT TO 路径修补 + | gixpp 错误转换: 'data/kin.db' -> 'sqlite://localhost/kin' + | 修补为: 'sqlite:///{db_path}' + | + v runner.compile(pp, exe, copybook_dirs, extra_srcs) + +-- cobc 编译 -> work_dir/bin/{program_id}.exe + +-- 编译日志写入 runtime_dir/logs/compile/ + | + v 返回 DbPipelineResult(step=1, success, data={exe_path, log}) + +**输入:** cobol_src_dir, copybook_dirs, schema.subprograms +**输出:** src_path, pp_path, exe_path + +### 3.3 Step 2: 输入数据生成 (step2_generate_inputs) + +**职责:** COBOL 解析 -> 测试数据生成 -> DB 初始化 -> 平面文件输出 + + src_text + schema + scenario + | + v COBOL 解析 + +-- extract_structure(src_text) -> 分支树 + 赋值表 + +-- generate_all_data() -> 测试数据记录 (白盒+机能+策略) + +-- 后处理: R02APPL-ID 链接 R01APPL-ID + | + v DB 初始化 + +-- 确定 DB 路径(场景分离: {program_id}_{scenario_id}.db) + +-- 清理旧 DB -> _init_database(db_path) + | +-- _create_tables(): 按 YAML schema 创建表 + 主键 + +-- _populate_database(): 注入种子行 + | +-- 解析 COBOL -> 分支树 -> 路径枚举 + | +-- build_db_input(): 生成 DB 输入行 + | | +-- collect_sql_meta(): 提取 SQL 元数据 (SELECT/INSERT/UPDATE/DELETE) + | | +-- _hostvar_root(): WHERE 宿主变量 MOVE 链解析 + | | +-- _resolve_where_hostvar(): 宿主变量追溯到输入记录根字段 + | | +-- 用输入键建种子(与运行时一致) + | +-- 覆盖率驱动数据补充(日期、假期等) + | +-- 区间协调(INSURANCE-RATES / EMP-MASTER) + | +-- INSERT OR IGNORE 写入 DB + +-- _inject_extra_seed_rows(): 大结果集注入 + +-- _inject_sql_error_rows(): PK 冲突行注入 + | + v 记录修补 + +-- records[0].R01EMP-ID = SPACE(触发空社员路径) + +-- 全零 EMP-ID -> SPACE 清洗 + +-- 注入重复 EMP-ID(AGG UPDATE 路径) + +-- _deduplicate_r01_pk(): PK 去重 + +-- _inject_aggregation_boundaries(): 聚合边界数据 + | + v 平面文件输出 + +-- write_all_files(): 全 FD 平面文件 + +-- write_sysin_file(): SYSIN 配置 + | + v 返回 DbPipelineResult(step=2, data={records, flat_files, db_path}) + +**输入:** src_path, pp_path, schema, scenario +**输出:** generated_records, generated_structure, db_path, 平面文件 + +### 3.4 Step 3: COBOL 执行 (step3_run_cobol) + +**职责:** 调用编译后的 COBOL 程序并收集 gcov 覆盖率数据 + + exe_path + schema + scenario + | + v 环境准备 + +-- 创建 runtime/run_{id}/main/{input,output}/ 目录 + +-- 复制生成的平面文件 -> input/ + +-- 复制 JSON -> json/ + | + v 文件方向映射 (_scan_assign_to) + +-- 正则扫描 SELECT/ASSIGN-TO -> {文件名: 方向} + +-- OPEN 语句解析 -> INPUT/OUTPUT 方向确定 + | + v DB 路径准备 + +-- 场景 DB -> 复制到默认 DB 路径 + +-- CWD/data/kin.db(CONNECT TO 路径) + | + v 执行 + +-- 清理前次 .gcda 文件 + +-- runner.run(exe, cwd, db_path, env_overrides, command_args) + +-- 日志写入 runtime_dir/logs/ + | + v gcov 数据收集 + +-- .gcda 从 CWD + exe_dir 复制到 gcov/run_{id}/ + +-- .gcno 同步(共享 .gcno,COPY 不 MOVE) + | + v 返回 DbPipelineResult(step=3, data={returncode, log, ...}) + +### 3.5 Step 4: 中间数据提取 (step4_extract_intermediate) + +**职责:** 从 SQLite DB 导出 Java 程序所需的 JSON 中介数据 + + _current_db_path + schema.db_tables + | + v + +-- 打开 DB + +-- 遍历 schema.db_tables,对每张表执行 SELECT * FROM [table] + +-- 构建 meta = {program_id, tables: {table_name: [rows]}} + +-- 写入 work_dir/intermediate/{program_id}_W01.json + +-- 返回 DbPipelineResult(step=4, data={tables, w01_path}) + +### 3.6 Step 5: Java 执行 (step5_run_java) + +**职责:** 调用 Java 转换程序处理 COBOL 输出数据 + + java_input_path + java_jar + | + v + +-- 创建 java_output 目录 + +-- 构建命令: java -jar {java_jar} -i {java_input_path} -o {java_out} + +-- subprocess.run(cmd, capture_output=True, timeout=60) + +-- 返回 DbPipelineResult(step=5, data={returncode, log}) + +### 3.7 Step 6: 结果验证 (step6_verify) + +**职责:** 比较 Java 输出与 COBOL 期望值 + + java_output_path + _current_db_path + | + v + +-- 构建 VerificationRun 结果对象 + +-- 读取 DB 各表行数(调试信息) + +-- 扫描 java_output_path 下的 .txt/.json 文件 + +-- 设置 exit_code 和 status(PASS/MISMATCH) + +-- 返回 VerificationRun +--- + +## 4. 核心数据结构 + +### 4.1 fields 列表格式 + +fields 是整个数据流的核心数据结构,贯穿输入-生成-运行全流程。 + + # 类型: list[dict] + # 来源: read.parse_data_division() + expand_occurs() + # 用途: 分支树构建、路径枚举、约束应用、JSON 输出 + + [ + { + 'name': str, # 字段名 (大写, 如 'R01EMP-ID') + 'level': int, # 层号 (01, 05, 77, 88) + 'pic': str | None, # PIC 子句原始文本 + 'pic_info': { # PIC 解析结果 + 'type': str, # 'numeric' | 'alphanumeric' | 'alphabetic' | 'unknown' + 'digits': int, # 整数位数 (numeric) + 'decimal': int, # 小数位数 (numeric) + 'length': int, # 总长度 (alphanumeric) + 'signed': bool, # 是否有符号 + }, + 'section': str, # 'FILE' | 'WORKING-STORAGE' | 'LINKAGE' + 'occurs': int, # OCCURS 次数 (0=无) + 'occurs_depending': str | None, # OCCURS DEPENDING ON 目标 + 'redefines': str | None, # REDEFINES 目标字段名 + 'usage': str | None, # 'COMP' | 'COMP-3' | 'BINARY' | 'PACKED-DECIMAL' | 'DISPLAY' + 'is_88': bool, # 是否 88 级条件 + 'parent': str | None, # 88 级父字段名 + 'value': str | None, # VALUE 子句值 + 'values': list[str] | None, # 88 级多值列表 + 'is_filler': bool, # 是否 FILLER + }, + # ... 更多字段 + ] + +### 4.2 Constraint 约束格式 + +Constraint 是路径枚举和约束应用的基本单元。 + + # 类型: tuple (4 元组) + # 定义: models.py 中 Constraint = tuple + # 格式: (field, operator, value, want_true) + + Constraint = ( + str, # field: 字段名 (如 'WRK-MONTH', 'R01EMP-ID') + str, # operator: 比较运算符 ('=' | '<>' | '>' | '<' | '>=' | '<=' | 'not_in') + str, # value: 比较值 (字符串形式, 如 '12', '00000000', 'SPACE') + bool, # want_true: True=满足条件, False=不满足条件 + ) + + # 示例: + ('WRK-MONTH', '>', '0', True) # WRK-MONTH > 0 为真 + ('R01EMP-ID', '<>', '00000000', True) # R01EMP-ID 不等于 00000000 为真 + ('SQLCODE', '=', '100', False) # SQLCODE = 100 为假 (即 SQLCODE != 100) + +### 4.3 Path 路径格式 + +Path 是一条完整执行路径的所有约束集合。 + + # 类型: list[Constraint] + # 定义: models.py 中 Path = list[Constraint] + # 含义: 所有约束同时满足时,程序沿该路径执行 + + Path = [ + ('WRK-MONTH', '>', '0', True), + ('WRK-MONTH', '<', '13', True), + ('R01EMP-ID', '<>', '00000000', True), + ('__DP', '=', 'T', True), # 决策点标记 (设计内部使用) + ] + + # path_infos 格式 (生成记录的输入): + path_infos = [ + # (constraints, path_assignments, term_type) + ( + [Constraint, ...], # 路径约束列表 + {str: list[dict]}, # 赋值表 (目标 -> 赋值操作列表) + 'normal' | 'abend', # 终止类型 + ), + # ... 更多路径 + ] + + # 赋值表 (path_assignments) 格式: + { + 'WRK-PREV-EMP-ID': [ + {'type': 'move', 'source_vars': ['R01EMP-ID']} + ], + 'DBV-EMP-ID': [ + {'type': 'move_literal', 'literal': 'A0000001'} + ], + 'WS-COUNT': [ + {'type': 'compute', 'op': 'add', 'left': 'WS-COUNT', 'right': '1'} + ], + } + +### 4.4 测试数据 JSON 格式 + +测试数据 JSON 是非 DB 管道和 DB 管道共享的输出格式。 + + { + 'program': str, # 程序名 (如 'KIN04CHK') + 'records': [ + { + 'input': { # 按 FD 分组的输入字段 + 'FD_NAME': { + 'FIELD1': str, + 'FIELD2': str, + ... + } + }, + 'expected_output': { # 按 FD 分组的期望输出字段 + 'FD_NAME': { + 'FIELD1': str, + ... + } + }, + 'working_storage': { # 不属于任何 FD 的工作存储字段 + 'WRK-MONTH': str, + 'WS-COUNT': str, + ... + }, + 'termination': str, # 'normal' | 'abend' + }, + # ... 更多记录 + ], + 'db_input': { # DB 管道专用: DB 种子数据 (可选) + 'table_name': [ + {'col1': val1, 'col2': val2, ...}, + ... + ] + } + } +--- + +## 5. 数据流图 + +### 5.1 非 DB 管道完整流程 (Mermaid) + +`mermaid +flowchart TD + A[COBOL 源码 .cbl] --> B[read.py preprocess] + B --> C[read.py parse_data_division] + C --> D[expand_occurs] + D --> E[fields: list dict] + + E --> F[core.py build_branch_tree] + F --> G[branch_tree + assignments] + + G --> H[design.py enum_paths] + H --> I[path_infos] + + I --> J[design.py generate_records] + E --> J + J --> K[records: list dict] + + K --> L[output.py output_json] + L --> M[测试数据 JSON] + + K --> N[output.py output_input_files] + K --> O[flatfile.write_all_files] + N --> P[固定长度平面文件] + O --> P + + P --> Q[cobol_runner compile] + Q --> R[cobol_runner run] + R --> S[COBOL 输出文件] + + S --> T[comparator/aligner align_records] + U[Java 输出文件] --> T + T --> V[记录对 pairs] + + V --> W[comparator/normalizer] + W --> X[comparator/field_compare] + X --> Y[FieldResult list] + + Y --> Z[report/generator generate_html] + Z --> AA[HTML 验证报告] +` + +### 5.2 DB 管道完整流程 (Mermaid) + +`mermaid +flowchart TD + A[COBOL 源码 含 EXEC SQL] --> B[Step 1: 环境整备] + B --> B1[gixpp 预处理] + B1 --> B2[cobc 编译] + B2 --> B3[exe_path] + + A --> C[Step 2: 输入数据生成] + B3 --> C + C --> C1[extract_structure] + C1 --> C2[generate_all_data] + C2 --> C3[records] + + C3 --> C4[flatfile.write_all_files] + C4 --> C5[平面文件 input/] + + C3 --> C6[build_db_input] + C6 --> C7[INSERT INTO SQLite DB] + C7 --> C8[db_path] + + C5 --> D[Step 3: COBOL 执行] + C8 --> D + D --> D1[runner.run] + D1 --> D2[COBOL 输出文件] + D1 --> D3[gcov 数据] + + D2 --> E[Step 4: 中间数据提取] + C8 --> E + E --> E1[SELECT * FROM tables] + E1 --> E2[W01 JSON] + + E2 --> F[Step 5: Java 执行 可选] + F --> F1[java -jar migration.jar] + F1 --> F2[Java 输出文件] + + F2 --> G[Step 6: 验证] + D2 --> G + G --> G1[VerificationRun] + G1 --> G2[PASS / MISMATCH] +` + +### 5.3 数据流关键节点汇总 + +`mermaid +flowchart LR + subgraph 输入层 + A1[COBOL 源码] + A2[COPYBOOK] + A3[YAML schema] + end + + subgraph 解析层 + B1[preprocess] + B2[parse_data_division] + B3[build_branch_tree] + end + + subgraph 生成层 + C1[enum_paths] + C2[generate_records] + C3[build_db_input] + end + + subgraph 输出层 + D1[output_json] + D2[write_all_files] + D3[write_sysin_file] + end + + subgraph 执行层 + E1[cobol_runner] + E2[gixsql_runner] + E3[java -jar] + end + + subgraph 验证层 + F1[aligner] + F2[field_compare] + F3[coverage] + F4[report] + end + + A1 --> B1 --> B2 --> B3 + A2 --> B1 + A3 --> C3 + B3 --> C1 --> C2 + C2 --> D1 + C2 --> D2 + C3 --> D2 + C3 --> D3 + D2 --> E1 + D2 --> E2 + D3 --> E2 + E1 --> F1 + E2 --> F1 + E3 --> F1 + F1 --> F2 --> F4 + B3 --> F3 --> F4 +` + +--- + +## 6. 跨模块数据流转 + +### 6.1 模块间数据传递关系 + +| 源模块 | 目标模块 | 传递数据 | 数据格式 | +|--------|----------|----------|----------| +| read.py | core.py | preprocessed, data_fields | str, list[dict] | +| read.py | design.py | data_fields, open_dir, file_sec | list[dict], dict, dict | +| core.py | design.py | branch_tree, assignments | BrSeq, dict | +| cond.py | design.py | path constraints | list[Constraint] | +| design.py | output.py | records, kept_path_cons, term_types | list[dict], list, list[str] | +| design.py | to_sql.py | records, data_fields, assignments | list[dict], list[dict], dict | +| output.py | runner.py | records (JSON/binary) | dict, bytes | +| runner.py | comparator/ | output files | file paths | +| to_sql.py | orchestrator_db.py | db_input (DB seed rows) | dict[str, list[dict]] | +| flatfile.py | orchestrator_db.py | flat files (binary) | file paths | +| orchestrator_db.py | gixsql_runner.py | exe_path, db_path, env | Path, Path, dict | +| gixsql_runner.py | orchestrator_db.py | RunResult | dataclass | +| comparator/aligner.py | comparator/field_compare.py | aligned pairs | list[tuple] | +| comparator/field_compare.py | report/generator.py | FieldResults | list[FieldResult] | +| coverage.py | report/generator.py | DecisionPoints, coverage rates | list[DecisionPoint], float | +| data_merger.py | __init__.py | merged records | list[dict] | +| hina/strategy.py | data_merger.py | strategy records | list[dict] | + +### 6.2 核心数据流路径 + +**路径 1: 非 DB 管道 (flat file)** + + read.py (fields) -> core.py (branch_tree) -> design.py (records) + -> output.py (JSON + flat files) -> cobol_runner (output files) + -> comparator/ (verification results) -> report/ (HTML) + +**路径 2: DB 管道 (SQL/SQLite)** + + read.py (fields) -> core.py (branch_tree) -> design.py (records) + -> to_sql.py (DB seed rows) -> flatfile.py (flat files) + -> gixsql_runner (output files + DB state) + -> step4 (W01 JSON) -> step5 (Java output) -> step6 (verification) + +**路径 3: 覆盖率收集** + + core.py (branch_tree) -> coverage.py (decision_points) + -> mark_coverage (covered branches) -> gcov.py (dynamic coverage) + -> coverage.py (merged coverage) -> report/ (HTML report) + +### 6.3 关键中间产物 + +| 产物 | 生成位置 | 消费位置 | 格式 | +|------|----------|----------|------| +| preprocessed | read.py | core.py, read.py | str (预处理后源码) | +| data_fields | read.py | core.py, design.py, to_sql.py | list[dict] | +| branch_tree | core.py | design.py, coverage.py | BrSeq | +| assignments | core.py | design.py, to_sql.py | dict | +| path_infos | design.py | design.py (generate_records) | list[tuple] | +| records | design.py | output.py, to_sql.py, flatfile.py | list[dict] | +| fd_fields | read.py | output.py | dict[str, set[str]] | +| open_dir | read.py | output.py, flatfile.py | dict[str, str] | +| file_sec | read.py | output.py, __init__.py | dict[str, list[str]] | +| db_input | to_sql.py | orchestrator_db.py | dict[str, list[dict]] | +| flat files | flatfile.py | runner.py | file paths (binary) | +| JSON | output.py | runner.py, coverage.py | file path | +| gcov data | gcov.py | coverage.py | dict[int, int] | +| DecisionPoints | coverage.py | report/generator.py | list[DecisionPoint] | +| VerificationRun | comparator/ | report/generator.py | dataclass | +| FieldResult | field_compare.py | report/generator.py | dataclass | diff --git a/docs/detailed-design/append_doc.py b/docs/detailed-design/append_doc.py new file mode 100644 index 0000000..7305c75 --- /dev/null +++ b/docs/detailed-design/append_doc.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +"""Append the remaining sections to the design document.""" +from pathlib import Path + +OUT = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-java-v3\docs\detailed-design\01-cobol-testgen-core.md") +content = OUT.read_text(encoding="utf-8") +content = content.replace("PLACEHOLDER", "") + +# Read part2 content +part2 = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-java-v3\docs\detailed-design\part2.md") +content += part2.read_text(encoding="utf-8") + +# Read part3 content +part3 = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-java-v3\docs\detailed-design\part3.md") +content += part3.read_text(encoding="utf-8") + +# Read part4 content +part4 = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-java-v3\docs\detailed-design\part4.md") +content += part4.read_text(encoding="utf-8") + +# Read part5 content +part5 = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-java-v3\docs\detailed-design\part5.md") +content += part5.read_text(encoding="utf-8") + +OUT.write_text(content, encoding="utf-8") +print(f"Document complete: {len(content)} chars, {content.count(chr(10))+1} lines") diff --git a/docs/development-paradigm.md b/docs/development-paradigm.md new file mode 100644 index 0000000..89ea2cf --- /dev/null +++ b/docs/development-paradigm.md @@ -0,0 +1,345 @@ +# 开发范式流程图 + +> 本文档定义 COBOL 迁移验证平台的开发工作流,用于展示团队的开发范式。 + +--- + +## 一、开发流程概览 + +```mermaid +graph TD + A[1. 需求分析] --> B[2. AI方案生成] + B --> C{3. 人工审核} + C -->|通过| D[4. AI编码实现] + C -->|需要修改| B + D --> E[5. 测试验证] + E --> F{6. 质量评审} + F -->|达标| G[7. 交付归档] + F -->|未达标| D + + style A fill:#e1f5fe + style B fill:#f3e5f5 + style C fill:#fff3e0 + style D fill:#f3e5f5 + style E fill:#e8f5e8 + style F fill:#fff3e0 + style G fill:#e8f5e8 +``` + +### 流程说明 + +| 步骤 | 名称 | 负责人 | 说明 | +|:----:|------|:------:|------| +| 1 | 需求分析 | 人工 | 分析COBOL源码结构,明确迁移目标和验收标准 | +| 2 | AI方案生成 | AI | 利用AI分析代码,生成迁移方案和测试策略 | +| 3 | 人工审核 | 人工 | 审核AI方案的可行性和完整性 | +| 4 | AI编码实现 | AI | 根据方案生成代码、测试数据和配置 | +| 5 | 测试验证 | 工具+人工 | 运行测试,验证功能和覆盖率 | +| 6 | 质量评审 | 人工 | 评审测试结果,确认是否达标 | +| 7 | 交付归档 | 人工 | 整理交付物,归档项目文档 | + +--- + +## 二、各阶段详细说明 + +### 1. 需求分析 + +**目标:** 理解COBOL程序的业务逻辑,明确迁移需求 + +**负责人:** 开发团队 + +**输入:** +- COBOL源代码 +- 业务需求文档 +- 迁移规范要求 + +**输出:** +- 需求分析报告 +- 程序清单(含功能描述) +- 验收标准文档 + +**质量标准:** +- 需求覆盖率100% +- 程序分类准确(33+2种类型) +- 验收标准可量化 + +**活动:** +1. 阅读COBOL源码,理解业务逻辑 +2. 识别程序类型(匹配系/键中断系/条件分支系等) +3. 分析数据流向和文件结构 +4. 确定迁移目标和技术约束 +5. 编写需求文档和验收标准 + +--- + +### 2. AI方案生成 + +**目标:** 利用AI生成迁移方案和测试策略 + +**负责人:** AI(DeepSeek) + +**输入:** +- 需求分析报告 +- COBOL源代码 +- 程序分类结果 + +**输出:** +- 迁移方案文档 +- 测试策略报告 +- 技术选型建议 + +**质量标准:** +- 方案完整性检查 +- 技术可行性评估 +- 测试覆盖率目标明确 + +**活动:** +1. AI分析COBOL程序结构 +2. 生成迁移路径建议 +3. 设计测试策略(分支覆盖/MC/DC) +4. 推荐技术方案和工具 +5. 输出方案文档供人工审核 + +--- + +### 3. 人工审核 + +**目标:** 确认AI方案的可行性和完整性 + +**负责人:** 开发团队 + +**输入:** +- AI生成的迁移方案 +- 测试策略报告 + +**输出:** +- 审核意见(通过/修改建议) +- 最终确认的方案 + +**质量标准:** +- 技术可行性确认 +- 风险识别完整 +- 资源评估合理 + +**活动:** +1. 审核AI方案的技术合理性 +2. 评估方案的可行性 +3. 识别潜在风险和问题 +4. 提出修改建议(如需要) +5. 确认最终方案 + +**决策点:** +- 通过 → 进入步骤4(AI编码实现) +- 需要修改 → 返回步骤2(AI方案生成) + +--- + +### 4. AI编码实现 + +**目标:** 根据审核通过的方案生成代码和测试数据 + +**负责人:** AI(DeepSeek) + +**输入:** +- 审核通过的迁移方案 +- 需求文档 +- COBOL源代码 + +**输出:** +- 迁移代码(Python/Java) +- 测试数据文件 +- 配置文件 +- 单元测试脚本 + +**质量标准:** +- 代码规范检查通过 +- 测试数据完整性验证 +- 配置文件格式正确 + +**活动:** +1. AI根据方案生成代码 +2. 创建测试数据和测试用例 +3. 编写配置文件 +4. 生成单元测试脚本 +5. 输出代码供测试验证 + +--- + +### 5. 测试验证 + +**目标:** 验证代码功能和测试覆盖率 + +**负责人:** 工具+人工 + +**输入:** +- 迁移代码 +- 测试数据 +- 测试脚本 + +**输出:** +- 测试报告(通过/失败) +- 覆盖率报告(分支/语句) +- 比对结果报告 + +**质量标准:** +- 测试通过率≥95% +- 分支覆盖率≥80% +- 无严重缺陷 + +**活动:** +1. 运行单元测试(pytest) +2. 执行集成测试 +3. 收集覆盖率数据(gcov) +4. 比对COBOL和Java输出 +5. 生成测试报告 + +**工具:** +- pytest(Python测试) +- gcov(覆盖率收集) +- 自定义比对脚本 + +--- + +### 6. 质量评审 + +**目标:** 评审测试结果,确认是否达标 + +**负责人:** 开发团队 + +**输入:** +- 测试报告 +- 覆盖率报告 +- 比对结果 + +**输出:** +- 评审意见(达标/未达标) +- 改进建议(如需要) + +**质量标准:** +- 所有关键指标达标 +- 无阻塞性问题 +- 风险可控 + +**活动:** +1. 审查测试报告 +2. 分析覆盖率数据 +3. 确认比对结果 +4. 识别未覆盖的分支 +5. 做出质量决策 + +**决策点:** +- 达标 → 进入步骤7(交付归档) +- 未达标 → 返回步骤4(AI编码实现,反馈迭代) + +--- + +### 7. 交付归档 + +**目标:** 整理交付物,归档项目文档 + +**负责人:** 开发团队 + +**输入:** +- 测试报告 +- 覆盖率报告 +- 代码和配置文件 +- 需求文档 + +**输出:** +- 最终迁移报告 +- 代码交付包 +- 验证文档 +- 项目归档 + +**质量标准:** +- 文档完整 +- 代码可追溯 +- 归档规范 + +**活动:** +1. 整理最终报告 +2. 打包代码和配置 +3. 编写交付说明 +4. 归档项目文档 +5. 完成项目总结 + +--- + +## 三、流程特点 + +### 3.1 人机协作 + +| 阶段 | 人/AI | 说明 | +|------|:-----:|------| +| 需求分析 | 人工 | 人工理解业务逻辑 | +| 方案生成 | AI | AI分析代码生成方案 | +| 方案审核 | 人工 | 人工确认可行性 | +| 编码实现 | AI | AI生成代码和测试 | +| 测试验证 | 工具 | 自动化测试执行 | +| 质量评审 | 人工 | 人工确认质量 | +| 交付归档 | 人工 | 人工整理交付 | + +### 3.2 质量门禁 + +| 检查点 | 位置 | 标准 | +|--------|------|------| +| 方案完整性 | 步骤2→3 | 方案包含所有必要内容 | +| 技术可行性 | 步骤3 | 方案技术上可实现 | +| 代码规范 | 步骤4 | 代码符合规范要求 | +| 测试通过率 | 步骤5 | ≥95% | +| 分支覆盖率 | 步骤5 | ≥80% | +| 质量达标 | 步骤6 | 所有关键指标达标 | + +### 3.3 反馈迭代 + +``` +迭代循环: + 步骤4 → 步骤5 → 步骤6 → 步骤4 (如未达标) + +迭代次数: + 通常 1-3 次 + 最多 5 次(超过需重新评估方案) +``` + +### 3.4 可审计性 + +| 特性 | 说明 | +|------|------| +| **步骤可追溯** | 每个步骤有明确的输入输出 | +| **角色可确认** | 每个步骤有明确的负责人 | +| **时间可记录** | 每个步骤的开始和结束时间 | +| **产出物可验证** | 每个步骤的产出物可检查 | + +--- + +## 四、流程图(简化版) + +``` +需求分析 ──→ AI方案生成 ──→ 人工审核 ──→ AI编码实现 + ↑ │ │ │ + │ │ │ │ + │ ↓ │ ↓ + │ (不通过) │ 测试验证 + │ │ │ │ + │ │ │ ↓ + │ │ │ 质量评审 + │ │ │ │ + │ │ │ │ 达标 + │ │ │ ↓ + │ │ │ 交付归档 + │ │ │ │ + └──────────────┴──────────────┴──────────────┘ + (未达标时反馈) +``` + +--- + +## 五、与AI使用日志的关系 + +本流程图定义了开发范式的各个步骤。在实际执行过程中,每个步骤的执行记录会体现在 `_AI_USAGE_LOG.md` 中,包含: + +- 执行时间 +- 执行步骤(对应本流程图的步骤名称) +- 修改摘要 +- 涉及文件 +- 使用的AI模型