Welcome, and thanks for bringing the scar tissue with you. The rules where you say the security lives are the right ones, and the bearer-file lesson is the one most teams ship before they learn it. On your question 4, the capability URL rules are pitched close to right, but the section would get sturdier by naming what “authorized independently” actually consists of, because it is two checks, and they close different holes.
A pass is presentation. Every artifact in this design (the .pkpass, the save link, the capability URL) is a bearer artifact. Two facts, together, authorize an action, and neither lives in the artifact. First, the actor proves control of the owning account: a signature over a server challenge that names the token and the action, not possession of a file. Second, the server takes a fresh on-chain read of that account’s standing (ownerOf for 721) at the time of the request, not at pass issuance and not at URL minting.
Each closes a hole the other cannot reach. The fresh read closes the transfer window: a sold token stops acting immediately, however many valid-looking passes are still installed. The control proof closes forwarding: your shared-pass incident stays closed even when the URL leaks and the owner has not changed, which is the case rotation cannot reach. Naming the token and the action in the challenge closes replay, so a proof taken for a cheap action cannot be presented for an expensive one.
There is also a tension between the discovery seam and the unguessability rule that is worth calling out in the spec. passURI is a public view function, and per your first question the manifest is meant to be fetched by any marketplace in one request, so the acquisition URL inside it is one public chain read away from anyone who can enumerate token ids. Unguessability does not survive publication. That is not an argument for dropping the rule, it is the reason the rule cannot be the boundary on its own. Where the pass UX genuinely cannot carry a signature the URL is standing in as the possession proof, your rotation rule and your escalation to MUST when action links exist are both right, and it would help implementers to say which of the two jobs the URL is doing in each configuration, so they know when it is the boundary and when it is hygiene.
One note on your onboarding story, since this could read as putting the seed phrase back in front of the user. It does not have to. An account created from an email address can produce the control proof invisibly, either from an embedded signer or as a contract account whose signature is checked under ERC-1271.
There is fresh precedent one thread over: ERC-8291, SIWE-gated NFT media, at ERC-8291: SIWE-Gated NFT Media URI. It is still an open PR against ethereum/ERCs, which is why your prior-art search would not have surfaced it. It worked through the same trust shape for web-served private content and landed on the same pair: a SIWE proof of account control, bound to the exact resource, plus entitlement authorization evaluated at the time of the request, with servers told to re-check ownership, balance, approval, delegation, or policy state before every protected response. Passes are a different delivery surface with the same shape, and aligning the wording would let the two specs reinforce each other.
On question 3, starting 721-only is the right call, and 8291’s 1155 handling is a usable model for when you extend. The binding names an account alongside the token id, and the holder test is balanceOf(account, id) against a minimum that defaults to 1, rather than the exclusive ownerOf equality that 721 gets. That keeps multi-holder semantics out of the pass file entirely and in the authorization check where they belong.
The discovery seam itself, passURI plus one fetched manifest, looks right to me, and your instinct to keep the platform plumbing out of scope is what makes it standardizable.
Douglas