"""データ統合 — 白盒 + 机能 + 策略データの統合と合併。 generate_all_data() エントリポイント: ① generate_data() → 白盒(MC/DC パスカバレッジ) ② DesignDataGenerator → 机能(式样书から LLM 生成) ③ strategy_supplement() → 策略(HINA 分類に基づく境界条件) ④ 重複除去 + フィールド名正規化 ⑤ 統合リスト返却 """ import logging from pathlib import Path from typing import Optional from cobol_testgen import extract_structure, generate_data logger = logging.getLogger(__name__) def _dedup( main_records: list[dict], additional_records: list[dict] | None = None, key_fields: list[str] | None = None, ) -> list[dict]: """合并+去重,additional 优先保留。""" if not additional_records: return list(main_records) seen = set() result = [] def _hash(rec, keys): if keys: return tuple(rec.get(k, "") for k in keys) return tuple(sorted(rec.items())) for rec in additional_records: h = _hash(rec, key_fields) if h not in seen: seen.add(h) result.append(rec) for rec in main_records: h = _hash(rec, key_fields) if h not in seen: seen.add(h) result.append(rec) return result def generate_all_data( program_id: str, src_text: str, st: dict | None = None, copybook_dirs: list[str | Path] | None = None, design_doc_dir: str | Path | None = None, llm_client=None, config=None, merge_strategy: str = "merge_to_normal", ) -> list[dict]: """白盒 + 机能 + 策略 全量生成と統合。 Args: program_id: プログラム ID src_text: COBOL ソーステキスト st: extract_structure() 結果(省略時は内部で再解析) copybook_dirs: COPYBOOK 探索パス design_doc_dir: 式样书配置ディレクトリ llm_client: LLMClient インスタンス(None で LLM 系スキップ) config: Config インスタンス merge_strategy: merge_to_normal / as_separate_scenes / auto Returns: list[dict]: 統合済みレコードリスト """ cbd = [str(d) for d in (copybook_dirs or [])] # ① 白盒データ if st is None: st = extract_structure(src_text, copybook_dirs=cbd) whitebox = generate_data(src_text, st, copybook_dirs=cbd) logger.info(f" White-box records: {len(whitebox)}") # ② 机能データ(式样书 + LLM) func_data: list[dict] = [] if design_doc_dir and llm_client: design_path = Path(design_doc_dir) / f"詳細設計書_{program_id}.md" if design_path.exists(): from agents.design_data import DesignDataGenerator, _extract_replacing_rules gen = DesignDataGenerator(llm_client, cbd) v3_names = list(st.get("field_names", [])) if st else None replacing = _extract_replacing_rules(src_text) try: func_data = gen.generate( design_md_text=design_path.read_text(encoding="utf-8"), source_text=src_text, replacing_rules=replacing, v3_field_names=v3_names, ) except Exception as e: logger.warning(f" DesignDataGenerator failed: {e}") else: logger.info(f" Design doc not found: {design_path}") logger.info(f" Functional records: {len(func_data)}") # ③ 策略データ strategy_data: list[dict] = [] try: from hina.strategy import supplement strat_raw = supplement([], {}) for s in strat_raw: if isinstance(s, dict) and "fields" in s: strategy_data.append(s["fields"]) except Exception as e: logger.debug(f" Strategy supplement skipped: {e}") logger.info(f" Strategy records: {len(strategy_data)}") # ④ 統合 all_records = _dedup(whitebox, func_data) if strategy_data: all_records = _dedup(all_records, strategy_data) logger.info(f" Total merged records: {len(all_records)}") return all_records