<?php
// B-only shadow tool. Inclusion and --gate are pure: no config/PDO/HTTP.
function pp_reference() {
    return json_decode(<<<'PP_REFERENCE_JSON'
{
  "contract": {
    "status": "PROPOSAL_ONLY_NO_EXECUTION_AUTHORIZATION",
    "lane": "B",
    "marker": "CDXPPUT261011S1",
    "table": "cdx_pput261011_s1",
    "columns": [
      "ID",
      "LEASE_ID",
      "MEAL_ORDER_ID",
      "MEAL_ORDER_NO",
      "USER_ID",
      "UPDATE_BY",
      "RAW_REQUEST_A",
      "EXPIRE_TIME",
      "CREATE_TIME",
      "UPDATE_TIME"
    ],
    "budget": {
      "read": 120,
      "DML": 28,
      "DDL": 2,
      "HTTP": 0,
      "business_writes": 0,
      "max_rows": 4
    },
    "connection": {
      "config_path": "/workspace/zhct/zhctproject/store/application/config/local/database.php",
      "expected_database": "zhct",
      "expected_version": "5.6.50-log",
      "expected_sql_mode": "NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION",
      "charset": "utf8mb4"
    },
    "runtime_directory": "/tmp/cdx-prepay-onupdate-B-oracle-20261011",
    "read_queries": {
      "identity": {
        "SQL": "SELECT VERSION() AS VERSION,DATABASE() AS DB,@@session.sql_mode AS SQL_MODE,@@session.time_zone AS TIME_ZONE,@@session.character_set_connection AS CONNECTION_CHARSET",
        "binds": []
      },
      "clock": {
        "SQL": "SELECT CURRENT_TIMESTAMP(0) AS T0,CURRENT_TIMESTAMP(6) AS T6",
        "binds": []
      },
      "table": {
        "SQL": "SELECT TABLE_NAME,ENGINE,ROW_FORMAT,TABLE_COLLATION,CREATE_OPTIONS FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=?",
        "binds": [
          "cdx_pput261011_s1"
        ]
      },
      "indexes": {
        "SQL": "SELECT INDEX_NAME,NON_UNIQUE,COLUMN_NAME,SEQ_IN_INDEX,SUB_PART,COLLATION,INDEX_TYPE FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY INDEX_NAME,SEQ_IN_INDEX",
        "binds": [
          "cdx_pput261011_s1"
        ]
      },
      "constraints": {
        "SQL": "SELECT * FROM information_schema.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA=DATABASE() AND (TABLE_NAME=? OR CONSTRAINT_NAME=?) ORDER BY TABLE_NAME,CONSTRAINT_NAME",
        "binds": [
          "cdx_pput261011_s1",
          "PK_CDX_PPUT261011_S1"
        ]
      },
      "keys": {
        "SQL": "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",
        "binds": [
          "cdx_pput261011_s1",
          "cdx_pput261011_s1"
        ]
      },
      "triggers": {
        "SQL": "SELECT * FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=DATABASE() AND (EVENT_OBJECT_TABLE=? OR ACTION_STATEMENT LIKE ?) ORDER BY TRIGGER_NAME",
        "binds": [
          "cdx_pput261011_s1",
          "%cdx_pput261011_s1%"
        ]
      },
      "views": {
        "SQL": "SELECT TABLE_NAME,VIEW_DEFINITION FROM information_schema.VIEWS WHERE TABLE_SCHEMA=DATABASE() AND VIEW_DEFINITION LIKE ? ORDER BY TABLE_NAME",
        "binds": [
          "%cdx_pput261011_s1%"
        ]
      },
      "routines": {
        "SQL": "SELECT ROUTINE_NAME,ROUTINE_TYPE,ROUTINE_DEFINITION FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA=DATABASE() AND ROUTINE_DEFINITION LIKE ? ORDER BY ROUTINE_NAME,ROUTINE_TYPE",
        "binds": [
          "%cdx_pput261011_s1%"
        ]
      },
      "columns": {
        "SQL": "SELECT COLUMN_NAME,COLUMN_TYPE,IS_NULLABLE,COLUMN_DEFAULT,EXTRA,CHARACTER_SET_NAME,COLLATION_NAME,CHARACTER_MAXIMUM_LENGTH,CHARACTER_OCTET_LENGTH,DATETIME_PRECISION,ORDINAL_POSITION FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY ORDINAL_POSITION",
        "binds": [
          "cdx_pput261011_s1"
        ]
      },
      "ddl": {
        "SQL": "SHOW CREATE TABLE cdx_pput261011_s1",
        "binds": []
      },
      "snapshot": {
        "SQL": "SELECT T.*,CAST(ID AS CHAR) AS H_ID,CAST(MEAL_ORDER_ID AS CHAR) AS H_MEAL_ORDER_ID,CAST(USER_ID AS CHAR) AS H_USER_ID,HEX(LEASE_ID) AS H_LEASE_ID,HEX(MEAL_ORDER_NO) AS H_MEAL_ORDER_NO,HEX(UPDATE_BY) AS H_UPDATE_BY,HEX(RAW_REQUEST_A) AS H_RAW_REQUEST_A,DATE_FORMAT(EXPIRE_TIME,'%Y-%m-%d %H:%i:%s.%f') AS F_EXPIRE_TIME,DATE_FORMAT(CREATE_TIME,'%Y-%m-%d %H:%i:%s.%f') AS F_CREATE_TIME,DATE_FORMAT(UPDATE_TIME,'%Y-%m-%d %H:%i:%s.%f') AS F_UPDATE_TIME,CURRENT_TIMESTAMP(0) AS CLOCK0,CURRENT_TIMESTAMP(6) AS CLOCK6 FROM cdx_pput261011_s1 T ORDER BY ID",
        "binds": []
      },
      "warnings": {
        "SQL": "SHOW WARNINGS",
        "binds": []
      }
    },
    "cases": [
      {
        "label": "CAS4",
        "SQL": "UPDATE cdx_pput261011_s1 SET MEAL_ORDER_ID=?,MEAL_ORDER_NO=?,USER_ID=?,UPDATE_BY=? WHERE ID=? AND MEAL_ORDER_ID=?",
        "binds": [
          7,
          "CDXPPUT261011S1_ORDER",
          8,
          "miniapp",
          1,
          0
        ],
        "PDO_types": [
          1,
          2,
          1,
          2,
          1,
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          null,
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          0,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "changed => server-generated whole second"
      },
      {
        "label": "NOOP_SCALAR",
        "SQL": "UPDATE cdx_pput261011_s1 SET MEAL_ORDER_ID=? WHERE ID=?",
        "binds": [
          0,
          1
        ],
        "PDO_types": [
          1,
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          null,
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          0,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "unchanged scalar => preserve anchor"
      },
      {
        "label": "VARCHAR_CASE",
        "SQL": "UPDATE cdx_pput261011_s1 SET UPDATE_BY=? WHERE ID=?",
        "binds": [
          "leasea",
          1
        ],
        "PDO_types": [
          2,
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          null,
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          0,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "case byte change => server-generated whole second"
      },
      {
        "label": "CLOB_NULL_EMPTY",
        "SQL": "UPDATE cdx_pput261011_s1 SET RAW_REQUEST_A=? WHERE ID=?",
        "binds": [
          "",
          1
        ],
        "PDO_types": [
          2,
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          null,
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          0,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "NULL to non-NULL empty => changed"
      },
      {
        "label": "CLOB_EMPTY_NULL",
        "SQL": "UPDATE cdx_pput261011_s1 SET RAW_REQUEST_A=? WHERE ID=?",
        "binds": [
          null,
          1
        ],
        "PDO_types": [
          0,
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          "",
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          2,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "empty to NULL => changed"
      },
      {
        "label": "CLOB_SAME",
        "SQL": "UPDATE cdx_pput261011_s1 SET RAW_REQUEST_A=? WHERE ID=?",
        "binds": [
          "原始A",
          1
        ],
        "PDO_types": [
          2,
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          "原始A",
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          2,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "SOURCE_ORACLE_REQUIRED; do not assume LOB assignment no-op"
      },
      {
        "label": "CLOB_CASE",
        "SQL": "UPDATE cdx_pput261011_s1 SET RAW_REQUEST_A=? WHERE ID=?",
        "binds": [
          "原始a",
          1
        ],
        "PDO_types": [
          2,
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          "原始A",
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          2,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "CLOB case byte change => changed"
      },
      {
        "label": "EXPLICIT_SELF_CHANGED",
        "SQL": "UPDATE cdx_pput261011_s1 SET MEAL_ORDER_ID=?,UPDATE_TIME=UPDATE_TIME WHERE ID=?",
        "binds": [
          7,
          1
        ],
        "PDO_types": [
          1,
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          null,
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          0,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "explicit self preserves anchor despite other change"
      },
      {
        "label": "EXPLICIT_VALUE_CHANGED",
        "SQL": "UPDATE cdx_pput261011_s1 SET MEAL_ORDER_ID=?,UPDATE_TIME=? WHERE ID=?",
        "binds": [
          7,
          "2001-01-01 09:07:25.720472",
          1
        ],
        "PDO_types": [
          1,
          2,
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          null,
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          0,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "explicit DATETIME0 rounds to 09:07:26; never automatic current time"
      },
      {
        "label": "EXPLICIT_NULL_CHANGED",
        "SQL": "UPDATE cdx_pput261011_s1 SET MEAL_ORDER_ID=?,UPDATE_TIME=? WHERE ID=?",
        "binds": [
          7,
          null,
          1
        ],
        "PDO_types": [
          1,
          0,
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          null,
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          0,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "SOURCE_ORACLE_REQUIRED under actual SQL_MODE; preserve warning/error and full before/after"
      },
      {
        "label": "EXPLICIT_DEFAULT_CHANGED",
        "SQL": "UPDATE cdx_pput261011_s1 SET MEAL_ORDER_ID=?,UPDATE_TIME=DEFAULT WHERE ID=?",
        "binds": [
          7,
          1
        ],
        "PDO_types": [
          1,
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          null,
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          0,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "explicit DEFAULT observed against local clock; no assumption it is a no-op"
      },
      {
        "label": "ALL9_SELF",
        "SQL": "UPDATE cdx_pput261011_s1 SET ID=ID,LEASE_ID=LEASE_ID,MEAL_ORDER_ID=MEAL_ORDER_ID,MEAL_ORDER_NO=MEAL_ORDER_NO,USER_ID=USER_ID,UPDATE_BY=UPDATE_BY,RAW_REQUEST_A=RAW_REQUEST_A,EXPIRE_TIME=EXPIRE_TIME,CREATE_TIME=CREATE_TIME WHERE ID=?",
        "binds": [
          1
        ],
        "PDO_types": [
          1
        ],
        "reset_binds": [
          "CDXPPUT261011S1",
          0,
          "",
          0,
          "leaseA",
          null,
          "2000-01-01 00:00:00",
          "2001-01-01 00:00:00",
          "2001-01-01 00:00:00",
          1
        ],
        "reset_PDO_types": [
          2,
          1,
          2,
          1,
          2,
          0,
          2,
          2,
          2,
          1
        ],
        "hypothesis": "SOURCE_ORACLE_REQUIRED; Staff ALL76_SELF counterexample remains open"
      }
    ]
  },
  "create": "CREATE TABLE cdx_pput261011_s1 (ID INT NOT NULL,LEASE_ID VARCHAR(32) NOT NULL,MEAL_ORDER_ID INT UNSIGNED NOT NULL DEFAULT 0,MEAL_ORDER_NO VARCHAR(32) NOT NULL DEFAULT '',USER_ID INT UNSIGNED NOT NULL DEFAULT 0,UPDATE_BY VARCHAR(32) NOT NULL DEFAULT '',RAW_REQUEST_A TEXT NULL,EXPIRE_TIME DATETIME(0) NOT NULL DEFAULT '2000-01-01 00:00:00',CREATE_TIME DATETIME(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,UPDATE_TIME DATETIME(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,CONSTRAINT PK_CDX_PPUT261011_S1 PRIMARY KEY(ID)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci",
  "reset": "UPDATE cdx_pput261011_s1 SET LEASE_ID=?,MEAL_ORDER_ID=?,MEAL_ORDER_NO=?,USER_ID=?,UPDATE_BY=?,RAW_REQUEST_A=?,EXPIRE_TIME=?,CREATE_TIME=?,UPDATE_TIME=? WHERE ID=?",
  "drop": "DROP TABLE cdx_pput261011_s1",
  "seeds": [
    {
      "ordinal": 21,
      "kind": "DML",
      "label": "SEED1",
      "role": "seed",
      "SQL": "INSERT INTO cdx_pput261011_s1 (ID,LEASE_ID,MEAL_ORDER_ID,MEAL_ORDER_NO,USER_ID,UPDATE_BY,RAW_REQUEST_A,EXPIRE_TIME,CREATE_TIME,UPDATE_TIME) VALUES (?,?,?,?,?,?,?,?,?,?)",
      "binds": [
        1,
        "CDXPPUT261011S1",
        0,
        "",
        0,
        "leaseA",
        null,
        "2000-01-01 00:00:00",
        "2001-01-01 00:00:00",
        "2001-01-01 00:00:00"
      ],
      "PDO_types": [
        1,
        2,
        1,
        2,
        1,
        2,
        0,
        2,
        2,
        2
      ],
      "seed_id": 1
    },
    {
      "ordinal": 25,
      "kind": "DML",
      "label": "SEED2",
      "role": "seed",
      "SQL": "INSERT INTO cdx_pput261011_s1 (ID,LEASE_ID,MEAL_ORDER_ID,MEAL_ORDER_NO,USER_ID,UPDATE_BY,RAW_REQUEST_A,EXPIRE_TIME,CREATE_TIME,UPDATE_TIME) VALUES (?,?,?,?,?,?,?,?,?,?)",
      "binds": [
        2,
        "CDXPPUT261011S1",
        0,
        "",
        0,
        "",
        null,
        "2001-01-01 01:01:01.499999",
        "2001-01-01 01:01:01.499999",
        "2001-01-01 01:01:01.499999"
      ],
      "PDO_types": [
        1,
        2,
        1,
        2,
        1,
        2,
        0,
        2,
        2,
        2
      ],
      "seed_id": 2
    },
    {
      "ordinal": 29,
      "kind": "DML",
      "label": "SEED3",
      "role": "seed",
      "SQL": "INSERT INTO cdx_pput261011_s1 (ID,LEASE_ID,MEAL_ORDER_ID,MEAL_ORDER_NO,USER_ID,UPDATE_BY,RAW_REQUEST_A,EXPIRE_TIME,CREATE_TIME,UPDATE_TIME) VALUES (?,?,?,?,?,?,?,?,?,?)",
      "binds": [
        3,
        "CDXPPUT261011S1",
        0,
        "",
        0,
        "",
        null,
        "2001-01-01 01:01:01.500000",
        "2001-01-01 01:01:01.500000",
        "2001-01-01 01:01:01.500000"
      ],
      "PDO_types": [
        1,
        2,
        1,
        2,
        1,
        2,
        0,
        2,
        2,
        2
      ],
      "seed_id": 3
    },
    {
      "ordinal": 33,
      "kind": "DML",
      "label": "SEED4",
      "role": "seed",
      "SQL": "INSERT INTO cdx_pput261011_s1 (ID,LEASE_ID) VALUES (?,?)",
      "binds": [
        4,
        "CDXPPUT261011S1"
      ],
      "PDO_types": [
        1,
        2
      ],
      "seed_id": 4
    }
  ]
}
PP_REFERENCE_JSON
, true);
}

function pp_require($ok, $message) {
    if (!$ok) { throw new RuntimeException($message); }
}

function pp_add_step(&$steps, $kind, $label, $role, $sql, $binds = [], $types = null, $extra = []) {
    if ($types === null) {
        $types = array_map(static function ($v) { return $v === null ? 0 : (is_int($v) ? 1 : 2); }, $binds);
    }
    $steps[] = array_merge(['ordinal'=>count($steps)+1,'kind'=>$kind,'label'=>$label,
        'role'=>$role,'SQL'=>$sql,'binds'=>$binds,'PDO_types'=>$types], $extra);
}

function pp_add_read(&$steps, $queries, $label, $role, $key, $extra = []) {
    pp_add_step($steps,'read',$label,$role,$queries[$key]['SQL'],$queries[$key]['binds'],null,
        array_merge(['read_query'=>$key],$extra));
}

function pp_add_operation(&$steps, $queries, $label, $role, $sql, $binds, $types, $extra) {
    pp_add_read($steps,$queries,$label.'.before','before','snapshot',array_merge(['operation_label'=>$label],$extra));
    pp_add_step($steps,'DML',$label,$role,$sql,$binds,$types,$extra);
    pp_add_read($steps,$queries,$label.'.warnings','warnings','warnings',array_merge(['operation_label'=>$label],$extra));
    pp_add_read($steps,$queries,$label.'.after','after','snapshot',array_merge(['operation_label'=>$label],$extra));
}

function pp_expected_steps($reference) {
    $p = $reference['contract']; $q = $p['read_queries']; $steps = [];
    pp_add_read($steps,$q,'pre.identity','identity','identity');
    pp_add_read($steps,$q,'pre.clock','clock','clock');
    foreach (['table','indexes','constraints','keys','triggers','views','routines'] as $key) {
        pp_add_read($steps,$q,'pre.'.$key,'collision',$key);
    }
    pp_add_step($steps,'DDL','create','create',$reference['create']);
    foreach (['columns','indexes','constraints','keys','table','ddl','triggers','views','routines'] as $key) {
        pp_add_read($steps,$q,'schema.'.$key,'schema',$key);
    }
    foreach ($reference['seeds'] as $s) {
        pp_add_operation($steps,$q,$s['label'],'seed',$s['SQL'],$s['binds'],$s['PDO_types'],['seed_id'=>$s['seed_id']]);
    }
    foreach ($p['cases'] as $c) {
        pp_add_operation($steps,$q,$c['label'].'.RESET','reset',$reference['reset'],$c['reset_binds'],$c['reset_PDO_types'],['case_label'=>$c['label']]);
        pp_add_operation($steps,$q,$c['label'],'mutation',$c['SQL'],$c['binds'],$c['PDO_types'],['case_label'=>$c['label']]);
    }
    pp_add_read($steps,$q,'cleanup.identity','cleanup','identity');
    pp_add_read($steps,$q,'cleanup.snapshot','cleanup','snapshot');
    foreach (['columns','indexes','constraints','keys','table','ddl','triggers','views','routines'] as $key) {
        pp_add_read($steps,$q,'cleanup.'.$key,'cleanup',$key);
    }
    pp_add_step($steps,'DDL','drop','drop',$reference['drop']);
    foreach (['table','indexes','constraints','keys','triggers','views','routines'] as $key) {
        pp_add_read($steps,$q,'post.'.$key,'zero',$key);
    }
    return $steps;
}

function pp_gate_plan($plan) {
    $reference = pp_reference(); $contract = $plan; unset($contract['steps']);
    pp_require($contract === $reference['contract'], 'Exact immutable B contract/lease/budget/SQL');
    pp_require(isset($plan['steps']) && $plan['steps'] === pp_expected_steps($reference), 'Exact complete literal statement ledger');
    $counts = ['read'=>0,'DML'=>0,'DDL'=>0];
    foreach ($plan['steps'] as $step) {
        pp_require(isset($counts[$step['kind']]), 'Known statement kind'); ++$counts[$step['kind']];
        pp_require(substr_count($step['SQL'],'?') === count($step['binds']), 'Placeholder count');
        pp_require(count($step['binds']) === count($step['PDO_types']), 'Bind/type count');
        foreach ($step['binds'] as $i => $value) {
            pp_require($value === null || is_string($value) || is_int($value), 'No float/object bind');
            pp_require($step['PDO_types'][$i] === ($value === null ? 0 : (is_int($value) ? 1 : 2)), 'Exact native bind type');
        }
    }
    pp_require($counts === ['read'=>120,'DML'=>28,'DDL'=>2], 'Exact120/28/2 budget');
    return $counts;
}

function pp_gate_step($plan, $step, $state) {
    pp_require(isset($plan['steps'][$state['cursor']]) && $step === $plan['steps'][$state['cursor']], 'No unknown SQL/bind/order/replay');
    pp_require($state[$step['kind']] < $plan['budget'][$step['kind']], 'Statement budget');
    if ($step['role'] === 'create') {
        pp_require(!$state['created'] && $state['collision_zero'], 'CREATE exact collision0 and not replay');
    } elseif ($step['role'] === 'drop') {
        pp_require($state['created'] && $state['drop_proof'], 'DROP original creation/row/schema/dependency proof');
    } elseif ($step['kind'] === 'DML') {
        pp_require($state['created'], 'DML only on own proven-created table');
    }
}

function pp_physical($rows) {
    foreach ($rows as &$row) { unset($row['clock0'],$row['clock6']); } unset($row);
    return $rows;
}

function pp_row_digests($rows, $plan) {
    $result=[];
    foreach ($rows as $row) {
        $values=[]; $types=[];
        foreach (array_map('strtolower',$plan['columns']) as $column) {
            $values[$column]=$row[$column]; $types[$column]=gettype($row[$column]);
        }
        $json=json_encode(['values'=>$values,'native_types'=>$types],JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION);
        pp_require($json!==false,'Full10 native row digest encoding');
        $result[(string)$row['id']]=hash('sha256',$json);
    }
    return ['rows'=>$result,'all4_or_current_rows_sha256'=>hash('sha256',json_encode($result))];
}

function pp_assert_snapshot($rows, $ids, $plan) {
    pp_require(count($rows) === count($ids) && count($rows) <= 4, 'Exact own row set');
    $columns = array_map('strtolower',$plan['columns']);
    foreach ($rows as $i => $row) {
        pp_require(count($row) === 22, 'All10 native fields plus12 full helpers');
        foreach ($columns as $column) { pp_require(array_key_exists($column,$row), 'Missing native column'); }
        pp_require((string)$row['id'] === (string)$ids[$i] && $row['lease_id'] === $plan['marker'], 'Own exact ID and lease');
        foreach (['id','meal_order_id','user_id'] as $column) {
            pp_require(is_int($row[$column]) || is_string($row[$column]), 'Native integer shape');
            pp_require($row['h_'.$column] === (string)$row[$column], 'Server exact integer text');
        }
        foreach (['lease_id','meal_order_no','update_by','raw_request_a'] as $column) {
            pp_require($row[$column] === null || is_string($row[$column]), 'Native text/null shape');
            $hex = $row[$column] === null ? null : strtoupper(bin2hex($row[$column]));
            pp_require($row['h_'.$column] === $hex, 'Complete native UTF8 bytes/HEX, including empty vs NULL');
        }
        foreach (['expire_time','create_time','update_time'] as $column) {
            pp_require(is_string($row[$column]) && preg_match('/^\d{4}-\d\d-\d\d \d\d:\d\d:\d\d$/D',$row[$column]) === 1, 'Original fsp0 native19 retained');
            pp_require($row['f_'.$column] === $row[$column].'.000000', 'Original FF6 helper exactly six zero digits');
        }
        pp_require(is_string($row['clock0']) && preg_match('/^\d{4}-\d\d-\d\d \d\d:\d\d:\d\d$/D',$row['clock0']) === 1, 'Clock0 raw native whole second');
        pp_require(is_string($row['clock6']) && preg_match('/^\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}$/D',$row['clock6']) === 1, 'Clock6 original fraction retained');
    }
}

function pp_value($actual, $expected) {
    return $expected === null ? $actual === null : (is_int($expected) ? (string)$actual === (string)$expected : $actual === $expected);
}

function pp_verify_values($row, $values, $plan) {
    foreach ($values as $column => $value) {
        pp_require(pp_value($row[strtolower($column)],$value), 'Full expected physical value: '.$column);
    }
}

function pp_clock_value($value, $before, $after) {
    return $value >= $before[0]['clock0'] && $value <= $after[0]['clock0'];
}

function pp_check_transition($before, $after, $label, $role, $success, $plan) {
    pp_require(count($before) === 4 && count($after) === 4, 'Mutation protects all4');
    pp_require(pp_physical(array_slice($before,1)) === pp_physical(array_slice($after,1)), 'IDs2/3/4 all10 fields and native types preserved');
    if (!$success) {
        pp_require($role === 'mutation' && $label === 'EXPLICIT_NULL_CHANGED' && pp_physical($before) === pp_physical($after), 'Only observed NULL failure; reset must succeed; statement atomic full row');
        return;
    }
    $case = null;
    foreach ($plan['cases'] as $c) { if ($c['label'] === $label) { $case = $c; break; } }
    pp_require($case !== null, 'Exact case label');
    if ($role === 'reset') {
        $values = array_combine(array_slice($plan['columns'],1),array_slice($case['reset_binds'],0,9));
        $values['ID'] = 1; pp_verify_values($after[0],$values,$plan); return;
    }
    $allow = ['update_time']; $values = [];
    if ($label === 'CAS4') { $allow = array_merge($allow,['meal_order_id','meal_order_no','user_id','update_by']); $values = ['meal_order_id'=>7,'meal_order_no'=>'CDXPPUT261011S1_ORDER','user_id'=>8,'update_by'=>'miniapp']; }
    elseif ($label === 'VARCHAR_CASE') { $allow[]='update_by'; $values=['update_by'=>'leasea']; }
    elseif (in_array($label,['CLOB_NULL_EMPTY','CLOB_EMPTY_NULL','CLOB_SAME','CLOB_CASE'],true)) { $allow[]='raw_request_a'; $values=['raw_request_a'=>$case['binds'][0]]; }
    elseif (strpos($label,'EXPLICIT_') === 0) { $allow[]='meal_order_id'; $values=['meal_order_id'=>7]; }
    pp_verify_values($after[0],$values,$plan);
    foreach (array_map('strtolower',$plan['columns']) as $column) {
        if (!in_array($column,$allow,true)) { pp_require($before[0][$column] === $after[0][$column], 'Undeclared physical/native-type change: '.$column); }
    }
    $ut = $after[0]['update_time']; $old = $before[0]['update_time'];
    if (in_array($label,['CLOB_SAME','ALL9_SELF'],true)) {
        pp_require($ut === $old || pp_clock_value($ut,$before,$after), 'Observed source oracle: old or local generated time');
    } elseif ($label === 'EXPLICIT_NULL_CHANGED') {
        // Native source oracle may reject, warn, assign zero datetime, or another source value.
        // Keep original19/FF6 and complete raw warnings; never replace it with an invented NOW.
    } elseif (in_array($label,['NOOP_SCALAR','EXPLICIT_SELF_CHANGED'],true)) {
        pp_require($ut === $old, 'Scalar noop or explicit self preserves source anchor');
    } elseif ($label === 'EXPLICIT_VALUE_CHANGED') {
        pp_require($ut === '2001-01-01 09:07:26', 'Explicit original .720472 rounds to next second');
    } else {
        pp_require(pp_clock_value($ut,$before,$after), 'Automatic/default time is local whole second, not rounded explicit input');
    }
}

function pp_verify_seed($before, $after, $step, $plan) {
    $id = $step['seed_id'];
    pp_require(pp_physical($before) === pp_physical(array_slice($after,0,$id-1)), 'INSERT preserves all existing native rows');
    $row = $after[$id-1];
    if ($id <= 3) {
        $values = array_combine($plan['columns'],$step['binds']);
        if ($id === 2 || $id === 3) {
            foreach (['EXPIRE_TIME','CREATE_TIME','UPDATE_TIME'] as $column) {
                $values[$column] = $id === 2 ? '2001-01-01 01:01:01' : '2001-01-01 01:01:02';
            }
        }
        pp_verify_values($row,$values,$plan);
    } else {
        pp_verify_values($row,['ID'=>4,'LEASE_ID'=>$plan['marker'],'MEAL_ORDER_ID'=>0,'MEAL_ORDER_NO'=>'','USER_ID'=>0,'UPDATE_BY'=>'','RAW_REQUEST_A'=>null,'EXPIRE_TIME'=>'2000-01-01 00:00:00'],$plan);
        pp_require(pp_clock_value($row['create_time'],$before,$after) && pp_clock_value($row['update_time'],$before,$after), 'Omitted defaults generated whole seconds within local clock');
    }
}

function pp_verify_schema($schema, $plan) {
    $names = array_map('strtolower',array_column($schema['columns'],'column_name'));
    pp_require($names === array_map('strtolower',$plan['columns']), 'Exact10 physical columns/order');
    $typeMap=['id'=>'int(11)','lease_id'=>'varchar(32)','meal_order_id'=>'int(10) unsigned',
        'meal_order_no'=>'varchar(32)','user_id'=>'int(10) unsigned','update_by'=>'varchar(32)',
        'raw_request_a'=>'text','expire_time'=>'datetime','create_time'=>'datetime','update_time'=>'datetime'];
    $defaultMap=['id'=>null,'lease_id'=>null,'meal_order_id'=>'0','meal_order_no'=>'',
        'user_id'=>'0','update_by'=>'','raw_request_a'=>null,'expire_time'=>'2000-01-01 00:00:00',
        'create_time'=>'CURRENT_TIMESTAMP','update_time'=>'CURRENT_TIMESTAMP'];
    foreach ($schema['columns'] as $i=>$column) {
        $name = strtolower($column['column_name']);
        pp_require(strtolower($column['column_type'])===$typeMap[$name] && (int)$column['ordinal_position']===$i+1, 'Exact source column type/unsigned/ordinal');
        $actualDefault=$column['column_default']; $expectedDefault=$defaultMap[$name];
        pp_require($expectedDefault===null ? $actualDefault===null : (is_string($actualDefault) && strcasecmp($actualDefault,$expectedDefault)===0), 'Every original column default');
        pp_require($column['is_nullable'] === ($name === 'raw_request_a' ? 'YES' : 'NO'), 'Source nullability');
        if (in_array($name,['expire_time','create_time','update_time'],true)) {
            pp_require((int)$column['datetime_precision'] === 0 && $column['column_type'] === 'datetime', 'Actual source fsp0 DATETIME');
            $default = $name === 'expire_time' ? '2000-01-01 00:00:00' : 'CURRENT_TIMESTAMP';
            pp_require(strcasecmp((string)$column['column_default'],$default) === 0, 'Actual source time default');
        }
        if ($name === 'update_time') { pp_require(strcasecmp($column['extra'],'on update CURRENT_TIMESTAMP') === 0, 'Source ON UPDATE'); }
        elseif ($column['extra'] !== '') { throw new RuntimeException('No other generated/identity behavior'); }
        if (in_array($name,['lease_id','meal_order_no','update_by','raw_request_a'],true)) {
            pp_require($column['character_set_name'] === 'utf8mb4' && $column['collation_name'] === 'utf8mb4_general_ci', 'Source text charset/collation');
            $length=$name==='raw_request_a'?65535:32;
            pp_require((int)$column['character_maximum_length']===$length && (int)$column['character_octet_length']===($name==='raw_request_a'?65535:128), 'Exact source character and octet capacity');
        }
    }
    pp_require(count($schema['table']) === 1 && $schema['table'][0]['engine'] === 'InnoDB', 'Atomic source InnoDB');
    pp_require(count($schema['indexes']) === 1 && $schema['indexes'][0]['index_name'] === 'PRIMARY' && strtolower($schema['indexes'][0]['column_name']) === 'id' && (int)$schema['indexes'][0]['non_unique'] === 0, 'Only own ID primary index');
    pp_require(count($schema['constraints']) === 1 && $schema['constraints'][0]['constraint_type'] === 'PRIMARY KEY', 'Only own primary constraint');
    pp_require(count($schema['keys']) === 1 && $schema['keys'][0]['referenced_table_name'] === null, 'No visible incoming/outgoing FK');
    foreach (['triggers','views','routines'] as $key) { pp_require($schema[$key] === [], 'No visible text-matched dependencies: '.$key); }
    pp_require(count($schema['ddl']) === 1 && isset($schema['ddl'][0]['create table']), 'Full original SHOW CREATE definition');
}

function pp_append($handle, $event) {
    $json = json_encode($event,JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION);
    pp_require($json !== false, 'Raw JSON encoding');
    pp_require(fwrite($handle,$json."\n") === strlen($json)+1 && fflush($handle), 'Append-only evidence flush');
}

function pp_execute($plan, $planSha, $runnerSha) {
    // This function is never invoked by --gate or the offline test suite.
    pp_require(getenv('PP_B_ROOT_APPROVAL_SHA') === $planSha && getenv('PP_B_ROOT_APPROVAL_RUNNER_SHA') === $runnerSha, 'Separate Root approval required before loading config or connecting');
    $runtime = $plan['runtime_directory'];
    pp_require(!file_exists($runtime) && !is_link($runtime), 'Fresh exact own runtime collision0; no resume/replay');
    pp_require(mkdir($runtime,0700), 'Own private evidence directory');
    $handle = fopen($runtime.'/events.jsonl','x'); pp_require($handle !== false,'Exclusive original journal');
    chmod($runtime.'/events.jsonl',0600);
    $state = ['cursor'=>0,'read'=>0,'DML'=>0,'DDL'=>0,'created'=>false,'collision_zero'=>false,'drop_proof'=>false];
    $schema = []; $cleanup = []; $last = []; $before = []; $pending = null; $identity = null;
    try {
        $cfgPath = $plan['connection']['config_path'];
        pp_require(realpath($cfgPath) === $cfgPath && !is_link($cfgPath), 'Exact original code-local config file');
        $cfg = (static function ($file) { return require $file; })($cfgPath);
        foreach (['hostname','database','username','password'] as $key) { pp_require(isset($cfg[$key]) && is_string($cfg[$key]), 'Original local config field'); }
        pp_require($cfg['database'] === $plan['connection']['expected_database'], 'Exact original B database');
        $iniPath='/workspace/zhct/zhctproject/ai_api/.env.local';
        pp_require(realpath($iniPath)===$iniPath && !is_link($iniPath),'Exact original private AI local config');
        $ini=parse_ini_file($iniPath,true,INI_SCANNER_RAW);
        pp_require(isset($ini['DATABASE_ZHCT']),'Original AI Store connection section');
        $other=$ini['DATABASE_ZHCT'];
        foreach (['hostname'=>'HOSTNAME','database'=>'DATABASE','username'=>'USERNAME','password'=>'PASSWORD'] as $key=>$otherKey) {
            pp_require(isset($other[$otherKey]) && (string)$cfg[$key]===(string)$other[$otherKey],'Original Store and AI local target identity agree');
        }
        pp_require((string)(empty($cfg['hostport'])?'3306':$cfg['hostport'])===(string)(empty($other['HOSTPORT'])?'3306':$other['HOSTPORT']),'Original local ports agree');
        unset($ini,$other);
        $dsn = 'mysql:host='.$cfg['hostname'].';port='.(empty($cfg['hostport']) ? '3306' : $cfg['hostport']).';dbname='.$cfg['database'].';charset=utf8mb4';
        $db = new PDO($dsn,$cfg['username'],$cfg['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_CASE=>PDO::CASE_LOWER,PDO::ATTR_STRINGIFY_FETCHES=>false,PDO::ATTR_EMULATE_PREPARES=>false]);
        unset($cfg,$dsn);
        pp_append($handle,['event'=>'start','plan_sha256'=>$planSha,'runner_sha256'=>$runnerSha,'lane'=>'B','utc'=>gmdate('c')]);
        foreach ($plan['steps'] as $step) {
            pp_gate_step($plan,$step,$state); ++$state[$step['kind']];
            pp_append($handle,['event'=>'sent','step'=>$step,'utc'=>gmdate('c'),'microtime'=>sprintf('%.6F',microtime(true))]);
            $stmt = $db->prepare($step['SQL']);
            foreach ($step['binds'] as $i=>$value) { pp_require($stmt->bindValue($i+1,$value,$step['PDO_types'][$i]),'Native binding succeeded'); }
            if ($step['kind'] === 'DML') {
                $pending = ['step'=>$step,'before'=>$before,'ok'=>false,'rowCount'=>null,'error'=>null,'errorInfo'=>null];
                try { $pending['ok']=$stmt->execute(); $pending['rowCount']=$stmt->rowCount(); }
                catch (Throwable $e) { $pending['error']=['class'=>get_class($e),'code'=>$e->getCode(),'message'=>$e->getMessage(),'errorInfo'=>$stmt->errorInfo()]; }
                $pending['errorInfo']=$stmt->errorInfo();
                pp_append($handle,['event'=>'DML-original-result','data'=>$pending]);
                // The next SQL is literally SHOW WARNINGS, on this same PDO. No observer SQL intervenes.
            } elseif ($step['kind'] === 'DDL') {
                pp_require($stmt->execute(), 'Native DDL succeeded');
                $state['created'] = $step['role'] === 'create';
                pp_append($handle,['event'=>'DDL-original-result','label'=>$step['label'],'ok'=>true,'errorInfo'=>$stmt->errorInfo()]);
            } else {
                pp_require($stmt->execute(),'Native read succeeded'); $rows=$stmt->fetchAll(PDO::FETCH_ASSOC);
                pp_require(count($rows)<=128,'Bounded own/catalog read'); $types=[];
                foreach ($rows as $row) { $types[]=array_map('gettype',$row); }
                $digest=$step['read_query']==='snapshot' ? pp_row_digests($rows,$plan) : null;
                pp_append($handle,['event'=>'read-original-result','label'=>$step['label'],'rows'=>$rows,'native_types'=>$types,'full10_row_digests'=>$digest,'errorInfo'=>$stmt->errorInfo()]);
                $role=$step['role']; $query=$step['read_query'];
                if ($role === 'identity') {
                    pp_require(count($rows)===1 && $rows[0]['version']===$plan['connection']['expected_version'] && $rows[0]['db']===$plan['connection']['expected_database'] && $rows[0]['sql_mode']===$plan['connection']['expected_sql_mode'], 'Actual B version/schema/unaltered SQL_MODE');
                    pp_require($rows[0]['connection_charset']==='utf8mb4','Explicit own PDO connection charset'); $identity=$rows;
                } elseif ($role === 'collision') {
                    pp_require($rows===[],'Exact table/index/constraint/FK/visible-dependency collision0');
                    if ($query==='routines') { $state['collision_zero']=true; }
                } elseif ($role === 'schema') {
                    $schema[$query]=$rows;
                    if ($query==='routines') { pp_verify_schema($schema,$plan); }
                } elseif ($role === 'before') {
                    $seedId=isset($step['seed_id']) ? $step['seed_id'] : null;
                    $ids=$seedId!==null ? ($seedId===1 ? [] : range(1,$seedId-1)) : [1,2,3,4];
                    pp_assert_snapshot($rows,$ids,$plan);
                    pp_require(pp_physical($rows)===pp_physical($last),'Full row protection before every DML'); $before=$rows;
                } elseif ($role === 'warnings') {
                    pp_require($pending!==null && $step['operation_label']===$pending['step']['label'],'Warnings immediately follow exact pending DML');
                    $pending['warnings']=$rows;
                } elseif ($role === 'after') {
                    pp_require($pending!==null && isset($pending['warnings']) && $step['operation_label']===$pending['step']['label'],'Complete original outcome/warnings before observer');
                    $write=$pending['step']; $seedId=isset($write['seed_id']) ? $write['seed_id'] : null;
                    pp_assert_snapshot($rows,$seedId!==null ? range(1,$seedId) : [1,2,3,4],$plan);
                    if ($seedId!==null) {
                        pp_require($pending['ok'] && $pending['rowCount']===1,'INSERT exactly one own row'); pp_verify_seed($pending['before'],$rows,$write,$plan);
                    } else {
                        if ($pending['ok']) { pp_require(in_array($pending['rowCount'],[0,1],true),'Native UPDATE rowCount retained0/1'); }
                        pp_check_transition($pending['before'],$rows,$write['case_label'],$write['role'],$pending['ok'],$plan);
                    }
                    pp_append($handle,['event'=>'protected-outcome','label'=>$write['label'],'hypothesis_is_not_oracle'=>true,'ok'=>$pending['ok'],'rowCount'=>$pending['rowCount'],'warnings'=>$pending['warnings'],'before'=>$pending['before'],'after'=>$rows]);
                    $last=$rows; $pending=null;
                } elseif ($role === 'cleanup') {
                    $cleanup[$query]=$rows;
                    if ($query==='identity') { pp_require($rows===$identity,'Source SQL_MODE/session identity unchanged'); }
                    elseif ($query==='snapshot') { pp_assert_snapshot($rows,[1,2,3,4],$plan); pp_require(pp_physical($rows)===pp_physical($last),'All4 final rows including source-oracle NULL result preserved'); }
                    elseif ($query==='routines') {
                        $struct=$cleanup; unset($struct['identity'],$struct['snapshot']);
                        pp_verify_schema($struct,$plan); pp_require($struct===$schema,'Full native schema/index/constraints/DDL/dependency fingerprint');
                        pp_require($state['created'] && $state['DDL']===1 && $state['DML']===28 && $pending===null,'Exact completed creation/attempt journal'); $state['drop_proof']=true;
                    }
                } elseif ($role === 'zero') { pp_require($rows===[],'Exact own objects/index/constraint/FK/visible-dependencies0 after DROP'); }
            }
            ++$state['cursor'];
        }
        pp_require($state['cursor']===150 && $state['read']===120 && $state['DML']===28 && $state['DDL']===2 && !$state['created'],'Complete approved ledger and exact own cleanup');
        pp_append($handle,['event'=>'summary','status'=>'ACTUAL_B_ORACLE_CAPTURED_REQUIRES_ROOT_REVIEW','counts'=>$state,'HTTP'=>0,'business_writes'=>0]);
        fclose($handle); echo json_encode(['status'=>'ACTUAL_B_ORACLE_CAPTURED_REQUIRES_ROOT_REVIEW','read'=>120,'DML_attempts'=>28,'DDL_attempts'=>2,'HTTP'=>0]),"\n";
    } catch (Throwable $e) {
        pp_append($handle,['event'=>'stopped_no_retry_or_automatic_cleanup','class'=>get_class($e),'code'=>$e->getCode(),'message'=>$e->getMessage(),'last_statement_errorInfo'=>isset($stmt)?$stmt->errorInfo():null,'state'=>$state]);
        fclose($handle); fwrite(STDERR,json_encode(['status'=>'STOPPED_ORIGINAL_STATE_RETAINED','class'=>get_class($e),'counts'=>$state,'automatic_cleanup'=>false])."\n"); return 1;
    }
    return 0;
}

if (isset($_SERVER['SCRIPT_FILENAME']) && realpath($_SERVER['SCRIPT_FILENAME']) === __FILE__) {
    try {
        $file=__DIR__.'/plan.json'; $raw=file_get_contents($file); pp_require($raw!==false,'Literal plan available');
        $plan=json_decode($raw,true); pp_require(is_array($plan),'Plan JSON'); $counts=pp_gate_plan($plan);
        $sha=hash('sha256',$raw); $runnerSha=hash_file('sha256',__FILE__);
        $mode=isset($argv[1]) ? $argv[1] : '--gate';
        if ($mode==='--gate') {
            echo json_encode(['status'=>'PURE_PLAN_GATE_PASS','plan_sha256'=>$sha,'runner_sha256'=>$runnerSha,'literal_counts'=>$counts,'actual_DB_connections'=>0,'actual_SQL'=>0,'actual_HTTP'=>0]),"\n";
        } else {
            pp_require($mode==='--execute','Only --gate or separately approved --execute'); exit(pp_execute($plan,$sha,$runnerSha));
        }
    } catch (Throwable $e) { fwrite(STDERR,$e->getMessage()."\n"); exit(1); }
}
