This would be easy to tell which attribute caused the notification to fire off because we can set the state of the notification triggered by each condition to be different. Then by verify the state of the notification, you can know which attribute caused the trigger.
For example the following codes get all the notification instances for the last 2 hours for a particular notification, and print out the state of the notification
OSIsoft.AF.Time.AFTime start = new OSIsoft.AF.Time.AFTime(System.DateTime.Now.AddHours(-2));
OSIsoft.AF.Time.AFTime end = new OSIsoft.AF.Time.AFTime(System.DateTime.Now);
afsrv.Connect(); //connect to AF server
OSIsoft.AF.AFDatabase afdb = afsrv.Databases.DefaultDatabase;
OSIsoft.AF.Notification.AFNotification notifigen = afdb.Notifications["CDT158 Value"];
foreach (OSIsoft.AN.Notification.ANInstance notifiIns in OSIsoft.AN.Notification.ANNotification.GetInstances(notifigen, start, end, OSIsoft.AF.Asset.AFSearchMode.Inclusive, OSIsoft.AN.Notification.ANGetInstanceMode.All))
MessageBox.Show("Notification State = " + notifiIns.State.Name);
If you need to identify cases where both attributes are triggering at the same time, then a 3rd "AND" condition can be added and above the 2 "Comparison" conditions.
You could do a bitstring. It is not directly supported, but if you want to skip retesting you could create an status that is the result of the bitstring and then you would have 0 if everything is false... or a value that has the specific power_of_two bits activated for the culprit tags.
I remember this was really used when doing configuration files and other stuff in asm. Old days. But the principle could still be applied. Rest assured that if a condition is fired the culprit will be (most likely) the left most tag that evaluates to true, as all other man not be evaluated after that. But a condition could be true due to more than one tag at a given time.