"""Report Phase 4S gates without selecting new parameters or checkpoints.""" from pathlib import Path import json import sys import numpy as np import pandas as pd root=Path('/data/digital-drosophila/experiments/phase4s-timing-credit') r=json.loads((root/'audit/results.json').read_text()) report={'status':r['status'],'timing':r['calibration'],'heldout':r['heldout'],'formal':r['formal'], 'isolated_endpoint':r['isolated']['endpoint'] if r['isolated'] else None, 'isolated_pass':r['isolated']['gate_pass'] if r['isolated'] else None, 'whole':r['whole'],'timing_gate_pass':r['timing_candidate'],'credit_gate_pass':r['credit_candidate'], 'regression_pass':r['regression_pass'],'performance':json.loads((root/'performance/summary.json').read_text()), 'scope':'Open-loop credit accumulation and replay; no learned weights fed back into trial generation; no associative memory claim.'} if (root/'formal/group-trajectory.parquet').exists(): f=pd.read_parquet(root/'formal/group-trajectory.parquet') endpoint=f[f.pairing==100].groupby(['arm','group'],as_index=False).agg( mean_updated_edges=('updated_edges','mean'),mean_delta_E=('mean_delta_E','mean'), mean_total_abs_delta_E=('total_abs_delta_E','mean'),mean_weighted_delta_mv=('total_weighted_delta_mv','mean')) report['group_endpoints']=endpoint.to_dict('records') c=pd.read_parquet(root/'formal/B-contamination.parquet') report['B_contamination_unique_edges']=c.groupby('arm').edge_id.nunique().to_dict() if len(c) else {} trajectory=pd.DataFrame(r['isolated']['trajectory']).groupby('pairing',as_index=False).agg( A_L1=('A','mean'),B_L1=('B','mean'),random_A_L1=('random_A','mean'), A_specific_seeds=('A_specific','sum'),random_specific_seeds=('random_specific','sum')) report['isolated_trajectory']=trajectory.to_dict('records') sys.path.insert(0,'/tmp/malecns-phase4r-plot-20260929/lib/python3.10/site-packages') import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt fig,axes=plt.subplots(1,3,figsize=(15,4.5),layout='constrained') for ax,group in zip(axes[:2],['A-specific','B-specific']): for arm in ('v2_same_US','v2_90ms','v3_matched','v3_random'): z=f[(f.group==group)&(f.arm==arm)].groupby('pairing').total_abs_delta_E.mean() ax.plot(z.index,z.values,marker='.',label=arm) ax.set(title=group+' credit',xlabel='Pairings',ylabel='Mean sum |delta E|');ax.legend(fontsize=8) for name in ('A_L1','B_L1','random_A_L1'): axes[2].plot(trajectory.pairing,trajectory[name],marker='.',label=name) axes[2].set(title='Isolated MBON output change',xlabel='Pairings',ylabel='Mean spike-count L1');axes[2].legend(fontsize=8) (root/'figures').mkdir(exist_ok=True);fig.savefig(root/'figures/credit-and-transfer.png',dpi=180);plt.close(fig) (root/'audit/mechanism-summary.json').write_text(json.dumps(report,indent=2,sort_keys=True)+'\n') lines=['# Phase 4S:时序修复与 credit 特异性验证','',f"状态:`{r['status']}`",'', '本轮只改变外部 US 时序及预注册的局部 eligibility 窗口。全脑动力学、APL、嗅觉 encoder、学习幅度和 14,232 条 plastic mask 保持冻结。', '', '比较采用同一批真实 KC 事件,累积实验性 E overlay;事件采集始终使用未学习的 base brain。结果不构成在线关联记忆声明。',''] if r['calibration']: t=r['calibration'];lines+=[f"校准选择:US={t['US_ms']} ms,window={t['window_ms']} ms,tau={t['tau_ms']:.6f} ms。",''] if r['heldout']: lines+=['独立 seeds 验证:','', '| 气味 | matched/random credit 比值 | 达标 seeds |','|---|---:|---:|'] for x in r['heldout']['odors']:lines.append(f"| {x['label']} | {x['ratio']:.4f} | {x['qualifying_seeds']}/5 |") lines+=['',f"独立 timing gate:{r['heldout']['pass']}。",''] if r['formal']: lines+=[f"正式 A/B credit gate:{r['formal']['gate_pass']}(预注册 100-pairing 终点)。",''] else: lines+=['独立 timing gate 未通过,正式累积权重实验、isolated replay 和 whole-brain 传递实验均未执行。未生成学习产物;不能据此判断这些未执行实验的结果。',''] if r['isolated']: lines+=[f"Isolated gate:{r['isolated']['gate_pass']}。",'', '| Seed | A L1 | B L1 | random A L1 | random B L1 |','|---|---:|---:|---:|---:|'] for x in r['isolated']['endpoint']:lines.append(f"| {x['seed']} | {x['A']} | {x['B']} | {x['random_A']} | {x['random_B']} |") lines+=['','![Credit 与功能传递](../figures/credit-and-transfer.png)',''] lines += [f"Whole-brain:{json.dumps(r['whole'],ensure_ascii=False)}",'', f"冻结参考回归:{r['regression_pass']}。完整 frozen integrity 结果见 `frozen-integrity.json`。",'', '限制:只有两个 calibration odors 和五个独立验证 seeds;credit 改善与刺激特异 MBON 功能变化分别判定。没有根据正式 A/B 或 heldout 结果重新挑参数,没有提前停止在最有利 checkpoint。'] (root/'audit/REPORT.md').write_text('\n'.join(lines)+'\n',encoding='utf-8') print(json.dumps({k:v for k,v in report.items() if k not in ('group_endpoints','isolated_trajectory')},indent=2))