"Can this user do this thing given these constraints?" or even "Show me all the things this user can do given these constraints"
Our team is solving for this use case. While we focus a lot on abstractions, APIs, etc. that are appropriate for our use case, under the hood everything is driven by an embeddable logic language that we write in Rust, called Polar: https://docs.osohq.com/reference/polar.html
That is, trying to converge a system from current state to desired state.
If it were written with logic programming and were able to run things in reverse, then it would be able to explain exactly why it is unable to converge the system to the desired state, and what other factors it is waiting on to do so. I think that would greatly enhance observability in a complex system.
I was also in the process of writing a chat bot accepting commands be able to autocompletion that takes authorization into account. So given what the user has typed so far, and what it is authorized to use, it would be able to show the available commands.
In principle, this would have allowed us to do something akin to property based integration testing (we only tested the fully integrated system, no partial integrations of subsystems or unit testing). The same program could have been used to analyze recordings of real world communications to see if they were correct (to the spec) and where they diverged if not, with only minor modification to the way we interacted with it.
That's actually one of the really nice things about Prolog, you can work in both directions with the same program, you can't do that in any of the mainstream programming languages without libraries (minikanren, for instance, allows for an embedding of this in many languages).
For instance, while trivial, you can use append/3 in Prolog to get the result of appending two lists, or to find all prefixes and suffixes of a list, or to find a particular prefix/suffix given both the combined list and the other (suffix or prefix, respectively).
append([1,2], [3,4], AB). -- AB = [1,2,3,4]
append(A, [3,4], [1,2,3,4]). -- A = [1,2]
append([1,2], B, [1,2,3,4]). -- B = [3,4]
append(A, B, [1,2,3,4]). -- A = [], B = [1,2,3,4];
-- A = [1], B = [2,3,4];
-- ...
By writing one program, perhaps supplying synonyms to get something that reads better, you can get all these options depending on which parts you choose to supply as knowns and which you leave as variables.