I think it's funny how I had this kind of sort of "clear" understanding of Rust ownership from experience, and asking "why" repeatedly puts a few holes in the illusion of my understanding being clear. It's mostly familiarity of concepts from working with C++ and RAII and solving some ownership issues. It's kind of like when people ask you for the definition of a word, and you know what it means, but you also can't quite explain it.
I would say you're correct that ownership is something that only exists on the language level. Going back to the documentation: https://doc.rust-lang.org/book/ch04-01-what-is-ownership.htm...
The first part that gives a hint is this
>Rust uses a third approach: memory is managed through a system of ownership with a set of rules that the compiler checks.
This clearly means ownership is a concept in the Rust language. Defined by a set of rules checked by the compiler.
Later:
>First, let’s take a look at the ownership rules. Keep these rules in mind as we work through the examples that illustrate them:
>
>*Each value in Rust has an owner*.
>There can only be one owner at a time.
>*When the owner goes out of scope*, the value will be dropped.
So the owner can go out of scope and that leads to the value being dropped. At the same time each value has an owner.
So from this we gather. An owner can go out of scope, so an owner would be something that lives within a scope. A variable declaration perhaps? Further on in the text this seems to be confirmed. A variable can be an owner.
>Rust takes a different path: the memory is automatically returned once the variable that owns it goes out of scope.
Ok, so variables can own values. And borrowed variables (references) are owned by the variables they borrow from, this much seems clear. We can recurse all the way down. What about up? Who owns the variables? I'm guessing the program or the scope, which in turn is owned by the program.
So I think variables own values directly, references are owned by the variables they borrow from. All variables are owned by the program and live as long as they're in scope (again something that only exists at program level).