From b8d9aa4fce78f4523cffaba8b46095d2dfb66310 Mon Sep 17 00:00:00 2001 From: blasty Date: Sat, 25 Jul 2026 23:03:10 +0200 Subject: projects phase 4: cross-binary back, linkage-guided pre-warm, project verbs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things, all following from phase 3 making cross-binary jumps ordinary. **A cross-binary jump was a one-way door.** Nav history is per-binary, so arriving in another binary — a project search hit, or now following an import into the library that implements it — landed you in an empty history with nothing to take you back. _switch_then_goto records the binary it came FROM, and action_back falls through to that hop once local history is spent: Esc walks back through the function you were in, then the binary you were in. Manual Ctrl+O switching records nothing, because that isn't navigation. **Pre-warm follows the linkage graph, not list order.** _prewarm_provider warms the binary providing the most of this one's imports — where a follow is most likely to go, so its startup is paid before you ask for it. "Next in the list" would have been arbitrary; phase 3 gave us something better to ask. pool.prewarm() refuses rather than making room. Evicting a binary the user visited to speculatively load one they haven't is a straight downgrade, and it throws away that binary's caches as well; at a tight budget pre-warm just does nothing. The cost of a worker that doesn't exist yet can only be estimated, so it uses the largest resident one (same program, different database) — and if that estimate proves wrong, the speculative worker is the one evicted, never a chosen one. **Driving a project.** pane spawn --project FILE [--open BIN]; `binaries` lists the inventory (active / resident / indexed / where Esc returns to) and `switch {binary,addr?}` makes another active — with an address it takes the search-hit path, so it records a hop. state gains `binary` and `hops`, which it should have had the moment project mode existed. Verified on real sessions: drive binaries/switch against an echo+cat project pane; Esc crossing back from a switch; and prewarm on echo+libc picking libc (provider of echo's imports) and warming it after an evict. tests: +5 pool (prewarm warms, no-ops when resident, refuses at budget, evicts nothing when refusing, ignores unknown labels) and +4 project UI (jump records the hop, Esc crosses back, hop consumed). Confirmed the Esc-back checks fail with the branch removed. 195/0 scenarios, 27/0 project UI, 36/0 index, 27/0 pool, 33/0 project. Left open: project-level persistence across sessions. --- docs/PROJECTS.md | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'docs/PROJECTS.md') diff --git a/docs/PROJECTS.md b/docs/PROJECTS.md index e0484ad..e5359e0 100644 --- a/docs/PROJECTS.md +++ b/docs/PROJECTS.md @@ -197,9 +197,36 @@ original fix — recognise the thunk and present it as an import ("strcmp — imported, provider not in project") rather than surfacing a decompiler error. Phase 3 covers the valuable half; stub *presentation* stays worth doing. -**Phase 4 — polish.** Background pre-warm, nav-history policy (per-binary to -start; a global stack is a later question), RPC/`drive` verbs (`binaries`, -`switch`), project-level persistence. +**Phase 4 — polish (mostly done).** + +*Nav history is per-binary, with a cross-binary way back.* Each binary keeps its +own stack in `BinaryState`; switching restores it (addresses outlive the worker, +so it survives eviction). But phase 3 made a cross-binary jump an ordinary +action, and arriving in a binary whose history is empty made it a one-way door. +`_switch_then_goto` now records the binary it came FROM, and `action_back` falls +through to that hop once local history is spent. So Esc walks back through the +function you were in, then the binary you were in. Manual switching (Ctrl+O) +records nothing — that's not navigation. + +*Pre-warm follows the linkage graph, not list order.* When a binary finishes +indexing, `_prewarm_provider` warms the binary that provides the most of its +imports — where a follow is most likely to take you, so its startup is paid +before you ask. `WorkerPool.prewarm()` refuses rather than evicting: spending a +binary you visited on one you haven't is a straight downgrade, and it would throw +away that binary's caches too. At a tight budget pre-warm simply does nothing. It +estimates the cost of a not-yet-spawned worker from the largest resident one, +which is the only evidence available; if the estimate proves wrong, the +speculative worker is the one that goes. + +*Driving a project.* `pane spawn --project FILE [--open BIN]` opens a project +pane. `binaries` lists the inventory (active / resident / indexed count / where +Esc returns to) and `switch {binary,addr?}` makes another one active — with an +address it goes through the same path as a search hit, so it records a hop. The +state snapshot now carries `binary` and `hops`. + +Still open: project-level persistence (remember the active binary and each +binary's position across sessions — today a fresh launch auto-lands). + ## Decisions -- cgit v1.3.1-sl0p