aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/PAGING_FINDINGS.md66
-rw-r--r--docs/RPC.md7
-rw-r--r--docs/TEXTUAL_NOTES.md2
-rw-r--r--docs/TUI_DRIVING_BLUEPRINT.md8
4 files changed, 30 insertions, 53 deletions
diff --git a/docs/PAGING_FINDINGS.md b/docs/PAGING_FINDINGS.md
index d2187ae..bcde583 100644
--- a/docs/PAGING_FINDINGS.md
+++ b/docs/PAGING_FINDINGS.md
@@ -2,7 +2,10 @@
Measured against a real target: `libcrypto.so.3` (5.7 MB, **10,092 functions**,
biggest function **52,120 instructions**). These constraints drive the domain /
-paging layer. Reproduce with `tests/stress_paging.py --db <session>`.
+paging layer. They describe the ida-pro-mcp *tool functions* (`list_funcs`,
+`disasm`, `decompile`, `xref_query`, …) which the idalib worker now calls
+in-process (`idatui/worker.py`) — the shapes and caps below are the tools'
+behaviour and are unchanged by dropping the HTTP transport.
## Response shape (list_* / *_query tools)
@@ -93,52 +96,25 @@ fall back to the disassembly view or show an error panel.
Normal decompile bodies are server-truncated with a `[N chars total]` marker
(still to be solved for full-body display — see Phase 2).
-## Workers self-exit when idle (`idle_ttl_sec`, default 600s) — SOLVED
+## Worker lifecycle (idatui's own idalib worker)
-### Why it happens
-Each idalib worker runs a `WorkerLifecycle` watchdog
-(`ida_pro_mcp/worker_lifecycle.py`): if no JSON-RPC request hits its dispatcher
-for `idle_ttl_sec` (default **600s**), the worker **self-exits cleanly**. It is
-refcount-free — "activity == alive": every forwarded tool call `touch()`es the
-timer. This is deliberate resource hygiene for a *shared* supervisor (each worker
-holds an IDA license slot + the DB's RAM; default max 4 workers), aimed at
-ephemeral/agent usage that opens a DB and wanders off. For an **interactive TUI
-that should be able to just chill, it's the wrong default.** The startup binary
-passed to `idalib-mcp` on the CLI always gets 600s (no CLI flag to change it).
+idatui no longer uses ida-pro-mcp's shared HTTP supervisor. `idatui/worker.py`
+opens exactly **one** database with `idapro.open_database(...)` in its own process
+and serves tool calls over a unix socket (`WorkerClient`). Consequences vs the
+old supervisor model, which several design choices here were built around:
-After self-exit the session lingers in `idb_list` but calls fail with
-`"Worker for session <id> is not reachable"` (distinct from `"Session not
-found"`).
-
-### The fix (both implemented + verified in `tests/test_keepalive.py`)
-1. **`IDAClient.bump_idle_ttl(idle_ttl_sec=1e9)`** — `idb_open` on the
- already-open path is idempotent and re-applies the TTL; `set_idle_ttl` has no
- upper cap, so ~1e9s is effectively 'never'. This is the intended knob and the
- primary fix: the TUI calls it once at startup.
-2. **`IDAClient.keepalive(interval=120)` -> `KeepAlive`** — a background
- heartbeat issuing a cheap `server_health` (~2ms) that resets the watchdog.
- Belt-and-suspenders, and it also covers *adopted* sessions whose path we don't
- control / don't want to re-open.
-
-Recommended TUI policy: run a `KeepAlive` heartbeat (interval < TTL) to keep the
-*running* session warm, and use a **moderate** idle TTL (not ‘never’) so the
-worker is reclaimed after the TUI exits. "Worker not reachable" then only occurs
-on a real crash, which the app handles by re-`idb_open`.
-
-## Supervisor worker cap (`max_workers`, default 4)
-
-The supervisor allows at most `max_workers` concurrently-open binaries; a 5th
-`idb_open` fails with "Maximum idalib worker count reached". Before counting it
-**prunes unreachable workers**, so a dead/killed worker frees its slot on the
-next open. Two consequences drove design choices:
-
-* Do **not** make sessions immortal (`bump_idle_ttl(1e9)`) — they pile up to the
- cap and never free. Instead: `KeepAlive` while running + a moderate TTL
- (idatui uses 1800s on `--open`) so idle sessions self-exit after the TUI
- closes and free their slot.
-* `spawn.sh` sets `IDA_MCP_MAX_WORKERS` (default raised to 8) for headroom; to
- free a stuck slot immediately, kill the idle worker process (it gets pruned on
- the next open).
+* **No `max_workers` cap, no cross-session contention.** Each TUI owns its
+ worker; there is no "Maximum idalib worker count reached" and no shared license
+ slot to free.
+* **No idle self-exit / keepalive dance.** The old per-worker `WorkerLifecycle`
+ watchdog (`idle_ttl_sec`, default 600s) and the `KeepAlive` heartbeat that
+ fought it are gone with the supervisor. The worker lives as long as the TUI
+ holds the socket and dies with it. `WorkerClient.keepalive()` is a no-op kept
+ for API parity, and `--ttl` is passed through but the single owned worker does
+ not self-reap.
+* **A crashed worker drops the socket**, surfacing as `IDAConnectionError`; the
+ app's `_reconnect` respawns a fresh worker (re-opening + re-analyzing the
+ binary). The hard-kill lock recovery below still applies.
## Writable path requirement (operational)
diff --git a/docs/RPC.md b/docs/RPC.md
index 4a68fbe..d1290f5 100644
--- a/docs/RPC.md
+++ b/docs/RPC.md
@@ -16,7 +16,7 @@ this doc is the underlying protocol reference.
```
# pane A — the TUI (real render) + a socket listener
-python -m idatui.tui --db <session> --rpc /tmp/ida.sock
+./ida-tui /abs/path/to/binary --rpc /tmp/ida.sock
# pane B — drive it. Ergonomic (auto-finds the socket, terse text):
python -m idatui.drive where
@@ -117,6 +117,7 @@ to read the pseudocode → `cursor line=.. col=..` onto a token → `rename name
a generic worker-drain — read `state()` to confirm.
- IDA renders some names without a leading `.` (e.g. `.init_proc` → `init_proc`
in pseudocode); resolve/goto by the list name, but match tokens by what's shown.
-- `tests/rpc_smoke.py` boots the app on a socket in-process and drives the whole
- surface end-to-end — the protocol's regression lock.
+- Drive the surface end-to-end from another process with `idatui.rpcclient` /
+ `idatui.drive`; the headless pilot (`tests/test_scenarios.py`) is the UI
+ regression lock and shares `_sync.py`'s settle logic with the RPC server.
```
diff --git a/docs/TEXTUAL_NOTES.md b/docs/TEXTUAL_NOTES.md
index 6ce9037..4bf7fcb 100644
--- a/docs/TEXTUAL_NOTES.md
+++ b/docs/TEXTUAL_NOTES.md
@@ -1,7 +1,7 @@
# Textual notes & app patterns
Hard-won Textual behaviour and the patterns this app relies on. Pairs with
-`PAGING_FINDINGS.md` (the ida-pro-mcp/idalib side).
+`PAGING_FINDINGS.md` (the idalib side).
## Textual pitfalls
diff --git a/docs/TUI_DRIVING_BLUEPRINT.md b/docs/TUI_DRIVING_BLUEPRINT.md
index 094f87a..cb16d73 100644
--- a/docs/TUI_DRIVING_BLUEPRINT.md
+++ b/docs/TUI_DRIVING_BLUEPRINT.md
@@ -328,9 +328,9 @@ terse, socket auto-resolved, every action visible in the gdb TUI pane.
vocabulary — don't invent; mirror what a power user types).
4. Wire the **spawn command** + **readiness** into the pane manager.
5. Reuse transport, client, and ergonomic CLI unchanged.
-6. Add a **smoke test** that spawns the target on a socket and drives the whole
- surface end-to-end (idatui's `rpc_smoke.py` is the template — it also locks the
- protocol against regressions).
+6. Add a **regression test** that drives the surface end-to-end (idatui uses a
+ headless Textual Pilot suite, `tests/test_scenarios.py`, sharing the settle
+ logic with the live RPC server via `_sync.py`).
## 13. Pitfalls & lessons (paid for once already)
@@ -352,4 +352,4 @@ terse, socket auto-resolved, every action visible in the gdb TUI pane.
---
*Reference implementation: `idatui/{rpc,rpcclient,drive,pane,_sync}.py`,
-`docs/RPC.md`, `tests/rpc_smoke.py` in this repo.*
+`docs/RPC.md`, `tests/test_scenarios.py` in this repo.*