[PR #4062] [MERGED] fix(kuna): list a cold target from the export's own inventory #6026

Closed
opened 2026-10-31 01:11:17 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/4062
Author: @kaoru0822-kitauji
Created: 10/15/2026
Status: ✅ Merged
Merged: 10/15/2026
Merged by: @kaoru0822-kitauji

Base: main ← Head: fix/kuna-share-export-inventory


📝 Commits (5)

  • f9e0df3 fix(kuna): list a cold target from the export's own inventory
  • a071652 fix(kuna): replay a running build's status after its waiter can cancel
  • 59e923f perf(kuna): publish the export's inventory without parsing it twice
  • dadfff6 test(kuna): exercise export inventory sharing from pseudocode requests
  • da4b2cb fix(kuna): let a listing wait for an export that is still starting

📊 Changes

7 files changed (+224 additions, -31 deletions)

View changed files

📝 docs/kuna-provider.md (+2 -2)
📝 src/kuna/KunaProjectCache.ts (+8 -0)
📝 src/kuna/KunaProjectExport.ts (+39 -21)
📝 src/kuna/KunaSessionClient.ts (+29 -4)
➕ tests/boundary/providers/kuna/kunaExportInventory.test.ts (+98 -0)
📝 tests/boundary/providers/kuna/kunaProjectCache.test.ts (+11 -4)
📝 tests/boundary/providers/kuna/kunaProjectConcurrency.test.ts (+37 -0)

📄 Description

Summary

On a cold cache, a text request (pseudocode, assembly, analyze_function) starts the background export and then resolves its procedure through the inventory. The session ran kuna functions --json for that resolution while the export ran the same kuna functions --json as its first step, so the target was inventoried twice at once. On a large app binary this doubles the most expensive part of the first request, and the session's run was also bound by the 120 s single-function deadline. Refs #1957.

Problem and expected behavior

Smallest trigger: cold cache, open_binary with provider_id: "kuna", then procedure_pseudo_code, by name or by address. Since c9f9b83c6, inventory-only requests (listings, procedure_address, call relationships, xrefs) no longer start the export, so they run one inventory on main too. The duplicate remains for every text request, and for listings issued while an export builds. The fake Kuna records two functions invocations; a real run shows two concurrent kuna functions processes. Expected: one inventory per cold target. The export's listing answers the session as soon as it is parsed, before decompilation starts.

Change and scope

  • KunaExportStatus.inventoryFunctions: number | null becomes inventory: readonly KunaInventoryFunction[] | null, the inventory the export already parsed. project_export.inventory_functions in raw_result is derived from it, so its value is unchanged.
  • KunaProjectCache keeps each running build's latest status and replays it to a request that joins later. A second session joining a running export therefore gets the inventory already listed. Before, it also saw phase: null until the next status.
  • KunaSessionClient takes listings from the published export, then from the building export's inventory. It runs kuna functions itself only when the export ends without an inventory (for example, the export's listing failed), keeping today's error reporting for that case.
  • docs/kuna-provider.md describes the cold listing source and the fallback's deadline.
  • Review follow-ups: the cache replays the status only after a joining request's cancellation is registered. The export publishes the inventory it already parsed instead of re-parsing functions.json (new readKunaExportSource owns the .c scan), so the status, the session and the published project share one array. On main the export held two parsed copies during publication and the session a third.

Not included: the 128 MiB inventory output cap (KUNA_INVENTORY_OUTPUT_BYTES). Telegram's 696,944-entry inventory is 124 MB, 93% of the cap, while the code comment assumes at most about 393k entries. That is a separate capacity question.

Scope: an ordinary fix within the existing Kuna provider boundary; no maintainer scope decision applies.

Contract and boundary impact

  • Semantic owner and earliest changed stage: exportKunaProject (which already owns the parsed inventory) → KunaProjectCache status fan-out → KunaSessionClient listings.
  • Contribution scope fit and linked maintainer decision: not applicable.
  • CLI and MCP/tool-catalog contract: unchanged. Listing results are the same inventory, now from the export's own functions run.
  • Provider, bridge, target-format, or platform compatibility: Kuna only.
  • Evidence, artifact, provenance, or reconstruction contract: unchanged. Listings carry no raw_result, as before.
  • Target selection, authority, upstream behavior, and cleanup details: one fewer Kuna process per cold target. The listing no longer creates the single-function workspace copy, which is now made only when a single-function run needs it.
  • Generated metadata, package, or installation impact: none.

Expected effects:

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

(Process launches are the existing kuna runs; this change removes one.)

Evidence and regression coverage

  • Tests added or updated: new kunaExportInventory.test.ts:

    • a cold pseudocode request and a following search answered with one functions run while the export keeps decompiling;
    • a second session's pseudocode request, joining the running export, gets the replayed inventory with no new run;
    • when the export's listing fails (non-JSON), the session's own run reports the error.
    • a search sent together with a cold pseudocode request waits for that request's startup decision (review fix), so one functions run serves both; on the previous head it recorded 2.

    kunaProjectCache.test.ts "reports each build phase" now also requires waiters to receive the very array the export publishes (toBe).
    kunaProjectConcurrency.test.ts "lets a joining request cancel from the status replayed to it" covers the review fix: the replay happens after the joining request's cancellation is registered.

  • Base reproduction, with src/kuna checked out from origin/main (c9f9b83c6): the first two new tests fail with 2 and 3 functions runs instead of 1. The phase test (toBe) and the replay-cancellation test fail too, and the fallback test passes on both, as intended.

  • Real Kuna 1.833, macOS arm64 (16 GB), default REA_KUNA_JOBS=1, cold cache, on main c9f9b83c6 vs this PR rebased onto it. Target: /Applications/Telegram.app/Contents/MacOS/Telegram (thin arm64, 254 MB, 696,944 inventory entries). MCP procedure_pseudo_code by address 0x1000e9428, also timing when the export reports decompiling (10 s progress granularity). One run per build:

    Build pseudocode answered export reached decompiling Process wall Process user CPU kuna functions runs
    main 74 s 82 s 83.8 s 147.3 s 2
    this PR 68 s 76 s 76.9 s 77.9 s 1

    Earlier, before c9f9b83c6, cold search_procedures gave 81.6 / 82.6 s and 152.8 / 152.0 s CPU on main versus 70.9 / 75.0 s and 70.2 / 72.3 s on this PR. CPU halves consistently. I make no memory claim: sampled RSS of the kuna functions runs (main 2842 + 2620 MiB, this PR 6614 MiB) is distorted by macOS memory compression under pressure on this host. CPU and wall come from /usr/bin/time -p around the MCP harness. Model tokens were not measured.

  • Remaining proof gaps: no Linux run; one real large target; the replay to a joining session is covered with the fake only.

  • Observed, derived, and inferred claims remain distinguishable.

  • Artifact identity, source provenance, and failed attempts remain preserved.

  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npm run test:focused -- tests/boundary/providers/kuna/*.test.ts: 139 passed three times on the latest head (138 ×2 before the startup-wait fix). Earlier heads: 97 ×3 after the first review fix, 96 ×4 before it.
  • New and changed tests on main's src/kuna: 4 failed, the fallback test passed, as described above.
  • npm run check:fast: typecheck and lint passed.
  • npm run docs:check: passed.
  • REA_KUNA_COMMAND=… npm run verify:kuna (real Kuna 1.833, darwin/arm64): passed, process lineage verified, cleanup: "complete".
  • Real Telegram measurements above. Real Sublime Text arm64, concurrent cold pseudocode and search: 2 distinct kuna functions processes on main, 1 on this head.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. KunaExportStatus is internal to the provider.
  • Real Hopper/Ghidra, browser, or OS coverage: real Kuna on macOS arm64 only.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: one fewer owned Kuna process per cold target. Cancellation and cleanup of the remaining run are unchanged.

Author readiness

Human owner:

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/4062 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/15/2026 **Status:** ✅ Merged **Merged:** 10/15/2026 **Merged by:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Base:** `main` ← **Head:** `fix/kuna-share-export-inventory` --- ### 📝 Commits (5) - [`f9e0df3`](https://github.com/morluto/rea/commit/f9e0df3670f80cc48754b2615112096a6b94b29c) fix(kuna): list a cold target from the export's own inventory - [`a071652`](https://github.com/morluto/rea/commit/a0716528043806be3f577789ced867b561795739) fix(kuna): replay a running build's status after its waiter can cancel - [`59e923f`](https://github.com/morluto/rea/commit/59e923f649dd2c7769e072e90e30227de30729ba) perf(kuna): publish the export's inventory without parsing it twice - [`dadfff6`](https://github.com/morluto/rea/commit/dadfff6f56e29a637798054f3743aa0d2e06f98f) test(kuna): exercise export inventory sharing from pseudocode requests - [`da4b2cb`](https://github.com/morluto/rea/commit/da4b2cbcf6fd033e6de447b3921ac17188638bd8) fix(kuna): let a listing wait for an export that is still starting ### 📊 Changes **7 files changed** (+224 additions, -31 deletions) <details> <summary>View changed files</summary> 📝 `docs/kuna-provider.md` (+2 -2) 📝 `src/kuna/KunaProjectCache.ts` (+8 -0) 📝 `src/kuna/KunaProjectExport.ts` (+39 -21) 📝 `src/kuna/KunaSessionClient.ts` (+29 -4) ➕ `tests/boundary/providers/kuna/kunaExportInventory.test.ts` (+98 -0) 📝 `tests/boundary/providers/kuna/kunaProjectCache.test.ts` (+11 -4) 📝 `tests/boundary/providers/kuna/kunaProjectConcurrency.test.ts` (+37 -0) </details> ### 📄 Description ## Summary On a cold cache, a text request (pseudocode, assembly, `analyze_function`) starts the background export and then resolves its procedure through the inventory. The session ran `kuna functions --json` for that resolution while the export ran the same `kuna functions --json` as its first step, so the target was inventoried twice at once. On a large app binary this doubles the most expensive part of the first request, and the session's run was also bound by the 120 s single-function deadline. Refs #1957. ## Problem and expected behavior Smallest trigger: cold cache, `open_binary` with `provider_id: "kuna"`, then `procedure_pseudo_code`, by name or by address. Since c9f9b83c6, inventory-only requests (listings, `procedure_address`, call relationships, xrefs) no longer start the export, so they run one inventory on main too. The duplicate remains for every text request, and for listings issued while an export builds. The fake Kuna records two `functions` invocations; a real run shows two concurrent `kuna functions` processes. Expected: one inventory per cold target. The export's listing answers the session as soon as it is parsed, before decompilation starts. ## Change and scope - `KunaExportStatus.inventoryFunctions: number | null` becomes `inventory: readonly KunaInventoryFunction[] | null`, the inventory the export already parsed. `project_export.inventory_functions` in `raw_result` is derived from it, so its value is unchanged. - `KunaProjectCache` keeps each running build's latest status and replays it to a request that joins later. A second session joining a running export therefore gets the inventory already listed. Before, it also saw `phase: null` until the next status. - `KunaSessionClient` takes listings from the published export, then from the building export's inventory. It runs `kuna functions` itself only when the export ends without an inventory (for example, the export's listing failed), keeping today's error reporting for that case. - `docs/kuna-provider.md` describes the cold listing source and the fallback's deadline. - Review follow-ups: the cache replays the status only after a joining request's cancellation is registered. The export publishes the inventory it already parsed instead of re-parsing `functions.json` (new `readKunaExportSource` owns the `.c` scan), so the status, the session and the published project share one array. On main the export held two parsed copies during publication and the session a third. Not included: the 128 MiB inventory output cap (`KUNA_INVENTORY_OUTPUT_BYTES`). Telegram's 696,944-entry inventory is 124 MB, 93% of the cap, while the code comment assumes at most about 393k entries. That is a separate capacity question. Scope: an ordinary fix within the existing Kuna provider boundary; no maintainer scope decision applies. ## Contract and boundary impact - Semantic owner and earliest changed stage: `exportKunaProject` (which already owns the parsed inventory) → `KunaProjectCache` status fan-out → `KunaSessionClient` listings. - Contribution scope fit and linked maintainer decision: not applicable. - CLI and MCP/tool-catalog contract: unchanged. Listing results are the same inventory, now from the export's own `functions` run. - Provider, bridge, target-format, or platform compatibility: Kuna only. - Evidence, artifact, provenance, or reconstruction contract: unchanged. Listings carry no `raw_result`, as before. - Target selection, authority, upstream behavior, and cleanup details: one fewer Kuna process per cold target. The listing no longer creates the single-function workspace copy, which is now made only when a single-function run needs it. - Generated metadata, package, or installation impact: none. Expected effects: - [x] Read existing files or captured data. - [x] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. (Process launches are the existing `kuna` runs; this change removes one.) ## Evidence and regression coverage - Tests added or updated: new `kunaExportInventory.test.ts`: - a cold pseudocode request and a following search answered with one `functions` run while the export keeps decompiling; - a second session's pseudocode request, joining the running export, gets the replayed inventory with no new run; - when the export's listing fails (non-JSON), the session's own run reports the error. - a search sent together with a cold pseudocode request waits for that request's startup decision (review fix), so one `functions` run serves both; on the previous head it recorded 2. `kunaProjectCache.test.ts` "reports each build phase" now also requires waiters to receive the very array the export publishes (`toBe`). `kunaProjectConcurrency.test.ts` "lets a joining request cancel from the status replayed to it" covers the review fix: the replay happens after the joining request's cancellation is registered. - Base reproduction, with `src/kuna` checked out from origin/main (c9f9b83c6): the first two new tests fail with 2 and 3 `functions` runs instead of 1. The phase test (`toBe`) and the replay-cancellation test fail too, and the fallback test passes on both, as intended. - Real Kuna 1.833, macOS arm64 (16 GB), default `REA_KUNA_JOBS=1`, cold cache, on main c9f9b83c6 vs this PR rebased onto it. Target: `/Applications/Telegram.app/Contents/MacOS/Telegram` (thin arm64, 254 MB, 696,944 inventory entries). MCP `procedure_pseudo_code` by address `0x1000e9428`, also timing when the export reports `decompiling` (10 s progress granularity). One run per build: | Build | pseudocode answered | export reached decompiling | Process wall | Process user CPU | `kuna functions` runs | | --- | --- | --- | --- | --- | --- | | main | 74 s | 82 s | 83.8 s | 147.3 s | 2 | | this PR | 68 s | 76 s | 76.9 s | 77.9 s | 1 | Earlier, before c9f9b83c6, cold `search_procedures` gave 81.6 / 82.6 s and 152.8 / 152.0 s CPU on main versus 70.9 / 75.0 s and 70.2 / 72.3 s on this PR. CPU halves consistently. I make no memory claim: sampled RSS of the `kuna functions` runs (main 2842 + 2620 MiB, this PR 6614 MiB) is distorted by macOS memory compression under pressure on this host. CPU and wall come from `/usr/bin/time -p` around the MCP harness. Model tokens were not measured. - Remaining proof gaps: no Linux run; one real large target; the replay to a joining session is covered with the fake only. - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npm run test:focused -- tests/boundary/providers/kuna/*.test.ts`: 139 passed three times on the latest head (138 ×2 before the startup-wait fix). Earlier heads: 97 ×3 after the first review fix, 96 ×4 before it. - New and changed tests on main's `src/kuna`: 4 failed, the fallback test passed, as described above. - `npm run check:fast`: typecheck and lint passed. - `npm run docs:check`: passed. - `REA_KUNA_COMMAND=… npm run verify:kuna` (real Kuna 1.833, darwin/arm64): passed, process lineage verified, `cleanup: "complete"`. - Real Telegram measurements above. Real Sublime Text arm64, concurrent cold pseudocode and search: 2 distinct `kuna functions` processes on main, 1 on this head. ## Compatibility, safety, and release - Breaking changes or migration steps: none. `KunaExportStatus` is internal to the provider. - Real Hopper/Ghidra, browser, or OS coverage: real Kuna on macOS arm64 only. - Package or release metadata impact: none. - Security, privacy, process, or containment review: one fewer owned Kuna process per cold target. Cancellation and cleanup of the remaining run are unchanged. ## Author readiness Human owner: <!-- @GitHub-handle --> - [ ] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [ ] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [ ] I declare this PR ready for initial maintainer review. ## Before merge - [ ] This PR addresses a concrete problem or an agreed enhancement. - [ ] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [ ] The PR has one focused outcome and the title follows `type(scope): outcome`. - [ ] Related issue is linked, or the reason for not linking one is stated above. - [ ] Tests cover changed observable behavior and meaningful failure paths. - [ ] Owning docs, contracts, and generated metadata are updated where needed. - [ ] User-visible CLI/MCP changes include representative output. - [ ] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:11:17 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#6026
No description provided.