<?php
/** Private harness gate. No business implementation is replaced here. */
function cdxWriteGate(string $sql,array $bindings,$execute,array $ctx,callable $owned):string {
 $bindings=array_change_key_case($bindings,CASE_LOWER);
 $reject=static function($ok,$why){if(!$ok)throw new RuntimeException('Native DML gate: '.$why);};
 $reject($execute===null,'execute array forbidden');
 $reject(isset($ctx['nonce'],$ctx['expected_nonce'])&&$ctx['nonce']!==''&&hash_equals($ctx['expected_nonce'],$ctx['nonce']),'case nonce');
 $spec=[1=>['nutrition_time','INSERT',['function','name','order_no']],2=>['nutrition_time','UPDATE',['function','name','order_no','uuid']],3=>['nutrition_set','INSERT',['name','order_no','use_time']],4=>['nutrition_set','UPDATE',['name','order_no','use_time']],6=>['nutrition_time','UPDATE',['status']],7=>['nutrition_time','UPDATE',['status']],8=>['nutrition_set','UPDATE',['status']],9=>['nutrition_set','UPDATE',['status']],10=>['nutrition_set','UPDATE',['is_del']],11=>['nutrition_time','UPDATE',['del_flag']]];
 $case=$ctx['case']??0;$reject(isset($spec[$case]),'unknown or read-only case');[$table,$op,$columns]=$spec[$case];
 $reject(($ctx['table']??'')===$table&&($ctx['op']??'')===$op,'exact case action/table');
 $keys=array_keys($ctx['fields']??[]);sort($keys);$reject($keys===$columns,'case columns');
 $reject(in_array($ctx['lane']??'', ['B','C'],true),'lane');
 $reject(!preg_match('/[;#]|--|\/\*/',$sql),'single statement');
 $sql=strtolower(preg_replace('/\s+/',' ',trim(str_replace(['`','"'],'',$sql))));
 $used=[];$value=static function($placeholder)use($bindings,&$used,$reject){$reject(isset($bindings[$placeholder])&&array_key_exists('value',$bindings[$placeholder]),'bound placeholder');$used[]=$placeholder;return $bindings[$placeholder]['value'];};
 $data=[];$uuid=null;
 if($op==='INSERT'){
  $reject(preg_match('/^insert into ydy_'.$table.' \(([^)]+)\) values \(([^)]+)\)$/D',$sql,$m)===1,'exact INSERT shape');
  $fields=array_map('trim',explode(',',$m[1]));$params=array_map('trim',explode(',',$m[2]));$reject(count($fields)===count($params)&&count(array_unique($fields))===count($fields),'insert arity');
  foreach($fields as $i=>$field){$reject(preg_match('/^:[a-z_0-9]+$/D',$params[$i])===1,'bound insert');$data[$field]=$value($params[$i]);}
  $expected=$columns;array_push($expected,'create_by','create_time','uuid');sort($expected);$actual=array_keys($data);sort($actual);$reject($actual===$expected,'insert exact columns');
  $uuid=$data['uuid'];$reject(is_string($uuid)&&preg_match('/^[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}$/D',$uuid),'generated guid');
  $reject(hash('sha256',(string)$data['create_by'])===$ctx['creator_sha'],'actual creator');
  $reject(is_string($data['create_time'])&&preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/D',$data['create_time'])&&abs(time()-strtotime($data['create_time']))<=120,'actual API clock');
  $reject($owned($table,$uuid,true)===0,'insert UUID absence');
 }else{
  $reject(preg_match('/^update ydy_'.$table.' set (.+) where uuid (?:= (:[a-z_0-9]+)|in \((:[a-z_0-9]+)\))(?: and status <> (:[a-z_0-9]+))?$/D',$sql,$m)===1,'single UUID WHERE');
  foreach(explode(',',$m[1]) as $assignment){$reject(preg_match('/^\s*([a-z_]+)\s*=\s*(:[a-z_0-9]+)\s*$/D',$assignment,$a)===1,'bound update assignment');$reject(!array_key_exists($a[1],$data),'duplicate assignment');$data[$a[1]]=$value($a[2]);}
  $actual=array_keys($data);sort($actual);$reject($actual===$columns,'update exact columns');
  $uuid=$value(($m[2]??'')!==''?$m[2]:$m[3]);$reject(is_string($uuid)&&$uuid===($ctx['uuid']??null),'owned UUID');
  if($ctx['require_atomic']??false)$reject(!empty($m[4]),'required approved atomic predicate');
  if(!empty($m[4])){$reject($ctx['lane']==='C'&&in_array($case,[6,7,8,9],true),'C canonical atomic guard only');$reject((string)$value($m[4])==='0','desired status predicate');}
  $reject($owned($table,$uuid,false)===1,'exact one marker-owned row');
 }
 foreach($ctx['fields'] as $field=>$expected)$reject((string)($data[$field]??'')===(string)$expected,'exact value '.$field);
 $actual=array_keys($bindings);sort($actual);$used=array_values(array_unique($used));sort($used);$reject($actual===$used,'no unused bindings');
 return $op;
}
