In terms of the practical purpose of this thread as a discussion of if EA should be changed.Both forms of HasTag behave as if they are evaluating based on a single call to get the value. As a result:
HasTag(tagname) gives a result that doesn't match the function name when an empty tag is present
HasTag(tagname, tagvalue) gives a result that doesn't match the function name when no tag is present and checking for an empty value
Unfortunately, changing the behavior of either of these cases would almost certainly break existing shape scripts out there in user land. I'm not willing to do that. The documentation will have to be updated to clarify the behavior and there will have to a be a separate solution to your requirement of distinguishing between an empty value and a missing tag.
Additionally, don't expect to see any change to purge tagged values that are empty. There are too many users that depend on the way it currently works. Not just in the UI, but in documentation, API and export functions.
For the conceptual topic that is diverging further and further from being useful...Whoops! As per Helsinki, I should have defined my terms:
«Empty», «Missing», «Not present» There should be a value, but none was provided
«Unknown» There is a value but we don't know what it is
«None», «No one», «Nothing» There is NO Value
«Not applicable» NO value can be applied
are just some of the standard extrinsic definitions I use.
Useful categories in theory. Like you, I could add additional categories. Where I disagree with you is the inclusion of «Empty» into no value was provided. I would define a string as a sequence of zero or more characters. Similar to sets, I consider empty to be a useful value in its own right. Empty may not be permitted in your model, but the appropriate place to specify that is in a constraint, not the definition of what a (string) value is. As an example, I define a function that removes all instances of a single character from a string. Logically it has to result in a string. If the string only contained the specified character there's certainly a value there. As far as I'm concerned it's still a string.
How does that impact EA?For string tagged values, the only category that can be stored against a tag in EA is the empty string. As I said, in my opinion this is distinct from a null value and still useful. The only way to represent a none or missing value is to delete the tag. In addition to shape scripts, reporting, code generation and csv exports that request the value of a tag by name will be unable to distinguish between these two states. For that reason I would no recommend placing too much significance on the that difference.
For other tagged values (eg. Boolean, enumeration, Dates) the situation is slightly different because unless otherwise specified the default will still be represented by an empty string. For those types there is a missing or none state, but often the UI doesn't allow you to go back to it after it gets a value.