Files
reverse-engineering-anything/src/mcpStartupPolicy.ts
T
Syed Rishadandgensokyo-dev a062529bb2 feat(ghidra): bound one procedure's decompile without closing the session (#5662)
* feat(ghidra): bound one procedure's decompile without closing the session

Fixes #5340

* fix(ghidra): report decompile limit as a request timeout

Keeps BinarySession from marking every Ghidra operation unavailable after one procedure's decompile reaches the limit, and names the MCP tool-call deadline in the remediation.

* fix(ghidra): budget the decompile limit and report cancellation-closed sessions

Adds REA_GHIDRA_DECOMPILE_TIMEOUT_SECONDS to the derived Codex/Kimi tool deadline and forwards it through setup. Marks a remote failure that settles after caller cancellation so the timeout projection no longer promises session reuse.

* fix(ghidra): align deadline bounds and cancellation outcomes

* refactor(ghidra): shorten deadline recovery guidance

* fix(mcp): clarify the scope of inferred decompile deadlines

* test(ghidra): verify deadline workflows and document measured costs

Separate failure and registration cases by their distinct contracts.
Record actual Linux Ghidra, CLI and MCP evidence with measured context,
elapsed time, CPU and memory, and explicit remaining coverage limits.

* docs(ghidra): pin integration and distinguish baseline format failures

* fix(ghidra): own failure lifecycle wording in the provider

* test(ghidra): budget timeout fixture generation before allocation

* fix(ghidra): align capability and traversal deadline guidance

* style(config): align deadline guidance formatting

* docs(ghidra): record capability and traversal verification

---------

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-10-24 07:42:50 +08:00

66 lines
2.7 KiB
TypeScript

import type { AnalysisProviderSelector } from "./contracts/providerSelection.js";
import {
mcpPhaseBudgetRecovery,
type McpPhaseBudget,
} from "./config/mcpStartupBudgets.js";
/**
* Client startup guidance, operation headroom, and doctor output retention.
* REA startup phase deadlines belong to config/mcpStartupBudgets; consumers
* resolve them from the selected environment with resolveMcpStartupBudgets.
*/
export const MCP_STARTUP_POLICY = {
codexStartupTimeoutSeconds: 30,
kimiStartupTimeoutMs: 30_000,
toolOperationHeadroomMs: 120_000,
doctorStderrBytes: 64 * 1024,
} as const;
/** Doctor startup recovery. The Codex figure is client guidance REA does not enforce. */
export const mcpDoctorDeadlineRecovery = (budget: McpPhaseBudget): string =>
`${mcpPhaseBudgetRecovery(budget)} Codex startup_timeout_sec of ${String(MCP_STARTUP_POLICY.codexStartupTimeoutSeconds)} seconds is client guidance; REA does not enforce that figure as this deadline.`;
/** Parsed startup and upstream request budgets affecting a client's tool deadline. */
export interface McpToolTimeoutInputs {
readonly analysisProvider: AnalysisProviderSelector;
readonly ghidraStartupTimeoutMs: number;
/** One configured Ghidra decompile allowance; bulk cardinality is unknown here. */
readonly ghidraDecompileTimeoutMs?: number;
readonly hopperStartupTimeoutMs: number;
readonly jebMcpTimeoutMs?: number;
readonly providerRequestTimeoutMs?: number;
}
/** Allow for known startup phases and caller-selected upstream request budgets. */
export const mcpProviderDeadlineAllowanceMs = (
inputs: McpToolTimeoutInputs,
): number => {
const selectedProvider = inputs.analysisProvider;
// A bounded decompile can run right after a cold import in the same call.
const ghidraAllowance =
inputs.ghidraStartupTimeoutMs + (inputs.ghidraDecompileTimeoutMs ?? 0);
const selectedTimeout =
selectedProvider === "ghidra"
? ghidraAllowance
: selectedProvider === "hopper"
? inputs.hopperStartupTimeoutMs
: Math.max(ghidraAllowance, inputs.hopperStartupTimeoutMs);
return Math.max(
selectedTimeout,
inputs.jebMcpTimeoutMs ?? 0,
inputs.providerRequestTimeoutMs ?? 0,
);
};
/** Add headroom to the single-request estimate; this is not a bulk-workflow bound. */
export const recommendedMcpToolTimeoutMs = (
inputs: McpToolTimeoutInputs,
): number =>
mcpProviderDeadlineAllowanceMs(inputs) +
MCP_STARTUP_POLICY.toolOperationHeadroomMs;
/** Round up so Codex's whole-second deadline still covers the millisecond budget. */
export const recommendedMcpToolTimeoutSeconds = (
inputs: McpToolTimeoutInputs,
): number => Math.ceil(recommendedMcpToolTimeoutMs(inputs) / 1000);