from pathlib import Path
import hashlib,json,zipfile
R=Path(__file__).resolve().parent;B=R.parent;H=B/'engineering_handoff_local';sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
T=R/'firmware/固件/lamp_target';C=R/'firmware/固件/lamp_control';build=json.loads((T/'build/build_verification.json').read_text());tests=json.loads((R/'test_results.json').read_text())
assert build['A35_IR_policy_linked'] and not build['led_output_enabled']
for n in ['lamp_guard.c','lamp_guard.h']:
 assert sha(C/n)==sha(B/'lamp_ir_A35/lamp_control'/n)
checks={'status':'A37_LOCAL_IR_POLICY_TARGET_LINK_AND_CONTACT_SAMPLING_PASS_FABRICATION_HOLD','tests':tests,'boot_regression':json.loads((R/'boot_test_results.json').read_text()),'target_build':build,'linked_guard_sha256':sha(C/'lamp_guard.c'),'guard_header_sha256':sha(C/'lamp_guard.h'),'physical_verified_requirements':0,'reference_requirements':20,'physical_testing':'NOT_RUN_NO_SAMPLE','fresh_CAD_checks_run':False,'BOM_changed':False,'physical_IR_interface':'UNIMPLEMENTED; PC15 pin3 still NC','NTC_ADC_and_supply':'UNIMPLEMENTED; readiness held false','LED_driver_health':'UNIMPLEMENTED; readiness held false'}
(R/'checks.json').write_text(json.dumps(checks,ensure_ascii=False,indent=2)+'\n')
report=f'''# 灯具红外策略目标集成与安全输入采样 A37

状态：本地源代码回归、实际启动函数寄存器回归、完整目标固件编译链接及调用路径静态核验通过。FABRICATION_HOLD；三款整机20项实测仍0项验证。

## 实际完成

A35 的独立红外门控 `lamp_guard.c/h` 已原样合入 A37 的完整目标固件，两文件 SHA 与 A35 核对一致。新增 `lamp_board_inputs_read` 从 PCA 安全控制分支的 PA12（物理脚17温控触点）、PA0（联锁）、PB0（按键）读取实际 IDR。主循环及每个完整串口命令/AI结果处理前都重新采样并调用 `lg_poll`；仍由主循环单上下文操作 guard。原先 A36 的物理脚映射启动修订保留。

温控触点闭合不能代替已校准 NTC 温度。采样结果单独保留温控、联锁和按键的原始状态，供调试查看；只有联锁原始状态送入相应 guard 字段。由于红外、NTC、供电 ADC、LED 驱动健康反馈还未落地，其授权字段保持 false。没有把 AI_RESULT 的 `hand_present` 当作物理红外，没有伪造输入就绪；按键只采样，未绑定动作。

## 验证

- 128组 GPIO组合检验 PA12/PA10 别名隔离、热触点/联锁/按键状态、读操作不改变寄存器，以及未知输入不能授权。测试先在明确的主机模拟就绪环境下产生 AI 输出，再经实际采样器和 `lg_poll` 撤销输出及待处理票据；这是主机MMIO模型，不是通电实测。
- A35红外缺席、移手、重入、迟到包、定时及回绕回归通过；guard33项输出不变量、程序44项、UI55/110项、串口到策略、票据派发、原有输出适配器模拟测试通过。全部使用 ASan/UBSan。原有正向测试中明确添加模拟 IR=true，未改变目标硬件授权。
- 8组 A36 实际启动函数寄存器测试再次通过，旧启动代码负对照继续失败。
- 完整 Cortex-M0+ 编译链接通过，FLASH {build['flash_binary_bytes']}字节。BIN SHA256 `{build['sha256_bin']}`。静态验证检查 main 可达的采样和 `lg_poll` 调用。

## 尚未实现与配对限制

guard 仍未配置校准或授权，输出适配器未绑定，未踢外部看门狗；目标保持LED关断。A37 合入的是红外策略，物理 IR 接口仍未连接，PC15/物理脚3仍 NC。NTC/电压电流ADC、驱动读回、配置/会话与光学标定仍待完成。没有修改CAD，不新增ERC/DRC结论。仅配对 PCA9956B lamp_safety 分支，不能直接用于 IS31FL3236A SDB_N 相反极性分支。

## 交付与下一步

包内可编辑全部目标和控制源、ELF/BIN/MAP、测试、日志与 SHA 清单。运行 `sh run_checks.sh`，需要 cc/Python3/arm-none-eabi 工具链；所有必要源码路径均在包内。此次未增加 BOM 元件；不能据此认定千台整机成本达标。下一步完成红外物理接口、NTC及电源测量通道，再接驱动健康反馈与输出闭环；仍需三款整机的结构/负载/温升/效果台架验证，不能将策略或编译通过当作功能效果等同原产品。未采购、联系供应商、烧录或通电。
'''
(R/'README.md').write_text(report);(H/'A37-lamp-target-input-integration.md').write_text(report)
files=[p for p in R.rglob('*') if p.is_file() and not p.name.startswith('.') and p.name not in ['prepare.py','finish.py'] and p.suffix in ['.c','.h','.py','.sh','.md','.json','.log','.txt','.elf','.bin','.map','.s','.ld']]
manifest=''.join(f'{sha(p)}  {p.relative_to(R).as_posix()}\n' for p in sorted(files));(H/'A37-SHA256SUMS.txt').write_text(manifest)
z=H/'Lamp-target-IR-policy-and-input-sampling-A37.zip'
with zipfile.ZipFile(z,'w',zipfile.ZIP_DEFLATED) as a:
 for p in files:a.write(p,p.relative_to(R).as_posix())
 a.writestr('SHA256SUMS.txt',manifest)
with zipfile.ZipFile(z) as a:
 assert a.testzip() is None
 for line in manifest.splitlines():
  digest,name=line.split('  ',1);assert hashlib.sha256(a.read(name)).hexdigest()==digest
 count=len(a.namelist())
j=json.loads((H/'LOCAL-PACKAGES.json').read_text());j['status']=checks['status'];j['latest_report']='A37-lamp-target-input-integration.md';j['latest_machine_report']='../lamp_input_A37/checks.json';j['latest_manifest']='A37-SHA256SUMS.txt'
j['packages'].append({'archive':z.name,'sha256':sha(z),'bytes':z.stat().st_size,'zip_entries':count,'manifest_entries':len(files),'zip_crc':'PASS','manifest_readback':'PASS','manufacturing_status':'FABRICATION_HOLD'})
j['latest_lamp_safe_firmware_A37']={'source':'../lamp_input_A37/firmware/固件/lamp_target','binary_sha256':build['sha256_bin'],'branch':'PCA9956B lamp_safety','A35_policy_linked':True,'physical_contact_GPIO_sampling_bound':True,'IR_GPIO_binding':'UNIMPLEMENTED','led_output_enabled':False,'physical_test_release':False}
j['latest_lamp_IR_policy_A35']['target_linked']=True;j['latest_lamp_IR_policy_A35']['linked_candidate']='../lamp_input_A37/firmware/固件/lamp_target'
j['lamp_clean_build']={'report':'../lamp_input_A37/firmware/固件/lamp_target/build/build_verification.json','binary_sha256':build['sha256_bin'],'physical_validation':'NOT_RUN_NO_SAMPLE','led_output_enabled':False,'scope':'A37 current PCA branch hard-off review image; A35 policy linked, physical IR absent'}
(H/'LOCAL-PACKAGES.json').write_text(json.dumps(j,ensure_ascii=False,indent=2)+'\n')
print(json.dumps(j['packages'][-1],indent=2))
