Compare commits

...
Author SHA1 Message Date
ClaudeandClaude Opus 5.5 f4ae028154 evidence: digest reads DFG Re20 result.json of schema 1 or 2
final_physical_digest.py indexed [0] on the bare-list (schema 1) native
receipt. v4_cases() accepts schema 1 and the versioned schema-2 object
and rejects others. Existing outputs and final-physical-digest.json are
unchanged; that digest records the previous postprocessor hash, so a
rerun with this version is a new digest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 18:36:44 +00:00
Frank14f 70f66176bc docs: record six-case physical validation evidence for 750e8a4
Preserve native gate outcomes and source/output hashes. No simulation or production source changes.
2026-10-20 22:46:29 +08:00
3 changed files with 3162 additions and 0 deletions
@@ -0,0 +1,76 @@
待 Grok 独立复核:750e8a4 本轮六例物理验证
==========================================
固定候选 `750e8a483ec47dcf472e528edc1cf2936f0e7e83`,工作树 `/home/frank14f/CelerisLab-release-prep-20261020` 干净。六例全部完成、退出码 0、无超时;调度器和六个子进程均已消失,最终 `nvidia-smi` 无计算进程。206 个源码/测试/文档哈希与启动 manifest 一致,各例运行前后 source map 相同,原生结果与外部摘要一致;V2 原生源码捕获及 runner 哈希也一致。V4 采用外部 manifest 绑定,没有冒称 runner 内部具备同样 provenance。没有新实验、阈值变更、源码变更、main 合并或公开发布。
六例状态及进程墙钟秒数:V2 zero refined `periodic` 511.409,zero uniform `periodic` 325.254;fixed refined `driven_diagnostics_complete` 530.173,fixed uniform 同状态 333.016;V4 refined `NOT_STEADY` 315.714,uniform `NOT_STEADY` 114.183。墙钟包含初始化和观测开销,仅用于执行记录,不能作正式性能比较。
**V2 zero:MRT、unshifted,均达到 t*=300。** 每例 3480 条 history;refined 1.2M steps,uniform 2.4M steps。各提取 14 个 t*>250 的周期,末五周期全部原生周期门槛通过,各自与冻结参考比较通过。
| 周期指标 | refined | uniform | 原门槛 |
|---|---:|---:|---:|
| 末五周期范围 | 281.663875–298.232508 | 281.590556–298.153468 | 起点>=250,5 个连续周期 |
| period min / max | 3.311073 / 3.316868 | 3.311314 / 3.314196 | 每周期严格在 (2,5) |
| period ptp/mean | 0.00174873 | 0.000869972 | <=0.005 |
| 末周期距最后力采样 | 1.757492 | 1.836532 | [0,5] |
| 连续周期最大间隙 | 0 | 0 | <1e-8 |
| 最小 Cl peak-to-peak | 2.003137 | 1.998667 | >=0.2 |
| Cd_min / Cd_max 跨周期 range | 8.14323e-5 / 1.39714e-4 | 2.60406e-4 / 8.66420e-5 | 每项<=0.005 |
| Cl_min / Cl_max 跨周期 range | 1.96279e-4 / 1.15290e-4 | 1.59490e-4 / 1.82477e-4 | 每项<=0.005 |
| dp_min / dp_max 跨周期 range | 5.50774e-4 / 5.87194e-4 | 8.12699e-4 / 7.99311e-4 | 每项<=0.005 |
| 周期质量均值 ptp/abs(mean) | 3.61945e-8 | 8.51505e-9 | <=1e-4 |
| 最大周期均值 flux_relative | 6.35676e-6 | 5.22752e-5 | <=0.005 |
末周期实际值:refined period=3.312817588、St=0.301857852、Cd=[3.160863689,3.234990541]、Cl=[-1.019161308,0.984224152]、dp=[2.404928344,2.499337133];uniform period=3.311313790、St=0.301994937、Cd=[3.161468623,3.231458726]、Cl=[-1.016677997,0.982020469]、dp=[2.420541455,2.513318511]。
| 末周期参考误差 | refined | uniform | 原门槛 |
|---|---:|---:|---:|
| Cd_min / Cd_max 相对误差 | 0.00107520 / 0.00235425 | 0.000884026 / 0.00125993 | 每项<=0.02 |
| Cl_min / Cl_max 绝对误差 | 0.00212432 / 0.00234646 | 0.00460763 / 0.00455014 | 每项<=0.03 |
| dp_min / dp_max 相对误差 | 0.00638037 / 0.00306172 | 0.0000703422 / 0.00251519 | 每项<=0.02 |
| St 相对误差 | 0.0000558054 | 0.000509970 | <=0.02 |
| Cd / Cl / dp waveform RMS | 0.00472589 / 0.00216188 / 0.0117979 | 0.00317231 / 0.00337428 / 0.00382206 | 描述指标,不是 gate |
`matched_case_pass=false` 原样保留:四次 V2 调用均选择单 case,runner 只有 `--case both` 的两结果原生比较分支才赋值这一字段。它不等于 zero 的各自周期或参考比较失败,也不能由执行者自行改为 true;本轮没有运行该 paired-case 原生比较。fixed 没有官方 DFG 参考 verdict,完成执行不等于物理验收。
**Fixed Jet 健康与 CV。** 两例达到 t*=300,五个 250–300 诊断窗均完整。原健康规则为 physical leaf 数据及 impulse 有限、rho_min>=0.5、rho_max<=1.5、Mach<=0.2。所有 3480 条 history 均有限,观测数值如下。
| 指标 | refined | uniform |
|---|---:|---:|
| 全序列 rho min / max | 0.994218661 / 1.004163150 | 0.993391573 / 1.004678726 |
| 全序列 max Mach | 0.0422925943 | 0.0421810197 |
| mass t*=0.5 / t*=300 | 0.8931541481 / 0.8931214909 | 0.8936680602 / 0.8936524063 |
| 上述端点质量相对变化 | -3.65640e-5 | -1.75164e-5 |
| t*=290–300 mass ptp/mean | 8.40337e-5 | 6.31000e-5 |
| 290–300 Cd / Cl 均值 | 3.184020005 / -0.580990812 | 3.182612828 / -0.582235721 |
CV 各 501 个端点,间距 t*=0.02,积分区间 290–300(root time 40000)。排除首端点之前的 impulse,只累加后 500 个区间;root reaction impulse refined=(254.721600438,-46.479264945),uniform=(254.609026243,-46.578857642)。两条矩形轮廓 refined 为 (48,44,160,120)/(44,36,180,128),uniform 的 x 坐标均加 0.25。以原式 `J_CV=-ΔP-∫outward_momentum_flux dt`,残差为 `J_CV-J_raw`,系数除以 `duration*0.5*U_root²*D_root=80`。这里是 wall+aperture 原始流体对物体反作用,不是已修正的 nozzle thrust。
| 动量残差系数 (x,y) | refined | uniform |
|---|---|---|
| 内轮廓、stride1 | (2.24958e-4,-1.00611e-4) | (1.78190e-4,-7.24811e-5) |
| 外轮廓、stride1 | (7.88038e-5,-4.35879e-5) | (-8.30841e-5,-1.99246e-5) |
| 外减内 | (-1.46155e-4,5.70231e-5) | (-2.61274e-4,5.25565e-5) |
| stride2 相对 stride1 最大分量差 | 1.18312e-5 | 2.19402e-5 |
| stride4 相对 stride1 最大分量差 | 4.44884e-5 | 6.26044e-5 |
CV 未定义验收门槛,以上仅为离线积分诊断。质量记录缺少 raw `mass_into_fluid` Jet 源账本,无法扣除质量源判断闭合。`ΔM+∫outward_mass_flux dt` 仅是表观质量源:refined 内/外=-0.0172316912/-0.646617293 root mass;uniform=3.519017515/3.575029022。相对初始 CV 库存分别 (-2.37505e-6,-5.74501e-5)/(4.84891e-4,3.17573e-4)。轮廓间质量差异保留供审查,不能据此宣称质量闭合通过。
**V4:SRT,无 Jet,t*=60。** uniform 480k/refined 240k steps,各 120 个样本。末窗 t*=50–60 共 21 点;drift 是原 runner 的 `abs(OLS slope per t*)*10`。
| case / 指标 | 末窗 range | 原 range 上限 | 末窗 drift | 原 drift 上限 |
|---|---:|---:|---:|---:|
| refined Cd | 9.86614e-4 | 0.002 | 4.68834e-6 | 0.0004 |
| refined Cl | 6.95374e-5 | 6e-5 | 3.28188e-6 | 1.2e-5 |
| refined p_diff | 1.45066e-4 | 4e-5 | 9.28999e-6 | 8e-6 |
| uniform Cd | 1.19061e-3 | 0.002 | 1.60374e-4 | 0.0004 |
| uniform Cl | 7.93289e-5 | 6e-5 | 5.92289e-6 | 1.2e-5 |
| uniform p_diff | 1.27157e-4 | 4e-5 | 2.80735e-5 | 8e-6 |
两例均有 Cl range、p_diff range/drift 超限,保持 `steady=false,status=NOT_STEADY,verdict=null`。末窗均值 refined=(Cd 5.588876919,Cl 0.010732806,p_diff 0.117811546),uniform=(5.586439289,0.010680915,0.117402607)。原区间 Cd=[5.57,5.59]、Cl=[0.0104,0.011]、p_diff=[0.1172,0.1176];refined 压差均值在区间外,uniform 均值在区间内,但均不能越过稳态 gate。
120 点全序列(t*=0.5–60)存在初始瞬态和反复起伏:refined Cd/Cl/p_diff 的增量符号变化次数为 82/80/82,uniform 为 79/78/81;末窗仍为 13/13/14 和 12/13/11。末窗有符号 OLS slope per t* refined=(-4.68834e-7,-3.28188e-7,-9.28999e-7),uniform=(-1.60374e-5,+5.92289e-7,-2.80735e-6)。这只是当前采样分辨率下的非单调时序描述,不能确定振荡频率、物理/数值根因,也不是发散或瓶颈结论。完整 JSON 保留全序列及逐 10 t* 窗统计。边界偏差仍为 pressure-NEQ/neq_extrap outlet 与 local Zou-He inlet,不能称为原始 do-nothing DFG 边界。
**复核边界与证据。** 本轮不是发布通过:短套件仍为 767 passed/24 failed/1 skipped;V1 历史 pin 阻塞,V3 四例原 TG dry-run 均被 frozen-source guard 拒绝、尚无 CUDA 计算或 TG 结果;未接纳待修订 `56004f44`,没有修改 dtype/NumPy/数值核心。下一步由 Claude 提交修订和解释、Grok 独立复核,再由集成任务接受明确通过审查的 SHA。
原始证据根 `/home/frank14f/CelerisLab-release-evidence-20261020/physical-750e8a4/followup-queue`。`final-physical-digest.json` 约 99 KB,含全部六例原生小摘要、门槛、CV 抽稀结果、源/输出哈希、进程检查和限制;后处理脚本 `final_physical_digest.py` 不导入或运行模拟器。原始 history/log 只保留在 Horsea,没有上传巨量日志。
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,94 @@
"""Read-only postprocessing of the six existing, authorized simulation outputs."""
import csv
import hashlib
import json
import math
from pathlib import Path
import subprocess
import datetime
import numpy as np
Q = Path('/home/frank14f/CelerisLab-release-evidence-20261020/physical-750e8a4/followup-queue')
R = Path('/home/frank14f/CelerisLab-release-prep-20261020')
SHA = '750e8a483ec47dcf472e528edc1cf2936f0e7e83'
def read(p):
return json.loads(p.read_text())
def v4_cases(data):
"""DFG Re20 result.json: schema 1 is a bare case list, schema 2 is {schema, provenance, cases}."""
if isinstance(data, list): return data
if isinstance(data, dict) and data.get('schema') == 2: return data['cases']
raise ValueError('unknown DFG Re20 result schema')
def sha(p):
return hashlib.sha256(p.read_bytes()).hexdigest()
def cmd(*a):
return subprocess.check_output(a, text=True).strip()
def span(a):
return float(np.ptp(a))
def finite(x):
if isinstance(x, dict): return all(finite(v) for v in x.values())
if isinstance(x, list): return all(finite(v) for v in x)
return not isinstance(x, (int,float)) or math.isfinite(x)
def stats(rows, key):
t=np.array([v['tstar'] for v in rows]); v=np.array([r[key] for r in rows])
d=np.diff(v); nz=np.sign(d[d!=0])
return dict(samples=len(v),first=float(v[0]),last=float(v[-1]),min=float(min(v)),max=float(max(v)),mean=float(np.mean(v)),range=span(v),ols_slope_per_tstar=float(np.polyfit(t-t[0],v,1)[0]),increment_sign_changes=int(np.count_nonzero(nz[1:]!=nz[:-1])),total_variation=float(np.abs(d).sum()))
state=read(Q/'state.json'); manifest=read(Q/'manifest.json'); execution=read(Q/'execution.json')
out=dict(schema=1,utc=datetime.datetime.now(datetime.timezone.utc).isoformat(),sha=SHA,evidence_root=str(Q),postprocessor_sha256=sha(Path(__file__)),scope='Offline read-only digest; no new simulation, gate edit, acceptance promotion, or performance claim',verification={},cases={})
v=out['verification']; v['all_six_completed']=len(state['jobs'])==6 and all(x['status']=='COMPLETED' for x in state['jobs'].values())
v['all_exit_zero_no_timeout']=all(x['exit_code']==0 and not x['timeout'] for x in state['jobs'].values())
v['head']=cmd('git','-C',str(R),'rev-parse','HEAD');v['git_status_porcelain']=cmd('git','-C',str(R),'status','--porcelain');v['clean_fixed_head']=v['head']==SHA and not v['git_status_porcelain']
v['tree']=cmd('git','-C',str(R),'rev-parse','HEAD^{tree}');v['src_tree']=cmd('git','-C',str(R),'rev-parse','HEAD:src')
v['tracked_source_map_matches_manifest']=all(sha(R/p)==h for p,h in manifest['files_sha256'].items());v['tracked_source_map_count']=len(manifest['files_sha256'])
v['execution_final_source_matches_manifest']=all(execution['source_after'][k]==manifest[k] for k in ['sha','tree','src_tree','git_status','git_diff_sha256','files_sha256'])
pids=[state['scheduler_pid']]+[x['pid'] for x in state['jobs'].values()]
v['tracked_processes']={}
for pid in pids:
p=subprocess.run(['ps','-p',str(pid),'-o','pid=,ppid=,stat=,comm='],capture_output=True,text=True)
v['tracked_processes'][str(pid)]=p.stdout.strip() or 'absent'
v['no_tracked_process_running']=all(s=='absent' or ' Z' in s for s in v['tracked_processes'].values())
v['gpu_compute_processes']=cmd('nvidia-smi','--query-compute-apps=gpu_uuid,pid,process_name,used_gpu_memory','--format=csv')
out['hashes']={p.name:sha(p) for p in [Q/'manifest.json',Q/'execution.json',Q/'state.json',Q/'queue-plan.json',Q/'receipt-preflight.json',Q/'authorized_followup_queue.py',Q/'v4_external_timing.py']}
for label,sj in state['jobs'].items():
p=Q/label; r=read(p/'result.json'); c=out['cases'][label]=dict(status=sj['native_status'],exit_code=sj['exit_code'],timeout=sj['timeout'],process_wall_seconds=sj['wall_seconds'],pid=sj['pid'],gpu_uuid=sj['gpu_uuid'],source_unchanged=r['source_unchanged'])
c['source_matches_manifest']=all(r['source'][k]==manifest[k] and r['source_after'][k]==manifest[k] for k in ['sha','tree','src_tree','git_status','git_diff_sha256','files_sha256'])
c['external_manifest_hash_matches']=r['external_manifest_sha256']==sha(Q/'manifest.json')
c['hashes']={str(z.relative_to(p)):sha(z) for z in [p/'command.json',p/'result.json',*sorted((p/'output').rglob('*.json')),*sorted((p/'output').rglob('*.csv')),*sorted((p/'output').rglob('*.jsonl'))]}
if label.startswith('v4'):
n=v4_cases(read(p/'output/result.json'))[0]; rows=n['rows']
captured=r['native_results'][0]
c['native_receipt_matches_external_result']=all(n[k]==z for k,z in captured.items() if k not in ['last_row','rows_count']) and captured['last_row']==rows[-1] and captured['rows_count']==len(rows)
c['external_receipt_history_handling']='V4 external receipt stores row count and last row; full native rows are separately hashed'
c['native_all_finite']=finite(n)
c['native']={k:z for k,z in n.items() if k not in ['rows','lattice']}
c['full_series']={k:stats(rows,k) for k in ['cd','cl','p_diff']}
c['ten_tstar_windows']={str(a):{k:stats([z for z in rows if a<=z['tstar']<=a+10],k) for k in ['cd','cl','p_diff']} for a in range(0,60,10)}
c['last_window']=dict(tstar=[50,60],metrics={k:stats(rows[-21:],k) for k in ['cd','cl','p_diff']})
c['health']=dict(rho_min=min(z['rho_min'] for z in rows),rho_max=max(z['rho_max'] for z in rows),max_mach=max(z['max_mach'] for z in rows))
continue
case=label.rsplit('-',1)[1]; base=p/'output'/case;n=read(base/'summary.json');plan=read(p/'output/plan.json')
c['native_receipt_matches_external_result']={k:z for k,z in n.items() if k!='history'}==r['native_summary']
c['external_receipt_history_handling']='V2 external receipt omits the history path; complete history.csv is separately hashed'
c['native_all_finite']=finite(n)
c['native_runner_hash_matches']=plan['runner_sha256']==sha(R/'tests/validation/run_refined_dfg.py')
sm=plan['source_manifest'];c['native_source_capture_matches']=sm['checkout_revision']==SHA and not sm['checkout_dirty'] and all(sha(R/f)==h==manifest['files_sha256'][f] for f,h in sm['sha256'].items())
c['native_source_capture_file_count']=len(sm['sha256'])
c['native']={k:z for k,z in n.items() if k not in ['history','cycles','jet_diagnostic_windows']}; c['comparison']=read(p/'output/comparison.json');c['gates']=plan['gates'];c['reference_gates']=plan['reference_gates'];c['diagnostic_windows']=n['jet_diagnostic_windows']
rows=[{k:float(z) for k,z in row.items()} for row in csv.DictReader((base/'history.csv').open())];late=[x for x in rows if x['tstar']>=290]
c['health']=dict(rows=len(rows),tstar=[rows[0]['tstar'],rows[-1]['tstar']],all_finite=finite(rows),rho_min=min(z['rho_min'] for z in rows),rho_max=max(z['rho_max'] for z in rows),max_mach=max(z['max_mach'] for z in rows),mass_first=rows[0]['mass'],mass_last=rows[-1]['mass'],mass_change_fraction=(rows[-1]['mass']-rows[0]['mass'])/rows[0]['mass'],mass_late_range_fraction=span([z['mass'] for z in late])/np.mean([z['mass'] for z in late]))
if n['cycles']:
tail=n['cycles'][-5:]; periods=[z['period'] for z in tail]; masses=[z['mass_time_mean'] for z in tail]
c['periodic_actual']=dict(cycles_total=len(n['cycles']),tail_cycles=len(tail),tail_start=tail[0]['start'],tail_end=tail[-1]['end'],period_min=min(periods),period_max=max(periods),period_mean=float(np.mean(periods)),period_relative_range=span(periods)/np.mean(periods),last_cycle_age=rows[-1]['tstar_force']-tail[-1]['end'],consecutive_max_gap=max(abs(a['end']-b['start']) for a,b in zip(tail,tail[1:])),minimum_lift_amplitude=min(z['cl_amplitude'] for z in tail),extrema_ranges={k+'_'+e:span([z[k+'_'+e] for z in tail]) for k in ['cd','cl','dp'] for e in ['min','max']},mass_relative_range=span(masses)/abs(np.mean(masses)),max_cycle_flux_relative=max(z['flux_relative'] for z in tail),last_cycle={k:z for k,z in tail[-1].items() if not k.endswith('_waveform')})
cv=[json.loads(x) for x in (base/'cv_history.jsonl').read_text().splitlines()];t=np.array([x['time_root'] for x in cv]);inv=np.array([x['inventory'] for x in cv]);flux=np.array([x['outward_flux'] for x in cv]);j=np.array([x['interval_impulse_root'] for x in cv[1:]]).sum(axis=0);duration=t[-1]-t[0];norm=duration*.5*.01**2*40
cvout=c['cv']=dict(samples=len(cv),all_finite=finite(cv),tstar=[cv[0]['tstar'],cv[-1]['tstar']],duration_root=duration,coefficient_normalization=norm,raw_body_reaction_impulse_root=j.tolist(),first_preceding_impulse_excluded=True,contours_root=plan['cv_observation'][case+'_contours_root'],mass_qualification='Apparent mass source only: raw Jet mass_into_fluid ledger was not recorded, so mass-source-subtracted closure cannot be assessed',acceptance='offline diagnostics only; no CV pass threshold was defined',strides={})
for stride in [1,2,4]:
idx=np.arange(0,len(t),stride);assert idx[-1]==len(t)-1
integral=np.trapz(flux[idx],t[idx],axis=0); delta=inv[-1]-inv[0];jcv=-delta[:,1:]-integral[:,1:];res=jcv-j
cvout['strides'][str(stride)]=dict(samples=len(idx),momentum_delta_root=delta[:,1:].tolist(),outward_momentum_integral_root=integral[:,1:].tolist(),cv_reaction_impulse_root=jcv.tolist(),residual_impulse_root=res.tolist(),residual_coefficient=(res/norm).tolist(),apparent_mass_source_root=(delta[:,0]+integral[:,0]).tolist(),apparent_mass_source_fraction_initial_inventory=((delta[:,0]+integral[:,0])/inv[0,:,0]).tolist())
a=np.array(cvout['strides']['1']['residual_coefficient']);cvout['contour_residual_coefficient_difference']=(a[1]-a[0]).tolist();cvout['coarsening_coefficient_difference']={s:(np.array(cvout['strides'][s]['residual_coefficient'])-a).tolist() for s in ['2','4']}
v['all_six_source_unchanged']=all(c['source_unchanged'] and c['source_matches_manifest'] and c['external_manifest_hash_matches'] for c in out['cases'].values())
v['all_six_native_receipts_match']=all(c['native_receipt_matches_external_result'] and c['native_all_finite'] for c in out['cases'].values())
v['all_v2_native_captures_match']=all(c['native_runner_hash_matches'] and c['native_source_capture_matches'] for k,c in out['cases'].items() if k.startswith('v2'))
out['limitations']=['V1 historical source pin remains blocked','V3 original TG source guard blocked all four dry-runs before CUDA; no TG result or acceptance','Short suite remains 767 passed, 24 failed, 1 skipped; not a release pass','Matched_case_pass remains false because each invocation selected one case; native paired-case comparison branch did not execute','Fixed Jet CV is diagnostic; mass source ledger absent; no physical acceptance','V4 both NOT_STEADY with original ranges/drifts/bands; boundary deviations retained','No formal performance claim: timings include observation/profiling and startup is separately recorded']
dest=Q/'final-physical-digest.json';dest.write_text(json.dumps(out,indent=2,allow_nan=False)+'\n')
print(json.dumps(dict(output=str(dest),bytes=dest.stat().st_size,sha256=sha(dest),verification=v),indent=2))