"""Additional live QA evidence: independent appeal, public editorial gates and external dependencies.""" import importlib.util from pathlib import Path spec=importlib.util.spec_from_file_location('opportunity_workflow_http_qa',Path(__file__).with_name('opportunity-workflow-http-qa.py')) module=importlib.util.module_from_spec(spec);spec.loader.exec_module(module) globals().update({name:getattr(module,name) for name in ['Session','actors','PRIVATE','EXPECTED','REASON','events','page','transition','save','png','review','superuser','promoter','validator','publisher']}) import json import uuid from datetime import datetime, timezone previous = json.loads((PRIVATE / 'opportunity-workflow-http-qa.json').read_text()) assert previous['result']=='passed' and previous['target']==EXPECTED case = next(c for c in previous['cases'] if c['category']=='real_estate') land = next(c for c in previous['cases'] if c['category']=='land_rights') id=case['id'];document=case['document_id'] proof={'target':EXPECTED,'active_writes':0,'interface_demonstrated':False,'started_at':datetime.now(timezone.utc).isoformat()} path=PRIVATE/'opportunity-workflow-extended-http-qa.json' try: assignments=superuser.call('GET','/perfis/gestao',inertia=True)['props']['assignments'] existing=[g for g in assignments if g['user_id']==actors['bootstrap']['id'] and g['role']=='validator' and g['revoked_at'] is None and 'appeal_reviewer' in json.loads(g['responsibilities'])] if not existing: superuser.call('POST','/perfis/atribuicoes',{'user_id':actors['bootstrap']['id'],'role':'validator','opportunity_types':['real_estate'], 'responsibilities':['appeal_reviewer'],'reason':'Instância independente estritamente sintética QA, sem designar responsável real'},status=201) appeal=Session('bootstrap').login() transition(appeal,id,'appeal_reopen') recovered=Session('promoter').login().call('GET',f'/minhas-oportunidades/{id}/view',inertia=True)['props'] assert recovered['workflowState']=='needs_information' and not recovered['profileContext']['appeal']['pending'] proof['appeal']={'id':id,'rejector_id':actors['validator']['id'],'appeal_reviewer_id':actors['bootstrap']['id'],'independent_decision':'reopen','recovered_in_new_session':True} # No extra copies of originals: new image is a separate, deliberately distinct synthetic fixture. image=promoter.call('POST',f'/minhas-oportunidades/{id}/resources/images',{'etag':page(promoter,id)['etag'],'creation_key':str(uuid.uuid4()),'reason':REASON, 'payload':json.dumps({'title':'Imagem sintética QA','caption':'Ilustração sintética para ensaio QA','alt_text':'Área colorida gerada exclusivamente para QA','is_cover':True,'rights_status':'owned','visibility':'public'})},multipart=png(id+100),status=201) resources=promoter.call('GET',f'/minhas-oportunidades/{id}/resources',inertia=True)['props']['resources'] row=next(i for i in resources['images'] if i['id']==image['id']) assert row['file']['malware_scan_status']=='clean' promoter.call('POST',f"/minhas-oportunidades/{id}/resources/images/{image['id']}/prepare",{'etag':page(promoter,id)['etag'],'version':row['version'],'reason':REASON}) resources=promoter.call('GET',f'/minhas-oportunidades/{id}/resources',inertia=True)['props']['resources'] row=next(i for i in resources['images'] if i['id']==image['id']) assert row['payload']['derivatives'] and len(row['derivativePreviews'])==len(row['payload']['derivatives']) p=page(promoter,id)['values']['canonical'];p.update({'visibility':'public','images':[image['id']],'review_due_date':'2027-01-01'}) p['real_estate']['price']=None save(promoter,id,p);transition(promoter,id,'submit',status=422) p['real_estate']['price']=1000 save(promoter,id,p);transition(promoter,id,'submit');transition(validator,id,'start_review');review(id,document) transition(publisher,id,'publish',status=422,confirm_publication=False) transition(publisher,id,'publish',status=409,preview_hash='0'*64) transition(publisher,id,'publish') published=page(promoter,id) public=Session('public').login() response=public.call('GET','/api/v1/opportunities/'+published['record']['slug']) serialized=json.dumps(response) assert 'canonical' not in serialized and 'workflow_context' not in serialized and 'internal_contact_id' not in serialized proof['public_publication']={'id':id,'public_route':'/api/v1/opportunities/'+published['record']['slug'],'image_original_clean':True,'derived_previews':len(row['derivativePreviews']), 'preview_confirmation_enforced':True,'preview_hash_enforced':True,'private_fields_not_exposed':True} transition(promoter,id,'request_revision');p['official_title']+=' — proposta privada não publicada';save(promoter,id,p) still_public=public.call('GET','/api/v1/opportunities/'+published['record']['slug']) assert 'proposta privada não publicada' not in json.dumps(still_public) transition(publisher,id,'suspend') public.call('GET','/api/v1/opportunities/'+published['record']['slug'],status=404) proof['material_change_and_suspend']={'id':id,'public_version_preserved_while_preparing':True,'approval_invalidated':True,'suspended_public_get':404} # All internal gates may be recorded, but do not manufacture the missing external authorization. transition(validator,land['id'],'start_review');review(land['id'],land['document_id']) transition(publisher,land['id'],'publish',status=422) proof['external_authorization']={'id':land['id'],'internal_approval':'approved','external_authorization':'pending','publication_status':422,'external_decision_not_fabricated':True} proof['result']='passed';proof['completed_at']=datetime.now(timezone.utc).isoformat() print(json.dumps({'result':'passed','target':EXPECTED,'appeal_id':id,'independent_actor':actors['bootstrap']['id'],'real_image_derivatives':len(row['derivativePreviews']),'visual_pending':True,'active_writes':0})) except Exception: proof['result']='failed';raise finally: proof['events']=events;path.write_text(json.dumps(proof,indent=2),encoding='utf-8')