from research import *
s=begin(903,'Contrast whole-frame motion with source-fixed anchor change','Why are some paired fields rigid translations while File52c is not?',{},['C852–858','C868','C893','C839'])
p=json.loads((ROOT/'model/inverse_inputs.json').read_text())
duration_invariant=[]
for row in p['source_rows']:
 d=row['source_BC']
 for key in ['Nativity','Conquest']:
  a=row[key]['anchor_BC']
  duration_invariant.append((d+30)-(a+30)==d-a)
g=json.loads((ROOT/'model/inverse_gain_field.json').read_text())
if isinstance(g,dict):g=g['rows']
contrasts={'whole_frame':'(D,A)→(D+t,A+t) keeps original span and digits fixed; output translates t','fixed_source_anchor':'D fixed, A changes1400; original duration changes and digit branch can change','NT':'6→36 hinge and full display move together','carrier':'paired endpoints move together; coefficient sum1','festival':'anchor moves, ordered count prefixes remain fixed'}
art=artifact('model/frame_vs_anchor_change.json',json.dumps(contrasts,indent=2)+'\n')
finish(s,{'comparison':art,'original_spans_preserved':len(duration_invariant),'different_inverse_gaps':len({r['delta'] for r in g})},'Whole-frame covariance applies across the new objects because their relative inputs remain fixed. File52c changes only the anchor while holding the source date, so its measured span and digit branch change. This explains rigid NT/carrier translations versus the nonuniform paired inverse field.','Classify every festival prefix against the49/70 common measure.',{'all64_original_spans':len(duration_invariant)==64 and all(duration_invariant),'nonuniform':len({r['delta'] for r in g})>1})
