# v0.7 — Search + better git > Part of the [Typoena macro plan](macroplan.md). Requirements and targets: > [qfd.md](qfd.md). Load-bearing decisions: [adr.md](adr.md). **Status:** **`/` search + `n N` done in core** (2026-07-13, host-tested — 207 editor tests). **`:gl` pull BUILT end-to-end 2026-07-14** (firmware 0.7.0, compiles clean; editor refresh hooks host-tested, 209 tests) — **on-device verification pending** (needs Wi-Fi + a remote that moved). - [x] `/` forward search, `n N` — done in core 2026-07-13 (host-tested). Literal, case-sensitive substring (no regex on-device, no smartcase surprises); `/` reuses the `:` command line's editing with a `/` prompt (one command-line mode, as in vim), and the jump happens on **Enter only** — no incremental caret-chasing, for the same e-ink-refresh reason snippets have no completion popup. Wraps around with a "wrapped" notice; "not found: pat" leaves the caret alone; a bare `/`+Enter repeats the last pattern, which is editor-global (survives buffer switches, like vim's search register). `n`/`N` are motions (counts work, Visual extends over them); deliberately **not** operator targets (`dn` out of scope). - [~] `:gl` — pull: fetch + **fast-forward only**, refuse on divergence and surface it (renamed from the planned `:Gpull`). Editor command + `Effect::Pull` done 2026-07-11; **the git-thread fetch/fast-forward is BUILT 2026-07-14** — on-device verification pending. How it works: - The git thread takes a `GitRequest::Pull` on the same channel as publish (shared `ensure_online` Wi-Fi/clock/TLS preamble). `pull_once` fetches origin (the fetch also refreshes the remote-tracking ref, keeping publish's radio-free up-to-date check honest), then maps the four shapes: up to date / **LocalAhead** (stranded commit — `:sync`'s job) / clean fast-forward / **Diverged** (refused, no merge on the device). - The fast-forward is checkout-then-ref-move with a **SAFE** checkout: it refuses to overwrite a file whose content differs from HEAD (belt; the UI gate is the braces). FAT caveat: the splice never updates the index, so SAFE re-hashes each file the pull changes — O(changed), never O(tree). - UI gate: `:gl` is refused while the dirty journal is non-empty ("unsynced changes - :sync first") — an unpublished save would fight the checkout, and sync-then-pull is the single-writer appliance's natural order. A RAM-dirty (never-saved) buffer does *not* gate: its edits simply win over the pulled state (last-writer-wins, like the reconcile). - After a `Pulled` outcome the UI drops clean parked buffers (next switch re-reads the disk), re-reads the clean active buffer in place (`Editor::refresh_active` — boot posture, undo cleared), keeps a RAM-dirty active buffer untouched, and re-walks the palette file list. Snackbar: `pulled ` / `up to date` / `ahead - :sync to publish` / `diverged - resolve on a computer` / `pull: `. Sync performance — inherited from the [real-repo-sync kaizen](kaizen/real-repo-sync.md) (closed 2026-07-13 at 24.1 s end-to-end; target ≤ ~10 s): - [ ] Close the publish gap: 19.8 s today — the splice's 5.0 s and the ~7 s of repo-open/negotiation overhead are the next curves ([tradeoff analysis](tradeoff-curves/sync-commit-staging.md)). - [ ] Instrument the residual ~360 ms/loose-write (suspect: FAT directory-op cost in the freshen/refresh path) — one `sd_bench` + `p_mmap`-miss logging pass. - [ ] The images-off-card lever ([notes/git-sync-images-and-repo-size.md](notes/git-sync-images-and-repo-size.md)) composes with the splice — decide whether to take it here.