So, there are two questions here: 1) what is the intended behavior? 2) what does the spec actually say at the moment?
Intended Behavior
The intended behavior is that GET /articles/1 is a 404 if an article with that id does not exist.
Here’s the reasoning/backstory:
A relationship is, conceptually: 1) a collection of resource identifier objects with 2) an associated type (to-one or to-many). In a to-many relationship, the contents are always serialized as an array; in a to-one relationship, they’re serialized as null or a single identifier object.
The related url represents a projection of the relationship, where each resource identifier object is mapped to the resource object it identifies. This result retains the same rules for communicating the relationship type — a to-one relationship gets projected to null or a single resource, and a to-many gets projected to a (possibly empty) array of resource objects.
So, if a resource object includes a relationship with a related url, then that related url represents a set of related resources that does conceptually exist, but might be empty. If it is empty, the server should return data: null in this case, rather than 404, precisely to tell the client that the related collection does at least exist. (As you guys have pointed out, this is a useful distinction.)
Communicating “this exists but is currently empty” is the only reason the spec introduces the data: null response. When something simply doesn’t exist at the time of the request, 404 is appropriate.
Spec text
When the spec talks about a URL that “might correspond to a single resource, but doesn’t currently”, it’s trying to get at this idea of “the thing exists but doesn’t currently have any contents”.
I agree with Michael that the spec doesn’t actually say that, but my strong suspicion is that many implementations have interpreted 404 as the correct response anyway. I know that’s how my implementation has always behaved, I assume it’s how Scott’s behaves, and I imagine it’s how @dgeb’s behaves as well.
Unless a strong majority of implementations use the 200 OK interpretation (which I doubt), I have no problems clarifying the spec text to reflect the 404 behavior. At the end of the day, our backwards compatibility promises are about maintaining interoperability, so, if implementations in practice are already divided on this, clarifying the text doesn’t make things less interoperable.
I’d also point out that, if we were instead to double down on Michael’s reading of the spec, it would lead to some pretty bizarre behavior. In particular, JSON:API gives a server the flexibility to assign urls to resources however it wants, so, in theory, almost any url “might correspond to a single resource”. Therefore, reading the text as Michael suggests would make it impossible for a server to return a 404 at a clearly non-existent resource. For example, every JSON:API server would have to have GET /xcvcxtfien return a 200 Ok with data null. I don’t think that’s plausible/something we want.