From 7ae3c50a9d49c480035855de9fcc4484befacd92 Mon Sep 17 00:00:00 2001 From: Ysopwnable <161784452+N0zoM1z0@users.noreply.github.com> Date: Mon, 12 Oct 2026 22:14:25 +0800 Subject: [PATCH] docs: correct drift and reorganize English guides (#2207) Put setup, developer commands, MCP replies, and investigation recipes before client details and implementation references. Preserve existing guide anchors, examples, provenance, partial-result recovery, and provider restrictions. Correct verified documentation drift, synchronize the Ghidra capability wording, and regenerate metadata for skill version 40. Keep uncertain platform and lifecycle findings unchanged. Refs #2156. Validation: 56 focused tests, check:fast, docs:check, VitePress production build, format and link/example checks. Real isolated CLI/MCP probes cover Ghidra, NativeAOT, HAR, cancellation, Chrome, large ELF delivery, native type limits, and the new JS/managed/process/setup recipes. Heavy work uses two CPUs; a resource-heavy DOM probe was stopped and replaced by a smaller real CDP payload-limit control. Windows, macOS GUI, ADB, and the full CI matrix were not executed. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../skills/reverse-engineer-anything/SKILL.md | 2 +- .../references/native-and-artifacts.md | 18 +- docs/.vitepress/config.ts | 10 +- docs/binary-diagnostics.md | 4 +- docs/browser-observation.md | 10 +- docs/cli.md | 2 +- docs/client-configuration.md | 225 +++++ docs/client-verification.md | 488 +++++++++++ docs/ghidra-dos.md | 11 +- docs/index.md | 20 + docs/installation.md | 679 ++++++--------- docs/javascript-artifact-reconstruction.md | 357 ++++---- docs/managed-code-analysis.md | 128 +-- docs/mcp-contracts.md | 699 +++++++-------- docs/mcp-prompts.md | 6 + docs/native-investigation.md | 301 ++++--- docs/process-capture.md | 164 ++-- docs/testing.md | 806 ++++-------------- docs/wasm-artifacts.md | 2 +- docs/windows-ghidra-p0.md | 6 +- src/generatedPackageMetadata.ts | 2 +- src/ghidra/GhidraProviderCapabilities.ts | 2 +- tests/conformance/README.md | 2 +- third_party/README.md | 2 +- third_party/web-network-captures/README.md | 5 +- 25 files changed, 2096 insertions(+), 1855 deletions(-) create mode 100644 docs/client-configuration.md create mode 100644 docs/client-verification.md diff --git a/.agents/skills/reverse-engineer-anything/SKILL.md b/.agents/skills/reverse-engineer-anything/SKILL.md index e21de6c0a..63f16b978 100644 --- a/.agents/skills/reverse-engineer-anything/SKILL.md +++ b/.agents/skills/reverse-engineer-anything/SKILL.md @@ -2,7 +2,7 @@ name: reverse-engineer-anything description: Reverse engineer native, managed, Electron/JavaScript, packaged, firmware, and browser targets with REA. Use shipped-artifact or requested runtime evidence to explain features, compare versions, decompile code, or guide a reconstruction. Skip REA for ordinary source-repository architecture analysis. metadata: - version: "39" + version: "40" --- # REA diff --git a/.agents/skills/reverse-engineer-anything/references/native-and-artifacts.md b/.agents/skills/reverse-engineer-anything/references/native-and-artifacts.md index dfb701760..e2f3230db 100644 --- a/.agents/skills/reverse-engineer-anything/references/native-and-artifacts.md +++ b/.agents/skills/reverse-engineer-anything/references/native-and-artifacts.md @@ -135,15 +135,15 @@ them. For packaged apps, inventory/extract with REA's artifact tools and retain the exact contained image identity. PDB, ELF debug, or dSYM sidecars are additional evidence only when the provider accepts and matches them. -For deeper type recovery, the optional third-party -[Ghidra NativeAOT analyzer](https://github.com/Washi1337/ghidra-nativeaot) -rehydrates ReadyToRun metadata and can recover method tables, type relationships, -frozen objects, and strings. This is a Ghidra extension with its own install and -interactive workflow; it is not currently part of REA's managed parser or -headless Ghidra bridge. Treat its annotations as analysis evidence, retain the -binary identity, and do not present recovered types as original source. Header -discovery may require a symbol or analyst identification of the ReadyToRun -header, depending on the binary and analyzer version. +REA has a built-in read-only snapshot parser for x64 PE targets with .NET 8 RTR +9.1 metadata. An optional headless Ghidra adapter adds database annotations and +broader metadata recovery on Linux; it requires an explicitly configured +NativeAOT JAR. These are separate routes. See the +[NativeAOT guide](https://github.com/morluto/rea/blob/main/docs/ghidra-nativeaot.md) +for setup, supported layouts, and host restrictions. Preserve binary identity +and distinguish derived metadata from Ghidra database observations. Recovered +types and native pseudocode are not original C# source. Windows Ghidra P0 has +no database mutation authority. ## Packages and extraction diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 7006478bb..c906c4176 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -17,6 +17,7 @@ export default defineConfig({ text: "Getting started", items: [ { text: "Installation and setup", link: "/installation" }, + { text: "Client configuration", link: "/client-configuration" }, { text: "CLI and Evidence", link: "/cli" }, { text: "Agent prompts", link: "/mcp-prompts" }, { text: "Roadmap", link: "/roadmap" }, @@ -42,10 +43,6 @@ export default defineConfig({ { text: "Android applications", link: "/android-analysis" }, { text: "Apple applications", link: "/apple-application-analysis" }, { text: "Firmware", link: "/firmware-analysis" }, - { - text: "Reconstruction readiness", - link: "/reconstruction-readiness", - }, ], }, { @@ -67,6 +64,11 @@ export default defineConfig({ { text: "MCP contracts", link: "/mcp-contracts" }, { text: "Tool design", link: "/tool-design" }, { text: "Testing", link: "/testing" }, + { text: "Client verification", link: "/client-verification" }, + { + text: "Reconstruction readiness", + link: "/reconstruction-readiness", + }, { text: "Releasing", link: "/releasing" }, ], }, diff --git a/docs/binary-diagnostics.md b/docs/binary-diagnostics.md index fc110b685..29e10a33c 100644 --- a/docs/binary-diagnostics.md +++ b/docs/binary-diagnostics.md @@ -101,7 +101,9 @@ Complete results have a 32 MiB input, 64 MiB reply, 1 MiB combined diagnostics and 30-second owned command deadline. The reply budget applies to the decoder record; the CLI/MCP Evidence envelope adds copies and encoding overhead. The pinned MCP SDK defaults to a 10 MiB receive buffer. Large complete results need -a caller-configured `StdioClientTransport({ maxBufferSize: ... })`; the large +a caller-configured `StdioClientTransport({ maxBufferSize: ... })` and a matching +server `REA_MCP_MAX_RESPONSE_BYTES`. See [MCP delivery budgets](mcp-contracts.md#tool-results). +These settings affect delivery, not decoder coverage or limits. The large extended-index verification uses 256 MiB and an explicit five-minute request timeout in its separate opt-in MCP lane. REA does not silently truncate the result. Python lowers resource soft limits to at most 3 GiB virtual address space, 30 CPU seconds and 64 MiB file output. Inherited tighter soft/hard limits are diff --git a/docs/browser-observation.md b/docs/browser-observation.md index 6cdf2942a..2e3d8e37c 100644 --- a/docs/browser-observation.md +++ b/docs/browser-observation.md @@ -193,7 +193,15 @@ validation and resource bounds. Omitted script metadata makes its affected section explicitly truncated. Disallowed-origin entries are filtered before retention. -CDP discovery, WebSocket connection, and commands continue until the peer responds or the caller cancels the operation; REA has no internal byte, message-count, or pending-command quota for these exchanges. Without caller cancellation, a stalled peer can leave an operation waiting. On cancellation, REA closes only its own WebSocket, waiting up to one second before terminating it. Malformed unsolicited events and malformed replies to pending commands poison the connection so later commands fail closed. When a correlated reply reports a session ID, it must match the command's selected session. An optional method is reported unavailable only when the browser rejects it as unknown; other command rejections retain their reported failure. +CDP discovery, connection, and commands wait for the peer or caller cancellation; +a stalled peer can leave an operation waiting. WebSocket messages remain subject +to the [64 MiB limit](#request-boundary). REA does not impose a message-count or +pending-command quota. On cancellation, it closes only its own WebSocket, +waiting up to one second before terminating it. Malformed unsolicited events +and malformed replies to pending commands poison the connection so later +commands fail closed. A correlated reply's session ID must match the command's +selected session. An optional method is unavailable only when the browser +rejects it as unknown; other command rejections retain their reported failure. Network and console coverage starts only after REA attaches and enables the relevant CDP domains. `prior_activity_available` is always `false`; absence from these arrays is not evidence that an event never occurred. If CDP reuses a request ID without supplying redirect metadata, REA retains the predecessor observation and marks network coverage incomplete. diff --git a/docs/cli.md b/docs/cli.md index 48e061c66..3e565c8d7 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -93,7 +93,7 @@ a function dossier; `decompile` returns pseudocode. For assembly instructions alone, use `rea instructions`. A macOS `.app` bundle can be supplied directly. Run `rea --help` or a command's `--help` for arguments and output options. -The [generated catalog](product-catalog.json) lists all CLI commands and MCP +The [generated catalog](mcp-contracts.md#generated-catalog) lists all CLI commands and MCP tools. Provider-specific target support is described in the [native guide](native-investigation.md), [DOS guide](ghidra-dos.md), [raw binary guide](raw-binary.md), and diff --git a/docs/client-configuration.md b/docs/client-configuration.md new file mode 100644 index 000000000..640f559eb --- /dev/null +++ b/docs/client-configuration.md @@ -0,0 +1,225 @@ +# Client configuration and troubleshooting + +Use this reference when a client's configuration paths, profiles, trust settings, +or schema limits affect REA. Start with [installation and setup](installation.md) +for the reviewed setup transaction and [client IDs](installation.md#supported-agents). +The versioned verification notes below describe their stated runs; live service +acceptance is verified only where explicitly recorded. + +## GitHub Copilot CLI + +For GitHub Copilot CLI 1.0.95, `gpt-4.1` model metadata can block ordinary +chat with REA's full input-schema profile before sending a model request +(`compaction_static_context_blocked`; [#1554](https://github.com/morluto/rea/issues/1554)). +For the native offline OpenAI-compatible BYOK adapter, full-profile chat and +analysis also passed with a distinct `COPILOT_PROVIDER_MODEL_ID` such as +`rea-gpt-4.1`, `COPILOT_PROVIDER_WIRE_MODEL=gpt-4.1`, and that distinct ID selected +through `copilot --model rea-gpt-4.1`. The local fixture requested +`COPILOT_PROVIDER_MAX_PROMPT_TOKENS=1000000`; configure the limit supported by +your backend. This keeps every full schema and the actual wire model intact. +It does not establish the effective client budget or fix the built-in-ID path. +The existing compact profile passed native chat and analysis with the complete +tool inventory on Linux using a loopback model fixture. After setup, add +`"REA_MCP_INPUT_SCHEMA_PROFILE": "compact"` to the `env` object of the +`mcpServers.rea` entry in Copilot's `mcp-config.json`, preserving its other +settings, then restart the client. Compact advertisements can reduce nested +schema constraints; REA still validates complete canonical inputs. Full-profile +`gpt-5.4` metadata is also verified locally. Live model API acceptance and +Windows remain unverified; see [native client verification](testing.md). + +## Claude Code + +Claude Code normally defers MCP tool definitions through tool search. It +[turns tool search off](https://code.claude.com/docs/en/mcp#configure-tool-search) +when `ANTHROPIC_BASE_URL` points to a non-first-party host, such as DeepSeek's +Anthropic-compatible endpoint. It then sends every REA tool's name, description +and input schema with every request +([#2019](https://github.com/morluto/rea/issues/2019)). On main at 04089d5be, +with 172 tools, that payload measured about 496 KB with the default profile and +about 290 KB with `compact`. By the o200k and cl100k tokenizers, that is roughly +120k and 68k tokens. Compaction cannot remove tool definitions. If they nearly +fill the window Claude Code assumes, the context refills after every compaction +and Claude Code reports that autocompact is thrashing. To avoid this: + +- Make Claude Code assume the model's actual context window. DeepSeek's Claude + Code guide selects `deepseek-flash[1m]`; the `[1m]` suffix makes Claude Code + assume a one-million-token window. For other unrecognized model IDs, set + `CLAUDE_CODE_MAX_CONTEXT_TOKENS` to the window the provider documents. +- If the endpoint forwards `tool_reference` blocks, set `ENABLE_TOOL_SEARCH=true` + to restore deferred loading. DeepSeek's Anthropic API guide does not list + `tool_reference` among its supported content blocks, so this setting may cause + its requests to fail. +- To shrink the upfront catalog, add + `"REA_MCP_INPUT_SCHEMA_PROFILE": "compact"` to the `env` object of the + `mcpServers.rea` entry in `~/.claude.json` (`$CLAUDE_CONFIG_DIR/.claude.json` + when that variable is set), then restart Claude Code. Setup keeps this + override. + +The sizes above come from REA's own `tools/list`. A live Claude Code session +against DeepSeek's API is unverified. + +## Pi + +For [Pi](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/mcp.md), +setup writes a `type: "stdio"` entry under `mcpServers.rea` in the user-level +`~/.pi/agent/mcp.json` and installs the bundled skill under `~/.agents/skills`. +Use `rea setup --client pi --dry-run --json` to inspect the plan, then +`rea setup --client pi --yes --json` to approve it. Check the registration with +`rea doctor --client pi --json`. Pi reads `mcp.json` as strict JSON, like its +own loader: comments, trailing commas, a byte-order mark, or an empty existing +file are invalid, and setup reports them instead of rewriting the file. Repair +such a file to plain JSON first, then rerun setup. + +Setup follows Pi's `PI_CODING_AGENT_DIR`: unset or empty selects the default; +`~` and `~/` expand to the home directory; absolute paths and file URLs select +that directory; relative paths stay relative to the command's working directory. +On Windows, native paths, `~\`, and Git Bash/MSYS, Cygwin, and WSL drive paths +are normalized as Pi does. Run REA and Pi from the same working directory when +using a relative override. Pi has no profiles: `OMP_PROFILE`, `PI_PROFILE`, +`PI_CONFIG_DIR`, and OMP's `enabledServers`/`disabledServers` lists do not affect +Pi registration. Doctor accepts an omitted `type` for stdio but reports a +non-stdio type as invalid; `enabled: false` stays disabled. + +REA configures only the user scope. Pi also reads `.pi/mcp.json` in trusted +projects; a same-name project entry can replace the user entry or override its +enabled state and exposure. Check that file if the user registration is aligned +but unavailable in a project. An extension that registers `/mcp` can replace +Pi's built-in MCP support and use its own configuration instead. Run `/reload` +in an existing Pi session after changing servers outside the session. + +## Qwen Code + +For Qwen Code, setup registers `rea` in the `mcpServers` table of the +user-level `~/.qwen/settings.json`, or `$QWEN_HOME/settings.json` when configured. +Setup and doctor follow Qwen Code's tilde and working-directory-relative home +overrides. Qwen Code also discovers personal skills in `~/.agents/skills`, +where setup installs the bundled workflow. + +## Gemini CLI + +Gemini CLI uses `$GEMINI_CLI_HOME/.gemini/settings.json` when that home override +is nonempty, including its shared personal skills at +`$GEMINI_CLI_HOME/.agents/skills`. Setup and doctor check MCP allow/exclude +policies from system defaults, user settings, trusted workspace settings, and +system overrides. Workspace trust follows `GEMINI_CLI_TRUST_WORKSPACE`, +`GEMINI_RESTRICTED_MODE`, the effective `security.folderTrust.enabled` setting, +and the selected `trustedFolders.json` (including +`GEMINI_CLI_TRUSTED_FOLDERS_PATH`). Settings in an untrusted workspace do not +participate. A workspace or system `mcpServers.rea` replaces the entire user +entry; setup stops if the winning definition conflicts with its planned entry. +Review those files manually: setup never edits administrator/workspace settings +or grants workspace trust. Trust supplied only by a running IDE is outside this +standalone CLI check. + +## Codex and Devin + +Codex treats an unset or empty `CODEX_HOME` as `~/.codex`. Devin honors +`XDG_CONFIG_HOME` for its `devin/mcp_config.json` on non-Windows systems. + +## OMP + +For OMP, setup writes a `type: "stdio"` entry to the user-level +`~/.omp/agent/mcp.json`. It follows `PI_CONFIG_DIR` and +`PI_CODING_AGENT_DIR` (relative to the setup working directory), and the profile selected by `OMP_PROFILE` or +`PI_PROFILE` (`~/.omp/profiles//agent/mcp.json`). Setup also removes +`rea` from that file's `disabledServers` list, which would otherwise hide the +registration. Doctor treats an `enabled: false` entry as active when +`enabledServers` lists `rea`, as OMP does, unless `disabledServers` also lists +it. Run setup under each profile that should load REA. + +## Hermes + +For Hermes, setup writes a `mcp_servers.rea` entry to `config.yaml`, preserving +comments and unrelated settings. It resolves that file from `HERMES_HOME`, else +from the platform default Hermes itself uses — `%LOCALAPPDATA%\hermes` on +Windows, `~/.hermes` elsewhere — including any `HERMES_DATA_DIR_SUFFIX`. Hermes +connects an entry unless `enabled` is false, so setup states `enabled: true`. + +Hermes personal skills install under the active Hermes home's `skills` directory. +Setup, doctor and uninstall follow the root's `active_profile` selection, as +plain Hermes CLI commands do. An explicit `HERMES_HOME` pointing to +`profiles/` selects that named profile directly. An invalid, missing or +deleted sticky profile is reported instead of writing into the default home; +repair the profile or run `hermes profile use default` before retrying. +REA follows `HERMES_HOME` whitespace trimming, environment-variable expansion, +and home expansion before resolving that profile. Setup previews the resolved +configuration and skill destinations; doctor and uninstall use those same paths. + +## DeepSeek Harness + +DeepSeek Harness registers MCP clients through a Cordis YAML patch sequence +rather than a `mcpServers` object. `rea setup --client dsh` appends (or +replaces) the REA entry in the home patch `$DSH_HOME/cordis.patch.yml` +(`~/.dsh/cordis.patch.yml` when `DSH_HOME` is unset), preserving unrelated +patches and comments. `rea doctor --client dsh` checks that same entry id. +`rea uninstall` removes it by scanning supported clients; uninstall takes no +`--client` flag. The home patch applies to every Harness profile, so the +registration is written once and no per-profile edit is needed. The written +entry is: + +```yaml +- insert: + - id: rea-mcp + name: "@deepseek-ai/dsh-mcp-client" + config: + serverName: rea + transport: stdio + command: /absolute/path/to/node + args: ["/absolute/path/to/rea/scripts/rea.mjs", mcp] +``` + +Setup preserves caller-owned Cordis expressions and replaces launcher fields +with literal values that doctor can verify. It refuses to edit an expression +that produces the entire REA config, or a group-targeted REA insertion. Use a +literal config and a root-level insertion as shown above. + +For a global npm installation, the launcher is under +`$(npm root -g)/rea-agents/scripts/rea.mjs`. Restart Harness after setup; it +exposes tools as `mcp__rea__`. Run `rea setup --skill --dry-run`, +review the destination, then `rea setup --skill --yes` to install the workflow +in `~/.agents/skills` (`$DSH_AGENTS_HOME/skills` when configured); Harness +discovers that directory, and its native `skill` tool can load +`reverse-engineer-anything`. + +REA's optional [native client verification](testing.md#end-to-end-integration-and-golden-evidence) +checks headless chat, skill loading, all tool input schemas and actual analysis +using the installed Harness and a local model fixture. This establishes the +Harness integration, with live DeepSeek API compatibility remaining unverified. +See the [Harness MCP guide](https://github.com/deepseek-ai/deepseek-harness/blob/639ed015397290b3745d163aafe02ffee4aa3f84/packages/mcp/mcp-client/README.md) +for its native configuration contract. + +## Other client settings + +For OpenCode, setup writes the V1 `mcp.rea` entry, which OpenCode V1 and V2 +both load. If the configuration already uses OpenCode V2's native +`mcp.servers` table, setup registers REA there instead and replaces any earlier +`mcp.rea` entry from REA. Setup honors `OPENCODE_CONFIG_DIR` and +`OPENCODE_CONFIG`, preferring the later-loaded JSONC file when both JSON and +JSONC exist. The ordinary XDG global configuration still participates when a +custom directory is selected. Doctor checks the merged user registration; uninstall removes +REA-owned entries from every applicable user file so an older entry cannot +become active again. Malformed applicable files block setup before changes. + +Grok Build loads `[mcp_servers.rea]` from `$GROK_HOME/config.toml`, or from +`~/.grok/config.toml` when `GROK_HOME` is unset or empty. Setup edits that server +table, `[mcp_servers.rea.env]`, and a root `disabled_mcp_servers` entry that +names `rea`. It sets `startup_timeout_sec = 30` and leaves every other name +in that list. The shared skill installed under `~/.agents/skills` is already +on Grok Build's skill path. + +Grok Bot (`grok_bot`) is detected from `~/.grokbot`, or from `SAND_DATA_ROOT` +when that value is an absolute path. A relative or empty `SAND_DATA_ROOT` +stays on `~/.grokbot`. That directory is not the connector store. Grok Bot +keeps connectors in the signed-in account and runs them on its hosted +computer. It does not import `mcp.json` from the data directory, and it does +not attach a stdio server running on this machine. Setup does not call the +account connector API, does not write a registration file, and does not report +the data directory as aligned. Ask the Grok Bot chat to add a custom MCP +server named `rea` that runs on the Bot's computer: + +```bash +npx -y rea-agents@ mcp +``` + +Do not put credentials in that command or its arguments. `rea doctor --client grok_bot` +reports this manual step. `rea uninstall` does not remove the account connector. diff --git a/docs/client-verification.md b/docs/client-verification.md new file mode 100644 index 000000000..a02c67edf --- /dev/null +++ b/docs/client-verification.md @@ -0,0 +1,488 @@ +# Client and agent verification + +Use these optional lanes to verify an installed client or evaluate an agent's +REA workflow. [Testing REA](testing.md) provides the normal development commands +and provider lanes. Each record below states its host, client version, model +fixture, and remaining coverage; a native-client run with a loopback model does +not establish live model-service acceptance. + +## End-to-end, integration and golden evidence + +The optional `verify:qwen-client`, `verify:pi-client`, and `verify:hermes-client` +lanes require an installed native client. Select its executable with +`REA_VERIFY_QWEN_COMMAND`, `REA_VERIFY_PI_COMMAND`, or `REA_VERIFY_HERMES_COMMAND`. +They configure disposable profiles through the public REA CLI, preserve caller +settings and backups, and exercise real stdio MCP calls and skill loading. The +`call` mode checks complete catalog discovery and actual JavaScript Evidence; +pass `-- chat` to check plain chat with REA enabled. Qwen also reads the full +result that its client offloads, and Pi exercises default codemode execution. +Use `REA_VERIFY_RUNTIME_ROOT` to select a production-only installed REA package. +Receipts retain client versions, result digests, host coverage and owned-process +cleanup. These POSIX lanes use a deterministic loopback model, so they do not +prove live model-provider or native Windows compatibility. Qwen, Pi and Hermes +bind both `HOME` and `USERPROFILE` to the disposable account. Qwen and Pi discover +the shared personal skill through their default search paths without an explicit +skill setting; Hermes discovers it through the selected `HERMES_HOME`. +Set `REA_VERIFY_HERMES_STICKY_PROFILE=1` to exercise native Hermes selection of +a named sticky profile with `HERMES_HOME` still pointing to its root. + +`verify:gemini-client` requires an installed Gemini CLI (verified with +`@google/gemini-cli@0.63.0` on POSIX and native Windows); select it with +`REA_VERIFY_GEMINI_COMMAND`. A selected `.js`, `.mjs` or `.cjs` entry point runs +under the verifier's Node. On Windows, select the npm install's +`node_modules/@google/gemini-cli/bundle/gemini.js`, because only a `gemini.cmd` +shim reaches `PATH`. +The optional lane uses native `GEMINI_CLI_HOME` discovery in an isolated +Git project, checks setup plans, backups and idempotence, activates the installed +personal skill, validates all forwarded input JSON Schemas against their declared +dialect, forwards the complete REA catalog and checks full JavaScript +Evidence for a Unicode path. Use `-- chat` for ordinary chat with REA enabled, +or `REA_VERIFY_RUNTIME_ROOT` for a production-only installed REA package. +The local fixture exercises the real Gemini API adapter, including its +`untrusted_context` tool-result envelope. Token counts are synthetic; live +Google API compatibility remains unverified. The lane disables +the client's memory-based relaunch to preserve the caller's Node heap budget. + +`verify:opencode-client` requires an installed OpenCode (verified with +`opencode-ai@1.18.35`); select it with `REA_VERIFY_OPENCODE_COMMAND`. +The optional POSIX lane configures isolated XDG roots and `OPENCODE_CONFIG_DIR`, +checks setup plans, backups, preserved JSONC comments and idempotence, activates +the installed skill, validates all forwarded input schemas and verifies complete +JavaScript Evidence for a Unicode path. JSONC is the default fixture; set +`REA_VERIFY_OPENCODE_CONFIG_FORMAT=json` for JSON. Use `-- chat` for ordinary +chat or `REA_VERIFY_RUNTIME_ROOT` for a production-only installed package. +The native core runs with external plugins disabled through `OPENCODE_PURE`; +the local OpenAI-compatible fixture has a caller-declared one-million-token +context and synthetic usage. Skills use an explicit isolated `skills.paths` +directory, so default OS-home discovery remains unverified. Live model APIs and +native Windows are also unverified. + +`verify:claude-client` requires installed Claude Code (verified with +`@anthropic-ai/claude-code@2.1.296` on POSIX and native Windows); select it +with `REA_VERIFY_CLAUDE_COMMAND`. On Windows, select +`claude.exe`: npm installs put only a `claude.cmd` shim on `PATH`, and the real +executable is under `node_modules/@anthropic-ai/claude-code/bin`. +The optional lane uses native `CLAUDE_CONFIG_DIR` discovery, an independent +Git workspace, user settings and default built-in tools. It preserves caller +preferences and backups, checks idempotent setup, waits through the native +`WaitForMcpServers` tool when discovery is pending, and validates the complete +catalog and forwarded input schemas. Call mode loads the personal skill through +native `Skill`, checks its full body and verifies named-schema JavaScript Evidence +for a Unicode path. Use `-- chat` for ordinary chat with REA enabled, or +`REA_VERIFY_RUNTIME_ROOT` for a production-only installed package. The local +Anthropic Messages/SSE fixture preserves native resource-hint envelopes in its +request artifacts. Usage is synthetic; live Anthropic API and bare-mode +personal-skill activation remain unverified by this lane. + +`verify:copilot-client` requires installed GitHub Copilot CLI (verified with +`@github/copilot@1.0.95`); select it with `REA_VERIFY_COPILOT_COMMAND`. +The optional POSIX lane uses native `COPILOT_HOME` discovery, an independent +Git workspace, guarded setup plans, preserved registrations, backups and +idempotence. Native `skill add` registers the isolated installed skill; call +mode loads its full body, validates all forwarded input schemas and checks +named-schema JavaScript Evidence for a Unicode path. When Copilot spills a +large MCP result, the model requests native `view` with `forceReadLargeFiles` +and validates the complete returned Evidence rather than its preview. +Use `-- chat` for ordinary +chat or `REA_VERIFY_RUNTIME_ROOT` for a production-only installed package. +The native offline BYOK adapter uses a loopback OpenAI completions/SSE fixture +and `gpt-5.4` model metadata; model inference and token usage are synthetic. +Set `REA_VERIFY_COPILOT_MODEL` to examine another client model ID and +`REA_VERIFY_COPILOT_WIRE_MODEL` for its backend model name (defaults to the client +ID). Every actual HTTP request's model is checked and recorded separately. +Both `HOME` and `USERPROFILE` point to the disposable account; native `skill add` +still selects the installed skill directory explicitly. + +The same native client passed full-profile chat and analysis with the actual +wire model `gpt-4.1` under a distinct BYOK model ID: + +```bash +REA_VERIFY_COPILOT_MODEL=rea-gpt-4.1 REA_VERIFY_COPILOT_WIRE_MODEL=gpt-4.1 npm run verify:copilot-client -- chat +REA_VERIFY_COPILOT_MODEL=rea-gpt-4.1 REA_VERIFY_COPILOT_WIRE_MODEL=gpt-4.1 npm run verify:copilot-client -- call +``` + +These runs retain full canonical input/output schemas, all tools, installed-skill +loading and complete Evidence readback. They use the fixture's requested +one-million-token BYOK prompt setting; effective capacity and live API acceptance +remain unknown. With the built-in `gpt-4.1` model ID, the verified client still +blocks the full input-schema profile before HTTP with +`compaction_static_context_blocked`, even when requesting a larger BYOK prompt +capacity. The effective capacity is unknown. The default verifier preserves +the complete catalog and full schemas. To verify the existing compact profile: + +```bash +REA_VERIFY_COPILOT_MODEL=gpt-4.1 REA_VERIFY_COPILOT_SCHEMA_PROFILE=compact npm run verify:copilot-client -- chat +REA_VERIFY_COPILOT_MODEL=gpt-4.1 REA_VERIFY_COPILOT_SCHEMA_PROFILE=compact npm run verify:copilot-client -- call +``` + +Both native workflows passed with the complete tool inventory. The verifier selects the +profile only in its disposable Copilot registration and records it in the +receipt. Compact advertisements can reduce nested validation structure; the +server still validates complete canonical inputs. This is a tested alternate +workflow, not a fix for the full-profile client/model limit tracked in #1554. +Live model APIs, native Windows and default OS-home skill discovery remain +unverified. + +`verify:grok-client` requires installed Grok Build (verified with the official +Linux x64 1.0.50 binary); select it with `REA_VERIFY_GROK_COMMAND`. This optional +POSIX lane isolates `GROK_HOME`, an independent Git workspace and additional +skill roots, disables foreign configuration discovery, guards setup writes, +preserves unrelated registrations/backups and checks idempotence. Call mode +loads the full skill through native `read_file`, queries all REA names and input +schemas through native `search_tool`, and calls analysis through `use_tool`. +If discovery reports `partial`, the native agent diagnoses REA registration and +retries discovery. No startup-timeout override or fixed readiness delay is used. +A larger Unicode-path fixture exercises native result offloading: the full +retained Evidence is validated against its named schema, then native terminal +queries recover the selected export facts, subject and full artifact digest in +the next model request. This verifies useful artifact recovery without claiming +that every offloaded graph fact enters model context. Native line-number and +truncation envelopes remain in the request artifacts. Use `-- chat` for ordinary +chat, or `REA_VERIFY_RUNTIME_ROOT` for a production-only installed package. +The loopback OpenAI completions/SSE custom model declares a one-million-token +context and synthetic usage. Live xAI APIs, native Windows and default OS-home +skill discovery remain unverified. + +`verify:commandcode-client` requires installed Command Code (verified with npm +1.79.2); select it with `REA_VERIFY_COMMANDCODE_COMMAND`. Auth, MCP tokens and +sessions use the actual OS home, so provision a disposable POSIX account rather +than overriding `HOME`. Set `REA_VERIFY_COMMANDCODE_ACCOUNT_HOME` to that account's +actual home and create `.rea-client-verification` there with exactly +`Disposable REA client verification account` followed by a newline. The lane +owns that account's `.commandcode` configuration and shared REA skill. Build the +runtime as the checkout owner, then run `node scripts/verify-commandcode-client.mjs` +as the disposable account; the npm shortcut also needs a writable checkout. +The verifier does not create accounts or install clients. It guards setup +targets, preserves an unrelated registration and backups, checks idempotence, +and verifies native default shared-skill discovery and complete activation. +Default deferred-schema delivery stays enabled: the native prompt advertises +every REA tool, exact-name `search_tools` returns every input schema, and a native +shell query recovers the saved catalog's count and digest when the client spills +it. Actual analysis of a Unicode-path fixture delivers full named-schema Evidence +to the next model request. Use `-- chat` for ordinary chat or +`REA_VERIFY_RUNTIME_ROOT` for a production-only installed package. The loopback +OpenAI completions/SSE model is a keyless BYOK endpoint declaring a million-token +context with synthetic usage. A synthetic account-key value satisfies the +client's print-mode gate; native local-only mode refuses hosted API calls. +Updates, telemetry and cron are disabled. Hosted authentication, live models +and Windows remain unverified. + +`verify:omp-client` requires installed OMP (verified with the official Linux x64 +18.8.7 binary); select it with `REA_VERIFY_OMP_COMMAND`. This optional POSIX lane +isolates the default agent, global config and XDG roots, guards setup targets, +preserves unrelated registrations and backups, and checks idempotence. It +compares native rejection of an invalid profile with REA's refusal to plan +fallback writes. OMP's default `xd://` interface mounts the complete REA catalog +as devices: call mode reads the complete installed skill and tool documentation, +then dispatches analysis through native `write`. It checks full named-schema +JavaScript Evidence with a Unicode path in the next model request. Device +metadata and documentation are distinct from forwarding all JSON schemas as +model functions. Native print-mode MCP readiness uses its defaults. +Use `-- chat` for ordinary chat or `REA_VERIFY_RUNTIME_ROOT` for a production-only +installed package. The loopback OpenAI completions/SSE model fixture declares a +one-million-token context and synthetic usage. Live model APIs, native Windows, +named-profile native execution and default OS-home skill discovery are +unverified; skill discovery uses an explicit isolated custom directory. + +`verify:deepseek-client` requires an installed DeepSeek Harness (`dsh`; +verified with `@deepseek-ai/dsh@0.2.0-rc.2`) and Git. Set +`REA_VERIFY_DEEPSEEK_COMMAND` to select its executable. This optional POSIX lane +seeds caller model settings and a stale Cordis registration in an isolated +`DSH_HOME`, then runs public `setup --client dsh` dry-run, setup, repeated setup, +and scoped doctor. It checks the backup and unrelated patches before booting +Harness with the generated registration. After native execution it uninstalls +through the public CLI and checks that only caller patches remain. `HOME` and +`USERPROFILE` point to the disposable account. The native default +`~/.agents/skills` search path discovers +the installed skill without a `DSH_AGENTS_HOME` override. A separate Git root prevents inherited project skills from +masking a missing installation. The default `call` mode checks skill loading, +complete catalog discovery, the actual forwarded input schemas and regexes, +and full JavaScript Evidence for a Unicode path. Use `-- chat` for ordinary +chat with REA enabled, or `REA_VERIFY_RUNTIME_ROOT` for an installed package. +The fixture uses Harness's custom OpenAI adapter and the one-million-token +context capacity declared by its default DeepSeek Flash model; it does not +establish live DeepSeek API or native Windows coverage. Receipts include +request artifacts, result digests and owned-process lineage. + +The DSH acceptance journey also exercises public setup, approval, doctor, +generated-launcher MCP startup and uninstall without an installed Harness. +That journey proves REA workflow behavior, not native Cordis expression +evaluation. Filesystem regressions retain tagged values and unrelated rows +across alias dependencies and check refusal of unsafe YAML without mutation. + +Full E2E tests invoke the production command dispatcher and real providers, +without fake launchers, runners or responses. `verify:keyed-archive` writes +Foundation binary, XML, and integer archives using one run-owned Swift module +cache. It checks CLI and separate stdio MCP parity, pagination, escaping-path +rejection, an XML graph golden, and numeric meaning for safe controls, unsafe +integers, boxed numbers, and integral-valued reals. `verify:asset-catalog` +compiles source-owned colors with +`actool`, invokes real `assetutil`, then checks CLI/MCP results, exact catalog +digest, every raw metadata field, pagination and malformed input rejection. +Neither artifact workflow requires Hopper or launches it. Both run in macOS CI. +`verify:macos-bundle` needs only macOS with Command Line Tools. It compiles a +source-owned app with `clang`: a versioned framework, XPC services, an app +extension, a login item, a privileged helper, launchd plists, and a helper tool, +signed ad hoc. It packs the app as a directory, a `ditto` ZIP, and an APFS DMG, +then checks that `inspect-artifact` plus `project-apple-application-graph` +report the same bundle anatomy for all three through the CLI, with stdio MCP +parity. It also checks that the DMG is detached afterwards. The same app +covers `trace-dylib-resolution`: + +- each resolution status and finding, with CLI/MCP parity; +- for every traced image, dependencies, rpaths, and install names equal to + `otool -l`; +- for the main executable and an XPC service, a predicted load order equal to + the images dyld actually loads under `DYLD_PRINT_LIBRARIES`. + +The lane also compiles executable/library pairs with empty embedded directory, +versioned-path, and suffix settings. It checks present and removed dependencies +through CLI and MCP, and compares actual `DYLD_PRINT_SEARCHING` diagnostics for +root-level candidates. These cases distinguish an empty search directory from +an empty versioned scan or a suffix that only repeats the original path. + +It runs in macOS CI. + +Prepare the native inspector before cases that measure producer output or exit +behavior; keep startup deadlines and cancellation in distinct cases. Run real +process-capture verification separately from package or build checks. On macOS, +new npm processes can become token-unreadable after changing their display +title and prevent verified cleanup during a capture's ownership sweep. + +MCP SDK transport tests with recording providers remain integration tests. +They are useful for schema drift and failure projection but do not prove that +Hopper, Ghidra or another substituted engine works. `verify:package` proves +packaging/install behavior and fake-provider integration; use the corresponding +real-provider lanes for engine claims. Packed-bridge checks verify shipped files and Python syntax. +Real Apple dispatch and Interface +Builder verifiers currently prove format integration through production readers. + +`verify:hopper` exercises an installed Hopper through the production stdio MCP +server and CLI. It checks source-owned call chains, CFG edges, references and +complete large inventories, then probes unnamed bookmarks, annotation clearing, +batch validation before mutation, malformed addresses and regexes, segment-end +partial reads, and synthetic file-offset rejection. Advertised schemas are +validated in their JSON Schema dialect and successful replies are checked against +their advertised output schemas. Navigation checks cover interior-object cursor +readback and mapped-memory boundaries. Annotation probes verify invalid native +text and duplicate destinations/names before mutation, preserve unselected label +owners, and exercise explicit batch label swaps. Function locals retain observed +names and stack displacements. Graph probes check symbol/interior-address parity +and a source-owned recursive cycle; literal tracing preserves complete queries +and whitespace. Disposable binary copies prove that switching and closing +actually removes the native document, and that CLI byte, function-dossier, +literal-trace results and invalid-address diagnostics agree with MCP. +No provider is mocked in this lane. +Real search probes cover Unicode names, literal metacharacters, case and regex +modes, annotation cache invalidation, complete native fragments of long literals +checked against byte reads, escaped UTF-8/control text, byte-preserving Latin-1 +decoding, and Hopper's UTF-16 symbol-name truncation boundary. It verifies native +CallReference classifications across reference and dossier results, retains long +string fragment metadata in dossiers, and exercises pathological regex deadline +and cancellation followed by successful requests in the same native session. When the macOS +Objective-C fixture is present, the lane also verifies native UTF-16 string objects +and their inferred encodings against their actual bytes. Native terminal calls +are checked across reference, instruction, assembly, block-range and procedure-length +projections; block endpoints are normalized using actual native membership. +Exact Objective-C names also exercise named CLI selectors for function, instruction, +decompilation, reference and search operations. A literal `--help` trace query proves +that selector data is preserved independently of global CLI flags. +Unmapped annotation destinations and +oversized later batch names fail before any earlier edit is applied. + +`verify:hopper:deadlines` checks the native client's optional request deadlines +on macOS with an owned source-built fixture. Zero and elapsed deadlines must +leave native comments unchanged, including when a synchronous progress observer +delays timer dispatch. It also observes a short analysis deadline and verifies +subsequent wire recovery and clean shutdown. Caller timeout does not interrupt +Hopper's synchronous native operation. Socket boundary tests deterministically +cover active and queued expiry, late replies and timer cleanup. + +The Linux demo lane remains a separate `verify:hopper:linux` command. Its +lifecycle checks attempt competing CLI launches for the active target and a +different target, requiring rejection before either can change the owning +MCP session's documents or procedures. Lease boundary tests also preserve +unresponsive or malformed live endpoints while allowing confirmed stale +sockets to recover. + +`verify:hopper:fat` is a separate macOS lane requiring installed Hopper and the +existing Xcode clang/lipo toolchain. It compiles arm64/x86-64 thin executables and +one- and two-slice FAT32 containers, verifies exact/interior address mappings +against bytes in the original files, checks CLI/MCP parity, and checks owned +runtime cleanup. Source byte changes, removal, permission denial (for non-root +callers), and nonregular replacement must retain native partial mapping facts, +reject unverified original-file coordinates, +and recover after restoration. Single-slice FAT cases also relocate the slice +without changing its loaded bytes. `verify:hopper:fat64` additionally checks +FAT64 preparation through Hopper's native Mach-O loader, source-container +mappings, profile identity, +malformed and ambiguous slice rejection, and temporary-image lifetime. Both +lanes have been verified on Hopper 6.1.0-demo; this establishes REA's prepared +FAT64 workflow, not native FAT64-loader support. +Cross-architecture fixture compilation is not required by `verify:hopper`. + +Golden tests use immutable captured text inputs with producer/source provenance +under `tests/fixtures/golden/`. Expected results are reviewed for the semantic +claim; capture commands do not automatically approve new expected outputs. +Do not call handcrafted utility output or synthetic binary builders real-data +goldens. Keep unsupported binary layouts and malformed boundaries as targeted +regressions until a real fixture establishes equivalent coverage. + +`verify:browser` exercises source-map failure isolation and expanded-output limits through the compiled CLI and stdio MCP with real Chrome. It also submits five 2 MiB source-map annotations, checks retained script identities and explicit map omissions, and closes its owned fixture target. Replacement and document-reset behavior has separate producer-boundary coverage. + +The raw Chrome fixture launchers use `--password-store=basic` so Linux startup +does not wait for an unlock prompt from a reachable but locked desktop keyring. +Such a stall leaves the initial page unloaded with empty or placeholder CDP URLs; +it does not establish permission to capture that page. See +[the keyring diagnosis](https://github.com/morluto/rea/issues/1384#issuecomment-6093781686). + +`verify:browser` also captures a source-owned noise canvas as a real PNG above +8 MiB through the CLI and stdio MCP, with complete byte/digest parity and real PNG +decoding. Its SDK client explicitly permits the larger inline JSON response; +this lane does not establish large image-comparison request transport coverage. + +The scenario checks read locale, timezone, device scale and viewport dimensions +from actual page JavaScript through CLI and stdio MCP DOM captures. They also +verify that attached-page emulation is released after success, initialization +failure, action failure and cancellation while the external target stays open. + +`verify:browser:network` is a focused real-browser lane for transaction identity, +selected request/response bytes, binary and compressed responses, duplicate +headers, credential and declared-secret redaction, redirects, streaming cutoff, +CLI/MCP parity, and owned-profile cleanup. Set `REA_BROWSER_EXECUTABLE` to an +installed Chrome-family browser. An optional script argument selects an already +installed package's `scripts/rea.mjs` entry point for packaged-artifact checks. +The complete `verify:browser` lane includes these same checks. + +After building, `verify:browser:dom` checks empty and HTML-whitespace form +destinations against a native Chrome DOM-property oracle through CLI and stdio +MCP. It requires `REA_BROWSER_EXECUTABLE` and accepts an optional installed REA +entrypoint. The full browser lane includes the same public-adapter assertions +before other fixtures navigate the selected page. + +`verify:browser:scripts` checks active script capture → exact-byte export → +existing static JavaScript analysis through CLI and stdio MCP, including +manifest readback, competing query variants, and resolved relative imports. +It uses an installed browser and accepts an optional installed REA entrypoint. +The complete `verify:browser` lane also exercises passive script export through +both public adapters. See [website script export](website-script-export.md). + +`verify:browser:modules` compares CLI and stdio MCP traces against an independent +real Chromium module-loading fixture: import-map scopes, package prefixes, +null/backtracking rejection, query/fragment identities, repeated module instances, +lazy and computed unknowns, exact source/map identities and no implicit refetch. +Set `REA_BROWSER_EXECUTABLE`; the optional script argument selects an installed +package entrypoint. The complete `verify:browser` lane and existing conditional +Chrome CI include this verifier. See [module relationships](website-module-trace.md). + +## Agent evaluation and conformance records + +Evaluate native, JavaScript, managed and browser investigation tasks through a +real local Codex CLI with: + +```bash +npm run verify:agent +``` + +The lane runs scenarios sequentially in standalone Codex (`--no-daemon`) with a +disposable HOME and CODEX_HOME under `~/.cache/rea-agent-evaluations/`. Set +`REA_AGENT_EVAL_ROOT` to choose another parent directory outside the OS temporary +directory: current Codex refuses helper aliases under `/tmp`, preventing shell +commands and skill reads even if MCP works. Each owned run directory is removed +after verification unless fixture retention is requested. The lane +installs the packaged skill and MCP registration through public `rea setup`, +rather than copying a skill into a project that also inherits the caller's +skills and configuration. Only authentication is copied, when present, and it +is removed even with `REA_AGENT_EVAL_KEEP_FIXTURES=true`. No user configuration, +rules, plugins or history is copied; shell snapshots and additional agents are +disabled. Existing API-key environment authentication remains available. +The native missing-provider scenario preapproves only `open_binary` and +`close_binary` in the disposable client so it reaches REA's actual provider +boundary instead of stopping at Codex approval. This does not validate a real +native engine or authorize arbitrary runtime execution. + +Select a smaller run with `REA_AGENT_EVAL_SCENARIOS`, a comma-separated list of +scenario IDs. `asar-zh` exercises the packaged desktop rubric from a Chinese +request. `javascript-module-view` exercises summary analysis, module paging and +item inspection in a tree with unrelated modules; its routing and text checks +remain heuristic, so review the retained transcript for selector choice and +coverage claims. Set `REA_CODEX_CLI` to an installed Codex executable and +`REA_AGENT_EVAL_MODEL` to an account-supported model. Use an external resource +limit for the whole process tree when testing on a constrained host; a Node +heap limit alone does not bound client and child-process memory. + +`missing-target` leaves desktop fixtures visible without selecting one in the +request. It requires zero REA calls and a structured request for an app name or +artifact path. Its `expectedFirstTool` is `null`, and +`targetClarificationPassed` grades that limited routing outcome independently +of analysis prose heuristics. Analyzing a nearby example cannot pass this case. + +The packaged desktop and parser-comparison scenarios now assess a closed set of +known fixture claims. Each final answer must be a strict JSON manifest containing +exactly the requested claim IDs, values, Evidence IDs, and Evidence authority and +confidence. Golden values are not included in the prompt. The evaluator checks +exact values against both the fixture oracle and authenticated successful REA +results; an Evidence ID by itself is insufficient. Missing, duplicate, extra, +contradictory, incorrectly sourced, or unsupported claims fail the scenario. + +The desktop rubric covers the exposed bridge API and members, renderer and main +IPC operations, and the resolved preload. It binds its Evidence to the exact +packaged artifact path and SHA-256. The parser rubric checks the precise heading +depth addition, discriminant, complete comparison counts, and the explicit limit +on runtime semantics. Its comparison must link to the two delivered source +analyses and use the requested module and export selectors. Boundary tests package +the same source-owned desktop fixture and compare the same source-owned parser +files through actual MCP tool results, then verify that fabricated answers fail. + +Per-scenario `factualCorrectness` is `passed`, `failed`, or `not_assessed` within +the `configured_fixture_claims` scope. A pass establishes only the configured +claims, not unrestricted factual correctness. Native, managed, browser, +navigation-context, and address-context scenarios have no factual rubric and +remain `not_assessed`; the managed workflow requires both artifact and member +inspection to answer its type and entry-point question. + +The closed factual scenarios request complete producer Evidence on the initial +analysis so their source selectors can authenticate all configured facts. +Summary/page/item workflows are exercised separately by `javascript-module-view`; +its heuristic gate does not establish full-producer factual correctness. + +All scenarios retain routing, workflow, validation, repetition, process-exit, +and token-use gates. Configured factual scenarios additionally require a factual +pass. Their answer-text heuristics are diagnostic and do not affect the gate. +Validation counts include complete text-only REA `invalid_request` envelopes +and failed SDK calls whose arguments violate the named current REA contract. +Client approval rejections and provider unavailability remain distinct failures; +truncated JSON previews are not parsed into invented error codes. +Repeated `binary_session` observations separated by a successful `open_binary` +or `close_binary` are treated as lifecycle verification. An unchanged retry, +including one after a failed lifecycle call, still counts as repetition. +Scenarios without a rubric retain the legacy text-heuristic gate. +`answerTermCoverageMet` checks case-insensitive substrings, +`epistemicCuePresent` checks keywords, and `finalCitesEvidence` checks only an ID's +presence. These metrics can still accept fabricated prose and must not be read +as factual assessments. Set `REA_AGENT_EVAL_TRANSCRIPT_DIR` to retain complete +tool results and final answers for review. + +Report schema version 4 adds negative routing scenarios with nullable +`expectedFirstTool` and a `targetClarificationPassed` outcome. Consumers must +allow an expected absence of REA calls; this does not make an analysis scenario +pass without its required tools. Version 3 changed the top-level +`factualCorrectness` from a constant +string to an assessment summary with status, scope, and assessed/passed/failed/ +not-assessed scenario counts. Scenario records include the factual assessment and +configured claim IDs. The evaluation scope is +`routing_workflow_and_configured_fixture_claims`. Update report consumers for +these changes. The narrower heuristic field names introduced in version 2 remain: +`answerHeuristicsMet`, `epistemicCuePresent`, `answerTermCoverageMet`, and +`requiredAnswerTermGroups`. + +Regenerate the managed conformance manifest and Evidence completion ledger from +live verification results, or check them for drift: + +```bash +npm run evidence:generate +npm run evidence:check +``` + +The records preserve unsupported and unverified coverage as explicit unknowns. +Run the matching real-tool prerequisites described in this guide. diff --git a/docs/ghidra-dos.md b/docs/ghidra-dos.md index 808303681..487899bb7 100644 --- a/docs/ghidra-dos.md +++ b/docs/ghidra-dos.md @@ -130,8 +130,9 @@ range's file offset and analysis address; it does not locate the first differing byte inside that range. Mapping ends are **inclusive**, unlike the exclusive ends from `list_segments`. Appended overlays remain in source-file identity and are excluded from initialized module coverage. Uninitialized allocations are reported; -their contents and DOS runtime semantics are not verified. Formats other than MZ and explicit COM return -`unsupported` with measured observations, not a successful MZ verification. +their contents and DOS runtime semantics are not verified. Independent verification +also covers explicit [raw-binary imports](raw-binary.md); other formats return +`unsupported` with measured observations. `read_bytes` returns initialized provider memory, including loader fixups; an unmapped or uninitialized byte ends the read with an explicit returned length and @@ -150,8 +151,10 @@ For a packed executable, importing the original can analyze its unpacking stub. Analyze a separately prepared unpacked copy to inspect the original program's recovered code. Retain both artifact digests and the transformation evidence; REA never silently replaces the admitted target. Appended overlays -are separate from the initialized MZ module. Raw COM files and DOS extenders -without an admitted MZ real-mode entry are outside this import boundary. +are separate from the initialized MZ module. Headerless COM requires the +[explicit COM interpretation](#headerless-com-images); REA does not guess it +from the filename or unrecognized bytes. DOS extenders without an admitted +MZ real-mode entry remain outside this import boundary. DOS MZ is available through Ghidra, with no Hopper support claim. It is outside the Windows native PE P0 boundary. macOS x64 DOS verification remains unverified. diff --git a/docs/index.md b/docs/index.md index 17fed2a95..732ad9f05 100644 --- a/docs/index.md +++ b/docs/index.md @@ -45,4 +45,24 @@ See [installation and setup](./installation.md) for requirements and configurati For runtime instrumentation, see the [Frida guide](./frida-instrumentation.md). +## Choose a guide + +| Task | Guides | +| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Inspect native functions, references, or types | [Native binaries](native-investigation.md), [Go metadata](go-binaries.md), [offline ELF layout](binary-diagnostics.md), [recorded crashes](recorded-crashes.md) | +| Select a native provider or import format | [Ghidra semantics](ghidra-provider.md), [Windows](windows-ghidra-p0.md), [DOS](ghidra-dos.md), [raw bytes](raw-binary.md), [MIPS](ghidra-mips.md), [PSP](ghidra-psp.md), [NativeAOT](ghidra-nativeaot.md), [IDA](ida-provider.md), [JEB](jeb-analysis.md) | +| Analyze JavaScript or Electron artifacts | [Static analysis](javascript-artifact-reconstruction.md), [tracing and comparisons](javascript-application-workflows.md), [application graph](javascript-application-graph.md), [source recovery](javascript-recovery.md) | +| Compare static JavaScript with runtime observations | [Runtime attribution](javascript-runtime-observation.md), [reconciliation](javascript-runtime-reconciliation.md), [Electron observation](electron-observation.md) | +| Inspect assemblies, packages, or firmware | [.NET](managed-code-analysis.md), [Android](android-analysis.md), [Apktool resources](apktool-resource-analysis.md), [ADB acquisition](adb-device-analysis.md), [Apple](apple-application-analysis.md), [Harmony](harmony-analysis.md), [firmware](firmware-analysis.md), [WASM](wasm-artifacts.md), [EVM](evm-bytecode.md) | +| Observe or compare a browser scenario | [CDP observation](browser-observation.md), [scenarios](browser-scenario-contract.md), [runtime evidence](web-runtime.md), [historical captures](web-network-captures.md) | +| Trace captured website source | [Source locations](web-source-location.md), [module traces](website-module-trace.md), [script export](website-script-export.md) | +| Capture and compare a command | [Process capture](process-capture.md) | +| Use CLI/MCP and retain evidence | [CLI](cli.md), [MCP contracts](mcp-contracts.md), [agent prompts](mcp-prompts.md), [obligation ledgers](reconstruction-obligation-ledgers.md) | + +For development, use [testing](testing.md), [client verification](client-verification.md), +[tool design](tool-design.md), and [releasing](releasing.md). +[Reconstruction readiness](reconstruction-readiness.md) describes a development +conformance verifier. [The 6.2 migration](migration-6.2.md) records that release's +compatibility changes; [the roadmap](roadmap.md) tracks future work. + ![REA inspecting a native binary in Hopper](./assets/rea-hopper-analysis.png) diff --git a/docs/installation.md b/docs/installation.md index 1df0a7479..181b75c92 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,84 +1,199 @@ # Installation and setup -REA separates installing its CLI from configuring external software and agents. +Run REA, connect your selected agents, and check the tools needed for your task. +Setup previews configuration changes and asks for approval before applying them. + +| Task | Section | +| --------------------------------- | ------------------------------------------------------------------------- | +| Connect an agent | [Start setup](#start-setup), then [review changes](#review-setup-changes) | +| Diagnose one task | [Scoped readiness checks](#check-readiness-for-your-task) | +| Configure an analysis engine | [Hopper](#hopper), [Ghidra](#ghidra), or the [IDA guide](ida-provider.md) | +| Update or remove REA | [Maintenance](#diagnose-update-and-remove) | +| Resolve a client-specific problem | [Client configuration](client-configuration.md) | ## Start setup -Start setup with: - ```bash npx rea-agents setup ``` -If npm asks to download and run REA, that approval applies only to downloading -the package. REA shows its own plan and asks before changing agent configuration -or installing Hopper. +Choose the agents to configure, review the proposed paths and changes, and +approve the plan. npm's package-download approval and REA's setup approval are +separate. Setup asks before changing agent configuration or installing Hopper. +Restart the agents named in the completion message. -The short command can use a REA version installed in the current project. To -request the latest release explicitly, use: +For the latest published release, use `npx rea-agents@latest setup`. +[Package-runner and global-installation options](#package-runners-and-global-installation) +cover explicit versions, Bun, runtime requirements, and the curl wrapper. + +## Review setup changes + +`rea setup` first offers the supported agents in a multi-select. Existing REA +registrations are selected by default. Newly detected clients remain available +but unselected: detection gives setup context, not permission to add a new +registration. Clients without a detected configuration can still be selected. +Explicit `--client` flags skip this question. + +Setup adds MCP access for selected clients. It installs REA's bundled workflow +with those integrations by default; use `--skill=false` to omit it. If no agent +is selected, setup offers the workflow separately for CLI use, with No as the +default. Hopper is a separate optional choice: setup shows its proposed +installation or connection and requires its own explicit approval. It can also +save verified paths for an existing Ghidra installation. + +After selection, review the plan's exact paths and changes and approve before +REA writes files or installs Hopper. You can cancel at any prompt. + +Before applying changes, REA checks your current configuration. The plan lists: + +- an existing Hopper installation, a verified existing Ghidra installation, or the official Hopper package it proposes to install; +- each detected agent configuration path; +- each selected REA skill destination; +- external software, network origins, integrity evidence, and package-manager + commands. + +Malformed or unsafe existing configuration blocks the whole transaction before +Hopper installation or any file write. Declining or pressing Ctrl-C makes no +changes. Agent configuration writes preserve unrelated entries and comments, +create backups, use atomic replacement, and verify their result. Setup and +uninstall retain an existing `.rea.backup` rather than replacing the first snapshot. +Setup also retains valid environment overrides in REA's existing server entry, +such as `REA_MCP_INPUT_SCHEMA_PROFILE` and `REA_MCP_MAX_RESPONSE_BYTES`. +Detected provider settings replace only matching environment keys. +Setup and doctor report a malformed REA environment map or invalid runtime +setting before setup writes files. Repair the named setting in the client +configuration; setup does not silently discard the rest of the map. + +After setup, REA reports which agents, analysis tools, and workflow files passed +its final checks. Restart any agent named in the completion message, then begin +your investigation. Failed steps and diagnostics remain in terminal history. + +Select exact clients in scripts with repeatable `--client` flags. Each explicit +client skips interactive selection. Use `--all-detected` only when you intend +to configure every detected supported client. `--skill=false` omits the +workflow, and `--dry-run` returns a read-only plan with status `planned` and +exit code 0: ```bash -npx rea-agents@latest setup +rea setup --client codex --client cursor --skill=false --dry-run ``` -REA runs the version npm selects. To update older agent registrations, run the -latest-version command and review its setup plan. For unattended package -downloads, add `--yes` before the package name; this does not approve REA's -setup changes. +Prompt UI and progress are written to stderr so stdout remains available for +structured results and pipelines. `NO_COLOR=1` disables color. Use +`--accessible` for sequential, vertically rendered yes/no prompts. Implicit +interactive setup requires stdin, stdout, and stderr to all be terminals; when +any stream is redirected, setup stays non-interactive. Declining or cancelling +returns status `cancelled` with exit code 0. -For an intentional rollback, make the package request explicit: +For automation, `rea setup --json` reports the plan and a compact `.doctor` +readiness projection without applying it. Use `rea doctor --json` for full +health diagnostics and canonical tool catalog details. Pair +`--yes` with explicit scope such as `--client codex`, or use +`--all-detected` when the broad scope is intended. Without a scope flag, +`--yes` is limited to existing REA-owned registrations; it does not select all +detected clients. An unapproved actual apply reports `needs_confirmation` and +exits 1. Installing missing Hopper non-interactively additionally requires +`--install-hopper`: ```bash -npm exec --yes --package=rea-agents@2.4.0 -- rea setup +rea setup --yes --all-detected --install-hopper --json ``` -Setup continues to pin persistent MCP registrations to the exact version that -performed setup. Running current setup later migrates unversioned or older -managed registrations through the normal reviewed setup transaction. +### Skill destinations -With Bun, `bunx rea-agents setup` (or `bunx rea-agents@latest setup`) is the -equivalent entry point. Setup run through `npx` registers -`npx -y rea-agents@ mcp`; setup run through `bunx` or `bun x` registers -`bunx rea-agents@ mcp`. On Windows, setup wraps either command in -`cmd.exe /d /c` so clients can start the runner's command shim. Neither -registration points into the runner's temporary package cache. +The bundled skill is installed where each selected client discovers personal +skills: Claude Code uses `~/.claude/skills` (or +`$CLAUDE_CONFIG_DIR/skills` when configured). Gemini CLI uses `.agents/skills` +under its selected home; Antigravity 2.0 uses `~/.gemini/config/skills`. +Other integrations, including Qwen Code, use `~/.agents/skills`. +A mixed selection plans each distinct destination. Selecting the skill without a client uses the shared +directory. Setup leaves existing skill copies in other locations untouched. -REA supports Node.js 22.x (>=22.19), 24.x (>=24.11), and 26+. Node.js 23, 25, and prereleases are unsupported. It uses the npm already paired with that runtime and never upgrades Node.js, npm, or Homebrew. +`rea setup --skill-client claude_code --yes --json` refreshes and verifies the +selected skill destination independently of MCP registration selection. The +final `doctor.scope.skill_clients` records which skill destinations were +checked; `doctor.scope.clients` continues to describe required registrations. +An unselected shared skill does not affect a client-only refresh. -When REA runs on Bun, the `rea doctor` `node` check reports the Bun version and -the Node.js compatibility version Bun declares, and passes when that -compatibility version is in the supported range. Bun does not enforce the V8 -heap flags REA gives its owned helper processes, so Evidence that reports those -limits on Node.js records them as unavailable under Bun. On Windows, the owned -Job Object of each JavaScript helper (source analyzer, source-map codec and HAR -decoder) instead limits its committed memory to that helper's heap budget plus -a 512 MiB reserve for Bun itself, and Evidence reports that limit. This needs -the matching bundled Windows native artifact; an artifact without the control -refuses to start the helper rather than running it unlimited. CI tests Node.js -only. +`doctor --skill --json` verifies the selected copies against the bundled +instructions and references. Consumers should use `identity.skill.state`, +`installed_version`, and `installed_tool_count` for skill readiness. The +obsolete `installed_catalog_digest` field has been removed; current catalog +identity remains available at `identity.catalog`. -Running `npm install rea-agents` without `--global` installs the executable only -in the current project's `node_modules/.bin`; it does not make `rea` available -on the shell `PATH`. Use the setup command above for the guided setup -journey, `npx -y rea-agents@latest` for unattended one-off commands, or install globally -with `npm install --global rea-agents` for a shell-visible `rea` command. +Setup pins package-runner MCP registrations to the exact installed REA version, +installs the matching skill and on-demand references in the same plan, and adds +`startup_timeout_sec = 30` for Codex and Grok Build. -The optional curl wrapper installs only the global npm package: +## Check readiness for your task + +Run `rea doctor` when you need diagnosis. It reads host prerequisites and agent +configuration without changing them. Without options, it audits every detected +registration, the installed skill and optional analysis engines; its overall +`healthy` value can be false while your chosen workflow works. + +Select the part you want to check: + +| Task | Readiness check | +| ----------------------------------- | ------------------------------------------------------------------------ | +| Static JavaScript/Electron analysis | Run `rea analyze-javascript-application PATH --json` directly. | +| One analysis engine | `rea doctor --provider ghidra --json` (or `hopper`, `ida`) | +| One agent registration | `rea doctor --client codex --json` (see [client IDs](#supported-agents)) | +| Installed workflow instructions | `rea doctor --skill --json` | + +A scoped report has `scope.mode: "explicit"`. Its `scope_checks` determine +`healthy` and the exit status. Other checks appear in `informational_checks`; +`environment_healthy` summarizes the full audit. `--target` adds a target check, +but the report remains audit-wide unless a scope option is also supplied. + +Follow the remediation for the failed check. If a native target has several +available providers, choose one with `--provider` on the CLI or `provider_id` +on `open_binary`. A `capability_unavailable` failure carries +`details.selection_reason`: `ambiguous` asks you to choose from +`details.candidate_ids`, while `provider_unavailable` asks you to repair the +selected engine. See [provider selection](cli.md#choose-a-provider). + +## Diagnose, update, and remove + +`rea doctor --json` is strictly read-only. `rea update` updates only the npm or Bun global installation that owns the running CLI. Source checkouts and package-runner copies must be updated through the mechanism that owns them; a fresh package-runner invocation can use `npx rea-agents@latest` or `bunx rea-agents@latest`. `rea uninstall` removes only REA-owned agent registrations and skill files; `--purge-data` additionally removes REA cache and state paths. ```bash -curl -fsSL https://raw.githubusercontent.com/morluto/rea/main/install.sh | bash +rea update +rea uninstall +rea uninstall --purge-data ``` -It prints the version, runtime, npm command, and destination before installing. When a controlling terminal exists it starts `rea setup`; otherwise it prints the command to run later. +Uninstall preserves Hopper, Node.js, Evidence files, captures, unrelated skills +and other MCP servers. Purging removes only REA's cache and state under +`~/.rea`. A client configuration that is malformed, unreadable, or at an unsafe +path stops the operation before anything is removed, and a client that fails +while being updated stops the remaining removals. A purge path that is a +symbolic link is retained and reported rather than followed. Uninstall checks +REA's managed shared and Claude Code personal skill locations. See the +[CLI guide](cli.md#output-and-exit-status) for exit statuses. -Pass options with `bash -s --`: +### Update the owning installation -```bash -curl -fsSL https://raw.githubusercontent.com/morluto/rea/main/install.sh | - bash -s -- --dry-run -``` - -Supported options are `--version `, `--dry-run`, `--no-setup`, `--no-prompt`, and `--verbose`. Neither `--no-prompt` nor a non-interactive shell grants permission to install external dependencies. +`rea update` installs the exact resolved +release into the npm prefix or Bun global directory that owns the running +package, then checks the new executable's version before reporting success. It +does not reopen onboarding. For npm installations, release lookup and +installation both use npm's configured registry. Bun global updates require +Bun 1.2.17 or later, which introduced `bun info`. The updater checks `bun --version` +first and stops with an instruction to upgrade Bun manually if the version is +older or cannot be parsed; it does not upgrade Bun itself. +For supported Bun global installations, `bun info` and +`bun add --global --ignore-scripts` use Bun's configured registry +and run inside the owning Bun global directory (`BUN_INSTALL_GLOBAL_DIR`, else +`$BUN_INSTALL/install/global`, else `$XDG_CACHE_HOME/.bun/install/global`, +else `~/.bun/install/global`), never in the caller's current project. A Bun +global directory without its `package.json` is not treated as an owned +installation, because Bun would install into the nearest ancestor project +instead. +Its maintenance plan selects only existing REA registrations and an already +installed REA skill. Run the returned scoped setup command to review and approve +those changes, then restart affected agents. The plan is returned in terminal, +non-TTY, and JSON modes without applying configuration changes. ## Released package and main @@ -143,8 +258,8 @@ readiness for one task instead of auditing every integration, see ## Supported agents -Setup can configure these clients for REA's local MCP server. Grok Bot is -listed after the table because its connector is not one of these files: +Setup can configure these clients for REA's local MCP server. Grok Bot uses a manual +hosted connector; see [its configuration](client-configuration.md#other-client-settings). | Client | `--client` value | | ------------------ | ---------------- | @@ -170,351 +285,16 @@ listed after the table because its connector is not one of these files: `dsh` is main-only until a release after 6.4.0. The registry check above does not cover it. -For GitHub Copilot CLI 1.0.95, `gpt-4.1` model metadata can block ordinary -chat with REA's full input-schema profile before sending a model request -(`compaction_static_context_blocked`; [#1554](https://github.com/morluto/rea/issues/1554)). -For the native offline OpenAI-compatible BYOK adapter, full-profile chat and -analysis also passed with a distinct `COPILOT_PROVIDER_MODEL_ID` such as -`rea-gpt-4.1`, `COPILOT_PROVIDER_WIRE_MODEL=gpt-4.1`, and that distinct ID selected -through `copilot --model rea-gpt-4.1`. The local fixture requested -`COPILOT_PROVIDER_MAX_PROMPT_TOKENS=1000000`; configure the limit supported by -your backend. This keeps every full schema and the actual wire model intact. -It does not establish the effective client budget or fix the built-in-ID path. -The existing compact profile passed native chat and analysis with the complete -tool inventory on Linux using a loopback model fixture. After setup, add -`"REA_MCP_INPUT_SCHEMA_PROFILE": "compact"` to the `env` object of the -`mcpServers.rea` entry in Copilot's `mcp-config.json`, preserving its other -settings, then restart the client. Compact advertisements can reduce nested -schema constraints; REA still validates complete canonical inputs. Full-profile -`gpt-5.4` metadata is also verified locally. Live model API acceptance and -Windows remain unverified; see [native client verification](testing.md). - -Claude Code normally defers MCP tool definitions through tool search. It -[turns tool search off](https://code.claude.com/docs/en/mcp#configure-tool-search) -when `ANTHROPIC_BASE_URL` points to a non-first-party host, such as DeepSeek's -Anthropic-compatible endpoint. It then sends every REA tool's name, description -and input schema with every request -([#2019](https://github.com/morluto/rea/issues/2019)). On main at 04089d5be, -with 172 tools, that payload measured about 496 KB with the default profile and -about 290 KB with `compact`. By the o200k and cl100k tokenizers, that is roughly -120k and 68k tokens. Compaction cannot remove tool definitions. If they nearly -fill the window Claude Code assumes, the context refills after every compaction -and Claude Code reports that autocompact is thrashing. To avoid this: - -- Make Claude Code assume the model's actual context window. DeepSeek's Claude - Code guide selects `deepseek-flash[1m]`; the `[1m]` suffix makes Claude Code - assume a one-million-token window. For other unrecognized model IDs, set - `CLAUDE_CODE_MAX_CONTEXT_TOKENS` to the window the provider documents. -- If the endpoint forwards `tool_reference` blocks, set `ENABLE_TOOL_SEARCH=true` - to restore deferred loading. DeepSeek's Anthropic API guide does not list - `tool_reference` among its supported content blocks, so this setting may cause - its requests to fail. -- To shrink the upfront catalog, add - `"REA_MCP_INPUT_SCHEMA_PROFILE": "compact"` to the `env` object of the - `mcpServers.rea` entry in `~/.claude.json` (`$CLAUDE_CONFIG_DIR/.claude.json` - when that variable is set), then restart Claude Code. Setup keeps this - override. - -The sizes above come from REA's own `tools/list`. A live Claude Code session -against DeepSeek's API is unverified. - -For [Pi](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/mcp.md), -setup writes a `type: "stdio"` entry under `mcpServers.rea` in the user-level -`~/.pi/agent/mcp.json` and installs the bundled skill under `~/.agents/skills`. -Use `rea setup --client pi --dry-run --json` to inspect the plan, then -`rea setup --client pi --yes --json` to approve it. Check the registration with -`rea doctor --client pi --json`. Pi reads `mcp.json` as strict JSON, like its -own loader: comments, trailing commas, a byte-order mark, or an empty existing -file are invalid, and setup reports them instead of rewriting the file. Repair -such a file to plain JSON first, then rerun setup. - -Setup follows Pi's `PI_CODING_AGENT_DIR`: unset or empty selects the default; -`~` and `~/` expand to the home directory; absolute paths and file URLs select -that directory; relative paths stay relative to the command's working directory. -On Windows, native paths, `~\`, and Git Bash/MSYS, Cygwin, and WSL drive paths -are normalized as Pi does. Run REA and Pi from the same working directory when -using a relative override. Pi has no profiles: `OMP_PROFILE`, `PI_PROFILE`, -`PI_CONFIG_DIR`, and OMP's `enabledServers`/`disabledServers` lists do not affect -Pi registration. Doctor accepts an omitted `type` for stdio but reports a -non-stdio type as invalid; `enabled: false` stays disabled. - -REA configures only the user scope. Pi also reads `.pi/mcp.json` in trusted -projects; a same-name project entry can replace the user entry or override its -enabled state and exposure. Check that file if the user registration is aligned -but unavailable in a project. An extension that registers `/mcp` can replace -Pi's built-in MCP support and use its own configuration instead. Run `/reload` -in an existing Pi session after changing servers outside the session. - -For Qwen Code, setup registers `rea` in the `mcpServers` table of the -user-level `~/.qwen/settings.json`, or `$QWEN_HOME/settings.json` when configured. -Setup and doctor follow Qwen Code's tilde and working-directory-relative home -overrides. Qwen Code also discovers personal skills in `~/.agents/skills`, -where setup installs the bundled workflow. - -Gemini CLI uses `$GEMINI_CLI_HOME/.gemini/settings.json` when that home override -is nonempty, including its shared personal skills at -`$GEMINI_CLI_HOME/.agents/skills`. Setup and doctor check MCP allow/exclude -policies from system defaults, user settings, trusted workspace settings, and -system overrides. Workspace trust follows `GEMINI_CLI_TRUST_WORKSPACE`, -`GEMINI_RESTRICTED_MODE`, the effective `security.folderTrust.enabled` setting, -and the selected `trustedFolders.json` (including -`GEMINI_CLI_TRUSTED_FOLDERS_PATH`). Settings in an untrusted workspace do not -participate. A workspace or system `mcpServers.rea` replaces the entire user -entry; setup stops if the winning definition conflicts with its planned entry. -Review those files manually: setup never edits administrator/workspace settings -or grants workspace trust. Trust supplied only by a running IDE is outside this -standalone CLI check. - -Codex treats an unset or empty `CODEX_HOME` as `~/.codex`. Devin honors -`XDG_CONFIG_HOME` for its `devin/mcp_config.json` on non-Windows systems. - -For OMP, setup writes a `type: "stdio"` entry to the user-level -`~/.omp/agent/mcp.json`. It follows `PI_CONFIG_DIR` and -`PI_CODING_AGENT_DIR` (relative to the setup working directory), and the profile selected by `OMP_PROFILE` or -`PI_PROFILE` (`~/.omp/profiles//agent/mcp.json`). Setup also removes -`rea` from that file's `disabledServers` list, which would otherwise hide the -registration. Doctor treats an `enabled: false` entry as active when -`enabledServers` lists `rea`, as OMP does, unless `disabledServers` also lists -it. Run setup under each profile that should load REA. - -For Hermes, setup writes a `mcp_servers.rea` entry to `config.yaml`, preserving -comments and unrelated settings. It resolves that file from `HERMES_HOME`, else -from the platform default Hermes itself uses — `%LOCALAPPDATA%\hermes` on -Windows, `~/.hermes` elsewhere — including any `HERMES_DATA_DIR_SUFFIX`. Hermes -connects an entry unless `enabled` is false, so setup states `enabled: true`. - -Hermes personal skills install under the active Hermes home's `skills` directory. -Setup, doctor and uninstall follow the root's `active_profile` selection, as -plain Hermes CLI commands do. An explicit `HERMES_HOME` pointing to -`profiles/` selects that named profile directly. An invalid, missing or -deleted sticky profile is reported instead of writing into the default home; -repair the profile or run `hermes profile use default` before retrying. -REA follows `HERMES_HOME` whitespace trimming, environment-variable expansion, -and home expansion before resolving that profile. Setup previews the resolved -configuration and skill destinations; doctor and uninstall use those same paths. +See [client configuration and troubleshooting](client-configuration.md) for +configuration paths, profiles, trust policies, and schema-limit workarounds. ### DeepSeek Harness -DeepSeek Harness registers MCP clients through a Cordis YAML patch sequence -rather than a `mcpServers` object. `rea setup --client dsh` appends (or -replaces) the REA entry in the home patch `$DSH_HOME/cordis.patch.yml` -(`~/.dsh/cordis.patch.yml` when `DSH_HOME` is unset), preserving unrelated -patches and comments. `rea doctor --client dsh` checks that same entry id. -`rea uninstall` removes it by scanning supported clients; uninstall takes no -`--client` flag. The home patch applies to every Harness profile, so the -registration is written once and no per-profile edit is needed. The written -entry is: - -```yaml -- insert: - - id: rea-mcp - name: "@deepseek-ai/dsh-mcp-client" - config: - serverName: rea - transport: stdio - command: /absolute/path/to/node - args: ["/absolute/path/to/rea/scripts/rea.mjs", mcp] -``` - -Setup preserves caller-owned Cordis expressions and replaces launcher fields -with literal values that doctor can verify. It refuses to edit an expression -that produces the entire REA config, or a group-targeted REA insertion. Use a -literal config and a root-level insertion as shown above. - -For a global npm installation, the launcher is under -`$(npm root -g)/rea-agents/scripts/rea.mjs`. Restart Harness after setup; it -exposes tools as `mcp__rea__`. Run `rea setup --skill --dry-run`, -review the destination, then `rea setup --skill --yes` to install the workflow -in `~/.agents/skills` (`$DSH_AGENTS_HOME/skills` when configured); Harness -discovers that directory, and its native `skill` tool can load -`reverse-engineer-anything`. - -REA's optional [native client verification](testing.md#end-to-end-integration-and-golden-evidence) -checks headless chat, skill loading, all tool input schemas and actual analysis -using the installed Harness and a local model fixture. This establishes the -Harness integration, with live DeepSeek API compatibility remaining unverified. -See the [Harness MCP guide](https://github.com/deepseek-ai/deepseek-harness/blob/639ed015397290b3745d163aafe02ffee4aa3f84/packages/mcp/mcp-client/README.md) -for its native configuration contract. +See [the Cordis patch and launcher setup](client-configuration.md#deepseek-harness). ### Other client settings -For OpenCode, setup writes the V1 `mcp.rea` entry, which OpenCode V1 and V2 -both load. If the configuration already uses OpenCode V2's native -`mcp.servers` table, setup registers REA there instead and replaces any earlier -`mcp.rea` entry from REA. Setup honors `OPENCODE_CONFIG_DIR` and -`OPENCODE_CONFIG`, preferring the later-loaded JSONC file when both JSON and -JSONC exist. The ordinary XDG global configuration still participates when a -custom directory is selected. Doctor checks the merged user registration; uninstall removes -REA-owned entries from every applicable user file so an older entry cannot -become active again. Malformed applicable files block setup before changes. - -Grok Build loads `[mcp_servers.rea]` from `$GROK_HOME/config.toml`, or from -`~/.grok/config.toml` when `GROK_HOME` is unset or empty. Setup edits that server -table, `[mcp_servers.rea.env]`, and a root `disabled_mcp_servers` entry that -names `rea`. It sets `startup_timeout_sec = 30` and leaves every other name -in that list. The shared skill installed under `~/.agents/skills` is already -on Grok Build's skill path. - -Grok Bot (`grok_bot`) is detected from `~/.grokbot`, or from `SAND_DATA_ROOT` -when that value is an absolute path. A relative or empty `SAND_DATA_ROOT` -stays on `~/.grokbot`. That directory is not the connector store. Grok Bot -keeps connectors in the signed-in account and runs them on its hosted -computer. It does not import `mcp.json` from the data directory, and it does -not attach a stdio server running on this machine. Setup does not call the -account connector API, does not write a registration file, and does not report -the data directory as aligned. Ask the Grok Bot chat to add a custom MCP -server named `rea` that runs on the Bot's computer: - -```bash -npx -y rea-agents@ mcp -``` - -Do not put credentials in that command or its arguments. `rea doctor --client grok_bot` -reports this manual step. `rea uninstall` does not remove the account connector. - -## Review setup changes - -`rea setup` first offers the supported agents in a multi-select. Existing REA -registrations are selected by default. Newly detected clients remain available -but unselected: detection gives setup context, not permission to add a new -registration. Clients without a detected configuration can still be selected. -Explicit `--client` flags skip this question. - -Setup adds MCP access for selected clients. It installs REA's bundled workflow -with those integrations by default; use `--skill=false` to omit it. If no agent -is selected, setup offers the workflow separately for CLI use, with No as the -default. Hopper is a separate optional choice: setup shows its proposed -installation or connection and requires its own explicit approval. It can also -save verified paths for an existing Ghidra installation. - -The bundled skill is installed where each selected client discovers personal -skills: Claude Code uses `~/.claude/skills` (or -`$CLAUDE_CONFIG_DIR/skills` when configured). Gemini CLI uses `.agents/skills` -under its selected home; Antigravity 2.0 uses `~/.gemini/config/skills`. -Other integrations, including Qwen Code, use `~/.agents/skills`. -A mixed selection plans each distinct destination. Selecting the skill without a client uses the shared -directory. Setup leaves existing skill copies in other locations untouched. - -`rea setup --skill-client claude_code --yes --json` refreshes and verifies the -selected skill destination independently of MCP registration selection. The -final `doctor.scope.skill_clients` records which skill destinations were -checked; `doctor.scope.clients` continues to describe required registrations. -An unselected shared skill does not affect a client-only refresh. - -`doctor --skill --json` verifies the selected copies against the bundled -instructions and references. Consumers should use `identity.skill.state`, -`installed_version`, and `installed_tool_count` for skill readiness. The -obsolete `installed_catalog_digest` field has been removed; current catalog -identity remains available at `identity.catalog`. - -After selection, review the plan's exact paths and changes and approve before -REA writes files or installs Hopper. You can cancel at any prompt. - -Before applying changes, REA checks your current configuration. The plan lists: - -- an existing Hopper installation, a verified existing Ghidra installation, or the official Hopper package it proposes to install; -- each detected agent configuration path; -- each selected REA skill destination; -- external software, network origins, integrity evidence, and package-manager - commands. - -Malformed or unsafe existing configuration blocks the whole transaction before -Hopper installation or any file write. Declining or pressing Ctrl-C makes no -changes. Agent configuration writes preserve unrelated entries and comments, -create backups, use atomic replacement, and verify their result. Setup and -uninstall retain an existing `.rea.backup` rather than replacing the first snapshot. -Setup also retains valid environment overrides in REA's existing server entry, -such as `REA_MCP_INPUT_SCHEMA_PROFILE` and `REA_MCP_MAX_RESPONSE_BYTES`. -Detected provider settings replace only matching environment keys. -Setup and doctor report a malformed REA environment map or invalid runtime -setting before setup writes files. Repair the named setting in the client -configuration; setup does not silently discard the rest of the map. - -After setup, REA reports which agents, analysis tools, and workflow files passed -its final checks. Restart any agent named in the completion message, then begin -your investigation. Failed steps and diagnostics remain in terminal history. - -Select exact clients in scripts with repeatable `--client` flags. Each explicit -client skips interactive selection. Use `--all-detected` only when you intend -to configure every detected supported client. `--skill=false` omits the -workflow, and `--dry-run` returns a read-only plan with status `planned` and -exit code 0: - -```bash -rea setup --client codex --client cursor --skill=false --dry-run -``` - -Prompt UI and progress are written to stderr so stdout remains available for -structured results and pipelines. `NO_COLOR=1` disables color. Use -`--accessible` for sequential, vertically rendered yes/no prompts. Implicit -interactive setup requires stdin, stdout, and stderr to all be terminals; when -any stream is redirected, setup stays non-interactive. Declining or cancelling -returns status `cancelled` with exit code 0. - -For automation, `rea setup --json` reports the plan and a compact `.doctor` -readiness projection without applying it. Use `rea doctor --json` for full -health diagnostics and canonical tool catalog details. Pair -`--yes` with explicit scope such as `--client codex`, or use -`--all-detected` when the broad scope is intended. Without a scope flag, -`--yes` is limited to existing REA-owned registrations; it does not select all -detected clients. An unapproved actual apply reports `needs_confirmation` and -exits 1. Installing missing Hopper non-interactively additionally requires -`--install-hopper`: - -```bash -rea setup --yes --all-detected --install-hopper --json -``` - -Setup pins package-runner MCP registrations to the exact installed REA version, -installs the matching skill and on-demand references in the same plan, and adds -`startup_timeout_sec = 30` for Codex and Grok Build. `rea update` installs the exact resolved -release into the npm prefix or Bun global directory that owns the running -package, then checks the new executable's version before reporting success. It -does not reopen onboarding. For npm installations, release lookup and -installation both use npm's configured registry. Bun global updates require -Bun 1.2.17 or later, which introduced `bun info`. The updater checks `bun --version` -first and stops with an instruction to upgrade Bun manually if the version is -older or cannot be parsed; it does not upgrade Bun itself. -For supported Bun global installations, `bun info` and -`bun add --global --ignore-scripts` use Bun's configured registry -and run inside the owning Bun global directory (`BUN_INSTALL_GLOBAL_DIR`, else -`$BUN_INSTALL/install/global`, else `$XDG_CACHE_HOME/.bun/install/global`, -else `~/.bun/install/global`), never in the caller's current project. A Bun -global directory without its `package.json` is not treated as an owned -installation, because Bun would install into the nearest ancestor project -instead. -Its maintenance plan selects only existing REA registrations and an already -installed REA skill. Run the returned scoped setup command to review and approve -those changes, then restart affected agents. The plan is returned in terminal, -non-TTY, and JSON modes without applying configuration changes. - -## Check readiness for your task - -Run `rea doctor` when you need diagnosis. It reads host prerequisites and agent -configuration without changing them. Without options, it audits every detected -registration, the installed skill and optional analysis engines; its overall -`healthy` value can be false while your chosen workflow works. - -Select the part you want to check: - -| Task | Readiness check | -| ----------------------------------- | ------------------------------------------------------------------------ | -| Static JavaScript/Electron analysis | Run `rea analyze-javascript-application PATH --json` directly. | -| One analysis engine | `rea doctor --provider ghidra --json` (or `hopper`, `ida`) | -| One agent registration | `rea doctor --client codex --json` (see [client IDs](#supported-agents)) | -| Installed workflow instructions | `rea doctor --skill --json` | - -A scoped report has `scope.mode: "explicit"`. Its `scope_checks` determine -`healthy` and the exit status. Other checks appear in `informational_checks`; -`environment_healthy` summarizes the full audit. `--target` adds a target check, -but the report remains audit-wide unless a scope option is also supplied. - -Follow the remediation for the failed check. If a native target has several -available providers, choose one with `--provider` on the CLI or `provider_id` -on `open_binary`. A `capability_unavailable` failure carries -`details.selection_reason`: `ambiguous` asks you to choose from -`details.candidate_ids`, while `provider_unavailable` asks you to repair the -selected engine. See [provider selection](cli.md#choose-a-provider). +See [OpenCode, Grok Build, and Grok Bot settings](client-configuration.md#other-client-settings). ## Hopper @@ -650,29 +430,8 @@ code or signal and bounded output in `details.launcher`. An exit can precede output-stream closure; `output_closed: false` keeps that uncertainty explicit. Later requests retain the known exit instead of reducing it to socket loss. An external GUI's helper exit does not establish that the GUI itself exited. -Cursor navigation returns the observed object start when Hopper snaps an interior -address; adjacent-object navigation rejects unmapped inputs and document ends. -Native API text rejects NUL characters and unpaired Unicode surrogates before -annotation changes. Renames preserve unselected label owners; use a batch with -all affected addresses to move or swap existing labels explicitly. Every rename -destination must be mapped, and native symbol names must fit Hopper's 1024 UTF-16 -code-unit limit. Oversized names fail before any batch edits; bookmarks and -literal string results are not subject to that symbol-name limit. Rename success -requires exact final readback. New bookmarks must point into mapped memory; -existing legacy bookmarks outside it can still be removed. -String results read each native typed object's complete bytes, retain the original -provider display in `provider_value`, and report its encoding, byte length, and -termination. `encoding_status: inferred` distinguishes REA's decoding from an -observed source encoding. Hopper can split long literals into adjacent -unterminated objects; search matches each object's decoded bytes independently. -Undecodable objects retain native display text with `decoding.available: false` -and a reason, so one uncertain object does not block unrelated inspections. -Function dossiers retain this same string evidence. Native call edges retain -Hopper's partial `CallReference` classification and exact endpoints; detailed -reference flags remain unavailable rather than being invented. -Regex searches use ECMAScript Unicode syntax in a cancellable worker with a -five-second matching deadline. Deadline or cancellation stops matching while -leaving the Hopper API available. Literal mode retains Unicode casefold matching. +For cursor navigation, string decoding, symbol-name limits, and regex matching, +see [Hopper analysis behavior](native-investigation.md#hopper-analysis-behavior). Closing or switching a target closes its bound Hopper document, shuts down REA's bridge and removes its temporary socket directory while preserving the Hopper @@ -732,7 +491,8 @@ operations and twelve function-analysis operations. These cover metadata, decompilation, assembly, resolved calls, typed references, xrefs, function dossiers, instructions, recovered data types, measured load mappings, loaded memory bytes, and observed file offsets. Independent load-image attestation -supports DOS MZ and explicitly selected COM; PE returns its measurements with that limitation. +supports DOS MZ, explicitly selected COM, and explicit raw-binary imports; +PE returns measurements with an unsupported attestation status. On Linux and macOS, `annotate_native_function` also edits a function name and/or entry comments atomically and returns refreshed analysis, and `set_address_name` and `set_addresses_names` name a function entry or any other mapped address @@ -982,25 +742,6 @@ read-only operations, digest identity, and runtime cleanup. The separate ordinary user. It requires the built Windows native bundle and an existing Ghidra/JDK installation; neither is inferred from startup alone. -## Diagnose, update, and remove - -`rea doctor --json` is strictly read-only. `rea update` updates only the npm or Bun global installation that owns the running CLI. Source checkouts and package-runner copies must be updated through the mechanism that owns them; a fresh package-runner invocation can use `npx rea-agents@latest` or `bunx rea-agents@latest`. `rea uninstall` removes only REA-owned agent registrations and skill files; `--purge-data` additionally removes REA cache and state paths. - -```bash -rea update -rea uninstall -rea uninstall --purge-data -``` - -Uninstall preserves Hopper, Node.js, Evidence files, captures, unrelated skills -and other MCP servers. Purging removes only REA's cache and state under -`~/.rea`. A client configuration that is malformed, unreadable, or at an unsafe -path stops the operation before anything is removed, and a client that fails -while being updated stops the remaining removals. A purge path that is a -symbolic link is retained and reported rather than followed. Uninstall checks -REA's managed shared and Claude Code personal skill locations. See the -[CLI guide](cli.md#output-and-exit-status) for exit statuses. - ## MCP Registry REA is published in the official MCP Registry as `io.github.morluto/rea`. Registry @@ -1033,3 +774,71 @@ writes the same package-runner shape, or `bunx rea-agents@ mcp` when setup runs through `bunx`, and pins it to the exact version that performed setup. Run current setup to refresh an older registration, then restart the client. + +## Package runners and global installation + +A package-runner invocation can use a REA version installed in the current project. To +request the latest release explicitly, use: + +```bash +npx rea-agents@latest setup +``` + +REA runs the version npm selects. To update older agent registrations, run the +latest-version command and review its setup plan. For unattended package +downloads, add `--yes` before the package name; this does not approve REA's +setup changes. + +For an intentional rollback, make the package request explicit: + +```bash +npm exec --yes --package=rea-agents@2.4.0 -- rea setup +``` + +Setup continues to pin persistent MCP registrations to the exact version that +performed setup. Running current setup later migrates unversioned or older +managed registrations through the normal reviewed setup transaction. + +With Bun, `bunx rea-agents setup` (or `bunx rea-agents@latest setup`) is the +equivalent entry point. Setup run through `npx` registers +`npx -y rea-agents@ mcp`; setup run through `bunx` or `bun x` registers +`bunx rea-agents@ mcp`. On Windows, setup wraps either command in +`cmd.exe /d /c` so clients can start the runner's command shim. Neither +registration points into the runner's temporary package cache. + +REA supports Node.js 22.x (>=22.19), 24.x (>=24.11), and 26+. Node.js 23, 25, and prereleases are unsupported. It uses the npm already paired with that runtime and never upgrades Node.js, npm, or Homebrew. + +When REA runs on Bun, the `rea doctor` `node` check reports the Bun version and +the Node.js compatibility version Bun declares, and passes when that +compatibility version is in the supported range. Bun does not enforce the V8 +heap flags REA gives its owned helper processes, so Evidence that reports those +limits on Node.js records them as unavailable under Bun. On Windows, the owned +Job Object of each JavaScript helper (source analyzer, source-map codec and HAR +decoder) instead limits its committed memory to that helper's heap budget plus +a 512 MiB reserve for Bun itself, and Evidence reports that limit. This needs +the matching bundled Windows native artifact; an artifact without the control +refuses to start the helper rather than running it unlimited. CI tests Node.js +only. + +Running `npm install rea-agents` without `--global` installs the executable only +in the current project's `node_modules/.bin`; it does not make `rea` available +on the shell `PATH`. Use the setup command above for the guided setup +journey, `npx -y rea-agents@latest` for unattended one-off commands, or install globally +with `npm install --global rea-agents` for a shell-visible `rea` command. + +The optional curl wrapper installs only the global npm package: + +```bash +curl -fsSL https://raw.githubusercontent.com/morluto/rea/main/install.sh | bash +``` + +It prints the version, runtime, npm command, and destination before installing. When a controlling terminal exists it starts `rea setup`; otherwise it prints the command to run later. + +Pass options with `bash -s --`: + +```bash +curl -fsSL https://raw.githubusercontent.com/morluto/rea/main/install.sh | + bash -s -- --dry-run +``` + +Supported options are `--version `, `--dry-run`, `--no-setup`, `--no-prompt`, and `--verbose`. Neither `--no-prompt` nor a non-interactive shell grants permission to install external dependencies. diff --git a/docs/javascript-artifact-reconstruction.md b/docs/javascript-artifact-reconstruction.md index b721d829d..090902ff8 100644 --- a/docs/javascript-artifact-reconstruction.md +++ b/docs/javascript-artifact-reconstruction.md @@ -1,19 +1,14 @@ # JavaScript artifact reconstruction -REA can project an operator-supplied Electron/JavaScript application directory -or ASAR into [JavaScript Application Graph](javascript-application-graph.md) -without executing application code. The target-free -`analyze_javascript_application` MCP tool, dedicated -`rea analyze-javascript-application` CLI command, and generic -`rea analyze PATH` directory/ASAR route expose the same application -service and return an Evidence envelope containing the graph and an Electron -boundary summary. +Inspect a local Electron/JavaScript directory or ASAR without executing its code. +`analyze_javascript_application` and the CLI routes below return an Evidence +record with the [application graph](javascript-application-graph.md), static +Electron observations, statistics, limitations, and coverage. -The resulting Evidence can be combined with passive web or Electron capture -Evidence through -[`reconcile_javascript_runtime`](javascript-runtime-reconciliation.md). That -second operation does not rerun static analysis or contact CDP; it preserves -separate static, runtime, and cross-layer inference authorities. +Start with the [public workflow](#public-workflow), select sources when useful, +then [read the analysis](#read-the-analysis). Use [application workflows](javascript-application-workflows.md) +for tracing and comparisons, or [partial recovery](#recover-partial-analysis) +when an operation is interrupted. ## Public workflow @@ -105,141 +100,7 @@ only reduces delivery; source selection reduces text acquisition and analysis. Explicit native provider or snapshot routing rejects `--source-path` rather than ignoring it. -## ASAR integrity - -ASAR inventory checks Electron integrity metadata for embedded archive entries -and supplied `.asar.unpacked` companion files. An integrity failure identifies -the logical path, declared and calculated SHA-256 values, and whether the entry -was unpacked. By default, a mismatch is returned as a failure with its artifact -context. Application analysis can explicitly select `record-and-continue` to -analyze observed bytes while retaining each contradiction's declared and -observed hashes and `observed-untrusted` trust. Such results mark application -graph coverage partial and include every contradicted path in the limitations. -Mismatched nested ASARs stay opaque rather than being expanded. An unpacked -entry whose companion bytes were not supplied remains `unavailable`. - -An unpacked entry whose companion bytes were not supplied remains -`unavailable`. REA continues analyzing embedded JavaScript and records the -missing native/resource bytes as unknown. See [what is reconstructed](#what-is-reconstructed) -for the inventory fields and [MCP integrity handling](mcp-contracts.md#integrity-record-and-continue) -for the tool-result contract. - -## Large results - -Application analysis projects semantic relationships one source file at a time. -After projection, it retains only the lexical module facts and exported return -shapes needed to build application relationships. Full source IR does not stay -resident for every file together. Callable ownership and contained-reference -queries use per-file range indexes, while call sites use exact-range lookups. -Existing node budgets and coverage reporting remain in effect. - -Progress identifies the source file being parsed and projected. Cancellation is -checked between files and throughout result transfer. The owned analyzer can -be stopped while its synchronous parser or semantic extractor is active; -the CLI/MCP process remains available for control requests. - -Graph and Evidence identifiers hash canonical JSON incrementally, without -assembling a single string for the whole graph. The canonical bytes and existing -identifiers remain unchanged. The opt-in regression check is -`npm run verify:javascript:digests`; -it hashes a value larger than the running Node engine's single-string limit. - -Both application CLI routes stream complete JSON and JSONL output in bounded -chunks, including field filters and `--full-output`. They wait for each stdout -write instead of constructing or reparsing a document-sized string. The opt-in -`npm run verify:javascript:output` checks the actual CLI formatting boundary with -a temporary output file larger than the running engine's string limit, verifies -its bytes and digest, and removes it. Use `-- jsonl` for the compact JSONL check. -Each check needs space for one output file plus a 1 GiB free-space reserve. - -Other CLI formats and `--token-count` still assemble whole strings. -Field selection remains useful when the caller needs a -smaller view, for example `--format json --filter-output -evidence_id,normalized_result.statistics`. Streaming output does not bound the -memory needed to construct the analysis graph itself. - -JavaScript source parsing, static analysis and semantic projection run in one -owned analysis process, reused sequentially across files. Target code is never -executed. The analyzer defaults to 1024 MiB of V8 old-space and a 300000 ms -deadline per source, including startup and fact transfer. Select -`max_heap_mb` and `analysis_timeout_ms` through MCP, or `--max-heap-mb` and -`--analysis-timeout-ms` on the dedicated CLI command. These choices control the -analyzer; the caller's `NODE_OPTIONS` still controls the CLI/MCP process heap. -V8 old-space limits do not impose a process RSS limit. When REA runs on Bun, -the analyzer ignores the V8 heap flags; resource failures then report -`worker_heap_limit_bytes` as null instead of a requested or V8-reported limit. -On Windows, the analyzer's owned Job Object instead limits its committed -memory to `max_heap_mb` plus a 512 MiB reserve for Bun itself (1536 MiB by -default). Reaching it fails the current source with the same memory resource -failure and reports `worker_process_memory_limit_bytes`, also a coverage limit; -the next source starts a new analyzer. Bun elsewhere enforces no analyzer limit. - -The default semantic capacities are 100000 nodes across the application and -20000 per source. Large bundles may explicitly select `max_semantic_nodes` and -`max_semantic_nodes_per_file` (CLI: `--max-semantic-nodes` and -`--max-semantic-nodes-per-file`), each from 1 to 1000000. The per-file offer is -also bounded by the remaining application capacity. Raising these controls does -not bypass worker heap, execution deadline or parent result admission. Truncated -coverage reports both effective node ceilings; omitted relationships remain -unknown. - -While sources remain, the sequential worker reserves one next compact static -checkpoint at its 8 MiB bound with the same 6x retention expansion used at -admission. Earlier checkpoints are already charged to retained bytes; the -remaining inventory does not multiply the reserve. Streamed file transfers keep the default 512 MiB -allowance, and can grow with the parent's offered retention budget (8x byte -expansion), up to 2 GiB. Individual records remain bounded to 8 MiB. The parent -still independently checks actual bytes, record overhead, digests and source -identities before adopting results. - -A source that exhausts the analyzer heap does not terminate the CLI/MCP -process. Completed static facts are retained, other files can still be analyzed, -and unexamined semantic relationships remain explicit unknowns. The parent -also checks transfer expansion and accumulated results against its remaining -heap before accepting semantic facts. A resource-limited result has partial -coverage, the observed limits and an `analyze-javascript-source` unknown scope -with the specific failure, including captured diagnostics when available. -Resource failures do not increment syntax parse failures. There is no fixed -source-length cutoff. - -Static observations also need memory when expanded into nodes, relationships -and Evidence. If that expansion does not fit, the file node retains -`static_analysis` and any admitted `semantic_module_analysis` observations, -including their exact values and source locations. Use the public modules item -view to read them. The graph marks those unexpanded relationships as unknown. -If cumulative result capacity is exhausted, analysis stops; inventoried but -unexamined files remain present with explicit unknown scopes. - -A timeout stops the remaining analysis and returns typed failure details with -completed partial Evidence. MCP failure details return -`partial_observation: { kind: "retained-evidence", evidence_id: "..." }` -after recording succeeds, so `inspect_analysis_view` can open that analysis -directly without serializing the entire partial graph into the error response. -CLI failure output retains the complete partial Evidence. -Cancellation after source analysis begins likewise retains completed facts, -including cancellation during analyzer cleanup, graph construction, or Evidence -sealing. REA finishes projecting those owned facts cooperatively to return partial -Evidence. An SDK client may reject its cancelled request before receiving that -reply. On the same MCP connection, inspect the Evidence bundle -and use the retained analysis ID with `inspect_analysis_view`. Owned analyzer -cleanup is verified before its private files are released. Cleanup uncertainty -is reported separately and retains ownership for retry. - -CLI workflows parse larger JSON input files incrementally from one verified -regular-file handle, without constructing a document-sized string. Smaller -files retain native JSON parsing. Both paths require strict JSON and valid -UTF-8, and return one complete value; the assembled object still needs memory. -An individual JSON string exceeding the native length limit or the available -heap headroom for assembly returns -`resource_constraint` with `input_reason: "too-large"`. Supply a smaller valid -value; for Evidence workflows, re-analyze a smaller selection of the original -target and use its complete Evidence. Splitting JSON text or trimming Evidence -fields does not produce a valid workflow input. - -Evidence bundle and analysis snapshot file readers still decode whole -documents. Their runtime string-limit failures report a resource constraint -with the selected path, observed bytes and UTF-16 limit, rather than malformed -JSON. +## Read the analysis `analyze_javascript_application` returns the complete analysis Evidence by default. Select `"detail": "summary"` to retain that complete Evidence in the @@ -251,18 +112,82 @@ workflows as a retained reference. The summary does not repeat or truncate the analysis; a server without session retention refuses summary detail with `capability_unavailable`. CLI output is unchanged and always complete. -MCP prepares the complete repeated response incrementally against the pinned -SDK's 10 MiB stdio receive-buffer budget. Oversized results return an actionable -transport constraint and the exact same-session Evidence reference. Use -`inspect_analysis_view` with the retained Evidence ID for a summary, one -module, or a stable page of module identities. Use `trace_application_feature` -once a module, route, or string seed is known, or `export_evidence_bundle` to -write the complete canonical bundle without a document-sized allocation. -Same-session analysis reads reuse authenticated immutable snapshots; foreign -inline Evidence is still parsed and authenticated. -See [MCP tool results](mcp-contracts.md#tool-results) for larger client buffers -and `REA_MCP_MAX_RESPONSE_BYTES`. Follow-up results remain complete and can also -exceed the transport budget. +With a connected MCP `client` and the caller-selected absolute `inputPath`, this +recipe analyzes once and pages module identities using the returned ID: + +```js +const analysis = await client.callTool({ + name: "analyze_javascript_application", + arguments: { input_path: inputPath, detail: "summary" }, +}); +if (analysis.isError) throw new Error(JSON.stringify(analysis.content)); +const parentId = + analysis.structuredContent.normalized_result.parent_evidence_id; +const modules = await client.callTool({ + name: "inspect_analysis_view", + arguments: { + source: { kind: "retained-evidence", evidence_id: parentId }, + view: { kind: "page", collection: "modules", offset: 0, limit: 16 }, + }, +}); +if (modules.isError) throw new Error(JSON.stringify(modules.content)); +``` + +Select a returned module's exact `node_id` for an item view. A path can identify +several graph roles; module items preserve their recorded properties and source +locations. Follow `coverage.next_offset` when another page matters. For feature +tracing, version comparison, and retained-input examples, use the +[application workflows](javascript-application-workflows.md). + +For supplied passive browser or Electron observations, use +[runtime reconciliation](javascript-runtime-reconciliation.md). It compares +existing Evidence without rerunning static analysis or contacting CDP. + +## ASAR integrity + +ASAR inventory checks Electron integrity metadata for embedded archive entries +and supplied `.asar.unpacked` companion files. An integrity failure identifies +the logical path, declared and calculated SHA-256 values, and whether the entry +was unpacked. By default, a mismatch is returned as a failure with its artifact +context. Application analysis can explicitly select `record-and-continue` to +analyze observed bytes while retaining each contradiction's declared and +observed hashes and `observed-untrusted` trust. Such results mark application +graph coverage partial and include every contradicted path in the limitations. +Mismatched nested ASARs stay opaque rather than being expanded. + +An unpacked entry whose companion bytes were not supplied remains +`unavailable`. REA continues analyzing embedded JavaScript and records the +missing native/resource bytes as unknown. The occurrence keeps +`hash_status: unavailable`; no content-addressed child artifact is created for +those missing bytes. See [MCP integrity handling](mcp-contracts.md#integrity-record-and-continue) +for the tool-result contract. + +## Large results + +Use MCP `detail: "summary"` for a large application, then read selected views of +the retained analysis. Summary changes delivery only. To reduce source parsing, +select exact [source paths](#select-sources-before-analysis). + +If a complete response exceeds the transport budget, use its retained Evidence +ID for a summary, module page, or item, or export the bundle. See +[MCP tool results](mcp-contracts.md#tool-results) for delivery limits, export, and +matching server/client buffer settings. Follow-up results also need to fit that +budget. [Analyzer limits](#analyzer-and-result-admission) control analysis memory, +source deadlines, and semantic capacity separately. + +## Recover partial analysis + +A source timeout stops the remaining analysis and returns completed facts as +partial Evidence. Cancellation after source analysis begins can also retain +completed facts, including when interrupted during cleanup, graph construction, +or Evidence sealing. Unexamined relationships remain unknown. + +MCP returns a `partial_observation` retained reference after recording succeeds; +open it with `inspect_analysis_view` on the same connection. If the SDK stopped +waiting before receiving the reply, follow [MCP cancellation recovery](mcp-contracts.md#progress-and-cancellation) +to find the record. CLI failure output contains the complete partial Evidence. +Owned analyzer cleanup is verified before private files are released; uncertain +cleanup retains ownership for retry and is reported separately. ## What is reconstructed @@ -279,14 +204,6 @@ execute them. JavaScript and HTML source ranges retain an initial UTF-8 BOM as one UTF-16 code unit, matching the original bytes identified by the artifact digest. -If an ASAR declares an unpacked companion entry but the corresponding -`.unpacked` file is absent from the operator-supplied artifact set, REA -keeps the ASAR occurrence with `hash_status: unavailable`, records an explicit -limitation, and does not create a content-addressed child artifact for those -missing bytes. This allows static JavaScript/Electron reconstruction to proceed -for the embedded files while preserving the missing native/resource bytes as an -unknown instead of silently treating them as absent or verified. - Plain `.ts` artifact sources use TypeScript syntax without JSX, including angle-bracket type assertions. `.tsx` and `.jsx` retain JSX parsing. @@ -516,6 +433,110 @@ and inventoried containment edge is retained. If parsing or artifact safety boundaries omit input, coverage reports that omission; when an exact omission count is not knowable, `omitted_count` is `null` rather than a guessed value. +### Analyzer and result admission + +Application analysis projects semantic relationships one source file at a time. +After projection, it retains only the lexical module facts and exported return +shapes needed to build application relationships. Full source IR does not stay +resident for every file together. Callable ownership and contained-reference +queries use per-file range indexes, while call sites use exact-range lookups. +Existing node budgets and coverage reporting remain in effect. + +Progress identifies the source file being parsed and projected. Cancellation is +checked between files and throughout result transfer. The owned analyzer can +be stopped while its synchronous parser or semantic extractor is active; +the CLI/MCP process remains available for control requests. + +Graph and Evidence identifiers hash canonical JSON incrementally, without +assembling a single string for the whole graph. The canonical bytes and existing +identifiers remain unchanged. The opt-in regression check is +`npm run verify:javascript:digests`; +it hashes a value larger than the running Node engine's single-string limit. + +Both application CLI routes stream complete JSON and JSONL output in bounded +chunks, including field filters and `--full-output`. They wait for each stdout +write instead of constructing or reparsing a document-sized string. The opt-in +`npm run verify:javascript:output` checks the actual CLI formatting boundary with +a temporary output file larger than the running engine's string limit, verifies +its bytes and digest, and removes it. Use `-- jsonl` for the compact JSONL check. +Each check needs space for one output file plus a 1 GiB free-space reserve. + +Other CLI formats and `--token-count` still assemble whole strings. +Field selection remains useful when the caller needs a +smaller view, for example `--format json --filter-output +evidence_id,normalized_result.statistics`. Streaming output does not bound the +memory needed to construct the analysis graph itself. + +JavaScript source parsing, static analysis and semantic projection run in one +owned analysis process, reused sequentially across files. Target code is never +executed. The analyzer defaults to 1024 MiB of V8 old-space and a 300000 ms +deadline per source, including startup and fact transfer. Select +`max_heap_mb` and `analysis_timeout_ms` through MCP, or `--max-heap-mb` and +`--analysis-timeout-ms` on the dedicated CLI command. These choices control the +analyzer; the caller's `NODE_OPTIONS` still controls the CLI/MCP process heap. +V8 old-space limits do not impose a process RSS limit. When REA runs on Bun, +the analyzer ignores the V8 heap flags; resource failures then report +`worker_heap_limit_bytes` as null instead of a requested or V8-reported limit. +On Windows, the analyzer's owned Job Object instead limits its committed +memory to `max_heap_mb` plus a 512 MiB reserve for Bun itself (1536 MiB by +default). Reaching it fails the current source with the same memory resource +failure and reports `worker_process_memory_limit_bytes`, also a coverage limit; +the next source starts a new analyzer. Bun elsewhere enforces no analyzer limit. + +The default semantic capacities are 100000 nodes across the application and +20000 per source. Large bundles may explicitly select `max_semantic_nodes` and +`max_semantic_nodes_per_file` (CLI: `--max-semantic-nodes` and +`--max-semantic-nodes-per-file`), each from 1 to 1000000. The per-file offer is +also bounded by the remaining application capacity. Raising these controls does +not bypass worker heap, execution deadline or parent result admission. Truncated +coverage reports both effective node ceilings; omitted relationships remain +unknown. + +While sources remain, the sequential worker reserves one next compact static +checkpoint at its 8 MiB bound with the same 6x retention expansion used at +admission. Earlier checkpoints are already charged to retained bytes; the +remaining inventory does not multiply the reserve. Streamed file transfers keep the default 512 MiB +allowance, and can grow with the parent's offered retention budget (8x byte +expansion), up to 2 GiB. Individual records remain bounded to 8 MiB. The parent +still independently checks actual bytes, record overhead, digests and source +identities before adopting results. + +A source that exhausts the analyzer heap does not terminate the CLI/MCP +process. Completed static facts are retained, other files can still be analyzed, +and unexamined semantic relationships remain explicit unknowns. The parent +also checks transfer expansion and accumulated results against its remaining +heap before accepting semantic facts. A resource-limited result has partial +coverage, the observed limits and an `analyze-javascript-source` unknown scope +with the specific failure, including captured diagnostics when available. +Resource failures do not increment syntax parse failures. There is no fixed +source-length cutoff. + +Static observations also need memory when expanded into nodes, relationships +and Evidence. If that expansion does not fit, the file node retains +`static_analysis` and any admitted `semantic_module_analysis` observations, +including their exact values and source locations. Use the public modules item +view to read them. The graph marks those unexpanded relationships as unknown. +If cumulative result capacity is exhausted, analysis stops; inventoried but +unexamined files remain present with explicit unknown scopes. + +### Large local JSON inputs + +CLI workflows parse larger JSON input files incrementally from one verified +regular-file handle, without constructing a document-sized string. Smaller +files retain native JSON parsing. Both paths require strict JSON and valid +UTF-8, and return one complete value; the assembled object still needs memory. +An individual JSON string exceeding the native length limit or the available +heap headroom for assembly returns +`resource_constraint` with `input_reason: "too-large"`. Supply a smaller valid +value; for Evidence workflows, re-analyze a smaller selection of the original +target and use its complete Evidence. Splitting JSON text or trimming Evidence +fields does not produce a valid workflow input. + +Evidence bundle and analysis snapshot file readers still decode whole +documents. Their runtime string-limit failures report a resource constraint +with the selected path, observed bytes and UTF-16 limit, rather than malformed +JSON. + ## Verification boundary The source-owned fixture covers an extracted directory, a direct ASAR with an diff --git a/docs/managed-code-analysis.md b/docs/managed-code-analysis.md index 386b7b6d5..06d0cceee 100644 --- a/docs/managed-code-analysis.md +++ b/docs/managed-code-analysis.md @@ -26,6 +26,20 @@ current tool set. The canonical tool inventory is the [build-generated catalog](mcp-contracts.md#generated-catalog). +## Inspect an assembly + +```bash +rea inspect-managed-artifact /absolute/path/Assembly.dll --json +rea inspect-managed-members /absolute/path/Assembly.dll --json +``` + +Use the artifact result to identify the assembly and its metadata coverage. +Member results retain build-local tokens, signatures, CIL bodies, and decoded +relationships. Use an exact reported `full_name` with `--type` when a focused +inspection is needed; see [selected member inspection](#selected-member-inspection). +Compare separate builds with [member comparison](#member-comparison), preserving +their paths, digests, and selection scope. + ## Shipped scope The canonical parser admits PE/CLI bytes and their metadata/CIL without loading @@ -94,19 +108,39 @@ assembly. Older member Evidence without `selection` remains readable. ## Analysis objective -REA's managed-code track is intended to answer five different questions without -collapsing them: +Start by identifying the artifact with `inspect_managed_artifact`, then inspect +its types and CIL with `inspect_managed_members`. Use [member comparison](#member-comparison) +for another build, and [managed/native boundary rules](#managednative-boundary-rules) +when matching declared native calls to supplied native Evidence. Static inspection +does not load or execute the assembly. Reconstructed structure and unresolved +native/runtime questions retain their own authority and coverage. -1. What exact artifact and managed deployment form is this? -2. What do its admitted metadata and CIL bytes state? -3. What source-like or behavioral structure can be reconstructed or inferred? -4. Which findings survive an exact-build check or a cross-build structural - comparison? -5. Which remaining questions require native analysis or runtime evidence that - static inspection cannot supply? +## Member comparison -The ordinary workflow ends at question four. Static analysis never loads or -executes the target. +Names and semantic labels do not establish durable member identity. Comparison +preserves observed differences, structural inferences, and unknowns separately. + +Cross-version matching first prefers exact CIL/signature identity. When that +does not match, it pairs an exact declared type, method name, and raw signature +before trying structural body shape. The exact-signature key uses names only +as part of that full tuple; names alone never select a pair. Duplicate tuples +remain ambiguous rather than being paired by token order. Fields follow the +same exact tiers. The raw signature is exact whether or not REA decoded it, so +undecoded signatures pair by that tuple too, but they never enter structural +rounds. An unmatched member is therefore reported as `unknown`, not added or +removed, when its own signature was not decoded or when the other side has an +unpaired member, one-sided or ambiguous, with the same declared type and name +whose signature was not decoded. + +For a matched method, an unavailable or partial body makes body-shape facets +unknown while preserving observed signature differences. Structural identity +compares normalized signatures, the limited decoded-CIL tuple fingerprint, +constants, and bounded shape context. It reports all candidates at the winning +score and remains ambiguous when the evidence does not distinguish them. The +digest does not itself remap metadata tokens. + +Tokens are always remapped through observed structure. A caller cannot carry +`0x06001234` into a new MVID and assume it names the same method. ## NativeAOT metadata recovery @@ -128,24 +162,38 @@ lists supported OS/architecture targets and deployment limitations, while its [native library guide](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/libraries) describes exported shared-library entry points. -REA supports an optional headless adapter for the Ghidra NativeAOT analyzer. -Supply a locally built `REA_GHIDRA_NATIVEAOT_JAR`; REA does not install the -extension or its toolchain. The verified boundary is .NET 8.0.22 RTR 9.1, -x86-64 ELF and native Windows PE targets analyzed on Linux x64 with Ghidra -12.1.4 and JDK 21. Other layouts, architectures, and hosts are unsupported. -See [NativeAOT recovery](ghidra-nativeaot.md) for build/configuration, recovered -metadata, derived-memory provenance, and the real verification lane. +REA offers a built-in read-only snapshot parser for x64 PE/RTR 9.1 metadata and +an optional Linux headless Ghidra adapter for annotations and broader recovery. +The adapter requires a locally built `REA_GHIDRA_NATIVEAOT_JAR`; REA does not +install it or its toolchain. The [NativeAOT guide](ghidra-nativeaot.md) defines +these routes, their layout/host restrictions, derived-memory provenance, and +verification coverage. REA's experimental Windows Ghidra boundary admits native x86 and x86-64 PE applications and DLLs for static analysis. This does not establish Windows NativeAOT metadata-recovery coverage. For NativeAOT analysis, preserve the selected native artifact's path and digest -and report recovered type data as provider observations. Linking those types +and report recovered type data with its returned provenance. Linking those types to native function addresses requires verified provider evidence; names or vtable similarity alone do not prove that a native function implements a specific managed method. +## Managed/native boundary rules + +`verify_managed_native_boundaries` compares declared P/Invoke module and entry +point identities with supplied native export or function evidence. Name/module +matches establish declaration links; they do not establish that a call executed. + +Metadata tokens are not native addresses. Native body mapping for C++/CLI, +ReadyToRun, NativeAOT, and IL2CPP requires separately verified format and provider +support. The managed static tools do not recover those mappings. The optional +[Ghidra NativeAOT extension](ghidra-nativeaot.md) has its own supported boundary. + +Declared import inventory supports a bounded positive claim. Its absence does +not exclude dynamic resolution, generated code, protected code, native helpers, +or server-side behavior. + ## Evidence record shape Member comparison, application graph projection, and managed/native verification @@ -229,48 +277,6 @@ For example, a decoded `nop; ret` body serializes exactly as This vector specifies the tuple order, `null` handling, absence of whitespace, UTF-8 encoding, and lowercase hexadecimal output. -## Member comparison - -Names and semantic labels do not establish durable member identity. Comparison -preserves observed differences, structural inferences, and unknowns separately. - -Cross-version matching first prefers exact CIL/signature identity. When that -does not match, it pairs an exact declared type, method name, and raw signature -before trying structural body shape. The exact-signature key uses names only -as part of that full tuple; names alone never select a pair. Duplicate tuples -remain ambiguous rather than being paired by token order. Fields follow the -same exact tiers. The raw signature is exact whether or not REA decoded it, so -undecoded signatures pair by that tuple too, but they never enter structural -rounds. An unmatched member is therefore reported as `unknown`, not added or -removed, when its own signature was not decoded or when the other side has an -unpaired member, one-sided or ambiguous, with the same declared type and name -whose signature was not decoded. - -For a matched method, an unavailable or partial body makes body-shape facets -unknown while preserving observed signature differences. Structural identity -compares normalized signatures, the limited decoded-CIL tuple fingerprint, -constants, and bounded shape context. It reports all candidates at the winning -score and remains ambiguous when the evidence does not distinguish them. The -digest does not itself remap metadata tokens. - -Tokens are always remapped through observed structure. A caller cannot carry -`0x06001234` into a new MVID and assume it names the same method. - -## Managed/native boundary rules - -`verify_managed_native_boundaries` compares declared P/Invoke module and entry -point identities with supplied native export or function evidence. Name/module -matches establish declaration links; they do not establish that a call executed. - -Metadata tokens are not native addresses. Native body mapping for C++/CLI, -ReadyToRun, NativeAOT, and IL2CPP requires separately verified format and provider -support. The managed static tools do not recover those mappings. The optional -[Ghidra NativeAOT extension](ghidra-nativeaot.md) has its own supported boundary. - -Declared import inventory supports a bounded positive claim. Its absence does -not exclude dynamic resolution, generated code, protected code, native helpers, -or server-side behavior. - ## Tool and packaging boundary The production parser is REA-owned TypeScript and ships with the existing Node diff --git a/docs/mcp-contracts.md b/docs/mcp-contracts.md index 1fb3b5e5d..8da586e8d 100644 --- a/docs/mcp-contracts.md +++ b/docs/mcp-contracts.md @@ -1,338 +1,13 @@ # MCP runtime contracts -## Generated catalog - -Run `npm run docs:generate` in a source checkout to generate the machine-readable -catalog at `docs/public/product-catalog.json`. Documentation deployments serve -the same file at [/rea/product-catalog.json](/rea/product-catalog.json). PR CI retains it with the packaged -skill and portable conformance projections in the `generated-docs` artifact. -These outputs describe the exact source revision being built; they are not -checked-in snapshots. For a running server, `binary_session` remains the -authoritative source of catalog identity and tool availability. - -## Identity and discovery - -`binary_session` reports the active package, server, SDK, and negotiated -protocol details. `rea doctor` separately inspects supported JSON/TOML client -registrations, reports their command vectors as aligned, stale, missing, or -invalid, and keeps live-server state `unknown` unless the active connection -supplies identity. - -`tools/list` returns the complete canonical tool inventory, including tools that -are currently unavailable. Opening or closing a target or observing a provider -health transition leaves that catalog unchanged and does not emit -`notifications/tools/list_changed`. - -Advertised input and output schemas contain no reachable recursive references. -Schemas share repeated definitions through schema-local references while -preserving complete nested fields and validation rules. Input properties retain -their descriptions and literal examples. - -Hosts forward input schemas to the model with every request, so advertised -examples never copy complete producer Evidence. An embedded Evidence record is -shown as its exact `{"kind":"retained-evidence","evidence_id":"ev_..."}` -reference where the tool accepts one. An example that can only carry inline -Evidence stays in the canonical contract and its executable tests, but is not -advertised. Every advertised example is a distinct valid canonical input. - -Root object unions are presented as -one object without root `anyOf`, `oneOf`, or `allOf` for model API compatibility. -The projection merges properties, retains shared required fields and -group-specific field dependencies, and describes the accepted input groups. -Canonical runtime validation enforces the exact union, including exclusions -that the advertised projection does not express. Tests validate the schemas -after SDK conversion and check advertised validation and actual calls. -Individual model APIs can impose additional nesting limits; complete producer -captures can exceed ten structural levels. - -### Compact input schema profile - -Some function-calling providers reject a request while any single tool's -`parameters` schema exceeds a literal serialized size cap; Moonshot clients -such as kimi-cli fail every request while the default catalog is attached -([#1484](https://github.com/morluto/rea/issues/1484)). Setting the server's -`REA_MCP_INPUT_SCHEMA_PROFILE` environment variable to `compact` renders every -advertised input schema within a 13,312-byte budget, measured to sit below -Moonshot's observed cap (community measurements: a 13.7 KB schema is accepted -while a ~15 KB one is rejected). The setting is read at startup; restart the -server to apply changes, as with `REA_MCP_MAX_RESPONSE_BYTES`. The default -value `full` keeps the complete advertisement unchanged. - -The compact profile renders the same tool set, output schemas, annotations, -and canonical server-side validation. It changes only the advertised input -JSON Schema: - -- Annotation prose leaves the advertised form: nested property descriptions, - literal examples, defaults, and titles are dropped. The root keeps its - description because it states the accepted input groups. -- Schema-local references are inlined within the budget. Kimi Code expands - references before sending provider requests, so sharing definitions cannot - establish the provider-facing size. Expansion stops at the budget before - allocating an oversized presentation. Unconstrained JSON fields advertise - all JSON value types explicitly so Kimi cannot infer string for Evidence - objects or arrays. -- The few schemas whose validation structure alone exceeds the budget - (`compare_web_captures`, `build_reconstruction_obligation_ledger`, - `evaluate_reconstruction_coverage`, `project_managed_application_graph`, - `compare_application_versions`, `capture_browser_scenario`) are advertised - in a reduced form: property names, reference-resolved types (including union - alternatives), first-level guidance, and the root's required-field constraints, - with nested validation detail elided. The - canonical schema still rejects malformed calls server-side, so callers - following the reduced advertisement receive the canonical typed error - instead of silent acceptance. - -Boundary tests pin every advertised compact schema to the budget, keep them -valid JSON Schema that still accepts every canonical example, and hold the -set of six reduced presentations as contracts evolve. Client verification -also checks provider-facing sizes and canonical examples after conversion by -the actual Kimi Code CLI; local captures do not establish Moonshot acceptance. - -Self-contained output schemas advertise a content-bound `$id`, including their -declared dialect. SDK validators can reuse compiled schemas across complete -catalog refreshes and equivalent tool outputs; changing the schema changes its -identity. Explicit schema IDs and relative external reference bases are -preserved. This keeps every tool and validation rule in discovery and does not -change the SDK's catalog invalidation or availability checks. - -`compare_web_captures` accepts exactly one of two input shapes: - -- Passive: `before` and `after` each contain `inspection`, the complete - `normalized_result` from `inspect_web_page`. Each may also contain `webmcp`, - the complete `normalized_result` from `discover_webmcp_tools`, or null. -- Scenario: `before_scenario` and `after_scenario` contain complete - `normalized_result` objects from `capture_browser_scenario`. Optional - `normalization` defaults to `{ "rules": [] }`. - -The advertised schema includes complete nested capture fields and rejects -incomplete pairs and structurally malformed captures. Mixed comparison families -can pass advertised validation; the SDK rejects them against the canonical -input schema before invoking the handler. Domain validation additionally checks -relationships such as event sequence references and retained counts; JSON -Schema does not express those cross-field invariants. - -Call `binary_session` with `{}` and read `result.tool_availability` to choose a -callable operation for the current target, provider, host, and negotiated client -capabilities. The default result contains the complete inventory in groups that -share status facts. `tool_availability.client_requirements` is the baseline for -each group; a group's optional `client_requirements` replaces that baseline for -the group's tools. Expand each group's `names` into one tool entry, carrying its -surface, availability, reason, remediation, default-mode status, modes, and -client requirements. Compare the union of group names with `tools/list` when -checking that a client received the full catalog. An operation absent from all -groups is missing from the complete inventory; it is not an implicit -unavailable entry. - -The `effects` and `annotations` arrays list the true members of their fixed -vocabularies. A known member omitted from either array is false. This applies -only to these closed flag sets; it does not make an omitted tool, provider, mode, -or limitation false. Keep availability reasons, remediation, client-feature -requirements, and mode facts inline with the grouped tool names. The optional -inputs `expected_package_version`, `expected_catalog_digest`, and -`expected_server_path` compare the live session with the caller's expectations. - -`server_identity.catalog` contains catalog counts and schema digests. Grouped -tool availability carries the name set and current per-tool facts; `tools/list` -is the canonical source for complete tool definitions, including input and -output schemas. Clients that previously read `server_identity.catalog.tools` -should expand `tool_availability.groups` and use `tools/list` for schemas. The -same catalog identity summary is returned by CLI `capabilities` and `providers`; -MCP tool definitions remain available through `tools/list`. - -Provider capabilities are grouped by provider identity and shared facts. In each -set, `shared_limitations` is the ordered common prefix; append a group's ordered -`limitations` suffix to recover each operation's exact limitations. Group -`effects` arrays use the same true-only closed-vocabulary rule as tool -availability. Expand every group operation while retaining its provider -identity, availability, reason, rejection code, effects, and ordered -limitations. - -`binary_session.analysis_provider_candidates` is authoritative for deep-engine -discovery. Each candidate's capability sets describe that possible provider; -they do not select it. The top-level `capabilities` describe the current route, -while `analysis_provider_binding` identifies the concrete selected route. These -fields are not interchangeable. Target-free discovery is sorted by provider ID, -reports host availability and `unknown` target support, and does not create an -analysis client. `open_binary.provider_id` accepts a concrete provider ID or -`auto`; it uses the same parser and selection policy as CLI `--provider` and -`REA_ANALYSIS_PROVIDER`. A successful deep open exposes one immutable provider, -concrete version, selection source, and complete analysis profile through -`analysis_provider_binding`. Ambiguity and unknown, unavailable, or unsupported -choices return typed selection details. A selected provider is never replaced -automatically after a runtime failure. - -Every successful target transition allocates `binary_session.analysis_run.run_id` -before any provider startup. `process_lineage` is `not_observed` until a dynamic -provider starts, then becomes `snapshots` with every started provider's identity -and retained ownership observation. Each observation records `observed_at` and -is `unavailable` with a reason when ownership could not be revalidated, or -`verified` with launcher PID, parent PID, process group, and descendants observed -at that bounded check. These are historical snapshots, not live process -inventories, and do not claim that no short-lived descendant existed. - -## Progress and cancellation - -Tool execution failures return `isError: true` and the complete canonical -`{ "error": ... }` diagnostic as JSON in text `content`. Read that diagnostic -for the error code, target details, partial observations, and remediation. -Failures omit `structuredContent`, since each advertised `outputSchema` -describes successful results. Successful replies retain their schema-validated -structured data and matching text projection. Oversized errors are retained -as Evidence before delivery of a bounded diagnostic with an export reference; -if retention is unavailable or fails, the diagnostic reports that reason. - -REA accepts ordinary `tools/call` progress tokens. The numeric `progress` counts -emitted status observations and strictly increases, including when a waiting -phase has completed no additional work. Updates are rate-bounded to at most one -intermediate update per 100 ms and always allow a terminal update. `total` is -omitted because the number of future status observations is unknown. Read -`message` for the phase and observed work; REA does not fabricate percentages. -`capture_process_scenario` uses that boundary only when the client supplies a -progress token. Notifications put the lifecycle phase, elapsed time, and final -cleanup status in `message`. A client -that does not send a progress token receives no progress notifications. The -tool result is unchanged either way. -Provider calls receive the request cancellation signal. Artifact traversal, -hashing, version comparisons, Hopper requests, and process capture -check the same signal. Cancellation is distinct from timeout. A cleanup failure -uses `cleanup_incomplete` and lists only the owned resource kinds that remain. -An atomic Evidence bundle or snapshot write can publish its complete output -before staging cleanup fails. In that case, `details.published: true`, -`details.published_path`, and `details.bytes` retain the publication receipt. -Use that receipt to distinguish completed publication from a write that never -committed. Staging resources remain owned until cleanup is verified. -Native call tracing and process capture retain available observations in -`details.partial_observation` on failure, including when cleanup succeeds. -The observation reports its partial coverage; cleanup details describe host -state separately from the execution failure. -A process capture that fails during a finalization interval keeps every signal -attempt and its delivery result in `details.partial_observation`, with -`elapsed_ms` and `exit_code` null when no exit was observed. -Derived comparisons and reconstruction verification yield before computation -and before publication, so cancellation cannot race with successful Evidence. - -`analyze_javascript_application` also yields between reconstruction phases and -during graph/result sealing, cross-graph binding checks, Evidence JSON validation, -and canonical hashing. Its final result validation reuses exact graphs whose -owned constructors validated and completely sealed them; imported graphs still -receive full schema and commitment checks. -Cancellation observed before completion returns `cancelled` and prevents the -provisional result from entering the session ledger; prior Evidence stays usable. -Single-file parsing, graph construction, and validation of imported graphs -still run synchronously, so control messages can wait for those -phases to release the event loop. A rejected client promise alone does not -establish that the server has stopped its work. - -Direct CLI analysis calls work without a progress token and translate SIGINT or -SIGTERM into the same AbortSignal used by providers. Signal guards remain active -through provider cleanup, including repeated delivery by package runners. -Existing controlled-process cleanup and provider shutdown rules still apply; -REA never kills a process it cannot prove it owns. - -## Ghidra first-query deadlines and recovery - -A successful MCP initialize handshake establishes the REA connection. -`open_binary` then selects a target and provider binding; it does not establish -that Ghidra has finished importing the target. The first Ghidra-backed query, -such as `binary_overview`, starts the engine and waits for import, default -auto-analysis, bridge connection, and health readiness before returning analysis. - -These deadlines have different owners: - -| Deadline | Owner and effect | -| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| MCP initialize | The client bounds transport/REA connection startup, before any target query. | -| Hopper startup | REA allows 120,000 ms by default; `REA_HOPPER_STARTUP_TIMEOUT_MS` accepts decimal integers from 1–2,147,483,647 ms. Invalid values fail configuration validation. Startup failure is reported by the first provider query. | -| Ghidra startup | REA allows 330,000 ms by default; `REA_GHIDRA_STARTUP_TIMEOUT_MS` accepts decimal integers from 1–2,147,483,647 ms. Invalid supplied values fail configuration validation. Startup failure is reported by the first provider query. | -| Individual tool call | The client bounds its wait, including cold engine startup. The pinned client SDK 2.3.1 defaults to 60,000 ms and can cancel earlier than REA's startup deadline. | - -For an already connected client using the pinned SDK, request options are the -**second** argument of `callTool`: - -```js -const overview = await client.callTool( - { name: "binary_overview", arguments: {} }, - { - timeout: 240000, - onprogress: ({ progress, total, message }) => { - console.error({ progress, total, message }); - }, - }, -); -``` - -The SDK's `onprogress` option supplies a progress token and handles matching -notifications. A raw MCP client can instead send `_meta.progressToken` in the -request and handle `notifications/progress`. Progress reports do not establish -engine readiness or a percentage of Ghidra auto-analysis. A longer server -startup allowance does not extend the client's deadline; progress also does not -extend it unless the client explicitly implements that policy. - -While Ghidra startup is pending, REA sends a waiting notification every ten -seconds when the request has a progress token. Its message gives elapsed waiting -time; import, auto-analysis and bridge readiness may all still be pending. -Waiting notifications stop when startup settles or the caller cancels. They do -not measure engine work completed. - -The pinned SDK can reset the request's inactivity timeout on progress with -`resetTimeoutOnProgress: true`. Also set `maxTotalTimeout` to bound the complete -request; the provider's startup deadline still applies. These options belong in -the same second argument of `callTool`. Without that explicit client policy, the -default 60-second request deadline still expires despite waiting notifications. - -The 240-second setting is a measured example, not a universal timeout: a -controlled Linux x64/WSL2 fixture took about 64 seconds for its first overview -with Ghidra 12.1.4 on a mounted NTFS installation, native JDK 21, two CPUs, and a -512 MiB Java heap. Target size, storage, and analysis work can change that time. -Configure the deadline in the caller's existing request settings; it is not a -tool argument, setup grant, or server-side automatic extension. CLI analysis has -no MCP client request deadline, but keeps the provider startup deadline and -SIGINT cancellation. - -If the client timed out or cancelled during startup, the pending query may have -been interrupted. Reissuing `open_binary` for the same active target can reuse -the current client, so it is not a fresh-start recovery. On the same connection: - -1. Keep any useful inline Evidence, or export a bundle before closing if retained - records are needed. `binary_session` can show the selected binding and its - recorded state; target selection alone does not prove engine readiness. -2. Call `close_binary` and check its result. It drains owned work, closes the - provider, and clears retained session records. A `cleanup_incomplete` result - must be addressed according to its reported owned resources before retrying. -3. Call `open_binary` with the same caller-selected path and - `provider_id: "ghidra"`, then retry the first query with an appropriate client - deadline. The connection and selected provider do not need to change. - -This close/reopen flow was exercised on one real Linux stdio connection after a -controlled startup timeout, followed by a successful overview and function -analysis. A separate Windows x64 stdio run with Ghidra 12.1.4, JDK 21 and Node -22.19.0 exercised the same connection and caller-selected native PE: the default -60-second client request timed out, close succeeded, and reopening before a -240-second request completed the cold overview in about 163 seconds. The next -overview took about 19 ms. The cold and warm overviews reported two procedures -and two segments; the input digest was unchanged and no owned runtime root or -observed process-family member remained after final close. This was a small -1,024-byte fixture, so the longer request setting remains an example, not a -guarantee for larger targets. No macOS cold-start recovery was exercised. - -With a supplied progress token, that earlier Windows run received an operation-start -notification before timeout and start/completion notifications for the -successful retry, before startup waiting notifications were added. It received -no intermediate import or auto-analysis progress. -These operation markers do not measure analysis work completed or extend the -client's deadline. Each new provider session still imports the target into a -fresh temporary project. - -REA cleans only resources it owns and never switches to another provider -automatically. A provider timeout, installation failure, or host permission -denial needs its own reported recovery; increasing a client deadline alone does -not fix those failures. +Use this reference to call REA tools and interpret their replies on one MCP +connection. Start with [tool results](#tool-results), [retained Evidence](#retained-application-evidence-inputs), +and [session discovery](#identity-and-discovery). See [cancellation](#progress-and-cancellation) +for partial-result recovery and [first-query deadlines](#ghidra-first-query-deadlines-and-recovery) +when a cold provider exceeds the client's wait. ## Tool results -Custom clients upgrading from 6.1 should follow the -[6.2 migration guide](migration-6.2.md#mcp-results-and-evidence). - Evidence-producing tools return the complete canonical Evidence record in both text and structured content. Read `structuredContent.normalized_result` for the operation result and `structuredContent.evidence_id` for its identity. @@ -346,6 +21,15 @@ directly to `compare_functions`, and `inspect_artifact` Evidence to `compare_artifacts`. Use `get_evidence_bundle` when the task needs broader retained session history or an explicit bundle for transfer. +Tool execution failures return `isError: true` and the complete canonical +`{ "error": ... }` diagnostic as JSON in text `content`. Read that diagnostic +for the error code, target details, partial observations, and remediation. +Failures omit `structuredContent`, since each advertised `outputSchema` +describes successful results. Successful replies retain their schema-validated +structured data and matching text projection. Oversized errors are retained +as Evidence before delivery of a bounded diagnostic with an export reference; +if retention is unavailable or fails, the diagnostic reports that reason. + `get_call_graph` returns a `graph` keyed by traversal depth and a top-level `limitations` array with deduplicated execution caveats. Each node keeps its relationship coverage and read-specific `limitations`, alongside observed @@ -526,18 +210,132 @@ JSON to a file and use `inspect-analysis-view` with inline source Evidence for later inventory summaries or pages; a one-shot CLI session cannot retain a parent for another invocation. -## Aggregate native context +## Identity and discovery -`get_navigation_context` composes the selected document, current address, and -current/containing procedure. Its capability inventory exposes a -`current_selection` mode and an `explicit_document` mode; the latter works when -the caller supplies `document` and the provider lacks `current_document`. A -cursor outside a procedure is represented as -`procedure: null`. `inspect_address_context` requires an explicit address and -returns name, procedure, comment, inline-comment, and bookmark facets; -unsupported facets are local `unavailable` outcomes. Use `current_document`, -`current_address`, and `current_procedure` for direct single-field lookups; use -the aggregate tools when you need related context together. +`binary_session` reports the active package, server, SDK, and negotiated +protocol details. `rea doctor` separately inspects supported JSON/TOML client +registrations, reports their command vectors as aligned, stale, missing, or +invalid, and keeps live-server state `unknown` unless the active connection +supplies identity. + +`tools/list` returns the complete canonical tool inventory, including tools that +are currently unavailable. Opening or closing a target or observing a provider +health transition leaves that catalog unchanged and does not emit +`notifications/tools/list_changed`. + +Call `binary_session` with `{}` and read `result.tool_availability` to choose a +callable operation for the current target, provider, host, and negotiated client +capabilities. The default result contains the complete inventory in groups that +share status facts. `tool_availability.client_requirements` is the baseline for +each group; a group's optional `client_requirements` replaces that baseline for +the group's tools. Expand each group's `names` into one tool entry, carrying its +surface, availability, reason, remediation, default-mode status, modes, and +client requirements. Compare the union of group names with `tools/list` when +checking that a client received the full catalog. An operation absent from all +groups is missing from the complete inventory; it is not an implicit +unavailable entry. + +The `effects` and `annotations` arrays list the true members of their fixed +vocabularies. A known member omitted from either array is false. This applies +only to these closed flag sets; it does not make an omitted tool, provider, mode, +or limitation false. Keep availability reasons, remediation, client-feature +requirements, and mode facts inline with the grouped tool names. The optional +inputs `expected_package_version`, `expected_catalog_digest`, and +`expected_server_path` compare the live session with the caller's expectations. + +`server_identity.catalog` contains catalog counts and schema digests. Grouped +tool availability carries the name set and current per-tool facts; `tools/list` +is the canonical source for complete tool definitions, including input and +output schemas. Clients that previously read `server_identity.catalog.tools` +should expand `tool_availability.groups` and use `tools/list` for schemas. The +same catalog identity summary is returned by CLI `capabilities` and `providers`; +MCP tool definitions remain available through `tools/list`. + +Provider capabilities are grouped by provider identity and shared facts. In each +set, `shared_limitations` is the ordered common prefix; append a group's ordered +`limitations` suffix to recover each operation's exact limitations. Group +`effects` arrays use the same true-only closed-vocabulary rule as tool +availability. Expand every group operation while retaining its provider +identity, availability, reason, rejection code, effects, and ordered +limitations. + +`binary_session.analysis_provider_candidates` is authoritative for deep-engine +discovery. Each candidate's capability sets describe that possible provider; +they do not select it. The top-level `capabilities` describe the current route, +while `analysis_provider_binding` identifies the concrete selected route. These +fields are not interchangeable. Target-free discovery is sorted by provider ID, +reports host availability and `unknown` target support, and does not create an +analysis client. `open_binary.provider_id` accepts a concrete provider ID or +`auto`; it uses the same parser and selection policy as CLI `--provider` and +`REA_ANALYSIS_PROVIDER`. A successful deep open exposes one immutable provider, +concrete version, selection source, and complete analysis profile through +`analysis_provider_binding`. Ambiguity and unknown, unavailable, or unsupported +choices return typed selection details. A selected provider is never replaced +automatically after a runtime failure. + +Every successful target transition allocates `binary_session.analysis_run.run_id` +before any provider startup. `process_lineage` is `not_observed` until a dynamic +provider starts, then becomes `snapshots` with every started provider's identity +and retained ownership observation. Each observation records `observed_at` and +is `unavailable` with a reason when ownership could not be revalidated, or +`verified` with launcher PID, parent PID, process group, and descendants observed +at that bounded check. These are historical snapshots, not live process +inventories, and do not claim that no short-lived descendant existed. + +## Progress and cancellation + +REA accepts ordinary `tools/call` progress tokens. The numeric `progress` counts +emitted status observations and strictly increases, including when a waiting +phase has completed no additional work. Updates are rate-bounded to at most one +intermediate update per 100 ms and always allow a terminal update. `total` is +omitted because the number of future status observations is unknown. Read +`message` for the phase and observed work; REA does not fabricate percentages. +`capture_process_scenario` uses that boundary only when the client supplies a +progress token. Notifications put the lifecycle phase, elapsed time, and final +cleanup status in `message`. A client +that does not send a progress token receives no progress notifications. The +tool result is unchanged either way. +Provider calls receive the request cancellation signal. Artifact traversal, +hashing, version comparisons, Hopper requests, and process capture +check the same signal. Cancellation is distinct from timeout. A cleanup failure +uses `cleanup_incomplete` and lists only the owned resource kinds that remain. +An atomic Evidence bundle or snapshot write can publish its complete output +before staging cleanup fails. In that case, `details.published: true`, +`details.published_path`, and `details.bytes` retain the publication receipt. +Use that receipt to distinguish completed publication from a write that never +committed. Staging resources remain owned until cleanup is verified. +Native call tracing and process capture retain available observations in +`details.partial_observation` on failure, including when cleanup succeeds. +The observation reports its partial coverage; cleanup details describe host +state separately from the execution failure. +A process capture that fails during a finalization interval keeps every signal +attempt and its delivery result in `details.partial_observation`, with +`elapsed_ms` and `exit_code` null when no exit was observed. +Derived comparisons and reconstruction verification yield before computation +and before publication, so cancellation cannot race with successful Evidence. + +`analyze_javascript_application` also yields between reconstruction phases and +during graph/result sealing, cross-graph binding checks, Evidence JSON validation, +and canonical hashing. Its final result validation reuses exact graphs whose +owned constructors validated and completely sealed them; imported graphs still +receive full schema and commitment checks. +Cancellation before completion returns `cancelled` instead of a successful +result. Completed facts can be retained as new partial Evidence; prior Evidence +also stays usable. Read the error's `partial_observation` reference on the same +MCP connection. If the SDK stopped waiting before that reply arrived, use +`get_evidence_bundle` with `detail: "summary"` and an operation filter to find +the partial record, then open it with `inspect_analysis_view`. Cancellation +before any facts are completed may leave no partial record. +Single-file parsing, graph construction, and validation of imported graphs +still run synchronously, so control messages can wait for those +phases to release the event loop. A rejected client promise alone does not +establish that the server has stopped its work. + +Direct CLI analysis calls work without a progress token and translate SIGINT or +SIGTERM into the same AbortSignal used by providers. Signal guards remain active +through provider cleanup, including repeated delivery by package runners. +Existing controlled-process cleanup and provider shutdown rules still apply; +REA never kills a process it cannot prove it owns. ## Request scope and local effects @@ -581,6 +379,118 @@ files into a fresh REA-chosen temporary directory and reports its path. `analyze_javascript_application` reads the supplied local directory or ASAR path and returns its result and Evidence inline. +## Ghidra first-query deadlines and recovery + +A successful MCP initialize handshake establishes the REA connection. +`open_binary` then selects a target and provider binding; it does not establish +that Ghidra has finished importing the target. The first Ghidra-backed query, +such as `binary_overview`, starts the engine and waits for import, default +auto-analysis, bridge connection, and health readiness before returning analysis. + +These deadlines have different owners: + +| Deadline | Owner and effect | +| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| MCP initialize | The client bounds transport/REA connection startup, before any target query. | +| Hopper startup | REA allows 120,000 ms by default; `REA_HOPPER_STARTUP_TIMEOUT_MS` accepts decimal integers from 1–2,147,483,647 ms. Invalid values fail configuration validation. Startup failure is reported by the first provider query. | +| Ghidra startup | REA allows 330,000 ms by default; `REA_GHIDRA_STARTUP_TIMEOUT_MS` accepts decimal integers from 1–2,147,483,647 ms. Invalid supplied values fail configuration validation. Startup failure is reported by the first provider query. | +| Individual tool call | The client bounds its wait, including cold engine startup. The pinned client SDK 2.3.1 defaults to 60,000 ms and can cancel earlier than REA's startup deadline. | + +For an already connected client using the pinned SDK, request options are the +**second** argument of `callTool`: + +```js +const overview = await client.callTool( + { name: "binary_overview", arguments: {} }, + { + timeout: 240000, + onprogress: ({ progress, total, message }) => { + console.error({ progress, total, message }); + }, + }, +); +``` + +The SDK's `onprogress` option supplies a progress token and handles matching +notifications. A raw MCP client can instead send `_meta.progressToken` in the +request and handle `notifications/progress`. Progress reports do not establish +engine readiness or a percentage of Ghidra auto-analysis. A longer server +startup allowance does not extend the client's deadline; progress also does not +extend it unless the client explicitly implements that policy. + +While Ghidra startup is pending, REA sends a waiting notification every ten +seconds when the request has a progress token. Its message gives elapsed waiting +time; import, auto-analysis and bridge readiness may all still be pending. +Waiting notifications stop when startup settles or the caller cancels. They do +not measure engine work completed. + +The pinned SDK can reset the request's inactivity timeout on progress with +`resetTimeoutOnProgress: true`. Also set `maxTotalTimeout` to bound the complete +request; the provider's startup deadline still applies. These options belong in +the same second argument of `callTool`. Without that explicit client policy, the +default 60-second request deadline still expires despite waiting notifications. + +The 240-second setting is a measured example, not a universal timeout: a +controlled Linux x64/WSL2 fixture took about 64 seconds for its first overview +with Ghidra 12.1.4 on a mounted NTFS installation, native JDK 21, two CPUs, and a +512 MiB Java heap. Target size, storage, and analysis work can change that time. +Configure the deadline in the caller's existing request settings; it is not a +tool argument, setup grant, or server-side automatic extension. CLI analysis has +no MCP client request deadline, but keeps the provider startup deadline and +SIGINT cancellation. + +If the client timed out or cancelled during startup, the pending query may have +been interrupted. Reissuing `open_binary` for the same active target can reuse +the current client, so it is not a fresh-start recovery. On the same connection: + +1. Keep any useful inline Evidence, or export a bundle before closing if retained + records are needed. `binary_session` can show the selected binding and its + recorded state; target selection alone does not prove engine readiness. +2. Call `close_binary` and check its result. It drains owned work, closes the + provider, and clears retained session records. A `cleanup_incomplete` result + must be addressed according to its reported owned resources before retrying. +3. Call `open_binary` with the same caller-selected path and + `provider_id: "ghidra"`, then retry the first query with an appropriate client + deadline. The connection and selected provider do not need to change. + +This close/reopen flow was exercised on one real Linux stdio connection after a +controlled startup timeout, followed by a successful overview and function +analysis. A separate Windows x64 stdio run with Ghidra 12.1.4, JDK 21 and Node +22.19.0 exercised the same connection and caller-selected native PE: the default +60-second client request timed out, close succeeded, and reopening before a +240-second request completed the cold overview in about 163 seconds. The next +overview took about 19 ms. The cold and warm overviews reported two procedures +and two segments; the input digest was unchanged and no owned runtime root or +observed process-family member remained after final close. This was a small +1,024-byte fixture, so the longer request setting remains an example, not a +guarantee for larger targets. No macOS cold-start recovery was exercised. + +With a supplied progress token, that earlier Windows run received an operation-start +notification before timeout and start/completion notifications for the +successful retry, before startup waiting notifications were added. It received +no intermediate import or auto-analysis progress. +These operation markers do not measure analysis work completed or extend the +client's deadline. Each new provider session still imports the target into a +fresh temporary project. + +REA cleans only resources it owns and never switches to another provider +automatically. A provider timeout, installation failure, or host permission +denial needs its own reported recovery; increasing a client deadline alone does +not fix those failures. + +## Aggregate native context + +`get_navigation_context` composes the selected document, current address, and +current/containing procedure. Its capability inventory exposes a +`current_selection` mode and an `explicit_document` mode; the latter works when +the caller supplies `document` and the provider lacks `current_document`. A +cursor outside a procedure is represented as +`procedure: null`. `inspect_address_context` requires an explicit address and +returns name, procedure, comment, inline-comment, and bookmark facets; +unsupported facets are local `unavailable` outcomes. Use `current_document`, +`current_address`, and `current_procedure` for direct single-field lookups; use +the aggregate tools when you need related context together. + ## Integrity record-and-continue Artifact integrity fails closed by default. A request can explicitly select @@ -609,3 +519,110 @@ writing the archive header, so their declared hashes no longer match. Electron does not check unpacked companions against those hashes at runtime. Integrity failures for such entries name this cause and the operation to rerun with `record-and-continue`; REA does not exempt unpacked entries silently. + +## Schema advertisement + +Advertised input and output schemas contain no reachable recursive references. +Schemas share repeated definitions through schema-local references while +preserving complete nested fields and validation rules. Input properties retain +their descriptions and literal examples. + +When a host forwards input schemas to the model, their examples consume context. +REA's advertised examples therefore never copy complete producer Evidence. +An embedded Evidence record is shown as its exact `{"kind":"retained-evidence","evidence_id":"ev_..."}` +reference where the tool accepts one. An example that can only carry inline +Evidence stays in the canonical contract and its executable tests, but is not +advertised. Every advertised example is a distinct valid canonical input. + +Root object unions are presented as +one object without root `anyOf`, `oneOf`, or `allOf` for model API compatibility. +The projection merges properties, retains shared required fields and +group-specific field dependencies, and describes the accepted input groups. +Canonical runtime validation enforces the exact union, including exclusions +that the advertised projection does not express. Tests validate the schemas +after SDK conversion and check advertised validation and actual calls. +Individual model APIs can impose additional nesting limits; complete producer +captures can exceed ten structural levels. + +### Compact input schema profile + +Some function-calling providers reject a request while any single tool's +`parameters` schema exceeds a literal serialized size cap; Moonshot clients +such as kimi-cli fail every request while the default catalog is attached +([#1484](https://github.com/morluto/rea/issues/1484)). Setting the server's +`REA_MCP_INPUT_SCHEMA_PROFILE` environment variable to `compact` renders every +advertised input schema within a 13,312-byte budget, measured to sit below +Moonshot's observed cap (community measurements: a 13.7 KB schema is accepted +while a ~15 KB one is rejected). The setting is read at startup; restart the +server to apply changes, as with `REA_MCP_MAX_RESPONSE_BYTES`. The default +value `full` keeps the complete advertisement unchanged. + +The compact profile renders the same tool set, output schemas, annotations, +and canonical server-side validation. It changes only the advertised input +JSON Schema: + +- Annotation prose leaves the advertised form: nested property descriptions, + literal examples, defaults, and titles are dropped. The root keeps its + description because it states the accepted input groups. +- Schema-local references are inlined within the budget. Kimi Code expands + references before sending provider requests, so sharing definitions cannot + establish the provider-facing size. Expansion stops at the budget before + allocating an oversized presentation. Unconstrained JSON fields advertise + all JSON value types explicitly so Kimi cannot infer string for Evidence + objects or arrays. +- The few schemas whose validation structure alone exceeds the budget + (`compare_web_captures`, `build_reconstruction_obligation_ledger`, + `evaluate_reconstruction_coverage`, `project_managed_application_graph`, + `compare_application_versions`, `capture_browser_scenario`) are advertised + in a reduced form: property names, reference-resolved types (including union + alternatives), first-level guidance, and the root's required-field constraints, + with nested validation detail elided. The + canonical schema still rejects malformed calls server-side, so callers + following the reduced advertisement receive the canonical typed error + instead of silent acceptance. + +Boundary tests pin every advertised compact schema to the budget, keep them +valid JSON Schema that still accepts every canonical example, and hold the +set of six reduced presentations as contracts evolve. Client verification +also checks provider-facing sizes and canonical examples after conversion by +the actual Kimi Code CLI; local captures do not establish Moonshot acceptance. + +### Output schemas + +Self-contained output schemas advertise a content-bound `$id`, including their +declared dialect. SDK validators can reuse compiled schemas across complete +catalog refreshes and equivalent tool outputs; changing the schema changes its +identity. Explicit schema IDs and relative external reference bases are +preserved. This keeps every tool and validation rule in discovery and does not +change the SDK's catalog invalidation or availability checks. + +### Comparison input shapes + +`compare_web_captures` accepts exactly one of two input shapes: + +- Passive: `before` and `after` each contain `inspection`, the complete + `normalized_result` from `inspect_web_page`. Each may also contain `webmcp`, + the complete `normalized_result` from `discover_webmcp_tools`, or null. +- Scenario: `before_scenario` and `after_scenario` contain complete + `normalized_result` objects from `capture_browser_scenario`. Optional + `normalization` defaults to `{ "rules": [] }`. + +The advertised schema includes complete nested capture fields and rejects +incomplete pairs and structurally malformed captures. Mixed comparison families +can pass advertised validation; the SDK rejects them against the canonical +input schema before invoking the handler. Domain validation additionally checks +relationships such as event sequence references and retained counts; JSON +Schema does not express those cross-field invariants. + +## Generated catalog + +Custom clients upgrading from 6.1 should follow the +[6.2 migration guide](migration-6.2.md#mcp-results-and-evidence). + +Run `npm run docs:generate` in a source checkout to generate the machine-readable +catalog at `docs/public/product-catalog.json`. Documentation deployments serve +the same file at [/rea/product-catalog.json](/rea/product-catalog.json). PR CI retains it with the packaged +skill and portable conformance projections in the `generated-docs` artifact. +These outputs describe the exact source revision being built; they are not +checked-in snapshots. For a running server, `binary_session` remains the +authoritative source of catalog identity and tool availability. diff --git a/docs/mcp-prompts.md b/docs/mcp-prompts.md index 3c9167265..6233d9de1 100644 --- a/docs/mcp-prompts.md +++ b/docs/mcp-prompts.md @@ -91,6 +91,12 @@ identifiers only; they do not retrieve or replace the inline Evidence result. Completion sources are live projections of the current session: +Document and procedure completion in a binary session reads an already-ready +provider; it does not start analysis. A cold provider, a target transition, or +unavailable inventory can return no suggestions. Run an analysis query first +when you need inventory from a provider that supplies it. An empty completion +list does not establish that the target has no procedures. + | Argument family | Source and filtering | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | Document | Current provider `list_documents` result. | diff --git a/docs/native-investigation.md b/docs/native-investigation.md index b878b17b1..3627379ad 100644 --- a/docs/native-investigation.md +++ b/docs/native-investigation.md @@ -1,132 +1,32 @@ -# Native UI and dispatch investigation +# Native binary investigation -REA joins static resources, native metadata and code facts while keeping runtime -observations separate. Every result reports its evidence, target identity, -coverage and unknowns. The CLI and MCP use the same application workflows. +Use a native provider to discover functions, inspect instructions and pseudocode, +follow references, and examine database types. Static resources and runtime +observation complement that analysis when they answer a specific question. -## Static inspection +## Start with a function -`inspect_macho.selected_architecture` identifies the exact selected lipo slice -and its `container_file_offset` in the input file. A thin Mach-O has a known -offset of zero; an unknown universal-slice offset stays null. The Evidence -subject format describes the input container: `mach-o-universal` for FAT files, -including those with one slice. The normalized result describes the selected -Mach-O image. Architecture -`file_offset` values are container-relative. Entrypoint, segment and section -`file_offset` values retain their source meaning and are relative to the -selected Mach-O slice. Raw load-command fields retain their original values. -Evidence locations map the LC_MAIN entrypoint and nonempty file-backed segment -ranges to container offsets by adding the observed slice offset. Zero-fill -segments do not produce file ranges. When the selected slice's container offset -is unknown, those mapped locations are omitted with an explicit limitation; -architecture inventory locations remain available. +Choose an installed provider from [setup](installation.md#hopper). For Ghidra: -Hopper's `address_to_file_offset` combines the native image-relative mapping with -original-file coordinates only after checking the source against the session's -SHA-256. FAT tables and embedded Mach-O headers come from that same hashing pass. -A changed or nonregular source reports `artifact_changed`; an unreadable or -missing source reports its access or filesystem failure. Those errors retain the native offset, -loaded header and provider source path in `details.partial_observation`, with the -original-file coordinate explicitly unavailable. Restore the original bytes or -reopen the changed executable to obtain verified coordinates. Snapshot replay -remains historical evidence for its recorded artifact identity. +```bash +rea inspect /absolute/path/to/program --provider ghidra --json +rea search /absolute/path/to/program entry --kind procedures --provider ghidra --json +``` -A selected Hopper database's digest identifies the database rather than its -original executable. Original-file mapping is unavailable for that selection; -native mapping facts remain in partial evidence, and `read_bytes` still reads -the loaded database. Open the original executable to verify source coordinates. +Select an exact name or address from the returned inventory, then use it with +`rea function PATH PROCEDURE --provider ghidra --json` for a function dossier, +`rea instructions` for assembly, or `rea decompile` for pseudocode. Do not assume +that every target names its entry function `entry`. MCP uses `open_binary` and +focused tools such as `list_procedures` and `analyze_function` on the same session. -Native Xcode command execution uses shared process supervision with a 60-second -deadline and a 64 MiB aggregate stdout/stderr budget. Timeout, cancellation, -stream failure, and output exhaustion retain the captured output, exit details, -and cleanup outcome in the error result. Truncated output is never parsed as a -complete observation. - -- `trace_dylib_resolution` / `rea trace-dylib-resolution ` - parses Mach-O load commands in TypeScript and follows dyld's path expansion - for every executable in an app bundle, or for one Mach-O within its directory. - It reports each `@rpath`, `@loader_path` and `@executable_path` candidate with - its outcome. Paths outside the analyzed root, including shared-cache system - libraries, stay undetermined. See - [Apple application analysis](apple-application-analysis.md#dylib-load-resolution). -- `inspect_asset_catalog` / `rea inspect-asset-catalog ` reads compiled - `Assets.car` metadata through macOS `assetutil --info`. Catalog digests, raw - rendition fields, pagination and exact UI resource-name matches are returned. - Image extraction and undocumented rendition interpretation are unsupported. -- `inspect_keyed_archive` / `rea inspect-keyed-archive ` reads XML or - binary Foundation keyed archives without instantiating classes. For an active - app, provide its relative archive path as the second CLI argument or MCP - `path`. Results retain original `$objects` indices, named `$top` roots, - shared/cyclic references, class descriptors, raw serialized fields and - malformed/unresolved/nil references. Missing fields stay absent; unknown - classes are preserved. Select `root`, `offset` and `limit` explicitly. - UID 0 cannot distinguish conditional nil from ordinary nil. Limits are - 64 MiB of input, 200,000 objects/references and 128 nesting levels. - XML dictionary entries decoded as `__proto__` are omitted with an explicit - count because REA results cannot represent that key. XML tag whitespace and - comments do not change that handling. Other values and the original archive - digest are preserved; key interpretation follows the pinned plist decoder. -- `decode_interface_builder` / `rea decode-interface-builder ` reads - compiled storyboard and nib resources into objects, outlets, actions, - connections and controller/class names. `verify:interface-builder` compiles - a source-owned AppKit XIB with `ibtool`. Storyboards require an installed - iOS platform; unsupported archive forms remain explicit. - XML plist archives accept UTF-8 and BOM-marked UTF-16 in either byte order. - App bundle `Info.plist` executable resolution uses the same decoder as keyed - archives and Interface Builder. The decoder consumes an initial - BOM and rejects malformed byte sequences, unsupported encoding declarations, - and declarations that disagree with the detected encoding. It never substitutes - UTF-8 for a declared encoding it cannot process. Archive and evidence digests - still identify the original serialized bytes. Bundle resolution reports - malformed bytes and unsupported encodings against the original plist path - before looking up the executable. Interface Builder decoding - limits aggregate input archives to 32 MiB. - Before decoding, it also bounds the serialized structure: expanded binary - plist references, NIB table records, XML elements and text, plus their - projected representations must fit the 256 MiB aggregate decode budget. - NIB string values, data, property names and class names are charged at each - projected JSON occurrence, including when the archive reuses one source - value. Binary plist data projection also accounts for the temporary byte - copy made by the pinned decoder projection. These are format-derived - representation reservations, not exact heap measurements or a process-wide - heap ceiling. - Archives beyond either aggregate budget are omitted with their paths and an - explicitly partial `archive_decode` facet; previously decoded documents and - their identities remain available. -- `inspect_native_dispatch_metadata` / - `rea inspect-native-dispatch-metadata ` prefers a validated macOS Mach-O byte reader. It decodes - 64-bit little-endian Objective-C class/metaclass records, superclass pointers, - absolute/relative method entries, ivar offsets/sizes/alignment and protocol - declarations. It also decodes simple Swift conformances, static synchronous - witness slots, signed-relative pointers and non-generic, non-resilient class - vtable descriptors. Records include exact virtual addresses/file offsets and - artifact evidence. Vtable indexes are metadata word offsets; witness indexes - start after the conformance header. Names unavailable in metadata remain null. - Pointers are decoded through the image's fixups: - - `LC_DYLD_CHAINED_FIXUPS` rebases and binds, including the authenticated - arm64e formats; - - legacy `LC_DYLD_INFO` bind opcodes. - - So an external superclass resolves from its `_OBJC_CLASS_$_` bind (for - example `NSObject`). The `pointer_fixups` coverage facet names the mechanism. - Class properties preserve each encoded attribute as a raw `{name, value}` - pair, for example `{ name: "N", value: "" }`, and report atomicity on the - property: `N` means `nonatomic`; a complete typed attribute string without - `N` means the Objective-C default `atomic`; - missing or incomplete attribute metadata leaves `atomicity` and any - unestablished read-only value null. `is_meta_class`, `is_root_class`, and - `ivar_count` are also nullable when the selected provider exposes only symbol - names. Class implementation methods have null `is_required` and `is_optional` - fields because those facts apply to protocol declarations; decoded protocol - method lists retain their observed required/optional values. Class properties - and `__objc_catlist` categories are also decoded. Categories record the - extended class, local or external, plus - their methods, protocols and properties; category methods appear as - implementations with a `category`. Swift field-offset globals that are only - initialized at runtime stay unresolved. Generic, resilient, async and - coroutine tables, and inherited overrides, have explicit unsupported or - partial coverage. Other providers retain the - existing symbol-based inventory with its narrower coverage. +| Question | Section | +| ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | +| Which instructions, calls, references, or types are present? | [Native primitives](#native-instruction-call-and-type-primitives) | +| How can I select a name beginning with a dash? | [CLI selectors](#exact-cli-selectors) | +| What static path connects these functions? | [Bounded traces](#bounded-static-traces) | +| Which UI resources or dispatch metadata are present? | [Static inspection](#static-inspection) | +| What did the declared runtime scenario observe? | [Desktop](#native-desktop-observation) or [call observation](#native-call-observation) | +| What can this provider and host establish? | [Provider boundaries](#provider-and-verification-boundaries) | ## Exact CLI selectors @@ -272,6 +172,37 @@ array semantics are not inferred. The real lane uses a native DWARF 4 object with a struct containing a union, enum and recursive pointer; a stripped linked binary may have no corresponding recovered layout. +Ghidra serializes at most 20,000 fields or enum members per inspected type. +Check `total_fields` and `truncated` before treating the returned layout as +complete. These fields describe omissions from the response, independently of +whether Ghidra recovered the original source layout. + +### Hopper analysis behavior + +Cursor navigation returns the observed object start when Hopper snaps an interior +address; adjacent-object navigation rejects unmapped inputs and document ends. +Native API text rejects NUL characters and unpaired Unicode surrogates before +annotation changes. Renames preserve unselected label owners; use a batch with +all affected addresses to move or swap existing labels explicitly. Every rename +destination must be mapped, and native symbol names must fit Hopper's 1024 UTF-16 +code-unit limit. Oversized names fail before any batch edits; bookmarks and +literal string results are not subject to that symbol-name limit. Rename success +requires exact final readback. New bookmarks must point into mapped memory; +existing legacy bookmarks outside it can still be removed. +String results read each native typed object's complete bytes, retain the original +provider display in `provider_value`, and report its encoding, byte length, and +termination. `encoding_status: inferred` distinguishes REA's decoding from an +observed source encoding. Hopper can split long literals into adjacent +unterminated objects; search matches each object's decoded bytes independently. +Undecodable objects retain native display text with `decoding.available: false` +and a reason, so one uncertain object does not block unrelated inspections. +Function dossiers retain this same string evidence. Native call edges retain +Hopper's partial `CallReference` classification and exact endpoints; detailed +reference flags remain unavailable rather than being invented. +Regex searches use ECMAScript Unicode syntax in a cancellable worker with a +five-second matching deadline. Deadline or cancellation stops matching while +leaving the Hopper API available. Literal mode retains Unicode casefold matching. + ## Bounded static traces `trace_native_ui_action` / `rea trace-native-ui-action ` accepts @@ -322,6 +253,130 @@ scaled ADD/BR instructions and the recovered target set. It reads exactly the proven count and preserves unknowns for other forms. Real ELF and host ARM64 Mach-O fixtures check each case against source-owned return values. +## Static inspection + +`inspect_macho.selected_architecture` identifies the exact selected lipo slice +and its `container_file_offset` in the input file. A thin Mach-O has a known +offset of zero; an unknown universal-slice offset stays null. The Evidence +subject format describes the input container: `mach-o-universal` for FAT files, +including those with one slice. The normalized result describes the selected +Mach-O image. Architecture +`file_offset` values are container-relative. Entrypoint, segment and section +`file_offset` values retain their source meaning and are relative to the +selected Mach-O slice. Raw load-command fields retain their original values. +Evidence locations map the LC_MAIN entrypoint and nonempty file-backed segment +ranges to container offsets by adding the observed slice offset. Zero-fill +segments do not produce file ranges. When the selected slice's container offset +is unknown, those mapped locations are omitted with an explicit limitation; +architecture inventory locations remain available. + +Hopper's `address_to_file_offset` combines the native image-relative mapping with +original-file coordinates only after checking the source against the session's +SHA-256. FAT tables and embedded Mach-O headers come from that same hashing pass. +A changed or nonregular source reports `artifact_changed`; an unreadable or +missing source reports its access or filesystem failure. Those errors retain the native offset, +loaded header and provider source path in `details.partial_observation`, with the +original-file coordinate explicitly unavailable. Restore the original bytes or +reopen the changed executable to obtain verified coordinates. Snapshot replay +remains historical evidence for its recorded artifact identity. + +A selected Hopper database's digest identifies the database rather than its +original executable. Original-file mapping is unavailable for that selection; +native mapping facts remain in partial evidence, and `read_bytes` still reads +the loaded database. Open the original executable to verify source coordinates. + +Native Xcode command execution uses shared process supervision with a 60-second +deadline and a 64 MiB aggregate stdout/stderr budget. Timeout, cancellation, +stream failure, and output exhaustion retain the captured output, exit details, +and cleanup outcome in the error result. Truncated output is never parsed as a +complete observation. + +- `trace_dylib_resolution` / `rea trace-dylib-resolution ` + parses Mach-O load commands in TypeScript and follows dyld's path expansion + for every executable in an app bundle, or for one Mach-O within its directory. + It reports each `@rpath`, `@loader_path` and `@executable_path` candidate with + its outcome. Paths outside the analyzed root, including shared-cache system + libraries, stay undetermined. See + [Apple application analysis](apple-application-analysis.md#dylib-load-resolution). +- `inspect_asset_catalog` / `rea inspect-asset-catalog ` reads compiled + `Assets.car` metadata through macOS `assetutil --info`. Catalog digests, raw + rendition fields, pagination and exact UI resource-name matches are returned. + Image extraction and undocumented rendition interpretation are unsupported. +- `inspect_keyed_archive` / `rea inspect-keyed-archive ` reads XML or + binary Foundation keyed archives without instantiating classes. For an active + app, provide its relative archive path as the second CLI argument or MCP + `path`. Results retain original `$objects` indices, named `$top` roots, + shared/cyclic references, class descriptors, raw serialized fields and + malformed/unresolved/nil references. Missing fields stay absent; unknown + classes are preserved. Select `root`, `offset` and `limit` explicitly. + UID 0 cannot distinguish conditional nil from ordinary nil. Limits are + 64 MiB of input, 200,000 objects/references and 128 nesting levels. + XML dictionary entries decoded as `__proto__` are omitted with an explicit + count because REA results cannot represent that key. XML tag whitespace and + comments do not change that handling. Other values and the original archive + digest are preserved; key interpretation follows the pinned plist decoder. +- `decode_interface_builder` / `rea decode-interface-builder ` reads + compiled storyboard and nib resources into objects, outlets, actions, + connections and controller/class names. `verify:interface-builder` compiles + a source-owned AppKit XIB with `ibtool`. Storyboards require an installed + iOS platform; unsupported archive forms remain explicit. + XML plist archives accept UTF-8 and BOM-marked UTF-16 in either byte order. + App bundle `Info.plist` executable resolution uses the same decoder as keyed + archives and Interface Builder. The decoder consumes an initial + BOM and rejects malformed byte sequences, unsupported encoding declarations, + and declarations that disagree with the detected encoding. It never substitutes + UTF-8 for a declared encoding it cannot process. Archive and evidence digests + still identify the original serialized bytes. Bundle resolution reports + malformed bytes and unsupported encodings against the original plist path + before looking up the executable. Interface Builder decoding + limits aggregate input archives to 32 MiB. + Before decoding, it also bounds the serialized structure: expanded binary + plist references, NIB table records, XML elements and text, plus their + projected representations must fit the 256 MiB aggregate decode budget. + NIB string values, data, property names and class names are charged at each + projected JSON occurrence, including when the archive reuses one source + value. Binary plist data projection also accounts for the temporary byte + copy made by the pinned decoder projection. These are format-derived + representation reservations, not exact heap measurements or a process-wide + heap ceiling. + Archives beyond either aggregate budget are omitted with their paths and an + explicitly partial `archive_decode` facet; previously decoded documents and + their identities remain available. +- `inspect_native_dispatch_metadata` / + `rea inspect-native-dispatch-metadata ` prefers a validated macOS Mach-O byte reader. It decodes + 64-bit little-endian Objective-C class/metaclass records, superclass pointers, + absolute/relative method entries, ivar offsets/sizes/alignment and protocol + declarations. It also decodes simple Swift conformances, static synchronous + witness slots, signed-relative pointers and non-generic, non-resilient class + vtable descriptors. Records include exact virtual addresses/file offsets and + artifact evidence. Vtable indexes are metadata word offsets; witness indexes + start after the conformance header. Names unavailable in metadata remain null. + Pointers are decoded through the image's fixups: + - `LC_DYLD_CHAINED_FIXUPS` rebases and binds, including the authenticated + arm64e formats; + - legacy `LC_DYLD_INFO` bind opcodes. + + So an external superclass resolves from its `_OBJC_CLASS_$_` bind (for + example `NSObject`). The `pointer_fixups` coverage facet names the mechanism. + Class properties preserve each encoded attribute as a raw `{name, value}` + pair, for example `{ name: "N", value: "" }`, and report atomicity on the + property: `N` means `nonatomic`; a complete typed attribute string without + `N` means the Objective-C default `atomic`; + missing or incomplete attribute metadata leaves `atomicity` and any + unestablished read-only value null. `is_meta_class`, `is_root_class`, and + `ivar_count` are also nullable when the selected provider exposes only symbol + names. Class implementation methods have null `is_required` and `is_optional` + fields because those facts apply to protocol declarations; decoded protocol + method lists retain their observed required/optional values. Class properties + and `__objc_catlist` categories are also decoded. Categories record the + extended class, local or external, plus + their methods, protocols and properties; category methods appear as + implementations with a `category`. Swift field-offset globals that are only + initialized at runtime stay unresolved. Generic, resilient, async and + coroutine tables, and inherited overrides, have explicit unsupported or + partial coverage. Other providers retain the + existing symbol-based inventory with its narrower coverage. + ## Native desktop observation `observe_native_ui` captures one explicitly selected existing PID/window ID. diff --git a/docs/process-capture.md b/docs/process-capture.md index 198ca264d..35e818f31 100644 --- a/docs/process-capture.md +++ b/docs/process-capture.md @@ -40,7 +40,17 @@ this helper before reporting macOS capture as available. ## Capture a command -Write a JSON scenario and pass its path to the CLI: +For a small first capture, save this as `scenario.json`: + +```json +{ + "executable": "node", + "arguments": ["-e", "console.log('ready')"], + "timeout_ms": 5000 +} +``` + +Run the scenario through the CLI: ```sh rea capture-process ./scenario.json --json > capture.json @@ -51,6 +61,85 @@ format is TOON. The file contains the complete capture Evidence record. Choose an output file distinct from the scenario input: shell redirection opens and truncates the output before REA reads the scenario. +Read the result's terminal observations, exit/settlement status, and cleanup +outcome. [Scenario and result details](#scenario-and-result-details) describe +limits, normalization, filesystem coverage, and incomplete observations. + +## Compare two captures + +Compare saved capture Evidence with: + +```sh +rea compare-process-captures authority.json reconstruction.json +``` + +The comparison checks terminal, interaction, exit, filesystem, and +process observations under a shared comparison contract. It reports observed +differences with their locations, while residual unknowns or truncated +observations prevent a complete-equivalence claim. Matching scenario +commitments do not reveal whether redacted sensitive inputs were equal. + +For scenarios where independent scheduling can change event order, the CLI +also accepts an optional trace-specification JSON file as the third argument. +That specification must state the exact events and ordering constraints to +accept; it does not discard unmatched observations or make timestamps into +causal evidence. Trace comparison returns `unknown` when a capture lacks the +required complete event journal or contains relevant residual unknowns. + +Each capture carries commitments for the selected scenario, executable, +comparison contract, and normalization rules. The comparison contract covers +the working directory, explicit environment, filesystem observation paths, +terminal size, scripted events, timeouts, limits, and normalization; the +executable and its arguments may differ. Comparison rejects captures whose +comparison contracts differ and names the differing fields, so run both +scenarios from the same absolute working directory and observation paths. +Captures are local Evidence files; keep +their source artifacts and invocation context available when interpreting a +difference. + +## Hash a report independently of terminal output + +Select the producer's report directory and give `file_bytes` enough room for +the complete files you need, including other files in those roots. For example, +save this scenario and run `rea capture-process ./scenario.json --json > capture.json`: + +```json +{ + "executable": "node", + "arguments": [ + "-e", + "const fs=require('node:fs');fs.mkdirSync('reports',{recursive:true});fs.writeFileSync('reports/final.json',JSON.stringify({status:'complete',data:'X'.repeat(131072)}));console.log('x'.repeat(8192));" + ], + "working_directory": ".", + "filesystem_observation_paths": ["./reports"], + "limits": { "output_bytes": 1024, "file_bytes": 262144 } +} +``` + +The report exceeds the terminal budget but fits the independent 256 KiB hash +budget. Its complete SHA-256 appears in `normalized_result.files_after` at +`root_0:final.json`; check `truncation_details.filesystem_after` for omissions +and actual bytes hashed. The verbose terminal output is truncated without +preventing the report digest. The same scenario object is the MCP +`capture_process_scenario` input. REA never returns a prefix hash as a full-file +digest: an insufficient remaining budget produces a null digest and an +explicit omission reason. + +A digest binds the complete bytes observed at that checkpoint, not the +producer's notion of a finished report. A stable periodic or running report +can also have a complete digest. Choose the final file and verify the +producer's documented completion marker, exit outcome and settlement +observations before calling it final. `after_settlement` names a filesystem +checkpoint, not a guarantee that an application finished successfully or +that an unobserved writer will never change the file. REA checks opened-file +identity/state around hashing and reports observed changes or unavailable +files; cancellation stops the hash. If an external sealer produces a manifest, +keep its completion claims and digest separate from REA's checkpoint facts. + +## Scenario and result details + +### Progress + While the capture runs, REA writes live status to stderr as one JSON object per line. Stdout stays the final Evidence document: @@ -79,7 +168,7 @@ into the latest status, and stale live observations are discarded before final cleanup status. Progress never copies child output. Child output remains in the capture Evidence on stdout. -For example: +### Scenario with interactions ```json { @@ -327,74 +416,3 @@ while its token became unavailable after this change; npm changes its title as well. A newly started unreadable process can prevent verified cleanup even after the selected command exits. REA preserves this uncertainty and leaves that process untouched. - -## Hash a report independently of terminal output - -Select the producer's report directory and give `file_bytes` enough room for -the complete files you need, including other files in those roots. For example, -save this scenario and run `rea capture-process ./scenario.json --json > capture.json`: - -```json -{ - "executable": "node", - "arguments": [ - "-e", - "const fs=require('node:fs');fs.mkdirSync('reports',{recursive:true});fs.writeFileSync('reports/final.json',JSON.stringify({status:'complete',data:'X'.repeat(131072)}));console.log('x'.repeat(8192));" - ], - "working_directory": ".", - "filesystem_observation_paths": ["./reports"], - "limits": { "output_bytes": 1024, "file_bytes": 262144 } -} -``` - -The report exceeds the terminal budget but fits the independent 256 KiB hash -budget. Its complete SHA-256 appears in `normalized_result.files_after` at -`root_0:final.json`; check `truncation_details.filesystem_after` for omissions -and actual bytes hashed. The verbose terminal output is truncated without -preventing the report digest. The same scenario object is the MCP -`capture_process_scenario` input. REA never returns a prefix hash as a full-file -digest: an insufficient remaining budget produces a null digest and an -explicit omission reason. - -A digest binds the complete bytes observed at that checkpoint, not the -producer's notion of a finished report. A stable periodic or running report -can also have a complete digest. Choose the final file and verify the -producer's documented completion marker, exit outcome and settlement -observations before calling it final. `after_settlement` names a filesystem -checkpoint, not a guarantee that an application finished successfully or -that an unobserved writer will never change the file. REA checks opened-file -identity/state around hashing and reports observed changes or unavailable -files; cancellation stops the hash. If an external sealer produces a manifest, -keep its completion claims and digest separate from REA's checkpoint facts. - -## Compare two captures - -Compare saved capture Evidence with: - -```sh -rea compare-process-captures authority.json reconstruction.json -``` - -The comparison checks terminal, interaction, exit, filesystem, and -process observations under a shared comparison contract. It reports observed -differences with their locations, while residual unknowns or truncated -observations prevent a complete-equivalence claim. Matching scenario -commitments do not reveal whether redacted sensitive inputs were equal. - -For scenarios where independent scheduling can change event order, the CLI -also accepts an optional trace-specification JSON file as the third argument. -That specification must state the exact events and ordering constraints to -accept; it does not discard unmatched observations or make timestamps into -causal evidence. Trace comparison returns `unknown` when a capture lacks the -required complete event journal or contains relevant residual unknowns. - -Each capture carries commitments for the selected scenario, executable, -comparison contract, and normalization rules. The comparison contract covers -the working directory, explicit environment, filesystem observation paths, -terminal size, scripted events, timeouts, limits, and normalization; the -executable and its arguments may differ. Comparison rejects captures whose -comparison contracts differ and names the differing fields, so run both -scenarios from the same absolute working directory and observation paths. -Captures are local Evidence files; keep -their source artifacts and invocation context available when interpreting a -difference. diff --git a/docs/testing.md b/docs/testing.md index 5df9c4d9e..ec065b14d 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -1,8 +1,141 @@ # Testing REA Use this guide when choosing coverage, pruning tests, or running a verification -lane. For commands, jump to [developer commands](#developer-commands); for engine -prerequisites, use [real-toolchain lanes](#real-toolchain-verification-lanes). +lane. Start with the commands below; use [real-toolchain lanes](#real-toolchain-verification-lanes) +for engine prerequisites and [client verification](client-verification.md) for +installed-client and agent runs. + +## Developer commands + +Use source feedback while editing, explicit boundary checks for the changed +behavior, and complete CI evidence before merging. + +| Command | Scope | +| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `npm run test:local` | Dirty source tests via the import graph, without build; explicit source paths run regardless of Git status | +| `npm run test:focused -- PATH...` | Exact existing test files; compiled boundaries build first, and unmatched paths fail | +| `npm run test:changed` | Source tests affected since the merge base with `origin/main`, including committed and dirty changes | +| `npm run test:fast` | All domain, service, adapter, composition, conformance, and evaluation tests without build | +| `npm run test:boundary` | Boundary, CLI boundary, MCP boundary, process boundary, and process-global projects | +| `npm run test:mcp` | MCP boundary project | +| `npm run test:acceptance` | Complete compiled CLI and MCP acceptance workflows | +| `npm run test:watch` | Dirty source tests in watch mode, without build | +| `npm run test:watch:all` | Changed tests from every project; builds at startup, so rebuild after production edits before relying on compiled tests | +| `npm run check:changed` | Cached typecheck/lint and branch-related source feedback | +| `npm run check:pr` | Opt-in complete local deterministic gate and generated-file checks | +| `npm run docs:check` | Generated-document validation from current source and build outputs | + +For example: + +```bash +npm run test:local -- src/config.test.ts +npm run test:focused -- tests/acceptance/applications/runtime.test.ts +npm run test:changed -- --base origin/main +npm run test:changed -- --dry-run +``` + +`test:focused` accepts exact repository-relative test file paths. Source-only +paths do not build; boundary, acceptance, process-global, or unfamiliar `tests/` +paths build conservatively. Tests use Vitest concurrency and isolated +workspaces; commands do not hold a broad test lock. Build and documentation +writers retain checkout-local locks for their shared output files. Explicit +selections do not use `--changed` or permit zero-test success. +The dry-run option reports the chosen merge base, scope and build prerequisite +without executing tests or building. A missing Git base reports how to fetch +it or select another revision. + +Source typechecking needs no compiled runtime or generated test metadata. +`npm run build:cached` compiles the CLI/MCP runtime and its packaged skill. +Turbo's strict task environment preserves caller-selected `GOMAXPROCS`, +`GOMEMLIMIT`, and `UV_THREADPOOL_SIZE` for resource-constrained builds and +checks. These execution controls do not change artifact content, so changing +their values retains cache reuse. They control individual runtimes; monitor +the complete process family separately when enforcing a total memory budget. +`npm run test:prepare` also generates the MCP contract test catalog, product +catalog, and portable managed evidence used by the complete suite. Focused +tests prepare those extra outputs only when their selected files consume them. +The MCP test catalog is JSON in `.cache/mcp-tool-catalog.json`; the tracked +test loader supplies its types without making generation a source-check +prerequisite. Run `npm run mcp-catalog:generate` to refresh it independently. +Documentation generation and managed conformance run through their separate +`docs:generate` and `evidence:generate` task graphs. + +Changed selection can miss runtime registration, generated data, shell +entrypoints, bridges, or other relationships absent from the import graph. +An empty changed selection means no tests were selected, not verified +correctness. Select relevant boundary files and real-provider lanes explicitly. +Source projects also contain large capacity regressions; `test:fast` promises +no compiled-runtime prerequisite, not a fixed time budget. + +Routine iterations and rebases need focused regressions and relevant checks. +Before handing off a PR, run `npm run check` and generated-document checks when +applicable; CI owns the full suite and coverage. Use the full local gate for +broad changes or diagnosing CI, rather than after every edit. Package/install +changes additionally need package verification; provider changes need actual +provider evidence. + +Vitest projects use up to two workers, bounded by host parallelism. +`process-boundary` runs later with serial files because process-tree sampling +shares host resources. Acceptance and process-global cases use isolated forks +without serial scheduling. Pure domain/service, composition, conformance, +evaluation, CLI boundary, and MCP boundary projects share module graphs. Their +tests avoid process-global state and keep resource cleanup test-scoped. Each +MCP session still owns its resources, and CLI cases retain fresh command +instances or subprocesses. CLI module mocks belong in `tests/process-global/` +so they keep per-file isolation. Product catalog verification stays with the +isolated filesystem boundary tests because it loads both source and compiled +module graphs. Adapter, other boundary, acceptance, and process-global projects +retain per-file isolation. See `vitest.config.ts` for current settings. + +The reused CLI boundary workers cap V8 old space at 384 MiB, based on their +profiled allocation and cleanup behavior. This encourages collection between +files; spawned REA processes retain their own heap settings. + +Vitest worker limits do not bound subprocesses launched within a test. Bound +those batches separately so repeated CLI validation cannot oversubscribe the +runner. Preserve simultaneous launches where concurrency is itself under test. + +Build/documentation writers hold checkout-local output locks. Tests do not +hold a broad command lock; `check:pr` finishes tests before document validation. + +Vitest's persistent compile cache remains disabled. The `cliTest` fixture shares +a temporary Node compile cache among its fresh CLI subprocesses. The worker +removes it after test-scoped processes finish. Explicit child environment +settings take precedence; children requesting `NODE_V8_COVERAGE` do not receive +the fixture cache. These subprocesses are outside aggregate Vitest coverage; +subprocess coverage attachment remains disabled. Cold-start import checks launch +independently without this fixture cache. + +The Apple artifact verifier step shares a job-temporary bytecode cache among +its fresh CLI/MCP children via `REA_ARTIFACT_NODE_COMPILE_CACHE`. The artifact +helper maps this setting to child `NODE_COMPILE_CACHE`; npm, Turbo, and nested +Vitest runs do not inherit that setting. Explicit `NODE_COMPILE_CACHE` takes +precedence, and coverage collection or `NODE_DISABLE_COMPILE_CACHE=1` disables +the helper's cache. The cache is discarded with the CI job. + +To evaluate persistent compile caching for repeated local runs, opt in for both +cold and warm measurements with an isolated cache: + +```bash +NODE_COMPILE_CACHE=.cache/node-compile npm test +``` + +Do not report the warm result as a cold-suite improvement, and do not enable +the cache in coverage or benchmark CI without first showing that its +instrumentation remains equivalent. + +## Choose verification for the change + +| Change or claim | First check | Additional coverage | +| ----------------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------- | +| Source semantics | `npm run test:local -- PATH...` | Relevant boundary cases when the behavior crosses a port | +| CLI/MCP workflow | `npm run test:focused -- PATH...` | Actual public calls; an injected provider has limited scope | +| Documentation or generated metadata | `npm run docs:check` | `npm run docs:build` for rendered pages and links | +| Engine adapter | Its real-provider lane below | Host, version, target identity, and owned cleanup | +| Client configuration or schema conversion | [Native client lane](client-verification.md) | Distinguish loopback models from live services | +| Agent investigation quality | [Agent evaluation](#agent-evaluation-and-conformance-records) | Review transcript and scenario-specific evidence | + +## Test design and pruning Prefer real public CLI/MCP workflows, then production-boundary integration, then goldens captured from real producers. Keep module tests for distinct @@ -93,372 +226,52 @@ entrypoint and include its verifier/fixture files in their cache inputs. ## End-to-end, integration and golden evidence -The optional `verify:qwen-client`, `verify:pi-client`, and `verify:hermes-client` -lanes require an installed native client. Select its executable with -`REA_VERIFY_QWEN_COMMAND`, `REA_VERIFY_PI_COMMAND`, or `REA_VERIFY_HERMES_COMMAND`. -They configure disposable profiles through the public REA CLI, preserve caller -settings and backups, and exercise real stdio MCP calls and skill loading. The -`call` mode checks complete catalog discovery and actual JavaScript Evidence; -pass `-- chat` to check plain chat with REA enabled. Qwen also reads the full -result that its client offloads, and Pi exercises default codemode execution. -Use `REA_VERIFY_RUNTIME_ROOT` to select a production-only installed REA package. -Receipts retain client versions, result digests, host coverage and owned-process -cleanup. These POSIX lanes use a deterministic loopback model, so they do not -prove live model-provider or native Windows compatibility. Qwen, Pi and Hermes -bind both `HOME` and `USERPROFILE` to the disposable account. Qwen and Pi discover -the shared personal skill through their default search paths without an explicit -skill setting; Hermes discovers it through the selected `HERMES_HOME`. -Set `REA_VERIFY_HERMES_STICKY_PROFILE=1` to exercise native Hermes selection of -a named sticky profile with `HERMES_HOME` still pointing to its root. +Prefer the public CLI or MCP workflow when it can observe the required behavior. +Use production-boundary integration for contracts the complete workflow cannot +reliably exercise, and producer goldens for format-specific facts. An acceptance +case with an injected provider verifies that integration boundary; it does not +establish real-provider behavior. -`verify:gemini-client` requires an installed Gemini CLI (verified with -`@google/gemini-cli@0.63.0` on POSIX and native Windows); select it with -`REA_VERIFY_GEMINI_COMMAND`. A selected `.js`, `.mjs` or `.cjs` entry point runs -under the verifier's Node. On Windows, select the npm install's -`node_modules/@google/gemini-cli/bundle/gemini.js`, because only a `gemini.cmd` -shim reaches `PATH`. -The optional lane uses native `GEMINI_CLI_HOME` discovery in an isolated -Git project, checks setup plans, backups and idempotence, activates the installed -personal skill, validates all forwarded input JSON Schemas against their declared -dialect, forwards the complete REA catalog and checks full JavaScript -Evidence for a Unicode path. Use `-- chat` for ordinary chat with REA enabled, -or `REA_VERIFY_RUNTIME_ROOT` for a production-only installed REA package. -The local fixture exercises the real Gemini API adapter, including its -`untrusted_context` tool-result envelope. Token counts are synthetic; live -Google API compatibility remains unverified. The lane disables -the client's memory-based relaunch to preserve the caller's Node heap budget. +For installed-client versions, executable selectors, disposable profiles, model +fixtures, and detailed receipts, see [client verification](client-verification.md#end-to-end-integration-and-golden-evidence). +Use [real-toolchain lanes](#real-toolchain-verification-lanes) for engines and +[agent evaluation](#agent-evaluation-and-conformance-records) for investigation +quality. Report unavailable tools or authority explicitly and verify owned +cleanup before claiming success. -`verify:opencode-client` requires an installed OpenCode (verified with -`opencode-ai@1.18.35`); select it with `REA_VERIFY_OPENCODE_COMMAND`. -The optional POSIX lane configures isolated XDG roots and `OPENCODE_CONFIG_DIR`, -checks setup plans, backups, preserved JSONC comments and idempotence, activates -the installed skill, validates all forwarded input schemas and verifies complete -JavaScript Evidence for a Unicode path. JSONC is the default fixture; set -`REA_VERIFY_OPENCODE_CONFIG_FORMAT=json` for JSON. Use `-- chat` for ordinary -chat or `REA_VERIFY_RUNTIME_ROOT` for a production-only installed package. -The native core runs with external plugins disabled through `OPENCODE_PURE`; -the local OpenAI-compatible fixture has a caller-declared one-million-token -context and synthetic usage. Skills use an explicit isolated `skills.paths` -directory, so default OS-home discovery remains unverified. Live model APIs and -native Windows are also unverified. +## Coverage and timing -`verify:claude-client` requires installed Claude Code (verified with -`@anthropic-ai/claude-code@2.1.296` on POSIX and native Windows); select it -with `REA_VERIFY_CLAUDE_COMMAND`. On Windows, select -`claude.exe`: npm installs put only a `claude.cmd` shim on `PATH`, and the real -executable is under `node_modules/@anthropic-ai/claude-code/bin`. -The optional lane uses native `CLAUDE_CONFIG_DIR` discovery, an independent -Git workspace, user settings and default built-in tools. It preserves caller -preferences and backups, checks idempotent setup, waits through the native -`WaitForMcpServers` tool when discovery is pending, and validates the complete -catalog and forwarded input schemas. Call mode loads the personal skill through -native `Skill`, checks its full body and verifies named-schema JavaScript Evidence -for a Unicode path. Use `-- chat` for ordinary chat with REA enabled, or -`REA_VERIFY_RUNTIME_ROOT` for a production-only installed package. The local -Anthropic Messages/SSE fixture preserves native resource-hint envelopes in its -request artifacts. Usage is synthetic; live Anthropic API and bare-mode -personal-skill activation remain unverified by this lane. +CI owns coverage; aggregate and domain/contract thresholds are maintained in +`vitest.config.ts`. They are glob-specific and never updated automatically. +Coverage does not replace named boundary or real-provider scenarios. -`verify:copilot-client` requires installed GitHub Copilot CLI (verified with -`@github/copilot@1.0.95`); select it with `REA_VERIFY_COPILOT_COMMAND`. -The optional POSIX lane uses native `COPILOT_HOME` discovery, an independent -Git workspace, guarded setup plans, preserved registrations, backups and -idempotence. Native `skill add` registers the isolated installed skill; call -mode loads its full body, validates all forwarded input schemas and checks -named-schema JavaScript Evidence for a Unicode path. When Copilot spills a -large MCP result, the model requests native `view` with `forceReadLargeFiles` -and validates the complete returned Evidence rather than its preview. -Use `-- chat` for ordinary -chat or `REA_VERIFY_RUNTIME_ROOT` for a production-only installed package. -The native offline BYOK adapter uses a loopback OpenAI completions/SSE fixture -and `gpt-5.4` model metadata; model inference and token usage are synthetic. -Set `REA_VERIFY_COPILOT_MODEL` to examine another client model ID and -`REA_VERIFY_COPILOT_WIRE_MODEL` for its backend model name (defaults to the client -ID). Every actual HTTP request's model is checked and recorded separately. -Both `HOME` and `USERPROFILE` point to the disposable account; native `skill add` -still selects the installed skill directory explicitly. +CI runs six native Vitest shards without retries. Each shard emits a blob +report; the merge job produces aggregate coverage plus JUnit and JSON timing +reports, uploads them together, and writes the slowest files to the workflow +summary. Static checks, documentation, build, package verification, and +real-system lanes remain separate jobs so one kind of evidence cannot stand in +for another. -The same native client passed full-profile chat and analysis with the actual -wire model `gpt-4.1` under a distinct BYOK model ID: +The build job saves portable Turbo outputs across runs. Eight Linux real-system +lanes restore this cache without waiting for the build job. The shared action +derives its key from `test:prepare --dry=json` task hashes, runner OS and +architecture, and `.npmrc`; test-only changes can reuse compiled outputs. Every +build and verification command still runs, so Turbo checks task inputs and +rebuilds misses. There is no prefix fallback to accumulate older build outputs. -```bash -REA_VERIFY_COPILOT_MODEL=rea-gpt-4.1 REA_VERIFY_COPILOT_WIRE_MODEL=gpt-4.1 npm run verify:copilot-client -- chat -REA_VERIFY_COPILOT_MODEL=rea-gpt-4.1 REA_VERIFY_COPILOT_WIRE_MODEL=gpt-4.1 npm run verify:copilot-client -- call -``` +Native package jobs, the Windows curated lane, and the Apple artifact lane reuse +the same workflow's Turbo cache for portable compiled JavaScript, skills, and +catalogs. The Windows lane relies on the Linux static job for typechecking. They retain the normal build and prepack +commands, which restore matching outputs or rebuild on a cache miss. Native +artifacts, dependency installs, package archives, and runtime verification remain +host-local. Keep platform-dependent outputs out of this shared cache. -These runs retain full canonical input/output schemas, all tools, installed-skill -loading and complete Evidence readback. They use the fixture's requested -one-million-token BYOK prompt setting; effective capacity and live API acceptance -remain unknown. With the built-in `gpt-4.1` model ID, the verified client still -blocks the full input-schema profile before HTTP with -`compaction_static_context_blocked`, even when requesting a larger BYOK prompt -capacity. The effective capacity is unknown. The default verifier preserves -the complete catalog and full schemas. To verify the existing compact profile: - -```bash -REA_VERIFY_COPILOT_MODEL=gpt-4.1 REA_VERIFY_COPILOT_SCHEMA_PROFILE=compact npm run verify:copilot-client -- chat -REA_VERIFY_COPILOT_MODEL=gpt-4.1 REA_VERIFY_COPILOT_SCHEMA_PROFILE=compact npm run verify:copilot-client -- call -``` - -Both native workflows passed with the complete tool inventory. The verifier selects the -profile only in its disposable Copilot registration and records it in the -receipt. Compact advertisements can reduce nested validation structure; the -server still validates complete canonical inputs. This is a tested alternate -workflow, not a fix for the full-profile client/model limit tracked in #1554. -Live model APIs, native Windows and default OS-home skill discovery remain -unverified. - -`verify:grok-client` requires installed Grok Build (verified with the official -Linux x64 1.0.50 binary); select it with `REA_VERIFY_GROK_COMMAND`. This optional -POSIX lane isolates `GROK_HOME`, an independent Git workspace and additional -skill roots, disables foreign configuration discovery, guards setup writes, -preserves unrelated registrations/backups and checks idempotence. Call mode -loads the full skill through native `read_file`, queries all REA names and input -schemas through native `search_tool`, and calls analysis through `use_tool`. -If discovery reports `partial`, the native agent diagnoses REA registration and -retries discovery. No startup-timeout override or fixed readiness delay is used. -A larger Unicode-path fixture exercises native result offloading: the full -retained Evidence is validated against its named schema, then native terminal -queries recover the selected export facts, subject and full artifact digest in -the next model request. This verifies useful artifact recovery without claiming -that every offloaded graph fact enters model context. Native line-number and -truncation envelopes remain in the request artifacts. Use `-- chat` for ordinary -chat, or `REA_VERIFY_RUNTIME_ROOT` for a production-only installed package. -The loopback OpenAI completions/SSE custom model declares a one-million-token -context and synthetic usage. Live xAI APIs, native Windows and default OS-home -skill discovery remain unverified. - -`verify:commandcode-client` requires installed Command Code (verified with npm -1.79.2); select it with `REA_VERIFY_COMMANDCODE_COMMAND`. Auth, MCP tokens and -sessions use the actual OS home, so provision a disposable POSIX account rather -than overriding `HOME`. Set `REA_VERIFY_COMMANDCODE_ACCOUNT_HOME` to that account's -actual home and create `.rea-client-verification` there with exactly -`Disposable REA client verification account` followed by a newline. The lane -owns that account's `.commandcode` configuration and shared REA skill. Build the -runtime as the checkout owner, then run `node scripts/verify-commandcode-client.mjs` -as the disposable account; the npm shortcut also needs a writable checkout. -The verifier does not create accounts or install clients. It guards setup -targets, preserves an unrelated registration and backups, checks idempotence, -and verifies native default shared-skill discovery and complete activation. -Default deferred-schema delivery stays enabled: the native prompt advertises -every REA tool, exact-name `search_tools` returns every input schema, and a native -shell query recovers the saved catalog's count and digest when the client spills -it. Actual analysis of a Unicode-path fixture delivers full named-schema Evidence -to the next model request. Use `-- chat` for ordinary chat or -`REA_VERIFY_RUNTIME_ROOT` for a production-only installed package. The loopback -OpenAI completions/SSE model is a keyless BYOK endpoint declaring a million-token -context with synthetic usage. A synthetic account-key value satisfies the -client's print-mode gate; native local-only mode refuses hosted API calls. -Updates, telemetry and cron are disabled. Hosted authentication, live models -and Windows remain unverified. - -`verify:omp-client` requires installed OMP (verified with the official Linux x64 -18.8.7 binary); select it with `REA_VERIFY_OMP_COMMAND`. This optional POSIX lane -isolates the default agent, global config and XDG roots, guards setup targets, -preserves unrelated registrations and backups, and checks idempotence. It -compares native rejection of an invalid profile with REA's refusal to plan -fallback writes. OMP's default `xd://` interface mounts the complete REA catalog -as devices: call mode reads the complete installed skill and tool documentation, -then dispatches analysis through native `write`. It checks full named-schema -JavaScript Evidence with a Unicode path in the next model request. Device -metadata and documentation are distinct from forwarding all JSON schemas as -model functions. Native print-mode MCP readiness uses its defaults. -Use `-- chat` for ordinary chat or `REA_VERIFY_RUNTIME_ROOT` for a production-only -installed package. The loopback OpenAI completions/SSE model fixture declares a -one-million-token context and synthetic usage. Live model APIs, native Windows, -named-profile native execution and default OS-home skill discovery are -unverified; skill discovery uses an explicit isolated custom directory. - -`verify:deepseek-client` requires an installed DeepSeek Harness (`dsh`; -verified with `@deepseek-ai/dsh@0.2.0-rc.2`) and Git. Set -`REA_VERIFY_DEEPSEEK_COMMAND` to select its executable. This optional POSIX lane -seeds caller model settings and a stale Cordis registration in an isolated -`DSH_HOME`, then runs public `setup --client dsh` dry-run, setup, repeated setup, -and scoped doctor. It checks the backup and unrelated patches before booting -Harness with the generated registration. After native execution it uninstalls -through the public CLI and checks that only caller patches remain. `HOME` and -`USERPROFILE` point to the disposable account. The native default -`~/.agents/skills` search path discovers -the installed skill without a `DSH_AGENTS_HOME` override. A separate Git root prevents inherited project skills from -masking a missing installation. The default `call` mode checks skill loading, -complete catalog discovery, the actual forwarded input schemas and regexes, -and full JavaScript Evidence for a Unicode path. Use `-- chat` for ordinary -chat with REA enabled, or `REA_VERIFY_RUNTIME_ROOT` for an installed package. -The fixture uses Harness's custom OpenAI adapter and the one-million-token -context capacity declared by its default DeepSeek Flash model; it does not -establish live DeepSeek API or native Windows coverage. Receipts include -request artifacts, result digests and owned-process lineage. - -The DSH acceptance journey also exercises public setup, approval, doctor, -generated-launcher MCP startup and uninstall without an installed Harness. -That journey proves REA workflow behavior, not native Cordis expression -evaluation. Filesystem regressions retain tagged values and unrelated rows -across alias dependencies and check refusal of unsafe YAML without mutation. - -Full E2E tests invoke the production command dispatcher and real providers, -without fake launchers, runners or responses. `verify:keyed-archive` writes -Foundation binary, XML, and integer archives using one run-owned Swift module -cache. It checks CLI and separate stdio MCP parity, pagination, escaping-path -rejection, an XML graph golden, and numeric meaning for safe controls, unsafe -integers, boxed numbers, and integral-valued reals. `verify:asset-catalog` -compiles source-owned colors with -`actool`, invokes real `assetutil`, then checks CLI/MCP results, exact catalog -digest, every raw metadata field, pagination and malformed input rejection. -Neither artifact workflow requires Hopper or launches it. Both run in macOS CI. -`verify:macos-bundle` needs only macOS with Command Line Tools. It compiles a -source-owned app with `clang`: a versioned framework, XPC services, an app -extension, a login item, a privileged helper, launchd plists, and a helper tool, -signed ad hoc. It packs the app as a directory, a `ditto` ZIP, and an APFS DMG, -then checks that `inspect-artifact` plus `project-apple-application-graph` -report the same bundle anatomy for all three through the CLI, with stdio MCP -parity. It also checks that the DMG is detached afterwards. The same app -covers `trace-dylib-resolution`: - -- each resolution status and finding, with CLI/MCP parity; -- for every traced image, dependencies, rpaths, and install names equal to - `otool -l`; -- for the main executable and an XPC service, a predicted load order equal to - the images dyld actually loads under `DYLD_PRINT_LIBRARIES`. - -The lane also compiles executable/library pairs with empty embedded directory, -versioned-path, and suffix settings. It checks present and removed dependencies -through CLI and MCP, and compares actual `DYLD_PRINT_SEARCHING` diagnostics for -root-level candidates. These cases distinguish an empty search directory from -an empty versioned scan or a suffix that only repeats the original path. - -It runs in macOS CI. - -Prepare the native inspector before cases that measure producer output or exit -behavior; keep startup deadlines and cancellation in distinct cases. Run real -process-capture verification separately from package or build checks. On macOS, -new npm processes can become token-unreadable after changing their display -title and prevent verified cleanup during a capture's ownership sweep. - -MCP SDK transport tests with recording providers remain integration tests. -They are useful for schema drift and failure projection but do not prove that -Hopper, Ghidra or another substituted engine works. `verify:package` proves -packaging/install behavior and fake-provider integration; use the corresponding -real-provider lanes for engine claims. Packed-bridge checks verify shipped files and Python syntax. -Real Apple dispatch and Interface -Builder verifiers currently prove format integration through production readers. - -`verify:hopper` exercises an installed Hopper through the production stdio MCP -server and CLI. It checks source-owned call chains, CFG edges, references and -complete large inventories, then probes unnamed bookmarks, annotation clearing, -batch validation before mutation, malformed addresses and regexes, segment-end -partial reads, and synthetic file-offset rejection. Advertised schemas are -validated in their JSON Schema dialect and successful replies are checked against -their advertised output schemas. Navigation checks cover interior-object cursor -readback and mapped-memory boundaries. Annotation probes verify invalid native -text and duplicate destinations/names before mutation, preserve unselected label -owners, and exercise explicit batch label swaps. Function locals retain observed -names and stack displacements. Graph probes check symbol/interior-address parity -and a source-owned recursive cycle; literal tracing preserves complete queries -and whitespace. Disposable binary copies prove that switching and closing -actually removes the native document, and that CLI byte, function-dossier, -literal-trace results and invalid-address diagnostics agree with MCP. -No provider is mocked in this lane. -Real search probes cover Unicode names, literal metacharacters, case and regex -modes, annotation cache invalidation, complete native fragments of long literals -checked against byte reads, escaped UTF-8/control text, byte-preserving Latin-1 -decoding, and Hopper's UTF-16 symbol-name truncation boundary. It verifies native -CallReference classifications across reference and dossier results, retains long -string fragment metadata in dossiers, and exercises pathological regex deadline -and cancellation followed by successful requests in the same native session. When the macOS -Objective-C fixture is present, the lane also verifies native UTF-16 string objects -and their inferred encodings against their actual bytes. Native terminal calls -are checked across reference, instruction, assembly, block-range and procedure-length -projections; block endpoints are normalized using actual native membership. -Exact Objective-C names also exercise named CLI selectors for function, instruction, -decompilation, reference and search operations. A literal `--help` trace query proves -that selector data is preserved independently of global CLI flags. -Unmapped annotation destinations and -oversized later batch names fail before any earlier edit is applied. - -`verify:hopper:deadlines` checks the native client's optional request deadlines -on macOS with an owned source-built fixture. Zero and elapsed deadlines must -leave native comments unchanged, including when a synchronous progress observer -delays timer dispatch. It also observes a short analysis deadline and verifies -subsequent wire recovery and clean shutdown. Caller timeout does not interrupt -Hopper's synchronous native operation. Socket boundary tests deterministically -cover active and queued expiry, late replies and timer cleanup. - -The Linux demo lane remains a separate `verify:hopper:linux` command. Its -lifecycle checks attempt competing CLI launches for the active target and a -different target, requiring rejection before either can change the owning -MCP session's documents or procedures. Lease boundary tests also preserve -unresponsive or malformed live endpoints while allowing confirmed stale -sockets to recover. - -`verify:hopper:fat` is a separate macOS lane requiring installed Hopper and the -existing Xcode clang/lipo toolchain. It compiles arm64/x86-64 thin executables and -one- and two-slice FAT32 containers, verifies exact/interior address mappings -against bytes in the original files, checks CLI/MCP parity, and checks owned -runtime cleanup. Source byte changes, removal, permission denial (for non-root -callers), and nonregular replacement must retain native partial mapping facts, -reject unverified original-file coordinates, -and recover after restoration. Single-slice FAT cases also relocate the slice -without changing its loaded bytes. `verify:hopper:fat64` additionally checks -FAT64 preparation through Hopper's native Mach-O loader, source-container -mappings, profile identity, -malformed and ambiguous slice rejection, and temporary-image lifetime. Both -lanes have been verified on Hopper 6.1.0-demo; this establishes REA's prepared -FAT64 workflow, not native FAT64-loader support. -Cross-architecture fixture compilation is not required by `verify:hopper`. - -Golden tests use immutable captured text inputs with producer/source provenance -under `tests/fixtures/golden/`. Expected results are reviewed for the semantic -claim; capture commands do not automatically approve new expected outputs. -Do not call handcrafted utility output or synthetic binary builders real-data -goldens. Keep unsupported binary layouts and malformed boundaries as targeted -regressions until a real fixture establishes equivalent coverage. - -`verify:browser` exercises source-map failure isolation and expanded-output limits through the compiled CLI and stdio MCP with real Chrome. It also submits five 2 MiB source-map annotations, checks retained script identities and explicit map omissions, and closes its owned fixture target. Replacement and document-reset behavior has separate producer-boundary coverage. - -The raw Chrome fixture launchers use `--password-store=basic` so Linux startup -does not wait for an unlock prompt from a reachable but locked desktop keyring. -Such a stall leaves the initial page unloaded with empty or placeholder CDP URLs; -it does not establish permission to capture that page. See -[the keyring diagnosis](https://github.com/morluto/rea/issues/1384#issuecomment-6093781686). - -`verify:browser` also captures a source-owned noise canvas as a real PNG above -8 MiB through the CLI and stdio MCP, with complete byte/digest parity and real PNG -decoding. Its SDK client explicitly permits the larger inline JSON response; -this lane does not establish large image-comparison request transport coverage. - -The scenario checks read locale, timezone, device scale and viewport dimensions -from actual page JavaScript through CLI and stdio MCP DOM captures. They also -verify that attached-page emulation is released after success, initialization -failure, action failure and cancellation while the external target stays open. - -`verify:browser:network` is a focused real-browser lane for transaction identity, -selected request/response bytes, binary and compressed responses, duplicate -headers, credential and declared-secret redaction, redirects, streaming cutoff, -CLI/MCP parity, and owned-profile cleanup. Set `REA_BROWSER_EXECUTABLE` to an -installed Chrome-family browser. An optional script argument selects an already -installed package's `scripts/rea.mjs` entry point for packaged-artifact checks. -The complete `verify:browser` lane includes these same checks. - -After building, `verify:browser:dom` checks empty and HTML-whitespace form -destinations against a native Chrome DOM-property oracle through CLI and stdio -MCP. It requires `REA_BROWSER_EXECUTABLE` and accepts an optional installed REA -entrypoint. The full browser lane includes the same public-adapter assertions -before other fixtures navigate the selected page. - -`verify:browser:scripts` checks active script capture → exact-byte export → -existing static JavaScript analysis through CLI and stdio MCP, including -manifest readback, competing query variants, and resolved relative imports. -It uses an installed browser and accepts an optional installed REA entrypoint. -The complete `verify:browser` lane also exercises passive script export through -both public adapters. See [website script export](website-script-export.md). - -`verify:browser:modules` compares CLI and stdio MCP traces against an independent -real Chromium module-loading fixture: import-map scopes, package prefixes, -null/backtracking rejection, query/fragment identities, repeated module instances, -lazy and computed unknowns, exact source/map identities and no implicit refetch. -Set `REA_BROWSER_EXECUTABLE`; the optional script argument selects an installed -package entrypoint. The complete `verify:browser` lane and existing conditional -Chrome CI include this verifier. See [module relationships](website-module-trace.md). +The PR acceptance target is a median `npm run check:pr` wall time below three +minutes across three warm-build runs on the benchmark host. Keep Vitest caches +cold unless separately identified. A PR that touches packaging or real-system +behavior requires the applicable `verify:*` lanes; packaging and installation +changes also require `npm run verify:package`. The full-gate benchmark measures +that explicit lane, not the routine iteration requirement. ## Real-toolchain verification lanes @@ -973,159 +786,6 @@ establish passing Android coverage; inspect its execution receipt. The `termux-browser-diagnostics` artifact retains the Termux command log, exit status, and Android logcat on success or failure. The emulator is disposable. -## Developer commands - -Use source feedback while editing, explicit boundary checks for the changed -behavior, and complete CI evidence before merging. - -| Command | Scope | -| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -| `npm run test:local` | Dirty source tests via the import graph, without build; explicit source paths run regardless of Git status | -| `npm run test:focused -- PATH...` | Exact existing test files; compiled boundaries build first, and unmatched paths fail | -| `npm run test:changed` | Source tests affected since the merge base with `origin/main`, including committed and dirty changes | -| `npm run test:fast` | All domain, service, adapter, composition, conformance, and evaluation tests without build | -| `npm run test:boundary` | Boundary, CLI boundary, MCP boundary, process boundary, and process-global projects | -| `npm run test:mcp` | MCP boundary project | -| `npm run test:acceptance` | Complete compiled CLI and MCP acceptance workflows | -| `npm run test:watch` | Dirty source tests in watch mode, without build | -| `npm run test:watch:all` | Changed tests from every project; builds at startup, so rebuild after production edits before relying on compiled tests | -| `npm run check:changed` | Cached typecheck/lint and branch-related source feedback | -| `npm run check:pr` | Opt-in complete local deterministic gate and generated-file checks | -| `npm run docs:check` | Generated-document validation from current source and build outputs | - -For example: - -```bash -npm run test:local -- src/config.test.ts -npm run test:focused -- tests/acceptance/applications/runtime.test.ts -npm run test:changed -- --base origin/main -npm run test:changed -- --dry-run -``` - -`test:focused` accepts exact repository-relative test file paths. Source-only -paths do not build; boundary, acceptance, process-global, or unfamiliar `tests/` -paths build conservatively. Tests use Vitest concurrency and isolated -workspaces; commands do not hold a broad test lock. Build and documentation -writers retain checkout-local locks for their shared output files. Explicit -selections do not use `--changed` or permit zero-test success. -The dry-run option reports the chosen merge base, scope and build prerequisite -without executing tests or building. A missing Git base reports how to fetch -it or select another revision. - -Source typechecking needs no compiled runtime or generated test metadata. -`npm run build:cached` compiles the CLI/MCP runtime and its packaged skill. -Turbo's strict task environment preserves caller-selected `GOMAXPROCS`, -`GOMEMLIMIT`, and `UV_THREADPOOL_SIZE` for resource-constrained builds and -checks. These execution controls do not change artifact content, so changing -their values retains cache reuse. They control individual runtimes; monitor -the complete process family separately when enforcing a total memory budget. -`npm run test:prepare` also generates the MCP contract test catalog, product -catalog, and portable managed evidence used by the complete suite. Focused -tests prepare those extra outputs only when their selected files consume them. -The MCP test catalog is JSON in `.cache/mcp-tool-catalog.json`; the tracked -test loader supplies its types without making generation a source-check -prerequisite. Run `npm run mcp-catalog:generate` to refresh it independently. -Documentation generation and managed conformance run through their separate -`docs:generate` and `evidence:generate` task graphs. - -Changed selection can miss runtime registration, generated data, shell -entrypoints, bridges, or other relationships absent from the import graph. -An empty changed selection means no tests were selected, not verified -correctness. Select relevant boundary files and real-provider lanes explicitly. -Source projects also contain large capacity regressions; `test:fast` promises -no compiled-runtime prerequisite, not a fixed time budget. - -Routine iterations and rebases need focused regressions and relevant checks. -Before handing off a PR, run `npm run check` and generated-document checks when -applicable; CI owns the full suite and coverage. Use the full local gate for -broad changes or diagnosing CI, rather than after every edit. Package/install -changes additionally need package verification; provider changes need actual -provider evidence. - -Vitest projects use up to two workers, bounded by host parallelism. -`process-boundary` runs later with serial files because process-tree sampling -shares host resources. Acceptance and process-global cases use isolated forks -without serial scheduling. Pure domain/service, composition, conformance, -evaluation, CLI boundary, and MCP boundary projects share module graphs. Their -tests avoid process-global state and keep resource cleanup test-scoped. Each -MCP session still owns its resources, and CLI cases retain fresh command -instances or subprocesses. CLI module mocks belong in `tests/process-global/` -so they keep per-file isolation. Product catalog verification stays with the -isolated filesystem boundary tests because it loads both source and compiled -module graphs. Adapter, other boundary, acceptance, and process-global projects -retain per-file isolation. See `vitest.config.ts` for current settings. - -The reused CLI boundary workers cap V8 old space at 384 MiB, based on their -profiled allocation and cleanup behavior. This encourages collection between -files; spawned REA processes retain their own heap settings. - -Vitest worker limits do not bound subprocesses launched within a test. Bound -those batches separately so repeated CLI validation cannot oversubscribe the -runner. Preserve simultaneous launches where concurrency is itself under test. - -Build/documentation writers hold checkout-local output locks. Tests do not -hold a broad command lock; `check:pr` finishes tests before document validation. - -Vitest's persistent compile cache remains disabled. The `cliTest` fixture shares -a temporary Node compile cache among its fresh CLI subprocesses. The worker -removes it after test-scoped processes finish. Explicit child environment -settings take precedence; children requesting `NODE_V8_COVERAGE` do not receive -the fixture cache. These subprocesses are outside aggregate Vitest coverage; -subprocess coverage attachment remains disabled. Cold-start import checks launch -independently without this fixture cache. - -The Apple artifact verifier step shares a job-temporary bytecode cache among -its fresh CLI/MCP children via `REA_ARTIFACT_NODE_COMPILE_CACHE`. The artifact -helper maps this setting to child `NODE_COMPILE_CACHE`; npm, Turbo, and nested -Vitest runs do not inherit that setting. Explicit `NODE_COMPILE_CACHE` takes -precedence, and coverage collection or `NODE_DISABLE_COMPILE_CACHE=1` disables -the helper's cache. The cache is discarded with the CI job. - -To evaluate persistent compile caching for repeated local runs, opt in for both -cold and warm measurements with an isolated cache: - -```bash -NODE_COMPILE_CACHE=.cache/node-compile npm test -``` - -Do not report the warm result as a cold-suite improvement, and do not enable -the cache in coverage or benchmark CI without first showing that its -instrumentation remains equivalent. - -## Coverage and timing - -CI owns coverage; aggregate and domain/contract thresholds are maintained in -`vitest.config.ts`. They are glob-specific and never updated automatically. -Coverage does not replace named boundary or real-provider scenarios. - -CI runs six native Vitest shards without retries. Each shard emits a blob -report; the merge job produces aggregate coverage plus JUnit and JSON timing -reports, uploads them together, and writes the slowest files to the workflow -summary. Static checks, documentation, build, package verification, and -real-system lanes remain separate jobs so one kind of evidence cannot stand in -for another. - -The build job saves portable Turbo outputs across runs. Eight Linux real-system -lanes restore this cache without waiting for the build job. The shared action -derives its key from `test:prepare --dry=json` task hashes, runner OS and -architecture, and `.npmrc`; test-only changes can reuse compiled outputs. Every -build and verification command still runs, so Turbo checks task inputs and -rebuilds misses. There is no prefix fallback to accumulate older build outputs. - -Native package jobs, the Windows curated lane, and the Apple artifact lane reuse -the same workflow's Turbo cache for portable compiled JavaScript, skills, and -catalogs. The Windows lane relies on the Linux static job for typechecking. They retain the normal build and prepack -commands, which restore matching outputs or rebuild on a cache miss. Native -artifacts, dependency installs, package archives, and runtime verification remain -host-local. Keep platform-dependent outputs out of this shared cache. - -The PR acceptance target is a median `npm run check:pr` wall time below three -minutes across three warm-build runs on the benchmark host. Keep Vitest caches -cold unless separately identified. A PR that touches packaging or real-system -behavior requires the applicable `verify:*` lanes; packaging and installation -changes also require `npm run verify:package`. The full-gate benchmark measures -that explicit lane, not the routine iteration requirement. - ## Apple native metadata and UI `npm run verify:apple-dispatch` compiles the Objective-C fixture (classes, @@ -1267,7 +927,8 @@ first argument to verify packaging independently of the checkout. The valid SHN_XINDEX fixture has 65,281 full section rows; CLI is checked in the ordinary lane. Its large MCP transfer is opt-in with `REA_VERIFY_LARGE_ELF_MCP=1` (or the workflow dispatch `large_mcp` input), an -explicit 256 MiB SDK receive buffer and five-minute request timeout. Ordinary +explicit 256 MiB SDK receive buffer, matching server `REA_MCP_MAX_RESPONSE_BYTES`, +and five-minute request timeout. Ordinary MCP fixtures retain the pinned SDK defaults. ### Offline EVM interface @@ -1304,115 +965,12 @@ installed package entrypoint as the script's first argument for package coverage ## Agent evaluation and conformance records -Evaluate native, JavaScript, managed and browser investigation tasks through a -real local Codex CLI with: - -```bash -npm run verify:agent -``` - -The lane runs scenarios sequentially in standalone Codex (`--no-daemon`) with a -disposable HOME and CODEX_HOME under `~/.cache/rea-agent-evaluations/`. Set -`REA_AGENT_EVAL_ROOT` to choose another parent directory outside the OS temporary -directory: current Codex refuses helper aliases under `/tmp`, preventing shell -commands and skill reads even if MCP works. Each owned run directory is removed -after verification unless fixture retention is requested. The lane -installs the packaged skill and MCP registration through public `rea setup`, -rather than copying a skill into a project that also inherits the caller's -skills and configuration. Only authentication is copied, when present, and it -is removed even with `REA_AGENT_EVAL_KEEP_FIXTURES=true`. No user configuration, -rules, plugins or history is copied; shell snapshots and additional agents are -disabled. Existing API-key environment authentication remains available. -The native missing-provider scenario preapproves only `open_binary` and -`close_binary` in the disposable client so it reaches REA's actual provider -boundary instead of stopping at Codex approval. This does not validate a real -native engine or authorize arbitrary runtime execution. - -Select a smaller run with `REA_AGENT_EVAL_SCENARIOS`, a comma-separated list of -scenario IDs. `asar-zh` exercises the packaged desktop rubric from a Chinese -request. `javascript-module-view` exercises summary analysis, module paging and -item inspection in a tree with unrelated modules; its routing and text checks -remain heuristic, so review the retained transcript for selector choice and -coverage claims. Set `REA_CODEX_CLI` to an installed Codex executable and -`REA_AGENT_EVAL_MODEL` to an account-supported model. Use an external resource -limit for the whole process tree when testing on a constrained host; a Node -heap limit alone does not bound client and child-process memory. - -`missing-target` leaves desktop fixtures visible without selecting one in the -request. It requires zero REA calls and a structured request for an app name or -artifact path. Its `expectedFirstTool` is `null`, and -`targetClarificationPassed` grades that limited routing outcome independently -of analysis prose heuristics. Analyzing a nearby example cannot pass this case. - -The packaged desktop and parser-comparison scenarios now assess a closed set of -known fixture claims. Each final answer must be a strict JSON manifest containing -exactly the requested claim IDs, values, Evidence IDs, and Evidence authority and -confidence. Golden values are not included in the prompt. The evaluator checks -exact values against both the fixture oracle and authenticated successful REA -results; an Evidence ID by itself is insufficient. Missing, duplicate, extra, -contradictory, incorrectly sourced, or unsupported claims fail the scenario. - -The desktop rubric covers the exposed bridge API and members, renderer and main -IPC operations, and the resolved preload. It binds its Evidence to the exact -packaged artifact path and SHA-256. The parser rubric checks the precise heading -depth addition, discriminant, complete comparison counts, and the explicit limit -on runtime semantics. Its comparison must link to the two delivered source -analyses and use the requested module and export selectors. Boundary tests package -the same source-owned desktop fixture and compare the same source-owned parser -files through actual MCP tool results, then verify that fabricated answers fail. - -Per-scenario `factualCorrectness` is `passed`, `failed`, or `not_assessed` within -the `configured_fixture_claims` scope. A pass establishes only the configured -claims, not unrestricted factual correctness. Native, managed, browser, -navigation-context, and address-context scenarios have no factual rubric and -remain `not_assessed`; the managed workflow requires both artifact and member -inspection to answer its type and entry-point question. - -The closed factual scenarios request complete producer Evidence on the initial -analysis so their source selectors can authenticate all configured facts. -Summary/page/item workflows are exercised separately by `javascript-module-view`; -its heuristic gate does not establish full-producer factual correctness. - -All scenarios retain routing, workflow, validation, repetition, process-exit, -and token-use gates. Configured factual scenarios additionally require a factual -pass. Their answer-text heuristics are diagnostic and do not affect the gate. -Validation counts include complete text-only REA `invalid_request` envelopes -and failed SDK calls whose arguments violate the named current REA contract. -Client approval rejections and provider unavailability remain distinct failures; -truncated JSON previews are not parsed into invented error codes. -Repeated `binary_session` observations separated by a successful `open_binary` -or `close_binary` are treated as lifecycle verification. An unchanged retry, -including one after a failed lifecycle call, still counts as repetition. -Scenarios without a rubric retain the legacy text-heuristic gate. -`answerTermCoverageMet` checks case-insensitive substrings, -`epistemicCuePresent` checks keywords, and `finalCitesEvidence` checks only an ID's -presence. These metrics can still accept fabricated prose and must not be read -as factual assessments. Set `REA_AGENT_EVAL_TRANSCRIPT_DIR` to retain complete -tool results and final answers for review. - -Report schema version 4 adds negative routing scenarios with nullable -`expectedFirstTool` and a `targetClarificationPassed` outcome. Consumers must -allow an expected absence of REA calls; this does not make an analysis scenario -pass without its required tools. Version 3 changed the top-level -`factualCorrectness` from a constant -string to an assessment summary with status, scope, and assessed/passed/failed/ -not-assessed scenario counts. Scenario records include the factual assessment and -configured claim IDs. The evaluation scope is -`routing_workflow_and_configured_fixture_claims`. Update report consumers for -these changes. The narrower heuristic field names introduced in version 2 remain: -`answerHeuristicsMet`, `epistemicCuePresent`, `answerTermCoverageMet`, and -`requiredAnswerTermGroups`. - -Regenerate the managed conformance manifest and Evidence completion ledger from -live verification results, or check them for drift: - -```bash -npm run evidence:generate -npm run evidence:check -``` - -The records preserve unsupported and unverified coverage as explicit unknowns. -Run the matching real-tool prerequisites described in this guide. +`npm run verify:agent` evaluates investigation scenarios through a real local +Codex CLI. The lane runs sequentially; select scenarios with +`REA_AGENT_EVAL_SCENARIOS` and choose the installed client/model with +`REA_CODEX_CLI` and `REA_AGENT_EVAL_MODEL`. The detailed +[agent evaluation reference](client-verification.md#agent-evaluation-and-conformance-records) +contains isolation, authentication cleanup, grading, and conformance boundaries. ## Frida instrumentation diff --git a/docs/wasm-artifacts.md b/docs/wasm-artifacts.md index 21e2735a0..6bc7c23ce 100644 --- a/docs/wasm-artifacts.md +++ b/docs/wasm-artifacts.md @@ -77,5 +77,5 @@ Candidates are caller-selected files; their identity does not imply validation. Both CLI and MCP use the same typed port and application service. MCP publishes SDK-compatible schemas and records Evidence for `get_evidence_bundle` readback. -See [WABT provenance](../third_party/wabt/README.md) and +See [WABT provenance](https://github.com/morluto/rea/blob/main/third_party/wabt/README.md) and [testing](testing.md#offline-wasm-artifacts) for real-tool verification. diff --git a/docs/windows-ghidra-p0.md b/docs/windows-ghidra-p0.md index 7d72056f6..d14add07c 100644 --- a/docs/windows-ghidra-p0.md +++ b/docs/windows-ghidra-p0.md @@ -21,8 +21,10 @@ additional permission flag or degraded mode is required. - the 25 read-only Ghidra inventory, memory, and function-analysis operations. Loaded memory reads and file offsets preserve Ghidra's observed source mappings. -PE load-image inspection returns an explicit unsupported attestation status; -independent load-image verification currently supports DOS MZ only. For x64 PE +PE load-image inspection returns an explicit unsupported attestation status. +Independent verification covers admitted DOS MZ, explicit COM, and explicit +[raw-binary imports](raw-binary.md) on their supported hosts. This does not +extend Windows P0 admission beyond native PE. For x64 PE NativeAOT RTR 9.1, the read-only snapshot parser can report metadata through `inspect_native_load_image` and `inspect_native_data_type` without a JAR or database mutation. A real Windows-host NativeAOT Ghidra run is still required diff --git a/src/generatedPackageMetadata.ts b/src/generatedPackageMetadata.ts index 00d5f109f..1af9203ad 100644 --- a/src/generatedPackageMetadata.ts +++ b/src/generatedPackageMetadata.ts @@ -5,5 +5,5 @@ export const PACKAGE_METADATA = { serverSdkVersion: "2.3.1", clientSdkVersion: "2.3.1", coreSdkVersion: "2.3.1", - skillVersion: "39", + skillVersion: "40", } as const; diff --git a/src/ghidra/GhidraProviderCapabilities.ts b/src/ghidra/GhidraProviderCapabilities.ts index f3f94c645..ea863e8a7 100644 --- a/src/ghidra/GhidraProviderCapabilities.ts +++ b/src/ghidra/GhidraProviderCapabilities.ts @@ -83,7 +83,7 @@ export const limitationsFor = (operation: string): readonly string[] => { case "inspect_native_load_image": return [ ...common, - "Independent verification supports DOS MZ and explicitly selected COM, including measured COM entry context. Measured source mappings use inclusive end addresses and complete region digests; no target execution or project mutation occurs.", + "Independent verification covers admitted DOS MZ, explicitly selected COM with measured entry context, and caller-supplied raw-binary imports. Measured source mappings use inclusive end addresses and complete region digests; no target execution or project mutation occurs.", ]; case "read_bytes": return [ diff --git a/tests/conformance/README.md b/tests/conformance/README.md index d8296e6ea..08f6b0576 100644 --- a/tests/conformance/README.md +++ b/tests/conformance/README.md @@ -18,7 +18,7 @@ the read-only Ghidra inventory contracts without committing a binary. `scripts/create-ghidra-windows-fixture.mjs` separately emits a deterministic, ignored native x86-64 PE application for the controlled Windows Ghidra P0 lane. The generator and fixed SHA-256 are versioned; the `.exe` is never committed or -executed. `npm run verify:ghidra:windows` uses it to prove all 19 operations, +executed. `npm run verify:ghidra:windows` uses it to verify the admitted read-only operation inventory, digest linkage, transport, and cleanup on the self-hosted real-Ghidra runner. The C fixture fixes a known call chain and strings. The version pair fixes an diff --git a/third_party/README.md b/third_party/README.md index fbf04c482..357049dd5 100644 --- a/third_party/README.md +++ b/third_party/README.md @@ -34,7 +34,7 @@ audited source revision. ## Public APK fixture -`scripts/fetch-android-fixtures.mjs` explicitly downloads the audited engine and +`npm run fixtures:android` (`scripts/fixtures/android/fetch.mjs`) downloads the audited engine and Appium ApiDemos v6.0.18 into ignored `_reference/apk-integration/`. Both downloads are checked against fixed SHA-256 values. Fixture provenance is recorded in `scripts/fixtures/android-apidemos.json`; the source uses Apache-2.0. This is a diff --git a/third_party/web-network-captures/README.md b/third_party/web-network-captures/README.md index 49d0bc110..4561258af 100644 --- a/third_party/web-network-captures/README.md +++ b/third_party/web-network-captures/README.md @@ -32,5 +32,6 @@ null retained. The upstream schemas themselves remain unchanged. The strict JSON visitor supplies member events before object materialization; REA rejects all duplicate names and retains original numeric token spelling. -The shared JSON schema currently drops `__proto__` members, so both adapters -report that representation as unsupported instead of returning incomplete data. +The shared JSON representation preserves all own members, including `__proto__`, +`constructor`, and `prototype`, without invoking prototype setters. These names +do not make a capture unsupported.