diff --git a/src/service/service/service_handlers/l3slice_ietfslice/ConfigRules.py b/src/service/service/service_handlers/l3slice_ietfslice/ConfigRules.py
index 466c53fe4b576f794091112f9c5958f2e17d5fca..173d4ba10dbf1f6a8aead912a2a1435632f94569 100644
--- a/src/service/service/service_handlers/l3slice_ietfslice/ConfigRules.py
+++ b/src/service/service/service_handlers/l3slice_ietfslice/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.
@@ -22,8 +22,114 @@ from common.tools.object_factory.ConfigRule import (
 from context.client.ContextClient import ContextClient
 
 
+def build_match_criterion(
+    vlan: str,
+    src_ip: str,
+    src_port: str,
+    dst_ip: str,
+    dst_port: str,
+    target_conn_group_id: str = "line1",
+    index: int = 1,
+) -> Dict:
+    """
+    Build the match-criterion structure used in the 'service-match-criteria'.
+    """
+    return {
+        "index": index,
+        "match-type": [
+            {"type": "ietf-network-slice-service:vlan", "value": [vlan]},
+            {
+                "type": "ietf-network-slice-service:source-ip-prefix",
+                "value": [src_ip],
+            },
+            {
+                "type": "ietf-network-slice-service:source-tcp-port",
+                "value": [src_port],
+            },
+            {
+                "type": "ietf-network-slice-service:destination-ip-prefix",
+                "value": [dst_ip],
+            },
+            {
+                "type": "ietf-network-slice-service:destination-tcp-port",
+                "value": [dst_port],
+            },
+        ],
+        "target-connection-group-id": target_conn_group_id,
+    }
+
+
+def build_sdp(
+    sdp_id: str,
+    node_id: str,
+    mgmt_ip: str,
+    ac_node_id: str,
+    ac_ep_id: str,
+    match_criterion: Dict,
+    attachment_id: str = "0",
+    attachment_description: str = "dsc",
+) -> Dict:
+    """
+    Build the sdp structure used in the 'slice_service' dictionary.
+    """
+    return {
+        "id": sdp_id,
+        "node-id": node_id,
+        "sdp-ip-address": [mgmt_ip],
+        "service-match-criteria": {"match-criterion": [match_criterion]},
+        "attachment-circuits": {
+            "attachment-circuit": [
+                {
+                    "id": attachment_id,
+                    "description": attachment_description,
+                    "ac-node-id": ac_node_id,
+                    "ac-tp-id": ac_ep_id,
+                }
+            ]
+        },
+    }
+
+
+def build_slo_policy_bound(
+    one_way_delay: int, one_way_bandwidth: int, one_way_packet_loss: float
+) -> List[Dict]:
+    """
+    Build the 'metric-bound' portion of the 'slo-policy' dictionary.
+    """
+    return [
+        {
+            "metric-type": "ietf-network-slice-service:one-way-delay-maximum",
+            "metric-unit": "milliseconds",
+            "bound": one_way_delay,
+        },
+        {
+            "metric-type": "ietf-network-slice-service:one-way-bandwidth",
+            "metric-unit": "Mbps",
+            "bound": one_way_bandwidth,
+        },
+        {
+            "metric-type": "ietf-network-slice-service:two-way-packet-loss",
+            "metric-unit": "percentage",
+            "percentile-value": one_way_packet_loss,
+        },
+    ]
+
+
+def _get_device_endpoint_name(device_obj, endpoint_uuid: str) -> str:
+    """
+    Given a device object and an endpoint UUID, return the device endpoint name.
+    Raises an exception if not found.
+    """
+    for d_ep in device_obj.device_endpoints:
+        if d_ep.endpoint_id.endpoint_uuid.uuid == endpoint_uuid:
+            return d_ep.name
+    raise Exception("Endpoint not found")
+
+
 def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]:
     operation_type: str = json_settings["operation_type"]
+
+    # Source parameters
     src_node_id: str = json_settings["src_node_id"]
     src_mgmt_ip_address: str = json_settings["src_mgmt_ip_address"]
     src_ac_node_id: str = json_settings["src_ac_node_id"]
@@ -38,6 +144,8 @@ def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]:
     source_one_way_packet_loss: float = float(
         json_settings["source_one_way_packet_loss"]
     )
+
+    # Destination parameters
     dst_node_id: str = json_settings["dst_node_id"]
     dst_mgmt_ip_address: str = json_settings["dst_mgmt_ip_address"]
     dst_ac_node_id: str = json_settings["dst_ac_node_id"]
@@ -54,101 +162,47 @@ def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]:
     destination_one_way_packet_loss: float = float(
         json_settings["destination_one_way_packet_loss"]
     )
+
+    # Slice ID
     slice_id: str = json_settings["slice_id"]
 
-    sdps = [
-        {
-            "id": "1",
-            "node-id": src_node_id,
-            "sdp-ip-address": [src_mgmt_ip_address],
-            "service-match-criteria": {
-                "match-criterion": [
-                    {
-                        "index": 1,
-                        "match-type": [
-                            {
-                                "type": "ietf-network-slice-service:vlan",
-                                "value": [src_vlan],
-                            },
-                            {
-                                "type": "ietf-network-slice-service:source-ip-prefix",
-                                "value": [src_source_ip_prefix],
-                            },
-                            {
-                                "type": "ietf-network-slice-service:source-tcp-port",
-                                "value": [src_source_tcp_port],
-                            },
-                            {
-                                "type": "ietf-network-slice-service:destination-ip-prefix",
-                                "value": [src_destination_ip_prefix],
-                            },
-                            {
-                                "type": "ietf-network-slice-service:destination-tcp-port",
-                                "value": [src_destination_tcp_port],
-                            },
-                        ],
-                        "target-connection-group-id": "line1",
-                    }
-                ]
-            },
-            "attachment-circuits": {
-                "attachment-circuit": [
-                    {
-                        "id": "0",
-                        "description": "dsc",
-                        "ac-node-id": src_ac_node_id,
-                        "ac-tp-id": src_ac_ep_id,
-                    }
-                ]
-            },
-        },
-        {
-            "id": "2",
-            "node-id": dst_node_id,
-            "sdp-ip-address": [dst_mgmt_ip_address],
-            "service-match-criteria": {
-                "match-criterion": [
-                    {
-                        "index": 1,
-                        "match-type": [
-                            {
-                                "type": "ietf-network-slice-service:vlan",
-                                "value": [dst_vlan],
-                            },
-                            {
-                                "type": "ietf-network-slice-service:source-ip-prefix",
-                                "value": [dst_source_ip_prefix],
-                            },
-                            {
-                                "type": "ietf-network-slice-service:source-tcp-port",
-                                "value": [dst_source_tcp_port],
-                            },
-                            {
-                                "type": "ietf-network-slice-service:destination-ip-prefix",
-                                "value": [dst_destination_ip_prefix],
-                            },
-                            {
-                                "type": "ietf-network-slice-service:destination-tcp-port",
-                                "value": [dst_destination_tcp_port],
-                            },
-                        ],
-                        "target-connection-group-id": "line1",
-                    }
-                ]
-            },
-            "attachment-circuits": {
-                "attachment-circuit": [
-                    {
-                        "id": "0",
-                        "description": "dsc",
-                        "ac-node-id": dst_ac_node_id,
-                        "ac-tp-id": dst_ac_ep_id,
-                    }
-                ]
-            },
-        },
-    ]
+    # build source & destination match criteria
+    src_match_criterion = build_match_criterion(
+        vlan=src_vlan,
+        src_ip=src_source_ip_prefix,
+        src_port=src_source_tcp_port,
+        dst_ip=src_destination_ip_prefix,
+        dst_port=src_destination_tcp_port,
+    )
+    dst_match_criterion = build_match_criterion(
+        vlan=dst_vlan,
+        src_ip=dst_source_ip_prefix,
+        src_port=dst_source_tcp_port,
+        dst_ip=dst_destination_ip_prefix,
+        dst_port=dst_destination_tcp_port,
+    )
+
+    # Build SDPs
+    sdp_src = build_sdp(
+        sdp_id="1",
+        node_id=src_node_id,
+        mgmt_ip=src_mgmt_ip_address,
+        ac_node_id=src_ac_node_id,
+        ac_ep_id=src_ac_ep_id,
+        match_criterion=src_match_criterion,
+    )
+    sdp_dst = build_sdp(
+        sdp_id="2",
+        node_id=dst_node_id,
+        mgmt_ip=dst_mgmt_ip_address,
+        ac_node_id=dst_ac_node_id,
+        ac_ep_id=dst_ac_ep_id,
+        match_criterion=dst_match_criterion,
+    )
 
+    sdps = [sdp_src, sdp_dst]
+
+    # Build connection-groups
     connection_groups = [
         {
             "id": "line1",
@@ -160,23 +214,11 @@ def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]:
                     "p2p-receiver-sdp": "2",
                     "service-slo-sle-policy": {
                         "slo-policy": {
-                            "metric-bound": [
-                                {
-                                    "metric-type": "ietf-network-slice-service:one-way-delay-maximum",
-                                    "metric-unit": "milliseconds",
-                                    "bound": source_one_way_delay,
-                                },
-                                {
-                                    "metric-type": "ietf-network-slice-service:one-way-bandwidth",
-                                    "metric-unit": "Mbps",
-                                    "bound": source_one_way_bandwidth,
-                                },
-                                {
-                                    "metric-type": "ietf-network-slice-service:two-way-packet-loss",
-                                    "metric-unit": "percentage",
-                                    "percentile-value": source_one_way_packet_loss,
-                                },
-                            ]
+                            "metric-bound": build_slo_policy_bound(
+                                one_way_delay=source_one_way_delay,
+                                one_way_bandwidth=source_one_way_bandwidth,
+                                one_way_packet_loss=source_one_way_packet_loss,
+                            )
                         }
                     },
                 },
@@ -186,29 +228,18 @@ def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]:
                     "p2p-receiver-sdp": "1",
                     "service-slo-sle-policy": {
                         "slo-policy": {
-                            "metric-bound": [
-                                {
-                                    "metric-type": "ietf-network-slice-service:one-way-delay-maximum",
-                                    "metric-unit": "milliseconds",
-                                    "bound": destination_one_way_delay,
-                                },
-                                {
-                                    "metric-type": "ietf-network-slice-service:one-way-bandwidth",
-                                    "metric-unit": "Mbps",
-                                    "bound": destination_one_way_bandwidth,
-                                },
-                                {
-                                    "metric-type": "ietf-network-slice-service:two-way-packet-loss",
-                                    "metric-unit": "percentage",
-                                    "percentile-value": destination_one_way_packet_loss,
-                                },
-                            ]
+                            "metric-bound": build_slo_policy_bound(
+                                one_way_delay=destination_one_way_delay,
+                                one_way_bandwidth=destination_one_way_bandwidth,
+                                one_way_packet_loss=destination_one_way_packet_loss,
+                            )
                         }
                     },
                 },
             ],
         }
     ]
+
     slice_service = {
         "id": slice_id,
         "description": "dsc",
@@ -216,6 +247,7 @@ def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]:
         "connection-groups": {"connection-group": connection_groups},
     }
     slice_data_model = {"network-slice-services": {"slice-service": [slice_service]}}
+
     json_config_rules = [
         json_config_rule_set(
             "/service[{:s}]/IETFSlice".format(service_uuid),
@@ -250,23 +282,15 @@ def get_link_ep_device_names(
     ep_device_id_1 = ep_ids[0].device_id
     ep_uuid_1 = ep_ids[0].endpoint_uuid.uuid
     device_obj_1 = context_client.GetDevice(ep_device_id_1)
-    for d_ep in device_obj_1.device_endpoints:
-        if d_ep.endpoint_id.endpoint_uuid.uuid == ep_uuid_1:
-            ep_name_1 = d_ep.name
-            break
-    else:
-        raise Exception("endpoint not found")
+    ep_name_1 = _get_device_endpoint_name(device_obj_1, ep_uuid_1)
     device_obj_name_1 = device_obj_1.name
+
     ep_device_id_2 = ep_ids[1].device_id
     ep_uuid_2 = ep_ids[1].endpoint_uuid.uuid
     device_obj_2 = context_client.GetDevice(ep_device_id_2)
-    for d_ep in device_obj_2.device_endpoints:
-        if d_ep.endpoint_id.endpoint_uuid.uuid == ep_uuid_2:
-            ep_name_2 = d_ep.name
-            break
-    else:
-        raise Exception("endpoint not found")
+    ep_name_2 = _get_device_endpoint_name(device_obj_2, ep_uuid_2)
     device_obj_name_2 = device_obj_2.name
+
     return (
         device_obj_name_1,
         ep_name_1,
diff --git a/src/service/service/service_handlers/l3slice_ietfslice/L3SliceIETFSliceServiceHandler.py b/src/service/service/service_handlers/l3slice_ietfslice/L3SliceIETFSliceServiceHandler.py
index ea1c0f425f62d4f250c4e195ef91eb2a1e78e94d..0df8b56e3495dcf70dcfd78b8e3ea83bef93dc46 100644
--- a/src/service/service/service_handlers/l3slice_ietfslice/L3SliceIETFSliceServiceHandler.py
+++ b/src/service/service/service_handlers/l3slice_ietfslice/L3SliceIETFSliceServiceHandler.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.
@@ -38,6 +38,30 @@ from .ConfigRules import (
     teardown_config_rules,
 )
 
+RUNNING_RESOURCE_KEY = "running_ietf_slice"
+CANDIDATE_RESOURCE_KEY = "candidate_ietf_slice"
+
+SDP_DIFF_RE = re.compile(
+    r"^root\[\'network-slice-services\'\]\[\'slice-service\'\]\[0\]\[\'sdps\'\]\[\'sdp\'\]\[(\d)\]$"
+)
+CONNECTION_GROUP_DIFF_RE = re.compile(
+    r"^root\[\'network-slice-services\'\]\[\'slice-service\'\]\[0\]\[\'connection-groups\'\]\[\'connection-group\'\]\[(\d)\]$"
+)
+MATCH_CRITERION_DIFF_RE = re.compile(
+    r"^root\[\'network-slice-services\'\]\[\'slice-service\'\]\[0\]\[\'sdps\'\]\[\'sdp\'\]\[(\d)\]\[\'service-match-criteria\'\]\[\'match-criterion\'\]\[(\d)\]$"
+)
+
+RE_GET_ENDPOINT_FROM_INTERFACE = re.compile(r"^\/interface\[([^\]]+)\].*")
+
+LOGGER = logging.getLogger(__name__)
+
+METRICS_POOL = MetricsPool(
+    "Service", "Handler", labels={"handler": "l3slice_ietfslice"}
+)
+
+
+RAISE_IF_DIFFERS = True
+
 
 class Ipv4Info(TypedDict):
     src_lan: str
@@ -63,34 +87,68 @@ class ConnectivityConstructInfo:
     packet_loss: float = 0.0
 
 
-RUNNING_RESOURCE_KEY = "running_ietf_slice"
-CANDIDATE_RESOURCE_KEY = "candidate_ietf_slice"
-
-SDP_DIFF_RE = re.compile(
-    r"^root\[\'network-slice-services\'\]\[\'slice-service\'\]\[0\]\[\'sdps\'\]\[\'sdp\'\]\[(\d)\]$"
-)
-CONNECTION_GROUP_DIFF_RE = re.compile(
-    r"^root\[\'network-slice-services\'\]\[\'slice-service\'\]\[0\]\[\'connection-groups\'\]\[\'connection-group\'\]\[(\d)\]$"
-)
-MATCH_CRITERION_DIFF_RE = re.compile(
-    r"^root\[\'network-slice-services\'\]\[\'slice-service\'\]\[0\]\[\'sdps\'\]\[\'sdp\'\]\[(\d)\]\[\'service-match-criteria\'\]\[\'match-criterion\'\]\[(\d)\]$"
-)
-
-RE_GET_ENDPOINT_FROM_INTERFACE = re.compile(r"^\/interface\[([^\]]+)\].*")
-
-LOGGER = logging.getLogger(__name__)
-
-METRICS_POOL = MetricsPool(
-    "Service", "Handler", labels={"handler": "l3slice_ietfslice"}
-)
+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
 
 
-RAISE_IF_DIFFERS = True
+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_match_criterion_ipv4_info(match_criterion: Dict) -> Ipv4Info:
+    """
+    Extracts IPv4 info from the match criterion dictionary.
+    """
+    src_lan = dst_lan = src_port = dst_port = vlan = ""
+    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_lan = val
+        elif m_type == "ietf-network-slice-service:destination-ip-prefix":
+            dst_lan = val
+        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
+        elif m_type == "ietf-network-slice-service:vlan":
+            vlan = val
+    return Ipv4Info(
+        src_lan=src_lan,
+        dst_lan=dst_lan,
+        src_port=src_port,
+        dst_port=dst_port,
+        vlan=vlan,
+    )
 
 
 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": {}},
@@ -100,20 +158,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
@@ -125,7 +187,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"]
@@ -136,6 +198,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
@@ -159,18 +222,13 @@ def get_removed_items(
     return removed_items
 
 
-def extract_source_destination_device_endpoint_info(
-    device_ep_pairs: list, connection_group: Dict, candidate_connection_groups: List
-) -> Tuple[DeviceEpInfo, DeviceEpInfo]:
-    connectivity_construct = connection_group["connectivity-construct"][0]
-    sender_sdp = connectivity_construct["p2p-sender-sdp"]
-    receiver_sdp = connectivity_construct["p2p-receiver-sdp"]
-    if sender_sdp == device_ep_pairs[0][4]:
-        ...
-    elif sender_sdp == device_ep_pairs[1][4]:
-        device_ep_pairs = device_ep_pairs[::-1]
-    else:
-        raise Exception("Sender SDP not found in device_ep_pairs")
+def gather_connectivity_construct_info(
+    candidate_connection_groups: List[Dict],
+) -> Dict[Tuple[str, str], ConnectivityConstructInfo]:
+    """
+    Creates a dict mapping (sender_sdp, receiver_sdp) -> ConnectivityConstructInfo
+    from the given list of candidate connection groups.
+    """
     cc_info: Dict[Tuple[str, str], ConnectivityConstructInfo] = {}
     for cg in candidate_connection_groups:
         for cc in cg["connectivity-construct"]:
@@ -201,12 +259,39 @@ def extract_source_destination_device_endpoint_info(
                     and metric_bound["metric-unit"] == "Mbps"
                 ):
                     cc_info[cc_key].bandwidth = int(metric_bound["bound"])
+    return cc_info
+
+
+def extract_source_destination_device_endpoint_info(
+    device_ep_pairs: list, connection_group: Dict, candidate_connection_groups: List
+) -> Tuple[DeviceEpInfo, DeviceEpInfo]:
+    """
+    Given device_ep_pairs, the relevant connection_group data, and all candidate
+    connection groups, figure out the final DeviceEpInfo for source and destination.
+    This includes computing the combined bandwidth, min delay, etc.
+    """
+    connectivity_construct = connection_group["connectivity-construct"][0]
+    sender_sdp = connectivity_construct["p2p-sender-sdp"]
+    receiver_sdp = connectivity_construct["p2p-receiver-sdp"]
+
+    # If the first pair is not the sender, we invert them
+    if sender_sdp == device_ep_pairs[0][4]:
+        ...
+    elif sender_sdp == device_ep_pairs[1][4]:
+        device_ep_pairs = device_ep_pairs[::-1]
+    else:
+        raise Exception("Sender SDP not found in device_ep_pairs")
+
+    # Gather info from candidate connection groups
+    cc_info = gather_connectivity_construct_info(candidate_connection_groups)
+
     source_delay = int(1e6)
     source_bandwidth = 0
     source_packet_loss = 1.0
     destination_delay = int(1e6)
     destination_bandwidth = 0
     destination_packet_loss = 1.0
+
     if cc_info:
         common_sdps = set.intersection(*[set(key) for key in cc_info.keys()])
         if len(cc_info) > 2 and len(common_sdps) != 1:
@@ -216,9 +301,11 @@ def extract_source_destination_device_endpoint_info(
         if len(common_sdps) == 1:
             common_sdp = common_sdps.pop()
         elif len(common_sdps) == 2:
+            # Fallback if intersection is 2 => pick sender_sdp
             common_sdp = sender_sdp
         else:
-            raise Exception('Invalid number of common sdps')
+            raise Exception("Invalid number of common sdps")
+
     for (sender, receiver), metrics in cc_info.items():
         cc_bandwidth = metrics.bandwidth
         cc_max_delay = metrics.delay
@@ -235,6 +322,7 @@ def extract_source_destination_device_endpoint_info(
                 destination_delay = cc_max_delay
             if cc_packet_loss < destination_packet_loss:
                 destination_packet_loss = cc_packet_loss
+
     source_device_ep_info = DeviceEpInfo(
         ipv4_info=device_ep_pairs[0][5],
         node_name=device_ep_pairs[0][2],
@@ -251,58 +339,45 @@ def extract_source_destination_device_endpoint_info(
         one_way_bandwidth=destination_bandwidth,
         one_way_packet_loss=destination_packet_loss,
     )
-    return source_device_ep_info, destination_device_ep_info
-
-
-def extract_match_criterion_ipv4_info(
-    match_criterion: Dict,
-) -> Ipv4Info:
-    for type_value in match_criterion["match-type"]:
-        if type_value["type"] == "ietf-network-slice-service:source-ip-prefix":
-            src_lan = type_value["value"][0]
-        elif type_value["type"] == "ietf-network-slice-service:destination-ip-prefix":
-            dst_lan = type_value["value"][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]
-        elif type_value["type"] == "ietf-network-slice-service:vlan":
-            vlan = type_value["value"][0]
-    return Ipv4Info(
-        src_lan=src_lan,
-        dst_lan=dst_lan,
-        src_port=src_port,
-        dst_port=dst_port,
-        vlan=vlan,
-    )
 
-
-def get_custom_config_rule(
-    service_config: ServiceConfig, resource_key: str
-) -> Optional[ConfigRule]:
-    for cr in service_config.config_rules:
-        if (
-            cr.WhichOneof("config_rule") == "custom"
-            and cr.custom.resource_key == resource_key
-        ):
-            return cr
+    return source_device_ep_info, destination_device_ep_info
 
 
-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
-    )
-    return DeepDiff(
-        running_resource_value_dict,
-        candidate_resource_value_dict,
-    )
+def _parse_item_added(diff: Dict) -> dict:
+    """
+    Helper to parse 'iterable_item_added' from the running_candidate_diff
+    and return the relevant items for sdp, connection_group, match_criterion, etc.
+    """
+    added_items = {
+        "sdp": {"sdp_idx": None, "value": {}},
+        "connection_group": {"connection_group_idx": None, "value": {}},
+        "match_criterion": {
+            "sdp_idx": None,
+            "match_criterion_idx": None,
+            "value": {},
+        },
+    }
+    for added_key, added_value in diff["iterable_item_added"].items():
+        sdp_match = SDP_DIFF_RE.match(added_key)
+        connection_group_match = CONNECTION_GROUP_DIFF_RE.match(added_key)
+        match_criterion_match = MATCH_CRITERION_DIFF_RE.match(added_key)
+        if sdp_match:
+            added_items["sdp"] = {
+                "sdp_idx": int(sdp_match.groups()[0]),
+                "value": added_value,
+            }
+        elif connection_group_match:
+            added_items["connection_group"] = {
+                "connection_group_idx": int(connection_group_match.groups()[0]),
+                "value": added_value,
+            }
+        elif match_criterion_match:
+            added_items["match_criterion"] = {
+                "sdp_idx": int(match_criterion_match.groups()[0]),
+                "match_criterion_idx": int(match_criterion_match.groups()[1]),
+                "value": added_value,
+            }
+    return added_items
 
 
 class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
@@ -326,12 +401,15 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
         results = []
         try:
             service_config = self.__service.service_config
+
+            # 1. Identify source and destination devices
             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))
             )
             src_device_name = src_device_obj.name
             src_controller = self.__task_executor.get_device_controller(src_device_obj)
+
             dst_device_uuid, dst_endpoint_uuid = get_device_endpoint_uuids(
                 endpoints[-1]
             )
@@ -340,18 +418,16 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
             )
             dst_device_name = dst_device_obj.name
             dst_controller = self.__task_executor.get_device_controller(dst_device_obj)
+
             if (
                 src_controller.device_id.device_uuid.uuid
                 != dst_controller.device_id.device_uuid.uuid
             ):
                 raise Exception("Different Src-Dst devices not supported by now")
-            controller = src_controller
-            context_client = ContextClient()
-            edge_device_names = [src_device_name, dst_device_name]
-            link_list = context_client.ListLinks(Empty())
-            links = link_list.links
-            device_ep_pairs = []
-            sdp_ids = []
+
+            controller = src_controller  # same device controller
+
+            # 2. Determine how the candidate & running resources differ
             running_candidate_diff = get_running_candidate_ietf_slice_data_diff(
                 service_config
             )
@@ -370,35 +446,39 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
             slice_name = running_resource_value_dict["network-slice-services"][
                 "slice-service"
             ][0]["id"]
+
+            # 3. Retrieve the context links for matching endpoints
+            context_client = ContextClient()
+            links = context_client.ListLinks(Empty()).links
+
+            device_ep_pairs = []
+            sdp_ids = []
+            target_connection_group_id = None
+            operation_type = "update"  # default fallback
+
+            # 4. Handle creation vs additions vs removals
             if not running_candidate_diff:  # Slice Creation
-                slice_services = candidate_resource_value_dict[
+                # 4a. New Slice Creation
+                operation_type = "create"
+
+                candidate_slice_service = candidate_resource_value_dict[
                     "network-slice-services"
-                ]["slice-service"]
-                candidate_slice_service = slice_services[0]
+                ]["slice-service"][0]
                 full_connection_groups = candidate_slice_service["connection-groups"][
                     "connection-group"
                 ]
                 sdps = candidate_slice_service["sdps"]["sdp"]
-                operation_type = "create"
                 sdp_ids = [sdp["node-id"] for sdp in sdps]
+
+                # figure out which device is connected to which link
+                edge_device_names = [src_device_name, dst_device_name]
                 for sdp in sdps:
                     node_id = sdp["node-id"]
                     for link in links:
-                        (
-                            device_obj_name_1,
-                            ep_name_1,
-                            device_obj_1,
-                            device_obj_name_2,
-                            ep_name_2,
-                            device_obj_2,
-                        ) = get_link_ep_device_names(link, context_client)
-                        if (
-                            device_obj_name_1 == node_id
-                            and device_obj_name_2 in edge_device_names
-                        ):
-                            del edge_device_names[
-                                edge_device_names.index(device_obj_name_2)
-                            ]
+                        info = get_link_ep_device_names(link, context_client)
+                        dev1, ep1, _, dev2, ep2, _ = info
+                        if dev1 == node_id and dev2 in edge_device_names:
+                            edge_device_names.remove(dev2)
                             match_criteria = sdp["service-match-criteria"][
                                 "match-criterion"
                             ]
@@ -413,9 +493,9 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                             device_ep_pairs.append(
                                 (
                                     node_id,
-                                    ep_name_1,
-                                    device_obj_name_2,
-                                    ep_name_2,
+                                    ep1,
+                                    dev2,
+                                    ep2,
                                     sdp["id"],
                                     ipv4_info,
                                 )
@@ -423,19 +503,19 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                             target_connection_group_id = match_criterion[
                                 "target-connection-group-id"
                             ]
-                            del sdp_ids[sdp_ids.index(node_id)]
+                            sdp_ids.remove(node_id)
                             break
+
+                # find the second link
+                if not edge_device_names:
+                    raise Exception("Edge device names exhausted unexpectedly.")
+
+                # second link logic
                 for link in links:
-                    (
-                        device_obj_name_1,
-                        ep_name_1,
-                        device_obj_1,
-                        device_obj_name_2,
-                        ep_name_2,
-                        device_obj_2,
-                    ) = get_link_ep_device_names(link, context_client)
+                    info = get_link_ep_device_names(link, context_client)
+                    dev1, ep1, device_obj_1, dev2, ep2, device_obj_2 = info
                     if (
-                        device_obj_name_1 == edge_device_names[0]
+                        dev1 == edge_device_names[0]
                         and device_obj_2.controller_id != device_obj_1.controller_id
                     ):
                         for sdp in sdps:
@@ -454,62 +534,34 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                             )
                             device_ep_pairs.append(
                                 (
-                                    device_obj_name_2,
-                                    ep_name_2,
-                                    device_obj_name_1,
-                                    ep_name_1,
+                                    dev2,
+                                    ep2,
+                                    dev1,
+                                    ep1,
                                     sdp["id"],
                                     ipv4_info,
                                 )
                             )
+                            break
+                        else:
+                            raise Exception("No matching sdp found for second link.")
                         break
                 else:
                     raise Exception("sdp between the domains not found")
+
             elif "iterable_item_added" in running_candidate_diff:  # new SDP added
-                slice_services = candidate_resource_value_dict[
+                # 4b. A new SDP was added
+                operation_type = "update"
+
+                candidate_slice_service = candidate_resource_value_dict[
                     "network-slice-services"
-                ]["slice-service"]
-                candidate_slice_service = slice_services[0]
+                ]["slice-service"][0]
+                sdps = candidate_slice_service["sdps"]["sdp"]
                 full_connection_groups = candidate_slice_service["connection-groups"][
                     "connection-group"
                 ]
-                sdps = candidate_slice_service["sdps"]["sdp"]
-                operation_type = "update"
-                added_items = {
-                    "sdp": {"sdp_idx": None, "value": {}},
-                    "connection_group": {"connection_group_idx": None, "value": {}},
-                    "match_criterion": {
-                        "sdp_idx": None,
-                        "match_criterion_idx": None,
-                        "value": {},
-                    },
-                }
-                for added_key, added_value in running_candidate_diff[
-                    "iterable_item_added"
-                ].items():
-                    sdp_match = SDP_DIFF_RE.match(added_key)
-                    connection_group_match = CONNECTION_GROUP_DIFF_RE.match(added_key)
-                    match_criterion_match = MATCH_CRITERION_DIFF_RE.match(added_key)
-                    if sdp_match:
-                        added_items["sdp"] = {
-                            "sdp_idx": int(sdp_match.groups()[0]),
-                            "value": added_value,
-                        }
-                    elif connection_group_match:
-                        added_items["connection_group"] = {
-                            "connection_group_idx": int(
-                                connection_group_match.groups()[0]
-                            ),
-                            "value": added_value,
-                        }
-                    elif match_criterion_match:
-                        added_items["match_criterion"] = {
-                            "sdp_idx": int(match_criterion_match.groups()[0]),
-                            "match_criterion_idx": int(
-                                match_criterion_match.groups()[1]
-                            ),
-                            "value": added_value,
-                        }
+                added_items = _parse_item_added(running_candidate_diff)
+
                 new_sdp = sdps[added_items["sdp"]["sdp_idx"]]
                 src_sdp_name = new_sdp["node-id"]
                 dst_sdp_idx = sdps[added_items["match_criterion"]["sdp_idx"]]["id"]
@@ -517,16 +569,10 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                     "node-id"
                 ]
                 for link in links:
-                    (
-                        device_obj_name_1,
-                        ep_name_1,
-                        device_obj_1,
-                        device_obj_name_2,
-                        ep_name_2,
-                        device_obj_2,
-                    ) = get_link_ep_device_names(link, context_client)
+                    info = get_link_ep_device_names(link, context_client)
+                    dev1, ep1, device_obj_1, dev2, ep2, device_obj_2 = info
                     if (
-                        device_obj_name_1 == src_sdp_name
+                        dev1 == src_sdp_name
                         and device_obj_2.controller_id != device_obj_1.controller_id
                     ):
                         for sdp in sdps:
@@ -545,10 +591,10 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                             )
                             device_ep_pairs.append(
                                 (
-                                    device_obj_name_2,
-                                    ep_name_2,
-                                    device_obj_name_1,
-                                    ep_name_1,
+                                    dev2,
+                                    ep2,
+                                    dev1,
+                                    ep1,
                                     sdp["id"],
                                     ipv4_info,
                                 )
@@ -560,16 +606,10 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                 else:
                     raise Exception("sdp between the domains not found")
                 for link in links:
-                    (
-                        device_obj_name_1,
-                        ep_name_1,
-                        device_obj_1,
-                        device_obj_name_2,
-                        ep_name_2,
-                        device_obj_2,
-                    ) = get_link_ep_device_names(link, context_client)
+                    info = get_link_ep_device_names(link, context_client)
+                    dev1, ep1, device_obj_1, dev2, ep2, device_obj_2 = info
                     if (
-                        device_obj_name_1 == dst_sdp_name
+                        dev1 == dst_sdp_name
                         and device_obj_2.controller_id != device_obj_1.controller_id
                     ):
                         for sdp in sdps:
@@ -598,10 +638,10 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                             )
                             device_ep_pairs.append(
                                 (
-                                    device_obj_name_2,
-                                    ep_name_2,
-                                    device_obj_name_1,
-                                    ep_name_1,
+                                    dev2,
+                                    ep2,
+                                    dev1,
+                                    ep1,
                                     sdp["id"],
                                     ipv4_info,
                                 )
@@ -610,6 +650,9 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                 else:
                     raise Exception("sdp between the domains not found")
             elif "iterable_item_removed" in running_candidate_diff:  # an SDP removed
+                # 4c. An existing SDP was removed
+                operation_type = "update"
+
                 slice_services = running_resource_value_dict["network-slice-services"][
                     "slice-service"
                 ]
@@ -622,7 +665,6 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                     "connection-group"
                 ]
                 sdps = slice_service["sdps"]["sdp"]
-                operation_type = "update"
                 removed_items = get_removed_items(
                     candidate_resource_value_dict, running_resource_value_dict
                 )
@@ -725,10 +767,15 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                         break
                 else:
                     raise Exception("sdp between the domains not found")
+            else:
+                raise Exception(
+                    "transition from candidate to running info not supported"
+                )
+
             candidate_connection_groups = candidate_slice_service["connection-groups"][
                 "connection-group"
             ]
-            LOGGER.debug(f"connection_groups: {candidate_connection_groups}")
+
             if (
                 len(
                     candidate_resource_value_dict["network-slice-services"][
@@ -737,12 +784,19 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                 )
                 == 0
             ):
+                # 5. If connection_groups is now empty => operation = delete
                 operation_type = "delete"
+
+            # 6. Retrieve actual target connection_group from the full connection groups
+            if not target_connection_group_id:
+                raise Exception("No target_connection_group_id found.")
             target_connection_group = next(
                 cg
                 for cg in full_connection_groups
                 if cg["id"] == target_connection_group_id
             )
+
+            # 7. Build source/destination device info
             source_device_ep_info, destination_device_ep_info = (
                 extract_source_destination_device_endpoint_info(
                     device_ep_pairs,
@@ -799,10 +853,13 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler):
                 ],
                 "slice_id": slice_name,
             }
+
+            # 9. Create config rules and configure device
             json_config_rules = setup_config_rules(slice_name, resource_value_dict)
             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)
         except Exception as e:  # pylint: disable=broad-except
             raise e
diff --git a/src/service/service/service_handlers/l3slice_ietfslice/__init__.py b/src/service/service/service_handlers/l3slice_ietfslice/__init__.py
index 53d5157f750bfb085125cbd33faff1cec5924e14..3ccc21c7db78aac26daa1f8c5ff8e1ffd3f35460 100644
--- a/src/service/service/service_handlers/l3slice_ietfslice/__init__.py
+++ b/src/service/service/service_handlers/l3slice_ietfslice/__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.