def onTagChange(initialChange, newValue, previousValue, event, executionCount):
	# ============================================================================
	# Gateway Tag Change Script - MTN6_SCADA/Item Change
	# Triggers on: Item_000..Item_100 bData_Ready (listed in Tags tab)
	# Logic:
	#   - Only act when:
	#       * not initialChange
	#       * quality is good
	#       * tag ends with /bData_Ready
	#       * rising edge 0 -> 1
	#   - Then:
	#       * Read sibling tags
	#       * INSERT into item_data
	#       * Reset bData_Ready to 0
	# ============================================================================
	
	DB_NAME = "MariaDB"
	import system
	
	# ============================================================================
	# ENTRY BLOCK – runs on every configured tag change
	# Objects: event, initialChange, newValue, previousValue, executionCount
	# ============================================================================
	
	logger = system.util.getLogger("ItemDataGateway")
	
	tag_path = str(event.getTagPath())
	
	# Quality check
	quality_ok = newValue.getQuality().isGood()
	
	# Rising edge detection 0 -> 1 (defensive)
	try:
	    prev_raw = previousValue.getValue()
	    cur_raw  = newValue.getValue()
	
	    prev_val = int(prev_raw) if prev_raw not in (None, "") else 0
	    cur_val  = int(cur_raw)  if cur_raw  not in (None, "") else 0
	except Exception:
	    prev_val = 0
	    cur_val = 0
	
	is_rising_edge = (prev_val == 0 and cur_val == 1)
	
	# Gate all conditions in one boolean
	should_process = (
	    (not initialChange) and
	    quality_ok and
	    tag_path.endswith("/bData_Ready") and
	    is_rising_edge
	)
	
	if should_process:
	    try:
	        parent = tag_path.rsplit("/", 1)[0]
	
	        read_paths = [
	            parent + "/sBarcode",
	            parent + "/iPackage_Length",
	            parent + "/adiSort_Code_0",
	            parent + "/asRequested_Dest_ID_0",
	            parent + "/sActual_Dest_ID",
	            parent + "/sLocation_ID",
	            parent + "/iItem_Carrier_Count",
	            parent + "/diPLC_RecordNumber",
	        ]
	
	        results = system.tag.readBlocking(read_paths)
	
	        if not all(r.quality.isGood() for r in results):
	            logger.warn(
	                "Bad quality reading tags for [{}]: {}".format(
	                    parent, [str(r.quality) for r in results]
	                )
	            )
	        else:
	            logger.warn("HELLO")
	            barcode       = results[0].value
	            length        = results[1].value
	            sort_code     = results[2].value
	            req_dest      = results[3].value
	            act_dest      = results[4].value
	            location_id   = results[5].value
	            carrier_count = results[6].value
	            record_num    = results[7].value
	
	            sql = """
	                INSERT INTO item_data (
	                    t_stamp,
	                    sBarcode,
	                    iPackage_Length,
	                    adiSort_Code_0,
	                    asRequested_Dest_ID_0,
	                    sActual_Dest_ID,
	                    sLocation_ID,
	                    iItem_Carrier_Count,
	                    diPLC_RecordNumber
	                )
	                VALUES (CURRENT_TIMESTAMP, ?, ?, ?, ?, ?, ?, ?, ?)
	            """
	
	            params = [
	                barcode,
	                length,
	                sort_code,
	                req_dest,
	                act_dest,
	                location_id,
	                carrier_count,
	                record_num,
	            ]
	
	            system.db.runPrepUpdate(sql, params, DB_NAME)
	
	            # Reset handshake to 0
	            wr = system.tag.writeBlocking([tag_path], [0])
	            if not wr[0].isGood():
	                logger.warn("Failed to reset {}: {}".format(tag_path, wr[0]))
	
	    except Exception as ex:
	        logger.error("Error processing {}: {}".format(tag_path, ex))
	        # Best-effort reset on error so PLC doesn't hang
	        try:
	            system.tag.writeBlocking([tag_path], [0])
	        except Exception:
	            pass
	