Skip to content

fix: refresh the AI decompilation when a predicted name is accepted - #182

Merged
vgoat21 merged 1 commit into
refactor/v3-endpointsfrom
fix/ai-decomp-rename-refresh
Oct 20, 2026
Merged

vgoat21 merged 1 commit into
refactor/v3-endpointsfrom
fix/ai-decomp-rename-refresh

Conversation

@vgoat21

@vgoat21 vgoat21 commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Stack: #178 → #179 → #180 → #181 → this.

The bug

Accepting a predicted name renames the function in IDA, then calls only refresh_disassembly_view() — which refreshes the disassembly, not the AI-decomp panel. So the panel keeps rendering its cached result and the body still reads FUN_140004780 after the rename.

Two things make it stick:

  • update_function_name / apply_deduped_name are pure ida_name.set_name calls (base_service.py:46,94). Nothing reaches the platform, so a refetch alone would still return the server's name.
  • _rerender() renders DecompilationData.decompilation — a server-rendered string. The only client-side lever on it is the user-override map, which an in-panel rename already writes via v3_upsert_ai_decompilation_overrides.

The fix

Both rename paths now go through _after_function_renamed, which reuses the refresh button's own logic. When the token map is loaded it writes the local name as a user override on the own_function placeholder — exactly what an in-panel rename does — so the re-rendered decompilation uses the name the function now has in IDA. Before the tokens land there is no placeholder to override, so it falls back to refresh_current().

Adds own_function_placeholder(); own_function is a distinct RenderedToken.kind alongside function and funcptr.

Note this makes "use suggested name" consistent with the in-panel rename: both write an override, so the portal shows the same name. If you'd rather the local rename stay local, the alternative is a local-name branch in effective_values() instead — say the word and I'll swap it.

Verification

541 passed, 3 skipped     (538 before — +3 new tests)
ruff: All checks passed!

Separately: gaps found against the portal

Diffed the plugin's SSE handling against the Dashboard's (apps/dashboard/utils/v3/aiDecompilation/). Not fixed here — flagging for triage:

  1. types_applied triggers no refetch. The Dashboard invalidates three caches on it, guarded on types !== 0: the decompilation tokens, the type suggestions, and the analysis data-type list. Its comment: "every data_type_id the page is holding for this function is one revision behind." The plugin only increments a counter, so its tokens go stale after a type-apply.
  2. rename_applied is parsed and dropped. StreamState.renames is appended to at stream.py:141 and read nowhere. The Dashboard applies each one to the buffered source as a whole-word replace — word boundaries are load-bearing there, since var_1 is a prefix of var_10.
  3. No seq gap detection. The Dashboard tracks two independent seq spaces (decomp-phase and naming-phase), drops duplicates, and stops accumulating source_delta once it sees a hole. The plugin ignores seq entirely, so a dropped frame silently corrupts the streamed preview.
  4. Attempt-reset may wipe the buffer. StreamState.apply resets on event.attempt > self.attempt for every event. The Dashboard excludes the naming events and decomp_failed from attempt tracking because they carry sentinel attempt numbers — if a sentinel is higher than the real attempt, the plugin clears source right before names_finished.
  5. decomp_finished is correctly non-terminal in both — worth keeping that way; the spec is explicit that identifiers are rewritten after it.

🤖 Generated with Claude Code

Accepting a predicted name renamed the function in IDA and then only called
refresh_disassembly_view(), which refreshes the disassembly, not the AI
decompilation panel. update_function_name and apply_deduped_name are pure
ida_name.set_name calls, so nothing reached the platform and the panel kept
rendering its cached result -- the body still read FUN_<addr> after the rename.

Route both rename paths through _after_function_renamed, which reuses the
refresh button's own logic. When the token map is loaded it writes the local
name as a user override on the own_function placeholder, exactly as an in-panel
rename does, so the re-rendered decompilation uses the name the function now
has in IDA. Before the tokens land there is no placeholder to override, so it
falls back to refresh_current().

Adds own_function_placeholder() to locate the token that names the function
itself; own_function is a distinct RenderedToken kind alongside function and
funcptr.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vgoat21
vgoat21 requested a review from a team as a code owner October 20, 2026 10:34
@vgoat21
vgoat21 merged commit 965f87c into refactor/v3-endpoints Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant