Semantic Equality, SetAttribute, and configuration changes

I’m having some trouble understanding the exact purpose of implementing semantic equality for a custom type.

It seems like the only thing it is used for is comparing the Read() value to the state value for a resource, so that Terraform knows whether to update the state or leave it as-is. For example, if I’m using timetypes.GoDuration as a custom attribute type, configure a value of "1m", and then Read() returns a value of "60s", Terraform will use semantic equality to determine that the state does not need to be updated for that attribute, and its value will remain "1m" in the stored state.

However, it seems like it is not used when comparing the configured value to the state value. For example, configuring a value of "1m", then later changing it to "60s", will still trigger an Update().

It also does not seem to be used when comparing items in a SetAttribute. For example, configuring a SetAttribute having an ElementType of timetypes.GoDuration with a value of ["1m", "60s"] will cause problems, since the underlying API will often silently deduplicate/normalize the value during Create() and Update(), causing Read() to only return ["1m0s"], which Terraform will incorrectly interpret as configuration drift.

But I also can’t create a custom type which behaves the way I would expect it to in these latter scenarios; if I normalize the value in ValueFromString(), then Terraform raises an error that the planned value does not match the configured value; if I implement Equal() the same way as StringSemanticEquals(), then Terraform incorrectly thinks the value has drifted when it hasn’t.

Is this by design, or unintentional? Is it possible to correctly handle all of these cases the way I would expect them to behave?

I’ve been kicking around a SetWithSemanticEquals attribute because the regular set attribute only calls Equal() when comparing elements of the set.

I don’t know if it’s going to work out the way either of us hope, but maybe take a look?