<?php
declare(strict_types=1);
$mode=$argv[1]??'';if(!in_array($mode,['dry-run','apply'],true)||getenv('MR3_LANE')!=='C')exit(78);define('CDX_MS_CONTEXT',true);require __DIR__.'/preflight.php';
$table='YDY_MARKETING_STRATEGY';$constraint='CDX_MS_CONSUME_SCENE_UINT8';$comment='消费场景：1本人餐/未订餐现场消费 2亲友餐 3招待餐 4外卖点餐 5普通消费';$columns=$q('SELECT COLUMN_NAME,DATA_TYPE,DATA_PRECISION,DATA_SCALE,NULLABLE,DATA_DEFAULT FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID',[$table]);$names=array_map(static function($r){return strtoupper($r['column_name']);},$columns);$check(count($names)===19&&!in_array('CONSUME_SCENE_TYPE',$names,true),'Exact 19-column missing state');foreach($names as $name)$check(preg_match('/^[A-Z_][A-Z0-9_]*$/D',$name)===1,'Metadata identifier');
$projection=implode(',',array_map(static function($s){return '"'.$s.'"';},$names));$rows=$q('SELECT '.$projection.' FROM '.$table.' ORDER BY ID');$originalSha=hash('sha256',serialize($rows));$indexes=$q('SELECT i.INDEX_NAME,i.UNIQUENESS,c.COLUMN_NAME,c.COLUMN_POSITION FROM USER_INDEXES i JOIN USER_IND_COLUMNS c ON i.INDEX_NAME=c.INDEX_NAME WHERE i.TABLE_NAME=? ORDER BY i.INDEX_NAME,c.COLUMN_POSITION',[$table]);$constraints=$q('SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,R_CONSTRAINT_NAME,SEARCH_CONDITION FROM USER_CONSTRAINTS WHERE TABLE_NAME=? ORDER BY CONSTRAINT_NAME',[$table]);$triggers=$q('SELECT TRIGGER_NAME,STATUS,TRIGGERING_EVENT FROM USER_TRIGGERS WHERE TABLE_NAME=?',[$table]);$check($triggers===[],'No trigger effects');
$ddl=["ALTER TABLE ZHCT_APP.YDY_MARKETING_STRATEGY ADD CONSUME_SCENE_TYPE SMALLINT DEFAULT 5 NOT NULL",'ALTER TABLE ZHCT_APP.YDY_MARKETING_STRATEGY ADD CONSTRAINT '.$constraint.' CHECK (CONSUME_SCENE_TYPE BETWEEN 0 AND 255)',"COMMENT ON COLUMN ZHCT_APP.YDY_MARKETING_STRATEGY.CONSUME_SCENE_TYPE IS '".$comment."'"];
$out=['mode'=>$mode,'target'=>'nonproduction-5237-ZHCT_APP.YDY_MARKETING_STRATEGY','source_definition'=>['column_type'=>'tinyint(3) unsigned','nullable'=>false,'default'=>'5','comment'=>$comment,'observed_distribution_only'=>[['value'=>1,'count'=>7],['value'=>5,'count'=>29]]],'original_columns'=>$columns,'original_rows'=>count($rows),'original_projection_sha256'=>$originalSha,'original_indexes'=>$indexes,'original_constraints'=>$constraints,'original_triggers'=>$triggers,'planned_ddl'=>$ddl,'applied_statements'=>0,'historical_semantics_not_migrated'=>true,'result'=>'dry-run-only'];
file_put_contents(__DIR__.'/repair-state-before.json',json_encode($out,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));chmod(__DIR__.'/repair-state-before.json',0600);
if($mode==='apply'){
 foreach($ddl as $sql){$db->exec($sql);++$out['applied_statements'];file_put_contents(__DIR__.'/repair-state-progress.json',json_encode($out,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));chmod(__DIR__.'/repair-state-progress.json',0600);}
 $after=$q('SELECT COLUMN_NAME,DATA_TYPE,DATA_PRECISION,DATA_SCALE,NULLABLE,DATA_DEFAULT FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID',[$table]);$afterRows=$q('SELECT '.$projection.' FROM '.$table.' ORDER BY ID');$afterIndexes=$q('SELECT i.INDEX_NAME,i.UNIQUENESS,c.COLUMN_NAME,c.COLUMN_POSITION FROM USER_INDEXES i JOIN USER_IND_COLUMNS c ON i.INDEX_NAME=c.INDEX_NAME WHERE i.TABLE_NAME=? ORDER BY i.INDEX_NAME,c.COLUMN_POSITION',[$table]);$afterConstraints=$q('SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,R_CONSTRAINT_NAME,SEARCH_CONDITION FROM USER_CONSTRAINTS WHERE TABLE_NAME=? ORDER BY CONSTRAINT_NAME',[$table]);$afterTriggers=$q('SELECT TRIGGER_NAME,STATUS,TRIGGERING_EVENT FROM USER_TRIGGERS WHERE TABLE_NAME=?',[$table]);$oldConstraints=array_values(array_filter($afterConstraints,static function($c)use($constraint){return $c['constraint_name']!==$constraint;}));$distribution=$q('SELECT CONSUME_SCENE_TYPE,COUNT(*) AS N FROM '.$table.' GROUP BY CONSUME_SCENE_TYPE');$newComment=$q('SELECT COMMENTS FROM USER_COL_COMMENTS WHERE TABLE_NAME=? AND COLUMN_NAME=?',[$table,'CONSUME_SCENE_TYPE']);
 $out['verification']=['column_count'=>count($after),'original_columns_unchanged'=>array_slice($after,0,19)===$columns,'original_rows_unchanged'=>$rows===$afterRows,'original_projection_sha256_after'=>hash('sha256',serialize($afterRows)),'indexes_unchanged'=>$indexes===$afterIndexes,'old_constraints_unchanged'=>$constraints===$oldConstraints,'new_uint8_constraint_count'=>count($afterConstraints)-count($constraints),'triggers_unchanged'=>$triggers===$afterTriggers,'new_column_default_distribution'=>$distribution,'source_comment_preserved'=>count($newComment)===1&&$newComment[0]['comments']===$comment];$v=$out['verification'];$check($v['column_count']===20&&$v['original_columns_unchanged']&&$v['original_rows_unchanged']&&$v['indexes_unchanged']&&$v['old_constraints_unchanged']&&$v['new_uint8_constraint_count']===1&&$v['triggers_unchanged']&&$v['source_comment_preserved'],'Add-only DDL verification');$out['result']='applied-and-original-19-column-state-unchanged';
}
file_put_contents(__DIR__.'/repair-result-'.$mode.'.json',json_encode($out,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));chmod(__DIR__.'/repair-result-'.$mode.'.json',0600);echo json_encode($out,JSON_UNESCAPED_UNICODE),"\n";
