From ec517839215534c9d95eb99d16364e635beaa01c Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Sat, 19 Sep 2026 13:55:14 -0700 Subject: [PATCH] Bind normal RoadScore sessions to causal host semantic plans and native sampling --- .../ace_chestnut_20260916/ace_worker.py | 28 +++++-- roadscore/prototype/hook_launch.py | 35 ++++++++ roadscore/prototype/hook_service.py | 82 +++++++++++++++++++ roadscore/prototype/native_receiver.sh | 1 + roadscore/prototype/normal_onroad.py | 16 +++- roadscore/prototype/planned_composition.py | 53 ++++++++++++ roadscore/prototype/prepared_session.py | 12 +++ roadscore/prototype/test_hook_launch.py | 20 +++++ .../prototype/test_planned_composition.py | 73 +++++++++++++++++ 9 files changed, 310 insertions(+), 10 deletions(-) create mode 100644 roadscore/prototype/hook_launch.py create mode 100644 roadscore/prototype/hook_service.py create mode 100644 roadscore/prototype/planned_composition.py create mode 100644 roadscore/prototype/prepared_session.py create mode 100644 roadscore/prototype/test_hook_launch.py create mode 100644 roadscore/prototype/test_planned_composition.py diff --git a/roadscore/experiments/ace_chestnut_20260916/ace_worker.py b/roadscore/experiments/ace_chestnut_20260916/ace_worker.py index 4cf12844f1..3c0c92c5bb 100644 --- a/roadscore/experiments/ace_chestnut_20260916/ace_worker.py +++ b/roadscore/experiments/ace_chestnut_20260916/ace_worker.py @@ -18,6 +18,11 @@ from generation_seed import configured_seed,sample_seed base_seed=configured_seed(required=True) from quality_gate import QualifiedGenerator,POLICY from link_health import LinkProbe +from hook_service import Client +from planned_composition import PlannedComposition +composition_policy=os.environ.get('ROADSCORE_COMPOSITION_POLICY','prepared-v1') +if composition_policy not in ('prepared-v1','hook-v2'):raise ValueError('Unknown composition policy') +if composition_policy=='hook-v2' and not windowed:raise ValueError('Hook planning requires windowed native sampler') from tinygrad import Device profile=selected();preparation_id=f'{profile}_{time.time_ns()}' lock=open(G/'gpu.lock','w');fcntl.flock(lock,fcntl.LOCK_EX|fcntl.LOCK_NB) @@ -28,16 +33,23 @@ def write_json(path,data): tmp=path.with_suffix('.tmp');tmp.write_text(json.dumps(data,indent=2));tmp.replace(path) def save_wave(path,wave):sf.write(path,wave*POLICY.output_gain,48000,subtype='FLOAT') try: - write_json(G/'ace_worker_state.json',{'pid':os.getpid(),'generation_seed':base_seed,'profile':profile,'phase':'preparing'}) + write_json(G/'ace_worker_state.json',{'pid':os.getpid(),'generation_seed':base_seed,'composition_policy':composition_policy,'profile':profile,'phase':'preparing'}) load_started=time.monotonic() c=Composer(P,profile=profile) if windowed else Composer(P) model_load_seconds=time.monotonic()-load_started probe=LinkProbe(Device['AMD'],G/'ace_link.jsonl');probe.install_failure_hook(contain=True) if windowed:c.decoder.trace=probe.trace + planned=None + if composition_policy=='hook-v2': + from ace_runtime import Composer as NativeComposer + from window_policy import retained_end + planned=PlannedComposition(Client(os.environ['ROADSCORE_PLANNER_URL'],os.environ['ROADSCORE_PLANNER_TOKEN']),G/'hook_sessions'/preparation_id,base_seed,profile) + def planned_generate(role,seed,previous):return planned.generate(lambda case,seed,previous:NativeComposer.generate(c,case,seed,previous),seed,previous,retained_end) + sample=planned_generate if planned else c.generate def generate(role,seed,previous): probe.preflight(role=role,seed=seed) try: - wave,latent,stats=c.generate(role,seed,previous);stats['power_limit_watts']=float(os.environ['AM_POWER_LIMIT']) if os.environ.get('AM_POWER_LIMIT') else None;stats['link_session']=probe.session;stats['host_peak_rss_kib']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss;stats['tracked_allocation_bytes']=probe.last.get('allocator_bytes');return wave,latent,stats + wave,latent,stats=sample(role,seed,previous);stats['power_limit_watts']=float(os.environ['AM_POWER_LIMIT']) if os.environ.get('AM_POWER_LIMIT') else None;stats['link_session']=probe.session;stats['host_peak_rss_kib']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss;stats['tracked_allocation_bytes']=probe.last.get('allocator_bytes');return wave,latent,stats except Exception as e: probe.sample('generation_exception',error=str(e),role=role,seed=seed);raise qualified=QualifiedGenerator(generate) @@ -52,9 +64,11 @@ try: initial=None;last=None;preparation=[];slot=0 while initial is None or len(initial)/480008:raise RuntimeError('Initial buffer did not fill within bounded preparation') save_wave(G/'ace_initial.wav',initial);np.save(G/'ace_initial.npy',last) - write_json(G/'ace_initial.json',{'generation_seed':base_seed,'composer':'ace','startup_seconds':time.monotonic()-BOOT,'model_load_seconds':model_load_seconds,'host_peak_rss_kib':resource.getrusage(resource.RUSAGE_SELF).ru_maxrss,'duration':len(initial)/48000,'source_identity':'kpop_control','prepared_profile':profile if windowed else 'legacy','preparation_id':preparation_id,'continuation_policy':'quality-gated fixed lookahead','generation':preparation,'prepared_identity':True,'output_gain':POLICY.output_gain,'created_wall':time.time()}) - write_json(G/'ace_worker_state.json',{'pid':os.getpid(),'generation_seed':base_seed,'profile':profile,'phase':'READY','initial_buffer_seconds':len(initial)/48000}) + write_json(G/'ace_initial.json',{'generation_seed':base_seed,'composition_policy':composition_policy,'composer':'ace','startup_seconds':time.monotonic()-BOOT,'model_load_seconds':model_load_seconds,'host_peak_rss_kib':resource.getrusage(resource.RUSAGE_SELF).ru_maxrss,'duration':len(initial)/48000,'source_identity':'kpop_control','prepared_profile':profile if windowed else 'legacy','preparation_id':preparation_id,'continuation_policy':'quality-gated fixed lookahead','generation':preparation,'prepared_identity':True,'output_gain':POLICY.output_gain,'created_wall':time.time()}) + write_json(G/'ace_worker_state.json',{'pid':os.getpid(),'generation_seed':base_seed,'composition_policy':composition_policy,'profile':profile,'phase':'READY','initial_buffer_seconds':len(initial)/48000}) (G/'request.json').unlink(missing_ok=True);ready.write_text('ace');print('ACE_READY',flush=True) while True: request=G/'request.json' @@ -81,10 +95,12 @@ try: if case is None:raise ValueError('Unsupported ACE section intent') if windowed:case=case.removeprefix('repaint_') previous=np.load(req['latents']) + if planned:case=planned.begin(previous,arrival=case=='outro') deadline=req.get('playback_deadline_monotonic') - wave,latent,stats=qualified.run(case,int(req.get('seed',job%(2**32))),previous,deadline=deadline,record=record_for(job)) + wave,latent,stats=qualified.run(case,int(req['seed']),previous,deadline=deadline,record=record_for(job)) if wave is None: write_json(G/f'result_{job}.json',{**req,**stats,'id':job,'composer':'ace','seconds':time.monotonic()-start});continue + if planned:planned.accept(wave,latent) wav=G/f'ace_job_{job}.wav';lat=G/f'ace_job_{job}.npy';save_wave(wav,wave);np.save(lat,latent) result={**req,**stats,'id':job,'composer':'ace','backend':'ACE-Step1.5 turbo native Chestnut, prepared identity','wav':str(wav),'latents':str(lat),'seconds':time.monotonic()-start,'retained_seconds':stats['prefix_seconds'],'new_audio_start_frame':round(stats['prefix_seconds']*48000),'overlap_frames':96000,'sample_rate':48000,'output_gain':POLICY.output_gain,'conditioning':req['conditioning']} write_json(G/f'result_{job}.json',result);print('ACE_RESULT',job,result['seconds'],flush=True) @@ -93,4 +109,4 @@ try: finally:busy.unlink(missing_ok=True) finally: ready.unlink(missing_ok=True) - write_json(G/'ace_worker_state.json',{'pid':os.getpid(),'generation_seed':base_seed,'profile':profile,'phase':'Stopped'}) + write_json(G/'ace_worker_state.json',{'pid':os.getpid(),'generation_seed':base_seed,'composition_policy':composition_policy,'profile':profile,'phase':'Stopped'}) diff --git a/roadscore/prototype/hook_launch.py b/roadscore/prototype/hook_launch.py new file mode 100644 index 0000000000..f1039ce316 --- /dev/null +++ b/roadscore/prototype/hook_launch.py @@ -0,0 +1,35 @@ +"""Automatic Mac planner lifecycle for ordinary remote native sessions.""" +import json +import os +from pathlib import Path +import secrets +import subprocess +import time + + +def enabled(session, replay, composer): + return bool(session and not replay and composer=='ace' and session['seed_origin']!='judging-route') + + +def start_planner(launch, env, out, roadscore, bench, native=False): + if native: + if not env.get('ROADSCORE_PLANNER_URL') or not env.get('ROADSCORE_PLANNER_TOKEN'): + raise RuntimeError('Hook composition needs a connected host semantic planner; launch on the Mac or configure its authenticated loopback tunnel') + return + assets=Path(env.get('ROADSCORE_ASSETS_ROOT',str(Path.home()/'Desktop/RoadScore'))) + python=Path(env.get('ROADSCORE_PLANNER_PYTHON',str(assets/'experiments/composition_20260916/venv/bin/python'))) + if not python.is_file():raise RuntimeError('Existing Mac ACE preparation environment missing: '+str(python)) + env['ROADSCORE_PLANNER_TOKEN']=secrets.token_urlsafe(32) + ready=out/'planner_ready.json' + planner=launch([str(python),str(roadscore/'prototype/hook_service.py'),'--assets-root',str(assets),'--cache',str(assets/'cache/hook-plans-v2'),'--ready',str(ready)],'semantic_planner') + deadline=time.monotonic()+300 + while not ready.exists(): + if planner.poll() is not None or time.monotonic()>deadline:raise RuntimeError('Host semantic planner failed; see semantic_planner.log') + time.sleep(.1) + port=int(json.loads(ready.read_text())['port']);remote_port=int(env.get('ROADSCORE_PLANNER_REMOTE_PORT','8767')) + tunnel=launch(['ssh','-T','-o','ExitOnForwardFailure=yes','-o','ServerAliveInterval=15','-R',f'127.0.0.1:{remote_port}:127.0.0.1:{port}',bench,'printf "PLANNER_TUNNEL_READY\\n"; cat'],'semantic_tunnel',stdin=subprocess.PIPE) + deadline=time.monotonic()+30 + while b'PLANNER_TUNNEL_READY' not in (out/'semantic_tunnel.log').read_bytes(): + if tunnel.poll() is not None or time.monotonic()>deadline:raise RuntimeError('Exclusive planner tunnel unavailable; see semantic_tunnel.log') + time.sleep(.1) + env['ROADSCORE_PLANNER_URL']=f'http://127.0.0.1:{remote_port}' diff --git a/roadscore/prototype/hook_service.py b/roadscore/prototype/hook_service.py new file mode 100644 index 0000000000..48e0bc36d5 --- /dev/null +++ b/roadscore/prototype/hook_service.py @@ -0,0 +1,82 @@ +"""Loopback-only semantic preparation transport; no diffusion or route input.""" +import argparse +import base64 +import hmac +import json +import os +from pathlib import Path +import sys +import tempfile +import threading +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from urllib.request import Request, urlopen +from hook_planning import PlanCache, PlanRequest, request_plan + +LIMIT = 32 * 1024 * 1024 + +class Client: + def __init__(self, url, token, timeout=600): + if not url.startswith('http://127.0.0.1:'):raise ValueError('Planner must use authenticated loopback tunnel') + self.url,self.token,self.timeout=url.rstrip('/'),token,timeout + def call(self, endpoint, data=None): + body=None if data is None else json.dumps(data).encode() + req=Request(self.url+endpoint,data=body,headers={'Authorization':'Bearer '+self.token,'Content-Type':'application/json'}) + with urlopen(req,timeout=self.timeout) as response: + result=response.read(LIMIT+1) + if len(result)>LIMIT:raise ValueError('Oversized planner response') + return json.loads(result) + def fingerprints(self):return self.call('/identity') + def prepare(self, request, sources, output): + data=self.call('/plan',{'request':request.identity(),'sources':{k:base64.b64encode(Path(v).read_bytes()).decode() for k,v in sources.items()}}) + for name,encoded in data['files'].items(): + if Path(name).name!=name or name in ('.','..','cache.json'):raise ValueError('Invalid planner filename') + (output/name).write_bytes(base64.b64decode(encoded,validate=True)) + + +def make_server(adapter, cache, token, port=0): + lock=threading.Lock() + class Handler(BaseHTTPRequestHandler): + def log_message(self,*args):pass + def respond(self,status,data): + body=json.dumps(data).encode();self.send_response(status);self.send_header('Content-Type','application/json');self.send_header('Content-Length',str(len(body)));self.end_headers();self.wfile.write(body) + def authorized(self):return hmac.compare_digest(self.headers.get('Authorization',''),'Bearer '+token) + def do_GET(self): + if not self.authorized():return self.respond(403,{'error':'Authentication required'}) + if self.path!='/identity':return self.respond(404,{'error':'Unknown endpoint'}) + try:self.respond(200,adapter.fingerprints()) + except Exception as exc:self.respond(500,{'error':str(exc)}) + def do_POST(self): + if not self.authorized():return self.respond(403,{'error':'Authentication required'}) + if self.path!='/plan':return self.respond(404,{'error':'Unknown endpoint'}) + try: + size=int(self.headers.get('Content-Length','0')) + if not 0deadline:raise RuntimeError('Stored audio failed; see stored_audio.log') time.sleep(.1) else: - receiver_command=(['env','-u','ZMQ','ROADSCORE_AUDIBLE='+('1' if a.audible else '0'),'bash',str(R/'prototype/native_receiver.sh'),a.routeid] if native else ['ssh',a.bench,(remote_assignments(session) if session else '')+'ROADSCORE_RENDER_MODE='+a.render_mode+' ROADSCORE_COMPOSER='+a.composer+' ROADSCORE_ACE_PROFILE='+a.profile+' ROADSCORE_PCM_RETURN=1 '+('ROADSCORE_NO_GENERATION=1 ' if a.transport_only else '')+'bash /data/roadscore/prototype/native_receiver.sh '+shlex.quote(a.routeid)]) + remote_policy=' '.join(k+'='+shlex.quote(env[k]) for k in ('ROADSCORE_PRESENTATION_POLICY','ROADSCORE_COMPOSITION_POLICY','ROADSCORE_PLANNER_URL','ROADSCORE_PLANNER_TOKEN') if k in env)+' ' + receiver_command=(['env','-u','ZMQ','ROADSCORE_AUDIBLE='+('1' if a.audible else '0'),'bash',str(R/'prototype/native_receiver.sh'),a.routeid] if native else ['ssh',a.bench,(remote_assignments(session) if session else '')+remote_policy+'ROADSCORE_RENDER_MODE='+a.render_mode+' ROADSCORE_COMPOSER='+a.composer+' ROADSCORE_ACE_PROFILE='+a.profile+' ROADSCORE_PCM_RETURN=1 '+('ROADSCORE_NO_GENERATION=1 ' if a.transport_only else '')+'bash /data/roadscore/prototype/native_receiver.sh '+shlex.quote(a.routeid)]) receiver=launch(receiver_command,'receiver',stdin=subprocess.PIPE) deadline=time.monotonic()+(1560 if a.composer=='ace' else 420) while b'BRIDGE_READY' not in (out/'receiver.log').read_bytes(): diff --git a/roadscore/prototype/planned_composition.py b/roadscore/prototype/planned_composition.py new file mode 100644 index 0000000000..ec8899d864 --- /dev/null +++ b/roadscore/prototype/planned_composition.py @@ -0,0 +1,53 @@ +"""Transactional semantic-plan binding to the native sampler and accepted audio.""" +import json +import hashlib +from pathlib import Path +import time +import numpy as np +import soundfile as sf +from hook_planning import PlanCache, digest, request_plan, next_section + +class PlannedComposition: + def __init__(self, client, root, session_seed, profile): + self.client,self.root,self.seed,self.profile=client,Path(root),session_seed,profile + self.root.mkdir(parents=True,exist_ok=True) + self.cache=PlanCache(self.root/'plans');self.identity=client.fingerprints() + self.index=0;self.previous_key=None;self.pending=None;self.accepted={} + self.hook=self.root/'accepted_hook.wav' + def begin(self, previous, arrival=False): + sources={};context={} + if previous is not None: + identity=hashlib.sha256(previous.tobytes()).hexdigest() + if identity not in self.accepted:raise ValueError('Continuation source was not accepted in this session') + self.index,self.previous_key=self.accepted[identity] + role='initial' if self.index==0 else next_section(self.index-1,arrival_intent=arrival) + if self.index: + if previous is None or previous.ndim!=3 or previous.shape[0]!=1 or previous.shape[1]<200 or previous.shape[2]!=64:raise ValueError('Committed musical tail required') + prefix=self.root/'committed_prefix.npy';np.save(prefix,previous[:,-200:].copy()) + sources={'hook_reference':self.hook,'committed_prefix':prefix} + context={'hook_reference_sha256':digest(self.hook),'committed_prefix_sha256':digest(prefix),'previous_plan_sha256':self.previous_key} + elif previous is not None:raise ValueError('Fresh composition cannot reuse a previous session latent') + request=request_plan(session_seed=self.seed,plan_index=self.index,profile=self.profile,section=role,window_seconds=30 if self.index==0 else 45,**self.identity,**context) + started=time.monotonic();directory,hit=self.cache.resolve(request,self.client.prepare,sources=sources) + self.pending={'request':request.identity(),'plan_key':request.cache_key,'directory':str(directory),'host_preparation_seconds':time.monotonic()-started,'plan_cache_hit':hit} + (self.root/f'plan_{self.index}.json').write_text(json.dumps(self.pending,indent=2)) + return role + def generate(self, native_generate, seed, previous, retain): + if self.pending is None:raise RuntimeError('Begin a semantic plan before sampling') + wave,latent,stats=native_generate(self.pending['directory'],seed,previous) + role=self.pending['request']['section'];seconds=28 if self.index==0 else 36 + try:frames,endpoint=retain(wave,48000,stats['prefix_seconds'],seconds,allow_fade=role=='outro') + except ValueError as exc: + frames=seconds*25;endpoint={'rejected':str(exc)};stats['endpoint_error']=str(exc) + committed=wave[:frames*1920];z=latent[:,:frames] + if len(committed)!=frames*1920 or z.shape[1]!=frames:raise ValueError('Native sampler returned incomplete planned window') + model_duration=stats['duration'];duration=frames/25;new=duration-stats['prefix_seconds'] + if new<=0 or not np.isfinite(committed).all():raise ValueError('Invalid committed planned audio') + stats.update(self.pending,case=role,prepared_profile=self.profile,model_duration=model_duration,duration=duration,new_seconds=new,discarded_lookahead_seconds=model_duration-duration,endpoint=endpoint,composition_policy='hook-v2',preparation_host='authenticated host semantic planner',warm_rtf_new_audio=(stats['generation_seconds']+stats['decode_seconds'])/new) + return committed,z,stats + def accept(self,wave,latent): + if self.pending is None:raise RuntimeError('No pending plan') + if self.index==0:sf.write(self.hook,wave,48000,subtype='FLOAT') + self.previous_key=self.pending['plan_key'];self.index+=1 + self.accepted[hashlib.sha256(latent.tobytes()).hexdigest()]=(self.index,self.previous_key) + self.pending=None diff --git a/roadscore/prototype/prepared_session.py b/roadscore/prototype/prepared_session.py new file mode 100644 index 0000000000..27aa782712 --- /dev/null +++ b/roadscore/prototype/prepared_session.py @@ -0,0 +1,12 @@ +"""Refuse accidental reuse of a different resident composition.""" +import json +import os +from pathlib import Path + + +def verify(metadata,environ): + if int(metadata.get('generation_seed',-1))!=int(environ['ROADSCORE_GENERATION_SEED']):raise ValueError('Resident composer belongs to another seed; its owner must finish/release that session') + if metadata.get('prepared_profile')!=environ.get('ROADSCORE_ACE_PROFILE','prism'):raise ValueError('Resident composer profile differs from this launch') + if metadata.get('composition_policy','prepared-v1')!=environ.get('ROADSCORE_COMPOSITION_POLICY','prepared-v1'):raise ValueError('Resident composer policy differs from this launch') + +if __name__=='__main__':verify(json.loads(Path('/data/roadscore/generated/ace_initial.json').read_text()),os.environ) diff --git a/roadscore/prototype/test_hook_launch.py b/roadscore/prototype/test_hook_launch.py new file mode 100644 index 0000000000..5f3b21bfb4 --- /dev/null +++ b/roadscore/prototype/test_hook_launch.py @@ -0,0 +1,20 @@ +import unittest +from hook_launch import enabled +from prepared_session import verify +from session_seed import select_session + +class LaunchTests(unittest.TestCase): + def test_fresh_and_explicit_but_not_judging_or_replay(self): + self.assertTrue(enabled(select_session(123),False,'ace')) + self.assertTrue(enabled(select_session(random_bits=lambda _:234),False,'ace')) + self.assertFalse(enabled(select_session(123,judging_seed=123),False,'ace')) + self.assertFalse(enabled(select_session(123),True,'ace')) + self.assertFalse(enabled(None,False,'sa3')) + def test_resident_policy_and_seed_must_match(self): + metadata={'generation_seed':123,'prepared_profile':'prism','composition_policy':'hook-v2'} + env={'ROADSCORE_GENERATION_SEED':'123','ROADSCORE_ACE_PROFILE':'prism','ROADSCORE_COMPOSITION_POLICY':'hook-v2'} + verify(metadata,env) + for key,value in [('generation_seed',124),('prepared_profile','aurora'),('composition_policy','prepared-v1')]: + with self.assertRaises(ValueError):verify({**metadata,key:value},env) + +if __name__=='__main__':unittest.main() diff --git a/roadscore/prototype/test_planned_composition.py b/roadscore/prototype/test_planned_composition.py new file mode 100644 index 0000000000..755110a8da --- /dev/null +++ b/roadscore/prototype/test_planned_composition.py @@ -0,0 +1,73 @@ +import json +from pathlib import Path +import tempfile +import threading +import unittest +from urllib.error import HTTPError +import numpy as np +from hook_service import Client,make_server +from hook_planning import PlanCache +from planned_composition import PlannedComposition +from test_hook_planning import fake_prepare + +class Adapter: + def fingerprints(self):return {'model_fingerprint':'a'*64,'preparation_fingerprint':'b'*64} + def __call__(self,req,sources,out): + fake_prepare(req,sources,out) + if req.prefix_seconds: + n=req.window_seconds*25;prefix=np.load(sources['committed_prefix']) + context=np.zeros((1,n,128),np.float32);context[:,:200,:64]=prefix + source=np.zeros((1,n,64),np.float32);source[:,:200]=prefix + np.save(out/'context_latents.npy',context);np.save(out/'sampler_clean_src_latents.npy',source) + np.save(out/'sampler_repaint_mask.npy',np.arange(n)[None,:]>=200) + (out/'sampler.json').write_text(json.dumps({'repaint_crossfade_frames':12,'repaint_injection_ratio':.5})) + +def retain(wave,sr,prefix,seconds,allow_fade=False):return seconds*25,{} + +def sampler(path,seed,previous): + context=np.load(Path(path)/'context_latents.npy');n=context.shape[1] + latent=np.full((1,n,64),seed,np.float16) + wave=np.full((n*1920,2),.1,np.float32) + return wave,latent,dict(duration=n/25,prefix_seconds=0 if previous is None else 8,generation_seconds=1,decode_seconds=.1) + +class IntegrationTests(unittest.TestCase): + def setUp(self): + self.temp=tempfile.TemporaryDirectory();self.root=Path(self.temp.name) + self.server=make_server(Adapter(),PlanCache(self.root/'server'),'secret') + self.thread=threading.Thread(target=self.server.serve_forever,daemon=True);self.thread.start() + self.client=Client('http://127.0.0.1:'+str(self.server.server_port),'secret') + def tearDown(self): + self.server.shutdown();self.server.server_close();self.thread.join();self.temp.cleanup() + def test_freshplans_causal_chain_and_discarded_result(self): + run=PlannedComposition(self.client,self.root/'session',101,'prism') + self.assertEqual(run.begin(None),'initial') + wave,latent,stats=run.generate(sampler,11,None,retain) + self.assertEqual(len(wave),28*48000);self.assertEqual(latent.shape,(1,700,64)) + initial_key=stats['plan_key'];run.accept(wave,latent) + committed=latent.copy() + self.assertEqual(run.begin(committed),'verse') + wave,latent,stats=run.generate(sampler,12,committed,retain) + self.assertEqual(len(wave),36*48000);self.assertEqual(stats['new_seconds'],28) + self.assertEqual(stats['request']['previous_plan_sha256'],initial_key) + prefix=np.load(self.root/'session/committed_prefix.npy');np.testing.assert_array_equal(prefix,committed[:,-200:]) + run.accept(wave,latent) + # Audio scheduler discarded this result: its next request supplies the old committed tail. + self.assertEqual(run.begin(committed),'verse') + self.assertEqual(run.pending['request']['previous_plan_sha256'],initial_key) + self.assertTrue(run.pending['plan_cache_hit']) + run.accept(wave,latent) + self.assertEqual(run.begin(latent),'prechorus') + wave,new,stats=run.generate(sampler,13,latent,retain);run.accept(wave,new) + self.assertEqual(run.begin(new),'chorus') + other=PlannedComposition(self.client,self.root/'other',102,'prism');other.begin(None) + self.assertNotEqual(other.pending['plan_key'],initial_key) + def test_unknown_context_and_bad_auth_fail_closed(self): + run=PlannedComposition(self.client,self.root/'session',101,'prism') + with self.assertRaises(ValueError):run.begin(np.zeros((1,700,64))) + with self.assertRaises(HTTPError):Client(self.client.url,'wrong').fingerprints() + def test_seed_and_prompt_tampering_rejected(self): + run=PlannedComposition(self.client,self.root/'session',101,'prism');run.begin(None) + request=run.pending['request'].copy();request['caption']='stale generic plan' + with self.assertRaises(HTTPError):self.client.call('/plan',{'request':request,'sources':{}}) + +if __name__=='__main__':unittest.main()