from pathlib import Path
import json,openpyxl,hashlib,re
ROOT=Path('/Users/jack/code/010-cpt/008-zhct/zhctprompt');R=Path(__file__).resolve().parent
w=openpyxl.load_workbook(next(R.glob('交付*.xlsx')),data_only=True)
m=json.loads((R/'source/manifest.json').read_text());assert hashlib.sha256(Path(m['original']).read_bytes()).hexdigest()==m['sha256'];assert hashlib.sha256((R/m['snapshot']).read_bytes()).hexdigest()==m['sha256']
raw=json.loads((R/'source/original-rows.json').read_text());s=w['原计划完整保留'];norm=lambda v:'' if v is None else str(v)
for i,row in enumerate(raw[1:],2):assert [norm(s.cell(i,c).value) for c in range(1,14)]==[norm(x) for x in row],i
mapping=json.loads((R/'source/task-map.json').read_text());assert len(mapping)==36
library=json.loads((R/'source/task-library.json').read_text());ids={x[0] for x in library};assert len(ids)==len(library)==62
lw=openpyxl.load_workbook(next((ROOT/'modules/presales-bidding/workflows/2026-10-08-presales-contract-scope/v02-service-work-alignment').glob('虚拟*.xlsx')),data_only=True)
labels={row[0] for row in list(lw['统一标签字典'].values)[1:]};assert all(x[2] in labels for x in library)
assert all(z in ids for v in mapping.values() for z in v)
flows=['部队内网流程','政府政务流程','国央企集成流程','企业标准流程','学校多账户流程','医院多部门流程']
for flow in flows:
 rows=list(w[flow].values)[1:];assert len(rows)==52
 ids={x[0] for x in rows};deps={x[0]:[z for z in (x[8] or '').split(',') if z] for x in rows}
 assert all(z in ids for v in deps.values() for z in v)
 assert all(x[10] is None and x[11] is None and x[12]=='待指定' and x[13]=='待安排' for x in rows)
 done=set();pending=set()
 def visit(n):
  assert n not in pending,('cycle',flow,n)
  if n in done:return
  pending.add(n)
  for dep in deps[n]:visit(dep)
  pending.remove(n);done.add(n)
 for n in ids:visit(n)
 assert len(deps['P10'])==10
 order={x[0]:i for i,x in enumerate(rows)}
 assert all(order[d]<order[task] for task,ds in deps.items() for d in ds)
 assert len(ids-set(x[0] for x in list(w['通用任务库'].values)[1:51]))==2
assert w['旧新任务对应'].max_row-1==36
assert {w['人员建议分工'].cell(i,1).value for i in range(2,7)}==set(m['delivery_staff'])
for sheet in w:
 for row in sheet:
  for c in row:
   assert c.data_type!='e'
   if isinstance(c.value,str):assert not re.search(r'(?i)\bCpt@\d+|\b(?:\d{1,3}\.){3}\d{1,3}\b|(?:password|token|secret)\s*[:=]\s*\S+',c.value),(sheet.title,c.coordinate)
result={'status':'PASS','old_tasks':36,'new_task_library':62,'shared_tasks':50,'specialized_tasks':12,'flows':6,'tasks_per_flow':52,'delivery_staff':5,'all_dependencies_exist':True,'dependency_cycles':0,'predecessors_before_dependents':True,'source_rows_preserved':True,'new_dates_blank_and_status_unassigned':True,'shared_tags_valid':True,'source_original_unchanged':True,'sheets':len(w.sheetnames)}
(R/'validation.json').write_text(json.dumps(result,ensure_ascii=False,indent=2));print(json.dumps(result,ensure_ascii=False))
