['total_investment',10,['technical_review']],31=>['real_estate.title_holder_name','QA changed holder',['registry_urban_review']],32=>['land_rights.holder_document_id',null,['land_legal_review']],33=>['business_transaction.entity_registration.registration_number','QA changed registry',['corporate_screening']],34=>['business_transaction.governance_rights.voting','QA changed voting',['partnership_governance_review','legal_tax_due_diligence']],35=>['business_transaction.entity_registration.registration_number','QA changed registry',['franchise_legal_review']]]; foreach($changes as $id=>[$field,$value,$expected]) { $record=Opportunity::findOrFail($id);$before=app(OpportunityCanonicalContract::class)->validateSubmission($record);$reviews=[]; foreach(app(OpportunityCanonicalContract::class)->gates($record) as $gate) { $reviews[$gate]=['decision'=>'approved','hash'=>$before['hash'],'actor_id'=>24,'at'=>'2026-10-10T20:00:00Z','scope_rule'=>OpportunityReviewMateriality::PREVIOUS_VERSION]; $reviews[$gate]['scope_hash']=$m->hash($before,$gate,$reviews[$gate],false,OpportunityReviewMateriality::PREVIOUS_VERSION); throw_unless($m->matches($before,$gate,$reviews[$gate]),RuntimeException::class,'Original v2 signature must remain readable.'); } $after=$before;Arr::set($after['payload'],$field,$value);$after['hash']=hash('sha256',json_encode($after,JSON_THROW_ON_ERROR)); $result=$m->reconcile($before,$after,$reviews,app(OpportunityCanonicalContract::class)->gates($record)); $actual=$result['reopened'];sort($actual);sort($expected);throw_unless($actual===$expected,RuntimeException::class,'Incorrect affected gates for '.$record->opportunity_category.': '.implode(',',$actual)); foreach($result['reviews'] as $gate=>$review) { throw_unless($review['hash']===$reviews[$gate]['hash']&&$review['at']===$reviews[$gate]['at']&&$review['actor_id']===$reviews[$gate]['actor_id'],RuntimeException::class,'Signed decision changed.'); } $editorial=$before;$editorial['payload']['official_title'].=' QA typo';$editorial['hash']=hash('sha256',json_encode($editorial,JSON_THROW_ON_ERROR)); throw_unless($m->reconcile($before,$editorial,$reviews,array_keys($reviews))['reopened']===[],RuntimeException::class,'Editorial title must not reopen reviews.'); $checks[]=['category'=>$record->opportunity_category,'id'=>$id,'field'=>$field,'reopened'=>$actual,'retained'=>array_keys($result['reviews']),'editorial_retained'=>true,'v2_signed_decisions_verified'=>true]; } // A file referenced by the contract must invalidate the gate relying on it, // even if it was not the manually selected supporting document. $before=app(OpportunityCanonicalContract::class)->validateSubmission(Opportunity::findOrFail(33));$originalId=$before['payload']['business_transaction']['entity_registration']['legal_document_id']; $id='aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa'; // In-memory isolated reference probe, never persisted or certified. $before['payload']['business_transaction']['entity_registration']['legal_document_id']=$id; $before['resources']['documents'][$id]=$before['resources']['documents'][$originalId]; $after=$before;$after['resources']['documents'][$id]['sha256']=str_repeat('f',64); throw_unless($m->hash($before,'corporate_screening')!==$m->hash($after,'corporate_screening'),RuntimeException::class,'Referenced file change was ignored.'); throw_unless($m->hash($before,'financial_review')===$m->hash($after,'financial_review'),RuntimeException::class,'Unrelated review reopened.'); return ['result'=>'passed','at'=>gmdate('c'),'rule'=>OpportunityReviewMateriality::VERSION,'checks'=>$checks,'nested_reference_material'=>true,'active_writes'=>0]; }); file_put_contents($dir.'/functional-materiality-semantic-qa-20261011.json',json_encode($proof,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR));echo json_encode($proof,JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR).PHP_EOL;