# 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 验证,依赖调用方保证格式正确