300 lines
15 KiB
Markdown
300 lines
15 KiB
Markdown
# Over-optimization and over-engineering action plan
|
||
|
||
- **Status:** phases 1 and 2 implemented; phase 3 still draft, for manual review
|
||
- **Date:** 2026-09-13
|
||
- **Basis:** optimization inventory audit of branch `remove-ai-slop` (HEAD `534d572`)
|
||
- **Scope:** non-UI crates only — `signed_state`, `signed_git`, `signed_core`, `utils`,
|
||
`settings`, `paths`.
|
||
- **Moved out:** all UI-layer findings (workspace views, `signed_ui` components, dock chrome)
|
||
were removed from this plan and are tracked with the separate UI effort. See the appendix
|
||
for the mapping, so nothing is lost.
|
||
- **Owner decisions already made:**
|
||
- `BackendEvent::SyncProgress` **stays**. It is not removed by this plan.
|
||
- `Cargo.toml` build profiles and dependency feature selections are **out of scope**.
|
||
|
||
Each task is written so it can be implemented and verified on its own.
|
||
|
||
## Goals
|
||
|
||
1. Remove speculative and dead machinery in the state/data layer that no behavior depends on.
|
||
2. Fix the places where an existing optimization is subtly incorrect or self-defeating.
|
||
3. Record, for every finding that is *not* acted on, why it is kept (see "Reviewed and kept").
|
||
|
||
## Non-goals
|
||
|
||
- No UI work. Anything that changes rendering, view state, or widget behavior belongs to the
|
||
separate UI effort, even when the edit itself lands in a view file.
|
||
- No speculative performance work. Tasks in phase 3 are marked "measure first" and stay
|
||
optional until profiling or a concrete bug justifies them.
|
||
- No rewrite of the backend/store architecture. The coalescing model is kept; only its dead
|
||
state and one blocking sleep are touched.
|
||
- No dependency changes. In particular, no `smol`, no `ArcSwap`, no `indexmap`, no `dashmap`.
|
||
|
||
## How to read a task
|
||
|
||
- **Where** — files and current line numbers. Line numbers drift; re-locate symbols by name.
|
||
- **Size** — S (under an hour), M (half a day), L (a day or more).
|
||
- **Risk** — chance of a behavior change a user can notice.
|
||
- **Change** — what to do.
|
||
- **Acceptance** — how to know it is done.
|
||
|
||
Implementers must follow the repository `.rules`: no `unwrap()` on fallible paths, propagate
|
||
errors where an operation can fail, full variable names, comments only for non-obvious "why",
|
||
and GPUI executor timers in tests when a test needs time to pass.
|
||
|
||
## Baseline validation
|
||
|
||
Run before and after every phase:
|
||
|
||
```sh
|
||
cargo check --workspace
|
||
cargo test --workspace
|
||
```
|
||
|
||
Manual checks for phases 2 and 3 are in the validation section at the end.
|
||
|
||
---
|
||
|
||
## Phase 1 — Trivial cleanups
|
||
|
||
### OV-01 — Make `shorten_pubkey` panic-free and char-safe
|
||
|
||
- **Where:** `crates/utils/src/pubkey.rs:4-14`
|
||
- **Evidence:** `to_bech32().unwrap()` and byte slicing `&npub[..9]` / `&npub[len-4..]`.
|
||
`crates/signed_ui/src/util.rs:4` has a char-safe `middle_truncate` with the same shape, but
|
||
moving it into `utils` would add a cross-crate dependency direction, so this task stays
|
||
local.
|
||
- **Change:** encode with `to_bech32().unwrap_or_else(|_| public_key.to_hex())` and truncate
|
||
by chars (collect to `Vec<char>`, or iterate), leaving values too short for the ellipsis to
|
||
save space intact (the same `head + tail + ellipsis` guard as `signed_ui::middle_truncate`).
|
||
Output for normal keys must remain `npub1xxxx...yyyy`.
|
||
- **Acceptance:** add a unit test for a valid key and for a short fallback value; output of
|
||
the existing call site (`crates/signed_state/src/profile.rs:53`) is visibly unchanged.
|
||
- **Size:** S. **Risk:** low.
|
||
- **Status:** done 2026-09-13 — `crates/utils/src/pubkey.rs`, tests passing.
|
||
|
||
### OV-02 — Align `docs/TODO.md` with the decision to keep `SyncProgress`
|
||
|
||
- **Where:** `docs/TODO.md:3-9`
|
||
- **Evidence:** the TODO currently instructs a future session to delete the variant, the
|
||
`sync_progress` field, its accessor, and the progress task. That contradicts the owner
|
||
decision above.
|
||
- **Change:** replace that section with a short "kept intentionally" entry: the pipeline is
|
||
retained for a planned sync progress indicator; no subscriber exists yet. Do not touch the
|
||
`login`/`logout` section (separate decision).
|
||
- **Acceptance:** the file no longer instructs removal; `SyncProgress` code untouched.
|
||
- **Size:** S. **Risk:** low.
|
||
- **Status:** done 2026-09-13 — `docs/TODO.md` now marks the pipeline as kept intentionally.
|
||
|
||
---
|
||
|
||
## Phase 2 — Runtime behavior
|
||
|
||
### OV-03 — Simplify `RefreshGate` to running/dirty and give `CheckoutsStore` its own debounce flag
|
||
|
||
- **Where:** `crates/signed_state/src/refresh.rs:1-56`; users at
|
||
`crates/signed_state/src/repos.rs:247,255,373,384`,
|
||
`crates/signed_state/src/repo.rs:300,312,455,554`,
|
||
`crates/signed_state/src/checkouts.rs:284,303,378,402,456,518`, and the one UI call site
|
||
`crates/workspace/src/views/inbox.rs:180-205,219,225,234`.
|
||
- **Evidence:** only `CheckoutsStore` ever leaves `debouncing` set across a call: it schedules
|
||
a 300 ms timer between `request()` and `begin()`. The other three users call `run_refresh`
|
||
synchronously, so the flag is set and cleared within one call. `inbox.rs:180` even asserts
|
||
the flag is false at its entry point.
|
||
- **Change:**
|
||
1. Reduce `RefreshGate` to `running: bool` plus `dirty: bool`. `request()` returns
|
||
`Fold` while running, otherwise `Schedule`. Keep `running()`, `begin()`, `finish()`
|
||
(returns and clears `dirty`), `abort()` (keeps pending requests, matching today).
|
||
2. Add `debounce_pending: bool` to `CheckoutsStore`. `refresh()` returns early when
|
||
`debounce_pending` or when `request()` returns `Fold`; otherwise it sets the flag and
|
||
spawns the existing `REFRESH_DEBOUNCE` timer. `run_refresh` clears the flag at its start.
|
||
`local_tick` and `run_local_statuses` check `refresh.running() || debounce_pending`.
|
||
3. The other three users keep calling `run_refresh` directly after `Schedule`.
|
||
4. The inbox view needs a mechanical adaptation only: delete the
|
||
`debug_assert!(!self.refresh.debouncing())` and replace it with a plain
|
||
`if self.refresh.running() { self.refresh.request(); return; }`. No rendering change.
|
||
If the UI effort is editing that file concurrently, coordinate the edit rather than
|
||
duplicating it.
|
||
- **Acceptance:**
|
||
- add unit tests in `refresh.rs` for: fold while running, follow-up after finish, abort
|
||
keeps the pending request, non-running request schedules;
|
||
- `cargo test -p signed_state`;
|
||
- manual: commit in a checkout, badges update within a few seconds; sidebar scan while
|
||
scanning coalesces; inbox refresh after a sync does not double-run.
|
||
- **Size:** M. **Risk:** medium. The debounce timing of `CheckoutsStore` must not regress; the
|
||
timer is preserved exactly, only its flag moves.
|
||
- **Status:** done 2026-09-13 — `RefreshGate` is `running`/`dirty` only, `CheckoutsStore` owns
|
||
`debounce_pending`, and the one-line `inbox.rs` adaptation landed here.
|
||
|
||
### OV-04 — Replace the blocking sleep in the grasp push retry
|
||
|
||
- **Where:** `crates/signed_state/src/backend.rs:1722-1726`
|
||
(`std::thread::sleep(GRASP_RETRY_DELAY)` inside `push_staged_to_grasps`)
|
||
- **Evidence:** the function is async and runs on GPUI's background executor. A blocking sleep
|
||
occupies a pool thread for up to two seconds per grasp server and can delay unrelated
|
||
background work.
|
||
- **Change:** await a GPUI executor timer for the same duration. `signed_state` has no
|
||
`smol` dependency and adding one is out of scope, but the executor is already reachable:
|
||
each caller captures `cx.background_executor().clone()` before `background_spawn` and
|
||
passes it into `push_staged_to_grasps` as a parameter, which then awaits
|
||
`executor.timer(GRASP_RETRY_DELAY)`. The accessor is already used this way at
|
||
`crates/signed_state/src/checkouts.rs:289`, and `BackgroundExecutor` is `Clone`.
|
||
- **Acceptance:** `cargo check -p signed_state`; a push that hits a transient denial still
|
||
retries with the same spacing.
|
||
- **Size:** S. **Risk:** low.
|
||
- **Status:** done 2026-09-13 — `push_staged_to_grasps` takes a `BackgroundExecutor` and awaits
|
||
`executor.timer(GRASP_RETRY_DELAY)`.
|
||
|
||
---
|
||
|
||
## Phase 3 — Measure first (optional)
|
||
|
||
These are optimization gaps, not over-engineering removals. Do not start any of them without
|
||
the measurement named in the task, and land them as separate PRs.
|
||
|
||
### OV-05 — Batch the per-root status queries
|
||
|
||
- **Where:** `crates/signed_state/src/repo.rs:390-396` issues one database query per root while
|
||
comments are batched at `:371-377`. `filters::statuses_for` already accepts many roots
|
||
(`crates/signed_core/src/filters.rs:83`).
|
||
- **Change:** collapse the loop into one query over all roots, mirroring the comment batching
|
||
above it.
|
||
- **Acceptance:** record refresh time on a repository with many issues/PRs before and after
|
||
the change; no change in resolved statuses (existing tests plus a manual comparison of a
|
||
repository with mixed open/closed/applied roots).
|
||
- **Size:** S. **Risk:** low.
|
||
|
||
### OV-06 — Consolidate the per-checkout repository opens
|
||
|
||
- **Where:** `crates/signed_state/src/checkouts.rs:598-668` calls five `signed_git` helpers per
|
||
checkout (`worktree_branches`, `worktree_dirty`, `worktree_current_branch`,
|
||
`head_commit_id`, `worktree_commits_ahead`), and each opens the repository separately. The
|
||
local poll runs every 2 s for up to `MAX_STATUS_CHECKOUTS` checkouts.
|
||
- **Change:** add a small `signed_git` API that opens the worktree once and returns the facts
|
||
the status computation needs (branches, dirty flag, current branch, head id, ahead count),
|
||
then use it from both status paths. Measure the poll cost before and after.
|
||
- **Acceptance:** checkouts tests in `crates/signed_state/src/checkouts.rs` pass; the
|
||
ready-to-push and ready-to-contribute statuses remain identical on a repository with a
|
||
dirty worktree, a clean feature branch, and a pushed branch.
|
||
- **Size:** M. **Risk:** medium (worktree state semantics).
|
||
|
||
### OV-07 — Index URL matching in association resolution
|
||
|
||
- **Where:** `crates/signed_state/src/checkouts.rs:573-593` is O(paths × announcements) with
|
||
repeated URL parsing on every full pass.
|
||
- **Change:** normalize and index the announcement clone URLs once per pass, then look up each
|
||
scanned origin instead of scanning all announcements. Keep the EUC match as a fallback.
|
||
- **Acceptance:** existing `resolve_associations` unit tests pass; record full-pass duration
|
||
on a large scan set before and after.
|
||
- **Size:** M. **Risk:** low to medium (URL identity rules are tested at `:754-777`).
|
||
|
||
### OV-08 — Decide the commit total semantics
|
||
|
||
- **Where:** `crates/signed_git/src/history.rs:159-190` caps materialization at
|
||
`MAX_LISTED_COMMITS` (20 000) but still walks all commits to compute `total`.
|
||
- **Change:** either accept the full walk and document it, or stop the walk at the cap and
|
||
expose whether the total is capped so callers can render `20000+`. The badge rendering
|
||
itself belongs to the UI effort; this task only changes the data layer and its contract.
|
||
- **Acceptance:** a decision is recorded here; if the cap is adopted, `CommitList` carries the
|
||
capped flag and the walk stops at the cap. Measure `worktree_all_commits` on the largest
|
||
available repository before deciding.
|
||
- **Size:** S to M. **Risk:** low.
|
||
|
||
---
|
||
|
||
## Reviewed and kept (no action)
|
||
|
||
These were flagged during the audit and reviewed; they should not be "fixed" without new
|
||
evidence:
|
||
|
||
- `SyncProgress` pipeline — kept by owner decision (see OV-02).
|
||
- `Cargo.toml` release profile and dependency feature selection — out of scope.
|
||
- `GitCache` on-disk mirrors and `ensure_clone` fetch-on-open — core product behavior.
|
||
- The 64 MiB gix object cache for history walks and the plain opens for single-object reads.
|
||
- `CommitList` cap plus summary-only commits — memory bound is deliberate; the CPU question is
|
||
OV-08.
|
||
- Backend notification pump debounce and the day-quantized deletion filter — required for
|
||
sync dedup.
|
||
- `CheckoutsStore` polling design as a whole — revisit only via OV-06 and OV-07.
|
||
- `UniversalSigner` (`Arc<RwLock<Arc<dyn InnerSigner>>>`) — needed for in-place signer swap.
|
||
- Grasp transient-denial classification and the stale-advertisement convergence probe —
|
||
behavior justified by real races; only the blocking sleep is changed (OV-04).
|
||
- Debounced/batched profile sync (`ProfileStore`) and the typed filters in `signed_core`.
|
||
|
||
## Validation
|
||
|
||
Automated, per phase:
|
||
|
||
```sh
|
||
cargo check --workspace
|
||
cargo test --workspace
|
||
```
|
||
|
||
Manual checks for the tasks that change runtime behavior:
|
||
|
||
- **OV-03:** make a commit in a tracked checkout; the "ready to push" badge updates within a
|
||
few seconds. Push and confirm the badge clears without waiting for the next poll. Let a
|
||
repository scan overlap a manual rescan and confirm only one follow-up runs.
|
||
- **OV-04:** push to a grasp server that produces a transient denial (or simulate one) and
|
||
confirm the retry still happens at the same spacing and the push result is unchanged.
|
||
- **OV-05:** open a repository with many issues and PRs; statuses and counts match the
|
||
previous build.
|
||
- **OV-06/OV-07:** with several associated checkouts, confirm ready-to-push and
|
||
ready-to-contribute statuses match the previous build and the poll CPU cost drops.
|
||
- **OV-08:** open the Commits tab for a repository larger than the cap; the list behaves as
|
||
decided.
|
||
|
||
## Suggested commit and PR breakdown
|
||
|
||
Follow the repository PR hygiene rules: imperative titles, no conventional prefixes, a final
|
||
`Release Notes:` section with exactly one bullet.
|
||
|
||
1. **`signed_state: Simplify refresh coalescing and stop blocking the executor`**
|
||
(OV-03, OV-04)
|
||
`Release Notes:` `- N/A`
|
||
2. **`utils: Make pubkey shortening panic-free`** (OV-01)
|
||
`Release Notes:` `- N/A`
|
||
3. **`docs: Record over-optimization decisions`** (OV-02 and the kept list)
|
||
`Release Notes:` `- N/A`
|
||
|
||
OV-05 to OV-08 become separate PRs only after their measurement/decision step.
|
||
|
||
## Appendix — moved UI tasks
|
||
|
||
The following findings from the audit were removed from this plan and belong to the separate
|
||
UI effort. They are listed so they can be folded into that plan rather than lost.
|
||
|
||
- Dock chrome: dead `add_bottom_panel`, unused visibility/scrollbar setters, `#[inline]` noise,
|
||
unreachable `Center` arm, duplicated `InvalidPanel` name, per-placement resize-handle
|
||
element ids (correctness), Linux window-controls decoration guard, per-frame layout walks,
|
||
never-set `tiles_scrollbar_mode`.
|
||
- Workspace views: file preview cache invariant drift, eager 1 MiB clone on cache hit,
|
||
`refs.rs` clone, repo header per-render announcement/share clones, eager share links,
|
||
About-dialog clone, PR row worktree clone, discussion participant dedup, Popular-sort
|
||
address recomputation, unbounded `tasks` vectors, duplicated close-panel helper, `defer_in`
|
||
for dock cleanup, PR alert state location, `open_pull_request` validation return value.
|
||
- `signed_ui`: per-render dropdown popover id allocation, pixel avatar RNG simplification.
|
||
- Retention/performance: `retain_all` image-cache memory profiling.
|
||
|
||
Renumbering, for traceability from the first review round:
|
||
|
||
| First-round ID | This plan |
|
||
|---|---|
|
||
| OV-08 | OV-01 |
|
||
| OV-09 | OV-02 |
|
||
| OV-10 | OV-03 |
|
||
| OV-11 | OV-04 |
|
||
| OV-30 | OV-05 |
|
||
| OV-31 | OV-06 |
|
||
| OV-32 | OV-07 |
|
||
| OV-34 | OV-08 |
|
||
| All other IDs | Moved to the UI effort (see above) |
|
||
|
||
## Open questions for the owner
|
||
|
||
1. OV-08: is an approximate (`20000+`) commit total acceptable for the badge contract?
|
||
|
||
OV-03's questions were settled during implementation: the gate keeps two flags (`running`,
|
||
`dirty`), `CheckoutsStore` owns `debounce_pending`, and the mechanical `inbox.rs` edit landed
|
||
in this phase.
|