diff --git a/src/service/service/service_handlers/l3nm_nce/ConfigRules.py b/src/service/service/service_handlers/l3nm_nce/ConfigRules.py
index d6bcadb45ba0190ac31b2b8a0329fca92193e73c..0544d897606afe950725349bfeb68c365189aa21 100644
--- a/src/service/service/service_handlers/l3nm_nce/ConfigRules.py
+++ b/src/service/service/service_handlers/l3nm_nce/ConfigRules.py
@@ -1,4 +1,4 @@
-# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/src/service/service/service_handlers/l3nm_nce/L3NMNCEServiceHandler.py b/src/service/service/service_handlers/l3nm_nce/L3NMNCEServiceHandler.py
index cbf92ac802edc8ecfa09e2920180538752124f3d..1317bd0615e4789d7ba76e8c0c6b0923d8f2dec7 100644
--- a/src/service/service/service_handlers/l3nm_nce/L3NMNCEServiceHandler.py
+++ b/src/service/service/service_handlers/l3nm_nce/L3NMNCEServiceHandler.py
@@ -1,4 +1,4 @@
-# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
 import json
 import logging
 import re
-from typing import Any, List, Optional, Tuple, Union
+from typing import Any, List, Optional, Tuple, Union, TypedDict, Dict
 from uuid import uuid4
 
 from deepdiff import DeepDiff
@@ -40,6 +40,7 @@ CANDIDATE_RESOURCE_KEY = "candidate_ietf_slice"
 LOGGER = logging.getLogger(__name__)
 
 METRICS_POOL = MetricsPool("Service", "Handler", labels={"handler": "l3nm_nce"})
+
 SDP_DIFF_RE = re.compile(
     r"^root\[\'network-slice-services\'\]\[\'slice-service\'\]\[0\]\[\'sdps\'\]\[\'sdp\'\]\[(\d)\]$"
 )
@@ -51,9 +52,20 @@ MATCH_CRITERION_DIFF_RE = re.compile(
 )
 
 
+class Ipv4Info(TypedDict):
+    src_ip: str
+    dst_ip: str
+    src_port: str
+    dst_port: str
+
+
 def get_removed_items(
     candidate_ietf_slice_dict: dict, running_ietf_slice_dict: dict
 ) -> dict:
+    """
+    For the 'iterable_item_removed' scenario, returns dict with removed sdp / connection_group / match_criterion info.
+    Raises an exception if there's inconsistent data or multiple items removed (which is not supported).
+    """
     removed_items = {
         "sdp": {"sdp_idx": None, "value": {}},
         "connection_group": {"connection_group_idx": None, "value": {}},
@@ -63,20 +75,24 @@ def get_removed_items(
             "value": {},
         },
     }
+
     running_slice_services = running_ietf_slice_dict["network-slice-services"][
         "slice-service"
     ][0]
-    running_slice_sdps = [sdp["id"] for sdp in running_slice_services["sdps"]["sdp"]]
     candidate_slice_services = candidate_ietf_slice_dict["network-slice-services"][
         "slice-service"
     ][0]
+
+    running_slice_sdps = [sdp["id"] for sdp in running_slice_services["sdps"]["sdp"]]
     candidiate_slice_sdps = [
         sdp["id"] for sdp in candidate_slice_services["sdps"]["sdp"]
     ]
     removed_sdps = set(running_slice_sdps) - set(candidiate_slice_sdps)
+
     if len(removed_sdps) > 1:
-        raise Exception("Multiple SDPs removed")
-    removed_sdp_id = list(removed_sdps)[0]
+        raise Exception("Multiple SDPs removed - not supported.")
+    removed_sdp_id = removed_sdps.pop()
+
     removed_items["sdp"]["sdp_idx"] = running_slice_sdps.index(removed_sdp_id)
     removed_items["sdp"]["value"] = next(
         sdp
@@ -88,7 +104,7 @@ def get_removed_items(
         "match-criterion"
     ]
     if len(match_criteria) > 1:
-        raise Exception("Multiple match criteria found")
+        raise Exception("Multiple match criteria found - not supported")
     match_criterion = match_criteria[0]
     connection_grp_id = match_criterion["target-connection-group-id"]
     connection_groups = running_slice_services["connection-groups"]["connection-group"]
@@ -99,6 +115,7 @@ def get_removed_items(
     )
     removed_items["connection_group"]["connection_group_idx"] = connection_group[0]
     removed_items["connection_group"]["value"] = connection_group[1]
+
     for sdp in running_slice_services["sdps"]["sdp"]:
         if sdp["id"] == removed_sdp_id:
             continue
@@ -119,41 +136,116 @@ def get_removed_items(
         or removed_items["connection_group"]["connection_group_idx"] is None
     ):
         raise Exception("sdp, connection group or match criterion not found")
+
     return removed_items
 
 
 def get_custom_config_rule(
     service_config: ServiceConfig, resource_key: str
 ) -> Optional[ConfigRule]:
+    """
+    Returns the ConfigRule from service_config matching the provided resource_key
+    if found, otherwise returns None.
+    """
     for cr in service_config.config_rules:
         if (
             cr.WhichOneof("config_rule") == "custom"
             and cr.custom.resource_key == resource_key
         ):
             return cr
+    return None
 
 
-def get_running_candidate_ietf_slice_data_diff(service_config: ServiceConfig) -> dict:
-    running_ietf_slice_cr = get_custom_config_rule(service_config, RUNNING_RESOURCE_KEY)
-    running_resource_value_dict = json.loads(
-        running_ietf_slice_cr.custom.resource_value
-    )
-    candidate_ietf_slice_cr = get_custom_config_rule(
-        service_config, CANDIDATE_RESOURCE_KEY
-    )
-    candidate_resource_value_dict = json.loads(
-        candidate_ietf_slice_cr.custom.resource_value
+def get_running_candidate_ietf_slice_data_diff(service_config: ServiceConfig) -> Dict:
+    """
+    Loads the JSON from the running/candidate resource ConfigRules and returns
+    their DeepDiff comparison.
+    """
+    running_cr = get_custom_config_rule(service_config, RUNNING_RESOURCE_KEY)
+    candidate_cr = get_custom_config_rule(service_config, CANDIDATE_RESOURCE_KEY)
+
+    running_value_dict = json.loads(running_cr.custom.resource_value)
+    candidate_value_dict = json.loads(candidate_cr.custom.resource_value)
+
+    return DeepDiff(running_value_dict, candidate_value_dict)
+
+
+def extract_qos_info(
+    connection_groups: List, connection_grp_id: str, src_sdp_idx: str, dst_sdp_idx: str
+) -> Dict:
+    """
+    Extract QoS information from connection groups based on the connection group ID.
+    """
+    qos_info = {
+        "upstream": {"max_delay": "0", "bw": "0", "packet_loss": "0"},
+        "downstream": {"max_delay": "0", "bw": "0", "packet_loss": "0"},
+    }
+    connection_group = next(
+        (cg for cg in connection_groups if cg["id"] == connection_grp_id), None
     )
-    return (
-        DeepDiff(
-            running_resource_value_dict,
-            candidate_resource_value_dict,
-        ),
-        DeepDiff(
-            running_resource_value_dict,
-            candidate_resource_value_dict,
-            ignore_order=True,
-        ),
+
+    if not connection_group:
+        return qos_info
+
+    for cc in connection_group["connectivity-construct"]:
+        if (
+            cc["p2p-sender-sdp"] == src_sdp_idx
+            and cc["p2p-receiver-sdp"] == dst_sdp_idx
+        ):
+            direction = "upstream"
+        elif (
+            cc["p2p-sender-sdp"] == dst_sdp_idx
+            and cc["p2p-receiver-sdp"] == src_sdp_idx
+        ):
+            direction = "downstream"
+        else:
+            raise Exception("invalid sender and receiver sdp ids")
+        for metric_bound in cc["service-slo-sle-policy"]["slo-policy"]["metric-bound"]:
+            if (
+                metric_bound["metric-type"]
+                == "ietf-network-slice-service:one-way-delay-maximum"
+                and metric_bound["metric-unit"] == "milliseconds"
+            ):
+                qos_info[direction]["max_delay"] = metric_bound["bound"]
+            elif (
+                metric_bound["metric-type"]
+                == "ietf-network-slice-service:one-way-bandwidth"
+                and metric_bound["metric-unit"] == "Mbps"
+            ):
+                qos_info[direction]["bw"] = metric_bound["bound"]
+            elif (
+                metric_bound["metric-type"]
+                == "ietf-network-slice-service:two-way-packet-loss"
+                and metric_bound["metric-unit"] == "percentage"
+            ):
+                qos_info[direction]["packet_loss"] = metric_bound["percentile-value"]
+
+    return qos_info
+
+
+def extract_match_criterion_ipv4_info(match_criterion: Dict) -> Ipv4Info:
+    """
+    Extracts IPv4 info from the match criterion dictionary.
+    """
+    src_ip = dst_ip = src_port = dst_port = ""
+
+    for type_value in match_criterion["match-type"]:
+        m_type = type_value["type"]
+        val = type_value["value"][0]
+        if m_type == "ietf-network-slice-service:source-ip-prefix":
+            src_ip = val.split("/")[0]
+        elif m_type == "ietf-network-slice-service:destination-ip-prefix":
+            dst_ip = val.split("/")[0]
+        elif m_type == "ietf-network-slice-service:source-tcp-port":
+            src_port = val
+        elif m_type == "ietf-network-slice-service:destination-tcp-port":
+            dst_port = val
+
+    return Ipv4Info(
+        src_ip=src_ip,
+        dst_ip=dst_ip,
+        src_port=src_port,
+        dst_port=dst_port,
     )
 
 
@@ -174,22 +266,25 @@ class L3NMNCEServiceHandler(_ServiceHandler):
         chk_type("endpoints", endpoints, list)
         if len(endpoints) == 0:
             return []
+
         results = []
         try:
             context_client = ContextClient()
             service_config = self.__service.service_config
             settings = self.__settings_handler.get("/settings")
+
             src_device_uuid, src_endpoint_uuid = get_device_endpoint_uuids(endpoints[0])
             src_device_obj = self.__task_executor.get_device(
                 DeviceId(**json_device_id(src_device_uuid))
             )
             controller = self.__task_executor.get_device_controller(src_device_obj)
+
             list_devices = context_client.ListDevices(Empty())
             devices = list_devices.devices
-            device_name_device = {d.name: d for d in devices}
-            device_uuid_device = {d.device_id.device_uuid.uuid: d for d in devices}
-            running_candidate_diff, running_candidate_diff_no_order = (
-                get_running_candidate_ietf_slice_data_diff(service_config)
+            device_name_map = {d.name: d for d in devices}
+
+            running_candidate_diff = get_running_candidate_ietf_slice_data_diff(
+                service_config
             )
             candidate_ietf_slice_cr = get_custom_config_rule(
                 service_config, CANDIDATE_RESOURCE_KEY
@@ -203,15 +298,17 @@ class L3NMNCEServiceHandler(_ServiceHandler):
             running_resource_value_dict = json.loads(
                 running_ietf_slice_cr.custom.resource_value
             )
+
             service_name = running_resource_value_dict["network-slice-services"][
                 "slice-service"
             ][0]["id"]
+
             if not running_candidate_diff:  # Slice Creation
                 operation_type = "create"
-                slice_services = candidate_resource_value_dict[
-                    "network-slice-services"
-                ]["slice-service"]
-                slice_service = slice_services[0]
+
+                slice_service = candidate_resource_value_dict["network-slice-services"][
+                    "slice-service"
+                ][0]
                 sdps = slice_service["sdps"]["sdp"]
                 connection_groups = slice_service["connection-groups"][
                     "connection-group"
@@ -219,7 +316,7 @@ class L3NMNCEServiceHandler(_ServiceHandler):
                 sdp_ids = [sdp["id"] for sdp in sdps]
                 for sdp in sdps:
                     node_id = sdp["node-id"]
-                    device_obj = device_name_device[node_id]
+                    device_obj = device_name_map[node_id]
                     device_controller = self.__task_executor.get_device_controller(
                         device_obj
                     )
@@ -237,15 +334,15 @@ class L3NMNCEServiceHandler(_ServiceHandler):
                 else:
                     raise Exception("connection group id not found")
             elif "iterable_item_added" in running_candidate_diff:  # new SDP added
-                slice_services = candidate_resource_value_dict[
-                    "network-slice-services"
-                ]["slice-service"]
-                slice_service = slice_services[0]
+                operation_type = "create"
+
+                slice_service = candidate_resource_value_dict["network-slice-services"][
+                    "slice-service"
+                ][0]
                 sdps = slice_service["sdps"]["sdp"]
                 connection_groups = slice_service["connection-groups"][
                     "connection-group"
                 ]
-                operation_type = "create"
                 added_items = {
                     "sdp": {"sdp_idx": None, "value": {}},
                     "connection_group": {"connection_group_idx": None, "value": {}},
@@ -287,6 +384,7 @@ class L3NMNCEServiceHandler(_ServiceHandler):
                 connection_grp_id = connection_groups[
                     added_items["connection_group"]["connection_group_idx"]
                 ]["id"]
+
                 if (
                     connection_grp_id
                     != added_items["match_criterion"]["value"][
@@ -299,15 +397,15 @@ class L3NMNCEServiceHandler(_ServiceHandler):
                 match_criteria = new_sdp["service-match-criteria"]["match-criterion"]
                 match_criterion = match_criteria[0]
             elif "iterable_item_removed" in running_candidate_diff:  # new SDP added
-                slice_services = running_resource_value_dict["network-slice-services"][
+                operation_type = "delete"
+
+                slice_service = running_resource_value_dict["network-slice-services"][
                     "slice-service"
-                ]
-                slice_service = slice_services[0]
+                ][0]
                 sdps = slice_service["sdps"]["sdp"]
                 connection_groups = slice_service["connection-groups"][
                     "connection-group"
                 ]
-                operation_type = "delete"
                 removed_items = get_removed_items(
                     candidate_resource_value_dict, running_resource_value_dict
                 )
@@ -317,6 +415,7 @@ class L3NMNCEServiceHandler(_ServiceHandler):
                 connection_grp_id = connection_groups[
                     removed_items["connection_group"]["connection_group_idx"]
                 ]["id"]
+
                 if (
                     connection_grp_id
                     != removed_items["match_criterion"]["value"][
@@ -330,65 +429,17 @@ class L3NMNCEServiceHandler(_ServiceHandler):
                     "match-criterion"
                 ]
                 match_criterion = match_criteria[0]
-            for type_value in match_criterion["match-type"]:
-                if type_value["type"] == "ietf-network-slice-service:source-ip-prefix":
-                    src_ip = type_value["value"][0].split("/")[0]
-                elif (
-                    type_value["type"]
-                    == "ietf-network-slice-service:destination-ip-prefix"
-                ):
-                    dst_ip = type_value["value"][0].split("/")[0]
-                elif type_value["type"] == "ietf-network-slice-service:source-tcp-port":
-                    src_port = type_value["value"][0]
-                elif (
-                    type_value["type"]
-                    == "ietf-network-slice-service:destination-tcp-port"
-                ):
-                    dst_port = type_value["value"][0]
-            qos_info = {
-                "upstream": {"max_delay": "0", "bw": "0", "packet_loss": "0"},
-                "downstream": {"max_delay": "0", "bw": "0", "packet_loss": "0"},
-            }
-            for cg in connection_groups:
-                if cg["id"] != connection_grp_id:
-                    continue
-                for cc in cg["connectivity-construct"]:
-                    if (
-                        cc["p2p-sender-sdp"] == src_sdp_idx
-                        and cc["p2p-receiver-sdp"] == dst_sdp_idx
-                    ):
-                        direction = "upstream"
-                    elif (
-                        cc["p2p-sender-sdp"] == dst_sdp_idx
-                        and cc["p2p-receiver-sdp"] == src_sdp_idx
-                    ):
-                        direction = "downstream"
-                    else:
-                        raise Exception("invalid sender and receiver sdp ids")
-                    for metric_bound in cc["service-slo-sle-policy"]["slo-policy"][
-                        "metric-bound"
-                    ]:
-                        if (
-                            metric_bound["metric-type"]
-                            == "ietf-network-slice-service:one-way-delay-maximum"
-                            and metric_bound["metric-unit"] == "milliseconds"
-                        ):
-                            qos_info[direction]["max_delay"] = metric_bound["bound"]
-                        elif (
-                            metric_bound["metric-type"]
-                            == "ietf-network-slice-service:one-way-bandwidth"
-                            and metric_bound["metric-unit"] == "Mbps"
-                        ):
-                            qos_info[direction]["bw"] = metric_bound["bound"]
-                        elif (
-                            metric_bound["metric-type"]
-                            == "ietf-network-slice-service:two-way-packet-loss"
-                            and metric_bound["metric-unit"] == "percentage"
-                        ):
-                            qos_info[direction]["packet_loss"] = metric_bound[
-                                "percentile-value"
-                            ]
-                break
+            else:
+                raise Exception(
+                    "transition from candidate to running info not supported"
+                )
+
+            ip_info = extract_match_criterion_ipv4_info(match_criterion)
+
+            qos_info = extract_qos_info(
+                connection_groups, connection_grp_id, src_sdp_idx, dst_sdp_idx
+            )
+
             resource_value_dict = {
                 "uuid": service_name,
                 "operation_type": operation_type,
@@ -401,22 +452,23 @@ class L3NMNCEServiceHandler(_ServiceHandler):
                 "upstream_max_bw": 2 * int(qos_info["upstream"]["bw"]) * 1e6,
                 "downstream_assure_bw": int(qos_info["downstream"]["bw"]) * 1e6,
                 "downstream_max_bw": 2 * int(qos_info["downstream"]["bw"]) * 1e6,
-                "src_ip": src_ip,
-                "src_port": src_port,
-                "dst_ip": dst_ip,
-                "dst_port": dst_port,
+                "src_ip": ip_info["src_ip"],
+                "src_port": ip_info["src_port"],
+                "dst_ip": ip_info["dst_ip"],
+                "dst_port": ip_info["dst_port"],
             }
             json_config_rules = setup_config_rules(service_name, resource_value_dict)
-            LOGGER.debug(f"Config Rules: {json_config_rules}")
+
             del controller.device_config.config_rules[:]
             for jcr in json_config_rules:
                 controller.device_config.config_rules.append(ConfigRule(**jcr))
+
             self.__task_executor.configure_device(controller)
             LOGGER.debug('Configured device "{:s}"'.format(controller.name))
+
         except Exception as e:  # pylint: disable=broad-except
-            LOGGER.exception(f"P4: {e}")
-            raise e
             results.append(e)
+
         return results
 
     @metered_subclass_method(METRICS_POOL)
diff --git a/src/service/service/service_handlers/l3nm_nce/__init__.py b/src/service/service/service_handlers/l3nm_nce/__init__.py
index 53d5157f750bfb085125cbd33faff1cec5924e14..3ccc21c7db78aac26daa1f8c5ff8e1ffd3f35460 100644
--- a/src/service/service/service_handlers/l3nm_nce/__init__.py
+++ b/src/service/service/service_handlers/l3nm_nce/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.