# -*- coding: utf-8 -*- """票 05 全量盘点:.bru 响应示例形态分布 + specimens 覆盖对账。 输出: A) 全仓形态统计(占位/真值/双节/错误码节) B) 占位残留清单(需处理) C) 占位且有真值块(仅需删占位)vs 占位且无真值块(需写数据) D) specimens 合并 key 清单 + 对账钥匙映射缺口 """ from __future__ import annotations import io import json import re import sys from pathlib import Path sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') A4 = Path('D:/code/crm-api-docs/A4 客户管理') SP = Path('.scratch/customer-integration-ready') files = [p for p in A4.rglob('*.bru') if p.name != 'folder.bru'] print(f'[A] 全仓 .bru = {len(files)}(排除 folder.bru)') # ---------- 形态扫描 ---------- ph_files, tv_files, dual_sec, no_sec = [], [], [], [] key_re = re.compile(r'^\s*`\s*(GET|POST)\s+(/[^\s`]+)\s*`', re.M) file_key = {} for p in sorted(files): txt = p.read_text(encoding='utf-8') rel = str(p.relative_to(A4)) has_ph = '非真实返回' in txt has_tv = 'E2E 实测真值' in txt n_sec = len(re.findall(r'^\s*## 响应示例', txt, re.M)) m = key_re.search(txt) if m: file_key[rel] = f'{m.group(1)} {m.group(2)}' if has_ph: ph_files.append(rel) if has_tv: tv_files.append(rel) if n_sec >= 2: dual_sec.append(rel) if n_sec == 0: no_sec.append(rel) print(f'[A] 含占位标记 = {len(ph_files)};含真值标记 = {len(tv_files)};双响应示例节 = {len(dual_sec)};无响应示例节 = {len(no_sec)}') # ---------- 分组 ---------- ph_set, tv_set = set(ph_files), set(tv_files) only_ph = sorted(ph_set - tv_set) # 有占位、无真值 → 必须写回数据 both = sorted(ph_set & tv_set) # 占位+真值并存 → 删占位块即可 print(f'[C] 占位+真值并存(删占位即可)= {len(both)}') for r in both: print(f' {r}') print(f'[C] 占位且无真值(需写数据)= {len(only_ph)}') for r in only_ph: print(f' {r}') # ---------- specimens 合并 ---------- merged = {} for name in ['specimens-core-r3.json', 'specimens-heavy-r3.json', 'specimens-incr-r3.json', 'specimens-graph-r3.json', 'specimens-doc-truth.json']: data = json.loads((SP / name).read_text(encoding='utf-8')) for k, v in data.items(): merged.setdefault(k, {'src': [], 'v': v})['src'].append(name) print(f'[D] {name}: {len(data)} 端点') print(f'[D] 合并后唯一端点 = {len(merged)}') # ---------- 对账钥匙 × specimens 覆盖 ---------- covered = missing = 0 missing_list = [] for rel, k in sorted(file_key.items()): if k in merged: covered += 1 else: missing += 1 missing_list.append(f'{rel} ← {k}') print(f'[D] 文件端点在 specimens 中 = {covered},缺 = {missing}') for r in missing_list: print(f' {r}') Path('.scratch/customer-integration-ready/audit_t05_out.txt').write_text( '\n'.join(['PH:' + r for r in ph_files] + ['TV:' + r for r in tv_files] + ['DUAL:' + r for r in dual_sec] + ['NOSEC:' + r for r in no_sec] + ['MISS:' + r for r in missing_list]), encoding='utf-8') print('[done] 明细 → audit_t05_out.txt')