status===$status,$message);} } $legacy=$store->read('targets.json'); unset($legacy['test']['hidden']);$store->write('targets.json',$legacy); check($store->targets()[0]['hidden']===false,'legacy target is visible by default'); check($store->target('test')===$legacy['test'],'legacy raw target identity remains unchanged'); foreach(['b','c','d'] as $id)$store->saveTarget(['id'=>$id,'domain'=>$id.'.invalid','type'=>'local','root'=>$root.'/site']); $store->setTargetVisibility('b',true); $before=$store->target('b'); check($before['hidden']===true,'visibility persists independently of transport'); $unchanged=$legacy['test'];$store->setTargetVisibility('test',true);$afterVisibility=$store->target('test');unset($afterVisibility['hidden']); check($afterVisibility===$unchanged,'visibility changes no credentials enabled verified or transport fields'); $store->setTargetVisibility('test',false); $store->saveTarget(['id'=>'b','hidden'=>false]); check($store->target('b')['hidden']===true,'editing connection cannot override hidden state'); $store->saveTarget(['id'=>'new','domain'=>'new.invalid','type'=>'local','root'=>$root.'/site','hidden'=>true]); check($store->target('new')['hidden']===false,'new connection is visible and appended'); $store->orderTargets(['d','test','new','c']); check(array_column((new PrelandAdmin\Store($root.'/state'))->targets(),'id')===['d','b','test','new','c'],'reorder persists while preserving hidden slot'); $store->setTargetVisibility('b',false); check(array_column($store->targets(),'id')===['d','b','test','new','c'],'restore returns target to preserved slot'); $unchanged=$store->read('targets.json'); foreach([['d','b','test','new'],['d','b','test','new','new'],['d','b','test','new','missing']] as $ids)targetProblem(fn()=>$store->orderTargets($ids),409,'stale incomplete duplicate or unknown order is rejected'); check($store->read('targets.json')===$unchanged,'rejected reorder does not alter persisted state'); targetProblem(fn()=>$store->orderTargets(['d',1,'test','new','c']),422,'order requires string IDs'); targetProblem(fn()=>$store->setTargetVisibility('missing',true),404,'visibility missing target returns 404'); targetProblem(fn()=>$store->deleteTarget('missing'),404,'delete missing target returns 404'); targetProblem(fn()=>$store->deleteTarget('b'),409,'visible target cannot be deleted'); $store->setTargetVisibility('b',true); $job=$jobs->create('check',['targets'=>['b'],'number'=>1]); targetProblem(fn()=>$store->deleteTarget('b'),409,'queued target cannot be deleted'); $rawJob=$store->read('jobs/'.$job['id'].'.json');$rawJob['status']='running';$store->write('jobs/'.$job['id'].'.json',$rawJob); targetProblem(fn()=>$store->deleteTarget('b'),409,'running target cannot be deleted'); check($store->target('b')['root']===$before['root'],'hiding and rejected deletion retain usable target transport'); $rawJob['status']='completed';$store->write('jobs/'.$job['id'].'.json',$rawJob); $job=$jobs->create('copy',['source'=>['id'=>'b'],'targets'=>[['id'=>'test']]]); targetProblem(fn()=>$store->deleteTarget('b'),409,'queued copy source cannot be deleted'); $rawJob=$store->read('jobs/'.$job['id'].'.json');$rawJob['status']='completed';$store->write('jobs/'.$job['id'].'.json',$rawJob); $store->deleteTarget('b'); check(array_column($store->targets(),'id')===['d','test','new','c'],'hidden idle target deletes only its connection'); check(is_file($root.'/site/config.json'),'connection deletion keeps site files'); foreach(['d','test','new','c'] as $id)$store->setTargetVisibility($id,true); $store->orderTargets([]); check(array_column($store->targets(),'id')===['d','test','new','c'],'empty visible order preserves all hidden connections'); echo "Targets Store contract complete\n";