chore(tabs): remove the home-tab constructor, keep the sentinel - #482
Closed
PathGao wants to merge 1 commit into
Closed
chore(tabs): remove the home-tab constructor, keep the sentinel#482PathGao wants to merge 1 commit into
PathGao wants to merge 1 commit into
Conversation
`TabManager.addHomeTab` built a tab whose `path` is the `HOME` sentinel. Its only caller was the document-level Ctrl+T branch in MarkdownViewer.svelte, and #480 pointed that chord at `handleNewFile`, which leaves the method reachable from tests alone. It is not just uncalled, it is the odd one out: everything else in the tab pipeline already treats a home tab as something to get rid of. `serializeState` refuses to write the sentinel and `restoreState` refuses to read it (both filter on `hasRealFilePath`, #401), windowSession drops restored tabs without a real file path, and `mergeSelfInto` closes a home tab rather than moving it. A constructor for a state the rest of the system is built to reject is a way back in, not a feature. What stays is the recognition. `isHomePath` and the sentinel it reads are what turn away the `HOME` entries in session snapshots written before #401, which are on users' disks now; `hasRealFilePath` is spelled in terms of it, so removing it would readmit the phantom tab that issue was about. The render gate from #429 and the tab-strip guards keep reading it for the same reason. homeTab.ts says so where the sentinel is defined. Also drops Editor.svelte's `onhome` prop and the `onhome={...}` the viewer passed it. The prop was declared and typed in e2fae4c and never read: every sibling prop appears three times in that file (destructured, typed, and called from an `editor.addAction`), `onhome` appeared twice. The editor's command table has no Home action, so the viewer was wiring up a callback that nothing could fire. The home screen is unaffected — the titlebar button and the `showHome` toggle are its live routes. Tests: the four files that called `addHomeTab` were testing recognition, not construction, so they build the state themselves and stay. Verified the fence still holds by dropping `isHomePath` from the gate: all four home-tab tests in homeTabRender.test.ts go red. tabPathIdentity's singleton test is deleted — its subject was the method's own dedupe, and there is no second call left to make. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PathGao
changed the base branch from
master
to
feat/format-shortcuts-and-ctrl-t
August 6, 2026 02:24
PathGao
added a commit
that referenced
this pull request
Aug 6, 2026
Follow-up to #482, which removed `TabManager.addHomeTab`. That method's `title: t('tabs.home', settings.language)` was the key's only consumer in `src/`, and the tab it titled no longer exists — nothing is left to name. 26 locales, one leaf each, all of them the second entry of a `tabs` block that keeps `untitled`. `menu.home` and the whole `home.*` section are untouched: the home SCREEN is very much alive, reached by the titlebar button and the `showHome` toggle. Only the tab's title is gone. homeTabRender.test.ts read the key to prove the render gate ignores the title in every language. It now reads `menu.home`, which every locale also defines. The claim under test is that the title cannot affect which branch runs, not which key the title came from. Nothing type-checks a `t()` key — the `Translation` interface is an index signature — so both directions were verified against i18nCoverage.test.ts rather than assumed: * leave the key in one locale after removing it from English, and `no language defines a key English does not have` fails with `tabs.home [1] ja`. A partial sweep across 26 locales cannot pass. * point any src file at `t('tabs.home', …)` again, and both `every key the source asks for exists in English` and `t() never echoes a key back for a reachable string` fail. A missed call site cannot pass either. npm audit / npm run check / npm test / cargo test all clean. Co-authored-by: PathGao <gaoyanbo@gaoyanbodeMacBook-Air.local> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Prerequisite
Merge #480 first. #480 is what makes
addHomeTabdead — it points thedocument-level Ctrl+T at
handleNewFile, and that branch was the method's onlycaller. So this PR is branched on
feat/format-shortcuts-and-ctrl-tand targetsit, which keeps the diff above to this change alone (1 commit, 10 files). GitHub
retargets the base to
masteron its own once #480 lands; no rebase neededunless #480 itself changes.
What this is
TabManager.addHomeTabbuilds a tab whosepathis theHOMEsentinel ratherthan a file. After #480 nothing in the app calls it — only tests do.
It is not merely uncalled. Every other part of the tab pipeline already treats a
home tab as something to get rid of:
serializeStatehasRealFilePath— never writes it (#401)restoreStatewindowSession.svelte.tsmergeSelfIntoSo the method was the one remaining way to produce a state the rest of the system
is built to reject. That is the argument for removing it rather than leaving it
as a harmless unused method.
Also removes
Editor.svelte'sonhomeprop and theonhome={...}the viewerpassed to it. Unrelated to the above, noticed in the same file.
Mechanism
addHomeTab. Before #480,Ctrl+Thad two meanings depending on where thecaret was: Monaco's
file-newaction inside the editor, this branch outside it.#480 settled both on new-file, and the branch that called
addHomeTabwent withit. Nothing else ever called it.
onhome. Declared and typed in e2fae4c and never read. Every sibling prop inEditor.svelteappears three times — destructured, typed, and called from aneditor.addAction({ run: () => onX?.() }).onhomeappears twice:The props block was written as a batch; the Home entry in the command table never
followed. So
MarkdownViewerwas wiringonhome={() => (showHome = true)}to acallback nothing could fire. The home screen itself is untouched — the titlebar
button and the
showHometoggle are its live routes, and the editor has no Homecommand to lose.
Scope
The
HOMEsentinel andisHomePathstay, deliberately. Only the constructoris dead; the recognition is not. Snapshots written before #401 have
HOMEinthem and are sitting on users' disks right now. What turns those away is
hasRealFilePath, and that predicate is spelled in terms ofisHomePath— therecognition IS the rejection. Delete it and #401's phantom tab comes straight
back. The render gate from #429 and the tab-strip guards keep reading it for the
same reason: they are what a stray home tab would run into.
homeTab.tsnow saysthis where the sentinel is defined, so the next person to find an "unused"
sentinel finds the reason too.
Left alone on purpose:
tabs.hometranslation key, in 26 locale files.addHomeTabwas itsonly consumer in
src/. Removing it is a large diff across every locale for nobehavioural gain,
homeTabRender.test.tsstill uses it to prove the gate doesnot depend on the title, and it is what a reinstated home tab would need. Happy
to do it in a follow-up if you'd rather it went.
formatShortcutKeymap.test.ts'sno path anywhere still opens a Home tabtest, which asserts no chord reaches
addHomeTab. It is feat(editor): shortcuts for the six unbound formatting commands, and one meaning for Ctrl+T #480's fence and nowpasses trivially. Rewriting another PR's test from this one seemed worse than
leaving it.
chore: bump pkgcommits.Tests
Four suites called
addHomeTabto construct a home tab so they could testrecognition. The recognition is what stays, so they stay too and build the
state themselves:
Setting
pathis the whole of it —isHomePathis a predicate overpathandnothing else. This is arguably the more honest fixture: it no longer inherits a
title from a constructor that the gate is explicitly required to ignore.
homeTabRender.test.ts,homeSentinelSnapshot.test.ts— localopenHomeTab.renderedHtmlField.test.ts—addHomeTabdropped from the construction-siteenumeration, expected tab count 5 → 4.
lossyDecodeSaveGuard.test.ts— this one I didn't anticipate. It countshasReplacementChars: falseoccurrences as a census of construction sites andexpected 4; removing one made it 3. It went red on the first run and is the
reason the census now names the three sites it is counting.
untitledTitle.test.ts—sliceBetween(tabs, 'addNewTab()', 'addHomeTab()')re-anchored to
'insertTransferredTab(', the method that now follows.tabPathIdentity.test.ts— deletedthe home tab is a singleton on its own terms. Its subject wasaddHomeTab's own dedupe (a second call re-activatedrather than duplicated); with one call site left there is no second call to
make. The half that outlives it — that the sentinel is not a file path and so
is not subject to the claim rule — is
hasRealFilePath's job and is alreadycovered by the untitled-tab case beside it. A comment records what left.
Does the fence still hold? Per the template: I dropped
isHomePathfrom therender gate (
{#if tabManager.activeTab && !showHome}) and re-ranhomeTabRender.test.ts— 4 of 8 red, every one of the home-tab cases:The three neighbour cases stayed green, so the tests still distinguish the branch
rather than always choosing HomePage. Gate restored, suite green.
I ran the same kind of check on the
onhomeremoval, since a dead prop isexactly the sort of thing no test covers: re-adding
onhome={...}to the viewerwith the prop gone makes
npm run checkfail withso the two sides are held together by the type checker, not by my having noticed.
Verification
All four CI commands, on macOS (darwin 25.5.0), on top of #480:
Not verified: nothing here was exercised in a running app — this is a
removal, and the argument that it is safe rests on the caller census
(
grep addHomeTab src/is empty,onhomeappears zero times outside its owndeclaration) plus the type checker, not on clicking around. Windows and Linux
untried; nothing in the diff is platform-conditional.
cargo testis includedbecause CI runs it, but no Rust changed.