<?php
// Approved actual Food schema/date audit only. No App/Auth/HTTP/DDL/DML.
set_exception_handler(static function(Throwable $e){$f=__DIR__.'/private/date-fresh-error.json';$h=fopen($f,'xb');fwrite($h,json_encode(['class'=>get_class($e),'message'=>$e->getMessage(),'line'=>$e->getLine(),'observer'=>$GLOBALS['FOOD_OBSERVER']??[]],JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION));fclose($h);chmod($f,0600);fwrite(STDERR,'Date readonly path stopped; other getters unaffected'.PHP_EOL);exit(1);});
$GLOBALS['FOOD_DATE_FRESH_ACTIVE']=true;require __DIR__.'/common.php';if(is_file(__DIR__.'/private/date-fresh-summary.json'))throw new RuntimeException('No repeated audit');if($lane==='B')$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,false);require_once __DIR__.'/ObserverGate.php';
$classify=static function($v){if($v===null)return 'NULL';if(!is_string($v)||!preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,6}))?$/D',$v,$m))return 'invalid';if((int)$m[1]===0||(int)$m[2]===0||(int)$m[3]===0)return 'zero-date';if((int)$m[1]<1000||!checkdate((int)$m[2],(int)$m[3],(int)$m[1])||(int)$m[4]>23||(int)$m[5]>59||(int)$m[6]>59)return 'invalid';if(!isset($m[7]))return 'integral';return trim($m[7],'0')===''?'zero-fraction':'nonzero-fraction';};
$stream=static function($label,$sql,$map=false)use($db,$budget,$classify){FoodROGate::sql($sql);$budget('observer',800);$s=$db->prepare($sql);$s->execute();$f=__DIR__.'/private/date-'.$label.'.jsonl';$h=fopen($f,'xb');if(!$h)throw new RuntimeException('Immutable date rows');chmod($f,0600);$all=hash_init('sha256');$other=hash_init('sha256');$ids=hash_init('sha256');$n=0;$counts=['create_time'=>[],'update_time'=>[]];$changed=['create_time'=>0,'update_time'=>0];while($row=$s->fetch(PDO::FETCH_ASSOC)){$row=array_change_key_case($row,CASE_LOWER);foreach($row as $v)if(is_resource($v))throw new RuntimeException('Unexpected LOB/resource in actual no-LOB Food');$n++;hash_update($all,serialize($row));hash_update($ids,serialize($row['id']));if(!$map){if(count($row)!==62)throw new RuntimeException('Actual complete62 row');$o=$row;unset($o['create_time'],$o['update_time']);if(count($o)!==60)throw new RuntimeException('Actual other60');$oh=hash('sha256',serialize($o));hash_update($other,$oh);foreach(['create_time','update_time']as $key){$c=$classify($row[$key]);$counts[$key][$c]=($counts[$key][$c]??0)+1;}$record=['row'=>$row,'native_types'=>array_map('gettype',$row),'other60_typed_sha256'=>$oh];}else{foreach(['create_time','update_time']as $key)if($row[$key.'_old']!==$row[$key.'_zero'])$changed[$key]++;$record=['map'=>$row,'native_types'=>array_map('gettype',$row)];}$j=json_encode($record,JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION);if($j===false)throw new RuntimeException('Raw native date row JSON');fwrite($h,$j."\n");}fclose($h);$r=['label'=>$label,'sql'=>$s->queryString,'binds'=>[],'rows'=>$n,'whole_native_typed_sha256'=>hash_final($all),'other60_typed_sha256'=>hash_final($other),'row_ids_typed_sha256'=>hash_final($ids),'date_classes'=>$counts,'changed_by_actual_CAST0'=>$changed,'private_rows_file'=>basename($f),'private_file_sha256'=>hash_file('sha256',$f),'rowCount'=>$s->rowCount()];$GLOBALS['FOOD_OBSERVER'][]=['role'=>'store','sql'=>$sql,'binds'=>[],'stream_summary'=>$r];return $r;};
$metadata=[];
if($lane==='B'){$metadata['identity']=$q('store','SELECT DATABASE() AS db,VERSION() AS version,@@SESSION.sql_mode AS sql_mode');$metadata['columns']=$q('store','SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY ORDINAL_POSITION',['ydy_foods_composition']);$budget('observer',800);$s=$db->prepare('SHOW CREATE TABLE ydy_foods_composition');$s->execute();$ddl=$s->fetchAll(PDO::FETCH_ASSOC);$metadata['table_ddl']=$ddl;$GLOBALS['FOOD_OBSERVER'][]=['role'=>'store','sql'=>'SHOW CREATE TABLE ydy_foods_composition','binds'=>[],'result'=>$ddl];$metadata['indexes']=$q('store','SELECT * FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY INDEX_NAME,SEQ_IN_INDEX',['ydy_foods_composition']);$metadata['key_columns']=$q('store','SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA=DATABASE() AND (TABLE_NAME=? OR REFERENCED_TABLE_NAME=?) ORDER BY TABLE_NAME,CONSTRAINT_NAME,ORDINAL_POSITION',['ydy_foods_composition','ydy_foods_composition']);$metadata['reference_rules']=$q('store','SELECT * FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_SCHEMA=DATABASE() AND (TABLE_NAME=? OR REFERENCED_TABLE_NAME=?)',['ydy_foods_composition','ydy_foods_composition']);$metadata['triggers']=$q('store','SELECT * FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE=?',['ydy_foods_composition']);$before=$stream('before62','SELECT * FROM ydy_foods_composition ORDER BY id');$after=null;$mapping=null;
}else{$metadata['version']=$q('store','SELECT * FROM V$VERSION');$metadata['columns']=$q('store','SELECT * FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID',['YDY_FOODS_COMPOSITION']);$metadata['table_ddl']=$q('store',"SELECT DBMS_METADATA.GET_DDL('TABLE',?,'ZHCT_APP') AS ddl FROM DUAL",['YDY_FOODS_COMPOSITION']);$metadata['indexes']=$q('store','SELECT * FROM USER_INDEXES WHERE TABLE_NAME=? ORDER BY INDEX_NAME',['YDY_FOODS_COMPOSITION']);$metadata['index_columns']=$q('store','SELECT * FROM USER_IND_COLUMNS WHERE TABLE_NAME=? ORDER BY INDEX_NAME,COLUMN_POSITION',['YDY_FOODS_COMPOSITION']);$metadata['constraints']=$q('store',"SELECT * FROM USER_CONSTRAINTS WHERE TABLE_NAME=? OR CONSTRAINT_TYPE='R' ORDER BY TABLE_NAME,CONSTRAINT_NAME",['YDY_FOODS_COMPOSITION']);$metadata['constraint_columns']=$q('store',"SELECT * FROM USER_CONS_COLUMNS WHERE TABLE_NAME=? OR CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE CONSTRAINT_TYPE='R') ORDER BY TABLE_NAME,CONSTRAINT_NAME,POSITION",['YDY_FOODS_COMPOSITION']);$metadata['triggers']=$q('store','SELECT * FROM USER_TRIGGERS WHERE TABLE_NAME=?',['YDY_FOODS_COMPOSITION']);$metadata['objects']=$q('store','SELECT OBJECT_NAME,OBJECT_TYPE,STATUS FROM USER_OBJECTS WHERE OBJECT_NAME IN (?,?) ORDER BY OBJECT_NAME',['YDY_FOODS_COMPOSITION','TRG_YDY_FOODS_COMPOSITION_UT']);$metadata['dependencies']=$q('store','SELECT * FROM USER_DEPENDENCIES WHERE REFERENCED_OWNER=? AND REFERENCED_NAME=?',['ZHCT_APP','YDY_FOODS_COMPOSITION']);$before=$stream('before62','SELECT * FROM ydy_foods_composition ORDER BY id');$mapping=$stream('map0',"SELECT ID,TO_CHAR(CREATE_TIME,'YYYY-MM-DD HH24:MI:SS.FF6') AS create_time_old,TO_CHAR(CAST(CREATE_TIME AS DATETIME(0)),'YYYY-MM-DD HH24:MI:SS.FF6') AS create_time_zero,TO_CHAR(UPDATE_TIME,'YYYY-MM-DD HH24:MI:SS.FF6') AS update_time_old,TO_CHAR(CAST(UPDATE_TIME AS DATETIME(0)),'YYYY-MM-DD HH24:MI:SS.FF6') AS update_time_zero FROM YDY_FOODS_COMPOSITION ORDER BY ID",true);$after=$stream('after62','SELECT * FROM ydy_foods_composition ORDER BY id');if($before['rows']!==$after['rows']||$before['whole_native_typed_sha256']!==$after['whole_native_typed_sha256']||$before['other60_typed_sha256']!==$after['other60_typed_sha256']||$before['row_ids_typed_sha256']!==$mapping['row_ids_typed_sha256'])throw new RuntimeException('Fresh date row set/other60 drift');$metadata['clock']=$q('store','SELECT CURRENT_TIMESTAMP AS full_clock,CURRENT_TIMESTAMP(0) AS zero_clock FROM DUAL');}
if(count($metadata['columns'])!==62)throw new RuntimeException('Fresh column count62');$types=[];$lob=[];foreach($metadata['columns']as $c){$t=strtoupper($c['data_type']);$types[$t]=($types[$t]??0)+1;if(in_array($t,['CLOB','BLOB','TEXT','LONGVARCHAR'],true))$lob[]=$c['column_name'];}$bad=0;foreach($before['date_classes']as $classes)foreach(['NULL','invalid','zero-date']as $key)$bad+=$classes[$key]??0;$freshReads=(int)file_get_contents(__DIR__.'/private/budget-date-fresh.json');$summary=['lane'=>$lane,'fresh_readonly'=>$freshReads,'cap'=>$lane==='B'?8:18,'Auth'=>0,'HTTP'=>0,'DML'=>0,'DDL'=>0,'actual_columns'=>62,'actual_types'=>$types,'actual_LOB_fields'=>$lob,'rows'=>$before['rows'],'date_classes'=>$before['date_classes'],'actual_CAST0_changed'=>$mapping['changed_by_actual_CAST0']??null,'other60_typed_sha256'=>$before['other60_typed_sha256'],'whole_before_after_equal'=>$after!==null?true:null,'current_trigger_count'=>count($metadata['triggers']),'invalid_NULL_zero_count'=>$bad,'DDL_path_blocked_by_dates'=>$bad>0,'formal_repair_executed'=>false,'natural_values_private_only'=>true];$save('date-fresh-private.json',['summary'=>$summary,'metadata'=>$metadata,'before'=>$before,'mapping'=>$mapping,'after'=>$after,'observer'=>$GLOBALS['FOOD_OBSERVER']]);$save('date-fresh-summary.json',$summary);echo json_encode($summary,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE),PHP_EOL;
