walkthrough: the tab-name clone check was a guess
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+21
-10
@@ -425,23 +425,34 @@ in.
|
|||||||
|
|
||||||
**The one hole is duplicate-tab**, which you use constantly — and duplicating a tab clones its
|
**The one hole is duplicate-tab**, which you use constantly — and duplicating a tab clones its
|
||||||
sessionStorage, so the copy would open wearing the original's name. Two tabs called "Platform Arch" is
|
sessionStorage, so the copy would open wearing the original's name. Two tabs called "Platform Arch" is
|
||||||
precisely what naming one was meant to prevent. `performance.getEntriesByType('navigation')[0].type`
|
precisely what naming one was meant to prevent.
|
||||||
separates the cases: a refresh reports `reload`, a duplicate reports `navigate`. So a `navigate` that
|
|
||||||
arrives already holding a name did not earn it, and the name is dropped. A brand-new tab is `navigate`
|
|
||||||
too but has nothing stored, so it's untouched.
|
|
||||||
|
|
||||||
That check **fails soft on purpose**: if the timing entry is missing, or some browser labels duplication
|
The first fix for that was a guess, and the guess was wrong. It read
|
||||||
differently, the copy just keeps the name — redundant, not wrong. Nothing else about the tab changes.
|
`performance.getEntriesByType('navigation')[0].type`, on the theory that a refresh reports `reload` and
|
||||||
|
a duplicate reports `navigate`, so a `navigate` arriving already holding a name did not earn it. Only
|
||||||
|
half of that is true: **`reload` means F5 or Ctrl-R and nothing else.** Pressing Enter in the address
|
||||||
|
bar is `navigate`. Following a link back into the app is `navigate`. Re-opening the URL after the server
|
||||||
|
was down — which is how you come back from every `pm2 restart` — is `navigate`. All of them threw the
|
||||||
|
name away, which read as "sessionStorage isn't surviving restarts". sessionStorage was fine; we were
|
||||||
|
deleting it on arrival.
|
||||||
|
|
||||||
|
So it asks now instead of guessing. Each tab stores an id beside its name, and a duplicate is a tab
|
||||||
|
whose id is **still held by a tab that is alive** — which the original can just say, over a
|
||||||
|
`BroadcastChannel`. The new document broadcasts `claim: <id>`; any live tab holding that id answers
|
||||||
|
`taken`; on hearing that, the copy mints a fresh id and gives up the name. A refresh has nobody to
|
||||||
|
answer, because the old document is destroyed before the new one's scripts run. A brand-new tab has no
|
||||||
|
id at all, so it can't be a copy of anything and never asks.
|
||||||
|
|
||||||
|
The answer arrives a beat late, so the header can show the inherited name for a frame before it clears.
|
||||||
|
That's the price of asking a real question instead of reading a tea leaf, and it's the right trade: this
|
||||||
|
still **fails soft toward keeping the name** — no `BroadcastChannel`, or nobody answering, means no
|
||||||
|
clone detected. A copy keeping a name is redundant. Losing a name you typed is a bug.
|
||||||
|
|
||||||
The header input also became a draft committed on blur/Enter rather than a live write. It wrote every
|
The header input also became a draft committed on blur/Enter rather than a live write. It wrote every
|
||||||
keystroke before, which was fine while the title was a plain string; now that an empty field means "use
|
keystroke before, which was fine while the title was a plain string; now that an empty field means "use
|
||||||
the route name", deleting the last character would have snapped the input to "Chat" under the cursor.
|
the route name", deleting the last character would have snapped the input to "Chat" under the cursor.
|
||||||
Escape discards the draft.
|
Escape discards the draft.
|
||||||
|
|
||||||
**Verified in the browser.** The clone heuristic was the one part I could only reason about; you tested
|
|
||||||
it and it behaves as designed — a duplicated tab keeps the _page_ (React Query cache and all) but not
|
|
||||||
the _name_, and the two tabs then diverge.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 17. Stop means stop, not "Claude Code returned an error"
|
## 17. Stop means stop, not "Claude Code returned an error"
|
||||||
|
|||||||
Reference in New Issue
Block a user