"""Explicit reproducibility exercise with authored synthetic input; no targets needed.""" from __future__ import annotations import argparse,concurrent.futures,contextlib,copy,json,multiprocessing,tempfile from pathlib import Path from generator import production,vocabulary from tests.solo_fixtures import song def main(): p=argparse.ArgumentParser(description=__doc__);p.add_argument('--output',type=Path,required=True);a=p.parse_args();a.output.mkdir(parents=True,exist_ok=True) data=Path('data').resolve();source=production.SourceAnalysis.read(song(count=1,chords=('C7',))) results={};evidence={'scope':'One-bar independently authored source, real production catalogs, all six roles; not a whole-song musical quality test.','canonical_source':source.musical_key,'cases':{}} def collect(label,values): hashes={role:vocabulary.fingerprint(value['document']) for role,value in values.items()} evidence['cases'][label]=hashes evidence.setdefault('reads',{})[label]={r:v.get('observed_reads',[]) for r,v in values.items()} if results:assert hashes==results['base'],label else:results['base']=hashes with tempfile.TemporaryDirectory() as temp: cache=Path(temp)/'cache' collect('alone_cold',{r:production.generate_role(source,r,data,cache_dir=cache) for r in production.ROLES}) collect('reverse_warm',{r:production.generate_role(source,r,data,cache_dir=cache) for r in reversed(production.ROLES)}) with concurrent.futures.ProcessPoolExecutor(max_workers=2,mp_context=multiprocessing.get_context('spawn')) as pool: futures={r:pool.submit(production._job,(source,r,data,{},None)) for r in reversed(production.ROLES)} collect('parallel_cold',{r:f.result() for r,f in futures.items()}) with contextlib.chdir(temp): refs=Path('build');refs.mkdir() for name in ('all-of-me','autumn-leaves'): for i in (1,2):(refs/f'{name}-solo-{i}.xml').write_text('invalid optional content') collect('targets_present_cold',{r:production.generate_role(source,r,data) for r in production.ROLES}) for path in refs.glob('*.xml'):path.unlink() collect('targets_absent_cold',{r:production.generate_role(source,r,data) for r in production.ROLES}) # Exercise an operational musical setting, not merely a different cache # key. A stream seed alone need not change a deterministic winner. changed=production.generate_role(source,'electric_solo',data,{'register_center':72}) changed_hash=vocabulary.fingerprint(changed['document']) assert changed_hash!=results['base']['electric_solo'],'electric setting was inert' evidence['changed_electric_register_hash']=changed_hash collect('after_electric_setting',{r:production.generate_role(source,r,data,cache_dir=cache) for r in production.ROLES}) evidence['passed']=True (a.output/'dependency.json').write_text(json.dumps(evidence,indent=2)) print(json.dumps({'passed':True,'hashes':results['base']},indent=2)) if __name__=='__main__':main()