Files
cobol-java-v3/docs/detailed-design/07-config-system.md
T

14 KiB
Raw Blame History

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 数据类定义

@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 加载

@classmethod
def from_toml(cls, path="aurak.toml") -> Config

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 数据类定义

@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 加载

@classmethod
def from_yaml(cls, path: str) -> MappingConfig

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 字段查询

def get_java_field(self, cobol_name: str) -> str

按 COBOL 字段名查找对应的 Java 字段名,未找到时返回原始 COBOL 字段名。

5.4 模块级断言

_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 数据类定义

@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 加载

@classmethod
def from_yaml(cls, path: str | Path) -> ProgramSchema

6.3 Schema 查找

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 模板

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

# 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 典型使用模式

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. MappingConfigredefines_strategy 仅存储字典,无验证逻辑
  4. ProgramSchemacoverage_dates 类型定义为 dict[str, list[dict[str, str]]],缺乏 schema 验证
  5. SysinDefperiod 字段无格式校验,允许非法期间值
  6. 程序级 YAML 无统一 schema 验证,依赖调用方保证格式正确