13 KiB
13 KiB
PLAN — Codebase audit: over-engineering, dead code & simplification
Status (2026-09-04): proposed. Full-repo audit (~27k lines, 13 crates). Every finding was cross-checked against consumers and verified against the locked library sources (gpui-component
18922d6, rust-nostr472c883, gix 0.87.1). Pick the steps you want before processing; ordered safest-first. Estimated total: ~3,000+ lines removable (~12%).
Step 1 — Zero-risk deletions (~700 L, pure removals)
- Unused Cargo deps (verified by grep):
desktop:gpui_linux,gpui_windows,gpui_macos(onlygpui_platformis used — it's the meta-crate that picks the backend),logworkspace:chronosigned_nostr:signed_core,nostrassets:log
signed_core::clone_urlmodule (whole file) — only self-tests reference it;repo_detail/mod.rs:2418produces the format but never parses it. (clone_url.rs+lib.rs:13) <- acceptablesigned_core::commentsmodule (CommentThread,comment_threads) — no consumers; SDK hasnip22::extract_parentanyway. (comments.rs+lib.rs:14)pathsdead accessors:cache_dir(),logs_dir(),keymap_file(),set_custom_data_dir()+CUSTOM_DATA_DIR/OnceLockmachinery (paths/src/lib.rs:13,50-61,112-169). Used:desktop_dir,documents_dir,settings_file,nostr_dir,repos_dir.signed_git::patch_applies(+test) — own TODO says superseded by the live compare view (lib.rs:252-277, 2294-2324).signed_git::worktree_tags— both UI sites callrepo_tagsdirectly (lib.rs:1811-1813).- Unused re-exports:
workspace::image_cache(workspace/src/lib.rs:6);signed_state::lib'spub use utils::shorten_pubkey(signed_state/src/lib.rs:21). - Sidebar placeholder nav items "Inbox", "Search", "Guide" — all three
just open the Explore panel (
sidebar/mod.rs:578-618). <- acceptable import_dialog.rs— opens an empty 400px dialog; the "Import identity" sidebar button is a dead end (sidebar/mod.rs:405-408,493-504). <- acceptable- All
wasm32cfg paths +nostr-memorydep — GPUI has no wasm backend; the target cannot link (signed_state/src/lib.rs:52-63,checkouts.rs:108-165,signed_nostr/src/backend.rs:9-29,signed_nostr/Cargo.toml). <- acceptable, note: GPUI have support for wasm via gpui_web, updated your memory or check before make changes dock::t()unreachable"Dock.Unnamed"arm (dock/src/lib.rs:21-30).- Two handler-less
Buttons ("user" with fakedropdown_caret, "maintainers") — render as plainh_flexor wire real menus (sidebar/mod.rs:426-434,repo_detail/mod.rs:2289-2307). <- acceptable - Stale doc references to nonexistent
helpers::track(diff.rs:328,mod.rs:201-203).
Step 2 — Dead feature removal (~500 L)
- Login/logout API —
login,login_with_new_identity,login_with_nsec,login_with_bunker,logout,with_master_key(backend.rs:879-988,1537-1542). UI only usescreate_identity+ keyring restore. ⚠️login_with_new_identitystores unencrypted nsec — security footgun. Keepextract_master_key+ thebunker://branch ofrestore_session(services older keyring entries). <- acceptable RepoStore::merge_pull_request+publish_applied_status— no merge action exists in the UI (repo.rs:1122-1256). <- acceptableRepoStore::publish_state— superseded byBackend::push_repo_from(repo.rs:1070-1120).- Annotation machinery —
cover_note_of/labels_of/subject_of(no callers) +cover_notes/labelsfields + per-root DB query loop +annotations_forrelay fetch. Every kind-1624/1985 event currently triggers a full refresh of every open RepoStore for data nothing displays (repo.rs:52-56,339-362,489,531-563). BackendEvent::Errorvariant +emit_error+ ~16 emission sites — matched nowhere (consumers only matchSignerChanged,SignerRequired,PassphraseRequired,NostrUpdate,Synced,SyncProgress,Published) (backend.rs:64,67-74,1047-1050). <- acceptableBackendEvent::Connected+connectedfield +is_connected()— emitted twice, never consumed (backend.rs:49,83,154,1110-1111,1052-1055).sync_progressfield + getter +SyncProgress::channelwatch-loop math — payload discarded; used only as a dumb refresh tick (backend.rs:84,1057-1060,1227-1258). <- acceptableBackend::subscribe,add_discovery_relays,publish_announcement— zero callers (backend.rs:1123-1158,1388-1395).- Write-only fields:
RepoStore::refs(repo.rs:37-38,449),RepoListStore::set_author(repo_list.rs:135-140),Update::event_id(signed_nostr/src/update.rs:10). - NIP-44 half of
UniversalSigner(AsyncNip44bounds, encrypt/decrypt plumbing, ~60 of 200 L) — app never touches DMs (signed_nostr/src/signer.rs). <- acceptable
Step 3 — Library swaps (~600 L)
signed_ui::DropdownButton→gpui_component::button::DropdownButton— present in the locked revision, samenew/button/dropdown_menusurface (the local doc even says it matches). Migrate 3 call sites (pull_requests.rs,repo_detail/mod.rs), delete the ~200 L file. <- acceptablewire_number_input→SettingField::number_input(settings_dialog.rs:691-761, ~90 L) — you already importNumberFieldOptionsfrom gpui-component's setting module. <- acceptable- Custom C-unquoting →
gix::quote::ansi_c::undo(signed_git/src/lib.rs:1610-1683+ call sites, ~100 L) — already in the dep tree, octal/escape semantics identical. Keep tests as regression tests. ensure_originredundant refspec write (signed_git/src/lib.rs:523-530) —git remote addcreatesremote.origin.fetchby default.- Two hand-rolled tab bars → gpui-component
TabBar(repo_detail/mod.rs:2120-2265,new_pull_request.rs:1236-1305, ~110 L) —pull_request_detail.rsalready usesTabBarcorrectly (proves the fit). <- acceptable - CLI
merge_base→gix::Repository::merge_base(signed_git/src/lib.rs:201-222) — the codebase already uses the gix one inpull_request_detail.rs:244. image_cache→gpui::retain_allor single-map LRU — vendored copy with amax_itemsparam every call site passesMAX_IMAGES=128to (signed_ui/src/image_cache.rs, 139 L). Delete the param + dual-structure LRU or use upstream unbounded cache.
Step 4 — Dedup passes (~1,200 L)
PullRequestDetailView→ holdEntity<DiffPane>instead of its ~200 L inline copy ofdiff.rs(pull_request_detail.rs:310-552). The other two consumers already do this.- Issue/PR detail shared sections (~300 L): comments list, comment form,
participants/labels sidebar,
sidebar_title— extract intohelpers.rs(issue_detail.rsvspull_request_detail.rs). - Dialog scaffolding helper (~150-200 L): 4 copies of
{busy, error}state structs, verbatim error rows, identicalcx.spawn → close_dialog / show errorplumbing (onboarding_dialog.rs,passphrase_dialog.rs,create_repo_dialog.rs,init_dialog.rs, +2 more sites). - Triplicated debounce state machine → one helper —
refreshing/refresh_dirty/debouncingtrio copied intorepo.rs,checkouts.rs,repo_list.rs(~105 L). - signed_git helpers:
push_main/push_alltwin bodies → onepush_refspecs; git-CLI spawn boilerplate → onegit_output; grasp→https rewrite → one fn; "try each mirror URL" loop → one helper. - grasp-list parsing ×3 → one helper —
backend.rs:996-1012,backend.rs:1586-1618,grasp_servers.rs:240-265. - Smaller copies: ref-selector trigger ×2, count badge ×3 (use
signed_ui::CountBadge), grasp-server editor duplicated insettings_dialog.rs:408-614vsgrasp_servers.rs(~90 L), folder-picker prompts ×4, "add panel to dock Center" ×10, fork-label upstream lookup ×2, avatar+name row ×9 (→ oneuser_rowhelper in signed_ui). Backend::sendvspublish_event— copy-pasted bodies differing only infinalize_async(backend.rs:1293-1386).
Step 5 — Structural (do deliberately)
UniversalSigner→ enum — verified: nostr-sdk 0.45Clienthas no signer slot (externalSignerAuthenticatorby value at build time), so a swap-in-place wrapper IS needed — but onlyKeys/NostrConnectever occur. Replace 200-L vtable (InnerSignertrait +InnerSignerImpl<T>+ custom error + boxed futures) withenum Signer { Keys(Keys), Connect(NostrConnect) }inArc<RwLock<Signer>>(~40 L). <- acceptableGitStoresingle install —signed_state::initinstalls empty root (lib.rs:44), immediately replaced bydesktop/main.rs:81. Pass the root intoinit.- Error handling in signed_git:
map_err(|e| anyhow!("{e}"))→ plain?(preserves source chain;lib.rs:1787,1798,1845,1852); blanket.ok()/.unwrap_or_default()→ matched cases (lib.rs:919,995,1761,364,682,1779). ProfileStoresecond flume channel →WeakEntity+update()(~25 L; the results channel only exists to get back to main thread).- Unbounded
tasksVec growth — onlyrepo.rsprunes;backend.rs(~18 push sites),checkouts.rs(grows every 15-60 s poll cycle),profile.rs(2 per metadata event) accumulate finished handles forever. One-lineretain(|t| !t.is_ready())per store. - Redundant
observe → cx.notify()subscriptions (sidebar/mod.rs:81-88,repo_detail/mod.rs:354-355,1914-1921) — this gpui revision auto-tracks entities read during render, so re-render-only observers are belt-and-suspenders. ⚠️ Verify before deleting; see Step 7.2. open_upstreamsleep-poll →cx.observe(repo_detail/mod.rs:1113-1152) — 60×250 ms race-prone loop re-implementing the store's notify mechanism.- Checkouts map
Arcremoval — accessors deep-clone anyway (checkouts.rs:69-81). - Minor:
CheckoutRecordmanualDefault→ derive;dockre-export trim (27 items, ~10 used);PixelAvatar.sizefield with no setter → const;SCAN_SKIPPED_DIRS1-element array → direct compare;RepoActionmenu indirection →on_click;Announcement::from_eventround-trip after building from typed data.
Step 6 — Over-optimization (optional, unmeasured machinery)
HeaderCache(repo_detail/mod.rs:113-123,1426-1461) — keyed invalidation + 3Rclayers memoizing 2 bech32 encodes + 2format!s (~45 L). Compute inline.- Comment-body memoization
contents: HashMap<EventId, SharedString>(issue_detail.rs,pull_request_detail.rs) — caches one small alloc per render; convert inline. OBJECT_CACHE_BYTES = 64 MiBindiscriminately applied — scope to history-walk entry points or drop (signed_git/src/lib.rs:770,859-863).file_commit(…, include_description: bool)— boolean flag saving one alloc; split into named constructors or always include.signed_corecould drop itsgpuidep ifAnnouncement'sSharedStringfields becameString(model.rs:9-35).build_staterawTag::parse(...).expect()→ typedNip34Tag::to_tag(signed_core/src/state.rs:7-18).PixelAvatarFNV/RNG stack (~60 L) — deterministic-hashing requirement is legit; reconsider ifDefaultHasherstability is acceptable.
Step 7 — Clean verdicts + one correctness note (no action)
- Confirmed clean, keep as-is:
signed_corecorrectly usesNip34Tag::parse/ SDK builders (only theutag is hand-parsed — SDK doesn't model it);dockcrate is a genuine thin skin overgpui_base::dockrenderer traits (keep; only trim re-exports); LMDB is justified (instant startup lists);signed_gittest suite +tempfilehealthy. Gossip/NIP-65 machinery serves only one login query — consider dropping if NIP-65 routing isn't on the roadmap. - Correctness note:
IssuesView/PullRequestsView/IssueDetailView/PullRequestDetailViewnever observe theirRepoStore— refresh only works because this gpui revision auto-tracks render reads. Accidental; pinning a different gpui breaks them silently. Relevant to Step 5.6.
Suggested order of operations
- Step 1 + Step 2 first — pure deletions, verify with
cargo check+cargo test. - Step 3 (library swaps) next — mechanical, mostly call-site migrations.
- Step 4 (dedup) — largest line savings.
- Step 5 (structural) — deliberate, one at a time.
- Step 6 (over-optimization) — optional, only if you want the extra ~110 L.
Each step below is self-contained; tick what you want done.
- Step 1 — zero-risk deletions
- Step 2 — dead feature removal
- Step 3 — library swaps
- Step 4 — dedup passes
- Step 5 — structural changes
- Step 6 — over-optimization cleanup