What I expected to happen was...:
The syntax is spectate [<player>] [<target>]. I can use spectate @p to stop @p from spectating.
What actually happened was...:
The syntax is spectate [<target>] [<player>]. I can never omit the [<target>] when specifying the [<target>], so I have to use execute as @p run spectate to stop @p from spectating.
Oh, I suddenly understand the current syntax. Both syntaxes make sense, so please just close this issue. Sorry for this, my bad.