LCS logic errors

There’s a flaw in my LCS logic somewhere but I can’t find where. I have a transform determining what LCS Identities go into, but for some reason it’s dumping 27 active Identities (they are active in our HR system I mean) in the terminated LCS. Can someone help? This transform was initially written by SailPoint Advisory Services but I’ve made some changes here and there.

{
    "id": "e4a012e2-32f7-4659-8162-446a9118f5f8",
    "name": " - LifeCycleState",
    "type": "static",
    "attributes": {
        "disableAD": {
            "type": "upper",
            "attributes": {
                "input": {
                    "type": "firstValid",
                    "attributes": {
                        "values": [
                            {
                                "type": "accountAttribute",
                                "attributes": {
                                    "attributeName": "companyUDF.DISABLE AD",
                                    "sourceName": "UKG Pro (HR)"
                                }
                            },
                            {
                                "type": "static",
                                "attributes": {
                                    "value": "NONE"
                                }
                            }
                        ]
                    }
                }
            }
        },
        "employeeStatus": {
            "type": "accountAttribute",
            "attributes": {
                "attributeName": "employeeStatus",
                "sourceName": "UKG Pro (HR)"
            }
        },
        "hireDate": {
            "type": "dateFormat",
            "attributes": {
                "inputFormat": "M/d/yyyy hh:mm:ss a",
                "outputFormat": "yyyy-MM-dd",
                "input": {
                    "type": "firstValid",
                    "attributes": {
                        "values": [
                            {
                                "type": "accountAttribute",
                                "attributes": {
                                    "attributeName": "hireDate",
                                    "sourceName": "UKG Pro (HR)"
                                }
                            },
                            {
                                "type": "static",
                                "attributes": {
                                    "value": "1/1/1900 12:00:00 AM"
                                }
                            }
                        ]
                    }
                }
            }
        },
        "termReason": {
            "type": "firstValid",
            "attributes": {
                "values": [
                    {
                        "type": "accountAttribute",
                        "attributes": {
                            "attributeName": "employmentDetails.termReason",
                            "sourceName": "UKG Pro (HR)"
                        }
                    },
                    {
                        "type": "static",
                        "attributes": {
                            "value": "NONE"
                        }
                    }
                ]
            }
        },
        "today": {
            "type": "dateMath",
            "attributes": {
                "expression": "now/d",
                "outputFormat": "yyyy-MM-dd"
            }
        },
        "termDatePlus180": {
            "type": "dateMath",
            "attributes": {
                "expression": "+180d/d",
                "outputFormat": "yyyy-MM-dd",
                "input": {
                    "type": "dateFormat",
                    "attributes": {
                        "inputFormat": "M/d/yyyy hh:mm:ss a",
                        "outputFormat": "ISO8601",
                        "input": {
                            "type": "firstValid",
                            "attributes": {
                                "values": [
                                    {
                                        "type": "accountAttribute",
                                        "attributes": {
                                            "attributeName": "terminationDate",
                                            "sourceName": "UKG Pro (HR)"
                                        }
                                    },
                                    {
                                        "type": "static",
                                        "attributes": {
                                            "value": "1/1/2099 12:00:00 AM"
                                        }
                                    }
                                ]
                            }
                        }
                    }
                }
            }
        },
        "value": "#if(($disableAD == 'ACQUISITION' or $disableAD == 'DOGWOOD' or $disableAD == 'SUNSET') and $employeeStatus != 'T')merger#elseif($employeeStatus == 'A' and $hireDate.compareTo($today) > 0)prehire#elseif(($employeeStatus == 'A') or ($employeeStatus == 'T' and ($termReason == '555' or $termReason == 'TRO')))active#elseif($employeeStatus == 'L')leaveOfAbsence#elseif($employeeStatus == 'T' and $today.compareTo($termDatePlus180) >= 0)delete#elseif($employeeStatus == 'T' and ($termReason != '555' or $termReason != 'TRO'))terminated#end"
    },
    "internal": false
}

Hi @pillar224 the if/else statement may not provide full coverage of all scenarios (I haven’t examined the full logic), so it may be returning null as there is no default else statement. In which case, the terminated value could have been set while testing previous iterations and the latest iteration is not updating it.

Actually, just had a look at your Boolean. This (in your last else) may not be giving you what you want:

This will always return true. You need to put the not around the or, not in the equality statements. Think about ‘555’, which is not equal to ‘TRO’ so the second predicate will return true meaning the or predicate will return true.

Not saying it’s causing your problem, but it’s sub-optimal :wink:

Re examining the transform, is it possible these users are in ‘T’ employmentStatus but no termReason provided? Ie termReason is “NONE” thus matching your final else statement.

Hi Jeremy, I appreciate your responses. To answer your last question, your correct, none of the ones that are incorrectly in the terminated LCS have term reasons

Hi @pillar224,

I don’t see any major issue with your transform logic. However, I would recommend setting the ignoreErrors flag to true for all firstValid sub transforms.

Also, in your last condition, it would be better to use and instead of or, like this:

($termReason != ‘555’ and $termReason != 'TRO

And their employeeStatus?

Hi @UjjwalJain Why would you recommend setting ignoreErrors to true for all firstvalid sub transforms? Particularly during testing.

As per documentation and best practices, this should be set to true to ensure the transform evaluates the next available option if an error occurs in the current block.

My point is, why would you not want to investigate errors? The documentation gives a specific example where a function ($identity.manager.attributes.networkDn) could generate an NPE and if you want to ignore that NPE then set ignoreErrors. The OP firstValid uses accountAttribute transform. If that is generating an error, you would want to investigate.

@pillar224 Hi Derek - Can you check the below corrected logic transform code -

{
    "id": "1cb35554-7cbe-46b6-97ad-3a6582432bf9",
    "name": " Determine LifeCycleState",
    "type": "static",
    "attributes": {
        "disableAD": {
            "type": "upper",
            "attributes": {
                "input": {
                    "type": "firstValid",
                    "attributes": {
                        "ignoreErrors": true,
                        "values": [
                            {
                                "type": "accountAttribute",
                                "attributes": {
                                    "attributeName": "companyUDF.DISABLE AD",
                                    "sourceName": "UKG Pro (HR)"
                                }
                            },
                            {
                                "type": "static",
                                "attributes": {
                                    "value": "NONE"
                                }
                            }
                        ]
                    }
                }
            }
        },
        "employeeStatus": {
            "type": "accountAttribute",
            "attributes": {
                "attributeName": "employeeStatus",
                "sourceName": "UKG Pro (HR)"
            }
        },
        "hireDate": {
            "type": "dateFormat",
            "attributes": {
                "inputFormat": "M/d/yyyy hh:mm:ss a",
                "outputFormat": "yyyy-MM-dd",
                "input": {
                    "type": "firstValid",
                    "attributes": {
                        "ignoreErrors": true,
                        "values": [
                            {
                                "type": "accountAttribute",
                                "attributes": {
                                    "attributeName": "hireDate",
                                    "sourceName": "UKG Pro (HR)"
                                }
                            },
                            {
                                "type": "static",
                                "attributes": {
                                    "value": "1/1/1900 12:00:00 AM"
                                }
                            }
                        ]
                    }
                }
            }
        },
        "termReason": {
            "type": "firstValid",
            "attributes": {
                "ignoreErrors": true,
                "values": [
                    {
                        "type": "accountAttribute",
                        "attributes": {
                            "attributeName": "employmentDetails.termReason",
                            "sourceName": "UKG Pro (HR)"
                        }
                    },
                    {
                        "type": "static",
                        "attributes": {
                            "value": "NONE"
                        }
                    }
                ]
            }
        },
        "today": {
            "type": "dateMath",
            "attributes": {
                "expression": "now/d",
                "outputFormat": "yyyy-MM-dd"
            }
        },
        "termDatePlus180": {
            "type": "dateMath",
            "attributes": {
                "expression": "+180d/d",
                "outputFormat": "yyyy-MM-dd",
                "input": {
                    "type": "dateFormat",
                    "attributes": {
                        "inputFormat": "M/d/yyyy hh:mm:ss a",
                        "outputFormat": "ISO8601",
                        "input": {
                            "type": "firstValid",
                            "attributes": {
                                "ignoreErrors": true,
                                "values": [
                                    {
                                        "type": "accountAttribute",
                                        "attributes": {
                                            "attributeName": "terminationDate",
                                            "sourceName": "UKG Pro (HR)"
                                        }
                                    },
                                    {
                                        "type": "static",
                                        "attributes": {
                                            "value": "1/1/2099 12:00:00 AM"
                                        }
                                    }
                                ]
                            }
                        }
                    }
                }
            }
        },
        "value": "#if(($disableAD == 'ACQUISITION' or $disableAD == 'DOGWOOD' or $disableAD == 'SUNSET') and $employeeStatus != 'T')merger#elseif($employeeStatus == 'A' and $hireDate.compareTo($today) > 0)prehire#elseif(($employeeStatus == 'A') or ($employeeStatus == 'T' and ($termReason == '555' or $termReason == 'TRO')))active#elseif($employeeStatus == 'L')leaveOfAbsence#elseif($employeeStatus == 'T' and $today.compareTo($termDatePlus180) >= 0)delete#elseif($employeeStatus == 'T' and ($termReason != '555' and $termReason != 'TRO'))terminated#else active#end"
    },
    "internal": false
}

Regards,

Kannan

@kannan_sb85 @UjjwalJain - The transform is not generating an error - why are you so quick to jump on ignoreErrors?

Hi @j_place,

I didn’t say that ignoreError is the issue, I only suggested using it. Please reread my message carefully.

That condition remains as it is.

Hi @j_place Jeremy - that is a completely valid point, and worth clarifying.
You are correct. The transform is not throwing errors it is producing wrong logical output due to the or vs and boolean bug. So Recommending ignoreErrors: true in that context was a reflex toward a best practice checklist rather than a diagnosis of the actual problem. To be precise about what ignoreErrors actually does: it tells the firstValid transform to suppress exceptions thrown by a sub-transform (e.g. a source lookup that fails mid-execution) and move on to the next value in the list. That is entirely separate from the issue here, where the sub-transforms are resolving fine they are just feeding correct values into broken conditional logic.

Regards,

Kannan

You actually described it as “best practice”. That is what we disagree on.

($employeeStatus == ‘T’ and ($termReason == ‘555’ or $termReason == ‘TRO’)))active

For active users, do you have employeeStatus=='T", could you please check it and confirm?

Hi Jeremy, thanks again for your response. The employeeStatuses of those 27 are A

Hi Satish,

Active users have an employeeStatus of ‘A.’ The vast majority of employees with ‘A’ employeeStatus are correctly being put in the Active LCS, it’s just those 27.

Hi Derek. Do you have Visual Stdio Code with ISC plugin? If not, I highly recommend to to test Identity attribute transforms such as LCS.