Compare commits

..
Author SHA1 Message Date
Kaoru0822andClaude Opus 5.5 528da7cc31 fix(batch): report a provider's null pseudocode as unavailable, not unreadable
`procedure_pseudo_code` may return null, which a provider uses to say a
procedure has no pseudocode: Kuna does so for an import slot or a function
it could not decompile. `batch_decompile` treated null like malformed
output and reported "unreadable result, run rea doctor". A null item is now
a non-retryable capability error pointing to the batch limitations, which
carry the provider's reason. An empty string remains unreadable output.

Refs #1957

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 13:38:40 +00:00
1504 changed files with 60245 additions and 242492 deletions

No files matched your search

@@ -1,113 +0,0 @@
---
name: rea-analysis-optimization
description: Optimize REA providers and shared analysis workflows for agent context, latency, CPU, and memory while preserving correctness and Evidence. Use for analysis bottlenecks and cache or query design; CI/test-suite optimization belongs to rea-ci-tests-audit.
---
# REA analysis optimization
Find a concrete source of unnecessary work, change it at its owner, and verify
equivalent completed investigations. A useful outcome can also be a measured
decision to leave an implementation alone.
Follow the checkout's [performance priorities](../../../AGENTS.md#performance),
[tool design](../../../docs/tool-design.md), and
[testing guide](../../../docs/testing.md). This skill supplies an optimization
workflow, not additional permission to execute targets, publish, or merge.
Use the current contracts, provider prerequisites, and user authorization.
Read [the Kuna case study](references/kuna-case-study.md) when selecting a
reuse strategy or interpreting a benchmark. Its pinned observations illustrate
tradeoffs; they are not current-provider guarantees or universal speedups.
## Pin the question and the correctness oracle
Describe the analyst's completed task, including the facts and relationships
needed to answer it, requested detail, source access, and meaningful unknowns.
Choose a representative real artifact and a small or empty case. Record the
baseline revision, target digest, engine identity, options, host, and entrypoint.
Use a separate checkout for changes without disturbing other work.
Establish an oracle independent of the changed implementation: source-built
fixture expectations, independently mapped file bytes, or a native producer
paired with checks of its interpretation. Comparing two wrappers around the
same faulty decoder does not establish correctness. Preserve address widths,
same-address alternatives, unresolved endpoints, coverage, and source linkage.
An empty result proves absence only within the actually examined scope.
## Locate the earliest unnecessary work
Trace one public CLI or MCP task through shared application code to its producer.
Measure relevant phases: admission and identity checks, native analysis,
decoding, lookup, projection, serialization, Evidence retention, and cleanup.
Include catalog discovery and extra calls when they affect the completed task.
Use the evidence to choose the smallest structural correction:
| Observed cost | Candidate correction | Condition to establish |
| --------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| Repeated scans of validated facts | Reuse existing order or lookup structure | The owner establishes ordering and identity; every matching alternative survives |
| Repeated equivalent engine work | Share a validated result or in-flight producer | Inputs, freshness, lifetime, and per-caller outcomes remain explicit |
| Full reports for selected facts | Push selection or projection to the earliest capable owner | Required facts and evidence remain reachable; examined coverage is reported |
| Large temporary transport buffers | Decode incrementally or use bounded source reads | Validate the whole admitted document; retained facts and copies still consume memory |
| Many repeated homogeneous reads | Share admission, decoding, or batch work | Preserve item identity, order where required, and individual failures |
Do not introduce an index, generic cache, batch endpoint, or orchestration layer
without identifying the work it removes and its maintenance/resource cost.
Projection after materializing a full report may reduce output while leaving
analysis time and peak memory unchanged. Fix missing or incorrect facts before
benchmarking an alternative composition against a better-covered workflow.
## Keep one interpretation and a defined reuse lifetime
Let the producer boundary validate and normalize facts once. Consumers query
that representation through the shared CLI/MCP implementation; adapters should
not rebuild relationships or independently reinterpret raw reports. Keep lookup
identity separate from display formatting. Reuse contracts when their intent
matches, honoring requested detail and complete Evidence access.
For every cache or shared producer, state its key, owner, invalidation, retained
size, and lifetime. Account for result-affecting target bytes, engine contents,
analysis options, architecture/load mapping, and parser/schema versions where
they affect reuse. Validate live state before calling a cached observation
current. Cache a refusal only when it is deterministic for that validated key;
malformed, partial, transient, or cancelled attempts need explicit retry policy.
One cancelled waiter must not invalidate a successful peer. Preserve producer
failure context and each caller's cancellation reason. Retain ownership and
capacity charges until shared work and cleanup settle; preserve completed
observations when cleanup fails. Exercise invalidation, concurrent consumers,
last-waiter cancellation, close, and cleanup retry when those paths change.
Bound the process family and retained state, not just a parent heap or worker
count. Account for decoding and serialization expansion before allocation.
Choose CPU, memory, concurrency, and disk limits from the host and workload;
stop before OOM and verify owned cleanup. A guard-stopped task is incomplete.
Do not replace a transport buffer cap with an unbounded retained inventory or
hide partial results behind a success status.
## Compare completed tasks and limit the claim
Run the affected real public workflow before and after with equivalent inputs,
results, coverage, and Evidence semantics. Include small inputs so setup costs
and regressions are visible. Distinguish fresh sessions, warm runtime caches,
and OS file caches. Alternate or repeat runs when variance affects the decision.
Choose meaningful boundary regressions for cases the actual engine cannot
reliably reproduce; a fake engine does not qualify a real provider.
Report task outcome, relevant phase timings, total elapsed and CPU time, peak
process-family memory and its accounting method, resource stops, and cleanup.
Check the payload exit status as well as the profiler's. Keep failed attempts
and identify unmeasured costs; a passing retry does not explain a failure.
For token claims, count schemas/discovery, arguments, replies, retries, and
continuations needed to finish the task. Label tokenizer estimates separately
from actual model usage and record the client/catalog behavior. Smaller JSON
alone establishes neither fewer model tokens nor better investigation quality.
Do not claim a complex-software advantage without completed representative
investigations and comparable correctness/coverage.
Finish with the bottleneck, owning change, preserved semantics, executed
checks, before/after measurements, and remaining limits. Keep any integration
record current with its tested revision and distinguish merged production work
from experiment-only code. Stop when the demonstrated bottleneck is resolved
or further benefit remains speculative.
@@ -1,4 +0,0 @@
interface:
display_name: "REA analysis optimization"
short_description: "Optimize analysis with preserved Evidence and measured costs"
default_prompt: "Use $rea-analysis-optimization to find and verify a concrete analysis bottleneck while preserving correctness and Evidence."
@@ -1,112 +0,0 @@
# Kuna: reuse before adding machinery
Read this reference for concrete examples of the skill's decisions. The records
below concern static Linux analysis with caller-supplied Kuna. They do not
establish parity with another provider or a general advantage for Code Mode,
atomic tools, or any particular orchestration design.
## Exact-address lookup: a measured, narrow improvement
[PR #4695](https://github.com/morluto/rea/pull/4695) reused the validated string
inventory's numeric address order. Previously, each `list_strings(address)`
filtered all cached facts. The owner now performs a binary lower-bound lookup
and returns every encoding at that address: O(log n + matches), without a
second retained lookup index.
The owning implementation is
[`KunaStringInventory.ts`](../../../../src/kuna/KunaStringInventory.ts), consumed
by [`KunaStringQueries.ts`](../../../../src/kuna/KunaStringQueries.ts). Inspect
their current versions before adapting the example. Numeric u64 addresses,
same-address encodings, duplicate rejection, source digests, caller selection,
and the existing session lifetime were part of the contract. Full listings and
literal/regex searches kept their semantics. An attempted removal of the
duplicate-detection set was dropped: no stable memory benefit was established,
and it delayed malformed-input rejection.
### Recorded workload and results
The benchmark used unmodified Kuna 1.833 and LLVM 16 on Linux x86-64, with
602,544 string facts. Baseline was `be0b2d138`; the final feature was
`5f564962da0e1b17f00a68a74a312539f0209a01`, subsequently integrated in
`c6b62754b095a134d6d67877508fa34311a2eda2`. These are historical observations,
not a benchmark of every subsequent main revision.
The same production stdio MCP task discovered the catalog, opened the binary,
made one cold selected read and 28 warm exact reads, checked retained Evidence,
and closed the session. Five selected addresses and two absent selectors were
read four times. A native filtered scan selected the strings; an independent
ELF load-header mapping checked the source bytes and terminators. Returned
facts, source linkage, target digests, and cleanup were checked.
Three alternating fresh sessions per implementation used one CPU, a 4 GiB
process-family hard limit, a 3 GiB early stop, and no swap. OS file caches were
warm. Whole-harness costs include the independent native oracle, hashing,
catalog/client work, and correctness checks.
| Median | Before | After |
| ---------------------------------------- | ---------: | ---------: |
| 28 warm exact MCP reads | 495.2 ms | 90.8 ms |
| Cold selected MCP read | 11.30 s | 11.01 s |
| Whole harness elapsed | 28.24 s | 27.43 s |
| Whole process-family CPU | 27.71 s | 26.89 s |
| Kernel family peak, including file cache | 2237.6 MiB | 2240.6 MiB |
Warm totals ranged from 491.7–544.3 ms before to 84.8–99.5 ms after: about
5.5 times faster at this phase. Cold/whole-task timing and memory overlapped;
no stable improvement in those costs was established. One small SQLite pair
(7,985 facts) measured 20 warm reads at 88.6 → 80.5 ms and the whole harness at
13.68 → 13.94 s. The large-inventory lookup benefit does not generalize to a
whole-task speedup on small inputs.
Catalog hashes, call counts, and normalized facts were unchanged. A
`cl100k_base` estimate over one pass of raw catalog JSON, arguments, and replies
was about 846,000 tokens in both lanes, with about 802,562 from the catalog.
This was transport serialization, not rendered model context or actual usage;
client discovery, prompts, replay, and protocol framing were unmeasured.
**No token reduction or improved agent investigation outcome was established.**
Pinned target SHA-256:
`f62d254b7f2bf42df8c8b07d46ee3bb4c2cafeca436b2e6bc6ccbe4581f58f40`.
Pinned engine SHA-256:
`d858918b0766435cd96b999a77f2d5a31a0cc4f07256421c883b5b9dc4dd58e4`.
All six normalized-result sequence digests were
`4d2f90269da8568984090b20274163c4a7c2a0538aab63530bd2fe44840a0bba`.
Selected byte agreement does not prove native discovery completeness; missing
strings and relationships can remain unknown.
## Other transferable changes and their limits
- [Cached string inventory and search, #4095](https://github.com/morluto/rea/pull/4095):
share validated facts across queries in a defined session. Audit key inputs
and lifetime before extending reuse across targets or engine revisions.
- [Shared single-function work, #4045](https://github.com/morluto/rea/pull/4045)
and [repeat-request reuse, #4169](https://github.com/morluto/rea/pull/4169):
avoid duplicate native work while retaining per-caller cancellation and
cleanup ownership. A query count alone cannot reveal duplicate subprocesses.
- [Streamed strings, #4318](https://github.com/morluto/rea/pull/4318)
and [streamed call graph, #4329](https://github.com/morluto/rea/pull/4329):
remove fixed aggregate transport-buffer failures through incremental parsing.
Streaming transport does not bound every retained object or final reply.
These links establish changes; no numerical speedup is asserted here.
Typed reference facts, native string-query projection, and shared native byte
reads remained experimental at the 2026-10-17 checkpoint
`65f2f9a22bc892f61d2b00f9a4611124f57d4bff` on
`experiment/atomic-codemode-20261016`. Some experiments used a patched native
engine. Check current integration and bring-your-own engine capabilities before
proposing them; a working experiment is not a stock-provider guarantee.
## Applying the reasoning elsewhere
For another provider or format, inspect its actual representation and native
capabilities before borrowing the implementation. Existing numeric ordering
may support range reads; an on-disk native query may avoid materializing an
inventory; an immutable parse may support several views. Measure the relevant
alternative rather than requiring every provider to use Kuna's cached array.
For live observations, immutable artifact caching rules are insufficient:
validate the process/session identity and freshness required by the caller.
For compact replies, preserve access to source Evidence and report examined
coverage; projection must not silently turn an unresolved edge into no edge.
For batching, test mixed successes and failures and measure the entire task,
including discovery, extra calls, native work, and serialization.
@@ -24,9 +24,7 @@ matching bundled native controls and uses an owned Job Object with bidirectional
stdio. A full JDK, including `jdk.compiler`, is required on every host; Windows
`JAVA_HOME` selects `bin\java.exe`. Consult the Android guide for actual host
verification coverage. Calls use one worker and provider deadlines; optional
`REA_JADX_HEAP_MIB` selects the JVM heap and `REA_JADX_OPERATION_TIMEOUT_MS`
the per-operation deadline (default 120000 ms; the MCP client's tool timeout
must also allow it). The APK is never launched,
`REA_JADX_HEAP_MIB` selects the JVM heap. The APK is never launched,
and no emulator is required.
Manifest entries and decompiled text are static observations, not execution or
@@ -195,8 +195,7 @@ accept complete inline Evidence or
`{"kind":"retained-evidence","evidence_id":"ev_<64 lowercase hex characters>"}`
for their application input (`application`, or `left`/`right`). `inspect_analysis_view`
uses the same retained-reference form in `source`, or portable inline Evidence,
to project a summary, module page, or one module with its recorded observations.
This notation is
to project a summary, module page, or one module with its recorded observations. This notation is
a template: replace it with the actual returned ID. Versions before 4.1.0 accept only full
inline Evidence. Use the exact ID
returned by the producer on the same MCP connection. Resolution does not run
@@ -204,15 +203,3 @@ analysis or select a provider; findings remain inline. Native observation
arrays still take full Evidence. `close_binary` clears retained references;
export a bundle before closing, or supply portable inline Evidence in another
connection. A missing reference includes its ID and recovery guidance.
For exact file/native metadata or processing gaps, use
`view: {kind: "javascript-facts", where: {paths: ["package.json"]}, property_keys: ["name", "operation", "analysis_status"], limit: 32}`.
Rows retain canonical node/observation identity and original Evidence. Paths
match Evidence artifact-path/source-range locations; missing properties remain
omitted and source coverage stays separate from page exhaustion. Batch paths and
select only needed property keys; complete Evidence remains accessible by export.
If names are unknown, opt into `include_available_property_keys: true`; it lists
the original keys per returned observation without unselected values. Keep each
row's node/observation identity paired when composing facts.
These rows select application-graph observations; semantic relationships and
semantic unknown records remain in the complete parent Evidence and trace tools.
@@ -124,26 +124,6 @@ operation's full ordered list. Candidate capabilities describe possible
providers. Top-level session capabilities describe the current route, and
`analysis_provider_binding` identifies the selected provider.
## Static memory and original file bytes
For Ghidra, `read_bytes` reads initialized analysis memory, including loader
fixups; it does not read a running process. Check `returned_bytes` and `complete`
before decoding a table. An incomplete read is missing coverage, not a zero-filled
tail. Use `list_segments` to inspect the selected block's initialization and address-space
facts, and retain unavailable facts as unknown.
Use `address_to_file_offset` to anchor one observed address to original file
bytes. A mapping for the first address does not establish a contiguous mapping
for an entire table, and loader fixups can make analysis bytes differ from source
bytes. Keep source ranges and analysis-memory observations separate.
A pointer table can refer to writable slots populated by a constructor rather
than directly to immutable resources. An uninitialized block or an observed zero
does not establish the slot's later runtime value. Follow `xrefs` and the relevant
writer's assembly or pseudocode; distinguish recorded assignments from inferred
execution order. Do not replace unreadable bytes with zeros or conclude that a
resource is absent without the necessary initialization evidence.
## DOS MZ with Ghidra
For an admitted DOS MZ target, use `inspect_native_load_image` to check measured
@@ -153,8 +133,10 @@ reported static image, not runtime DOS or PC-98 hardware behavior.
For Ghidra decompilation, `procedure_pseudo_code` also accepts `procedure: "file-offset:0x..."`; CLI `rea decompile <path> --file-offset=0x... --provider ghidra` resolves the source byte offset internally. An unresolved 0x-prefixed numeric procedure selector also falls back to a unique file mapping. Existing symbols and analysis addresses win; multiple mappings fail as ambiguous. Preserve the returned file-offset and address locations and raw selection observations. ELF virtual addresses are distinct from file offsets; never assume an arbitrary offset plus image base is an analysis address.
Complete function body ranges use inclusive ends and can contain gaps. Do not
treat the enclosing span as code.
Use `read_bytes` for initialized analysis memory and `address_to_file_offset` to
anchor one observed address to original file bytes. Loader fixups can change a
word; a source offset does not imply byte equality. Complete function body ranges
use inclusive ends and can contain gaps. Do not treat the enclosing span as code.
For packed targets, retain the original and separately derived artifact identities;
decompiling an unpacking stub does not recover the unpacked program.
@@ -264,15 +246,13 @@ context. PSP/stack/device state remains unmodeled. See [DOS guide](https://githu
For other headerless images (embedded firmware without ELF/Mach-O/PE/MZ
headers), open with `format: "raw-binary"`, `architecture` (`x86`, `x86_64`,
`arm`, `arm64`, `6502`, or `m68k`), and `entry_point` (`0x` hex). File offset 0 is mapped at
`arm`, `arm64`, or `6502`), and `entry_point` (`0x` hex). File offset 0 is mapped at
that address. Hopper and IDA refuse this interpretation; Ghidra uses
`BinaryLoader` with a generic language: big-endian for `m68k`, little-endian
otherwise. Big-endian ARM, Thumb-only, and Cortex-M variants are unsupported.
`6502` selects NMOS 6502; the entry and complete file mapping must fit within
`0x0000..0xffff`. 65C02, 65816, cartridge containers, bank switching, and mapper
semantics are unsupported. `m68k` requires an even entry and decodes the 68040
superset of the 68000 family; Amiga/Atari containers and vector-table entry
discovery are unsupported. Windows Ghidra P0 admits raw images only for `6502`. See [raw binary guide](https://github.com/morluto/rea/blob/main/docs/raw-binary.md).
`BinaryLoader` with a little-endian generic language. Big-endian, Thumb-only,
and Cortex-M variants are unsupported. `6502` selects NMOS 6502; the entry and
complete file mapping must fit within `0x0000..0xffff`. 65C02, 65816, cartridge
containers, bank switching, and mapper semantics are unsupported. Windows
Ghidra P0 admits raw images only for `6502`. See [raw binary guide](https://github.com/morluto/rea/blob/main/docs/raw-binary.md).
### Function annotations in Ghidra
@@ -24,7 +24,19 @@ runs:
BUILD_CACHE_PREFIX: rea-portable-build-v2-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.npmrc', '.nvmrc', 'package-lock.json') }}
run: |
npm run --silent test:prepare -- --dry=json |
node scripts/ci/portable-build-cache.mjs key >> "$GITHUB_OUTPUT"
node --input-type=module -e '
import { createHash } from "node:crypto";
import { readFileSync } from "node:fs";
const { tasks } = JSON.parse(readFileSync(0, "utf8"));
const hashes = tasks.map(({ taskId, hash }) => {
if (typeof hash !== "string")
throw new Error(`Build task ${taskId} must have an eager Turbo hash`);
return `${taskId}:${hash}`;
}).sort();
const hash = createHash("sha256").update(hashes.join("\n")).digest("hex");
console.log(`key=${process.env.BUILD_CACHE_PREFIX}-${hash}`);
console.log(`prefix=${process.env.BUILD_CACHE_PREFIX}-`);
' >> "$GITHUB_OUTPUT"
- name: Restore portable build outputs
if: inputs.build_cache_artifact == '' && inputs.save != 'true'
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
+2 -24
View File
@@ -60,7 +60,6 @@ jobs:
web_runtime: ${{ steps.plan.outputs.web_runtime }}
web_source_map: ${{ steps.plan.outputs.web_source_map }}
nativeaot: ${{ steps.plan.outputs.nativeaot }}
ghidra_bridge: ${{ steps.plan.outputs.ghidra_bridge }}
website: ${{ steps.plan.outputs.website }}
matrix: ${{ steps.plan.outputs.matrix }}
test_selection: ${{ steps.plan.outputs.test_selection }}
@@ -140,11 +139,6 @@ jobs:
- name: Validate workflow syntax and expressions
if: needs.changes.outputs.workflows == 'true'
run: go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.7 -shellcheck= -pyflakes=
# Code tiers run this source-only policy test in their existing shards.
# Workflow-only changes need the guard, without preparing runtime artifacts.
- name: Check action pins for workflow-only changes
if: needs.changes.outputs.workflows == 'true' && needs.changes.outputs.code != 'true'
run: node scripts/run-exact-tests.mjs run tests/boundary/filesystem/workflowActionPinning.test.ts
- name: Record static task source and execution identity
continue-on-error: true
if: needs.changes.outputs.code == 'true'
@@ -357,15 +351,10 @@ jobs:
# test:prepare caches only portable JS, skill, and catalog outputs.
# Native package jobs still run their build and prepack checks; Turbo
# restores matching outputs or rebuilds when their inputs differ.
- name: Stage current portable build task cache
shell: bash
run: |
# A new Turbo dry run can evict the entries this build just used.
node scripts/ci/portable-build-cache.mjs snapshot < .cache/ci-build-plan.json
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: rea-build-cache
path: .cache/ci-build-cache/
path: .turbo/cache/
include-hidden-files: true
if-no-files-found: error
retention-days: 7
@@ -653,7 +642,6 @@ jobs:
tests/boundary/cli/nativePlistPrototypeKeyCli.test.ts
tests/boundary/cli/nativePlistSelectionFailureCli.test.ts
tests/boundary/cli/nativeDemangleCli.test.ts
tests/boundary/cli/nativeDispatchPropertyAttributes.test.ts
tests/boundary/mcp/nativeDemangleMcp.test.ts
tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts
tests/boundary/cli/nativeSignatureCli.test.ts
@@ -716,12 +704,12 @@ jobs:
with:
name: rea-build-cache
path: .turbo/cache/
- run: npm run build:cached
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: windows-native-controls
path: native/windows/build/
- run: npm run verify:windows-native:artifact
- run: npm run build:cached
- name: Record named Windows host capabilities
run: node scripts/windows-capabilities.mjs | Out-File -Encoding utf8NoBOM windows-capabilities.json
- name: Validate Windows host capability report
@@ -753,8 +741,6 @@ jobs:
tests/boundary/filesystem/javascriptApplicationWorkflows.test.ts
tests/boundary/filesystem/webScriptManifestPaths.test.ts
tests/boundary/process/ProcessEvidence.host.test.ts
tests/boundary/process/packageNpmInvocation.test.ts
tests/boundary/process/packedBridgeVerification.test.ts
tests/boundary/process/windowsOutputCapture.test.ts
tests/acceptance/webModuleCli.test.ts
tests/acceptance/webSourceLocationCli.test.ts
@@ -777,8 +763,6 @@ jobs:
src/process/ProcessOwnership.validation.test.ts
src/application/Update.test.ts
tests/process-global/updateMaintenance.test.ts
tests/process-global/runnerCancellation.test.ts
tests/process-global/windowsOwnedCommand.test.ts
tests/conformance/providers/ghidra/realGhidraWindowsWorkflow.test.ts
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
@@ -914,11 +898,6 @@ jobs:
if: needs.changes.outputs.nativeaot == 'true'
uses: ./.github/workflows/nativeaot-fixtures.yml
ghidra_bridge:
needs: [changes, static]
if: needs.changes.outputs.ghidra_bridge == 'true'
uses: ./.github/workflows/ghidra-bridge-sources.yml
website:
needs: [changes, static]
if: needs.changes.outputs.website == 'true'
@@ -954,7 +933,6 @@ jobs:
web_runtime,
web_source_map,
nativeaot,
ghidra_bridge,
website,
]
runs-on: ubuntu-24.04
@@ -1,48 +0,0 @@
name: Ghidra bridge source compilation
on:
workflow_dispatch:
workflow_call:
permissions:
contents: read
env:
HUSKY: "0"
jobs:
ghidra-bridge-sources:
name: Compile packaged Ghidra bridge sources
runs-on: ubuntu-24.04
timeout-minutes: 15
env:
GHIDRA_RELEASE_URL: https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_12.1.4_build/ghidra_12.1.4_PUBLIC_20260921.zip
GHIDRA_RELEASE_SHA256: ddac49f903da9d5bac833e5cc79395098b9c33cfd3279be5f31bd00387d2d4db
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: .nvmrc
- name: Validate the SDK pin against the provider's verified release
run: node scripts/verify-ghidra-bridge-sources.mjs --check-sdk-pin >> "$GITHUB_ENV"
# Only the jars and application.properties are extracted: the check
# compiles against them and never launches Ghidra or imports a target.
- name: Acquire checksum-verified Ghidra jars in isolated runner storage
shell: bash
run: |
ghidra_root="${RUNNER_TEMP}/rea-ghidra"
mkdir -p "${ghidra_root}"
curl -fsSL --retry 3 --write-out 'ghidra_download_bytes=%{size_download} ghidra_download_seconds=%{time_total}\n' -o "${ghidra_root}/ghidra.zip" "${GHIDRA_RELEASE_URL}"
echo "${GHIDRA_RELEASE_SHA256} ${ghidra_root}/ghidra.zip" | sha256sum -c -
unzip -q "${ghidra_root}/ghidra.zip" '*/Ghidra/*.jar' '*/Ghidra/application.properties' -d "${ghidra_root}"
rm "${ghidra_root}/ghidra.zip"
properties="$(find "${ghidra_root}" -path '*/Ghidra/application.properties' -print -quit)"
test -n "${properties}"
echo "GHIDRA_INSTALL_DIR=$(dirname "$(dirname "${properties}")")" >> "${GITHUB_ENV}"
# JAVA_HOME_<major>_X64 comes from the runner image, not the env context.
- name: Compile bridge sources with the verified runner JDK
shell: bash
run: |
java_home_variable="JAVA_HOME_${GHIDRA_JAVA_MAJOR}_X64"
test -n "${!java_home_variable}"
JAVA_HOME="${!java_home_variable}" npm run verify:ghidra:bridge-sources -- --verified-sdk
+3 -3
View File
@@ -22,7 +22,7 @@ jobs:
sudo apt-get update
sudo apt-get install --no-install-recommends -y g++-mingw-w64-x86-64
- run: npm run build:windows-native
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@v4
with:
name: cutter-windows-native
path: native/windows/build/
@@ -53,7 +53,7 @@ jobs:
uses: ./.github/actions/npm-cache
- run: npm ci
- if: matrix.platform == 'Windows'
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
uses: actions/download-artifact@v4
with:
name: cutter-windows-native
path: native/windows/build/
@@ -67,7 +67,7 @@ jobs:
env:
EXPECTED_PLATFORM: ${{ matrix.platform }}
run: npm run verify:cutter
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@v4
if: always()
with:
name: cutter-upstream-${{ matrix.platform }}
+1 -1
View File
@@ -53,7 +53,7 @@ jobs:
- run: sudo apt-get update && sudo DEBIAN_FRONTEND=noninteractive apt-get install -y tshark util-linux python3
- run: npm ci
- run: npm run build:cached
- run: npm run test:focused -- tests/boundary/captures/fieldDiscovery.test.ts src/process/LinuxResourceLimits.test.ts tests/boundary/captures/captureProvider.test.ts tests/boundary/captures/captureDescriptorCleanup.test.ts tests/boundary/pcap/pcapProvider.test.ts tests/boundary/pcap/pcapProviderCrossPlatform.test.ts tests/boundary/captures/resourceLimits.test.ts tests/boundary/captures/packetOutput.test.ts tests/boundary/mcp/packetCaptureMcp.test.ts tests/boundary/cli/captureCleanup.test.ts
- run: npm run test:focused -- tests/boundary/captures/fieldDiscovery.test.ts src/process/LinuxResourceLimits.test.ts tests/boundary/captures/captureProvider.test.ts tests/boundary/captures/captureDescriptorCleanup.test.ts tests/boundary/captures/resourceLimits.test.ts tests/boundary/captures/packetOutput.test.ts tests/boundary/mcp/packetCaptureMcp.test.ts tests/boundary/cli/captureCleanup.test.ts
- run: node scripts/verify-packet-capture.mjs
env:
REA_TSHARK_COMMAND: /usr/bin/tshark
+5 -12
View File
@@ -24,19 +24,7 @@ jobs:
real-recorded-crash:
runs-on: ubuntu-24.04
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
image: ["ubuntu:24.04", "debian:trixie-slim"]
container: ${{ matrix.image }}
steps:
- name: Install fixture and debugger prerequisites in the disposable container
shell: bash
run: |
apt-get update -qq
apt-get install --yes --no-install-recommends \
ca-certificates git python3-venv gcc libc6-dev strace gdb
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
@@ -48,6 +36,11 @@ jobs:
- uses: ./.github/actions/portable-build-cache
with:
build_cache_artifact: ${{ inputs.build_cache_artifact }}
- name: Install GDB on the disposable CI runner
shell: bash
run: |
sudo apt-get update -qq
sudo apt-get install --yes --no-install-recommends gdb
- name: Acquire exact unchanged upstreams in isolated runner storage
shell: bash
run: |
+1 -1
View File
@@ -1,3 +1,3 @@
{
".": "6.7.0"
".": "6.5.0"
}
-2
View File
@@ -20,8 +20,6 @@ Give each interpretation and resource a clear owner. Consumers must use that own
Keep proof of ownership separate from validity, editability, and readiness. Malformed owned data may still be safely removable. Unresolved identity or applicability must remain unknown rather than be treated as absent, foreign, or aligned.
For lifecycle changes, follow [ownership and completion invariants](docs/tool-design.md#own-the-lifecycle) and select the applicable [lifecycle regressions](docs/testing.md#lifecycle-regressions). Include late handshakes, cancellation during final cleanup, mixed child outcomes, and cleanup retry where those stages exist; active-execution cancellation alone does not cover finalization.
Assess brittleness in touched code during implementation, debugging, review, and maintenance. Fix the producing representation or ownership rule before adding downstream repairs. Normalize once at the owning boundary using format-aware parsers. Remove superseded representations, aliases, wrappers, and redundant tests after verifying affected consumers. Introduce abstractions only when they remove observed complexity.
When fixing a bug, inspect the producing boundary and affected consumers for duplicated interpretation or unclear ownership. Complete any directly related refactor in the same change and remove superseded code. Passing regression tests alone does not establish that the brittleness is resolved. If related cleanup remains, explain what remains and why.
-88
View File
@@ -1,93 +1,5 @@
# Changelog
## [6.7.0](https://github.com/morluto/rea/compare/rea-agents-6.6.0...rea-agents-6.7.0) (2026-10-18)
### Highlights
- Client configuration edits follow the duplicate-member semantics used by MCP clients.
### Changes
- Includes the [6.6.0 changes and migration notes](https://github.com/morluto/rea/releases/tag/rea-agents-6.6.0). That version was tagged but was not published to npm.
### Fixes
- **Client configuration:** Setup edits the last repeated JSON/JSONC member, matching the value clients actually read. Setup and uninstall refuse a removal that would reactivate a shadowed duplicate, preserving the original configuration. ([#4957](https://github.com/morluto/rea/pull/4957), [morluto/rea#4952](https://github.com/morluto/rea/issues/4952)). Thanks @kaoru0822-kitauji, @xu91102.
Full contribution record: [4 commits and 1 merged PR](https://github.com/morluto/rea/blob/rea-agents-6.7.0/docs/releases/6.7.0.contributions.json).
## [6.6.0](https://github.com/morluto/rea/compare/rea-agents-6.5.0...rea-agents-6.6.0) (2026-10-18)
### Highlights
- Add Kuna as a caller-supplied static-analysis provider.
- Query selected JavaScript facts and multiple APK locale tables without repeating the underlying analysis.
- Extend Ghidra analysis to Windows ARM PE targets and explicit raw m68k images.
- Preserve completed Evidence, cancellation reasons and retryable cleanup across provider and CLI finalization.
### Changes
- **Kuna analysis:** Use a caller-installed Kuna for procedure listings, pseudocode, assembly, call relationships, exact-address xrefs and cached string searches. Project exports retain source spans and digests; repeated requests reuse completed work. Recorded real-provider coverage uses Kuna 1.833 on Linux; Windows, PE and universal Mach-O are unsupported. See [the provider guide](docs/kuna-provider.md). ([#3832](https://github.com/morluto/rea/pull/3832), [#3854](https://github.com/morluto/rea/pull/3854), [#4071](https://github.com/morluto/rea/pull/4071), [#4095](https://github.com/morluto/rea/pull/4095)). Thanks @gensokyo-dev, @kaoru0822-kitauji, @N0zoM1z0.
- **Retained JavaScript facts:** Query exact application paths, selected properties and filtered module references through `inspect_analysis_view`, with paging and complete row Evidence. These views reuse completed analysis and preserve source selection and unknown coverage. ([#4265](https://github.com/morluto/rea/pull/4265), [morluto/rea#4190](https://github.com/morluto/rea/issues/4190), [#4097](https://github.com/morluto/rea/pull/4097), [morluto/rea#4092](https://github.com/morluto/rea/issues/4092)). Thanks @kaoru0822-kitauji, @N0zoM1z0.
- **APK locale tables:** Request several resource locales in one decode with repeatable CLI `--locales` or MCP `locales`. Each table reports its status and coverage; existing single-locale fields remain available. ([#4804](https://github.com/morluto/rea/pull/4804), [morluto/rea#4777](https://github.com/morluto/rea/issues/4777)). Thanks @abhay-2108, @N0zoM1z0.
- **Windows ARM binaries:** Ghidra admits ARMNT/Thumb-2 and ARM64 PE applications and DLLs on the Windows x64 host lane. Recorded Ghidra 12.1.4 verification uses `WindowsResourceReference` disabled and raised startup budgets; default-analyzer completion, ARM64EC/ARM64X and Windows-on-Arm hosts remain unverified or unsupported. See [the exact scope](docs/windows-ghidra-p0.md#native-authority-and-target-identity). ([#3965](https://github.com/morluto/rea/pull/3965), [morluto/rea#2186](https://github.com/morluto/rea/issues/2186)). Thanks @N0zoM1z0, @WestLabsAI.
- **Raw m68k images:** Analyze explicitly selected big-endian m68k raw binaries using Ghidra’s fixed 68000 profile and a caller-supplied aligned entry. Real CLI/MCP verification used Ghidra 12.1.4 on macOS arm64; Linux is unverified and Windows P0 does not admit m68k. See [mapping requirements](docs/raw-binary.md). ([#4018](https://github.com/morluto/rea/pull/4018)). Thanks @icedac.
- **JADX deadlines:** Set `REA_JADX_OPERATION_TIMEOUT_MS` to extend APK loading and upstream operation deadlines together. Doctor reports the effective value and setup forwards an explicit selection. ([#4466](https://github.com/morluto/rea/pull/4466), [morluto/rea#3918](https://github.com/morluto/rea/issues/3918)). Thanks @jaychou813, @SandstromPL.
- **Electron window options:** Resolve stable local constant `BrowserWindow` options while retaining source provenance. Relevant writes and escapes keep the result unknown. ([#4400](https://github.com/morluto/rea/pull/4400), [morluto/rea#4366](https://github.com/morluto/rea/issues/4366)). Thanks @kaoru0822-kitauji, @N0zoM1z0.
- **Language editions:** Add the Greek website edition and Malayalam documentation, with Korean typography and translation corrections across the site. ([#3520](https://github.com/morluto/rea/pull/3520), [#4792](https://github.com/morluto/rea/pull/4792), [#3821](https://github.com/morluto/rea/pull/3821), [morluto/rea#3820](https://github.com/morluto/rea/issues/3820), [#3799](https://github.com/morluto/rea/pull/3799), [morluto/rea#3798](https://github.com/morluto/rea/issues/3798), [#4344](https://github.com/morluto/rea/pull/4344), [#3856](https://github.com/morluto/rea/pull/3856), [#4166](https://github.com/morluto/rea/pull/4166)). Thanks @gensokyo-dev, @hi2242, @kalayciburak, @kaoru0822-kitauji, @kraken-503, @kukinghan, @N0zoM1z0, @yeseong0412.
### Fixes
- **Cancellation and cleanup:** Keep completed observations, exact cancellation reasons and the original physical failure through finalization. Failed cleanup retains its process or file owner for retry; recovered resources disappear from pending-cleanup reports without replacing the original error. ([#4238](https://github.com/morluto/rea/pull/4238), [morluto/rea#4232](https://github.com/morluto/rea/issues/4232), [#4274](https://github.com/morluto/rea/pull/4274), [morluto/rea#3923](https://github.com/morluto/rea/issues/3923), [3e82366](https://github.com/morluto/rea/commit/3e8236639abffa39deb5d5e939ec8baf6aaf3ca3), [16924e2](https://github.com/morluto/rea/commit/16924e275e939d0543ba01493324959a9e1d731c), [bbfe6ed](https://github.com/morluto/rea/commit/bbfe6edd60290f9bfbec68c8a0bcf605d8bbf5b3), [1f23e97](https://github.com/morluto/rea/commit/1f23e977b50301e91f02a4a17c9f8d48bb7b60f3), [08fbeb8](https://github.com/morluto/rea/commit/08fbeb8bdab27118b6c57039aef7c0fa8b6463bc)). Thanks @coygeek.
- **Provider startup:** Join prerequisite probes and in-flight readiness work before shutdown, preserve typed timeout and JVM-memory failures, and retain startup diagnostics through cleanup. Ghidra recognizes keg-only Homebrew JDKs and names the setting responsible for a startup timeout. ([376eeca](https://github.com/morluto/rea/commit/376eeca770820b31f7f8d4c5fcc397315621643e), [ceeff5a](https://github.com/morluto/rea/commit/ceeff5a41788e47e5aee96a4baf191a6ce7fde4b), [3ad1032](https://github.com/morluto/rea/commit/3ad1032b11edea2dcb054e78f951cc43159ae83d), [964decd](https://github.com/morluto/rea/commit/964decd989acfa84c4bfc3295362c4c46877fc20), [3fa972a](https://github.com/morluto/rea/commit/3fa972af7c7cb6cf014ffc426bdf7130dc6f2fd2), [#4557](https://github.com/morluto/rea/pull/4557), [morluto/rea#4556](https://github.com/morluto/rea/issues/4556), [#4590](https://github.com/morluto/rea/pull/4590), [morluto/rea#4241](https://github.com/morluto/rea/issues/4241)). Thanks @DanielCvz1, @J0UH, @Rinkia, @RishTheFish21, @vadlachary2002.
- **Client configuration:** Preserve the selected launcher, destination file, caller timeout choices and unresolved configuration evidence. Setup/uninstall recovery stays bound to the exact published file, keeps current verified backups, and transfers failed cleanup ownership for retry. ([d0253c9](https://github.com/morluto/rea/commit/d0253c99d65afbbd12732a2fdaf711640574e17f), [7e4eed9](https://github.com/morluto/rea/commit/7e4eed9dd48485b6a7100300aa98401811c2deb9), [2fb5e20](https://github.com/morluto/rea/commit/2fb5e204a35723f6f843d56ca47b0db94d8fcc44), [8235210](https://github.com/morluto/rea/commit/823521085a28f825e7fee1929d852d420042d1f7), [d818c3d](https://github.com/morluto/rea/commit/d818c3d2639d3115edb8a5269a754101aea6c3bd), [19329e4](https://github.com/morluto/rea/commit/19329e43bb38ca9d64512d801b25abcb188d2512), [dadf909](https://github.com/morluto/rea/commit/dadf909dce2e8b3d055541de69b4118d21276316), [333e0ab](https://github.com/morluto/rea/commit/333e0ab0dfc126a9915907d5079ed6195190e38e), [c15c206](https://github.com/morluto/rea/commit/c15c2062ad815cc9a3222ccfaeb7ef53cacd8b72)). Thanks @Adolanium.
- **Configuration formats:** Read signed 64-bit TOML integers without rounding, handle large TOML documents without argument-spread failures, preserve JSONC trivia and Hermes YAML scalar text, and reject NUL bytes in registration environment values. ([#4937](https://github.com/morluto/rea/pull/4937), [morluto/rea#4917](https://github.com/morluto/rea/issues/4917), [c43bc0b](https://github.com/morluto/rea/commit/c43bc0bf66a4e245a0cafa40def0d0207bcbd73c), [4fd28fc](https://github.com/morluto/rea/commit/4fd28fc9e0c4f8358147af38c72ab9e814f52d61), [#3568](https://github.com/morluto/rea/pull/3568), [#4335](https://github.com/morluto/rea/pull/4335)). Thanks @alfredo1491, @gensokyo-dev, @kaoru0822-kitauji, @N0zoM1z0, @ShuaixinHuang, @xu91102.
- **Claude Code configuration:** Setup, doctor and uninstall now accept only the strict JSON format Claude Code reads, including a leading UTF-8 BOM. Comments and trailing commas are refused before backup or writing; clients that support JSONC retain their existing behavior. ([#4944](https://github.com/morluto/rea/pull/4944), [morluto/rea#4940](https://github.com/morluto/rea/issues/4940)). Thanks @kaoru0822-kitauji, @xu91102.
- **CLI output and dispatch:** Accept `--flag=value` and spaced global output values, keep array positions in filtered JSON, validate integer tokens before coercion, and exit quietly when the output reader closes. Cancellation remains effective through command finalization; app bundles and static native inspections select the intended workflow. ([#3811](https://github.com/morluto/rea/pull/3811), [#4823](https://github.com/morluto/rea/pull/4823), [2ae4e16](https://github.com/morluto/rea/commit/2ae4e1608f290c95ff7cff28c4d16a79b301d03d), [8d82579](https://github.com/morluto/rea/commit/8d8257928bbe8d43fedffc4db5fca26c8108820f), [#3781](https://github.com/morluto/rea/pull/3781), [279c590](https://github.com/morluto/rea/commit/279c590ef6bb737d4a48ea696a0ae5eb30010b3d), [#3511](https://github.com/morluto/rea/pull/3511), [morluto/rea#3321](https://github.com/morluto/rea/issues/3321), [f31b231](https://github.com/morluto/rea/commit/f31b231a92a61be6bd1800b16be0b3210ae82944)). Thanks @arjunprabhulal, @coygeek, @kaoru0822-kitauji, @ShuaixinHuang, @Sriram-PR, @Tapraj-Pathak.
- **Updates:** Route `--update` through the verified updater and bound retained package-manager diagnostics. ([4f7b5fb](https://github.com/morluto/rea/commit/4f7b5fb6023ce2ec449561782d09e3c7e5ac7c7b), [01cdbbd](https://github.com/morluto/rea/commit/01cdbbdc556262c47d04a5b3391dd9c17946d3fc)).
- **MCP contracts:** Advertise self-contained tool inputs while preserving tuple, array, Boolean and nested-JSON constraints across schema profiles. Schema-reference handling no longer rewrites literal metadata; catalog identity includes the output-schema profile. ([5e30969](https://github.com/morluto/rea/commit/5e30969cc5f1255d44ec7a1f1ca8dbac0af5e7c4), [10aa74d](https://github.com/morluto/rea/commit/10aa74dfedc3ae776f50d1fa1eb83b64ae82d3d6), [204b9f3](https://github.com/morluto/rea/commit/204b9f3ac140a993c3e458bb0e117de31818ab29), [b3389a5](https://github.com/morluto/rea/commit/b3389a5b0834265fe7a40391be315d810a53a97e), [a2e3016](https://github.com/morluto/rea/commit/a2e30168a046f3b79319eb7fbaf807b802104199), [ba98130](https://github.com/morluto/rea/commit/ba98130049fa40ade66b03611ff70c7ddc011a1d), [c5fb86d](https://github.com/morluto/rea/commit/c5fb86d1948af0a287a581b29b2b1d554743c607)). Thanks @akushonkamen, @HarsH-1877, @kaoru0822-kitauji, @xingzihai.
- **Session ordering:** Keep snapshot admission ahead of later calls on the same connection, retain shutdown signals until cleanup succeeds, and preserve inspection authority through investigation publication. ([#3661](https://github.com/morluto/rea/pull/3661), [morluto/rea#3334](https://github.com/morluto/rea/issues/3334), [8873b39](https://github.com/morluto/rea/commit/8873b39770e89eae22b7693bc492d7e423b22bea), [663d07f](https://github.com/morluto/rea/commit/663d07f02cd62c99d81c59391d2c6d745c875335)). Thanks @coygeek, @rudycelekli, @Swatantra-66.
- **JavaScript exports and resolution:** Retain CommonJS exports created with `Object.defineProperty` and track export receiver lifetimes. Resolve scoped packages, package `main`, JSON requires and `.mts`/`.cts` imports using the owning loader; overwritten `require` bindings and erased type-only imports no longer create false runtime links. ([#4725](https://github.com/morluto/rea/pull/4725), [morluto/rea#4724](https://github.com/morluto/rea/issues/4724), [#3567](https://github.com/morluto/rea/pull/3567), [morluto/rea#3541](https://github.com/morluto/rea/issues/3541), [#4838](https://github.com/morluto/rea/pull/4838), [morluto/rea#4632](https://github.com/morluto/rea/issues/4632), [#3844](https://github.com/morluto/rea/pull/3844), [morluto/rea#3383](https://github.com/morluto/rea/issues/3383), [#4164](https://github.com/morluto/rea/pull/4164), [morluto/rea#3915](https://github.com/morluto/rea/issues/3915), [#4223](https://github.com/morluto/rea/pull/4223), [#3801](https://github.com/morluto/rea/pull/3801), [morluto/rea#3393](https://github.com/morluto/rea/issues/3393), [#4165](https://github.com/morluto/rea/pull/4165), [morluto/rea#3932](https://github.com/morluto/rea/issues/3932)). Thanks @Abishek0070, @coygeek, @JNTMTMTM, @kaoru0822-kitauji, @prasad2512, @rodricksz4h5, @xu91102.
- **JavaScript value flow:** Preserve values captured before later assignments, guarded factory fallthrough and nested destructuring. Track exact property keys and setter writes; direct `eval`, compound assignments and incoming callbacks preserve unresolved effects instead of inventing certainty. ([#4196](https://github.com/morluto/rea/pull/4196), [morluto/rea#3881](https://github.com/morluto/rea/issues/3881), [#4341](https://github.com/morluto/rea/pull/4341), [morluto/rea#3963](https://github.com/morluto/rea/issues/3963), [bfb7ed0](https://github.com/morluto/rea/commit/bfb7ed0bd43edc605e00fc52c6e21e735b285904), [#3480](https://github.com/morluto/rea/pull/3480), [#3831](https://github.com/morluto/rea/pull/3831), [morluto/rea#3312](https://github.com/morluto/rea/issues/3312), [9ac76d3](https://github.com/morluto/rea/commit/9ac76d3d9486856d25395b413d7ac5ffa744cad0), [#4342](https://github.com/morluto/rea/pull/4342), [morluto/rea#4206](https://github.com/morluto/rea/issues/4206), [#4243](https://github.com/morluto/rea/pull/4243), [morluto/rea#3880](https://github.com/morluto/rea/issues/3880)). Thanks @coygeek, @kaoru0822-kitauji, @maxazure, @N0zoM1z0, @ShuaixinHuang.
- **JavaScript relationships:** Distinguish `Map` reads from network endpoints, associate response endpoints only with writes that reach the read, and preserve child-process receiver ownership and effective stdio choices. Version comparisons keep relocation and unknown relationships distinct from application changes. ([fbfdb6a](https://github.com/morluto/rea/commit/fbfdb6abe9d663be0be146a15a489e33ccba0f68), [#4759](https://github.com/morluto/rea/pull/4759), [morluto/rea#4606](https://github.com/morluto/rea/issues/4606), [#3819](https://github.com/morluto/rea/pull/3819), [morluto/rea#3362](https://github.com/morluto/rea/issues/3362), [#4336](https://github.com/morluto/rea/pull/4336), [morluto/rea#3355](https://github.com/morluto/rea/issues/3355), [556504e](https://github.com/morluto/rea/commit/556504edcbb0f8cd9eaf81a91b18ff891b8f5457), [4d980d0](https://github.com/morluto/rea/commit/4d980d017622d3175d86aaf3b0dcfbdf4ca3d091)). Thanks @Abdooo2235, @coygeek, @kaoru0822-kitauji, @Xinglan233.
- **JavaScript source admission:** Parse JavaScript with its own grammar, refuse FIFO recovery inputs without blocking, and report oversized or resource-skipped files with their actual capacity and coverage state. Malformed runtime events stay excluded rather than becoming policy-filtered facts. ([#3782](https://github.com/morluto/rea/pull/3782), [morluto/rea#3780](https://github.com/morluto/rea/issues/3780), [#3788](https://github.com/morluto/rea/pull/3788), [morluto/rea#3332](https://github.com/morluto/rea/issues/3332), [#4757](https://github.com/morluto/rea/pull/4757), [morluto/rea#4629](https://github.com/morluto/rea/issues/4629), [#3852](https://github.com/morluto/rea/pull/3852), [morluto/rea#3670](https://github.com/morluto/rea/issues/3670), [#4755](https://github.com/morluto/rea/pull/4755), [morluto/rea#4685](https://github.com/morluto/rea/issues/4685)). Thanks @andresaragon, @coygeek, @kaoru0822-kitauji, @sx4im.
- **Browser capture:** Bound CDP handshakes and command responses, preserve malformed inventory uncertainty and partial cleanup diagnostics, and report cancellation after content reads and final cleanup. Accessibility comparisons require observed coverage; attached emulation teardown limits remain explicit. ([#3555](https://github.com/morluto/rea/pull/3555), [morluto/rea#3553](https://github.com/morluto/rea/issues/3553), [#3901](https://github.com/morluto/rea/pull/3901), [morluto/rea#3379](https://github.com/morluto/rea/issues/3379), [4cc044b](https://github.com/morluto/rea/commit/4cc044be68f813e96907e6cedcf422d0a3170de3), [#4406](https://github.com/morluto/rea/pull/4406), [morluto/rea#4403](https://github.com/morluto/rea/issues/4403), [#2893](https://github.com/morluto/rea/pull/2893), [0123d59](https://github.com/morluto/rea/commit/0123d5976828bfe621bd51daa4cf39fee48a1349), [2ff0867](https://github.com/morluto/rea/commit/2ff086796ad7b8f60397956750584e170dbe2910)). Thanks @coygeek, @dakjdakd, @kaoru0822-kitauji, @maxazure, @N0zoM1z0, @YunzhouLi-hub.
- **Browser page facts:** Preserve URL path bytes when removing credentials, repeated document `Link` headers and complete COOP/COEP structured items. WebMCP discovery reads the actual schema properties and exact receiver path. ([#4731](https://github.com/morluto/rea/pull/4731), [df2fc25](https://github.com/morluto/rea/commit/df2fc251e318a1255309dba232f9f73c700777b6), [c360cfc](https://github.com/morluto/rea/commit/c360cfcd6d7901514b16dd6113eba2e0b0fdf422), [ebd5a82](https://github.com/morluto/rea/commit/ebd5a82c439f6deb3a06062225ce009eb03257cf), [38f92d1](https://github.com/morluto/rea/commit/38f92d108e3148cdf47e4ffbfe3de8a76e795d51)). Thanks @Abdooo2235, @geekwolf, @ShuaixinHuang.
- **Electron runtime capture:** Keep native IPC listener and one-shot dispatch behavior, block synchronous shell effects during capture, refuse active scenarios when the inspect fuse is disabled, and preserve fuse/transport cleanup ownership. ([#4389](https://github.com/morluto/rea/pull/4389), [morluto/rea#4390](https://github.com/morluto/rea/issues/4390), [#4605](https://github.com/morluto/rea/pull/4605), [morluto/rea#4593](https://github.com/morluto/rea/issues/4593), [#4562](https://github.com/morluto/rea/pull/4562), [morluto/rea#4393](https://github.com/morluto/rea/issues/4393), [#3605](https://github.com/morluto/rea/pull/3605), [morluto/rea#3453](https://github.com/morluto/rea/issues/3453), [f9de413](https://github.com/morluto/rea/commit/f9de41371f7536e2e22ce6e43c9314fa2f238a30), [e7df00e](https://github.com/morluto/rea/commit/e7df00e80777757b329bbe8aba6d421d8892b9d5)). Thanks @Adolanium, @gensokyo-dev, @gkobayashi0, @HarsH-1877, @kaoru0822-kitauji, @keeponlight, @N0zoM1z0, @Nitin13-git, @xu91102.
- **APK resource accuracy:** Retain completed tables and decode facts after interrupted or failed reads. Derive locale limits from resource configuration fields, disclose unselectable qualified tables, distinguish document failures from omitted entries, and bind Evidence to the decoded snapshot. ([34a88d6](https://github.com/morluto/rea/commit/34a88d6c1674710953e2c94bd0a17332cd69ca6f), [f5fcf52](https://github.com/morluto/rea/commit/f5fcf5216ffb3a266b8c00f6d9a0943051084ab5), [6385ef4](https://github.com/morluto/rea/commit/6385ef4355d7a794b3154ee38529cbddee583336), [98886ad](https://github.com/morluto/rea/commit/98886adddfcbd7b4f4236b3a9825f91878c3cb11), [dc2e811](https://github.com/morluto/rea/commit/dc2e8117b60c4481372ed89b077e6c1cf81ee653), [#4771](https://github.com/morluto/rea/pull/4771), [morluto/rea#4768](https://github.com/morluto/rea/issues/4768)). Thanks @abhay-2108, @gensokyo-dev, @Iyanuoluwa007, @kaoru0822-kitauji, @N0zoM1z0.
- **Apktool guidance:** Retain the observed version and disclose the matching platform/release advisory windows without treating a version string as proof of decoder safety. Missing prerequisites and decode refusals identify the selected APK or launcher. ([d38f099](https://github.com/morluto/rea/commit/d38f099692394ec90c582f9f0a14b036b421b160), [63696d2](https://github.com/morluto/rea/commit/63696d277328f556c971d1fc9f81ae83128d468b), [cc038da](https://github.com/morluto/rea/commit/cc038da218cada68c87700477aba3db4739791ff)). Thanks @GovinduSasanka, @peter-research.
- **Android method bodies:** Recover original bytecode bodies when Java source is omitted while preserving genuine native/abstract body absence and primary failures during retryable cleanup. ([63c65a2](https://github.com/morluto/rea/commit/63c65a22430a4bbc0c1807a0298edb867775001f), [742b6f5](https://github.com/morluto/rea/commit/742b6f587f3c4ef1b8212e7376d6f3a305b194dc), [9fa6d2b](https://github.com/morluto/rea/commit/9fa6d2b254cc390665974efb52463386a029e9fc)). Thanks @balkan16, @Chessing234.
- **ADB observations and transfers:** Preserve display-scoped focus, distinguish missing declarations from absent focus, retain numeric physical density and mark unknown permission coverage partial. Transfers use consumed snapshot identity and refuse unknown destination existence; uninstall requests explicitly select user zero. ([7086768](https://github.com/morluto/rea/commit/7086768a27242a15daa93486aefbaacc3c891e78), [3d028db](https://github.com/morluto/rea/commit/3d028dbc74a465f6f8df1813a931fbb5362e7dc3), [#4074](https://github.com/morluto/rea/pull/4074), [morluto/rea#3942](https://github.com/morluto/rea/issues/3942), [#4663](https://github.com/morluto/rea/pull/4663), [#4665](https://github.com/morluto/rea/pull/4665), [1342127](https://github.com/morluto/rea/commit/1342127e91d4db8b4113a7a4e85be909bc96e1db), [61e6880](https://github.com/morluto/rea/commit/61e688070f48016b6d178cd04c02fcc2f33e19ad), [be0b2d1](https://github.com/morluto/rea/commit/be0b2d138c46bb951fc3c8ee57ef7b0d57fed312)). Thanks @Copilot, @coygeek, @gongfpp, @Tapraj-Pathak, @yankikucuk.
- **Apple metadata:** Preserve exact plist/keyed-archive integers, negative zero, non-finite real identity and dictionary keys. Reject malformed XML before value decoding, retain undecodable dates as unknown and report unsupported OpenStep entries explicitly. ([#4324](https://github.com/morluto/rea/pull/4324), [morluto/rea#4292](https://github.com/morluto/rea/issues/4292), [2cf9c28](https://github.com/morluto/rea/commit/2cf9c28f27261b7e64af2ba7ecb4e23ea7714aee), [#4839](https://github.com/morluto/rea/pull/4839), [morluto/rea#4834](https://github.com/morluto/rea/issues/4834), [f2b7bbb](https://github.com/morluto/rea/commit/f2b7bbb31279a820f4cf32d439570f8e5381d010), [6c98708](https://github.com/morluto/rea/commit/6c98708793c23615de8053b2cd14d9f164b960c5), [78cf610](https://github.com/morluto/rea/commit/78cf6100f33ad2412c0a3d60b83f8a44a43fbbb5), [c7e9e09](https://github.com/morluto/rea/commit/c7e9e096d3e2444e4c251123b8e914e9c0941f4e), [#3793](https://github.com/morluto/rea/pull/3793), [#4105](https://github.com/morluto/rea/pull/4105), [morluto/rea#3892](https://github.com/morluto/rea/issues/3892)). Thanks @coygeek, @kaoru0822-kitauji, @mertkayacs, @pablodiazjorge, @pollychen-lab, @xu91102.
- **Apple application structure:** Derive bundle components and launchd domains from their owning directories, retain unavailable components, and select only exact `Assets.car` names as asset catalogs. Interface Builder keeps unresolved classes and counts hierarchy records beyond the returned object page. ([149a0fc](https://github.com/morluto/rea/commit/149a0fc06c3c67ee45624e6da14dfb0754473758), [5d6029e](https://github.com/morluto/rea/commit/5d6029ea62a65ec34fd739ee40223c77c6fdb63b), [c192c58](https://github.com/morluto/rea/commit/c192c58815ddeaf5cf30159e7082c742c0bc36b7), [#4094](https://github.com/morluto/rea/pull/4094), [morluto/rea#3914](https://github.com/morluto/rea/issues/3914), [#4118](https://github.com/morluto/rea/pull/4118), [morluto/rea#3958](https://github.com/morluto/rea/issues/3958), [#4162](https://github.com/morluto/rea/pull/4162), [morluto/rea#3950](https://github.com/morluto/rea/issues/3950)). Thanks @coygeek, @kaoru0822-kitauji.
- **Native names and layout:** Keep valid Objective-C records beside malformed neighbors, preserve leading U+FEFF and repeated load-command fields, and select exact arm64e.x1 slices. PE resource ownership and NativeAOT reads stay within declared image/header ranges. ([#3833](https://github.com/morluto/rea/pull/3833), [morluto/rea#3336](https://github.com/morluto/rea/issues/3336), [#4549](https://github.com/morluto/rea/pull/4549), [morluto/rea#4540](https://github.com/morluto/rea/issues/4540), [morluto/rea#4541](https://github.com/morluto/rea/issues/4541), [#4730](https://github.com/morluto/rea/pull/4730), [#4048](https://github.com/morluto/rea/pull/4048), [morluto/rea#4008](https://github.com/morluto/rea/issues/4008), [#3500](https://github.com/morluto/rea/pull/3500), [morluto/rea#3389](https://github.com/morluto/rea/issues/3389), [#4463](https://github.com/morluto/rea/pull/4463), [morluto/rea#4373](https://github.com/morluto/rea/issues/4373), [morluto/rea#4455](https://github.com/morluto/rea/issues/4455), [3fc0075](https://github.com/morluto/rea/commit/3fc007534bb2104d662b43cc712281f9d1d6a7d3), [4a076f3](https://github.com/morluto/rea/commit/4a076f368c62bdfb19415accad342e03a38d1005)). Thanks @coygeek, @Iyanuoluwa007, @jayinvers, @kaoru0822-kitauji, @kevinjosh10, @maxazure, @ShuaixinHuang.
- **Native analysis providers:** Keep Ghidra byte matches within examined coverage, retain PE PDB/function-boundary limitations and preserve configured MIPS choices. Attached IDA refuses universal Mach-O rather than silently choosing a slice; request timeout identity and captured output survive adapter handling. ([#4531](https://github.com/morluto/rea/pull/4531), [#2933](https://github.com/morluto/rea/pull/2933), [morluto/rea#2259](https://github.com/morluto/rea/issues/2259), [01a1b3f](https://github.com/morluto/rea/commit/01a1b3fda6a7dacd24a0b10619d41d12153080d4), [50dd9fc](https://github.com/morluto/rea/commit/50dd9fcad1efb47cb404192c30bdf190dcdaca58), [#4765](https://github.com/morluto/rea/pull/4765), [morluto/rea#3871](https://github.com/morluto/rea/issues/3871), [c0cfccb](https://github.com/morluto/rea/commit/c0cfccb45fe43e7eeff18e56c64caa5b121988f9)). Thanks @BeLit-Development-2, @coygeek, @kaoru0822-kitauji, @N0zoM1z0, @ShuaixinHuang.
- **Recorded crashes:** Prevent GDB from discovering an executable named by an untrusted core, reject core mapping paths that escape the isolated sysroot, and preserve pwntools worker ownership across launcher exec. Completed decode facts and cancellation reasons remain available through failed final cleanup. ([5bf4fff](https://github.com/morluto/rea/commit/5bf4fffc1b835130ddb16f96db9ce13b639591db), [b33c0df](https://github.com/morluto/rea/commit/b33c0df02e93fabca00a44f2de625b1a63637ee9), [#4435](https://github.com/morluto/rea/pull/4435), [morluto/rea#4011](https://github.com/morluto/rea/issues/4011)). Thanks @coygeek, @N0zoM1z0.
- **Cutter and Rizin:** Read Cutter’s active document from core configuration and attribute its host version correctly. Keep interrupted Rizin frames and output whitespace before completion markers, with exact command and cleanup failure attribution. ([#4507](https://github.com/morluto/rea/pull/4507), [morluto/rea#4497](https://github.com/morluto/rea/issues/4497), [#4514](https://github.com/morluto/rea/pull/4514), [morluto/rea#4498](https://github.com/morluto/rea/issues/4498), [#4459](https://github.com/morluto/rea/pull/4459), [morluto/rea#4015](https://github.com/morluto/rea/issues/4015), [d5fc7e6](https://github.com/morluto/rea/commit/d5fc7e6ebf9af050081fc4c6e18b9079cfaa5cdc), [199396f](https://github.com/morluto/rea/commit/199396f61c8f61da326d059606a992304a760147)). Thanks @coygeek, @N0zoM1z0, @Xander-AJ.
- **Windows cleanup:** Retain unpublished runtimes after failed removal, handle read-only attributes and sharing conflicts, preserve primary snapshot failures and honor caller environment overrides. ([f78d137](https://github.com/morluto/rea/commit/f78d137b42741a0ed5fb8ac161286f9a50220c4d), [d69acc3](https://github.com/morluto/rea/commit/d69acc3455c33f90a2fc4381db43d38b6af50622), [0679a79](https://github.com/morluto/rea/commit/0679a7972b4f2b02eee6a86a44f50f4c2967d3cb), [5f9ac2c](https://github.com/morluto/rea/commit/5f9ac2c98a6fe11988c41afb737df9b6d5c3a1b3), [1bbf4bd](https://github.com/morluto/rea/commit/1bbf4bd16ca134cdb2187eaf29291cae90d14a57)). Thanks @DeryFerd.
- **Managed metadata:** Compare nominal signatures and declaring identities across builds, preserve empty names without display substitutions, verify ABI-prefixed Mach-O exports exactly, and charge cached metadata once. Metadata errors report artifact file offsets; mixed-mode assemblies retain their actual boundary classification. ([#3059](https://github.com/morluto/rea/pull/3059), [#3079](https://github.com/morluto/rea/pull/3079), [#3853](https://github.com/morluto/rea/pull/3853), [morluto/rea#3352](https://github.com/morluto/rea/issues/3352), [#3974](https://github.com/morluto/rea/pull/3974), [morluto/rea#3961](https://github.com/morluto/rea/issues/3961), [#3491](https://github.com/morluto/rea/pull/3491), [morluto/rea#3449](https://github.com/morluto/rea/issues/3449), [#4418](https://github.com/morluto/rea/pull/4418), [morluto/rea#4372](https://github.com/morluto/rea/issues/4372), [#3516](https://github.com/morluto/rea/pull/3516), [morluto/rea#3366](https://github.com/morluto/rea/issues/3366)). Thanks @8rulerstar, @coygeek, @duckhunt113, @Hahaa909, @JayOfTheKeyboard, @kaoru0822-kitauji, @keeponlight, @N0zoM1z0, @tomyrms.
- **Archive and filesystem identity:** Reject colliding extraction paths before writing, classify ZIP offsets beyond EOF as malformed, normalize ZIP current-directory prefixes once, and preserve symlink and unreadable-path provenance. A directory named `*.map` is no longer mistaken for a source-map file. ([862a0b2](https://github.com/morluto/rea/commit/862a0b2631785492f8dc20c8acd396646c545fd1), [c209dcb](https://github.com/morluto/rea/commit/c209dcb209118069f123e789949eeba1ef78853e), [6b1c36e](https://github.com/morluto/rea/commit/6b1c36e336eeacbb7159b211e687b4b84f99b9f5), [25c2222](https://github.com/morluto/rea/commit/25c22222abe7a681491bdb4d7316250fdcf32973), [d6e4fe4](https://github.com/morluto/rea/commit/d6e4fe4a4dd8914ec3db50d2a7fc3d0802649262), [#4131](https://github.com/morluto/rea/pull/4131), [morluto/rea#3909](https://github.com/morluto/rea/issues/3909)). Thanks @Adkid-Zephyr, @coygeek, @jackie-cqz, @kaoru0822-kitauji, @maxazure, @XY-code1.
- **Evidence and reconstruction:** Authenticate all retained inventory substeps, preserve source-attributed caveats in composed workflows, and require comparable cited Evidence before declaring reconstruction coverage or readiness. Missing Evidence and residual replay uncertainty stay explicit. ([9ac91e0](https://github.com/morluto/rea/commit/9ac91e0c1e13e91cd21341635ad5be89b0e8642d), [c4608a2](https://github.com/morluto/rea/commit/c4608a29620ea3e7bb8259b47357b942fe4e4709), [#4075](https://github.com/morluto/rea/pull/4075), [morluto/rea#3357](https://github.com/morluto/rea/issues/3357), [#3526](https://github.com/morluto/rea/pull/3526), [morluto/rea#3363](https://github.com/morluto/rea/issues/3363), [153017d](https://github.com/morluto/rea/commit/153017d750322188c1a112b2284c1b8065c67320)). Thanks @coygeek, @gensokyo-dev, @kaoru0822-kitauji, @N0zoM1z0, @rudycelekli.
- **Offline data:** Preserve exact UTC packet-capture instants, SQLite column identity and snapshot admission failures, and cooked WASM directive literals. Cleanup cancellation retains completed EVM/WASM observations rather than losing them. ([796faa0](https://github.com/morluto/rea/commit/796faa0e4e6bf745bcdc33acef65af8ccfc3622d), [748ac7f](https://github.com/morluto/rea/commit/748ac7f0df340f0d0569eca2e803a59cd51ffdbd), [bc51d0e](https://github.com/morluto/rea/commit/bc51d0ea5df7dcee1fcc42dfae3ab0c62c9cca5e), [4f87f02](https://github.com/morluto/rea/commit/4f87f02bb19bf77349a683a5bcb2da2d1da427d0), [d694aef](https://github.com/morluto/rea/commit/d694aef227e90164e6654ea9e5ce6a854d099404), [321cacb](https://github.com/morluto/rea/commit/321cacb84a020f447e1110df5c58fa71d99b7bf1)). Thanks @himamaheswarreddy, @mertkayacs, @rollroyces, @viniciusdsandrade.
- **Kuna recovery:** Share concurrent single-function requests and cache repeats, validate warm exports once, stream string inventories beyond the former fixed buffer ceiling, and keep unproven processes in their run slots until close confirms release. Failure messages distinguish final buffer refusals from configurable deadlines. ([#4045](https://github.com/morluto/rea/pull/4045), [#4169](https://github.com/morluto/rea/pull/4169), [#4049](https://github.com/morluto/rea/pull/4049), [#4318](https://github.com/morluto/rea/pull/4318), [#4052](https://github.com/morluto/rea/pull/4052), [#4098](https://github.com/morluto/rea/pull/4098), [#4343](https://github.com/morluto/rea/pull/4343)). Thanks @kaoru0822-kitauji.
- **Flutter snapshots:** Check symbol-table ranges against loadable segments and retain completed inspection facts when cancellation occurs during snapshot cleanup. ([#3859](https://github.com/morluto/rea/pull/3859), [morluto/rea#3346](https://github.com/morluto/rea/issues/3346), [#4766](https://github.com/morluto/rea/pull/4766), [morluto/rea#4717](https://github.com/morluto/rea/issues/4717), [#4762](https://github.com/morluto/rea/pull/4762), [morluto/rea#4640](https://github.com/morluto/rea/issues/4640)). Thanks @coygeek, @kaoru0822-kitauji.
- **Native metadata recovery:** Keep unknown Objective-C category classes, empty protocol names, undecoded Swift aliases and unfinished property types explicit instead of discarding neighboring valid records. Preserve unnamed segment identity and exclude a dylib’s own install name from dependencies. ([#4093](https://github.com/morluto/rea/pull/4093), [morluto/rea#4012](https://github.com/morluto/rea/issues/4012), [#4078](https://github.com/morluto/rea/pull/4078), [morluto/rea#3873](https://github.com/morluto/rea/issues/3873), [#4085](https://github.com/morluto/rea/pull/4085), [morluto/rea#3934](https://github.com/morluto/rea/issues/3934), [#3825](https://github.com/morluto/rea/pull/3825), [morluto/rea#3345](https://github.com/morluto/rea/issues/3345), [#4051](https://github.com/morluto/rea/pull/4051), [morluto/rea#3875](https://github.com/morluto/rea/issues/3875), [#4050](https://github.com/morluto/rea/pull/4050), [morluto/rea#3872](https://github.com/morluto/rea/issues/3872)). Thanks @coygeek, @kaoru0822-kitauji.
- **Document selection:** Preserve explicitly selected plist paths and bundle defaults, and only use document fallback after confirming its applicability. Finalization keeps completed selection facts and cancellation outcomes. ([e6c4877](https://github.com/morluto/rea/commit/e6c487799bb64f559e66b69be1863e6ec5187548), [#3774](https://github.com/morluto/rea/pull/3774), [9df559b](https://github.com/morluto/rea/commit/9df559b7e712298a761ff26e9caae8d659b7e54b)). Thanks @kaoru0822-kitauji.
- **Capture and comparison accuracy:** Admit schema-valid HAR numeric values while retaining exact-publication limits, preserve empty URL path segments, and keep unrelated process traces and unnamed reference endpoints distinct or unknown. ([#3159](https://github.com/morluto/rea/pull/3159), [morluto/rea#3145](https://github.com/morluto/rea/issues/3145), [#3792](https://github.com/morluto/rea/pull/3792), [morluto/rea#3307](https://github.com/morluto/rea/issues/3307), [#4178](https://github.com/morluto/rea/pull/4178), [morluto/rea#3931](https://github.com/morluto/rea/issues/3931), [#3809](https://github.com/morluto/rea/pull/3809), [morluto/rea#3388](https://github.com/morluto/rea/issues/3388)). Thanks @coygeek, @gensokyo-dev, @kaoru0822-kitauji, @N0zoM1z0, @pablodiazjorge, @xu91102.
- **Evidence publication:** Recheck staged output identity after its final write, classify missing review Evidence and duplicate ledger entries as caller input, and preserve the selected freshness requirement in comparison parameters. ([#4764](https://github.com/morluto/rea/pull/4764), [morluto/rea#4613](https://github.com/morluto/rea/issues/4613), [#4452](https://github.com/morluto/rea/pull/4452), [morluto/rea#4444](https://github.com/morluto/rea/issues/4444), [#4065](https://github.com/morluto/rea/pull/4065), [morluto/rea#4000](https://github.com/morluto/rea/issues/4000)). Thanks @amyanger, @coygeek, @kaoru0822-kitauji, @Rinkia, @Swatantra-66.
### ⚠ BREAKING CHANGES
- **Saved Evidence:** Evidence and analysis snapshots now require explicit nullable `relationship_coverage` in their identity commitments. Artifact inventories require scoped coverage and explicit `integrity_contradictions`; obsolete `coverage_status` and prose-based coverage inference are removed. Regenerate old Evidence/snapshots and inventory observations with this release: saved files are not migrated and omitted facts are not filled with guessed defaults. ([db8128d](https://github.com/morluto/rea/commit/db8128dc0d1c4f731f3d19877fa00d25cf17f657), [0405c9d](https://github.com/morluto/rea/commit/0405c9d361de6d904dfa16cc0b6d8350407f2c9b), [a9588be](https://github.com/morluto/rea/commit/a9588be4ebdd20eeda975cb63ffcdb1cd868b340)).
- **Browser capture results:** Consumers must retain resolved capture limits, event families and omission facts. Set desired budgets through the supported capture options; omitted caller inputs still select defaults, but stored observations must report the resolved values. Admitted content reads queue behind bounded concurrency. ([57a23f0](https://github.com/morluto/rea/commit/57a23f0a2da0fdc3835e203718ded8acea5a34e6)).
- **Android version codes:** `inspect_adb_package.version_code` is a decimal string rather than a JSON number. Read it as a string, or use `BigInt` for numeric comparison. ([#3485](https://github.com/morluto/rea/pull/3485), [morluto/rea#3368](https://github.com/morluto/rea/issues/3368), [7666a48](https://github.com/morluto/rea/commit/7666a482b69dc7cabdbac3bbaf89a43e32300192)). Thanks @coygeek, @kaoru0822-kitauji.
- **Native UI failures:** Failed or cancelled native UI scenarios now return typed errors with the collected report in `partial_observation`. Handle the error path and read that report instead of expecting a successful result containing failed steps. ([d909919](https://github.com/morluto/rea/commit/d9099190ab3a819bd3a9fd62a8714cef398016d5)).
- **Provider status:** `binary_session` candidate availability can be unknown during owner finalization. Preserve that state rather than treating it as unavailable; internal consumers must await the asynchronous session status API. ([150e996](https://github.com/morluto/rea/commit/150e996a86f2bec4982ba87f37bf502a8d5e8214)).
- **Swift symbol locations:** `swift_symbols` entries may have a null `address` when the provider supplies no location. Handle unknown addresses; optional `evidence.reported_address` retains the original provider value. ([8116dc0](https://github.com/morluto/rea/commit/8116dc06512b4609d8db63cebc9f2ff8cb964151)).
- **Linux Hopper admission:** Older builds previously admitted by a fixed allowlist need retained publisher-signed package evidence or an approved update to the current public demo. Update explicit `HOPPER_LAUNCHER_PATH` selections when migrating; the live feed offers only its current release. The official RPM metadata mismatch remains unresolved and is refused. ([#3590](https://github.com/morluto/rea/pull/3590), [morluto/rea#3577](https://github.com/morluto/rea/issues/3577), [70cd4cb](https://github.com/morluto/rea/commit/70cd4cbfb849b61f05d97d2690372a9782831426)). Thanks @gensokyo-dev, @kaoru0822-kitauji, @N0zoM1z0.
Full contribution record: [571 commits and 236 merged PRs](https://github.com/morluto/rea/blob/rea-agents-6.6.0/docs/releases/6.6.0.contributions.json).
## [6.5.0](https://github.com/morluto/rea/compare/rea-agents-6.4.0...rea-agents-6.5.0) (2026-10-13)
Provider prerequisites and recorded verification scope are listed in [the testing guide](docs/testing.md).
+1 -24
View File
@@ -21,9 +21,6 @@ For analysis workflows and agent interfaces, follow the
[performance priorities](AGENTS.md#performance). Explain the selected output
scope, reuse/cache decisions, and relevant before/after measurements when these
costs change.
Use the [analysis optimization skill](.agents/skills/rea-analysis-optimization/SKILL.md)
to locate provider and shared-workflow bottlenecks, preserve Evidence, and
compare equivalent real tasks before claiming an improvement.
When adding or changing an MCP tool, follow the [tool design guide](docs/tool-design.md) and preserve the canonical contracts and generated catalog.
@@ -228,10 +225,7 @@ manifest. A source checkout does not: `native/windows/build/` is ignored by
Git, and neither `npm ci` nor `npm run build:cached` (or `npm run build`)
produces `rea-windows-x64.node` or `manifest.json` in that directory.
Windows workflows and tests that require native controls need these artifacts;
this includes `run-exclusive` commands, which use the native Job Object to keep
the artifact lock until every command descendant has exited. Without the
artifacts, those controls are unavailable even after a successful runtime
build.
without them, those controls are unavailable even after a successful runtime build.
Follow the [Windows native build guide](native/windows/README.md#build) before
running those workflows from source. The artifact build requires Linux,
@@ -261,23 +255,6 @@ The separate GitHub Pages host uses only the manual
**Settings → Pages → Build and deployment → Source** must be set to
**GitHub Actions** before deploying there.
### Translation corrections
README editions and website editions have separate translation sources:
- Find the language's `readme` path in the
[language inventory](website/locales/languages.json) and edit that file.
Locale codes and README suffixes can differ. Use the
[English README](README.md) to check commands, requirements, and analysis claims.
- Edit `msgstr` values in `website/locales/<language>/messages.po` for website
text. Follow the [website translation guide](website/locales/README.md) for
the Python environment, catalog validation, and local preview. Preserve source
strings, contexts, placeholders, commands, paths, and recorded evidence.
Before submitting a website translation, run the catalog and website checks in
that guide. Translated HTML in `website/_site/` is generated; edit the PO catalog
rather than the generated pages.
## Development feedback and PR verification
For routine merges, wait for the required checks to pass for the current PR
+2 -10
View File
@@ -1,7 +1,7 @@
<div align="center">
**English** · [简体中文](docs/readme/README_zh.md) · [繁體中文](docs/readme/README_zh-TW.md) · [日本語](docs/readme/README_ja.md) · [한국어](docs/readme/README_ko.md) · [Türkçe](docs/readme/README_tr.md) · [Русский](docs/readme/README_ru.md) · [Tiếng Việt](docs/readme/README_vi.md) · [ไทย](docs/readme/README_th.md) · [Deutsch](docs/readme/README_de.md) · [Español](docs/readme/README_es.md) · [Français](docs/readme/README_fr.md) · [Українська](docs/readme/README_uk.md) · [Polski](docs/readme/README_pl.md) · [Português (Brasil)](docs/readme/README_pt-BR.md) · [العربية](docs/readme/README_ar.md) · [فارسی](docs/readme/README_fa.md) · [Bahasa Indonesia](docs/readme/README_id.md) · [Italiano](docs/readme/README_it.md)
· [Ελληνικά](docs/readme/README_el.md) · [മലയാളം](docs/readme/README_ml.md)
· [Ελληνικά](docs/readme/README_el.md)
# REA: Reverse Engineer Anything
@@ -132,14 +132,6 @@ For a CLI installed with `npm install --global` or `bun add --global`:
rea update
```
`rea --update` is an alias for this verified workflow and accepts the same global
output flags. Use `rea update` when combining it with other command controls.
Updater commands retain at most 4 MiB of stdout and stderr combined. Oversized
metadata replies are rejected after the command exits; verbose installs continue
with bounded diagnostics. Human progress output respects terminal backpressure
and waits for submitted writes to finish.
Bun global updates require Bun 1.2.17 or later. With an older Bun release,
upgrade Bun manually before running `rea update`.
@@ -353,7 +345,7 @@ Report vulnerabilities through [SECURITY.md](SECURITY.md).
## Star history
🎉 **300,000 GitHub stars — thank you!**
🎉 **250,000 GitHub stars — thank you!**
Thanks to everyone using REA, reporting bugs, requesting features, testing builds, and contributing fixes.
+23 -167
View File
@@ -15,14 +15,11 @@ import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
import kotlin.Unit;
import kotlin.ResultKt;
import kotlin.coroutines.Continuation;
import kotlin.coroutines.CoroutineContext;
import kotlin.coroutines.EmptyCoroutineContext;
import kotlin.coroutines.intrinsics.IntrinsicsKt;
import kotlinx.coroutines.BuildersKt;
import kotlinx.io.CoreKt;
import kotlinx.io.JvmCoreKt;
import kotlinx.serialization.json.JsonObject;
/** REA-owned metadata boundary for the unmodified jadx-headless-mcp 0.7.1 JAR. */
class ReaJadxBridge {
@@ -31,8 +28,7 @@ class ReaJadxBridge {
private JadxSession indexedSession;
private Map<String, List<ClassSnapshot>> classes = Map.of();
private record MethodSnapshot(String name, String rawName, String shortId, List<String> bodyAbsenceMarkers,
Map<String, Object> summary) {}
private record MethodSnapshot(String name, String shortId, Map<String, Object> summary) {}
private record ClassSnapshot(JavaClass node, List<MethodSnapshot> methods, Map<String, Object> summary) {}
private static final class InputFailure extends IllegalArgumentException {
@@ -48,93 +44,15 @@ class ReaJadxBridge {
private static CallToolResult json(Object value) { return text(JSON.toJson(value), false); }
/** Translate the typed load outcome before upstream drops its exception identity. */
static Object loadResult(Object result) {
try { ResultKt.throwOnFailure(result); }
catch (Throwable failure) {
if (failure instanceof java.util.concurrent.CancellationException
|| failure instanceof Error && !(failure instanceof OutOfMemoryError)) return result;
if (failure instanceof OutOfMemoryError) {
String reason = failure.getMessage();
boolean heap = "Java heap space".equals(reason) || "GC overhead limit exceeded".equals(reason);
Map<String, Object> reply = new LinkedHashMap<>();
reply.put("kind", "jvm-memory-failure");
reply.put("memory_area", heap ? "heap" : "unknown");
reply.put("exception_type", "java.lang.OutOfMemoryError");
if (reason != null) reply.put("message", reason);
reply.put("max_heap_bytes", Runtime.getRuntime().maxMemory());
return text(JSON.toJson(reply), true);
}
return text("load failed: " + failure.getMessage(), true);
}
SessionHolder.LoadResult loaded = (SessionHolder.LoadResult) result;
Map<String, Object> reply = new LinkedHashMap<>();
reply.put("state", "LOADED");
reply.put("apk_path", loaded.getApkPath());
reply.put("class_count", loaded.getClassCount());
reply.put("raw_class_count", loaded.getRawClassCount());
reply.put("resource_count", loaded.getResourceCount());
reply.put("load_duration_ms", loaded.getLoadDurationMs());
reply.put("decompile_timeout_ms", loaded.getDecompileTimeoutMs());
reply.put("threads", loaded.getThreads());
reply.put("code_cache_size", loaded.getCodeCacheSize());
reply.put("resources", loaded.getResourceMode());
if (!loaded.getIncludePackages().isEmpty()) reply.put("include_packages", loaded.getIncludePackages());
if (!loaded.getExcludePackages().isEmpty()) reply.put("exclude_packages", loaded.getExcludePackages());
return json(reply);
}
private Object load(kotlinx.serialization.json.JsonObject arguments, SessionConfig defaults,
Continuation<? super CallToolResult> continuation) {
JsonObject args = JsonParser.parseString(arguments.toString()).getAsJsonObject();
String path = string(args, "path");
SessionConfig options = defaults.withLoadOverrides(
optionalString(args, "include_packages"), optionalString(args, "exclude_packages"),
args.has("threads") ? integer(args, "threads", 1) : null,
args.has("code_cache_size") ? integer(args, "code_cache_size", 64) : null,
optionalString(args, "resources"));
return loadCall(next -> holder.load(path, options, next), continuation);
}
static Object loadCall(kotlin.jvm.functions.Function1<Continuation<SessionHolder.LoadResult>, Object> load,
Continuation<? super CallToolResult> continuation) {
var forwarded = new java.util.concurrent.atomic.AtomicBoolean();
Continuation<SessionHolder.LoadResult> resumed = new Continuation<>() {
public CoroutineContext getContext() { return continuation.getContext(); }
public void resumeWith(Object result) {
if (!forwarded.compareAndSet(false, true)) throw new IllegalStateException("Load resumed twice");
Object translated;
try { translated = loadResult(result); }
catch (Throwable failure) { translated = ResultKt.createFailure(failure); }
// Keep the consumer outside the translation catch, including inline completion.
continuation.resumeWith(translated);
}
};
Object result;
try { result = load.invoke(resumed); }
catch (Throwable failure) {
if (forwarded.get()) ResultKt.throwOnFailure(ResultKt.createFailure(failure));
result = ResultKt.createFailure(failure);
}
if (result == IntrinsicsKt.getCOROUTINE_SUSPENDED()) return result;
Object translated = loadResult(result);
ResultKt.throwOnFailure(translated);
return translated;
}
private static String optionalString(JsonObject args, String name) {
return args.has(name) ? string(args, name) : null;
}
private static String string(JsonObject args, String name) {
JsonElement value = args.get(name);
JsonElement value = JsonParser.parseString(args.toString()).getAsJsonObject().get(name);
if (value == null || !value.isJsonPrimitive() || !value.getAsJsonPrimitive().isString())
throw new IllegalArgumentException(name + " must be a string");
return value.getAsString();
}
private static int integer(JsonObject args, String name, int fallback) {
JsonElement value = args.get(name);
JsonElement value = JsonParser.parseString(args.toString()).getAsJsonObject().get(name);
if (value == null) return fallback;
if (!value.isJsonPrimitive() || !value.getAsJsonPrimitive().isNumber())
throw new IllegalArgumentException(name + " must be a nonnegative integer");
@@ -172,13 +90,10 @@ class ReaJadxBridge {
if (!shortId.startsWith(rawName + "("))
throw new IllegalStateException("JADX method ID has no raw-name prefix: " + shortId);
String descriptor = shortId.substring(rawName.length());
List<String> bodyAbsenceMarkers = new ArrayList<>();
if (method.getAccessFlags().isNative()) bodyAbsenceMarkers.add("native_method");
if (method.getAccessFlags().isAbstract()) bodyAbsenceMarkers.add("abstract_method");
String signature = name + "(" + method.getArgTypes().stream()
.map(Object::toString).collect(Collectors.joining(", "))
+ "): " + method.getReturnType().toString();
return new MethodSnapshot(name, rawName, shortId, List.copyOf(bodyAbsenceMarkers), Map.of(
return new MethodSnapshot(name, shortId, Map.of(
"name", name, "signature", signature,
"dex_descriptor", descriptor,
"is_constructor", method.isConstructor(), "def_pos", 0));
@@ -225,52 +140,16 @@ class ReaJadxBridge {
private JadxSession.SmartCode methodBody(JadxSession current, ClassSnapshot cls,
MethodSnapshot selected, JavaMethod method) {
// Access flags belong to the parsed member, before code generation rewrites it.
// These methods have no Java body; source slicing can include unrelated members.
if (!selected.bodyAbsenceMarkers().isEmpty())
return new JadxSession.SmartCode("", "java", false, selected.bodyAbsenceMarkers());
if (!selected.shortId().equals("<clinit>()V"))
return current.getMethodBodySmart(method, current.getMaxSourceBytes(), true);
// Java code generation can fold all or part of <clinit> into field declarations.
// Its method text cannot establish coverage, even when a static block remains.
if (selected.shortId().equals("<clinit>()V"))
return exactMethodSmali(current, cls, selected, List.of("static_initializer_disassembly"));
String java = current.getMethodSource(method);
if (java.startsWith("// ERROR:")) throw new IllegalArgumentException(java);
// The upstream placeholder means only that Java code was omitted, including
// methods merged into synthetic bridges. Access flags established absence above.
if (java.isEmpty() || java.equals(
"// method exists but has no decompiled body (native/abstract)"))
return exactMethodSmali(current, cls, selected, List.of("java_body_unavailable"));
List<String> markers = DecompileFailureKt.detectDecompileFailure(java);
if (markers.stream().anyMatch(DecompileFailureKt.getSTRONG_FAILURE_MARKERS()::contains))
return exactMethodSmali(current, cls, selected, markers);
JadxSession.MethodSmali smali = current.getMethodSmali(cls.node(), method.getName());
if (!smali.getFound() || smali.getBlocks().size() != 1)
throw new IllegalArgumentException("Static initializer disassembly requires one exact method: " + selected.shortId());
return new JadxSession.SmartCode(
TextUtilKt.truncateToBytes(java, current.getMaxSourceBytes()), "java", false, markers);
}
private JadxSession.SmartCode exactMethodSmali(JadxSession current, ClassSnapshot cls,
MethodSnapshot selected, List<String> markers) {
JadxSession.MethodSmali smali = current.getMethodSmali(cls.node(), selected.rawName());
String block = selectMethodSmali(smali, selected.shortId());
return new JadxSession.SmartCode(
TextUtilKt.truncateToBytes(block, current.getMaxSourceBytes()), "smali", true, markers);
}
private static String selectMethodSmali(JadxSession.MethodSmali smali, String shortId) {
if (!smali.getFound())
throw new IllegalArgumentException("JADX could not disassemble " + shortId
+ (smali.getNote() == null ? "" : ": " + smali.getNote()));
// Upstream returns every same-name overload, and can return an unterminated
// trailing block. Match the full original identity before applying output limits.
List<String> matches = smali.getBlocks().stream().filter(block -> {
String header = block.lines().findFirst().orElse("").strip();
return header.startsWith(".method ") && header.endsWith(" " + shortId);
}).toList();
if (matches.size() != 1)
throw new IllegalArgumentException("Disassembly could not establish one selected method: " + shortId);
String block = matches.get(0);
if (!block.stripTrailing().endsWith("\n.end method"))
throw new IllegalArgumentException("Selected method disassembly is incomplete: " + shortId);
return block;
TextUtilKt.truncateToBytes(smali.getBlocks().get(0), current.getMaxSourceBytes()),
"smali", true, List.of("static_initializer_disassembly"));
}
// The local transport admits 8 MiB frames. Reserve 1 KiB for the fixed
@@ -324,8 +203,7 @@ class ReaJadxBridge {
return new DirectInvokes(sites, exhaustive[0]);
}
private CallToolResult handle(String name, kotlinx.serialization.json.JsonObject input) {
JsonObject args = JsonParser.parseString(input.toString()).getAsJsonObject();
private CallToolResult handle(String name, JsonObject args) {
if (name.equals("rea_jvm_status")) return json(Map.of(
"engine_reported_version", BuildInfo.VERSION,
"max_heap_bytes", Runtime.getRuntime().maxMemory(),
@@ -335,25 +213,12 @@ class ReaJadxBridge {
JadxSession current = session();
if (name.equals("list_classes")) {
List<String> names = current.getClassFqns();
String query = args.has("query") ? string(args, "query") : "";
int offset = integer(args, "offset", 0);
int limit = integer(args, "limit", 200);
int start = Math.min(offset, names.size());
int end = start;
List<String> items;
if (query.isEmpty()) {
end = (int) Math.min((long) start + limit, names.size());
items = names.subList(start, end);
} else {
items = new ArrayList<>();
while (end < names.size() && items.size() < limit) {
String nameInInventory = names.get(end++);
if (nameInInventory.contains(query)) items.add(nameInInventory);
}
}
return json(Map.of("total_classes", names.size(), "next_offset", end,
"scope", "top_level", "offset", offset, "limit", limit,
"items", items));
int end = (int) Math.min((long) start + limit, names.size());
return json(Map.of("total", names.size(), "offset", offset, "limit", limit,
"items", names.subList(start, end)));
}
ClassSnapshot cls = selected(args);
if (name.equals("get_class_summary")) return json(cls.summary());
@@ -365,7 +230,6 @@ class ReaJadxBridge {
JadxSession.SmartCode code = methodBody(current, cls, overloads.get(index), method);
return json(Map.of("class_name", cls.summary().get("full_name"),
"method_name", overloads.get(index).name(), "full_name", method.getFullName(),
"dex_descriptor", overloads.get(index).summary().get("dex_descriptor"),
"overload_index", index, "overload_count", overloads.size(),
"mode", code.getKind(), "fell_back", code.getFellBack(),
"markers", code.getMarkers(), "body", code.getText()));
@@ -377,7 +241,7 @@ class ReaJadxBridge {
if (name.equals("get_xrefs_to_class")) uses = cls.node().getUseIn();
else {
List<MethodSnapshot> overloads = methods(cls, args);
if (overloads.size() != 1 && !args.has("overload_index"))
if (overloads.size() != 1 && !args.containsKey("overload_index"))
throw new InputFailure("overload_index", "Select one of " + overloads.size() + " method overloads");
overloadIndex = integer(args, "overload_index", 0);
if (overloadIndex >= overloads.size())
@@ -423,12 +287,11 @@ class ReaJadxBridge {
public static void main(String[] args) throws Exception {
PrintStream protocolOut = System.out;
System.setOut(System.err);
SessionConfig defaults = new SessionConfig(
1048576, 0, 90000L, 1, List.of(), List.of(), 64, ResourceMode.FULL);
SessionHolder holder = new SessionHolder(defaults);
SessionHolder holder = new SessionHolder(new SessionConfig(
1048576, 0, 90000L, 1, List.of(), List.of(), 64, ResourceMode.FULL));
ServerCapabilities capabilities = new ServerCapabilities(
new ServerCapabilities.Tools(null), null, null, null, null, null, null, Map.of());
Server server = new Server(new Implementation("rea-jadx-bridge", "4", null, null, null),
Server server = new Server(new Implementation("rea-jadx-bridge", "1", null, null, null),
new ServerOptions(capabilities), "", ignored -> Unit.INSTANCE);
SessionToolsKt.registerSessionTools(server, holder);
ManifestToolsKt.registerManifestTools(server, holder);
@@ -436,17 +299,13 @@ class ReaJadxBridge {
MethodToolsKt.registerMethodTools(server, holder);
XrefToolsKt.registerXrefTools(server, holder);
ReaJadxBridge bridge = new ReaJadxBridge(holder);
Tool loadTool = server.getTools().get("load_apk").getTool();
server.removeTool("load_apk");
server.addTool(loadTool, (connection, request, continuation) ->
bridge.load(request.getArguments(), defaults, continuation));
Set<String> consumed = Set.of("load_apk", "get_app_info", "get_android_manifest",
"list_classes", "get_class_summary", "get_method_body",
"get_xrefs_to_class", "get_xrefs_to_method");
for (String name : new ArrayList<>(server.getTools().keySet()))
if (!consumed.contains(name)) server.removeTool(name);
Tool diagnostics = new Tool("rea_jvm_status",
new ToolSchema(null, new kotlinx.serialization.json.JsonObject(Map.of()), List.of(), null),
new ToolSchema(null, new JsonObject(Map.of()), List.of(), null),
"Observed worker JVM and metadata scope", null, null, null, null, null, null);
server.addTool(diagnostics, (connection, request, continuation) -> bridge.handle("rea_jvm_status", request.getArguments()));
for (String name : List.of("list_classes", "get_class_summary",
@@ -461,16 +320,13 @@ class ReaJadxBridge {
};
Map<String, kotlinx.serialization.json.JsonElement> properties = new LinkedHashMap<>();
for (String field : fields) properties.put(field, tool.getInputSchema().getProperties().get(field));
if (name.equals("list_classes")) properties.put("query",
new kotlinx.serialization.json.JsonObject(Map.of(
"type", kotlinx.serialization.json.JsonElementKt.JsonPrimitive("string"))));
String description = switch (name) {
case "list_classes" -> "Pages of case-sensitive matching top-level class names; offset and next_offset are inventory positions, limit bounds matching rows. Omitted or empty query inventories all names.";
case "list_classes" -> "Indexed pages of all top-level class names, with offset and limit.";
case "get_class_summary" -> "Parsed member metadata for one exact class name; no source generation.";
case "get_method_body" -> "Source for an exact class and stable same-name overload index; static initializers use smali to preserve folded field initialization.";
default -> "Complete static using-node inventory for an exact class or selected method overload; one node may contain multiple invoke instructions, and source lines are unresolved.";
};
Tool narrowed = new Tool(name, new ToolSchema(null, new kotlinx.serialization.json.JsonObject(properties),
Tool narrowed = new Tool(name, new ToolSchema(null, new JsonObject(properties),
tool.getInputSchema().getRequired(), null), description, null, null, null, null, null, null);
server.addTool(narrowed, (connection, request, continuation) -> {
try { return bridge.handle(name, request.getArguments()); }
+10 -19
View File
@@ -28,9 +28,9 @@ if os.name == "nt":
import cutter
try:
from PySide6.QtCore import QCoreApplication, QObject, Signal
from PySide6.QtCore import QObject, Signal
except ImportError:
from PySide2.QtCore import QCoreApplication, QObject, Signal
from PySide2.QtCore import QObject, Signal
MAX_FRAME_BYTES = 16 * 1024 * 1024
@@ -326,16 +326,15 @@ class _RequestDispatcher(QObject):
self._receipt_lock = threading.Lock()
self.current_file = self._read_current_file()
try:
value = QCoreApplication.applicationVersion()
self.cutter_version = value if isinstance(value, str) and value else None
self.cutter_version = str(cutter.core().getVersionInformation())
except Exception:
self.cutter_version = None
@staticmethod
def _read_current_file() -> str | None:
try:
value = cutter.core().getConfig("file.path")
return value if isinstance(value, str) and value else None
value = cutter.core().currentlyOpenFile()
return str(value) if value else None
except Exception:
return None
@@ -783,22 +782,14 @@ def _within_response_limit(value: Any) -> bool:
current = pending.pop()
if isinstance(current, str):
size += 2
if len(current) > MAX_FRAME_BYTES - size:
return False
if current.isascii():
size += len(current)
size += current.count('"') + current.count("\\")
size += sum(5 for character in current if ord(character) < 0x20)
else:
# Count UTF-8 bytes without allocating a copy of the whole output.
try:
size += sum(
len(current[start:start + 65536].encode("utf-8"))
for start in range(0, len(current), 65536)
)
except UnicodeEncodeError:
# Unencodable output also needs the signed omission fallback.
return False
size += current.count('"') + current.count("\\")
size += sum(5 for character in current if ord(character) < 0x20)
size += 4 * len(current)
size += current.count('"') + current.count("\\")
size += sum(5 for character in current if ord(character) < 0x20)
elif isinstance(current, dict):
identity = id(current)
if identity in seen:
-18
View File
@@ -140,7 +140,6 @@ public final class ReaGhidraBridge extends HeadlessScript {
"params"
);
private static final String[] CAPABILITIES = {
"read_binary_inventory_summary",
"annotate_native_function",
"set_address_name",
"set_addresses_names",
@@ -428,7 +427,6 @@ public final class ReaGhidraBridge extends HeadlessScript {
);
}
return switch (request.method) {
case "read_binary_inventory_summary" -> binaryInventorySummary(request.params);
case "inspect_native_load_image" -> inspectNativeLoadImage(request.params);
case "read_bytes" -> readMemoryBytes(request.params);
case "search_bytes" -> searchMemoryBytes(request.params, descriptor);
@@ -1976,18 +1974,6 @@ public final class ReaGhidraBridge extends HeadlessScript {
return result;
}
private JsonObject binaryInventorySummary(JsonObject params) throws Exception {
requireKeys(params, Set.of());
JsonObject result = new JsonObject();
result.addProperty("document", currentProgram.getName());
result.add("segments", segments());
// Count the owning inventories, preserving their exact discovery rules
// without serializing function identities or string values for counts.
result.addProperty("procedure_count", procedures().size());
result.addProperty("string_count", strings().size());
return result;
}
private JsonArray listNames(JsonObject params) throws Exception {
requireKeys(params, Set.of("document", "address"));
requireDocument(params);
@@ -2014,10 +2000,6 @@ public final class ReaGhidraBridge extends HeadlessScript {
private JsonArray listSegments(JsonObject params) {
requireKeys(params, Set.of("document"));
requireDocument(params);
return segments();
}
private JsonArray segments() {
JsonArray result = new JsonArray();
String imageBase = canonicalAddress(currentProgram.getImageBase());
MemoryBlock[] blocks = currentProgram.getMemory().getBlocks();
+1 -9
View File
@@ -1057,10 +1057,6 @@ def _serve_connection(connection):
):
raise PermissionError("Invalid bridge capability")
authenticated = True
# The connection grace period only bounds unauthenticated idle
# clients. Native analysis and a connected owner's idle time
# remain unbounded after capability validation.
connection.settimeout(None)
_write_message(file, {"id": request_id, "event": {
"type": "progress",
"phase": "hopper_bridge",
@@ -1152,17 +1148,13 @@ def _run():
server.bind(REA_SOCKET)
os.chmod(REA_SOCKET, 0o600)
server.listen(1)
# A bridge can start after its caller's startup/cleanup deadline. Bound
# the first accept as well as reconnects so an orphan cannot pin Hopper's
# dedicated Python thread and prevent later documents from starting REA.
server.settimeout(REA_RECONNECT_TIMEOUT_SECONDS)
try:
while True:
try:
connection, _ = server.accept()
except socket.timeout:
break
connection.settimeout(REA_RECONNECT_TIMEOUT_SECONDS)
connection.settimeout(None)
if _serve_connection(connection):
break
# Match REA's cleanup handshake budget without pinning Hopper's
+4 -48
View File
@@ -555,38 +555,6 @@ def _failed_launch_description(process):
return None
def _retire_failed_launch(process, config, listener, stdout, stderr):
"""Reconcile an SBProcess returned alongside a failed Launch error."""
if not process.IsValid():
stdout.close()
stderr.close()
return False
pid = process.GetProcessID()
if pid > 0:
# Even an already-exited process needs its PID published so the host
# can distinguish a completed launch failure from an unknown target.
with open(config["pid_path"], "w") as handle:
handle.write(str(pid))
if process.GetState() != lldb.eStateExited:
stdout.mark_launched()
stderr.mark_launched()
if pid > 0:
# Hold a surviving target until the host has captured its start
# identity. If that proof is unavailable, Kill still addresses
# this exact SBProcess created by the current launch request.
_wait_for_identity_ack(config)
process.Kill()
_wait_for_exit(listener, process, 5)
exit_observed = process.GetState() == lldb.eStateExited
expected_exit = exit_observed
stdout.close(expected_exit=expected_exit)
stderr.close(expected_exit=expected_exit)
return exit_observed
def trace(debugger, config):
global _TRACE_CONTEXT
debugger.SetAsync(True)
@@ -662,9 +630,8 @@ def trace(debugger, config):
)
process = target.Launch(_launch_info(target, config, listener), error)
if not error.Success() or not process.IsValid():
exit_observed = _retire_failed_launch(
process, config, listener, stdout, stderr
)
stdout.close()
stderr.close()
return {
"status": "launch-error",
"error": error.GetCString(),
@@ -673,26 +640,15 @@ def trace(debugger, config):
if process.IsValid()
else {}
),
**(
{"target_process_exit_observed": True}
if exit_observed
else {}
),
}
launch_failure = _failed_launch_description(process)
if launch_failure is not None:
exit_observed = _retire_failed_launch(
process, config, listener, stdout, stderr
)
stdout.close(expected_exit=True)
stderr.close(expected_exit=True)
return {
"status": "launch-error",
"error": launch_failure,
"target_process_created": True,
**(
{"target_process_exit_observed": True}
if exit_observed
else {}
),
}
stdout.mark_launched()
stderr.mark_launched()
-132
View File
@@ -15,8 +15,6 @@ fake_lldb = sys.modules.setdefault("lldb", types.ModuleType("lldb"))
fake_lldb.LLDB_INVALID_ADDRESS = -1
fake_lldb.eLaunchFlagDebug = 2
fake_lldb.eLaunchFlagStopAtEntry = 4
fake_lldb.eStateExited = 10
fake_lldb.SBEvent = lambda: object()
spec = importlib.util.spec_from_file_location(
"rea_lldb_tracer", os.path.join(os.path.dirname(__file__), "rea_lldb_tracer.py")
)
@@ -25,136 +23,6 @@ spec.loader.exec_module(tracer)
class NativeTraceBudgetTests(unittest.TestCase):
def test_failed_launch_does_not_infer_exit_from_a_failed_kill(self):
class Process:
def IsValid(self):
return True
def GetProcessID(self):
return 12345
def GetState(self):
return 6
def Kill(self):
return None
class Sink:
close_exit = None
def mark_launched(self):
pass
def close(self, expected_exit=False):
self.close_exit = expected_exit
with tempfile.TemporaryDirectory() as directory:
stdout, stderr = Sink(), Sink()
with patch.object(tracer, "_wait_for_identity_ack", return_value="unavailable"), patch.object(
tracer, "_wait_for_exit", return_value=None
):
exited = tracer._retire_failed_launch(
Process(), {"pid_path": os.path.join(directory, "pid")}, object(), stdout, stderr
)
self.assertFalse(exited)
self.assertFalse(stdout.close_exit)
self.assertFalse(stderr.close_exit)
def test_failed_launch_publishes_pid_and_retires_live_process(self):
class Process:
state = 6
killed = False
def IsValid(self):
return True
def GetProcessID(self):
return 12345
def GetState(self):
return self.state
def Kill(self):
self.killed = True
self.state = tracer.lldb.eStateExited
class Sink:
launched = False
close_exit = None
def mark_launched(self):
self.launched = True
def close(self, expected_exit=False):
self.close_exit = expected_exit
with tempfile.TemporaryDirectory() as directory:
pid_path = os.path.join(directory, "pid")
process = Process()
stdout, stderr = Sink(), Sink()
def acknowledge(config):
with open(config["pid_path"], "r") as pid_file:
self.assertEqual(pid_file.read(), "12345")
return "readable"
with patch.object(tracer, "_wait_for_identity_ack", acknowledge):
exited = tracer._retire_failed_launch(
process,
{"pid_path": pid_path},
object(),
stdout,
stderr,
)
self.assertTrue(exited)
self.assertTrue(process.killed)
self.assertTrue(stdout.launched)
self.assertTrue(stderr.launched)
self.assertTrue(stdout.close_exit)
self.assertTrue(stderr.close_exit)
def test_failed_launch_records_when_valid_process_is_already_exited(self):
class Process:
def IsValid(self):
return True
def GetProcessID(self):
return 12345
def GetState(self):
return tracer.lldb.eStateExited
def Kill(self):
raise AssertionError("an exited process must not be killed")
class Sink:
close_exit = None
def mark_launched(self):
raise AssertionError("an exited process has no output to drain")
def close(self, expected_exit=False):
self.close_exit = expected_exit
with tempfile.TemporaryDirectory() as directory:
pid_path = os.path.join(directory, "pid")
stdout, stderr = Sink(), Sink()
with patch.object(
tracer,
"_wait_for_identity_ack",
side_effect=AssertionError("exit is already observed"),
):
exited = tracer._retire_failed_launch(
Process(), {"pid_path": pid_path}, object(), stdout, stderr
)
with open(pid_path, "r") as pid_file:
self.assertEqual(pid_file.read(), "12345")
self.assertTrue(exited)
self.assertTrue(stdout.close_exit)
self.assertTrue(stderr.close_exit)
def test_pre_target_integrity_failure_reports_no_process_created(self):
original_debugger = getattr(tracer.lldb, "SBDebugger", None)
+2 -15
View File
@@ -20,9 +20,8 @@ def inspect(request):
root = Path(os.environ["REA_CORE_CONTEXT_REQUEST"]).parent
empty = root / "no-libraries"
empty.mkdir(mode=0o700)
for command in ["set auto-load off", "set debuginfod enabled off", "set auto-solib-add off", "set history save off", "set pagination off", "set target-file-system-kind unix",
"set sysroot ./no-libraries", "set solib-search-path ./no-libraries",
"set debug-file-directory ./no-libraries"]:
for command in ["set auto-load off", "set debuginfod enabled off", "set auto-solib-add off", "set history save off", "set pagination off",
"set sysroot ./no-libraries", "set solib-search-path ./no-libraries"]:
gdb.execute(command, to_string=True)
entry = request["gdbinit"]
try:
@@ -39,19 +38,7 @@ def inspect(request):
# relative filename in the owned cwd so no selected path becomes GDB syntax.
if Path(request["snapshot_path"]) != root.parent / "object.snapshot":
raise ContextFailure("decoder", "Core context request did not select the shared owned snapshot.")
# GDB 16 searches AT_EXECFN/NT_FILE outside sysroot when no executable BFD
# is selected. Occupy that slot with the already running, owned debugger;
# exec-file loads no symbols and never runs it. Clear it before any query.
# /proc/self/exe identifies this process, not the core's historical PID.
architecture = {"x86_64-little-endian": "i386:x86-64", "aarch64-little-endian": "aarch64"}.get(request["architecture"])
if architecture is None:
raise ContextFailure("unsupported", "Unsupported recorded core architecture.")
gdb.execute("exec-file /proc/self/exe", to_string=True)
# The placeholder must not select the core's architecture. Reuse the
# decoder's validated profile, including for cross-architecture GDB builds.
gdb.execute("set architecture " + architecture, to_string=True)
gdb.execute("core-file ../object.snapshot", to_string=True)
gdb.execute("file", to_string=True)
inferior = gdb.selected_inferior()
if inferior.connection is None or inferior.connection.type != "core" or gdb.current_progspace().filename is not None:
raise ContextFailure("decoder", "Requested core-only boundary was not established; no mapping query performed.")
-117
View File
@@ -1,117 +0,0 @@
"""Producer regressions with controlled GDB state, not native debugger qualification."""
import json
import os
from pathlib import Path
import runpy
import sys
import tempfile
import types
import unittest
from unittest.mock import patch
BRIDGE = Path(__file__).with_name("core_context.py")
class CoreContextTests(unittest.TestCase):
def inspect(self, failure=None, connection="core", symbols=None, architecture="x86_64-little-endian"):
commands, reads, queries = [], [], []
state = {"executable": None, "symbols": None, "connection": None}
gdb = types.ModuleType("gdb")
gdb.VERSION = "16.3"
gdb.selected_inferior = lambda: types.SimpleNamespace(
connection=state["connection"], pid=123)
gdb.current_progspace = lambda: types.SimpleNamespace(filename=state["symbols"])
def execute(command, to_string):
self.assertTrue(to_string)
commands.append(command)
if command == failure:
raise RuntimeError("controlled command failure")
if command == "exec-file /proc/self/exe":
state["executable"] = "/proc/self/exe"
elif command == "core-file ../object.snapshot":
if state["executable"] is None:
reads.append("recorded-executable")
state["executable"] = state["symbols"] = "recorded-executable"
state["connection"] = types.SimpleNamespace(type=connection)
elif command == "file":
state["executable"] = None
state["symbols"] = symbols
gdb.execute = execute
pwndbg = types.ModuleType("pwndbg")
pwndbg.aglib = types.ModuleType("pwndbg.aglib")
pwndbg.aglib.vmmap = types.ModuleType("pwndbg.aglib.vmmap")
pwndbg.lib = types.ModuleType("pwndbg.lib")
pwndbg.lib.version = types.ModuleType("pwndbg.lib.version")
pwndbg.lib.version.__version__ = "2026.09.15"
def maps():
self.assertIsNone(state["executable"], "Helper executable must be discarded before mapping queries")
queries.append("maps")
return [types.SimpleNamespace(start=4096, end=8192, offset=0, flags=5, objfile="recorded-executable")]
pwndbg.aglib.vmmap.get = maps
modules = {module.__name__: module for module in [
gdb, pwndbg, pwndbg.aglib, pwndbg.aglib.vmmap, pwndbg.lib, pwndbg.lib.version]}
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
stage = root / "debugger"
stage.mkdir()
plugin = root / "gdbinit.py"
plugin.write_text("")
request = stage / "request.json"
reply = stage / "reply.json"
request.write_text(json.dumps({"gdbinit": str(plugin), "architecture": architecture, "snapshot_path": str(root / "object.snapshot"), "reply_path": str(reply)}))
with patch.dict(sys.modules, modules), patch.dict(os.environ, REA_CORE_CONTEXT_REQUEST=str(request)):
runpy.run_path(str(BRIDGE))
result = json.loads(reply.read_text())
return result, commands, reads, queries
def test_core_load_never_opens_recorded_executable_and_queries_only_after_discard(self):
result, commands, reads, queries = self.inspect()
self.assertTrue(result["ok"], result)
self.assertEqual(reads, [])
self.assertEqual(queries, ["maps"])
self.assertEqual(commands[-4:], ["exec-file /proc/self/exe", "set architecture i386:x86-64", "core-file ../object.snapshot", "file"])
self.assertLess(commands.index("set debug-file-directory ./no-libraries"), commands.index("core-file ../object.snapshot"))
self.assertIsNone(result["value"]["executable"])
self.assertEqual(result["value"]["maps"][0]["current_file_identity"], "unknown")
def test_failed_guard_core_load_or_discard_never_queries_mappings(self):
for command in ["exec-file /proc/self/exe", "set architecture i386:x86-64", "core-file ../object.snapshot", "file"]:
with self.subTest(command=command):
result, commands, reads, queries = self.inspect(failure=command)
self.assertFalse(result["ok"])
self.assertEqual(reads, [])
self.assertEqual(queries, [])
if command in ["exec-file /proc/self/exe", "set architecture i386:x86-64"]:
self.assertNotIn("core-file ../object.snapshot", commands)
def test_cross_architecture_uses_the_validated_decoder_profile(self):
result, commands, reads, queries = self.inspect(architecture="aarch64-little-endian")
self.assertTrue(result["ok"], result)
self.assertEqual(reads, [])
self.assertEqual(queries, ["maps"])
self.assertLess(commands.index("set architecture aarch64"), commands.index("core-file ../object.snapshot"))
def test_unknown_architecture_refuses_before_loading_core(self):
result, commands, reads, queries = self.inspect(architecture="unknown")
self.assertFalse(result["ok"])
self.assertEqual(result["reason"], "unsupported")
self.assertNotIn("core-file ../object.snapshot", commands)
self.assertEqual(reads, [])
self.assertEqual(queries, [])
def test_wrong_connection_or_remaining_symbols_never_queries_mappings(self):
for options in [{"connection": "native"}, {"symbols": "unexpected-symbols"}]:
with self.subTest(options=options):
result, _, reads, queries = self.inspect(**options)
self.assertFalse(result["ok"])
self.assertEqual(reads, [])
self.assertEqual(queries, [])
if __name__ == "__main__":
unittest.main()
+5 -33
View File
@@ -98,37 +98,16 @@ existing analysis families directly, for example
| `collect_adb_bugreport` | read | Device-generated bugreport zip, digested |
| `push_adb_file` | **mutates device** | One local file to a device path (e.g. pushing tools into `/data/local/tmp`); checks for existing targets and refuses them without explicit overwrite (the check is not atomic); compares digests when device `sha256sum` is available |
| `install_adb_package` | **mutates device** | Local APK via `adb install [-r]`; preserves its Success/Failure verdict, records `replace_requested`, and leaves actual replacement `null` because prior package state is not observed |
| `uninstall_adb_package` | **mutates device** | Requests package removal for user 0 via `adb shell pm uninstall --user 0`, without data retention |
| `uninstall_adb_package` | **mutates device** | Removes a package and its data for user 0 |
| `start_adb_app` | **mutates device** | Resolves the package's launcher activity (`cmd package resolve-activity --brief`) and starts it (`am start -n`) |
| `start_adb_activity` | **mutates device** | Starts an intent (`am start -a` with optional URI, component, and up to 16 typed extras); preserves the activity manager's verdict |
| `stop_adb_app` | **mutates device** | Force-stops every process of a package, ending a dynamic-analysis run |
For `inspect_adb_window`, `focus_contexts` retains each display header, its exact
display ID when recognized, and every focus declaration with its original line.
Declarations without a display header are explicitly `unscoped`. A missing
declaration differs from a declaration whose `value` is JSON `null`.
`source_section` identifies the selected dumpsys section; `observed_lines`
preserves its focus declarations and display headers in source order.
`focus_summary` is `single_context` only for one context with no repeated focus
field. The singular `focused_window` and `focused_app` summarize that context;
they do not establish device-wide focus. Multiple contexts or repeated fields
produce `ambiguous` with null singular fields and all declarations retained.
When no focus field was declared, the status is `unavailable`. REA reads the
displays section only when the windows section declares neither focus field.
For `install_adb_package`, `replace_requested` records whether `-r` was sent.
The `replaced` result is `null`: the successful install response does not say
whether the package was installed fresh or replaced, and REA does not query the
device first. The install verdict and host APK digest remain available.
Push and install consume a private snapshot of the selected local input. The
reported size and SHA-256 identify those consumed bytes; `local_path` and
`apk_path` retain the original input path, whose contents may change later.
Snapshot creation needs temporary disk space proportional to the input size.
Failed snapshot cleanup remains owned and is retried before later operations
and during shutdown.
## Interpret the result
- **Directory names retain whitespace and newlines.** Symlink targets do too,
@@ -167,10 +146,8 @@ and during shutdown.
- **Mutations are explicit.** `push_adb_file`, `install_adb_package`, and
`uninstall_adb_package` declare `mutatesTarget` and never run implicitly:
pushes check for existing device files before transfer and refuse them
unless `overwrite` is set. A failed or unexpected existence probe stops
transfer even with `overwrite`; only a clean `test -e` exit of 1 with no
output is interpreted as absence. The check is not atomic, so a different
process can create the path before `adb push` writes it. When available, the device's
unless `overwrite` is set. The check is not atomic, so a different process
can create the path before `adb push` writes it. When available, the device's
`sha256sum` verifies the transfer; installs preserve the
device's `Failure [...]` reason verbatim.
- **Producer identity stays attached.** Every result embeds the producing
@@ -183,19 +160,14 @@ and during shutdown.
The app/activity lifecycle tools use `am start -W` and `am force-stop`.
- Per-invocation budgets: client/devices 10-20 s, shell reads 20-60 s with
64 KiB-8 MiB capture caps (logcat 4 MiB, screen 32 MiB), transfers and
bugreports 600 s. Output capture overflow reports `resource_constraint`;
deadline expiration, including the client-version probe, reports
`provider_timeout`. Command cancellation preserves the caller's exact reason;
a later abort does not replace an already completed command failure.
bugreports 600 s. Exceeded budgets report `resource_constraint`; stopped
commands report `provider_timeout`.
- Pull and capture outputs are additive: the destination must not already
exist. Re-running a completed pull refuses the existing directory instead
of overwriting evidence.
- Cancellation during a package pull preserves caller-selected output. The
error includes partial observations identifying completed artifacts and the
interrupted local path; remaining APKs were not attempted.
- Screen capture checks cancellation before publishing its exclusive output.
If cancellation arrives after publication, the error retains the committed
file's path, digest and dimensions; the file remains available as evidence.
- Bugreports collect into isolated staging and publish with exclusive creation;
filename collisions select the next numeric suffix. If publication fails, the
completed archive remains in staging. The error's partial observation gives
+13 -56
View File
@@ -103,10 +103,9 @@ that every class or engine operation will load successfully. Discovery limits
each ZIP metadata read to 8 MiB before allocation; a larger directory reports
the exhausted read budget and the selected JAR path.
The filtered class-page bridge (protocol 2) is verified on Linux x86-64 with
Temurin 21, public Appium ApiDemos 6.0.18 and NewPipe 0.29.1 APKs. Earlier
metadata-bridge records covered macOS arm64/OpenJDK 21 and Windows x64/JDK 21;
this protocol revision has not been rerun on those hosts or Linux/JDK 25.
The current metadata bridge is verified on macOS arm64 with OpenJDK 21 and the
public Appium ApiDemos fixture. The POSIX adapter also supports Linux; the new
bridge has not yet undergone real verification on Linux/JDK 25.
Windows x64 uses an owned Job Object with bidirectional stdio, atomic job
assignment and kill-on-owner-close. Real Windows verification uses JDK 21 and
the pinned JADX 0.7.1 JAR; see the real verification lane below.
@@ -147,20 +146,10 @@ queries accept the same `overload_index`; the bridge resolves the selected
method node and the result reports its index and displayed signature. These
indices are tied to the current artifact and engine, not stable across builds.
Smali fallbacks select one complete block using the original method name and DEX
descriptor, before applying the source byte limit. This preserves the selected
overload even when Java code generation renames a method. If the selected Java
body was omitted, including a method merged into a synthetic bridge, REA returns
its original smali with the `java_body_unavailable` marker. The marker describes
missing Java; it does not infer why the method was omitted or name a replacement.
Unresolved or duplicate disassembly identities fail instead of attributing another
method's instructions to the selection.
Native and abstract methods are identified from access flags
captured before code generation. They report `body_status: "not_available"`, an
empty source, and the `native_method` or `abstract_method` marker; their declarations
are not passed through the engine's source slicer. Other missing decompiled bodies
do not establish either access flag.
The engine's smali fallback also joins same-name overloads; REA rejects that
fallback for an overloaded method instead of attributing all bodies to one
selected overload. Native/abstract methods with no decompiled body report
`body_status: "not_available"` without inferring which implementation flag caused it.
Static initializers (`<clinit>`) return smali with the
`static_initializer_disassembly` marker. Java decompilation can move their
@@ -174,10 +163,7 @@ the same source byte limit and explicit truncation reporting.
permissions and class/resource counts. Summary fields are extracted by the
upstream engine and should be checked against the retained XML when needed.
Signature verification is explicitly `not_performed`.
- Class search filters the engine's cached top-level names before transferring
pages, then follows contiguous inventory positions without rescanning earlier
rows. It checks selection, scope, examined ranges and counts before reporting
complete coverage. Complete producer replies stay in Evidence; an empty `query`
- Class search consumes all pages and checks their counts. An empty `query`
inventories all class-name rows; class names are decompiler representations.
Repeated names remain repeated in `matches` so the inventory row count and
producer evidence stay visible. `duplicate_names` identifies matching names
@@ -247,12 +233,8 @@ rea project-android-application-graph '{"inventory_evidence":[<inventory_artifac
```
The projection reports exact component paths and hashes, runtime-family hints,
and path-based bridge hypotheses. File and slice occurrences supply component
endpoints; directory trees and symlinks retain their identities in the source
inventory without being classified as code files. It does not decode DEX or
claim observed runtime calls. DEX/JVM runtime hints summarize the classified
bytecode component lists. Framework hints match complete native library names,
such as
and path-based bridge hypotheses. It does not decode DEX or claim observed
runtime calls. Framework hints match complete native library names, such as
`libreactnativejni.so`, `libreactnative.so`, `libhermes.so`,
`libhermes_executor.so`, `libflutter.so`, and `libunity.so`; unrelated names
such as `libcommunity.so` and `libreactivity.so` do not identify those families.
@@ -317,34 +299,9 @@ settings. Evidence reports the worker's observed `Runtime.maxMemory()` rounded
down to MiB and retains exact bytes, Java version and visible processors in its
raw runtime response. The observed allocatable heap can differ from configured
`-Xmx`, especially with Serial GC. Heap is not a total RSS cap: the JVM also
uses native memory. A typed JVM memory allocation failure during APK loading
reports `resource_constraint` with the observed maximum heap in bytes. Known
heap failures name `REA_JADX_HEAP_MIB` in remediation; other memory regions
remain unknown. A healthy doctor configuration check does not establish that
any particular APK fits. Failures before the bridge can report a typed result
and upstream errors from other operations retain their existing diagnostics;
error text alone does not establish memory exhaustion.
Independent REA instances have independent queues. Whole
operations have a **120-second** execution deadline by default, starting after
they reach the queue's front. For a known slow cold load, such as a large
multidex APK, select another finite deadline:
```sh
export REA_JADX_OPERATION_TIMEOUT_MS=600000
```
The value must be a decimal millisecond count from 1 to 2147483647; anything
else is refused before Java starts. The same deadline bounds each upstream
call, a timeout reports the selected value, and a passing JADX configuration
check in `rea doctor` reports the effective `operation_timeout_ms`. Explicit
cancellation still ends the operation immediately, and partial observations
and owned-process cleanup are unchanged. Raising the deadline does not extend
the bridge's 30-second startup handshake or the upstream **90-second**
decompilation limit. MCP clients enforce their own tool-call timeouts, and
setup's derived [client tool timeout](client-configuration.md) does not include
this setting, so also raise the client timeout when selecting a longer
deadline.
uses native memory. Independent REA instances have independent queues. Whole
operations have a **120-second** execution deadline after reaching the queue's
front; upstream decompilation is limited to **90 seconds**.
Decoded manifest and method text have a **1 MiB** upstream byte budget and report
truncation. Class-name pages use indexed slices of up to 4,096 names without changing the
+8 -57
View File
@@ -24,30 +24,6 @@ missing launcher reports `capability_unavailable` with the
`binary_session` uses the same host probe for tool availability; it does not
validate a particular APK or guarantee that the selected input can be decoded.
Client inspection and decode results disclose the following reported-version
advisory windows without refusing otherwise compatible launchers:
| Advisory | Reported version window | Host scope |
| ----------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ---------- |
| [CVE-2024-21633](https://github.com/iBotPeaches/Apktool/security/advisories/GHSA-2hqv-2xv4-5h5w) | Before 2.9.2 | All |
| [GHSA-vgwr-4w3p-xmjv](https://github.com/iBotPeaches/Apktool/security/advisories/GHSA-vgwr-4w3p-xmjv) | Before 2.9.3 | Windows |
| [CVE-2026-39973](https://github.com/iBotPeaches/Apktool/security/advisories/GHSA-m8mh-x359-vm8m) | 3.0.0 release line through versions before 3.0.2 | All |
The 2026 advisory names 3.0.1 and its 3.0.2 fix. Inclusion of 3.0.0 is
source-derived: [tagged 3.0.0](https://github.com/iBotPeaches/Apktool/blob/f770b39e425af4fa6ac4ca1e9ea6c4824339c6d3/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/table/ResTypeSpec.java)
passes type names through unchanged; the [3.0.2 patch](https://github.com/iBotPeaches/Apktool/commit/65dd8480dfcb63068562ffaa527f71bb0a9f772c)
validates those names at their owner before they reach the output-path producer.
Prereleases before the fixed release are conservatively disclosed; the exact
`-dirty` downstream marker is compared as a release while preserving its spelling.
This is version guidance, not verification of a particular prerelease or decoder.
A launcher version does not prove the decoder's contents, execution platform,
downstream backports, or overall safety. Windows applicability uses the selected
local host; an opaque wrapper may run another engine. A missing warning means
only that none of these version/host windows matched. Verify the selected
decoder's patches before decoding untrusted APKs; the compatibility floor above
is not a security recommendation. REA does not fetch advisories at runtime.
On Windows, a `.bat` or `.cmd` launcher (such as Chocolatey's `apktool.bat`)
runs through an explicit `cmd.exe /d /s /c` call. That call has no AutoRun,
no delayed expansion, and quotes every argument. A launcher path that
@@ -62,15 +38,13 @@ reports `capability_unavailable`.
rea inspect-apktool-client
rea decode-android-resources /targets/Example.apk
rea decode-android-resources /targets/Example.apk --locale de
rea decode-android-resources /targets/Example.apk --locales de --locales pt-BR
rea decode-android-resources /targets/Example.apk --no-strings
```
Equivalent MCP methods are `inspect_apktool_client` and
`decode_android_resources`. The decode request takes `path`, an optional
primary `locale` (project `res/values-<locale>/strings.xml` instead of the default
table), `locales` (repeatable array of additional localized string tables to project
from the same single decode pass), and `include_strings` (default true). Regional locales such as `pt-BR`
`locale` (project `res/values-<locale>/strings.xml` instead of the default
table), and `include_strings` (default true). Regional locales such as `pt-BR`
select Android's `values-pt-rBR`; Android qualifiers such as `pt-rBR` and
`b+zh+Hans+CN` may also be supplied directly.
@@ -78,8 +52,6 @@ select Android's `values-pt-rBR`; Android qualifiers such as `pt-rBR` and
- **An owned APK snapshot is digested and decoded.** `target.sha256` and
`target.bytes` bind the observation to the exact APK that was decoded.
The Evidence subject carries the same snapshot digest and caller-selected
path, including when the original file changes during decoding.
- **Metadata comes from apktool.yml as apktool printed it.** Version codes
keep their own spelling (`'7'` versus `7`); `package_name` is read from
the decoded manifest, not inferred.
@@ -87,28 +59,9 @@ select Android's `values-pt-rBR`; Android qualifiers such as `pt-rBR` and
truncated when larger.
- **Strings are projected verbatim.** Escaped entities stay escaped, and
entries containing nested markup (`<b>`, `<xliff:g>`) are counted as
unparsed rather than flattened — the limitation names the examined count.
Malformed XML and a wrong document root are whole-document projection
failures: the result is partial, the failure reason is disclosed, and entry
counts remain unknown. They are not counted as one unsupported string.
The default table is bounded to 2000 entries with partial coverage when more
exist. `locales` lists observed regular `strings.xml` tables whose exact
`values-<locale>` directory is selectable by the request's locale grammar.
Locale suffixes allow up to 23 ASCII characters, derived from Apktool's
language, script, region, and variant fields; for example,
`b+sr+Latn+RS+REVISED` selects that exact table.
Other table directories, including combined qualifiers such as
`values-en-rUS-v21` and `values-mcc310-fr`, are named in limitations with
their source spelling. They are not advertised as selectable locales;
REA does not infer Android's runtime resource matching. Non-regular
strings-table paths are disclosed with partial coverage. Discovery uses
the same bounded traversal as the file count; filesystem failures remain
failures rather than being interpreted as missing tables.
When multiple tables are requested with `locales`, `string_tables` records
each projected table with its locale, status (`present`, `missing`,
`oversized`, `malformed`, or `skipped`), entry counts, and coverage,
bounded at an aggregate budget of 10,000 strings and 32 MiB XML. When `locales`
is omitted, legacy single-table payloads are preserved without adding `string_tables`.
unparsed rather than flattened — the limitation names the count. The
default table is bounded to 2000 entries with partial coverage when more
exist; `locales` lists every `values-<locale>` that has a strings table.
- **Smali is skipped by design** (`apktool d --no-src`): Java-source
recovery belongs to the JADX family. Resource smali edits and rebuild are
a follow-up lane with mutation authority.
@@ -128,11 +81,9 @@ select Android's `values-pt-rBR`; Android qualifiers such as `pt-rBR` and
coverage and an explicit limit, rather than reported as missing.
- `decoded_file_count` is capped at 100,000 files; the cap is reported in
the limitations when hit.
- An ordinary nonzero decode exit surfaces as `unsupported_target` naming
the caller-selected APK, with Apktool's diagnostic and captured output.
Launcher startup, ownership preparation, signal termination and incomplete
output collection remain provider failures; they do not establish that the
selected APK is unsupported.
- Apktool's own decode failures (`AndrolibException`, directory traversal
refusals) surface as `unsupported_target` with apktool's reason preserved
verbatim.
## Real verification
-18
View File
@@ -60,15 +60,6 @@ states that absence is unknown. Component arrays remain complete when candidate
hypotheses are omitted; component arrays still include every component from
the supplied inventory pages, and overall coverage is `partial` in that case.
Inventoried files whose bytes were not read, such as encrypted archive members,
are listed in `unavailable_components` with their original path, format,
encryption flag, limitations, and null content identity. The same application-root
and AppleDouble attribution rules apply. These files make overall coverage
`partial`; component absence is unknown even when `inventory_complete` is true.
Directories have no file bytes and symlinks remain in `symlinks`, so neither is
an unavailable file component. The additive field participates in `projection_id`,
including when empty, so Apple projection identifiers change.
## Application roots
| Inventory root | Application root |
@@ -77,15 +68,6 @@ including when empty, so Apple projection identifiers change.
| `.app` directory | `.`, the inventoried bundle itself |
| Directory, ZIP, or DMG containing apps | Each outermost `<Name>.app` followed by `Contents/` |
File and slice occurrences supply component endpoints. Directory tree identities
remain in source inventory and bundle anatomy, and links remain in `symlinks`.
Root and layout discovery use known directories and ancestors implied by deeper
inventory paths. A leaf file or symlink named `*.app`, `Contents`, or `Versions`
does not establish that directory. Directory and authenticated-file identity are
selected before applying anatomy case preferences, so a file cannot shadow a
folded directory name or a directory shadow a metadata/signature file.
ZIP archives made with `ditto -c -k --keepParent` report `<Name>.app`. A DMG
reports `<image>.dmg/<Volume>/<Name>.app`; DMG child inventory needs the native
macOS mounting adapter. When a DMG has only its root identity, the projection is
-6
View File
@@ -26,7 +26,6 @@ graph TD
end
subgraph "Provider Layers"
PROVIDER_OWNERS["src/providers/<br/>shared deferred client and inspection owners<br/>exact cleanup retry and attributed failures"]
PWNTOOLS["src/native/pwntools/ + src/native/pwndbg/<br/>BYO offline ELF/core adapters<br/>owned snapshots/Python and optional core-only GDB<br/>unchanged upstream parsers, ABI structures and mapping API"]
WASM["src/wasm/<br/>caller-supplied WABT; immutable artifact inspection<br/>owned process supervision and retryable workspace cleanup"]
EVM["src/evm/<br/>unchanged EVMole/WASM in bounded owned worker<br/>explicit carrier parsing and inferred interface adapter"]
@@ -139,11 +138,6 @@ graph TD
GHIDRA --> GHIDRA_BRIDGE
HOPPER --> PROCESS
GHIDRA --> PROCESS
GHIDRA --> PROVIDER_OWNERS
APP --> PROVIDER_OWNERS
PROVIDER_OWNERS --> PROCESS
PROVIDER_OWNERS --> AUX
PROVIDER_OWNERS --> DOMAIN
GHIDRA --> WINDOWS
PROCESS --> WINDOWS
WINDOWS --> WINDOWS_NATIVE
-18
View File
@@ -147,24 +147,6 @@ received signal alone does not establish its exact cause. Dynamic tags require
a complete DT_NULL inside PT_DYNAMIC; interpreter names and ranges end at the
first NUL, with any padding still represented by the original segment range.
## Ghidra process failures
When output from the failing Ghidra startup or operation reports
`java.lang.OutOfMemoryError`, REA returns `resource_constraint`. Java heap or GC
overhead exhaustion includes heap-specific recovery advice. Metaspace and array
size failures do not recommend increasing the heap; native-thread exhaustion is
reported as a capacity constraint with unknown limits.
`configured_jvm_max_heap` records the explicit `-Xmx` value selected by REA's
launch builder. It is a configuration fact, not measured memory use or proof of
the effective JVM limit; JVM environment options may affect that limit.
When a Windows script wrapper selects the JVM, this value remains unknown.
Historical stdout and stderr remain available, but classification uses only the
failing operation's `failure_output`. Output draining waits at most one second,
subject to earlier cancellation or the startup deadline. `output_incomplete`
marks a snapshot taken before stream closure; cleanup ownership remains with
the session until release succeeds.
## Portable PE resources
`inspect_pe_resources` / `inspect-pe-resources` inspects an explicit PE32 or
+9 -28
View File
@@ -66,25 +66,14 @@ Electron `file://` pages use a separate provider and target boundary; see [elect
## Provider authorities
CDP page capture and V8 Inspector observation attach to an already-running
target without launching it, driving actions, or evaluating target code.
Playwright scenarios drive actions and capture step snapshots in either a
provider-owned browser or a caller-selected external browser. Separate providers
preserve these authority and lifecycle differences. They share one exclusion
vocabulary (`BrowserExclusionReason`): every denial reason maps onto it, even
where a wire schema keeps a narrower historical bucket.
CDP attachment is not a guarantee that the browser preserves all state.
Chromium can clear another client's `navigator.platform` emulation when REA's
page session disconnects, even if that session sent no emulation commands.
This affects page inspection, bundle capture, session observation, screenshots,
WebMCP discovery, and Electron page inspection; target listing alone does not
attach a page session. REA cannot read the other client's complete
user-agent/client-hint configuration and does not replay guessed settings.
Use a disposable browser when preserving externally configured emulation is
required, or have the owning client reapply its complete configuration afterward.
See [the reproduction and Chromium ownership limitation](https://github.com/morluto/rea/issues/4089).
CDP page capture, V8 Inspector observation, and Playwright scenarios stay
separate providers because their authorities differ: CDP and V8 attach to an
already-running target and never launch, drive, evaluate, or mutate it, while
Playwright providers own and drive the runtime (launch browsers, run actions,
capture step snapshots). Merging them would mix attach-only and owned-process
lifecycles in one contract. What they share instead is one exclusion
vocabulary (`BrowserExclusionReason`): every denial reason in every stack maps
onto it, even where a wire schema keeps a narrower historical bucket.
Existing static application Evidence and passive web/Electron captures can be
combined later through
[JavaScript static/runtime reconciliation](javascript-runtime-reconciliation.md).
@@ -285,14 +274,6 @@ REA establishes a main-frame origin boundary before enabling Runtime, Debugger,
## Data minimization
The Link projection parses repeated CDP header field lines independently and
retains their declarations in order, including derived untrusted agent hints.
Commas inside URI targets or quoted parameters remain part of those values.
COOP and COEP projections retain the exact declared token after validating the
complete Structured Field Item, including parameters such as `report-to`.
These are declarations, not an assessment of the document's effective policy;
absent, malformed or non-token items project as `null`.
REA retains local observation data and removes only URL userinfo credentials, explicitly declared scenario secrets, and values from structured credential/storage fields:
- URL observations preserve the complete local URL, including query values, fragments, duplicate parameters, and their order. Only username/password userinfo is removed; malformed original URL strings remain available with `origin: null`.
@@ -328,7 +309,7 @@ REA retains local observation data and removes only URL userinfo credentials, ex
an omitted type leaves equality unknown rather than proving a modification.
- Console observations with a stack source retain call type, argument types, timestamp, and source location. When console text capture is selected, already-delivered primitive values are retained verbatim; objects, getters, and remote properties are never expanded.
- WebSocket observations retain direction, opcode, and payload byte length. When shape capture is selected, text frames are classified as text or complete value-free JSON shape; binary bytes, hashes, prefixes, and raw frames are never retained.
- Storage observations always redact values. Key names, IndexedDB names, and cache names require `include_storage_keys`; stable content fingerprints require the additional `include_storage_fingerprints` selection. Cookie fingerprints cover cookies applicable to the current main-frame URL, including its path, rather than every cookie path on that origin. Other storage remains scoped to the origin. Cache fingerprints hash all decoded response bytes, including bodies above 64 KiB, subject to the [64 MiB per-message CDP limit](#request-boundary). Missing or undecodable cache bodies and partial IndexedDB remote objects make fingerprint coverage incomplete, so identical observations remain `unknown`.
- Storage observations always redact values. Key names, IndexedDB names, and cache names require `include_storage_keys`; stable content fingerprints require the additional `include_storage_fingerprints` selection. Cookie fingerprints cover cookies applicable to the current main-frame URL, including its path, rather than every cookie path on that origin. Other storage remains scoped to the origin. Cache bodies above 64 KiB and partial IndexedDB remote objects make fingerprint coverage incomplete, so identical observations remain `unknown`.
- Unavailable or malformed storage inventories mark `storage_keys` unavailable, even without fingerprints. Comparisons suppress inferred key additions and removals while preserving modifications proven by complete fingerprints on both sides. Previously exported captures are not retroactively corrected; recapture them to obtain these coverage markers.
- Script metadata is included only when CDP supplies a URL on an allowed origin. Stable keys exclude transient CDP script IDs, and exact transient raw URLs are used only during script/resource reconciliation. URL-less scripts are excluded because their origin cannot be established. When CDP supplies an execution-context association, the accepted script retains its authorized frame ID for later attribution. Script metadata admission bounds retained identity and source-map strings to 8 MiB and 50,000 records. When a source-map URL cannot fit, the script identity remains and source-map coverage reports `resource_budget_exhausted`; rejected script observations are counted without retaining their IDs. Source content is omitted unless explicitly requested and is returned inline as a self-verifying artifact with its SHA-256 digest.
-21
View File
@@ -144,27 +144,6 @@ distinction: it closes and deletes provider-owned profiles, but only disconnects
from an external CDP browser. Real-browser verification checks both outcomes and
confirms that an attached external browser remains alive.
That cleanup requires REA to remain running. Abrupt termination, including
Windows process-tree termination or POSIX `SIGKILL`, can leave the launch
profile and Playwright artifacts behind. A profile can retain cookies, history,
cache and origin storage. Later REA runs currently do not reclaim these paths.
Playwright 1.58.2 can also leave an artifacts directory when launch preparation
fails before a browser process exists, such as for a missing executable.
POSIX wrappers can request awaited cancellation with `SIGINT` or `SIGTERM`;
Windows process termination is not an equivalent graceful-cancellation channel.
Do not identify owned artifacts by directory prefix or creation time alone.
See [#4659](https://github.com/morluto/rea/issues/4659) for the remaining recovery
and wrapper-cancellation work.
Keeping that browser alive does not guarantee its emulation state survives.
Chromium can clear caller-owned `navigator.platform` emulation when a page CDP
session disconnects, including sessions that sent no emulation commands. REA
cannot snapshot the other client's complete user-agent/client-hint settings and
does not replay a partial reconstruction. Use launch mode to keep this effect
inside a provider-owned browser, or have the external owning client reapply its
complete configuration after capture. Connected captures report this limitation;
see [issue #4089](https://github.com/morluto/rea/issues/4089).
`environment.locale` sets Intl formatting in both modes. Launch also sets
`navigator.language`, `navigator.languages`, and the request `Accept-Language`.
Connect preserves the caller's page and request languages; every attached
-6
View File
@@ -168,12 +168,6 @@ be verified. See [MCP contracts](mcp-contracts.md) for session lifecycle and
[Ghidra first-query deadlines](mcp-contracts.md#ghidra-first-query-deadlines-and-recovery)
for import, client timeouts and recovery.
If one-shot analysis fails and closing its session also fails, the original
error details remain inline and `details.cleanup_error` describes the later
close failure. Each diagnostic retains its own reported resources; the later
failure does not establish whether an earlier resource was released. Captured
output and partial observations remain in the original details.
## Save and reuse analysis snapshots
A snapshot retains successful analysis results for later queries. REA reuses
+2 -14
View File
@@ -52,16 +52,10 @@ in the file the installed app reads:
`%APPDATA%` file it still reads; with neither file, setup creates the
private copy.
- If `%LOCALAPPDATA%\Packages` holds a `Claude_<publisher ID>` package from
another publisher, an `AnthropicPBC.Claude_<publisher ID>` package, or cannot
be read, REA cannot establish which file Claude
another publisher, or cannot be read, REA cannot establish which file Claude
Desktop reads. Setup, doctor and uninstall report that instead of falling
back to `%APPDATA%`. Doctor then reports `claude_desktop` as invalid, and
uninstall stops before removing anything for any client.
The reported `AnthropicPBC.Claude_fnn82j28hfe8t` build can use the `Claude-3p`
deployment directory. REA recognizes that package as an unresolved location;
it does not assume that it reads the legacy AppData file or automatically
register in `Claude-3p`. See [#4432](https://github.com/morluto/rea/issues/4432)
for the reported build and manual registration evidence.
Quit Claude Desktop fully before approving setup; closing its window is not
enough. A running Claude Desktop can rewrite its configuration from memory and
@@ -157,10 +151,7 @@ An explicit `REA_JEB_MCP_TIMEOUT_MS` request budget also contributes to that
maximum. For `ida` or `auto` selection, a valid IDA registration's parsed
`timeoutMs` also contributes to that maximum; its default is 300000 ms.
Setup forwards these explicitly selected REA deadlines and the input schema
profile into the registration; unrelated process values are omitted. An
explicit `REA_JADX_OPERATION_TIMEOUT_MS` is forwarded with the JADX
registration but does not contribute to the derived tool timeout; raise
`toolTimeoutMs` to cover a longer selected JADX deadline.
profile into the registration; unrelated process values are omitted.
This headroom is a practical default, not a guarantee for every analysis
duration. Setup preserves positive timeout values already in the `rea` entry.
You can edit `startupTimeoutMs` and `toolTimeoutMs` there; doctor keeps positive
@@ -254,9 +245,6 @@ values in the REA entry, and doctor reports a non-blocking advisory when a tool
timeout is shorter than the known provider allowance. An explicitly selected
JEB request budget also contributes to the allowance. A configured IDA
registration's parsed `timeoutMs` contributes for `ida` or `auto` selection.
An explicit `REA_JADX_OPERATION_TIMEOUT_MS` is forwarded with the JADX
registration but does not contribute; raise `tool_timeout_sec` to cover a
longer selected JADX deadline.
These values are client-side deadlines, so increase them in `~/.codex/config.toml` if a
workload needs more time. Devin honors `XDG_CONFIG_HOME` for its
`devin/mcp_config.json` on non-Windows systems.
+4 -84
View File
@@ -2,12 +2,6 @@
REA can attach to an Electron/Chromium CDP endpoint and inspect existing `file://` renderer pages without evaluating JavaScript or invoking Electron APIs. The request supplies the endpoint directly; REA accepts only literal-port loopback HTTP endpoints. Selecting an endpoint exposes every Electron target it serves, including local file paths and page metadata.
Disconnecting the inspection's page session can clear caller-owned
`navigator.platform` emulation inside Chromium. REA cannot restore another
client's complete user-agent/client-hint configuration. Use a disposable target
or let the owning client reapply its configuration; see the shared
[CDP state limitation](browser-observation.md#provider-authorities).
This passive runtime surface is distinct from the target-free static
[`analyze_javascript_application`](javascript-artifact-reconstruction.md)
workflow. Static analysis reads a local ASAR or extracted directory without
@@ -56,15 +50,8 @@ rea inspect-electron-page http://127.0.0.1:9223 TARGET_ID \
The normalized result contains canonical local paths, frame and DOM
structure, resource metadata, stable script/resource identities, explicit
completeness, and content-addressed script artifacts. Resource sizes are unknown
when omitted or invalid; supplied invalid sizes also produce an explicit
completeness diagnostic.
DOM node indices retain their snapshot positions. Invalid rows are omitted with
completeness diagnostics, so `total_nodes` can exceed the retained node count
and a parent index can refer to an omitted source node.
Script metadata retains its execution-context frame ID when CDP supplies one. The capture also
completeness, and content-addressed script artifacts. Script metadata
retains its execution-context frame ID when CDP supplies one. The capture also
inventories worker, service-worker, and shared-worker targets with
validated opener-target and parent-frame IDs. Worker discovery uses passive
target metadata; REA does not attach to or execute code in those targets.
@@ -114,18 +101,8 @@ scenario controls; their attempted and observed outcomes remain in the
timeline. The active hook blocks and records external shell/navigation,
permission, download, popup, updater, and OS-integration effects. The timeline
is explicitly partial when attachment starts after application activity. The
startup, including the initial state snapshot, has a 60-second deadline.
Actions wait until completion or request cancellation; a click whose target
never appears, or a `wait` without `window_index` in an app that opens no
window, remains pending until cancelled. After cancellation, the final state
read has 5 seconds before REA keeps the initial snapshot instead; the
cancellation keeps the caller's reason and records that expiry in its
diagnostics.
Blocked synchronous shell APIs keep their return contracts:
`showItemInFolder` returns `undefined` and `writeShortcutLink` returns `false`.
Their `shell-attempt` events record the blocked phase and argument shapes;
neither result means the requested host operation occurred. The existing
`openExternal` and `openPath` blocks continue to reject their promises.
startup has a 60-second deadline. Actions wait until completion or request
cancellation; a click whose target never appears remains pending until cancelled.
CLI SIGINT/SIGTERM requests cancellation and awaits owned-process cleanup.
Window IDs, URLs, and cached titles come from one main-process Electron snapshot,
so a crashed renderer does not require a successful renderer-side title query.
@@ -139,63 +116,6 @@ If cleanup cannot be verified, the error retains collected observations in
`details.partial_observation` and marks their application cleanup `unverified`.
Cleanup uncertainty does not authorize signaling unrelated processes.
Main-process IPC recording keeps original-function removal for `on` and `once`
registrations and records a fired `once` callback once. Native Node.js owns
`once` registration, firing and callable dispatch as well as removal order and
traversal, including listeners registered by removal observers;
the hook translates only its own recording wrappers at the removal boundary.
Wrapper metadata uses weak keys and does not retain removed registrations.
Wrapper metadata operations, private collection methods and traversal constructors are captured
before target startup; later replacement of their global bindings does not
change listener registration or removal.
Native runtimes differ in whether `once` consults callback `.call` or `.apply`.
The hook observes actual callback entry without imposing another runtime's
property reads or argument-list representation. Application methods selected by
native dispatch keep their original receiver and argument-list object; opaque
methods produce a `custom-call` or `custom-apply` observation gap when callback
execution cannot be established.
If native wrapper creation or registration-method lookup could expose private
instrumentation through an application getter, setter or Proxy, registration
stays native and unwrapped. The `once-metadata` observation gap identifies that
unobserved registration attempt; it does not prove registration or delivery. The original callback,
metadata writes and native method receivers are preserved, including when
registration fails. Later registrations resume normal observation. Non-callable
`call`/`apply` properties produce failed observation gaps when native dispatch reads
them; callback entry is not fabricated.
An `on` listener's application-defined `.apply` receives the original argument-list
object unchanged. Borrowing the exposed method preserves its dynamic receiver.
Because that method owns argument interpretation and may not
invoke the callback, the hook records a bounded `ipc-observation-gap` timeline
entry with the registered channel rather than an IPC invocation. Its empty
`argument_shapes` means unobserved arguments, not a zero-argument callback;
callback execution and result remain unknown. Coverage and retention include
these gaps even when their individual records are dropped. Normal native
dispatch continues to record actual invocation frames. Evidence snapshots copy
retained arrays and counters without invoking application iterators or Array
species.
Listener-chain recognition distinguishes owned, unowned and unknown metadata.
Data links may be inherited; absence is established only after completing the
bounded prototype lookup. Exhausting either walk, encountering a getter or seeing a Proxy leaves
ownership unknown. The hook preserves native registration without adding another
recording wrapper and retains a `listener-chain` observation gap after successful
registration. This gap does not prove IPC delivery. An existing inner recording
wrapper can still report its actual invocation; otherwise callback activity
remains unobserved. Setter-only properties have a known undefined read.
Data-descriptor parsing is shared with removal normalization.
This does not establish complete JavaScript function introspection equivalence.
Caller-defined `.listener` properties can change the identity exposed by
`listeners()` and meta-events; accessors and Proxy metadata are not followed for
wrapper recognition. Re-registering a raw recording wrapper on another channel
retains the original registration's channel attribution.
Mutating `.listener` on a raw recording wrapper can also prevent removal through
application decorators; the reproduced identity conflict is tracked in
[#4513](https://github.com/morluto/rea/issues/4513).
### Target fuse prerequisites
Active scenario capture requires that the target Electron executable honors Node CLI inspector flags (`--inspect` or `--remote-debugging-port`) so that Playwright can establish its DevTools protocol session.
+1 -3
View File
@@ -153,9 +153,7 @@ tree semantics, vulnerability scanning, emulation or hardware runtime capture.
## Resource and lifecycle policy
- Nonempty regular firmware inputs: at most **128 MiB**, copied and hashed into
a private workspace before analysis. Growth beyond that allowance during
copying receives the same typed input refusal as an already oversized file.
Supply a stable copy within the allowance. No in-place source modification.
a private workspace before analysis. No in-place source modification.
- One queued heavy operation per provider instance; Binwalk one thread and
Unblob one worker. No automatic parallel extraction engines.
- **120-second** deadline; inherited **1 GiB per-process address-space** limit,
-8
View File
@@ -124,10 +124,6 @@ FileBytes digests, every source mapping and its memory digest, relocation record
module partitions, relocation fixups and linear coordinates rather than relying
on the imported executable SHA alone.
Expected DOS relocation records retain each fixup's pre-application bytes and
applied value. Their memory-byte windows come from the final relocated image,
including changes made by later overlapping fixups.
The result is `verified`, `mismatch`, or `unsupported`. Every check retains its
expected and observed values. A memory-digest mismatch identifies the source
range's file offset and analysis address; it does not locate the first differing
@@ -138,10 +134,6 @@ their contents and DOS runtime semantics are not verified. Independent verificat
also covers explicit [raw-binary imports](raw-binary.md); other formats return
`unsupported` with measured observations.
MZ verification retains the initialized image described by the header's page
count and streams appended overlay bytes into the complete original and modified
source digests. Overlay size does not increase the retained image allocation.
`read_bytes` returns initialized provider memory, including loader fixups; an
unmapped or uninitialized byte ends the read with an explicit returned length and
`complete: false`. `address_to_file_offset` uses the provider's source mapping;
-21
View File
@@ -65,14 +65,6 @@ PDB, or change analyzer settings.
## Loaded addresses and file offsets
Ghidra computes overview procedure and string counts from the same inventories
used by `list_procedures` and `list_strings`, without transporting those rows
solely to count them. Counts include external functions and only Ghidra-defined
strings; they do not establish discovery of unidentified functions or undefined
string bytes. Complete inventories remain available through the list tools.
Overview reuse follows the target/profile snapshot lifetime and is invalidated
by session metadata edits.
`rea analyze <path> --provider ghidra --json` and MCP `binary_overview` report
the observed loaded `image_base` in `normalized_result`. They retain each
segment's reported `image_base` and `address_space`. A provider that does not
@@ -147,19 +139,6 @@ overview merely because its source artifact is unchanged.
## Admitted function-analysis semantics
Concurrent callers share one startup while retaining independent cancellation.
Only the final departing caller abandons startup and waits for its cleanup.
New attempts wait for that cleanup; failed cleanup retains its original error
and owned directories until a successful close. Closing the provider reports a
provider-state failure to live callers rather than cancelling their signals.
Configured analysis extensions and seeds use owned file reads during profile
resolution and launch snapshots. A changed read extent or descriptor state
refuses the commitment. Failed source or snapshot descriptor closes remain
owned and block new admission until cleanup succeeds; the physical failure
and exact cancellation reason remain available. Provider shutdown joins all
profile stages before retrying their retained descriptors.
| Concern | Ghidra contract |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Decompiler lifetime | One persistent `DecompInterface` is opened for the imported Program and disposed during bridge shutdown. Native decompilation has no fixed per-function deadline. External functions or functions without bodies return `null`; cancellation and native failure remain distinct. |
+2 -13
View File
@@ -39,8 +39,8 @@ container format, architecture, word size and byte order. A recognized
- `module.dependencies`, with the same fields and their original order;
- `module.settings`, retaining ordered key/value entries and duplicate keys;
- `module.unparsed_lines`, `module.unparsed_line_bytes_base64` and
`module.complete`, which says whether every present module-text line was
parsed. It does not establish that the dependency inventory is complete.
`module.complete`, so unfamiliar, malformed, conflicting or undecodable records
do not disappear behind a complete result.
Missing checksums are `null`; empty fields and development/local replacement
versions remain unchanged. Build settings such as `GOOS`, `GOARCH` or `vcs.revision`
@@ -50,13 +50,6 @@ base64 while other decodable module records are still reported; the reader does
not insert replacement characters or reject the entire artifact for those
strings.
When no main-module (`mod`) record was decoded, `module.main` is `null` and
dependency coverage is unknown. Successfully decoded dependency records remain
visible. GOPATH-mode builds may contain only a package `path` and build settings;
their empty dependency array does not establish the absence of dependencies.
The result's limitations state this explicitly. A module-mode build with a main
module record and no dependency records has an observed empty dependency list.
## Supported boundary
The built-in TypeScript reader supports ELF, PE and thin Mach-O images with Go's
@@ -91,10 +84,6 @@ host permission denial, changed artifacts and cancellation retain distinct
errors. The selected file is never modified; this inspection creates no
temporary files, starts no subprocesses and accesses no network endpoint.
An input above 256 MiB returns `resource_constraint` with resource `file-size`
and `reported_limits.maximum_input_bytes`. Select a suitable input within that
fixed allowance; changing an output-write or transport budget does not admit it.
Resource guards bound the selected file and cumulative header searches to 256 MiB
each, aggregate embedded strings
to 1 MiB, structural table decoding to 16 MiB and the complete normalized metadata
-6
View File
@@ -45,12 +45,6 @@ The MCP tool `project_harmony_application_graph` takes the same
- path-based N-API bridge hypotheses between bytecode and `libs/<abi>` native
libraries
File and slice occurrences supply component and child-package paths; directory
trees and symlinks retain their identities in the source inventory without
being classified as code files. Ark and JavaScript runtime hints summarize the
classified bytecode and JavaScript lists; supported source extensions share the
same classification rule as their component rows.
Every claim is path-presence only. Manifest semantics (module identity,
abilities, entry points, permissions, dependencies), Ark bytecode contents and
versions, resource resolution, signing verification, and observed native
+1 -3
View File
@@ -8,8 +8,6 @@ Choose one lifecycle mode in an upstream MCP JSON registration. Set `REA_IDA_MCP
Each mode accepts one upstream tool profile, checked against `tools/list` before any analysis runs. The attached profile requires the legacy GUI tool names; upstream 2.0.0 renamed those tools, and REA has not established an equivalent attached-mode lifecycle and ownership contract for that catalog. It therefore fails closed with the missing tool names in the error diagnostics.
Startup failures identify the accepted REA analysis operation. Missing-profile and typed startup transport failures retain the original stage in `details.diagnostics.startup_operation`; existing diagnostics, timeout budgets and resource limits remain available. Startup remains shared within a session; each caller receives its own operation attribution. Cancellation retains live cleanup ownership, so a successful retry releases the originating cancellation outcome as well.
The headless profile is defined by the database-supervisor API, not by an upstream version string. The upstream source snapshot [`c133c385`](https://github.com/mrexodia/ida-pro-mcp/tree/c133c3853faa111a9b00ee615c013b720d0c4acd) includes `idb_close` (introduced by [upstream PR #495](https://github.com/mrexodia/ida-pro-mcp/pull/495)) alongside `idb_open` and `idb_list`. Earlier builds may report the same `2.0.0` version while lacking that tool, so REA checks the live catalog rather than treating a version number or branch name as a compatibility guarantee.
| Mode | Upstream profile | Known working |
@@ -41,7 +39,7 @@ rea function /absolute/path/to/program main --json
rea decompile /absolute/path/to/program main --json
```
Open the **original input binary** in REA, not an `.idb` or `.i64` database. Its SHA-256 must match IDA's recorded input hash. REA checks the attached identity and image base around each analysis request. A mismatch or target switch fails with recovery guidance. The original input must remain readable by REA; WSL can use its mounted alias while the GUI runs on Windows. Attached profiles, including native mode, refuse universal Mach-O inputs at admission: every slice shares the recorded whole-file hash, so REA cannot verify which slice the GUI loaded. Open a thin file extracted with `lipo -thin` in both IDA and REA, or use headless mode, which analyzes the selected slice.
Open the **original input binary** in REA, not an `.idb` or `.i64` database. Its SHA-256 must match IDA's recorded input hash. REA checks the attached identity and image base around each analysis request. A mismatch or target switch fails with recovery guidance. The original input must remain readable by REA; WSL can use its mounted alias while the GUI runs on Windows.
REA's close operation releases its MCP connection or proxy. It never saves or closes the existing GUI database. External edits remain visible because results are live and are not replayed from snapshots. These checks do not lock the GUI or prove that the database is unpatched.
+15 -113
View File
@@ -57,26 +57,12 @@ Before applying changes, REA checks your current configuration. The plan lists:
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, stage changes in a private directory, and verify their result.
Before publication, they refuse detected changes to the selected configuration.
Replacement uses an explicit destination under the selected canonical parent;
it does not follow a newly inserted destination symlink. First-run setup uses
an exclusive hard link and fails without overwriting a newly created destination;
filesystems without hard-link support cannot publish a first-run configuration.
Setup and uninstall retain an existing `.rea.backup` rather than replacing the
first snapshot.
If that snapshot differs from the current configuration, setup and uninstall
preserve a verified `.rea.backup.<sha256>.recovery` copy of the current bytes
before editing; setup also previews it. Both snapshots remain available.
When an edit made a backup, a failed uninstall update or restore, and a failed
setup readback or rollback, name the backup path that holds the bytes from just
before that edit.
If setup cannot verify a newly created configuration, it retains the file and
reports manual recovery instead of deleting a pathname that may have changed.
For an existing configuration, setup and uninstall recovery refuse a detected
replacement or edit and name the recovery backup. Quit clients before editing their configuration;
these checks do not lock out another writer modifying the same file in place,
or exclude pathname changes between the final check and publication.
create backups, use atomic replacement, and verify their result. Setup and
uninstall retain an existing `.rea.backup` rather than replacing the first snapshot.
If that snapshot differs from the current configuration, setup previews and
preserves a verified `.rea.backup.<sha256>.recovery` copy of the current bytes.
Both snapshots remain available; a failed rollback reports the current recovery
copy's path and the restore failure.
Setup also retains valid environment overrides in REA's existing server entry,
such as `REA_MCP_INPUT_SCHEMA_PROFILE`, `REA_MCP_OUTPUT_SCHEMA_PROFILE`, and
`REA_MCP_MAX_RESPONSE_BYTES`.
@@ -193,8 +179,6 @@ as well, so it is broader than this Claude-only migration.
history under `CLAUDE_CONFIG_DIR`. Setup follows the same
variable: it writes the registration to `$CLAUDE_CONFIG_DIR/.claude.json` and
the skill to `$CLAUDE_CONFIG_DIR/skills`.
For REA setup, an empty `CLAUDE_CONFIG_DIR` is treated as unset: registration
goes to `~/.claude.json` and the skill goes to `~/.claude/skills`.
```bash
CLAUDE_CONFIG_DIR=~/.claude-rea npx rea-agents setup --client claude_code
@@ -276,14 +260,14 @@ Register with the variable unset:
<!-- x-release-please-start-version -->
```bash
claude mcp add --scope local rea -- npx -y rea-agents@6.7.0 mcp
claude mcp add --scope local rea -- npx -y rea-agents@6.5.0 mcp
```
On native Windows, use the same project directory and wrap the package-runner
shim so the stdio client can launch it:
```powershell
claude mcp add --scope local rea -- cmd.exe /d /c npx -y rea-agents@6.7.0 mcp
claude mcp add --scope local rea -- cmd.exe /d /c npx -y rea-agents@6.5.0 mcp
```
<!-- x-release-please-end -->
@@ -651,11 +635,6 @@ bridge readiness. For large targets, set `REA_HOPPER_STARTUP_TIMEOUT_MS` to a
decimal integer from 1 to 2,147,483,647 milliseconds in the environment that
starts REA. CLI and MCP use the same setting; invalid values fail configuration
validation. An MCP client's own request timeout must also allow enough time.
`open_binary` validates and selects a target without waiting for native provider
readiness. During Hopper startup, `binary_session.provider_operation_health`
reports `busy` at stage `launch`; `analysis_activity` describes bridge requests
and can remain idle until the socket is ready. Cleanup work reports `busy` at
stage `connection`.
If macOS denies Apple Events, allow the application that starts REA under
**System Settings → Privacy & Security → Automation**, then retry. REA releases
@@ -665,12 +644,9 @@ Arguments containing quotes, backslashes, or line breaks remain unchanged but
cannot establish that a failed handoff opened no document. Other failed handoffs
retain ownership until document closure is confirmed. If a timed-out bridge
becomes ready later, `close_binary` connects to that run, authenticates its
identity, and requests document shutdown. Once its listener is ready, the bridge
allows 30 seconds for the first connection and capability validation. After a
connection drops, it allows the same grace period for an authenticated cleanup
reconnect, then releases Hopper's Python execution thread. Initial analysis is
outside this listener grace period, and authenticated native work is not bounded
by it. Expiry does not establish document closure, so REA
identity, and requests document shutdown. After a connection drops, the bridge
allows 30 seconds for an authenticated cleanup reconnect, then releases Hopper's
Python execution thread. Expiry does not establish document closure, so REA
retains unconfirmed ownership. Retry close while the bridge remains available.
If a Linux launcher exists but cannot start, inspect its shared libraries:
@@ -760,17 +736,9 @@ Once document and process closure are confirmed, the lease can be released even
if temporary-file cleanup fails. Another client can then launch, but the owning
client must finish its retained cleanup before starting again.
An unconfirmed external document can be retried while its authenticated bridge
remains available. The same authentication and process-identity capture apply
when the first successful handshake occurs during cleanup after a startup
timeout. REA can confirm closure if that exact authenticated process exits,
including while a shutdown request is in flight. A helper exit alone is
insufficient, and an application that never authenticated has no verified
process identity. If no matching bridge becomes available, inspect and close
the reported document in Hopper before ending the owning REA connection.
Export the Evidence bundle before `close_binary` clears session records.
`binary_session.cleanup_pending` remains true while provider cleanup is retained,
and provider health remains visible even with `open: false`; that flag alone
does not establish successful cleanup.
remains connected. If that bridge has disconnected, another close cannot confirm
the document: inspect and close the reported document in Hopper before ending
the owning REA connection.
### Hopper in CI
@@ -847,16 +815,6 @@ rea doctor --json
rea setup
```
On macOS, [Homebrew OpenJDK is keg-only](https://formulae.brew.sh/formula/openjdk)
and may be unavailable to the system `java` wrapper. Set `JAVA_HOME` to the
selected formula's `libexec/openjdk.jdk/Contents/Home`, for example
`/opt/homebrew/opt/openjdk/libexec/openjdk.jdk/Contents/Home` or
`/usr/local/opt/openjdk/libexec/openjdk.jdk/Contents/Home`. Use a JDK inside the
Java version bounds declared by your Ghidra installation; REA does not select
another installed JDK automatically. Doctor distinguishes an absent Java
command from a command that runs and fails, and retains bounded probe output
and any parsed properties when the selected runtime cannot be admitted.
On Windows, configure the existing installation in PowerShell:
```powershell
@@ -894,34 +852,6 @@ MCP clients do not depend on an incidental shell path. Setup shows every exact
environment entry in its plan, writes only after approval, and never downloads,
installs, upgrades, or modifies Ghidra or Java.
Installation inspection derives the private configuration directory identity from
`application.version` and `application.release.name` in
`Ghidra/application.properties`. The directory's version spelling follows Ghidra
(for example, `12.1.0` becomes
`12.1`), while the reported provider version preserves the original value.
The launcher uses that inspected coordinate; it does not reread the properties
or guess from the extracted folder's name.
If the identity is missing, malformed, or unsafe as a single path component,
the launcher fails before preparing its home/cache/config/temp directories or
starting Java. The client may already have allocated private runtime/endpoint
resources and a target snapshot; existing startup-failure cleanup still applies.
Restore the selected release's properties instead of renaming its installation folder.
Inspection follows selected properties symlinks, admits only a regular file,
and caps the metadata payload at 1 MiB under REA's resource budget. A final
one-byte probe checks for growth. This is not a Java
Properties format limit. Reads preserve Ghidra's Latin-1 byte mapping and check
the descriptor and selected name for changes. Permission failures and resource
refusals remain explicit; failed descriptor cleanup must succeed before that
owner admits another inspection.
Native decompiler compatibility inspection follows the selected executable symlink
and reads at most the first 4096 bytes through the same descriptor owner. It
checks the full extent and selected name for changes without reading the remainder.
An unreadable or unrecognized header leaves compatibility unknown; diagnostics
retain read failures. Cancellation and incomplete cleanup propagate as failures,
and failed cleanup retains the exact descriptor for retry.
This coordinate selects only REA's session-private configuration directory, not
the installation or an existing user configuration directory.
Each verified session uses an ephemeral temporary project and isolated
home/cache/config/temp paths. REA passes `-readOnly`, `-deleteProject`, uses
Ghidra's default analysis settings, and loads its packaged Java
@@ -937,10 +867,6 @@ ownership inspection, so retaining those wrappers would prevent verified
process-group cancellation during startup.
If ownership remains unverifiable, it reports the reason and retains the process
supervisor and private runtime instead of removing files beneath a live provider.
Startup preserves an observed launch failure when cancellation arrives during
rollback. Producer cancellation retains the caller's exact reason separately
from LaunchSupport warnings and cleanup failures. Failed rollback keeps the
original process owner for a later cleanup retry.
The experimental Windows transport uses authenticated IPv4 loopback with a
private native-owned bearer descriptor and Job Object process ownership.
@@ -952,9 +878,6 @@ bridge, and health readiness. Large binaries can need more: set
`REA_GHIDRA_STARTUP_TIMEOUT_MS` to an integer between 1 and 2,147,483,647
milliseconds in the server environment. An absent setting uses the default;
empty, invalid or out-of-range supplied values fail configuration validation.
When the deadline elapses, the `provider_timeout` error names
`REA_GHIDRA_STARTUP_TIMEOUT_MS` with the deadline that was applied and suggests
`REA_GHIDRA_DISABLED_ANALYZERS` for analyzers that dominate the time.
REA parses the supplied configuration environment and
passes the deadline to each provider client; a startup failure is returned by the query that triggered it,
without exposing partial analysis. This deadline is separate from MCP transport
@@ -1036,8 +959,6 @@ export REA_GHIDRA_COMPILER_SPEC_ID="borlandcpp" # optional; requires a languag
REA passes `-processor`/`-cspec`, checks both against the installation's `.ldefs`, and records them in the analysis profile. DOS imports reject an override.
Language definitions must be well-formed XML encoded as UTF-8 or BOM-marked UTF-16, with any encoding declaration matching the bytes. Literal Unicode replacement characters (U+FFFD) are accepted; malformed source bytes are rejected.
To seed code that auto-analysis cannot reach (computed jumps, pointers in data):
```bash
@@ -1137,10 +1058,6 @@ compiler remains distinguishable from a compiler that exited with an error.
The helper compile deadline defaults to 120,000 ms; set
`REA_SWIFTC_COMPILE_TIMEOUT_MS` to an integer between 1 and 2,147,483,647 when
a busy host needs longer.
On macOS, the Java prerequisite probe waits for this independently bounded
preparation before starting its five-second command deadline. Caller cancellation
still interrupts preparation, and failed helper cleanup remains owned for retry.
Linux process-table preparation remains inside the command deadline.
Other rejection values retain their primitive value or an explicit type.
Shutdown warnings include the failure
kind, message, and diagnostics, while process and temporary-project cleanup
@@ -1187,7 +1104,7 @@ For a client that requires manual configuration, use:
"mcpServers": {
"rea": {
"command": "npx",
"args": ["-y", "rea-agents@6.7.0", "mcp"]
"args": ["-y", "rea-agents@6.5.0", "mcp"]
}
}
}
@@ -1252,21 +1169,6 @@ 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.
For many concurrent agent sessions, run setup directly from a global installation
to avoid keeping a separate npm launcher process for each MCP connection:
```bash
npm install --global rea-agents
rea setup
```
Review the plan, approve the selected client changes, then restart those clients.
This registers the installed entrypoint directly; installing the global package
alone does not replace existing `npx` registrations. Each client still has its own
REA process and analysis state. Direct registrations follow the installed CLI;
use `rea update` to update it. Running setup through `npx` again selects the pinned
package-runner command. Do not register paths inside npm's temporary package cache.
The optional curl wrapper installs only the global npm package:
```bash
-11
View File
@@ -68,17 +68,6 @@ The node vocabulary covers:
- runtime script instance;
- an explicit `unknown` kind when classification is not justified.
Static network endpoints can have `resolution: "partial"` when the analyzer
recognizes a request call but cannot resolve its target to one exact value.
The observation's `value` then preserves the source expression, and its
evidence points to the call site. Partial and exact endpoints have distinct
identities even when their displayed values match. Partial identities also retain
the source site: matching expression text at different sites does not establish
the same runtime target. This records observed source syntax; it does not
establish that the call ran or contacted that endpoint.
Graph coverage describes the analyzed artifact scope and resource limits, not
runtime execution. A partial target alone does not imply omitted source.
The directed relation vocabulary is `contains`, `loads`, `imports`, `maps_to`,
`exposes`, `sends`, `invokes`, `handles`, `calls`, `persists_to`, `observed_as`,
and `changed_from`. Provider names are deliberately absent from both
+2 -113
View File
@@ -80,65 +80,6 @@ incompletely analyzed application. CLI `inspect-analysis-view` reads the same
request from a JSON file; portable input uses `source.kind: "inline"` with the
complete parent Evidence.
## Retained file and native facts
Read metadata, native inventory and unavailable processing scopes directly from
retained application observations:
```json
{
"source": {
"kind": "retained-evidence",
"evidence_id": "ev_ACTUAL_PARENT_ID"
},
"view": {
"kind": "javascript-facts",
"where": { "paths": ["package.json", "build/Release/addon.node"] },
"property_keys": [
"name",
"version",
"bytes",
"availability",
"operation",
"analysis_status"
],
"offset": 0,
"limit": 32
}
}
```
Each row preserves its node identity, observation ID, source-map reference and
original Evidence, including location, authority, confidence, coverage and
limitations. `property_keys` selects exact retained property names; absent keys
stay omitted and retained null values stay null. An empty list requests only
identity/provenance. Observations are not merged into a single asserted fact.
When property names are unknown, opt into
`include_available_property_keys: true`. Each returned row then lists its
original `available_property_keys`, without unselected values; combine this with
`property_keys: []` for discovery only. The default is false, so known-field
reads do not pay for field inventories. Keep node/observation IDs paired when
combining rows; location-related observations need not belong to the same node.
`where.paths` compares exact Evidence `artifact-path` values or `source-range`
sources. Empty query strings remain valid selectors, though current location
contracts require nonempty paths/sources. It does not inspect display labels or a
property named `path`, normalize URLs, or reopen files. Omission includes unknown
locations; an empty list matches none. Optional `where.kinds` filters original
node kinds, with an empty list likewise matching none. Multiple locations of
shared content remain separate rows with the same canonical node identity.
These rows select application-graph observations. Semantic relationships and
semantic unknown records remain in complete parent Evidence and trace tools.
Rows follow retained node/observation order. The default offset/limit is 0/64;
follow `coverage.next_offset`. Page totals count matching retained observations,
while `source_coverage` preserves caller selection and application/semantic
partial or unknown states. An empty or exhausted page does not establish absence
outside examined coverage. Complete source Evidence remains available through
export. CLI `inspect-analysis-view` and portable Evidence use the same contract
and application implementation as MCP.
## Feature tracing
Select one literal seed kind: node ID, route, string, API, IPC channel, module,
@@ -154,14 +95,6 @@ matches exactly. Otherwise the result recommends provider-neutral follow-up
tools and reports `requires-provider-analysis`; it never starts or switches a
provider implicitly.
A handoff requires the add-on's exact content identity. Unavailable unpacked
companions remain visible in the trace graph with their canonical path,
availability and container-backed Evidence. They yield no actionable handoff
until their bytes are available and the application is reanalyzed; the archive
digest does not identify the missing add-on. An empty handoff list does not prove
that the trace contains no native components. Source partial coverage remains
visible independently of handoff eligibility.
## Semantic relation tracing
`trace_javascript_semantics` queries the authenticated companion graph without
@@ -184,17 +117,6 @@ registrations/removals and dispatch, Node timers and cancellation handles, async
defaults, request construction and response consumers, parse/coercion/
validation boundaries, and built-in resource acquisition/release.
Local callback candidates do not establish a complete target set when a
conditional write may leave a parameter, catch binding, or uninitialized
variable unchanged. These calls retain candidate edges and dynamic uncertainty;
default traces remain ambiguous with partial coverage. Opt into
`include_ambiguous_dynamic_edges` to traverse the candidates. Proven preceding
unconditional assignments, including writes dominating a read in the same
conditional block, can resolve a target; later writes do not replace an
earlier read or captured alias. Unproved ordering across branches or function
activations remains conservative. Returned-reference effects use the same
read-position facts as call resolution.
Mutation tracking covers explicit member assignments, updates, deletion, and
loop assignment targets, including the supported local aliases and shared
nested references. Calls conservatively invalidate exposed mutable references;
@@ -244,13 +166,8 @@ graph and read literal values from `properties.value`, rather than decoding
role keys or labels. Previously stored graphs and their original IDs remain
valid inputs.
Endpoint observations keep their value in `properties.value`. When
`properties.resolution` is `partial`, that value is the unresolved source
expression, with an identity distinct from an exact endpoint of the same text.
Semantic request and response nodes keep their endpoint in `properties.endpoint`. Endpoint
lookup identities are preserved independently of the primitive-value lattice's
byte budget. An oversized normalized literal can become unknown while the same
string remains an exact endpoint for tracing and comparison. Endpoint
Endpoint nodes keep the exact endpoint in each observation's `properties.value`;
semantic request and response nodes keep it in `properties.endpoint`. Endpoint
identity keys use `value-sha256:<digest>` over the canonical JSON string when
that is shorter, or when the original value starts with the reserved digest
prefix. Other short endpoint keys remain unchanged. Endpoint labels use the
@@ -288,27 +205,6 @@ and the result includes its basis, candidates, changed dimensions, Evidence
links, limitations, and a `changed_from` graph containing all compared nodes,
their observations, and relationships.
A matched pair whose only differing dimension is `location` counts as
`unchanged` when both input graphs have complete coverage and its neighboring
relationship identities are resolved. This includes an
identical module shifted by an earlier bundle edit and a named IPC channel
observed at a new offset. The item still reports `dimensions: ["location"]`
and both node IDs; the graph retains both original observations and coordinates.
Content, property, and complete relationship differences still count as
`changed`. With incomplete coverage, relocation alone remains `unknown` and
retains the location and coverage dimensions. Matching confidence is unchanged:
an inferred pair is not promoted to exact identity by this classification.
Complete inventory does not resolve ambiguous or unmatched relationship targets.
A matched module with identical bytes can therefore remain `unknown` when a
neighbor, including its containing chunk, has no cross-version match. The item
retains its exact content match, coordinates, candidate inventory, and an explicit
relationship-identity limitation. `coverage` is added to its dimensions only for
incomplete inventory. Definite content, property, or complete topology differences
remain `changed` while retaining any separate relationship uncertainty.
An unknown item with no observed content, property, or relationship difference
does not emit a `changed_from` edge; its pairing and uncertainty remain in the item.
One-sided absence is `added` or `removed` only when the opposite input graph has
complete coverage. With partial, unavailable, or truncated input, the same
condition is `unknown`. The comparison retains every classified item and
@@ -352,13 +248,6 @@ Direct return expressions, including expression-bodied arrows, are evaluated
through an execution-free value lattice. Literal object fields and direct
return sites are represented in the result. Calls, dynamic spreads, computed
keys, and parser recovery remain partial or unknown.
Rebound values are evaluated at their read position: saving an incoming parameter
before a later assignment preserves caller-dependent uncertainty, while a proven
preceding assignment can supply a constant. Unresolved ordering remains unknown.
Supported reads within object and array literals follow left-to-right evaluation;
an unproved relative order remains unknown. A later write in a separate conditional
block can still leave an earlier capture unknown because ordering across those
blocks is not proven.
Objects and arrays passed to calls, constructors, or tagged templates, used
as method receivers, or stored through property targets are not assumed
unchanged afterward. Property stores conservatively retain reference escape
+12 -99
View File
@@ -182,18 +182,6 @@ 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.
Per-file gaps identify the applicable processing phase: JavaScript source analysis
uses AST authority, while package/JSON, HTML-reference and source-map processing
use artifact-byte authority. File-analysis interruption gaps carry `analysis_status`:
`interrupted` means the phase was entered (including source-worker startup),
and `not-started` means interruption prevented that phase from beginning.
Neither state establishes that parsing completed. Remaining parsers are not run
after interruption just to populate a result.
Native add-ons remain metadata-only and acquire no JavaScript parse or analysis
gap. This also applies when their paths are outside `source_paths`; their inventory
and caller selection remain available without implying applicable AST work.
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)
@@ -311,25 +299,13 @@ suffix. Utility calls such as `useUtils().invoice.list.fetch()`, `useQueries`,
and links whose callee was renamed by a minifier are not recognized.
Each recovered bundle module retains the exact factory-source digest. A complete
bounded AST also receives a `babel-ast-v3` structural fingerprint. It ignores
ordinary identifier spellings while retaining literal and directive values,
operators, fixed property names, and selected syntax flags such as computed
keys, declaration kind, function async/generator state, update-expression
prefix, method kind, and class static state. Local names used in computed keys
remain rename-resistant; private member names are also ignored while their
method kind and static state remain represented.
This fingerprint is structural evidence for candidate matching, not proof that
two modules behave equivalently. Its scope follows the AST facts listed above;
unrepresented syntax can still collide. The exact source digest remains
available to show byte-level change, and comparison reports content changes even
when structural matching succeeds.
Version comparison includes the algorithm in its structural matching key.
Retained `babel-ast-v1` results can still match other v1 results, and v2 results
can still match v2 results, but v1/v2 results cannot structurally match v3
results. Other matching tiers remain available across algorithm versions.
Re-analyze both snapshots to compare using the v3 rules.
bounded AST also receives a `babel-ast-v2` structural fingerprint that ignores
ordinary identifier names while retaining syntax, literals, operators, object
keys, and member properties. Computed member identifiers retain their access
syntax without treating a local variable's spelling as a fixed property; template
literal contents remain part of the fingerprint. Version comparison keeps the
algorithm in its matching key, so retained `babel-ast-v1` fingerprints cannot match
these new fingerprints. Re-analyze both snapshots to compare their new structure.
If fingerprint construction reaches its structural
bound, the fingerprint is unavailable and its status is `truncated`; a bounded
prefix is never presented as a complete stable fingerprint.
@@ -350,17 +326,6 @@ substitute version-dependent Electron defaults for omitted `webPreferences`.
Unresolved option objects, bridge keys, API objects, and IPC channel expressions
remain unknown and make coverage partial.
BrowserWindow options and `webPreferences` can follow local `const` aliases
whose initialization precedes the use. The shared lexical and mutation index
checks the selected `webPreferences` path, so an unrelated `options.icon` write
does not discard these facts. Reassignment, relevant writes, prior escapes,
ambiguous initialization, and unresolved spreads remain unknown. The binding
association is an inference: the window observation retains the constructor
location and `resolution_sources` identifies the original object literals in
the same artifact. Inline option syntax keeps its observed Evidence. This
does not execute code or establish runtime configuration; popup overrides from
`setWindowOpenHandler` are not covered by this constant-options resolution.
Recognized literal module-table bootstraps also support bounded lexical
substitution through module exports, import helper bodies, local wrapper calls,
returned closures, object spreads, and callback parameters. Recovered Electron
@@ -374,29 +339,6 @@ conditions retain both return branches, including fallthrough. Short-circuit
selection distinguishes truthiness from nullishness; uncertain `??` paths
retain a nullish guard rather than a falsy guard.
Recognized module factories retain a separate initialization boundary for each
reachable return and for fallthrough. A conditional early return does not hide
later exports on the continuing path; exports and captured initializers after a
definite exit remain unavailable. Fallthrough candidates retain their branch
predicates. Exports shared by the complete set of proven exits also retain
unconditional facts. Their shared view excludes later overwrites and bounds
captured initializers by the earliest completion; branch-dependent facts keep
their predicates. Incomplete or additionally guarded exit sets cannot use that
proof. Completed factory control flow is reused within that analysis only.
Guarded main-process registrations remain candidate paths even with empty
callbacks; they do not become unconditional IPC summary facts.
Factory guards read export writes at their source position. Destructured and
spread snapshots retain their capture position rather than reading later writes.
An unproven namespace read boundary remains unknown.
Completed factory environments preserve their `exports` and `module.exports`
alias identity when a namespace escapes through an export or returned closure.
Synchronous helper calls retain the caller's factory activation and read point;
lexical captures and executing callers remain separate facts.
Async calls retain their truthy Promise identity until an explicit `await`;
generator calls produce iterators without evaluating their bodies. Iterator
advancement and Promise/iterator members remain explicitly unresolved. Awaited
function values retain their source origins and captured initialization bounds.
These paths appear as contextual `javascript-expression` nodes. An exact `api`
seed such as `desktop.copy` can trace an exposed member through a unique IPC
pairing to an external API call. `addListener` is normalized to `on`. Semantic
@@ -460,13 +402,10 @@ For `.node` bindings, member names mean “requested by JavaScript syntax.” A
resolved add-on path does not convert them into verified native exports. Native
symbol verification remains a separate deep-analysis claim.
Exact endpoint values preserve useful local diagnostics, including query values
and fragments, while removing URL username/password credentials when the value
parses as a URL. When a recognized request target cannot be resolved exactly,
the endpoint's partial resolution retains the original source expression with
its call-site provenance. This does not establish that the request executed.
Artifact paths, digests, parse locations, and analysis metadata remain
actionable because REA is local-only.
Endpoint observations preserve useful local diagnostics, including query values
and fragments, while removing only URL username/password credentials. Artifact
paths, digests, parse locations, and analysis metadata remain actionable
because REA is local-only.
## Safety boundary
@@ -498,18 +437,7 @@ retained candidate strings and temporary canonical-key serialization. This is
an in-memory semantic allocation bound independent of CLI or MCP transport
budgets. Source literal bytes remain in the parsed source and artifact evidence;
when a normalized semantic value exceeds the bound, its value is unknown and
coverage is partial. Direct string literals, cooked templates without
substitutions, and derived strings all use this normalization boundary. A
single exact primitive is validated without allocating deduplication or sort
state or serializing a canonical key. Configuration defaults use the same
normalizer; limited defaults retain `value_resource_limit` and an anchored
resource-limit unknown. Known null, false, zero, and empty-string defaults stay
exact. This primitive-value bound does not truncate lookup identities such as
source paths, field names or request endpoints. Full endpoint properties remain
available for endpoint queries, tracing and comparison. Each analysis records encountered limit classifications independently of
later projections: a selected healthy sibling can remain exact while whole-file
coverage reports the encountered bound. Projection preserves limiting values
from the shared property-slot owner. Expression
coverage is partial. Expression
evaluation and provenance walks stop after 256 nested levels. Union products
and string lengths are checked before allocating combinations or concatenated
strings. When a boundary is reached, the value stays unknown, semantic coverage
@@ -586,21 +514,6 @@ not bypass worker heap, execution deadline or parent result admission. Truncated
coverage reports both effective node ceilings; omitted relationships remain
unknown.
Unknown records have independent defaults of 100000 across the application and
20000 per source. Select `max_semantic_unknowns` and
`max_semantic_unknowns_per_file` (CLI: `--max-semantic-unknowns` and
`--max-semantic-unknowns-per-file`), each from 1 to 1000000. The parent offers the
remaining capacity to the worker, and rejects excess records before adoption.
Unknown admission happens before canonical identity and provenance construction.
When capacity is exhausted, coverage is partial and truncated and names both
effective unknown ceilings. `coverage.omitted_unknown_occurrences` counts examined
emission occurrences by family and reason, including repeated emissions. It does
not claim distinct discarded identities or count frontiers in unexamined source.
Omitted unknown provenance and IDs are not retained. Existing source, node,
execution and memory limits continue to determine examined coverage. Raising only
a node capacity does not raise the unknown capacity. Graphs without unknown
omissions omit this optional coverage field, preserving their existing identities.
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
+2 -5
View File
@@ -133,11 +133,8 @@ Each operation uses one worker, a 1 GiB address-space ceiling and a 120-second
deadline; it accepts up to 64 MiB of total input across all selected files and
128 MiB/10000 entries of staged
output, with 8 MiB per diagnostic/report stream. Exceeding a limit is an explicit
failure with rollback. Selected inputs beyond the total input allowance return a
non-retryable `resource_constraint` with `resource: "file-size"` and
`reported_limits.maximum_input_bytes`/`remaining_input_bytes`; input that is not
valid UTF-8 is an `invalid_format` request issue. These limits apply per
operation and do not claim aggregate host containment across concurrent callers.
failure with rollback. These limits apply per operation and do not claim aggregate
host containment across concurrent callers.
See [testing.md](testing.md#javascript-source-recovery) for the focused real
Wakaru CLI/MCP lane and its source-owned compiler fixtures. Other host platforms
+1 -3
View File
@@ -109,9 +109,7 @@ The direct observations are:
- `Runtime.executionContextCreated`,
`Runtime.executionContextDestroyed`, and
`Runtime.executionContextsCleared`, establishing context lifecycle within
the capture window. A created or destroyed event whose context ID is
missing or not a safe integer adds no context record; it is retained only
as a count reported in `unknowns`.
the capture window.
The Inspector protocol does not directly expose require/import caller edges,
EventEmitter emissions or listener invocation, Electron IPC messages or
-1
View File
@@ -52,7 +52,6 @@ All four are read-only with respect to the target file; only `open_jeb_project`
- The engine caps `list_units` pages at 100; a full page is reported as `coverage: "partial"` because more units may exist. An empty remainder is `complete` only when fewer units than requested were returned.
- When `decompile_jeb_item` omits `unit_path`, the engine implicitly selects the project's first code unit; REA reports `unit_path: null` and a limitation instead of guessing the effective unit.
- Engine refusals (`success: false` envelopes) are preserved as unsupported-target errors carrying the engine's own message, for example a nonexistent item address.
- Successfully parsed client information is reused for the lifetime of the MCP connection, including when the engine omits its version. Explicit client inspection and availability probes refresh it.
- An unreachable endpoint is a provider-availability failure with recovery guidance; REA does not retry or spawn the engine.
Real-engine verification lives in the JEB lane described in [testing.md](testing.md); mock transport tests do not establish real-engine compatibility.
+3 -24
View File
@@ -22,8 +22,6 @@ Select it explicitly with `--provider kuna`, MCP's `open_binary.provider_id: "ku
| `REA_KUNA_TIMEOUT_MS` | 120 s | Deadline for one single-function decompile, and for the inventory run REA makes when the export ends without one. |
| `REA_KUNA_JOBS` | 1 | `decompile-project --jobs`. 1 is Kuna's reference answer; more jobs finish sooner but lose callee-first prototypes, and change about 40–60% of function bodies on the measured binaries. |
A single-function decompile, inventory, string, graph or xref run that exceeds its deadline fails as `provider_timeout`, naming the setting that owns the deadline and that raising it takes a restart. A project export that exceeds `REA_KUNA_PROJECT_TIMEOUT_MS` is an export failure instead: requests that need the export report `capability_unavailable` with the export's own retry guidance.
Windows is not supported yet. Supported targets are ELF and thin Mach-O executables for x86-64, AArch64 and ARM; PE and universal Mach-O are rejected with a typed reason.
## What Kuna answers
@@ -50,7 +48,6 @@ The first text or assembly request in a session looks for this target's export i
- REA starts `kuna decompile-project` in the background on a private copy of the target.
- Meanwhile, pseudocode comes from one `kuna decompile --addr` run. Name and address lookups, and listings, use the inventory the export takes with `kuna functions --json` before it decompiles. The session runs `kuna functions` itself, under `REA_KUNA_TIMEOUT_MS`, only when no export is building (an inventory-only request does not start one) or the export ends without an inventory.
- Requests for the same function share one run; it stops when its last waiting request is cancelled. Each run analyzes the whole image again in its own process, so one REA process runs at most as many at once as the host has cores beyond `REA_KUNA_JOBS` (at least one). Further requests wait in order, and a waiting request is answered from the export if it finishes first. A run whose stop REA cannot prove keeps its slot until `close_binary` proves it stopped.
- The session keeps each completed single-function text, up to 16 MiB in all with the least recently used dropped first, and answers repeats from it until the export can. After a failed export that lasts for the session.
- Assembly and data names wait for the export; progress notifications report the wait every ten seconds. A session does not rebuild a failed export: requests that need it fail with `retryable: false`, the export's failure, its captured Kuna output and what to change before reopening the target. A setting such as `REA_KUNA_PROJECT_TIMEOUT_MS` or `REA_KUNA_JOBS` is read when REA starts, so changing it also needs a restart. Pseudocode keeps using single-function runs.
- A single-function answer says so in its limitations. It lacks the export's whole-program prototypes, so a later request can return different text for the same function.
@@ -66,11 +63,11 @@ Single-function subprocess output and each cached source facet share a 16 MiB bu
## Strings
`list_strings` and `search_strings` share one lazy `kuna strings --json --encoding all --min-length 5 --termination any --no-xrefs` scan of the digest-checked private input. Skipping references avoids program lifting, a call graph and a C export. REA validates the input, scan policy, every row and the total before caching any facts. Encoding, character count, byte length and terminator facts must agree; supplementary UTF-8 characters count as Unicode scalars. Malformed output is an error, not an empty search. REA parses the JSON as Kuna writes it instead of buffering it, so the scan has no fixed size: Kuna writes about 290 bytes per row, 31 MB for a 20 MB Ghostty binary and 179 MB (611k rows) for an arm64 Firefox `XUL`. Rows are validated one at a time, and the first contradiction stops Kuna. Text REA does not keep is dropped unassembled; kept text and retained rows are admitted against the REA process's live heap headroom as they arrive; a refusal is a `memory` resource constraint with `retryable: false`, and closing other targets or starting REA with a larger Node.js heap makes room. String scans use the whole-program `REA_KUNA_PROJECT_TIMEOUT_MS` deadline; `REA_KUNA_TIMEOUT_MS` applies to single-function decompilation. The parsed inventory belongs to one selected target/executable profile and expires on session close; Kuna diagnostics beyond their 8 MiB buffer are retained as a failure until close, while other failures are not cached.
`list_strings` and `search_strings` share one lazy `kuna strings --json --encoding all --min-length 5 --termination any --no-xrefs` scan of the digest-checked private input. Skipping references avoids program lifting, a call graph and a C export. REA validates the input, scan policy, every row and the total before caching any facts. Encoding, character count, byte length and terminator facts must agree; supplementary UTF-8 characters count as Unicode scalars. Malformed or oversized output is an error, not an empty search. JSON admits at most 16 MiB before parsing. String scans use the whole-program `REA_KUNA_PROJECT_TIMEOUT_MS` deadline; `REA_KUNA_TIMEOUT_MS` applies to single-function decompilation. The parsed inventory belongs to one selected target/executable profile and expires on session close; deterministic output-buffer failures are retained until close, while other failures are not cached.
Results keep exact u64 virtual addresses, decoded text, native encoding, terminator status and byte length including any terminator. Kuna scans mapped sections or segments for runs of at least five characters; unterminated fragments can include instruction bytes. `all` includes ASCII, UTF-8 and the engine's Latin-range UTF-16LE reading. Other text, including short strings, non-Latin wide text and UTF-16BE, can remain undiscovered. An empty result does not prove absence.
Use `search_strings` for the matching rows or `list_strings` with an exact address for that location. The validated inventory is sorted by numeric address and encoding. Once cached, exact-address reads use binary search and return every encoding at that address without scanning the full inventory or retaining another lookup index. Literal and regex matching run in REA, preserving the existing case and ECMAScript Unicode semantics instead of substituting Kuna's different regex dialect. Procedure and string regex queries share one worker slot per session. Input projections are materialized only after admission, so queued queries retain no per-query inventory arrays. Close cancels and drains matching. Native metadata queries also share one admission slot, including references; a failed stop retains admission until cleanup is proven.
Use `search_strings` for the matching rows or `list_strings` with an exact address for that location. Literal and regex matching run in REA, preserving the existing case and ECMAScript Unicode semantics instead of substituting Kuna's different regex dialect. Procedure and string regex queries share one worker slot per session. Input projections are materialized only after admission, so queued queries retain no per-query inventory arrays. Close cancels and drains matching. Native metadata queries also share one admission slot, including references; a failed stop retains admission until cleanup is proven.
`raw_result.strings` reports the source JSON digest/size, scanned scope, extraction policy, complete inventory count and selected count without copying unrequested text into the answer. Omit the address from `list_strings` to retrieve the complete inventory as Evidence; normal session retention and bundle export apply, including transport-capacity errors for oversized inline replies. These operations preserve their complete-result contracts and do not add paging. Function-referenced string facets in `analyze_function` remain unavailable; call `xrefs` explicitly when references to one returned string are needed.
@@ -80,28 +77,10 @@ The first call query runs `kuna decompile-graph --functions ''`, admitting no C
`xrefs` runs native `xrefs --to ADDRESS --json` on demand. Kuna unifies forwarding aliases and suppresses edges internal to their class; REA filters to the requested address and records the excluded-row count. Duplicate source sites appear once. An empty result cannot establish the absence of references. Addresses are explicit u64 values or exact, unambiguous procedure names; Kuna has no cursor.
REA parses the graph as Kuna writes it, like the string scan, so the graph has no fixed size: a 53 MB Raycast binary produces 157 MB (180k functions, 773k edges), which REA retains in about 93 MB after a whole-program walk of about a minute. Unrequested bodies are refused before any of their text is assembled, and edges are indexed as they arrive, so retained rows and their indexes are admitted against live heap headroom. Xref JSON admits at most 16 MiB before parsing. Output or Kuna diagnostics beyond a buffer are reported as a `memory` resource constraint with `retryable: false`, because the same target and executable produce the same output. The session remembers such a graph failure, so later call queries fail at once instead of repeating the whole-program walk. The graph is cached for the selected target and executable profile within one session. Xref reuse is an LRU charged by source bytes plus metadata, limited to 16 MiB and 128 entries; at most eight distinct native xref queries may be pending. Reference commands run one at a time per session and share the provider's foreground budget with single-function decompiles. An unproven process stop retains its admission slots until cleanup succeeds. Concurrent callers share work, individual cancellation releases only that waiter, and the last departing waiter cancels its producer and receives any unproven cleanup. Session close aborts and drains producers, releases parsed caches and retries any retained process/file cleanup.
Graph JSON admits at most 32 MiB before parsing; xref JSON at most 16 MiB. A large image can exceed the graph budget: an arm64 Firefox `XUL` (404k functions) does, while a 14 MB Sublime Text binary produced 31.8 MB. Output beyond a buffer is reported as a `memory` resource constraint with `retryable: false`, because the same target and executable produce the same output. The session remembers a graph that overflowed, so later call queries fail at once instead of repeating the whole-program walk. The graph is cached for the selected target and executable profile within one session. Xref reuse is an LRU charged by source bytes plus metadata, limited to 16 MiB and 128 entries; at most eight distinct native xref queries may be pending. Reference commands run one at a time per session and share the provider's foreground budget with single-function decompiles. An unproven process stop retains its admission slots until cleanup succeeds. Concurrent callers share work, individual cancellation releases only that waiter, and the last departing waiter cancels its producer and receives any unproven cleanup. Session close aborts and drains producers, releases parsed caches and retries any retained process/file cleanup.
Evidence includes only selected addresses or dossier neighbors, the producing JSON's SHA-256/byte count, coverage and relevant function facts; unrequested program-wide JSON and instruction text are omitted. Reference caches are in memory and expire on close: a fresh CLI process or MCP server rebuilds them. A first call query therefore costs a whole-program reference walk even when a C export is warm. These operations do not establish full Ghidra/IDA feature parity.
Failures from shared installation or inventory work identify the operation the
caller requested. `diagnostics.producer_operation` retains the internal producer
name when it differs. Caller-specific failures keep the producer's typed outcome,
captured output, partial facts and live cleanup dependencies; cleanup retry
updates every projection rather than preserving an independent stale marker.
Installation acquisition is shared, with independently cancellable caller waits.
The final departing caller stops the probe and joins its cleanup; session close
also stops and joins acquisition. A cleanly cancelled acquisition can be retried,
while a retained cleanup failure blocks replacement until its owner is closed.
Shared string and reference queries preserve caller cancellation reasons and
join the final departing caller's command cleanup. A command cleanup error keeps
its typed primary failure and captured output. Its live resource list follows
both process and workspace ownership: proving process exit does not prove that
the private workspace was removed, and retry updates earlier caller errors.
If workspace setup fails, an unsuccessful rollback retains the original target
or read failure together with its cleanup owner. Replacement stays blocked until
that rollback is resolved; a clean rollback permits another setup attempt.
## Provenance and limitations
- Addresses and bytes are Kuna's observations of the image. Procedure entries and extents are its derivations: extents are upper bounds clipped at the next entry, and Kuna can split one function at an entry its own analysis infers. Pseudocode is its reconstruction, never original source.
+3 -74
View File
@@ -393,31 +393,15 @@ concrete version, selection source, and complete analysis profile through
choices return typed selection details. A selected provider is never replaced
automatically after a runtime failure.
Each provider client receives `binary_session.analysis_run.run_id` before any
provider startup, including clients whose startup fails. `process_lineage` is
`not_observed` until a dynamic provider starts, then becomes `snapshots` with
every started provider's identity
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.
`binary_session.cleanup_pending` reports whether the session retains a provider
client, session file resource, or provider-candidate resource whose cleanup
has not succeeded. It can be true with
`open: false`; target retirement does not establish resource release. For a
retained provider client, health, activity, and lineage remain available under
its original `analysis_run.run_id` where the provider supplies them.
Successful provider cleanup clears the retained run;
a replacement client receives a fresh run ID. Follow the cleanup error's
reported resources and recovery action before reopening; a missing health
observation does not establish an idle provider.
File cleanup can also remain after snapshot publication or after profile
inspection fails or is cancelled before a provider client exists. If no client
remains, no provider run or health observation is available; follow the cleanup
error's reported resources.
## Progress and cancellation
REA accepts ordinary `tools/call` progress tokens. The numeric `progress` counts
@@ -435,9 +419,6 @@ 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.
Once those owners confirm cleanup, composed failures recover their original
typed primary outcome and recovery guidance. Historical composition diagnostics
remain in `details.cleanup_history`, separate from the primary diagnostics.
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.
@@ -447,25 +428,12 @@ 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.
For these tools, cancellation observed during result finalization or owned
cleanup also returns typed cancellation with the available observations.
A normal target exit does not establish request completion. Incomplete cleanup
still takes precedence and retains its resource diagnostics.
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.
Bundle recovery requires a recorded Evidence ID. Some provider errors carry
typed raw observations in `details.partial_observation` instead of Evidence.
Those raw observations are not recorded in the Evidence bundle. If the SDK
suppresses the error reply after client cancellation, Evidence tools cannot
recover them. An empty bundle does not prove that no partial work or side
effect occurred; output receipts and cleanup observations remain distinct.
The broader retention decision is tracked in
[#4276](https://github.com/morluto/rea/issues/4276).
`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
@@ -524,12 +492,6 @@ analysis runtime. These failures are reported at the operation that needs
them. A configured provider or an endpoint alone does not establish that a
target is supported.
Composite Hopper regex searches report failures against the accepted
`search_strings` or `search_procedures` operation. The underlying inventory
method and request ID remain in `details.diagnostics.provider_request`, with
the bridge error code and diagnostic type when available. Reattribution
preserves the failure class, captured output, and live cleanup ownership.
Evidence bundles, snapshots, and extraction use the paths and output behavior
declared by their tools. Artifact extraction materializes the selected regular
files into a fresh REA-chosen temporary directory and reports its path.
@@ -540,25 +502,6 @@ temporary source files are declared as `launchesProcess` and `writesFilesystem`,
including for a single JavaScript source. This internal analysis does not execute
the supplied application code.
## Static Ghidra bytes and source mappings
`read_bytes` returns initialized analysis memory, including loader fixups, rather
than live process memory. Check `returned_bytes` and `complete` before decoding:
reads stop at unmapped or uninitialized bytes. Missing bytes are unknown; do not
pad an incomplete read with zeros and treat the result as an observation.
`list_segments` reports memory-block initialization and address-space facts.
`address_to_file_offset` maps one address through the provider's source-byte
mapping. A successful start-address mapping does not establish that an entire
range is contiguous in the original file, or that its bytes equal analysis
memory after loader fixups. Uninitialized, missing, and ambiguous mappings fail
explicitly; preserve the reported failure rather than guessing an offset.
For constructor-populated pointer or resource slots, a static zero is not proof
of a later null value. Inspect the slot's `xrefs` and the writer's assembly or
pseudocode, retaining uncertainty about execution order and runtime values.
These operations inspect static evidence and do not execute the target.
## Ghidra first-query deadlines and recovery
A successful MCP initialize handshake establishes the REA connection.
@@ -751,20 +694,6 @@ 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.
Boolean literal constraints in input schemas are relaxed only in this
advertisement. For example, a boolean `const` is presented as `type: boolean`;
an affected `not` is omitted, conditional predicates and their branches are
omitted together, pure boolean-literal `oneOf` branches collapse to a boolean,
and other affected `oneOf` branches are presented as `anyOf` to retain branch
guidance without making overlapping widened branches reject inputs.
This can make the advertised schema accept inputs the canonical contract
rejects. The MCP handler still validates every call with the canonical
contract. The Gemini CLI verifier checks the outgoing
`parametersJsonSchema` and canonical contract examples against that declaration
using a loopback model fixture; it does not establish live Google API or
OpenCode client behavior. Set `REA_VERIFY_GEMINI_SCHEMA_PROFILE=compact` to
verify the compact advertisement through the same client boundary.
### Compact input schema profile
Some function-calling providers reject a request while any single tool's
+3 -82
View File
@@ -261,23 +261,6 @@ Mach-O fixtures check each case against source-owned return values.
## Static inspection
`inspect_plist.format` describes the selected source, not plutil's conversion
format. Sources explicitly identified as XML, binary or JSON retain those
labels. For generic text, a bounded source-prefix probe recognizes leading XML
markup, including UTF-8 and BOM-marked UTF-16 sources. Unidentified text and
OpenStep plists, including a data-only value such as `<deadbeef>`, report
`unknown` even when plutil decodes their values through an XML conversion.
A plist explicitly selected through the path input or as the active plist target
reports an unreadable or malformed selection as `invalid_request`. A missing or
unreadable default plist of another target reports `capability_unavailable`.
Permission failures remain `access_denied`; output and cleanup failures retain
their own error categories.
A plist decode refusal includes plutil's diagnostic from either output stream.
`details.captured_output` retains bounded stdout/stderr excerpts, observed byte
totals and exit status. `truncated: true` means those excerpts are incomplete.
`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
@@ -334,16 +317,12 @@ complete observation.
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.
Object `kind` describes the decoded archive value: data, dates and numbers
remain `scalar` when their JSON value uses a `$plist_type` wrapper. An actual
dictionary with the same fields remains `dictionary`.
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. XML key names combine their text and
CDATA segments without trimming or expanding literal CDATA entities. Other
values and the original archive digest are preserved.
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 <app>` reads
compiled storyboard and nib resources into objects, outlets, actions,
connections and controller/class names. A full app graph is often several
@@ -419,10 +398,6 @@ complete observation.
coroutine tables, and inherited overrides, have explicit unsupported or
partial coverage. Other providers retain the
existing symbol-based inventory with its narrower coverage.
Symbols without a reported location remain in that inventory: Swift symbol
`address` and Objective-C `implementation_address` are null. An empty provider
address is retained as `reported_address` in the symbol's evidence, whose
location also remains unknown. Nonempty provider address syntax is preserved.
## Native desktop observation
@@ -439,11 +414,7 @@ decrement scrolling and text-value entry, or bounded waits. No global event
injection is used. Unsupported AX actions fail explicitly. The result preserves
ordered before/after captures and gaps; an action may have occurred before a
post-action capture fails. Application state is left as-is; REA does not attempt
to restore it. Failed or cancelled scenarios return a typed error with the
collected report in `partial_observation`, including ordered step outcomes.
Cancellation preserves the caller's reason and remains observable through helper
cleanup. A later abort does not replace an earlier helper or output failure.
Cleanup failures retain their runtime owner until a confirmed cleanup retry.
to restore it.
Scenarios accept caller-selected action lists and accessibility node counts.
Individual waits cannot exceed the operation's 180-second deadline, and the
@@ -480,11 +451,6 @@ The run ends when the process exits, `max_events` entries are recorded,
Bounded termination reports partial coverage. REA checks process termination
using a launch-time OS start identity; if ownership or cleanup cannot be
verified, the result or error preserves that uncertainty. The result reports:
Launch errors keep the fact that LLDB created a process separate from whether
it remains alive. An exited `SBProcess` is reported as exited only after LLDB
confirms that state; unresolved ownership remains retained for cleanup retry.
Cancellation observed while output and Evidence are finalized returns partial
cancellation Evidence, even if the target has already exited.
- the outcome, exit status and captured stdout/stderr (1 MiB kept per stream
while excess bytes are drained and counted without growing capture files).
@@ -515,11 +481,6 @@ with partial coverage. Available output prefixes remain inline; their byte
counts are observed lower bounds when final drain counters are unavailable.
The original failure classification and cleanup uncertainty remain separate.
An interrupted journal row is ignored with an explicit limitation.
If the trace completed before cancellation or runtime-directory cleanup failed,
the retained observation also keeps its exit status, termination proof, launch
identity, breakpoint results and final stream counters. Those fields remain
absent when the interrupted producer did not report them; partial coverage alone
does not mean that every retained fact is incomplete.
Only entries are observed: return values, floating-point and stack arguments,
and inlined or `objc_direct` calls are not. The target runs with the current
@@ -597,10 +558,6 @@ digests identify the original serialized bytes.
## Keyed archive integer precision
The archive reader observes XML number element types and binary number markers.
XML values and their number facts are interpreted together from the validated
DOM. Hexadecimal `<integer>` text, including an optional sign, retains its value;
`<real>` text and CDATA segments are combined without inferring text from nested
elements. The XML path does not serialize or reparse character references.
Integers beyond the exact range of a JSON number are reported with the original
decimal text as `{ "$plist_type": "integer", "decimal": "<exact digits>" }` when
that source value can be associated unambiguously. Integral real values remain
@@ -620,48 +577,12 @@ Exact and ambiguous value counts describe emitted root/object value instances;
a root and an object may contain the same value. Archive digests identify the
original bytes.
Interface Builder's XML and binary plist archives use the same number metadata
and exact-decimal representation for emitted node attributes. Projection follows
object and connection classification, so archive IDs, UID links and graph counts
keep their meaning. Precision limitations name the source document. Unsafe
integer-literal counts cover the archive, including fields not emitted as node
attributes; exact and ambiguous projection counts cover emitted attribute values.
Integral reals stay numbers, and ambiguous or incompletely observed values retain
explicit precision limitations. Before plist decoding, the existing aggregate
decode budget reserves estimated room for number metadata and attribute
projection; these estimates are not a hard process-memory bound. Native
NIBArchive decoding is unchanged by this plist-specific representation.
Dates are reported as `{ "$plist_type": "date", "iso8601": "<timestamp>" }`. A
date the decoder cannot represent, such as an XML date with a year beyond 9999
or a negative year, is reported as `{ "$plist_type": "date", "iso8601": null }`
with a counted limitation; the rest of the plist or archive is still decoded.
`inspect_plist` and Interface Builder decoding use the same projection.
A negative-zero real is reported as `{ "$plist_type": "real", "value": "-0" }`
because a JSON number cannot carry the sign of zero. `inspect_plist` and
`inspect_keyed_archive` count these values in a limitation, and Interface
Builder node attributes use the same value. Positive zero and integer zero,
including an `<integer>-0</integer>` literal, remain the number `0`.
Known non-finite reals are reported as
`{ "$plist_type": "real", "value": "nan" | "+infinity" | "-infinity" }`.
These are canonical numeric labels, not a claim about original source spelling.
Binary IEEE reals retain NaN versus signed infinity; NaN payload bits and sign
are not represented in the JSON value, and the original bytes remain the source
for those details. XML CFPropertyList literals (`nan`, `+infinity`, `-infinity`,
`infinity`, `inf`, `+inf`, `-inf`, case-insensitively) decode to the same known
values. Case and aliases normalize; original archive bytes retain source text.
XML numeric text whose identity the decoder cannot establish, including
unrecognized non-finite text and finite literals that overflow the numeric
representation, remains `{ "$plist_type": "real", "value": null }` with a
counted limitation. The XML decoder marks these values explicitly before shared
projection, so they cannot be confused with known binary IEEE values.
Incomplete numeric markup retains its existing compatibility behavior described
above. Known non-finite and unresolved numeric values have separate counts.
Native `inspect_plist` uses these same labels for plutil's XML conversion.
## Locate a byte signature
Use `search_bytes` after opening a target with Ghidra to locate a known constant
-5
View File
@@ -58,11 +58,6 @@ tools read that copy, which is hashed again after analysis. Capture metadata and
literal field values are producer observations; address/protocol counts and DNS
associations are derivations. Capture Evidence has historical-reference authority.
`capture_start` and `capture_end` are RFC 3339 UTC instants derived from
`capinfos -S` epoch seconds, retaining all producer fractional digits (up to
nanoseconds). Empty captures, malformed timestamps and instants outside years
0000–9999 remain `null`; host-local timestamps without a zone are not inferred.
Addresses count once per packet, including loopback and nested IP occurrences.
DNS addresses are associated only with one question in the same response packet;
additional records may be included, so this does not prove final resolution.
+1 -3
View File
@@ -425,9 +425,7 @@ results for unaffected dimensions and mark affected dimensions unknown; an
incomplete capture cannot locate the first divergence across all dimensions.
Trace assertions use coverage for the sources they select, so an assertion
about complete raw terminal output need not fail because rendered snapshots
were omitted. A trace difference applies to the dimensions identified by its
diagnostic; unrelated dimensions retain their own comparison, including unknown
coverage. Captures missing `truncation_details` are rejected on import;
were omitted. Captures missing `truncation_details` are rejected on import;
preserve them as historical files and recapture for current comparisons.
`limits.file_bytes` is already the cumulative whole-file hashing budget,
independent of `limits.output_bytes`, which bounds retained terminal content.
+13 -45
View File
@@ -25,31 +25,27 @@ rea inspect-native-load-image /absolute/path/to/ecu.bin --target-format raw-bina
}
```
`architecture` is one of `x86`, `x86_64`, `arm`, `arm64`, `6502`, or `m68k`. `entry_point` is a
`architecture` is one of `x86`, `x86_64`, `arm`, `arm64`, or `6502`. `entry_point` is a
hexadecimal address of the form `0x…`. The complete file is mapped starting at
that address, and Ghidra seeds an `entry` function there before auto-analysis.
ARM and AArch64 entries must be 4-byte aligned; m68k entries must be 2-byte
aligned; x86 and 6502 entries may be byte-aligned.
ARM and AArch64 entries must be 4-byte aligned; x86 and 6502 entries may be byte-aligned.
For 6502, the entry and complete mapped file must fit within `0x0000..0xffff`;
images that cross the 16-bit boundary are rejected before provider startup.
For m68k, the mapping must fit within `0x0..0xffffffff`.
`open_binary` and an open `binary_session` return the canonical `entry_point`
for raw targets so callers can verify the selected mapping directly.
Omitted `format` keeps header-based detection; architecture and entry without
`format=raw-binary` are rejected.
Ghidra imports a private snapshot with `BinaryLoader` and these generic
languages and compiler specifications. Each family has one fixed byte order:
m68k is big-endian and the others are little-endian.
Ghidra imports a private snapshot with `BinaryLoader` and these little-endian
generic languages and compiler specifications:
| architecture | language_id | compiler_spec_id |
| ------------ | --------------------- | ---------------- |
| x86 | `x86:LE:32:default` | `gcc` |
| x86_64 | `x86:LE:64:default` | `gcc` |
| arm | `ARM:LE:32:v7` | `default` |
| arm64 | `AARCH64:LE:64:v8A` | `default` |
| 6502 | `6502:LE:16:default` | `default` |
| m68k | `68000:BE:32:default` | `default` |
| architecture | language_id | compiler_spec_id |
| ------------ | -------------------- | ---------------- |
| x86 | `x86:LE:32:default` | `gcc` |
| x86_64 | `x86:LE:64:default` | `gcc` |
| arm | `ARM:LE:32:v7` | `default` |
| arm64 | `AARCH64:LE:64:v8A` | `default` |
| 6502 | `6502:LE:16:default` | `default` |
Compiler specifications select analysis conventions; they do not identify the
original compiler or ABI of a headerless target. Ghidra's x86 languages do not
@@ -110,40 +106,12 @@ unchanged source bytes and complete runtime cleanup. Windows requires the
matching native addon; the POSIX provider path has not been exercised by the
Windows run.
## Motorola 68000
```bash
rea function /absolute/path/to/image.bin 0x1000 --target-format raw-binary --architecture m68k --entry-point 0x1000 --provider ghidra --json
rea inspect-native-load-image /absolute/path/to/image.bin --target-format raw-binary --architecture m68k --entry-point 0x1000 --provider ghidra --json
```
Select only headerless big-endian 68000-family code with a known, even entry at
file offset 0. Ghidra's `68000:BE:32:default` language decodes the 68040
superset in the 32-bit `ram` address space. Instructions that a real MC68000
would not execute are therefore not rejected, and 68020, 68030, CPU32, and
ColdFire programs are not admitted as those variants. Addresses are not masked
to the MC68000 24-bit bus. Evidence preserves `architecture: "m68k"`, the
selected language, entry, file digest, and verified source mapping. Register and
calling conventions are analysis conventions, not a recovered source ABI.
This lane does not interpret Amiga hunks, Atari ST, or other container headers,
cartridge or console memory maps, or bank switching. REA does not read the
initial stack pointer and reset vector from the first eight bytes; select the
entry explicitly. Windows Ghidra P0 does not admit m68k.
`npm run verify:ghidra:m68k` uses a source-owned 22-byte fixture written as
annotated hex in the verifier, so it needs no assembler. The lane checks real
CLI/MCP load-image parity, mapped bytes, a decoded call, decompilation by address
and file offset, misaligned and out-of-range mappings, unchanged source bytes and
runtime cleanup. It has been run with Ghidra 12.1.4 on macOS; Linux has not been
exercised.
## Limitations
- Headers are not discovered from file bytes. This increment does not guess
load addresses, vector tables, or memory maps.
- Big-endian ARM, Thumb-only, Cortex-M, and other Ghidra processor variants are
unsupported. m68k is the only big-endian family.
- Big-endian, Thumb-only, Cortex-M, and other Ghidra processor variants are
unsupported.
- Reset vectors, memory-mapped I/O, and firmware boot sequences are not
emulated.
- Independent load-image verification covers source identity, mapped file
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · **العربية** · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: هندسة عكسية لأي شيء
@@ -274,7 +274,7 @@ npx rea-agents@latest setup
## سجل النجوم
🎉 **300,000 نجمة على GitHub — شكرًا لكم!**
🎉 **250,000 نجمة على GitHub — شكرًا لكم!**
شكرًا لكل من يستخدم REA، ويبلّغ عن الأخطاء، ويقترح ميزات، ويختبر إصدارات البناء، ويساهم بالإصلاحات.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · **Deutsch** · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: Alles reverse-engineeren
@@ -272,7 +272,7 @@ Melde Sicherheitslücken gemäß [SECURITY.md](../../SECURITY.md).
## Sternverlauf
🎉 **300.000 GitHub-Sterne – vielen Dank!**
🎉 **250.000 GitHub-Sterne – vielen Dank!**
Danke an alle, die REA nutzen, Fehler melden, Funktionswünsche äußern, Builds testen und Fehlerbehebungen beitragen.
+2 -2
View File
@@ -1,6 +1,6 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md) · **Ελληνικά** · [മലയാളം](README_ml.md)
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md) · **Ελληνικά**
# REA: Reverse Engineer Anything
@@ -285,7 +285,7 @@ npx rea-agents@latest setup
## Ιστορικό αστεριών
🎉 **300.000 αστέρια στο GitHub — σας ευχαριστούμε!**
🎉 **250.000 αστέρια στο GitHub — σας ευχαριστούμε!**
Ευχαριστούμε όλους όσοι χρησιμοποιούν το REA, αναφέρουν σφάλματα, ζητούν νέες λειτουργίες, δοκιμάζουν builds και συνεισφέρουν διορθώσεις.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · **Español** · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: Ingeniería inversa de cualquier cosa
@@ -272,7 +272,7 @@ Informa de vulnerabilidades siguiendo [SECURITY.md](../../SECURITY.md).
## Historial de estrellas
🎉 **300.000 estrellas en GitHub: ¡gracias!**
🎉 **250.000 estrellas en GitHub: ¡gracias!**
Gracias a quienes usan REA, informan de errores, solicitan funciones, prueban compilaciones y contribuyen con correcciones.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center" dir="rtl">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · **فارسی** · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: مهندسی معکوس هر چیزی
@@ -257,7 +257,7 @@ npx rea-agents@latest setup
## تاریخچهٔ ستاره‌ها
🎉 **۳۰۰٬۰۰۰ ستارهٔ GitHub — سپاسگزاریم!**
🎉 **۲۵۰٬۰۰۰ ستارهٔ GitHub — سپاسگزاریم!**
از همهٔ کسانی که از REA استفاده می‌کنند، خطاها را گزارش می‌دهند، قابلیت‌های جدید پیشنهاد می‌کنند، buildها را آزمایش می‌کنند و در بهبود پروژه مشارکت دارند سپاسگزاریم.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · **Français** · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA : rétro-ingénierie de tout
@@ -276,7 +276,7 @@ Signalez les vulnérabilités via [SECURITY.md](../../SECURITY.md).
## Historique des étoiles
🎉 **300 000 étoiles GitHub — merci !**
🎉 **250 000 étoiles GitHub — merci !**
Merci à toutes les personnes qui utilisent REA, signalent des bugs, proposent des fonctionnalités, testent les builds et contribuent des correctifs.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · **Bahasa Indonesia** · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: Rekayasa Balik Apa Pun
@@ -297,7 +297,7 @@ Laporkan kerentanan melalui [SECURITY.md](../../SECURITY.md).
## Riwayat Bintang
🎉 **300.000 bintang GitHub, terima kasih!**
🎉 **250.000 bintang GitHub, terima kasih!**
Terima kasih kepada semua orang yang menggunakan REA, melaporkan bug, meminta fitur, menguji build, dan berkontribusi dalam perbaikan.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · **Italiano**
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: Reverse Engineer Anything
@@ -276,7 +276,7 @@ Segnala vulnerabilità tramite [SECURITY.md](../../SECURITY.md).
## Cronologia delle stelle
🎉 **300.000 stelle su GitHub — grazie!**
🎉 **250.000 stelle su GitHub — grazie!**
Grazie a tutti coloro che usano REA, segnalano bug, propongono funzionalità, testano le build e contribuiscono con correzioni.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · **日本語** · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA:あらゆるものをリバースエンジニアリング
@@ -274,7 +274,7 @@ npx rea-agents@latest setup
## スター履歴
🎉 **GitHub スター 300,000 件、ありがとうございます!**
🎉 **GitHub スター 250,000 件、ありがとうございます!**
REA の利用、バグ報告、機能の要望、ビルドのテスト、修正への貢献に感謝します。
+3 -7
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · **한국어** · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: 무엇이든 리버스 엔지니어링
@@ -62,7 +62,7 @@ REA는 에이전트를 분석 도구에 연결해 네이티브 바이너리, Jav
설정 과정은 에이전트에 REA를 등록하고 해당 버전에 맞는 워크플로 지침을 설치합니다. 네이티브 분석에는 기존 Hopper, Ghidra 또는 IDA 설치를 사용할 수 있습니다. 승인하면 설정 과정에서 Hopper를 설치할 수도 있습니다. 정적 JavaScript 분석에는 네이티브 분석 엔진이 필요하지 않습니다.
> <strong>[REA 웹사이트](https://rea.tools/ko/)</strong>에서 설정 방법, 그림으로 설명한 가이드, 실제 사례를 확인하세요.
> **[REA 웹사이트](https://rea.tools/ko/)**에서 설정 방법, 그림으로 설명한 가이드, 실제 사례를 확인하세요.
## 빠른 시작
@@ -283,7 +283,7 @@ npx rea-agents@latest setup
## 스타 기록
🎉 **GitHub 스타 300,000개, 감사합니다!**
🎉 **GitHub 스타 250,000개, 감사합니다!**
REA를 사용하고, 버그를 보고하고, 기능을 요청하고, 빌드를 테스트하고, 수정에 기여해 주신 모든 분께 감사드립니다.
@@ -309,10 +309,6 @@ REA에 도움을 보태 주세요! [issue를 등록](https://github.com/morluto/
개발 환경과 검사 항목은 [CONTRIBUTING.md](../../CONTRIBUTING.md), 검증 절차는 [테스트 가이드](../testing.md), 프로젝트 구조는 [아키텍처 지도](../architecture.mermaid)를 참고하세요.
한국어 번역도 개선할 수 있습니다. 이 README를 수정할 때는 [영문 README](../../README.md)의 명령어, 요구 사항, 분석 범위와 일치하는지 확인하세요. 웹사이트 번역은 `website/locales/ko/messages.po`의 `msgstr` 값을 수정하세요.
웹사이트 번역의 수정 방법, 검사 명령, 로컬 미리보기는 `website/locales/README.md`를 따르세요. 위 기여 문서의 **Translation corrections** 절에서 이 가이드로 이동할 수 있습니다. 명령어, 경로, 자리표시자, 기록된 근거는 그대로 보존하세요. `website/_site/`의 한국어 HTML은 자동 생성되므로 직접 수정하지 마세요.
## 라이선스
[MIT](../../LICENSE)
-325
View File
@@ -1,325 +0,0 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · **മലയാളം**
# REA: എന്തും Reverse Engineer ചെയ്യുക
### Binaries, applications, runtime behavior എന്നിവയുടെ Reverse Engineering-നായി ഒരൊറ്റ MCP.
**നിങ്ങൾക്ക് ഇഷ്ടപ്പെട്ട ഒരു feature കണ്ടോ? അത് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് binary തലത്തിലേക്ക് വരെ മനസ്സിലാക്കൂ.**
[![npm version](https://img.shields.io/npm/v/rea-agents?style=flat-square&color=cb3837)](https://www.npmjs.com/package/rea-agents)
[![MCP tool catalog](https://img.shields.io/badge/MCP-tool_catalog-5c4ee5?style=flat-square)](../mcp-contracts.md#generated-catalog)
[![Node.js requirements](https://img.shields.io/badge/Node.js-requirements-339933?style=flat-square&logo=nodedotjs&logoColor=white)](#what-you-can-analyze)
[![skills.sh](https://skills.sh/b/morluto/rea?style=flat-square)](https://skills.sh/morluto/rea/reverse-engineer-anything)
[![MIT license](https://img.shields.io/badge/license-MIT-f4c430?style=flat-square)](../../LICENSE)
[![Discord](https://img.shields.io/discord/1556595354999332884?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/GkcryMnJDM)
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&amp;utm_medium=badge&amp;utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
**[വെബ്സൈറ്റ്](https://rea.tools/) · [ഗൈഡുകൾ](https://rea.tools/guides/) · [ഉദാഹരണങ്ങൾ](https://rea.tools/showcase/)**
[ദ്രുതാരംഭം](#ദ്രുതാരംഭം) · [REA എങ്ങനെ പ്രവർത്തിക്കുന്നു](#rea-എങ്ങനെ-പ്രവർത്തിക്കുന്നു) · [എന്തൊക്കെ വിശകലനം ചെയ്യാം](#എന്തൊക്കെ-വിശകലനം-ചെയ്യാം) · [ഉദാഹരണങ്ങൾ](#ഉദാഹരണങ്ങൾ) · [പതിവുചോദ്യങ്ങൾ](#പതിവുചോദ്യങ്ങൾ) · [ഡോക്യുമെന്റേഷൻ](#ഡോക്യുമെന്റേഷൻ)
<code>npx rea-agents setup</code>
</div>
> [!IMPORTANT]
> REA ലഭ്യമാക്കേണ്ടത് [morluto/rea](https://github.com/morluto/rea),
> [rea.tools](https://rea.tools/), അല്ലെങ്കിൽ [rea-agents npm package](https://www.npmjs.com/package/rea-agents) എന്നിവയിൽ നിന്നാണ്.
> ഈ ഔദ്യോഗിക ഉറവിടങ്ങളിലെ ഇൻസ്റ്റലേഷൻ, റിലീസ് ലിങ്കുകൾ പിന്തുടരുക. സമാനമായ
> repository പേരോ പകർത്തിയ README-യോ മാത്രം ഒരു download ഔദ്യോഗികമാണെന്ന് ഉറപ്പാക്കുന്നില്ല.
<div align="center">
<br />
<img src="../assets/rea-hopper-analysis.png" alt="ഒരു native binary പരിശോധിക്കുന്നതിനിടെ Hopper-ൽ REA അതിന്റെ analysis bridge ആരംഭിക്കുന്നു" width="1200" />
<br /><br />
<table aria-label="REA community">
<tr>
<td align="center" width="360">
<a href="https://discord.gg/GkcryMnJDM">
<img src="../assets/discord.svg" height="42" alt="Discord" /><br />
<strong>Reverse Engineering കമ്മ്യൂണിറ്റിയിൽ ചേരുക</strong>
</a><br />
<sub>Discord · ചോദ്യോത്തരങ്ങൾ · അനുഭവങ്ങളും കണ്ടെത്തലുകളും പങ്കിടുക</sub>
</td>
</tr>
</table>
<br />
</div>
---
നിങ്ങളുടെ സ്വന്തം product-ൽ ഉൾപ്പെടുത്താൻ ആഗ്രഹിക്കുന്ന ഒരു feature ഏതെങ്കിലും app-ൽ കണ്ടോ? REA ഉപയോഗിച്ച് അത് പരിശോധിക്കാൻ നിങ്ങളുടെ agent-നോട് ആവശ്യപ്പെടുക. source code ഇല്ലാതെയും അതിന് app പരിശോധിക്കാനും feature എങ്ങനെ പ്രവർത്തിക്കുന്നുവെന്ന് വിശദീകരിക്കാനും അതിനുള്ള തെളിവുകൾ കാണിക്കാനും നിങ്ങളുടെ project-നായി അതിന് സമാനമായൊരു പതിപ്പ് നിർമ്മിക്കാനും കഴിയും.
Native binaries, JavaScript, Electron apps, .NET assemblies, websites എന്നിവ പരിശോധിക്കുന്നതിനുള്ള tools-ലേക്ക് REA നിങ്ങളുടെ agent-നെ ബന്ധിപ്പിക്കുന്നു. ഇതേ tools നിങ്ങളുടെ terminal-ൽ നിന്നും ഉപയോഗിക്കാം. വിശകലനം local ആയി നടക്കുന്നു; ഓരോ നിഗമനത്തിനും പിന്നിലെ തെളിവുകളും പരിമിതികളും ഫലങ്ങളിൽ ഉൾപ്പെടുന്നു.
Setup നിങ്ങളുടെ agent-ിൽ REA രജിസ്റ്റർ ചെയ്യുകയും അനുയോജ്യമായ workflow നിർദ്ദേശങ്ങൾ ഇൻസ്റ്റാൾ ചെയ്യുകയും ചെയ്യുന്നു. Native analysis-നായി നിലവിലുള്ള Hopper, Ghidra, അല്ലെങ്കിൽ IDA installation ഉപയോഗിക്കാം; അനുമതി നൽകിയാൽ setup-ന് Hopper ഇൻസ്റ്റാൾ ചെയ്യാനും കഴിയും. Static JavaScript analysis-ന് native analysis engine ആവശ്യമില്ല.
> **[REA വെബ്സൈറ്റ് സന്ദർശിക്കുക](https://rea.tools/)** — setup നിർദ്ദേശങ്ങൾക്കും ചിത്രങ്ങളോടുകൂടിയ ഗൈഡുകൾക്കും യഥാർത്ഥ case study-കൾക്കും.
## ദ്രുതാരംഭം
Linux-ൽ Ghidra, JADX, firmware tool launches, static JavaScript/Electron analysis എന്നിവയ്ക്ക് process ownership പരിശോധിക്കാൻ REA-യുടെ `PATH`-ൽ procps-compatible `ps` ആവശ്യമാണ്. പരിഹാര നടപടികൾ `docs/installation.md`-യിലെ "Linux owned-process prerequisite" എന്ന വിഭാഗത്തിൽ ലഭ്യമാണ്.
### നിങ്ങളുടെ agent സജ്ജമാക്കുക
Node.js-ഉം npm-ഉം ഇൻസ്റ്റാൾ ചെയ്തശേഷം ഈ command പ്രവർത്തിപ്പിക്കുക:
```bash
npx rea-agents setup
```
നിങ്ങൾ ഉപയോഗിക്കുന്ന agents തിരഞ്ഞെടുക്കുക, നിർദ്ദേശിച്ച മാറ്റങ്ങൾ പരിശോധിക്കുക, തുടർന്ന് അവയ്ക്ക് അനുമതി നൽകുക. നിലവിലുള്ള configuration-ന്റെ backup-ുകൾ സൂക്ഷിച്ചുകൊണ്ട് setup, REA-യുടെ MCP server-ഉം അനുയോജ്യമായ workflow നിർദ്ദേശങ്ങളും ചേർക്കും. അതിനുശേഷം നിങ്ങളുടെ agent വീണ്ടും ആരംഭിക്കുക.
Claude Code, Codex, Cursor, Gemini CLI, Grok Build, കൂടാതെ [മറ്റ് agents](../installation.md#supported-agents) എന്നിവയെ setup പിന്തുണയ്ക്കുന്നു. provider configuration-നും manual MCP registration-നും [installation and setup](../installation.md) കാണുക.
### നിങ്ങളുടെ agent-നോട് ആവശ്യപ്പെടുക
```text
Notes app-ൽ search എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് മനസ്സിലാക്കി, അതിനുള്ള തെളിവുകൾ കാണിച്ചുതരികയും എന്റെ project-നായി സമാനമായൊരു feature നിർമ്മിക്കുകയും ചെയ്യുക.
```
`Notes` എന്നതിന് പകരം നിങ്ങൾ പരിശോധിക്കാൻ ആഗ്രഹിക്കുന്ന app-ിന്റെയും മനസ്സിലാക്കേണ്ട feature-ിന്റെയും പേരുകൾ നൽകുക.
### Terminal ഉപയോഗിക്കുക
Extract ചെയ്ത JavaScript/Electron app directory അല്ലെങ്കിൽ ASAR പരിശോധിക്കുക:
```bash
npx -y rea-agents@latest analyze-javascript-application /absolute/path/to/app --json
```
ഫലത്തിൽ modules, imports, Electron boundaries, അവയ്ക്കുള്ള തെളിവുകൾ എന്നിവ ഉൾപ്പെടും. `/absolute/path/to/app` എന്നതിന് പകരം നിങ്ങളുടെ target-ന്റെ path നൽകുക; Windows-ൽ ഉദാഹരണത്തിന് `"D:/apps/example"` ഉപയോഗിക്കാം.
സാധാരണ ഉപയോഗത്തിനായി `rea` command ഇൻസ്റ്റാൾ ചെയ്യാൻ:
```bash
npm install --global rea-agents
rea --help
```
Native analysis നടത്തുന്നതിന് മുമ്പ് ഒരു provider ക്രമീകരിക്കുക. Native commands, provider തിരഞ്ഞെടുക്കൽ, snapshots, scripting എന്നിവയ്ക്കായി [CLI and Evidence guide](../cli.md) കാണുക.
### REA അപ്‌ഡേറ്റ് ചെയ്യുക
REA-യിൽ പതിവായി മാറ്റങ്ങൾ വരുന്നു; പുതിയ releases-ൽ പല bug fixes-ഉം ഉൾപ്പെടുന്നു. നിങ്ങളുടെ installation ഏറ്റവും പുതിയ പതിപ്പിലേക്ക് അപ്‌ഡേറ്റ് ചെയ്യുക.
`npm install --global` അല്ലെങ്കിൽ `bun add --global` ഉപയോഗിച്ച് ഇൻസ്റ്റാൾ ചെയ്ത CLI-ക്കായി:
```bash
rea update
```
Bun-ന്റെ global updates-ന് Bun 1.2.17 അല്ലെങ്കിൽ അതിനുശേഷമുള്ള പതിപ്പ് ആവശ്യമാണ്. പഴയ Bun പതിപ്പാണെങ്കിൽ `rea update` പ്രവർത്തിപ്പിക്കുന്നതിന് മുമ്പ് Bun സ്വമേധയാ അപ്‌ഗ്രേഡ് ചെയ്യുക.
Agent registrations-ഉം skill-ഉം പുതുക്കാൻ, update കാണിക്കുന്ന setup command പ്രവർത്തിപ്പിക്കുക.
`npx` ഉപയോഗിക്കുന്നുവെങ്കിൽ, agent setup പുതുക്കാൻ:
```bash
npx rea-agents@latest setup
```
Setup-ൽ വരുത്തുന്ന മാറ്റങ്ങൾ പരിശോധിച്ച് നിങ്ങളുടെ agent വീണ്ടും ആരംഭിക്കുക. ഒറ്റത്തവണ മാത്രം ഉപയോഗിക്കുന്ന CLI commands-നായി command-ന് മുമ്പ് `npx rea-agents@latest` ഉപയോഗിക്കുക. Bun ഉപയോഗിക്കുമ്പോൾ `npx rea-agents@latest`-ന് പകരം `bunx rea-agents@latest` ഉപയോഗിക്കുക.
## REA എങ്ങനെ പ്രവർത്തിക്കുന്നു
Target പരിശോധിക്കാനും പ്രസക്തമായ code-ന്റെ പാത പിന്തുടരാനും നിങ്ങളുടെ agent MCP വഴി REA-യെ വിളിക്കുന്നു. REA കണ്ടെത്തലുകളും അവയ്ക്കുള്ള തെളിവുകളും തിരികെ നൽകുന്നു. തുടർന്ന് agent കൂടുതൽ ചോദ്യങ്ങൾ ചോദിക്കാനും പെരുമാറ്റം വിശദീകരിക്കാനും implementation എഴുതുകയും പരിശോധിക്കുകയും ചെയ്യാനും അവ ഉപയോഗിക്കുന്നു. CLI commands-ഉം ഇതേ workflows ഉപയോഗിക്കുന്നു.
![REA അന്വേഷണ പ്രവാഹം: നിങ്ങളുടെ agent ഒരു local target-നെക്കുറിച്ച് ചോദിക്കുന്നു; REA analysis tools ഉപയോഗിച്ച് അത് പരിശോധിക്കുകയും code-ന്റെ പാത പിന്തുടരുകയും ചെയ്യുന്നു; തിരികെ ലഭിക്കുന്ന code, references, അറിയാത്ത കാര്യങ്ങൾ എന്നിവ ഉപയോഗിച്ച് agent വിശദീകരിക്കുകയും implementation നടത്തുകയും പരിശോധിക്കുകയും ചെയ്യുന്നു.](../../website/public/assets/figures/rea-investigation-flow.svg)
[പൂർണ്ണ വലുപ്പത്തിലുള്ള ചിത്രം തുറക്കുക](../../website/public/assets/figures/rea-investigation-flow.svg).
<a id="current-status"></a>
## എന്തൊക്കെ വിശകലനം ചെയ്യാം
REA-യ്ക്ക് Node.js 22.x (>=22.19), 24.x (>=24.11), അല്ലെങ്കിൽ 26+ പതിപ്പും npm-ഉം ആവശ്യമാണ്. Target അനുസരിച്ച് അധിക tools-ഉം host support-ഉം വ്യത്യാസപ്പെടും:
| Target | REA നൽകുന്ന ഫലങ്ങൾ | ആവശ്യകതകളും ഗൈഡും |
| ---------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Native binaries | Pseudocode, assembly, strings, symbols, calls, references | Hopper, Ghidra അല്ലെങ്കിൽ IDA; [native analysis](../native-investigation.md) |
| Offline ELF layout | Sections, segments, യഥാർത്ഥ symbols/relocations, static mitigation candidates | Linux x64-ൽ caller നൽകുന്ന pwntools; [binary diagnostics](../binary-diagnostics.md) |
| Go binaries | ഉൾച്ചേർത്ത compiler version, modules, replacements, build settings | Built-in static ELF/PE/thin Mach-O പരിശോധന; Go installation ആവശ്യമില്ല |
| Rust binaries | ഉൾച്ചേർത്ത cargo-auditable crate പേരുകൾ, versions, sources, dependency edges | Built-in static ELF/PE/thin Mach-O പരിശോധന; [Rust binaries](../rust-binaries.md) |
| WASM artifact | Validation, sections, കൃത്യമായ import/export WAT രൂപങ്ങൾ, decoded WAT | Caller നൽകുന്ന WABT 1.0.42; `inspect_wasm_artifact` |
| EVM bytecode | Dispatch selectors, byte offsets, അനുമാനിച്ച arguments, mutability | Linux x64-ൽ local raw/hex carrier; [offline EVM guide](../evm-bytecode.md) |
| SQLite databases | Tables, columns, indexes, views, triggers, തിരഞ്ഞെടുത്ത സാധാരണ table rows | Local database/WAL snapshot; native SQLite പരിമിതികളോടെ Node.js 24.x >=24.15 അല്ലെങ്കിൽ 26+ |
| Recorded Linux crashes | Raw notes, രേഖപ്പെടുത്തിയ ഓരോ thread-ന്റെയും registers/signals, ഐച്ഛിക mapping candidates | Linux x64-ൽ caller നൽകുന്ന pwntools; ഐച്ഛിക GDB/pwndbg; [recorded crashes](../recorded-crashes.md) |
| JavaScript / Electron | Modules, imports, source maps, routes, IPC, native add-on ബന്ധങ്ങൾ | Node.js, npm; Linux: procps-compatible `ps`; [application analysis](../javascript-application-workflows.md) |
| Websites | Page structure, scripts, network observations, ആവശ്യപ്പെട്ട screenshots | Chrome-family browser; [browser analysis](../browser-observation.md) |
| Saved network captures | Requests, responses, പുറത്തുകാണുന്ന payload-ുകൾ, source locations | HAR അല്ലെങ്കിൽ Fiddler Everywhere SAZ; native mitmproxy-നായി Linux-ൽ mitmdump; [capture guide](../web-network-captures.md) |
| .NET assemblies | Metadata, CIL instructions, പ്രഖ്യാപിച്ച native dependencies, build comparisons | ഒന്നും ആവശ്യമില്ല (static മാത്രം); [managed-code guide](../managed-code-analysis.md) |
| Android APKs | Manifest declarations, classes, decompiled methods, references | Linux/macOS/Windows x64-ൽ Headless JADX-ഉം full JDK-ഉം; [Android guide](../android-analysis.md) |
| Android devices | Devices, packages, processes, logs, dumps, screen captures, APK/file transfers | Caller നൽകുന്ന adb (emulator അല്ലെങ്കിൽ hardware); [ADB guide](../adb-device-analysis.md) |
| JEB projects | Engine-backed project units, artifact digests, type/method pseudo-code | MCP സേവനം നൽകുന്ന caller ആരംഭിച്ച JEB client; REA_JEB_MCP_URL ഉപയോഗിച്ച് തിരഞ്ഞെടുക്കുക; [JEB guide](../jeb-analysis.md) |
| Android resources | Decoded manifest, string tables, locales, version വിവരങ്ങൾ | Caller നൽകുന്ന Apktool launcher; [resource guide](../apktool-resource-analysis.md) |
| Flutter apps | Dart snapshot hash, ഓരോ ABI-യിലെയും library digests, engine build provenance | ഒന്നും ആവശ്യമില്ല (static APK parsing); [Flutter guide](../flutter-analysis.md) |
| Firmware | Regions, extraction results, native-analysis handoffs | Linux-ൽ Binwalk / Unblob; [firmware guide](../firmware-analysis.md) |
| Recorded packets | തിരഞ്ഞെടുത്ത fields, ആവർത്തിക്കുന്ന values, filters, decode-as rules | Linux: TShark 4.x + prlimit; [capture guide](../packet-captures.md) |
| Packet summaries | Endpoints, DNS, TLS SNI, protocol distribution, HTTP requests | Caller നൽകുന്ന tshark, capinfos (Linux-ൽ പരിശോധിച്ചത്); [pcap guide](../pcap-analysis.md) |
| Recorded logic signals | Decoder annotations, sample ranges, diagnostics | Linux: sigrok-cli 0.7.2 + prlimit; [signal recordings](../signal-recordings.md) |
| Packages and resources | File inventories, digests, plists, Apple bundle ഘടന, extracted resources | [Artifact and JavaScript guide](../javascript-artifact-reconstruction.md), [Apple applications](../apple-application-analysis.md) |
| Process behavior | Terminal output, interactions, exit, filesystem observations, run comparisons | Native PTY ഉള്ള Linux/macOS; [process capture](../process-capture.md) |
Static JavaScript, .NET പരിശോധനകൾ application പ്രവർത്തിപ്പിക്കാതെ നൽകിയ files വായിച്ചാണ് നടത്തുന്നത്. Runtime capture, നിങ്ങളുടെ user permissions ഉപയോഗിച്ച് തിരഞ്ഞെടുത്ത target പ്രവർത്തിപ്പിക്കുകയോ അതുമായി ഇടപെടുകയോ ചെയ്യുന്നു; ഓരോ runtime guide-ലും അതിന്റെ പ്രത്യാഘാതങ്ങൾ വിശദീകരിച്ചിട്ടുണ്ട്.
Offline native-binary പരിശോധനയ്ക്കായി REA, caller നൽകുന്ന GNU objdump, Rizin എന്നിവയും പിന്തുണയ്ക്കുന്നു. Provider setup, CLI commands, Evidence-ന്റെ പരിമിതികൾ എന്നിവയ്ക്കായി [reverse-engineering tools guide](../reverse-engineering-tools.md) കാണുക. ഈ providers ഒന്നും REA ഇൻസ്റ്റാൾ ചെയ്യുകയോ അപ്‌ഡേറ്റ് ചെയ്യുകയോ ചെയ്യുന്നില്ല.
<a id="choosing-a-deep-analysis-provider"></a>
Native formats-ഉം host support-ഉം provider അനുസരിച്ച് വ്യത്യാസപ്പെടും. [Hopper and Ghidra setup](../installation.md#hopper), [IDA guide](../ida-provider.md) (ഐച്ഛിക native MCP bridge ഉൾപ്പെടെ), [Kuna decompiler guide](../kuna-provider.md), [പരീക്ഷണഘട്ടത്തിലുള്ള Windows Ghidra support](../windows-ghidra-p0.md) എന്നിവ കാണുക.
Ghidra, [16-bit DOS analysis](../ghidra-dos.md)-ഉം പിന്തുണയ്ക്കുന്നു.
വലിയ binaries-നായി `REA_GHIDRA_STARTUP_TIMEOUT_MS` അല്ലെങ്കിൽ `REA_HOPPER_STARTUP_TIMEOUT_MS` ഉപയോഗിച്ച് provider-ന്റെ startup deadline വർധിപ്പിക്കുക.
Provider തിരഞ്ഞെടുക്കാൻ [CLI guide](../cli.md#choose-a-provider) കാണുക.
ഏറ്റവും പുതിയ npm release-നുശേഷം ചേർത്ത features അറിയാൻ [release availability](../installation.md#released-package-and-main) പരിശോധിക്കുക.
## ഉദാഹരണങ്ങൾ
[![DX-Ball sound-pan, Notion clipboard-bridge, TH04 bullet-ring എന്നിവയുടെ ചിത്രീകരണങ്ങൾ](../assets/rea-showcases.png)](https://rea.tools/showcase/)
### DX-Ball: sound-pan കണക്കുകൂട്ടൽ പുനർനിർമ്മിക്കുക
ഒരു sound call-നെ അതിന്റെ position-to-pan helper വരെ പിന്തുടരുക, instructions പരിശോധിക്കുക, അപൂർണ്ണമായ pseudocode-നെ C-യാക്കി മാറ്റുക. ഈ പുനർനിർമ്മാണം യഥാർത്ഥ x86-ലെ 3,205 test cases വിജയിക്കുകയും compile ചെയ്ത function-ന്റെ 63 bytes-ഉം അതേപടി പുനരുത്പാദിപ്പിക്കുകയും ചെയ്യുന്നു.
[Case study വായിക്കുക](https://rea.tools/showcase/dx-ball/) ·
[പുനർനിർമ്മാണ repository](https://github.com/N0zoM1z0/dx-ball)
### Notion: Electron clipboard bridge പിന്തുടരുക
Renderer-ന്റെ clipboard API കണ്ടെത്തി, അതിനെ preload-ഉം IPC-ഉം വഴി main process വരെ പിന്തുടർന്ന് rich clipboard format പരിശോധിക്കുക.
[Case study വായിക്കുക](https://rea.tools/showcase/notion/)
### TH04: DOS bullet-ring കണക്കുകൂട്ടൽ വീണ്ടെടുക്കുക
യഥാർത്ഥ PC-98 game-ന്റെ 16-bit instructions പരിശോധിക്കുക, fixed, aimed angle കണക്കുകൂട്ടലുകൾ വീണ്ടെടുക്കുക, പുനർനിർമ്മിച്ച C++-നെ ചരിത്രപരമായ compiler output-ുമായി താരതമ്യം ചെയ്യുക.
[Case study വായിക്കുക](https://rea.tools/showcase/th04/) ·
[പുനർനിർമ്മാണ repository](https://github.com/N0zoM1z0/th04)
REA ഉപയോഗിച്ച് നിങ്ങൾ രസകരമായ എന്തെങ്കിലും പരിശോധിച്ചിട്ടുണ്ടെങ്കിൽ അത് കാണാൻ ഞങ്ങൾ ആഗ്രഹിക്കുന്നു. പരിശോധിച്ച target, നിങ്ങളുടെ ചോദ്യം, REA എങ്ങനെ സഹായിച്ചു, നിങ്ങൾ കണ്ടെത്തിയത് എന്നിവ ഉൾപ്പെടുത്തി [issue](https://github.com/morluto/rea/issues) അല്ലെങ്കിൽ [pull request](https://github.com/morluto/rea/pulls) വഴി നിങ്ങളുടെ case പങ്കിടുക.
## പതിവുചോദ്യങ്ങൾ
<details>
<summary><strong>ഏതൊക്കെ agents-ന് REA ഉപയോഗിക്കാം?</strong></summary>
Local MCP servers പിന്തുണയ്ക്കുന്ന ഏത് agent-നും REA ഉപയോഗിക്കാം. Setup, [പിന്തുണയ്ക്കുന്ന agents](../installation.md#supported-agents) ക്രമീകരിക്കുന്നു; മറ്റ് clients-ന് [manual MCP registration](../installation.md#mcp-registry) ഉപയോഗിക്കാം.
</details>
<details>
<summary><strong>Hopper, Ghidra അല്ലെങ്കിൽ IDA ആവശ്യമാണോ?</strong></summary>
ആഴത്തിലുള്ള native analysis-ന് ഇവയിൽ ഒന്ന് ആവശ്യമാണ്. Static JavaScript, .NET പരിശോധനകൾ native analysis engine ഇല്ലാതെയും പ്രവർത്തിക്കും. അനുമതി ലഭിച്ചാൽ setup-ന് Hopper ഇൻസ്റ്റാൾ ചെയ്യാം; Ghidra, IDA എന്നിവയ്ക്കായി നിങ്ങളുടെ നിലവിലുള്ള installations ഉപയോഗിക്കുന്നു. [Provider setup](../installation.md#hopper) കാണുക.
</details>
<details>
<summary><strong>Hopper ആദ്യം ആരംഭിക്കേണ്ടതുണ്ടോ?</strong></summary>
ഒരു operation-ന് ആവശ്യമാകുമ്പോൾ REA Hopper ആരംഭിക്കും. macOS-ൽ ആദ്യമായി പ്രവർത്തിപ്പിക്കുമ്പോൾ demo mode തിരഞ്ഞെടുക്കാനോ license activate ചെയ്യാനോ ആവശ്യപ്പെടുന്ന dialog പ്രത്യക്ഷപ്പെടാം. ആദ്യ CLI/MCP operation അല്ലെങ്കിൽ unattended job നടത്തുന്നതിന് മുമ്പ് അതേ user session-ൽ ആ prompt പൂർത്തിയാക്കുക. ആവശ്യമെങ്കിൽ Hopper സ്വമേധയാ തുറക്കുക. [Hopper startup and troubleshooting](../installation.md#launcher-paths-and-troubleshooting) കാണുക.
</details>
<details>
<summary><strong>skills.sh-ൽ നിന്ന് skill ഇൻസ്റ്റാൾ ചെയ്യുന്നത് എന്താണ് ചെയ്യുന്നത്?</strong></summary>
ഈ skill നിങ്ങളുടെ agent-ന് അന്വേഷണ നിർദ്ദേശങ്ങൾ നൽകുന്നു. REA-യുടെ MCP server രജിസ്റ്റർ ചെയ്യാനും അനുയോജ്യമായ നിർദ്ദേശങ്ങൾ ഇൻസ്റ്റാൾ ചെയ്യാനും `npx rea-agents setup` ഉപയോഗിക്കുക; തുടർന്ന് നിങ്ങളുടെ agent വീണ്ടും ആരംഭിക്കുക. [Skill-only installation](../installation.md#skill-only-installation) കാണുക.
</details>
<details>
<summary><strong>REA ഏത് തരത്തിലുള്ള code ആണ് നൽകുന്നത്?</strong></summary>
Native analysis pseudocode-ഉം assembly-ഉം നൽകുന്നു. JavaScript/Electron analysis modules-ഉം അവയുടെ ബന്ധങ്ങളും വീണ്ടെടുക്കുന്നു. ഈ കണ്ടെത്തലുകൾ ഉപയോഗിച്ച് നിങ്ങളുടെ agent implementation എഴുതുകയും പരിശോധിക്കുകയും ചെയ്യും; പ്രായോഗിക ഉദാഹരണങ്ങൾക്കായി [ഉദാഹരണങ്ങൾ](#showcases) കാണുക.
</details>
<details>
<summary><strong>REA എന്റെ app upload ചെയ്യുമോ?</strong></summary>
REA targets local ആയി വിശകലനം ചെയ്യുന്നു. Tool-ൽ നിന്നുള്ള ഫലങ്ങൾ നിങ്ങളുടെ agent-ന് ലഭിക്കും; അതിന്റെ model provider-ന് സ്വന്തമായ data policy ഉണ്ടായിരിക്കും.
</details>
<details>
<summary><strong>ഒരു bug നേരിട്ടാൽ എന്തുചെയ്യണം?</strong></summary>
ആദ്യം അപ്‌ഡേറ്റ് ചെയ്യുക; പുതിയ release-ൽ ആ പ്രശ്നത്തിനുള്ള പരിഹാരം ഇതിനകം ഉണ്ടായേക്കാം.
`npm install --global` അല്ലെങ്കിൽ `bun add --global` ഉപയോഗിച്ച് ഇൻസ്റ്റാൾ ചെയ്ത CLI-ക്കായി:
```bash
rea update
```
`npx` വഴി agent setup നടത്തുന്നതിനായി:
```bash
npx rea-agents@latest setup
```
നിങ്ങൾ agent ഉപയോഗിക്കുന്നുണ്ടെങ്കിൽ, [setup പുതുക്കൽ](#update-rea) പൂർത്തിയാക്കി അത് വീണ്ടും ആരംഭിക്കുക. അതേ task വീണ്ടും ശ്രമിക്കുക. പ്രശ്നം തുടരുകയാണെങ്കിൽ, നിങ്ങളുടെ REA version, target type, പ്രശ്നം ആവർത്തിക്കാൻ ആവശ്യമായ ഘട്ടങ്ങൾ, error output എന്നിവ ഉൾപ്പെടുത്തി [issue തുറക്കുക](https://github.com/morluto/rea/issues).
</details>
## ഡോക്യുമെന്റേഷൻ
വെബ്സൈറ്റിലെ [പ്രായോഗിക ഗൈഡുകൾ](https://rea.tools/guides/) ഉപയോഗിച്ച് തുടങ്ങുക.
കൃത്യമായ options, prerequisites, result contracts എന്നിവയ്ക്കായി:
- [Installation and setup](../installation.md): agent registration, provider configuration, updates, uninstall.
- [Readiness and troubleshooting](../installation.md#check-readiness-for-your-task): ഒരു agent-ന്റെയോ analysis engine-ന്റെയോ പ്രശ്നങ്ങൾ കണ്ടെത്തുക.
- [CLI and Evidence](../cli.md): commands, provider തിരഞ്ഞെടുക്കൽ, snapshots, import/export, exit statuses.
- [MCP contracts](../mcp-contracts.md), [agent prompts](../mcp-prompts.md): tool results, sessions, guided investigations.
- [Tool catalog](../mcp-contracts.md#generated-catalog): tools, providers, CLI commands എന്നിവയുടെ സ്വയമേവ സൃഷ്ടിച്ച പട്ടിക.
- [Roadmap](../roadmap.md): ആസൂത്രണം ചെയ്ത പ്രവർത്തനങ്ങളും capability trackers-ഉം.
സുരക്ഷാ ദുർബലതകൾ [SECURITY.md](../../SECURITY.md) വഴി റിപ്പോർട്ട് ചെയ്യുക.
## Star ചരിത്രം
🎉 **250,000 GitHub stars — നന്ദി!**
REA ഉപയോഗിക്കുന്നവർക്കും, bugs റിപ്പോർട്ട് ചെയ്യുന്നവർക്കും, features ആവശ്യപ്പെടുന്നവർക്കും, builds പരിശോധിക്കുന്നവർക്കും, fixes സംഭാവന ചെയ്യുന്നവർക്കും നന്ദി.
<a href="https://www.star-history.com/?repos=morluto%2Frea&amp;type=date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=morluto/rea&amp;type=date&amp;theme=dark&amp;legend=top-left" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=morluto/rea&amp;type=date" />
<img alt="REA GitHub star ചരിത്രം" src="https://api.star-history.com/chart?repos=morluto/rea&amp;type=date" />
</picture>
</a>
## നിരാകരണം
ഉത്തരവാദിത്തത്തോടെ ഉപയോഗിക്കുന്നതിനുള്ള മാർഗനിർദ്ദേശങ്ങൾക്ക് [DISCLAIMER.md](../../DISCLAIMER.md) കാണുക.
നിയമവിരുദ്ധമോ അനുമതിയില്ലാത്തതോ ആയ ഉപയോഗത്തെക്കുറിച്ചുള്ള project-ന്റെ നിലപാട് എല്ലാ REA versions-നും distribution channels-നും platforms-നും ബാധകമാണ്; ഓരോ copy-യും അതിന് ബാധകമായ licenses നിലനിർത്തുന്നു.
നിയമാനുസൃതമായ research, education, interoperability, software preservation, കൂടാതെ നിങ്ങൾക്ക് സ്വന്തമായതോ പരിശോധിക്കാൻ അനുമതിയുള്ളതോ ആയ software-ന്റെ analysis എന്നിവയ്ക്കാണ് REA ഉദ്ദേശിച്ചിരിക്കുന്നത്.
## സംഭാവനകൾ
REA-യ്ക്കായി നിങ്ങളുടെ സഹായം ഞങ്ങൾ സ്വാഗതം ചെയ്യുന്നു! bug റിപ്പോർട്ട് ചെയ്യാനോ feature നിർദ്ദേശിക്കാനോ [issue തുറക്കുക](https://github.com/morluto/rea/issues), code അല്ലെങ്കിൽ docs മെച്ചപ്പെടുത്താൻ [pull request അയയ്ക്കുക](https://github.com/morluto/rea/pulls).
Development setup-നും checks-നും [CONTRIBUTING.md](../../CONTRIBUTING.md), verification lanes-നായി [testing](../testing.md), project ഘടനയ്ക്കായി [architecture map](../architecture.mermaid) എന്നിവ കാണുക.
## ലൈസൻസ്
[MIT](../../LICENSE)
REA-യുടെ രചയിതാക്കൾ സൃഷ്ടിച്ച code MIT license പ്രകാരമാണ് ലൈസൻസ് ചെയ്തിരിക്കുന്നത്. Third-party material അതിന്റെ സ്വന്തം licenses-ഉം copyright notices-ഉം നിലനിർത്തുന്നു; dependencies-ന്റെ പട്ടിക, നിലനിർത്തിയ license text-ുകൾ, external tool നിബന്ധനകൾ എന്നിവയ്ക്കായി [Third-party notices](../../THIRD_PARTY_NOTICES.md) കാണുക.
**IDA Pro / Hex-Rays decompilers, Hopper, JEB എന്നിവ ഉൾപ്പെടെയുള്ള commercial tools നിയമാനുസൃതമായി സ്വന്തമാക്കുകയും അവയുടെ ബാധകമായ licenses പ്രകാരം ഉപയോഗിക്കാൻ അനുമതിയുണ്ടെന്ന് ഉറപ്പാക്കുകയും വേണം.** REA ഒരു tool license-ഓ key-യോ activation entitlement-ഓ നൽകുന്നില്ല. Trials-ഉം demos-ഉം ഉൾപ്പെടെ vendor നിബന്ധനകൾക്ക് വിധേയമാണ്; ഇതിൽ user, feature, automation, output sharing നിയന്ത്രണങ്ങളും ഉൾപ്പെടാം. Cracked copies, മോഷ്ടിച്ച keys, അനുമതിയില്ലാത്ത key sharing, license നിയന്ത്രണങ്ങൾ മറികടക്കൽ എന്നിവയ്ക്ക് അനുമതിയില്ല. ഈ മാർഗനിർദ്ദേശം MIT അല്ലെങ്കിൽ third-party licenses-ൽ മാറ്റം വരുത്തുന്നില്ല.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · **Polski** · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: Reverse Engineer Anything
@@ -272,7 +272,7 @@ Zgłaszaj podatności zgodnie z [SECURITY.md](../../SECURITY.md).
## Historia gwiazdek
🎉 **300 000 gwiazdek na GitHubie — dziękujemy!**
🎉 **250 000 gwiazdek na GitHubie — dziękujemy!**
Dziękujemy wszystkim, którzy używają REA, zgłaszają błędy, proponują nowe funkcje, testują kompilacje i przesyłają poprawki.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · **Português (Brasil)** · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: Faça engenharia reversa de qualquer coisa
@@ -272,7 +272,7 @@ Relate vulnerabilidades conforme [SECURITY.md](../../SECURITY.md).
## Histórico de estrelas
🎉 **300.000 estrelas no GitHub — muito obrigado!**
🎉 **250.000 estrelas no GitHub — muito obrigado!**
Obrigado a todos que usam o REA, relatam bugs, sugerem funcionalidades, testam builds e contribuem com correções.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · **Русский** · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: Реверс-инжиниринг чего угодно
@@ -272,7 +272,7 @@ npx rea-agents@latest setup
## История звёзд
🎉 **300 000 звёзд на GitHub — спасибо!**
🎉 **250 000 звёзд на GitHub — спасибо!**
Спасибо всем, кто использует REA, сообщает об ошибках, предлагает новые функции, тестирует сборки и помогает с исправлениями.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · **ไทย** · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: Reverse Engineer Anything
@@ -272,7 +272,7 @@ npx rea-agents@latest setup
## ประวัติดาว
🎉 **300,000 ดาวบน GitHub — ขอบคุณทุกคน!**
🎉 **250,000 ดาวบน GitHub — ขอบคุณทุกคน!**
ขอบคุณทุกคนที่ใช้ REA รายงานบั๊ก เสนอฟีเจอร์ ทดสอบบิลด์ และช่วยแก้ไข
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · **Türkçe** · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: Her şeyi tersine mühendislikle inceleyin
@@ -277,7 +277,7 @@ Güvenlik açıklarını [SECURITY.md](../../SECURITY.md) üzerinden bildirin.
## Yıldız geçmişi
🎉 **GitHub'da 300.000 yıldız — teşekkürler!**
🎉 **GitHub'da 250.000 yıldız — teşekkürler!**
REA'yı kullanan, hata bildiren, özellik talep eden, derlemeleri test eden ve düzeltmelere katkıda bulunan herkese teşekkürler.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · **Українська** · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: Реверс-інжиніринг будь-чого
@@ -272,7 +272,7 @@ npx rea-agents@latest setup
## Історія зірок
🎉 **300 000 зірок на GitHub — дякуємо!**
🎉 **250 000 зірок на GitHub — дякуємо!**
Дякуємо всім, хто використовує REA, повідомляє про помилки, пропонує нові функції, тестує збірки й допомагає з виправленнями.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · **Tiếng Việt** · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA: Kỹ thuật dịch ngược cho mọi thứ
@@ -272,7 +272,7 @@ Báo cáo lỗ hổng theo [SECURITY.md](../../SECURITY.md).
## Lịch sử sao
🎉 **300.000 sao trên GitHub — xin cảm ơn!**
🎉 **250.000 sao trên GitHub — xin cảm ơn!**
Cảm ơn mọi người đã sử dụng REA, báo lỗi, đề xuất tính năng, kiểm thử bản dựng và đóng góp bản sửa lỗi.
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · [简体中文](README_zh.md) · **繁體中文** · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA:逆向一切
@@ -278,7 +278,7 @@ npx rea-agents@latest setup
## Star 歷史
🎉 **GitHub Star 達到 300,000 個,感謝大家!**
🎉 **GitHub Star 達到 250,000 個,感謝大家!**
感謝每一位使用 REA、報告錯誤、提出功能需求、測試建置和貢獻修復的朋友。
+2 -2
View File
@@ -1,7 +1,7 @@
<div align="center">
[English](../../README.md) · **简体中文** · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
· [Ελληνικά](README_el.md)
# REA:逆向一切
@@ -278,7 +278,7 @@ npx rea-agents@latest setup
## Star 历史
🎉 **GitHub Star 达到 300,000 个,感谢大家!**
🎉 **GitHub Star 达到 250,000 个,感谢大家!**
感谢每一位使用 REA、报告错误、提出功能需求、测试构建和贡献修复的朋友。
+4 -18
View File
@@ -61,21 +61,9 @@ The outer provider owns both processes and one stable core snapshot. An owned
Python launcher lowers inherited soft limits before replacing itself with GDB.
GDB starts without initfiles, auto-load, debuginfod or automatic shared-library
loading. Owned empty library search paths and caches are used, with plugin
updates disabled. Debug-file lookup is also restricted to the owned empty
search directory. GDB 16 can otherwise locate the recorded executable independently
of these settings. While opening the core, fixed package code temporarily selects
`/proc/self/exe` (the already running debugger) with `exec-file`, without loading
symbols or running an inferior. This occupies GDB's executable slot and prevents
its automatic executable discovery. The validated decoder profile selects the
core architecture explicitly, so the placeholder cannot select it instead. The
bridge discards that selection with `file` before querying mapping candidates,
and verifies the core connection and absence of a main symbol file. Before launching GDB, the provider also checks
source-bound `NT_FILE` descriptors: mapping names must be absolute Unix paths
without dot segments. Relative names bypass GDB's sysroot, and traversal can
escape it. Unresolved or unsafe mapping coverage refuses debugger enrichment
while retaining the basic decoded observation and original bytes. No caller GDB
command language is exposed. The exact observed GDB/plugin version strings are
retained.
updates disabled. Fixed package code verifies a core connection and no paired
executable before querying mapping candidates. No caller GDB command language is
exposed. The exact observed GDB/plugin version strings are retained.
Mapping names are producer display metadata, with unknown current file identity.
Map permissions are derived from reported flags; zero/unfamiliar flags leave
@@ -105,6 +93,4 @@ GDB/Python/pwndbg/strace. Fixture generation explicitly launches its owned test
program; subsequent inspection only reads the resulting core. Real acceptance
checks recorded threads, high registers, missing/malformed notes, opaque owners,
CLI/MCP parity, optional debugger context and historical PID collision with an
owned live sentinel. The syscall trace also rejects access to the still-present
source executable. The CI workflow defines Ubuntu 24.04 and Debian 13 (GDB 16)
container lanes. Original inputs and host configuration remain unchanged.
owned live sentinel. Original inputs and host configuration remain unchanged.
File diff suppressed because it is too large. Load diff
-112
View File
@@ -1,112 +0,0 @@
{
"schemaVersion": 1,
"repository": "morluto/rea",
"version": "6.7.0",
"base": "2c4338db1fdb7773e05376301c558cff2a0b4b80",
"target": "b83b9caf4a5f0241a5fd370792f1aed1bffbb2cf",
"commits": [
{
"sha": "8cbaf6c7021b97dd4de6b5771c35fbed06b240e9",
"subject": "fix(tests): isolate command finalization module mocks",
"body": "fix(tests): isolate command finalization module mocks\n\nMove the five registered WASM finalization cases into the existing per-file isolated project. Preserve all result, exit-code, observation and cleanup assertions. A preloaded shared CLI graph reproduces three failures before the move; the isolated covered packet passes.\n\nFixes #4959\n",
"parents": ["2c4338db1fdb7773e05376301c558cff2a0b4b80"],
"authors": [
{
"name": "morluto",
"email": "76467478+morluto@users.noreply.github.com",
"user": {
"login": "morluto",
"__typename": "User"
}
}
],
"pullRequests": []
},
{
"sha": "6b180783ed04ebc87548c8385c80e05725804c47",
"subject": "fix(tests): budget CLI coverage from parsed options",
"body": "fix(tests): budget CLI coverage from parsed options\n\nUse the pinned Vitest parser for coverage and shard flags. Keep ordinary CLI workers at 384 MiB and covered workers at the tested 512 MiB with unchanged concurrency. Retain complete coverage and add actual-config regressions for false, provider-only and spaced-shard options.\n\nValidation: 27 focused cases; 16 covered cases with CLI preloaded; 5 docs checks; typecheck/lint; exact discovery of 1578 files. Measured covered control: 22.18s elapsed, 46.52s CPU, about 2.33 GiB sampled summed process-family RSS on macOS arm64. Full Linux CI pending. No runtime/device verification claimed.\n\nFixes #4960\n",
"parents": ["8cbaf6c7021b97dd4de6b5771c35fbed06b240e9"],
"authors": [
{
"name": "morluto",
"email": "76467478+morluto@users.noreply.github.com",
"user": {
"login": "morluto",
"__typename": "User"
}
}
],
"pullRequests": []
},
{
"sha": "bb212ffecb47e129cc569b9867b2b6e7c9b65685",
"subject": "fix(tests): inherit server identity deadline policy",
"body": "fix(tests): inherit server identity deadline policy\n\nRemove per-case ten-second overrides from MCP catalog and identity checks. Keep the suite-owned bounded ordinary and coverage deadlines, all assertions, and session cleanup.\n\nFixes #4967\n",
"parents": ["6b180783ed04ebc87548c8385c80e05725804c47"],
"authors": [
{
"name": "morluto",
"email": "76467478+morluto@users.noreply.github.com",
"user": {
"login": "morluto",
"__typename": "User"
}
}
],
"pullRequests": []
},
{
"sha": "b83b9caf4a5f0241a5fd370792f1aed1bffbb2cf",
"subject": "fix(setup): edit the duplicate JSON member that clients read (#4957)",
"body": "fix(setup): edit the duplicate JSON member that clients read (#4957)\n\nJSON.parse, JSONC parse, and native Claude Code keep the last duplicate\nobject member, and parseClientConfiguration therefore validates the last\none. The shared setup/uninstall serializer instead edited text through\njsonc-parser's modify and findNodeAtLocation, which select the first\nmatching member, so setup and uninstall on configurations with repeated\nserver tables or rea members wrote into a shadowed member and failed\nreadback.\n\nLocate every JSON text edit by the effective (last) member in one place,\nreplacing the first-member modify path. Removing an effective member\nthat shadows an earlier duplicate would activate that duplicate, whatever\nits ownership, so the serializer now returns a tagged shadowed_member\nfailure and setup and uninstall refuse before writing a backup or the\nconfiguration.\n\nFixes #4952\n\nCo-authored-by: Claude Opus 5.5 <noreply@anthropic.com>",
"parents": ["bb212ffecb47e129cc569b9867b2b6e7c9b65685"],
"authors": [
{
"name": "Kaoru0822",
"email": "kanadekitauji@proton.me",
"user": {
"login": "kaoru0822-kitauji",
"__typename": "User"
}
},
{
"name": "Claude Opus 5.5",
"email": "noreply@anthropic.com",
"user": {
"login": "claude",
"__typename": "User"
}
}
],
"pullRequests": [4957]
}
],
"pullRequests": [
{
"number": 4957,
"title": "fix(setup): edit the duplicate JSON member that clients read",
"url": "https://github.com/morluto/rea/pull/4957",
"author": {
"login": "kaoru0822-kitauji",
"__typename": "User"
},
"mergeCommit": {
"oid": "b83b9caf4a5f0241a5fd370792f1aed1bffbb2cf"
},
"issues": [
{
"number": 4952,
"url": "https://github.com/morluto/rea/issues/4952",
"author": {
"login": "xu91102",
"__typename": "User"
},
"repository": {
"nameWithOwner": "morluto/rea"
}
}
]
}
]
}
+1 -6
View File
@@ -73,12 +73,7 @@ invocation. A signed status response also confirms completion of older bridge
connections after its UI dispatch, preserving recovery proof for a caller whose
receipt another caller has acknowledged. Neither receipt recovery nor a status
probe retries the original command. Failed acknowledgements remain pending and
block new commands until they can be retried successfully. Status proof failures
identify `cutter_command` and retain `status` in
`details.diagnostics.auxiliary_operation`; malformed proof still blocks dispatch.
Descriptor failures likewise retain the requesting operation through cleanup.
Command admission reports typed cancellation and treats the caller's abort reason
as opaque metadata, without inferring cleanup ownership from it.
block new commands until they can be retried successfully.
## Configuration and coverage
+1 -18
View File
@@ -57,10 +57,7 @@ triggers or arbitrary SQL.
Rows are optional. `table` selects one exact ordinary-table name. `columns`
(CLI repeated `--column`) selects exact visible column names in the requested
order; omission selects all visible columns, including generated columns.
Unselected cells are not evaluated or projected. Malformed column-name bytes
cause a format refusal when all columns are requested. In inventory scope, an explicit valid subset can
still be sampled without decoding unrelated malformed column names.
Column selection requires a
Unselected cells are not evaluated or projected. Column selection requires a
table and at least one name; empty-string identifiers are valid. `row_limit`
requires `table`, defaults to 20 and accepts positive safe integers. Samples
remain subject to the byte and worker resource limits below, regardless of row count. The result reports
@@ -108,20 +105,6 @@ overall native heap and total resident memory are not capped. Row limits do not
override these byte and resource limits. Resource-limit failures do not return
an incomplete schema as successful complete evidence.
If the combined database and WAL exceed the snapshot budget, the refusal is a
`resource_constraint` and reports both the configured byte limit and the exact
observed combined size as a decimal string. The remediation directs callers to
create a smaller consistent offline snapshot containing only relevant data
through the application's supported export workflow. A generic backup or copy
does not guarantee a smaller result; REA does not truncate or modify the
selected source.
On hosts that cannot address the derived WAL or rollback-journal path for a
long selected database name, REA reports that the SQLite capability is
unavailable. It does not assume an inaccessible sidecar is absent. Use the
application's supported consistent offline export or copy workflow to place
the complete known file set at a shorter path.
MCP also applies its configured response budget to the complete Evidence
envelope. If delivery exceeds that budget, it reports a transport constraint
with guidance for exporting retained Evidence, requesting a matching larger
+7 -162
View File
@@ -110,14 +110,9 @@ rendered declarations. Keep canonical rejection checks separate from the
intentionally reduced compact advertisement, and probe actual client renderers
when changing schema representations.
The reused CLI boundary workers cap V8 old space at 384 MiB for ordinary runs
and 512 MiB with coverage enabled. Covered ADB fixtures exhaust the ordinary
384 MiB budget; those fixtures also complete with the shared CLI graph preloaded
at 512 MiB. This is a measured capacity control, not a suite-wide speedup claim.
Both profiles keep the
same bounded worker count, and spawned REA processes retain their own heap
settings. Explicitly disabling coverage retains the ordinary profile; coverage
provider options alone do not enable instrumentation.
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
@@ -204,121 +199,6 @@ Measure slow cases before pruning capacity coverage. Retain inputs beyond the
formerly failing size/depth and distinguish cold runs, warm builds, coverage,
and toolchain conditions when comparing timings.
## Lifecycle regressions
For changes to resource acquisition, readiness, cancellation, or cleanup, select
the affected owners and applicable scenarios below. Include temporary snapshots
and one-shot commands. Use public CLI/MCP workflows where practical and a
controlled production seam for interleavings that cannot be reproduced reliably.
| Scenario | Assertion and control |
| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Target admitted; startup still pending | Status preserves the readiness distinction and observed startup activity; readiness requires the provider's documented proof. |
| First handshake is late, absent, invalid, or recovered during close | Initial and recovery paths retain the same authenticated identity facts. Foreign run/token controls cannot authorize cleanup; authenticated idle/native work survives the unauthenticated listener deadline. |
| Launch returns an error with a valid process handle | Cover already-exited and still-live owned processes. Verify observed exit separately from creation; failed termination or unavailable identity remains unresolved. |
| Cancellation arrives after workload exit, during result reads or temporary-root removal | Return typed cancellation with available partial observations and actual cleanup status. The non-aborted control succeeds; existing primary/cleanup failures keep their precedence. |
| Children have mixed health or cleanup outcomes | Missing peer health does not erase an observed failure or activity. Idle plus unknown stays unknown. Retry a failed child without closing a successful peer again, including after a close-option change. |
| Cleanup fails after success or primary failure | Public output retains the completed observation or primary diagnostic, remaining resources, and owner recovery action. Restore the denied resource and verify the owning cleanup retry. |
| Target exits without an acknowledgement, or transport disappears while it stays alive | Positive owned exit proof resolves target lifetime; other resources still need cleanup. Lost transport alone does not prove exit. Verify unrelated/attached targets survive and same-connection recovery works when supported. |
Shared process-supervision controls separate leader exit from output closure.
Cover output during held or failed cleanup, bounded retention and drain timeout,
retry, and borrowed stream authority. The POSIX inherited-stderr control uses a
separate pipe as a release barrier after leader exit; it does not establish
native Windows Job Object behavior.
Synchronize cancellation with the finalization boundary being tested; a fixed
delay after dispatch does not establish that phase. Use markers, barriers, or
owned cleanup seams while preserving real cleanup where feasible. Check server
settlement and retained resources even if the MCP SDK rejects the client promise
before the handler finishes. A cancellation during active execution does not
cover cancellation during final cleanup.
Use explicit abort reasons and assert their identity at admission and after
provider completion, alongside retained observations and cleanup state.
Electron fuse regressions cover actual descriptor close denial and retry through
the built CLI, same-connection MCP recovery, mixed descriptor outcomes, and
server shutdown. Controlled seams cover cancellation during final close and
after reader finalization, plus active-provider shutdown during preflight.
They preserve real filesystem cleanup where possible; mocked launch boundaries
do not establish real Electron teardown or naturally occurring OS failures.
Active Electron cleanup controls retain independent transport and process-family
owners, block replacement captures until recovery, and retry only unresolved
owners. Cover late close acknowledgement and rejection after a wait deadline,
opaque rejection reasons, cancellation during failed finalization, and missing
lineage followed by a confirmed passive family census. Windows controls require
a fresh lineage observation and do not signal cached descendant PIDs after root
termination. Simulated Windows controls do not establish native Windows behavior.
For atomic writes, exercise cancellation on both sides of the documented commit
point and preserve any publication receipt. A late interruption does not prove
that no output was published.
For successful provider reports, test cancellation immediately before the report
reaches the application workflow as well as during provider cleanup. Validate
the report before classifying completion: a valid report must retain its Evidence
on cancellation, and an invalid report must keep its output error. Exercise both
the provider boundary and the shared CLI/MCP workflow; a downstream guard does
not repair the provider's own completion contract. When callers share startup,
cancel each waiter independently and verify that the last departure awaits owned
cleanup while interested peers can still reach readiness. Repeat the same
shutdown event after a cleanup failure to verify that its listener can retry.
Exercise non-default lifecycle deadlines through queued requests and their
consumers; default-only controls cannot detect dropped request options.
For descriptor-backed reads, inject a close failure after a successful read and
after a primary read or cancellation failure. Verify that the exact descriptor
remains owned, both failures survive, and a later close retries it. Repeat
admission attempts while close still fails: no additional descriptor or
native command should start. Restore close and verify that the exact owner
resolves the originating cleanup marker and allows later work, while the earlier
failure remains available as a diagnostic. Retain errors returned by multiple
failed retries, including admission and shutdown aggregates, and assert that
each becomes complete after recovery. For an aggregate with multiple owners,
release one owner while another still fails and assert that it remains incomplete.
Cover recovery before the
caller-specific error is bound to its retained owner, as
another request can retry cleanup concurrently. Confirm that an already released
owner resolves a later binding too. Include
admission failure after opening the descriptor. If caller cancellation returns
before an inspection settles, gate its final read or close and verify that
session shutdown waits for the owned work and reports any retained resources.
Gate a later read in a multi-read inspection, not only its first read. Overlap
operations so one retains a failed descriptor while another reaches its next
read; both the operation and shutdown must settle without nested-admission
deadlock. Deny child close and verify its containing root survives until retry.
Exercise publication on filesystems without hard links using an unsupported-link
seam. Check exclusive destination creation, stat/write/close failures, completed
output receipts, and cancellation at the documented cutoff. A streamed fallback
has different visibility from an atomic hard-link commit and must report it
accurately. For Windows command supervision, keep a descendant writing after its
leader exits, deny cleanup observation, and verify a competing writer remains
excluded until the exact Job Object closes. Portable doubles cover retry logic;
the native Windows lane must establish actual process-tree behavior.
Supervisor tests must observe process exit, output-pipe closure, and IPC
disconnection separately. In the pinned Node runtime, a parent-initiated IPC
disconnect can omit the aggregate `ChildProcess` close event. Join the actual
resource observations before reporting completion; process exit alone does not
establish pipe or process-tree release.
When changing an internal helper contract, check its JavaScript verifier and
subprocess-script consumers alongside TypeScript references. Source typecheck
does not check those calls; run their orchestration tests against the built
modules, including the verifier's failure and cleanup paths.
Representative regressions include
[process cleanup-time SIGINT](https://github.com/morluto/rea/blob/e78455338fe2d06c4cd03d59cbf33473d754998b/tests/boundary/process/processCaptureCancellationAdapters.test.ts),
[late authenticated cleanup](https://github.com/morluto/rea/blob/e78455338fe2d06c4cd03d59cbf33473d754998b/tests/boundary/providers/hopper/hopperClient.handshakeRecovery.test.ts),
[LLDB launch and finalization](https://github.com/morluto/rea/blob/e78455338fe2d06c4cd03d59cbf33473d754998b/tests/boundary/providers/native/lldbCallTracerFailures.test.ts),
[composed child ownership](https://github.com/morluto/rea/blob/e78455338fe2d06c4cd03d59cbf33473d754998b/src/application/binary/CompositeProvider.test.ts),
and [public CLI cleanup denial](https://github.com/morluto/rea/blob/e78455338fe2d06c4cd03d59cbf33473d754998b/tests/boundary/cli/wasmCleanupCli.test.ts).
These controlled probes do not replace the matching real-provider lane. Record
the base failure, passing control, exact host/provider, verified cleanup, and
unavailable coverage; a missing engine is not a pass.
## Behavioral depths
| Depth | Location | What it proves |
@@ -529,7 +409,7 @@ costs. Its queue, execution, and failures are independent of the required gate
and publication. CPU time and peak process-family memory are not measured by this API.
The build job saves portable Turbo outputs across runs. Eight Linux real-system
lanes reuse its current-run artifact; standalone dispatches restore the cross-run cache. The shared action
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, `.npmrc`, `.nvmrc`, and the lockfile; test-only changes can reuse compiled outputs. Every
build and verification command still runs, so Turbo checks task inputs and
@@ -539,15 +419,7 @@ that generator's entry. Native outputs are not stored in this cache.
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 key parser retains the validated `test:prepare` task identities in
`.cache/ci-build-plan.json`; staging reads this plan without starting another
Turbo run that could evict cache entries. The producer stages matching archives,
metadata, and available manifests into `.cache/ci-build-cache/`.
`portable-build-cache.json` records availability per task. Evicted or partially
missing entries are omitted as whole entries, and consumers rebuild cache misses,
including when every entry is unavailable. Malformed plans, non-file entries,
and I/O errors other than disappearance still fail publication. Older cross-run entries stay in the
original cache. The Windows lane relies on the Linux static job for typechecking. They retain the normal build and prepack
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.
@@ -1010,16 +882,6 @@ and runtime cleanup. Windows additionally requires the matching native addon;
its verifier lineage remains explicitly unavailable outside the provider's
retained Job Object, as in the other Windows lanes.
`npm run verify:ghidra:m68k` needs no assembler: its 22-byte big-endian 68000
fixture is source-owned annotated hex in the verifier, loaded at `0x1000`. With
an installed Ghidra 12.1.4 and full JDK on Linux or macOS, it verifies the
`68000:BE:32:default` BinaryLoader import, real CLI/stdio MCP load-image parity,
exact source bytes, both functions, the `bsr.b` call reference, decompilation
through address and file offset, rejection of a misaligned entry and of a mapping
past `0xffffffff` without replacing the active session, and runtime cleanup.
Windows Ghidra P0 does not admit m68k, so this is not a Windows lane. The lane
has been run on macOS; Linux has not been exercised.
`npm run verify:ghidra:raw` uses a generated ARM little-endian headerless image
through the compiled CLI and stdio MCP server. With the same Ghidra/JDK
prerequisites, it checks preparation and bridge startup, verified load mappings,
@@ -1127,19 +989,7 @@ the Apple or Windows curated lanes invoke explicitly, which also select that
lane. Edits to verifier entrypoints run only by manual, licensed or self-hosted
workflows run static checks and the Linux suite. Website changes run website
checks. Provider workflow changes validate the workflow and run that provider's
verifier. Changes under `bridge/ghidra/` also select the `ghidra_bridge` lane,
which compiles the packaged bridge sources against the pinned Ghidra 12.1.4
jars with `npm run verify:ghidra:bridge-sources`. It never launches Ghidra or
imports a target, so a missing import fails the PR instead of every Ghidra
session. The launcher, compiler and package checks share named required source
roles. The manifest must match the complete Java cohort, so deleting a helper
or adding an unregistered dependency cannot silently change the shipped set.
The preflight reuses the provider's Java Properties parser with the pinned Node
toolchain's native type stripping, without an npm install or runtime build.
The shared release policy owns the verified version and JDK major. CI checks
the archive pin before downloading and verifies the extracted SDK version;
changes to these source owners also select the compile lane.
Manual-provider/Android workflow changes run workflow validation only.
verifier. Manual-provider/Android workflow changes run workflow validation only.
The four-version SQLite compatibility matrix has its own `sqlite` scope for
SQLite implementation, contracts, CLI/MCP registration, fixtures, and shared
runtime boundaries. SQLite and server-lifecycle test edits and the SQLite npm
@@ -1570,12 +1420,7 @@ NUL-containing names. It compares exact WAT,
section output and selected/tool digests through the compiled CLI and real MCP
SDK, validates advertised schemas, checks identical CLI/MCP Evidence IDs and
session bundle readback, retains invalid/truncated module diagnostics, preserves
all inputs and checks workspace cleanup.
The lane also injects one cleanup denial for exact private runtime roots and
input descriptors, checks recovered CLI errors, and verifies retry on the same
MCP connection after repeated runtime-removal denial. These are controlled
faults, not naturally occurring permission failures; no WASM target is executed.
Pass an installed package's
all inputs and checks workspace cleanup. Pass an installed package's
`scripts/rea.mjs` as the first argument to run the same lane against the package.
`npm run verify:wasm:package` packs and installs REA into an isolated temporary
prefix with lifecycle scripts disabled and runs the same required real-tool lane.
-94
View File
@@ -68,100 +68,6 @@ satisfy. A plan without execution does not establish runtime behavior.
constraints. Report pagination, truncation, cancellation, and partial failure.
An assumed agent budget is insufficient justification for a limit.
## Own the lifecycle
For tools that acquire resources, identify the owner and the observations that
establish each transition. Include temporary files and one-shot commands, as
well as persistent engine sessions. Use the existing provider contracts;
providers need not expose identical state machines.
- Keep target admission, provider readiness, active work, observed process exit,
and resource release separate. A valid process handle, successful launcher,
or selected target establishes only its own fact. Publish available identity
and exit observations even when launch fails; retain unknown ownership.
- Process exit does not establish output closure. The shared process supervisor
retains at most 64 KiB of additional diagnostics from owned stop entry,
including pending cleanup and retries, and drains for up to one second after
verified stop. It marks output incomplete when closure cannot be
observed and releases owned event-loop references without changing the proven
process-cleanup outcome. Failed process cleanup retains capture for retry;
borrowed processes and streams retain their own lifetime and reference state.
- Authenticate and capture identity through the same boundary on initial and
recovery handshakes. Bound abandoned unauthenticated listeners where the
protocol permits it; that deadline must not expire authenticated idle sessions
or long-running native work. Listener expiry does not prove target closure.
- Readiness observations may await owned prerequisite commands. Status must
remain readable during owner finalization without starting replacement work;
report readiness as unknown when it cannot be re-observed.
- Shared startup has one producer and independently cancellable caller waits.
Keep it running while any caller still needs it. The final departing caller
waits for owned cleanup and retains its failure. Provider closure is distinct
from caller cancellation. Retained cleanup capabilities block replacement;
derive readiness from the current startup's completion and live connection.
- For cancellable observations, carry cancellation through result consumption
and awaited cleanup. Before returning success, check the signal after the
last awaited finalization step.
Retain collected observations under typed cancellation. Preserve an existing
primary failure and let incomplete cleanup retain its own classification.
Preserve the caller's abort reason as the typed cancellation error's cause,
including when cancellation is observed only after provider completion.
Shared command owners must retain the observed cancellation reason separately
from physical failures and cleanup ownership. Carry that fact through failure
wrapping so adapters can preserve the exact reason without interpreting it.
Client cancellation alone does not prove native work stopped.
For atomic publication, document the cancellation cutoff and preserve any
committed output's publication receipt.
Queued and retried work must retain the complete accepted execution controls,
including non-default lifecycle deadlines and cancellation signals.
- Release only owned resources. Attaching owns a connection or session unless
the provider contract explicitly establishes target ownership. A helper exit,
missing reply, or missing PID does not establish target exit.
- Retain successful child cleanup and retry only unresolved children, including
when close options change. Preserve observed child failure or activity when
another child's health is unavailable; idle plus missing coverage stays
unknown.
Bind cleanup failures to their exact resource owner. Resolve current cleanup
uncertainty only after that owner confirms release, while preserving the
original failure and completed observations. Later failure composition must
report only resources whose cleanup remains unresolved. Carry cleanup
capabilities explicitly in typed outcomes so consumers can bind returned errors
to exact owners without reparsing diagnostic cause chains.
Bind every caller-visible retry error and aggregate, including an error already
produced by the provider. An aggregate remains incomplete until all owners it
reports are released; releasing one child cannot clear another child's status.
- Await one-shot cleanup without discarding the completed result or primary
diagnostic. Preserve partial observations, remaining resources, and the cleanup
owner's recovery instructions. CLI adapters should reuse
[`finishAnalysisCommand`](https://github.com/morluto/rea/blob/main/src/cli/finishAnalysisCommand.ts) where its contract
applies rather than duplicate close/finally handling.
- Give descriptor-backed reads an owner before opening the file. A rejected
close must retain the exact handle and preserve any earlier failure. If an
abortable caller stops waiting, keep the underlying work in that owner's
lifetime so shutdown cannot report release before finalization settles.
Admit the entire inspection once, including later reads and finalization.
Helpers must borrow that admission or use an operation child scope; re-entering
the same draining scope can make cleanup wait for its own caller.
Retry retained cleanup before admitting new work and keep admission blocked
while it remains unresolved. Link the originating cleanup error to its exact
owner so confirmed release resolves its cleanup marker while preserving the
earlier diagnostic. Shared CLI/MCP adapters cannot infer that confirmation.
- Provider profile selection owns every asynchronous candidate through its
terminal result and finalization. The registry owns profile-file cleanup,
joins all automatic-selection children, and closes those file owners before
reporting candidate shutdown. Final caller cancellation joins the selection;
an adapter that ignores cancellation remains active and owned until it settles.
Block new admission during shutdown and while cleanup remains unresolved;
reopen after confirmed retry. Preserve failed results before considering a
later signal, and retain every child's attributed cleanup in mixed outcomes.
- Release child descriptors before removing their containing root. Retain a
composite owner when either stage fails so retry preserves that ordering.
A Windows command leader's exit does not establish Job Object closure. Keep
the process-tree observer and command lock alive through failed cleanup retries
until the owned tree's close event.
Exercise the applicable [lifecycle regression scenarios](testing.md#lifecycle-regressions)
through the producing owner and affected CLI/MCP consumers.
## Implement and evaluate
Put provider protocols/parsing in adapters and shared CLI/MCP workflows in the
+2 -2
View File
@@ -43,7 +43,7 @@ harm_rank,location,trigger,current_copy,user_risk,proposed_replacement,implement
31,src/application/ReferenceSourceImportTypes.ts:limit,Import reports terminal limit failure,No reachable constructor found,Declared state may be unreachable; false verification risk,Remove unreachable top-level limit variant; per-entry limit guidance remains caller-visible.,removed,"verified by typecheck, exhaustive projection test, and source search"
32,src/application/Setup.ts:configureDetectedClients(backup),Agent configuration backup fails,"{clientName} configuration backup verification failed; no successful configuration was reported.",Exposes machine client key and obscures no-write guarantee,"Agent configuration could not be backed up, so no change was made. Check file permissions, then rerun setup.",implemented,focused assertions passed
33,src/application/Setup.ts:configureDetectedClients(write),Agent configuration write fails,"{clientName} configuration write verification failed; no successful configuration was reported.",Exposes machine client key and gives no recovery,"Agent configuration could not be updated. Check file permissions, then rerun setup.",implemented,focused assertions passed
34,src/application/Setup.ts:configureDetectedClients(readback),Written agent configuration cannot be verified,"{clientName} configuration readback verification failed; no successful configuration was reported.",Exposes machine client key and omits backup recovery,"Agent configuration could not be verified after writing. The original was restored and its backup at {backupPath} was retained. Repair the configuration file or restore that backup, then rerun setup. Without a backup: Agent configuration could not be verified. Repair the configuration file, then rerun setup.",implemented,focused assertions passed
34,src/application/Setup.ts:configureDetectedClients(readback),Written agent configuration cannot be verified,"{clientName} configuration readback verification failed; no successful configuration was reported.",Exposes machine client key and omits backup recovery,"Agent configuration could not be verified after writing. Repair the configuration file or restore its `.rea.backup`, then rerun setup.",implemented,focused assertions passed
35,src/application/Setup.ts:installSkill,Skill install or semantic readback fails,Agent skill installation or readback failed.,No useful recovery action,"REA analysis skill could not be installed or verified. Check permissions for `~/.agents/skills`, then rerun setup.",implemented,focused assertions passed
36,src/main.ts:serveStdio.onerror,Established MCP client connection reports an error,MCP stdio transport error,Exposes transport implementation and gives no recovery,REA lost its MCP client connection. Restart REA from your MCP client.,implemented,verified by injected transport onerror runtime test
37,src/main.ts:serveStdio throw,MCP connection cannot be created,Failed to start MCP stdio transport,Exposes transport implementation and gives no recovery,REA could not start its MCP connection. Restart REA from your MCP client; run `rea doctor` if it fails again.,implemented,verified by injected transport startup-throw runtime test
@@ -55,7 +55,7 @@ harm_rank,location,trigger,current_copy,user_risk,proposed_replacement,implement
43,src/application/Uninstall.ts:removeClient parse,Agent configuration is malformed,Malformed configuration was preserved without mutation.,Does not name required repair format or retry,"Configuration is not valid JSON/TOML and was not changed. Repair it, then rerun uninstall.",implemented,focused JSON assertion passed; TOML path uses same branch
44,src/application/Uninstall.ts:removeClient backup,Configuration backup copy fails,Configuration backup failed; no mutation was attempted.,No recovery step,"Configuration could not be backed up, so no change was made. Check file permissions, then rerun uninstall.",implemented,verified by injected filesystem backup failure test
45,src/application/Uninstall.ts:removeClient update,Write or semantic readback fails,Configuration update failed; the original was restored and {backupPath} was retained.,Exposes local path and lacks clear next sequence,"Report whether the original was restored; if restoration also fails, direct the user to the retained backup.",implemented,verified by injected update and restoration failure tests
45.5,src/application/Uninstall.ts:removeClient restore,Configuration update fails and restoring the original also fails,"Configuration could not be updated or restored. Restore the backup at {backupPath} manually, then rerun uninstall.","High risk; persistent configuration may be damaged, but retained backup is authoritative",Keep new recovery copy,implemented,verified by injected restoration failure test
45.5,src/application/Uninstall.ts:removeClient restore,Configuration update fails and restoring the original also fails,"Configuration could not be updated or restored. Restore its `.rea.backup` manually, then rerun uninstall.","High risk; persistent configuration may be damaged, but retained backup is authoritative",Keep new recovery copy,implemented,verified by injected restoration failure test
46,src/application/Uninstall.ts:removeManagedPath symlink,Managed cache/state/skill path is a symbolic link,Refused to follow symlink {path}.,Exposes local path and does not explain manual safety check,"REA did not remove this item because its managed path is a symbolic link. Verify the link target before removing it manually.",implemented,focused assertion passed
47,src/application/Uninstall.ts:removeManagedPath failure,Managed item removal fails,{path} could not be removed.,Exposes local path and gives no recovery,"This item could not be removed. Check file permissions, then rerun uninstall.",implemented,verified by injected managed-path removal failure test
48,src/application/DoctorDiagnostics.ts:node,Runtime version is outside supported ranges,"Install Node.js 22.x (>=22.19), 24.x (>=24.11), or 26+.",Low risk; exact dependency recovery,Keep current copy,unchanged,verified by doctor unit test
1 harm_rank location trigger current_copy user_risk proposed_replacement implementation_status verification_result
43 31 src/application/ReferenceSourceImportTypes.ts:limit Import reports terminal limit failure No reachable constructor found Declared state may be unreachable; false verification risk Remove unreachable top-level limit variant; per-entry limit guidance remains caller-visible. removed verified by typecheck, exhaustive projection test, and source search
44 32 src/application/Setup.ts:configureDetectedClients(backup) Agent configuration backup fails {clientName} configuration backup verification failed; no successful configuration was reported. Exposes machine client key and obscures no-write guarantee Agent configuration could not be backed up, so no change was made. Check file permissions, then rerun setup. implemented focused assertions passed
45 33 src/application/Setup.ts:configureDetectedClients(write) Agent configuration write fails {clientName} configuration write verification failed; no successful configuration was reported. Exposes machine client key and gives no recovery Agent configuration could not be updated. Check file permissions, then rerun setup. implemented focused assertions passed
46 34 src/application/Setup.ts:configureDetectedClients(readback) Written agent configuration cannot be verified {clientName} configuration readback verification failed; no successful configuration was reported. Exposes machine client key and omits backup recovery Agent configuration could not be verified after writing. The original was restored and its backup at {backupPath} was retained. Repair the configuration file or restore that backup, then rerun setup. Without a backup: Agent configuration could not be verified. Repair the configuration file, then rerun setup. Agent configuration could not be verified after writing. Repair the configuration file or restore its `.rea.backup`, then rerun setup. implemented focused assertions passed
47 35 src/application/Setup.ts:installSkill Skill install or semantic readback fails Agent skill installation or readback failed. No useful recovery action REA analysis skill could not be installed or verified. Check permissions for `~/.agents/skills`, then rerun setup. implemented focused assertions passed
48 36 src/main.ts:serveStdio.onerror Established MCP client connection reports an error MCP stdio transport error Exposes transport implementation and gives no recovery REA lost its MCP client connection. Restart REA from your MCP client. implemented verified by injected transport onerror runtime test
49 37 src/main.ts:serveStdio throw MCP connection cannot be created Failed to start MCP stdio transport Exposes transport implementation and gives no recovery REA could not start its MCP connection. Restart REA from your MCP client; run `rea doctor` if it fails again. implemented verified by injected transport startup-throw runtime test
55 43 src/application/Uninstall.ts:removeClient parse Agent configuration is malformed Malformed configuration was preserved without mutation. Does not name required repair format or retry Configuration is not valid JSON/TOML and was not changed. Repair it, then rerun uninstall. implemented focused JSON assertion passed; TOML path uses same branch
56 44 src/application/Uninstall.ts:removeClient backup Configuration backup copy fails Configuration backup failed; no mutation was attempted. No recovery step Configuration could not be backed up, so no change was made. Check file permissions, then rerun uninstall. implemented verified by injected filesystem backup failure test
57 45 src/application/Uninstall.ts:removeClient update Write or semantic readback fails Configuration update failed; the original was restored and {backupPath} was retained. Exposes local path and lacks clear next sequence Report whether the original was restored; if restoration also fails, direct the user to the retained backup. implemented verified by injected update and restoration failure tests
58 45.5 src/application/Uninstall.ts:removeClient restore Configuration update fails and restoring the original also fails Configuration could not be updated or restored. Restore the backup at {backupPath} manually, then rerun uninstall. Configuration could not be updated or restored. Restore its `.rea.backup` manually, then rerun uninstall. High risk; persistent configuration may be damaged, but retained backup is authoritative Keep new recovery copy implemented verified by injected restoration failure test
59 46 src/application/Uninstall.ts:removeManagedPath symlink Managed cache/state/skill path is a symbolic link Refused to follow symlink {path}. Exposes local path and does not explain manual safety check REA did not remove this item because its managed path is a symbolic link. Verify the link target before removing it manually. implemented focused assertion passed
60 47 src/application/Uninstall.ts:removeManagedPath failure Managed item removal fails {path} could not be removed. Exposes local path and gives no recovery This item could not be removed. Check file permissions, then rerun uninstall. implemented verified by injected managed-path removal failure test
61 48 src/application/DoctorDiagnostics.ts:node Runtime version is outside supported ranges Install Node.js 22.x (>=22.19), 24.x (>=24.11), or 26+. Low risk; exact dependency recovery Keep current copy unchanged verified by doctor unit test
File diff suppressed because it is too large. Load diff
@@ -1,158 +0,0 @@
# Electron cancellation verification, 2026-10-16
[#4388](https://github.com/morluto/rea/issues/4388), existing
[#4387](https://github.com/morluto/rea/pull/4387), umbrella
[#4027](https://github.com/morluto/rea/issues/4027).
The cancellation boundaries and retained cancellation cause are verified below.
The complete real Linux Joplin workflow remains **partial or failed** because
process ownership/cleanup cannot be verified. Publishing a typed reply, exiting
the CLI, and cleaning up its application are separate observations.
## Source and deterministic regressions
Latest-main control is `fe2a398dd9ab290ba6cb3411403d319cec8d07a2`.
The existing reviewed PR head `af732dd8` was integrated with that main in
`3b094802a`. Its initial 47 focused cases passed. An unrelated compact-catalog
test hit its unchanged 10-second CI deadline; an unchanged-source job retry
passed. The original failed execution remains in CI history.
Real CLI verification exposed an introduced regression: the PR replaced an
already observed cancellation with success after the final snapshot. A later
cleanup failure then lost the cancellation category and caller reason. Two
deterministic cases reproduced this for process and transport cleanup: 20 old
cases passed and both new cases failed. Main's public reply retained category
`cancelled`; the reviewed PR returned `execution_failure` for the same kind of
cancelled wait plus incomplete cleanup.
Fix `73d4a712b` records cancellation before finalization and uses one constructor
for the early and late partial-capture errors. Cleanup failure keeps precedence,
its diagnostics and the earlier cancellation cause. Cancellation first observed
during cleanup retains the existing precedence. The fix changes the producing
outcome; no CLI/MCP projection repair or ownership-policy exception was added.
All **49 focused cases in three files** passed after the fix. Full static checks
passed: six tasks plus architecture guards. Documentation checks also passed
(six tasks, including two cached, plus five README consistency cases). One intermediate build rejected an
over-narrowed `aborted === true` comparison; the original truthiness pattern
resolved that TypeScript error before the passing build. Recorded catalog
metadata is byte-identical to main. No new tool, schema, cache or normal-case
result field was added.
## Real application observations
The unchanged official Joplin 3.7.21 ASAR is 233,575,014 bytes, SHA-256
`767df409b18effe60421fbefcca873de237c7e813eac744ecdeebbc5e825a33a`.
Acquisition is linked in the [original Joplin verification](javascript-native-handoff-identity-2026-10-15.md).
Its complete unpacked native files/assets accompany it. These trials use the
actual application with **generic Electron 44.7.0**, fresh profiles and Xvfb.
They exercise startup/cancellation, not a completed Joplin business workflow.
Frozen verifier revision `279aa29a7` records source/runtime hashes before the
final probes. The controlled cases hold a REA-side Playwright reply while the
real application runs. They do not establish a naturally occurring Joplin stall.
| Controlled condition | Observed result |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| Main: first-window reply stays pending | Still pending 20.001 s after cancellation; verifier watchdog fails |
| Fixed: same pending first-window reply | Cancellation returned in 5.658 s; cancelled action retained |
| Fixed: initial snapshot reply stays pending | Cancellation returned in 5.335 s; no invented partial snapshot |
| Fixed: final snapshot reply stays pending | Cancellation returned in 10.262 s; five-second cancellation grace expiry and initial snapshot retained |
Every fixed case preserves the `cancelled` category. Every real case still has
unverified provider cleanup and a nonzero verifier exit; these are cancellation
phase proofs, not complete runtime passes. The known Linux ownership gap is
tracked in [#4282](https://github.com/morluto/rea/issues/4282). Ownership was not
inferred from process names, PIDs or executable paths to make these tests pass.
The public CLI trials send SIGTERM after actual Joplin startup logging. Main
and the fixed version both publish `cleanup_incomplete` with category `cancelled`
and a cancelled action. The fixed reply was observed about 5.268 s after SIGTERM
(50 ms polling resolution). Both fail the verifier's 20-second first-signal exit
deadline and require a second, explicitly recorded recovery signal. The resulting
143 exit is not proof that the first signal completed cleanup.
The official packaged Joplin executable also passed static fuse admission, but
its initial Inspector evaluation failed with a destroyed execution context before
the cancellation condition was reached. Those attempts remain failed diagnostics;
they establish no bundled-runtime compatibility or cancellation result.
## Costs, limits and reproducibility
Costly operations run serially on one CPU 10 with an 8 GiB hard limit, 6 GiB
early stop, no swap and 192 tasks. The passing static gate used 153.534 s wall,
152.274161 family CPU seconds and 6,442,016,768 peak cgroup bytes. It reported
no OOM and verified payload cleanup. Cgroup memory includes file cache, not RSS.
Other trials' exact counters and failures are preserved in the
[compact record](electron-cancellation-2026-10-16.json).
Payload-exit counters are collected while the observer remains alive and are
not final whole-scope counters. Some failed probes retain live app/Xvfb processes
at that point. Every recorded scope was independently confirmed inactive/dead
after the external owner stopped it. That recovery does not establish successful
provider cleanup.
OS/build caches are uncontrolled. A timed-out baseline and a partial fixed
workflow do not establish a completed-task speedup. Live event sets also differ,
so reply-size differences do not establish token savings. Model billing, peak
agent context and complete host/tool-schema token costs are unmeasured. Historical
diagnostic helper hashes were not captured at execution; the record marks that
gap instead of assigning the later frozen hash to earlier runs.
Build each pinned checkout, then run under the existing
[resource observer](../../experiments/analysis-efficiency/resource-counters.md)
and a private Xvfb instance. The shared verifier supports all four named cases:
```sh
node experiments/analysis-efficiency/electron-cancellation.mjs \
--runtime-root /absolute/pinned-checkout \
--executable /absolute/electron-44.7.0/electron \
--application /absolute/Joplin/resources/app.asar \
--profile-root /absolute/temporary-profile-parent --case window-wait
```
Use `initial-state`, `final-state` or `normal-wait` for the other boundaries.
The public CLI probe has no injected stalled reply:
```sh
python3 experiments/analysis-efficiency/joplin-cli-cancellation.py \
--node /absolute/node-24.18.0/bin/node --runtime-root /absolute/pinned-checkout \
--executable /absolute/electron-44.7.0/electron \
--application /absolute/Joplin/resources/app.asar \
--profile-root /absolute/temporary-profile-parent
```
The scripts return failure rather than claiming complete cleanup when the real
owned app remains unresolved. App binaries, extracted runtimes/profiles and raw
large output are regenerable and are not committed. No macOS, Windows, full
Joplin GUI or live-model success is claimed.
## Review follow-up: verifier exit semantics
Review of `beb4a47db` found a verifier false pass: the shared probe could exit
successfully once its main process had exited even though provider cleanup was
still unverified. The CLI probe also accepted `cleanup_incomplete`. Those are
verifier bugs; they do not invalidate the recorded failed Joplin trials above.
Revision `227217ac3` requires verified provider cleanup in both probes and the
public `cancelled` category in the CLI. Six controlled oracle cases cover an
exited main process with incomplete cleanup, complete cleanup, transport failure
after process cleanup, and a wrong public category. Both old scripts fail these
regressions; the fixed scripts pass all six. These cases substitute provider/CLI
replies and do **not** establish real-provider compatibility or performance.
The fixed, frozen scripts were then rerun on the same real Joplin artifact. The
shared window-wait probe retained cancellation in 5.577 s and explicitly failed
because cleanup remained unverified. The public CLI retained category `cancelled`
and a cancelled action, published its reply about 6.335 s after SIGTERM, and
again failed the first-signal exit deadline. Both verifiers exited nonzero; their
externally owned scopes were stopped separately. Production source and the
earlier historical records are unchanged. The compact record appends these
observations under `review_followup`.
Run the controlled oracle regressions separately from the real-app commands:
```sh
python3 experiments/analysis-efficiency/electron-cancellation-oracles.py \
--node /absolute/node-24.18.0/bin/node
```
File diff suppressed because it is too large. Load diff
@@ -1,592 +0,0 @@
# Electron IPC listener verification, 2026-10-16
[#4390](https://github.com/morluto/rea/issues/4390), existing
[#4389](https://github.com/morluto/rea/pull/4389), umbrella
[#4027](https://github.com/morluto/rea/issues/4027).
All 73 IPC boundary regressions pass, alongside shared projection/actions and
converted MCP schema checks. Real draw.io operation phases succeed.
Every real capture still **fails overall provider cleanup**. These are distinct
results; neither completed-task acceleration nor token savings is established.
## Producing boundary and regressions
The existing PR `efd452948` was integrated with main `180ba03bf` in `5c3b02468`.
It fixes removal through the caller's original function and duplicate recording
of `once` invocations. Independent review found two further producing-boundary
problems: wrapper recognition evaluated caller `.listener` getters, and a copied
`removeAllListeners` snapshot loop differed from native live-array traversal when
removal observers prepended a listener.
Both new differential cases failed on that implementation (14 passed, two
failed). Fix `3c330f259` delegates traversal to Node, translating only owned `on`
wrappers at `removeListener`, and preserves the `off` alias. Descriptor reads
avoid evaluating getters. A further Proxy case exposed that descriptor reflection
can itself run a trap (16 passed, one failed); `2fb7f5523` uses Node's Proxy
identity first and removes the superseded catch. Those initial **17 cases** pass;
the later decorator finding and final 23-case validation are recorded below.
The native EventEmitter controls are semantic regressions, not real-app proof.
The change uses weak wrapper keys, removes the copied traversal and its snapshot
allocation, and adds no tool, cache, schema or normal reply field. Related
compiled provider/service modules and catalog metadata were byte-identical to
baseline main `180ba03bf` at the initial source freeze. This does not prove
arbitrary function introspection equivalence: custom
`.listener` properties and raw wrapper re-registration retain the limitations
documented in [Electron observation](../electron-observation.md).
## Unchanged real application and observed scenario
Official [draw.io Desktop 32.4.1](https://github.com/jgraph/drawio-desktop/releases/tag/v32.4.1)
AppImage SHA-256 is
`c687a9f1ddcaa146b78547452d264c03c2afcf125639cba5deeb65f3e9554c9e`;
both the release asset digest and published checksum file match. Its unchanged
62,941,673-byte ASAR is
`e64b9650c0b8241ca9a7d33b56386a385bceee63270cec701d3a467347b697e6`.
Complete accompanying resources were extracted; no application source was edited.
Public fuse inspection reports the official executable's Inspector fuse disabled.
No vendor Inspector attempt was made. The following trials explicitly select
generic Electron **44.7.0**, Xvfb and fresh profiles; they establish no packaged
runtime compatibility.
The real renderer initially displays an **Invalid file data** dialog. A public
CLI startup smoke and independent DOM/argv probes preserve this failure, tracked
separately in [#4494](https://github.com/morluto/rea/issues/4494). Its exact cause
is not proven. Two attempts to click a palette item without handling the dialog
timed out and were cancelled; they remain failed diagnostics. An initial helper
also incorrectly queried `application.process()` after transport closure; the
corrected helper retains the original ChildProcess handle instead.
The final scenario uses declared REA clicks to dismiss that actual error and
insert a visible palette item, then waits for rendering. Independent DOM reads
confirm SVG elements **0 → 2**, disappearance of the error and the real unsaved
changes indicator. The verifier exercises the real app callbacks and channels;
the production hook wraps their registration as described above.
The source also registers `app-load-finished` through both `once` and `on`;
recording its once callback twice adds a spurious event.
## Initial fixed-source ABBA observations
Verifier/source revision is `d02cc934c`; its hashes were recorded before all four
trials. Baseline is main `180ba03bf`. The same script, runtime, artifact and
declared actions run in the order baseline, candidate, candidate, baseline.
| Variant/run | IPC events | `app-load-finished` | SVG change | Pipeline wall s | Family CPU s | Peak cgroup bytes |
| ----------- | ---------- | ------------------- | ---------- | --------------- | ------------ | ----------------- |
| Baseline 1 | 8 | 3 | 0 → 2 | 11.084 | 6.270053 | 560,615,424 |
| Candidate 1 | 7 | 2 | 0 → 2 | 11.135 | 6.395461 | 550,383,616 |
| Candidate 2 | 7 | 2 | 0 → 2 | 11.898 | 6.907123 | 525,631,488 |
| Baseline 2 | 8 | 3 | 0 → 2 | 11.469 | 6.526674 | 558,456,832 |
Every declared action completed, every insertion oracle passed, and no verifier
deadline fired. Every provider returned `cleanup_failed`; the captures remain
partial/failed, including possible dirty-editor teardown and the known Linux
ownership gap [#4282](https://github.com/morluto/rea/issues/4282). Baseline 2 also
reports Xvfb temporary-directory cleanup failure (payload exit 5). Its directory
identity was not captured; no broad path-based deletion was attempted.
Runs are serial on CPU 10 with one-CPU quota, 8 GiB hard memory, 6 GiB early
stop, no swap and 192 tasks. Counters cover the cgroup family at payload exit
while the observer remains alive; they are **not final whole-scope counters**.
Memory includes file cache, not RSS. Some scopes still contain Xvfb at that
point; all recorded scopes were later independently confirmed inactive/dead.
External recovery does not establish provider cleanup.
OS/build caches are uncontrolled; these are first/repeat fresh-process runs,
not verified cold/warm system pairs. Two samples per variant and a cleanup-bound
failed workflow cannot establish a speedup. Token billing, peak agent context,
complete schema/call costs and actual MCP-wire parity are unmeasured. Fewer
events alone do not establish lower token cost.
Full static checks passed (two tasks, no cache hits): 89.441 s wall,
88.630288 family CPU s and 4,337,172,480 peak cgroup bytes, with no OOM.
Documentation checks also passed (6 tasks plus five README consistency cases).
The [selected JSON record](electron-ipc-listeners-2026-10-16.json) retains exact
source/input identities, failed attempts, coverage, IPC and resource receipts.
Historical diagnostic helper hashes were not captured and remain explicitly
unknown; the frozen hash is not assigned to them retrospectively.
## Reproduction
Build both pinned checkouts. Under the existing resource observer and a private
Xvfb instance, use the committed helper for each runtime root in ABBA order:
```sh
node experiments/analysis-efficiency/drawio-electron-lifecycle.mjs \
--runtime-root /absolute/pinned-checkout \
--executable /absolute/electron-44.7.0/electron \
--application /absolute/drawio/resources/app.asar \
--profile-root /absolute/temporary-profiles --dismiss-error \
--selector '.geSidebar a.geItem:visible >> nth=0'
```
The helper returns failure on incomplete provider cleanup. This shared-service
probe does not establish successful public CLI/MCP workflows. App images,
extractions/profiles and full Result files are regenerable and excluded from Git.
## Review follow-up: normalization before app decorators
Fresh review of `f3bb9b9ed` found that translation inside a patched
`removeListener` happened after an application's outer decorator had already
seen the recording wrapper. Two native controls reproduced this with stable and
replaced decorators (17 passed, two failed).
`c8c494b5c` delegates the original Node traversal through a private forwarding
receiver. It shares the real emitter's live state and translates owned `on`
entries **before** invoking the current application removal method. App methods
and getters receive the real emitter; read-only method properties remain valid.
Native once entries pass unchanged. The public `removeListener`/`off` patches
are removed. Five decorator variants pass: stable, replaced, read-only, getter
and Proxy.
An additional mutation case proved that reading a changed public `.listener`
getter before delegation also changed deletion timing (22 passed, one failed).
Final source `5a094a0df` retains canonical removal targets in the weak owner
registry. Only unchanged data links are translated; changed getters run when
Node performs removal, preserving the exception and state transition. All
**23 cases** pass, including the original retention/fatal-error coverage.
The same frozen draw.io verifier was reused. The follow-up ABBA attempt ran
its first baseline, then the resource launcher refused the other three requests
because 8 GiB plus its 4 GiB host reserve was unavailable. Those are **not
executed**, with no performance measurements. The final source was separately
admitted and completed dialog recovery and insertion with seven IPC events;
overall cleanup still failed, and Xvfb teardown also returned an error. No new
completed-task speedup or cold/warm pair is claimed.
Final static checks passed: two uncached tasks, 135.173 s wall, 133.786166 family
CPU s and 4,274,634,752 peak cgroup bytes, no OOM. The JSON record appends exact
source pins, denial logs, final real-app/public cleanup diagnostics and checks
under `review_followup`; the initial records were not overwritten.
## Callback invocation and remaining raw-metadata limitation
Source `514b73b78` invokes `handle` callbacks through captured `Reflect.apply`,
preserving the receiver and actual arguments without reading an app-defined
`.call` property. The added direct-call control and hook case pass; all **24
IPC regressions** pass (3.661 s wall, 3.404 family CPU s, 318,291,968 peak cgroup
bytes, no OOM). This is a Node boundary check, not a real Electron handle claim.
An initial three-case experiment incorrectly assumed native EventEmitter avoided
callable method-property reads. Its `on` and `once` controls themselves failed;
they do not demonstrate hook regressions. The attempted intrinsic event-call
change was reverted and those invalid cases removed. Both failed runs remain
in `callable_followup`; no successful result is assigned to them.
The same unchanged draw.io verifier at this source completes actual dialog
recovery and shape insertion, with seven IPC events, SVG elements 0 → 2 and an
unsaved-changes indicator. Overall provider cleanup still fails. Pipeline wall
time is 12.610 s, family CPU 7.062834 s and peak cgroup memory 634,187,776 bytes;
there is no paired performance or token claim. All recorded scopes were later
independently inactive/dead, which does not establish provider cleanup.
Fresh review also found a distinct remaining metadata case: changing a raw
recording wrapper's writable `.listener` property can make an app decorator
reject removal. A production-hook/native-Node probe reproduces this (plain:
removed; hook: decorator throws and one listener remains). Exact reproduction
and the ownership conflict are tracked in [#4513](https://github.com/morluto/rea/issues/4513).
No affected real app has been identified. Removing the descriptor guard alone
does not make native removal match the mutated wrapper; temporarily rewriting
public app metadata would add further visible mutations. This limitation is
explicit in the observation guide and is not represented as fixed by this PR.
Current-source static checks also pass: two uncached tasks, 92.912 s wall,
92.031383 family CPU s and 4,340,375,552 peak cgroup bytes, no OOM.
## Native single/array dispatch follow-up
Fresh review of `6fc2d2769` identified that the earlier native controls covered
only one listener. Node 24.18.0 reads `.apply` during single-listener dispatch,
but invokes each callback intrinsically during array dispatch. Native `once`
uses `.call` for zero arguments and `.apply` otherwise. Unconditional `.apply`
in the observation helper changed two of those paths: a multi-listener callback
could throw before later callbacks ran, and zero-argument once read the wrong
property. Four explicit native controls reproduce two failures (26 passed,
two failed), rather than assuming all callable-property reads should disappear.
Source `e8d7e8f20` keeps one observation boundary. An `on` recording wrapper
delegates direct calls intrinsically and forwards native `.apply` calls through
its own nonenumerable method. Node selects the route; the hook does not inspect
or copy listener storage. `once` preserves its native zero/nonzero-argument
invocation. All **28 cases** pass, including the prior callback identity,
retention, reentrant-removal and fatal-error coverage. `handle` remains intrinsic.
The unchanged real draw.io verifier again completes dialog recovery and shape
insertion, with seven IPC events, SVG elements 0 → 2 and the unsaved indicator.
Overall provider cleanup still fails; no deadline fires. Its 12.290 s pipeline
run is a validation observation, not a paired performance comparison. Exact
source hashes, failures, resource measurements and post-scope states are appended
under `native_dispatch_followup`; all previous records remain unchanged.
The separate raw metadata limitation [#4513](https://github.com/morluto/rea/issues/4513)
remains open and is not represented as fixed.
Final-source static checks pass: two uncached tasks, 171.430 s wall,
169.139239 family CPU s and 4,091,392,000 peak cgroup bytes, no OOM.
## Argument-list ownership follow-up
Review of `23700fd2c` found two related representation errors. A raw callback's
`.apply` accepts Arguments objects, other array-like objects, null or omitted
argument lists; the recording helper assumed an Array. Native once also passes
its actual Arguments object to a callback-defined `.apply`, whereas the hook
passed a rest Array. Seven explicit native controls reproduce six failures
(29 passed, six failed of 35).
Source `a82d935ba` binds captured native Function apply to the method-forwarding
function. JavaScript itself converts argument lists, treats null/undefined as
empty and rejects invalid primitives before recording reads values. The
array-like getter control is read exactly once. Once retains its actual
Arguments object for invocation; recording alone takes an array slice. The
captured slice helper is bound once, avoiding an extra helper-argument array
on each invocation. No custom array-like parser or exception repair is added.
All **35 cases** pass. The same frozen real draw.io verifier again completes
dialog recovery and shape insertion with seven IPC events; no deadline fires,
and overall provider cleanup still fails. Exact source identities, both failed
boundaries, intermediate/final tests, resource costs and post-scope states are
appended under `argument_list_followup`; previous records remain unchanged.
Current-source static checks pass: two uncached tasks, 122.454 s wall,
121.287057 family CPU s and 4,185,915,392 peak cgroup bytes, no OOM.
The unchanged ASAR digest was checked again after the real-app trial.
## Owned metadata and successful-Evidence verifier follow-up
Fresh review of `41a513d99` found that `on` wrapper metadata used strict
assignment. Native on does not write such metadata, so inherited Function or
Object prototype setters/read-only fields could prevent registration only under
capture. Four native controls fail before `5dcf79f29` (35 passed, four failed).
The recording wrapper now defines its own data property directly; native once
assignment behavior is retained. All **39 cases** pass.
The verifier also incorrectly treated a successful Evidence envelope as a raw
capture. Real cleanup failures had exercised only the separate partial path.
`4a9a01f7a` reads successful `value.normalized_result` and preserves failed
`error.partialObservation.capture`. The new
`experiments/analysis-efficiency/drawio-electron-lifecycle-oracles.py` exercises
the actual verifier with controlled success, partial cleanup, action failure,
insertion failure and absent capture. The old verifier rejects valid successful
Evidence before producing a summary; all five corrected controls pass.
**These are controlled reply/exit checks, not real-provider evidence.**
The corrected verifier was separately frozen before a real unchanged draw.io
trial. Actual dialog recovery and shape insertion again complete with seven IPC
events, no deadline and failed overall provider cleanup (pipeline 12.777 s).
Success with real provider cleanup remains unverified. Earlier trials retain
their earlier verifier hashes; the corrected hash is not assigned to them.
Exact source pins, failed controls, resource costs and post-scope states are
appended under `owned_metadata_and_verifier_followup` without replacing history.
Final-source static checks pass: two uncached tasks, 99.992 s wall,
98.956939 family CPU s and 4,237,795,328 peak cgroup bytes, no OOM.
## Species-free recording and snapshot ownership
Fresh review of `e2cf2d89b` found that slicing a rest Array invokes application
`Array[Symbol.species]` before dispatch. The first control reproduced failed on
dispatch (40 passed, one failed); once dispatch already used Arguments.
Extending the check to retrieve the retained snapshot while the throwing getter
remains installed exposed the same representation problem in snapshot maps
(39 passed, two failed).
Source `3141ac3f4` records from actual invocation frames while preserving native
callback argument-list types: the method-based on path still passes an Array,
and once passes Arguments. Group validation uses the existing recording loops
without a filtered intermediate Array. Captured `Array.from` produces snapshots
without species lookup, reading dropped-counter Maps directly rather than
spreading them into another Array first. The initial **41 cases** pass, including both
live snapshots under the throwing getter with zero getter reads.
The frozen-source real unchanged draw.io operation again completes recovery and
insertion with seven IPC events, no deadline and failed overall cleanup
(pipeline 12.779 s). This does not establish that draw.io customizes species.
The corrected verifier and its five previously passing controlled oracles are
byte-identical to `4a9a01f7a`, so those unchanged oracle sources were reused.
Exact hashes, failures, resource receipts and scope states are appended under
`array_species_followup`; earlier records remain unchanged. There is no new
completed-task performance or token/context claim.
The native multiple-listener route was then included in the same live-species
control: all **42 cases** pass. Only test coverage expanded; production hook
and verifier bytes remain identical to `3141ac3f4`. Exact validation identities
and the additional result are recorded under `all_native_dispatch_paths`.
A fresh-profile real negative control omits `--selector` while retaining dialog
recovery and the same 500 ms wait. SVG elements remain **0 → 0** and unsaved
changes remain false; insertion gives **0 → 2** and unsaved true. This supports
the operation oracle rather than attributing startup rendering to the click.
The control also returns seven IPC events and failed provider cleanup. These
are different tasks, not a performance pair or a model-cell-count proof.
Final 42-case source validation includes two uncached static tasks passing in
94.234 s wall, 93.308800 family CPU s and 4,406,538,240 peak cgroup bytes,
with no OOM. These are verification costs, not an application speedup.
## Opaque apply inputs and iterator-free snapshots
Fresh review of `84d9cf5db` found two producing-boundary regressions: native
array-like conversion replaced the argument-list object before a custom
listener `.apply` received it, and `Array.from` snapshots consulted application
iterators on retained arrays/Maps. Four exact-input native controls and two
snapshot controls fail before correction (42 passed, six failed of 48).
Source `e442ca27f` forwards custom `.apply` the original receiver and method
arguments without interpreting its opaque list. Custom apply may transform
arguments or skip callback execution, so the hook emits a bounded
`ipc-observation-gap` timeline record with the known registration channel. It
does not fabricate a main-event invocation, argument shapes or callback result.
The shared result projection retains explicit uncertainty and counts dropped
gaps through existing retention. The canonical timeline enum adds that kind;
the captured-IPC subset does not. Native apply still performs its own conversion
before an actual callback frame is observed.
Snapshots now copy arrays through private null-prototype indexed views and
counters through captured native Map traversal. Neither retained buffers nor
counter Maps are exposed to application iterators; returned records and shape
arrays remain independent copies. No cache, tool or normal-dispatch metadata
is added. The raw-wrapper metadata limitation in #4513 remains unfixed.
The focused hook/projection/actions gate passes **68 cases** (48 + 4 + 16).
The separate MCP/schema gate passes **23 cases**: an actual SDK client receives
the gap alongside ordinary IPC Evidence, and Ajv2020 validates the advertised
converted output; all canonical tool schemas also pass their existing checks.
These tests use controlled providers and establish no real-provider success.
The verifier and its five controlled exit/summary oracles are hash-identical to
the earlier passing source and are reused without another redundant run.
## Unrelated CI baseline failure
CI run `38935598884` tested synthetic merge `eedae92d406015895a6d0eced5035da1b9ead07a`
(head `84d9cf5db`, base `9d940c2f2`). Two firmware cleanup tests failed; another
shard was cancelled by fail-fast. A fresh, unmodified detached checkout of that
exact base reproduces the same failures: **33 passed, two failed** in
`tests/boundary/firmware/firmwareIntegration.test.ts`. Evidence is posted on
[the PR](https://github.com/morluto/rea/pull/4389#issuecomment-6221054273) and
[existing #4475](https://github.com/morluto/rea/issues/4475#issuecomment-6221054775).
This establishes that these failures predate the Electron changes; it does not
resolve whether the firmware producer or its expectations need correction. No
firmware code or assertions are changed here, and required CI is not bypassed.
The first final-source real request fails before application launch because the
previous `/tmp` runtime is absent. It is retained as an input-resolution failure,
not a provider measurement. The cached Electron 44.7.0 archive is verified against
the official release SHASUMS256 and extracted into a new owned task directory;
its executable/archive digests are pinned before the next request. No target
source, vendor fuse or scenario success requirement is changed.
The recovered-runtime real operation completes all three declared actions:
SVG elements **0 → 2**, unsaved changes true, seven IPC events, no deadline.
Overall provider cleanup still fails. Current-source static validation passes
two uncached tasks in **94.646 s wall, 93.878644 family CPU s and 4,300,570,624
peak cgroup bytes**, no OOM. The initial static attempt's test-only SDK/Ajv type
error is retained; parsing that boundary fixes it, and 12 affected client and
projection cases pass again. `opaque_apply_and_iterator_followup` preserves all
source pins, failures, resource receipts and independently checked scope states
without replacing earlier measurements. Draw.io does not establish that real
applications exercise the synthetic custom-apply/iterator cases.
The final documentation gate also passes six tasks and five README consistency
cases. Source and unchanged ASAR hashes are checked again after validation.
## Borrowed apply receivers
Fresh review of `7541a900c` supplied the borrowed custom-method case
`raw.apply.call(g, emitter, list)`: the plain emitter runs `g`, while the hook
hard-coded its registered callback as the method receiver. The same hard-coded
receiver also affected borrowed native apply. Both native differential controls
fail before correction (48 passed, two failed of 50).
Source `da04465fe` maps only the hook wrapper itself to the original listener
when forwarding custom apply; other method receivers pass unchanged. Native
apply uses its actual receiver, preserving both ordinary wrapper recording and
borrowed-call dispatch. The hook does not fabricate a registered callback
invocation when another callable is selected. The method-forwarding boundary is
corrected directly; no new helper, state, tool or schema is added. All **70**
hook/projection/actions cases pass (50 + 4 + 16). Shared schema/client, projection
and verifier/oracle sources are byte-identical to the prior passing versions,
so their checks are reused by verified hash.
CI run `38943919946` is confirmed by the successful build checkout log and Git
parents to use merge `98c14dfc01fe4698a50eedc8b1cd1ac9cd03267d`
(head `7541a900c`, main `4838f4449`). Its fifth shard fails the same two firmware
cleanup tests as the unmodified `9d940c2f2` base control. The relevant firmware
source/test and package paths have no changes between these main revisions.
The REST PR `base.sha` remains stale at `2c7583599`; it is not used as the CI
identity. No firmware code/assertion or required-check bypass is included.
The frozen-source unchanged draw.io operation completes recovery/insertion
again with seven IPC events, SVG **0 → 2**, unsaved changes true and failed
overall provider cleanup. Pipeline: **12.038 s wall, 6.662295 family CPU s,
598,835,200 peak cgroup bytes**. This remains a partial workflow, not a speedup
claim. Final static checks pass two uncached tasks in **108.067 s wall,
106.996233 family CPU s and 4,430,647,296 peak cgroup bytes**, no OOM.
All prior measurements remain unchanged under `borrowed_apply_followup`.
The final documentation gate also passes six tasks and five README consistency
cases. Current source digests are checked again after validation.
## Listener-owner intrinsic lifetime
Fresh review of `f5b489c1b` found that late application replacement of
`Object.defineProperty` prevents the hook's new wrapper properties from being
created, while a plain native emitter still registers/invokes its callbacks.
Inspection of this same new registration/removal owner found its other late
property/constructor lookups. Seven independent native controls replace
`Object.defineProperty`, `Object.getOwnPropertyDescriptor`, `Object.create`,
`Reflect.get`, `Reflect.set`, global `Set` or global `Proxy`; each fails before
correction (50 passed, seven failed of 57). The controls include both on/once
execution and complete removal, with globals restored after the scenario.
Source `a9c5611d0` captures the owner's descriptor/property operations and private
constructors before application startup. The private receiver uses a direct
null-prototype object literal instead of looking up Object.create. All **77**
hook/projection/actions cases pass (57 + 4 + 16). Application-owned callback
methods and actual receivers retain their existing semantics. No tool, schema,
state, target authority or general-purpose hardening layer is introduced; this
is not complete JavaScript introspection equivalence. Unchanged schema/client,
projection and verifier/oracle checks are reused by verified source hashes.
The preceding CI run `38946503183` tests confirmed merge
`fcd7a9d92a2e64d6eb96d4fabfed7fc7f44b0d45` (head `f5b489c1b`, main `4838f4449`).
Its 36 jobs finish with 29 successes, the same two firmware failures causing
three failed jobs including summaries, and four fail-fast cancellations. The
fifth-shard log again names the two cases reproduced on untouched main. No
firmware code/assertions or required checks are altered.
Frozen-source real unchanged draw.io actions complete again with seven IPC
events, SVG **0 → 2**, unsaved changes true, no deadline and failed overall
provider cleanup. Pipeline wall is **11.429 s**. Observed payload-exit cgroup
counters are 6.441029 CPU s and 550,363,136 peak bytes, but the observer still
sees one additional scope descendant: **family resource observation is
unverified**, not a complete-family performance measurement. The scope is later
inactive/dead after external recovery; this does not verify provider cleanup.
No identity or cleanup cause is inferred from the remaining PID.
Final static checks pass two uncached tasks in **90.980 s wall, 90.119351 family
CPU s and 4,338,749,440 peak cgroup bytes**, no OOM. Source identities, all seven
failures and resource limitations are appended under `listener_intrinsics_followup`
without replacing any previous measurements.
The final docs gate passes six tasks and five README consistency cases; source
digests are checked again after validation.
## Private collection method lifetime
Fresh review of `e6c373d0` found that replacing `WeakMap.prototype.has` after
hook initialization still intercepts its private wrapper registry. Inspecting
the same owner found analogous get/set and visited-Set has/add lookups. All five
independent native controls fail before correction (57 passed, five failed of
62); plain EventEmitter registration, on/once calls and complete removal succeed.
Source `774ed6aa6` binds these private WeakMap/Set methods before application
startup and reuses captured Set membership for event-family classification.
One initialization-only binding helper replaces duplicated binding construction
for existing Map traversal/argument slicing too. It adds no helper argument
arrays per invocation, cache, schema, tool or target authority. Application-owned
callback methods/receivers remain dynamic. All **82** hook/projection/actions
cases pass (62 + 4 + 16). The previous seven global-binding controls also remain
green, and unchanged schema/client/projection/verifier/oracle checks are reused
by verified source hashes. Arbitrary introspection and #4513 remain unsupported.
Frozen-source unchanged draw.io actions complete again with seven IPC events,
SVG **0 → 2**, unsaved changes true and failed overall provider cleanup. Pipeline
wall **11.238 s**; observed payload-exit cgroup CPU **6.285321 s**, peak
**556,285,952 bytes**. Another scope descendant remains at payload exit, so complete-family resource observation is unverified. Later external scope teardown does not prove provider cleanup.
Final static checks pass two uncached tasks in **92.999 s wall, 92.227652 family
CPU s and 4,371,951,616 peak cgroup bytes**, no OOM. Preceding CI38949129899 checks
confirmed e6c3 + main4838, repeats the same two firmware failures and finishes
31 successful /3 failed jobs including summaries /2 fail-fast cancellations.
Sources, failures and resource limitations are appended under
`private_collection_methods_followup`; prior fields remain unchanged.
The final docs gate passes six tasks and five README consistency cases; source
digests are verified again afterward.
## Unknown listener-chain ownership
Fresh review of `0b4f2e81` found that the bounded Boolean chain test treats a
still-unexamined function as fresh when 17 app decorators hide an owned once
wrapper. Two emits then produce three invocation records for one actual once
callback. The same unknown-as-fresh error affects accessor/Proxy links. Four
native controls fail before correction (63 passed, four failed of 67); the
16-decorator boundary already passes. A deep ordinary on control confirms
missing ownership cannot justify fabricated captured IPC either.
Source `ef46b8f0b` classifies metadata as owned, unowned or unknown. Bounded-walk
exhaustion, accessor links and Proxies preserve native registration without
adding another recording wrapper. Successful unknown registrations retain a
bounded `listener-chain` gap; this is not proof of IPC delivery. An existing
inner wrapper may still report its actual once invocation. Shared native
data-descriptor parsing preserves accessor uncertainty at recognition/removal
and avoids inherited descriptor-value interpretation. The superseded Boolean
classification is removed.
The shared projection explains both gap boundaries and retention/coverage, and
an actual MCP SDK client receives custom-apply and listener-chain gaps alongside
ordinary IPC Evidence, validated by its converted advertised schema. All **96**
hook/projection/actions/MCP cases pass (67 + 5 + 16 + 8). A test-only lint length
failure is corrected by generating repeated fixture rows from one table without
relaxing rules; all **13** affected client/projection cases pass again. The
canonical schema and unchanged verifier/five controlled oracle sources retain
their earlier passing checks by verified hashes; the changed projection/client
are freshly tested rather than claimed unchanged.
Prior CI run `38951509761` uses confirmed merge
`fa090a6bde3a5dadeb71066824477292520fb43b` (0b4f + mainf31b231a). All **36 jobs
succeed**. The earlier unrelated firmware failures do not recur in this
combination; their cause is not inferred or claimed fixed here. Current-source
CI/review remain required. No firmware code/assertions were modified.
Frozen-source unchanged draw.io recovery/insertion again completes with seven
IPC events, SVG **0 → 2**, unsaved true, no deadline and failed overall provider
cleanup. Pipeline wall **11.163 s**; observed payload-exit cgroup CPU **6.203177 s**,
peak **547,418,112 bytes**. An extra scope descendant leaves complete-family
resource observation unverified; later inactive/dead scope after external
recovery does not establish provider cleanup.
Final static checks pass two uncached tasks in **88.383 s wall, 87.726306 family
CPU s and 4,399,632,384 peak cgroup bytes**, no OOM. All source identities, failed
controls, corrected fixture-only lint failure and resource caveats are appended
under `chain_ownership_followup`; historical fields are unchanged.
Final docs validation passes six tasks and five README consistency cases;
current source digests are verified again afterward.
## Inherited listener-link coverage
Fresh review of `ae2cd8d4` found that a missing own descriptor is not absence:
an app decorator can inherit its data link to an owned once wrapper. Native
removal follows that link and removes the decorator; the hook hid it under
another recorder, left a listener installed and produced three invocation
records for one callback. Five native inherited-link cases fail before correction
(68 passed, five failed of 73): data/getter/Proxy prototypes and prototype
depths16/17. A late Object.getPrototypeOf replacement control already passes.
Source `e22ce9aaf` completes bounded native prototype lookup at the descriptor
owner, capturing getPrototypeOf before startup. Data links retain their actual
source value. A setter-only property has a known undefined read that shadows
ancestors; a getter, Proxy or incomplete walk remains unknown. Missing metadata becomes absent only after the prototype chain ends; found
properties retain native read/shadowing semantics. Registration and removal consume
the same parsed descriptor, and redundant outer Proxy interpretation is removed.
Neither existing resource bound is raised. All **102** hook/projection/actions/
MCP cases pass (73 + 5 + 16 + 8). Projection/client are freshly tested unchanged
sources; canonical schema and verifier/oracles retain prior checks by hash.
Prior CI run38955237255 tests confirmed merge9c0ceb152c902c1339806608f8b4a010c3d22fc6
(ae2c + main8116dc06). All36 jobs succeed; current-head CI/review remain required.
Frozen-source unchanged draw.io recovery/insertion again completes with seven
IPC events, SVG **0 → 2**, unsaved true and failed overall provider cleanup.
Pipeline: **11.264 s wall /6.376574 family CPU s /557,068,288 peak cgroup bytes**.
Payload-exit observation is verified at that phase while the observer lives;
these are not final whole-scope counters or provider cleanup proof.
Final static checks pass two uncached tasks in **90.797 s wall, 90.096799 family
CPU s and 4,335,267,840 peak cgroup bytes**, no OOM. All source identities, native
failures and current results are appended under `inherited_listener_links_followup`;
previous fields and earlier resource caveats remain unchanged.
Final docs validation passes six tasks and five README consistency cases;
current source digests are verified again afterward.
File diff suppressed because it is too large. Load diff
@@ -1,142 +0,0 @@
# Native Electron once dispatch — 2026-10-16
#4593 was reported by review of #4562, but its source was already in main from
#4389. The initial report was explicitly source-only; subsequent paired controls
confirmed the bug. This change delegates `once` creation, firing and callable
selection to the actual runtime and observes only established callback entry.
CLI and MCP continue to share the same hook, event model, projection and retained
Evidence. No new tool, schema, execution authority or analysis cache is introduced.
## Paired native controls
The baseline is `709b5cbdc15aa757f89c38ecd12e5a47710747a6`. Final source is
`4ebd0f60e860daa57a7033c6e77ea7f5f4b8ac97`, including the two review-gap fixes below. Earlier source cohort
`c0b52b5408fa97013798e6ecee885ccac08e7356` contains the fix; the final cleanup
commit is `e60c4a1098321ed2a7f564ae35909a31d707694f`, which removes the obsolete fifth helper argument and
unreachable copied call/apply dispatch branches after inspecting every caller.
The pre-review gap-owner follow-up is `7f05f476c52498adba41d943ead1a86e7216ca76`. The adjacent JSON preserves
source hashes and separate measurement cohorts, including the initial 93-row prefix.
The final review JSONL contains 117 paired rows (39 inputs × 3 runtimes). The
earlier 96-row JSONL remains unchanged, including its initial 93-row prefix. Both
comparisons have identical native
control facts in each before/after pair. Regenerable binaries, apps, profiles
and multi-MB raw captures are excluded from Git.
| Actual engine | Cases | Baseline behavioral differences | Fixed differences |
| ---------------------------------------------------------- | ----: | ------------------------------: | ----------------: |
| Node 24.18.0 (pinned) | 39 | 4 | 0 |
| Official Node 24.21.0 | 39 | 16 | 0 |
| Generic Electron 44.7.0 embedded Node 24.21.0, run as Node | 39 | 16 | 0 |
The original 21-case reproduction found 0/9/9 differences respectively. The
pre-review 32-case cohort found 1/13/13. The final 39-case suite adds readonly
callback methods, emitter method invariants, native metadata writes, failure
recovery and non-callable callback methods. The extra pinned-runtime difference is registration
metadata ordering. On the newer runtimes, opaque callback methods can suppress
callbacks under the old hook although native dispatch executes them. The pinned
runtime also catches false invocation records when an opaque method legitimately
skips the callback. The added regression fails on the baseline for that false fact.
These are **controlled producer cases with a minimal Electron module**, including
the actual embedded Node binary, not a real GUI application's natural callback
loss. Native traces, receiver checks, failures and remaining listeners are compared
exactly. Expected property reads are derived from each runtime rather than copied
from one Node implementation. The custom-apply guard still checks its original
Arguments representation when the runtime actually invokes that method.
## Ownership and uncertainty
Native once wrappers keep their public callback identity and descriptor attributes.
The registration receiver forwards methods/getters to the original emitter and
supports readonly method descriptors. A private callable receives an actual
Arguments frame, avoiding application Array species/iterators when recording.
Metadata recognition and admission share one bounded descriptor lookup.
An application-selected opaque call/apply can bypass observation; a bounded
`custom-call`/`custom-apply` gap replaces invented invocation facts. Opaque native
metadata writes or registration lookups keep the exact original callback/native
operation and emit `once-metadata` gaps. The temporary unobserved scope is restored
even if registration throws. The 39-case suite checks this recovery, including a native alias that bypasses
patched `on`; the once owner retains the observation gap for that path. #4513 raw
recording-wrapper mutation remains explicitly unfixed.
Review found two missing failure facts: a decorator can register through an
unhooked alias and then throw, and a runtime can read a non-callable call/apply
property before dispatch fails. Both new regressions fail on the pre-review
source. The once owner now finalizes its missing gap in `finally`, after restoring
the scope; the callable metadata owner records a failed gap while preserving the
exact non-callable value. Error identity and native callback behavior are retained.
Two short-lived proxies are used for an observable once registration. Metadata
remains weakly retained, and existing event/serialization budgets remain in force.
The added registration cost was not isolated; no speed or token improvement is
claimed. The saved producer comparison is a correctness experiment, not a whole
application performance benchmark. Its runner reports differences instead of
exiting unsuccessfully for an expected bad baseline; the regression tests assert
that fixed behavior matches native behavior and observation claims are truthful.
## Real application verification
Unchanged Joplin Desktop 3.7.21 ASAR and explicit generic Electron 44.7.0 run the
shipped welcome note/1075×666 PNG → actual resource context menu → app bridge →
blocked reveal workflow. The image stays visible, page errors remain empty,
reveal events increase 0→1, and the shared retained capture contains the exact
event. Both staged hook files are hashed against the selected source before launch.
No synthetic application IPC channels or replacement app callbacks are added.
The argv shim is an explicit test adapter for the still-failing standard startup
#2974. **Overall provider cleanup remains failed (#4282)** and the verifier exits
nonzero. External scope teardown is not provider cleanup. The first frozen real
pipeline takes 17.680 s; observed payload-exit CPU 16.272793 s and peak 1,395,253,248 B
have an extra descendant, so complete-family observation is **unverified**. The
cleanup cohort is recorded separately. The pre-review 32-case source repeats the real
operation successfully, but overall cleanup still fails: 18.074 s pipeline, observed
CPU 17.011774 s / peak 1,422,839,808 B; complete-family measurement remains unverified. No completed public CLI/MCP workflow,
real Windows/macOS run, natural app callback-loss reproduction or full check:pr
is claimed.
The final review source repeats the same real operation: 18.353 s pipeline,
observed CPU 17.098599 s / peak 1,387,556,864 B; complete-family measurement remains
unverified and overall provider cleanup fails. An earlier trial failed to initialize
the display because the provider environment omits XAUTHORITY. That launch is
preserved separately; the fresh final trial uses local Xvfb with `-nolisten tcp -ac`,
not a production provider change.
Frozen local validation: 75 hook cases on both Node versions; 5 projection + 8 MCP
cases on the unchanged shared contracts; static checks pass (final 118.946 s wall / 117.752622 s CPU / 4,282,826,752 B
cgroup peak, verified payload-exit family observation). The pinned final run uses
`test:focused`; an attempted `test:local` invocation was rejected before tests ran
and is recorded as not executed. See JSON for exact
commands/cohorts, failed candidate attempts, source pins and measured resources.
Failures include the Array-species frame, readonly receiver invariants, metadata
setter identity, on-getter ordering, a lint/interoperability correction and helper
preparation failures. They are not relabeled as results from the final source.
All heavy work runs serially with CPU 10/quota 1, 8 GiB hard/6 GiB early/no swap/192 tasks.
Counters are captured at payload exit with the observer alive, not final whole-scope
counters; cgroup peak includes file cache. Each final Joplin run has a new private
configuration mount. Filesystem/runtime/build caches are warm; cold-system and
warm-repeat costs are unmeasured. Agent/billed tokens and public reply/context
costs are unmeasured. The broad internal error capture size is not an agent-token
measurement. All owned scopes are checked inactive/dead independently.
## Reproduce the producer comparison
Use the pinned project toolchain and explicitly provided alternate runtimes.
The alternate Node 24.21 archive is checked against [official checksums](https://nodejs.org/download/release/v24.21.0/SHASUMS256.txt);
its archive/binary hashes are recorded. No global toolchain is upgraded.
```sh
python3 experiments/analysis-efficiency/electron-once-runtimes.py \
--hook-root /absolute/checkout-to-measure \
--node /absolute/pinned-node \
--node /absolute/node24.21 \
--electron /absolute/generic-electron44.7 \
--output /absolute/owned-output
```
Run this under the recorded resource wrapper. For a baseline comparison, use a
clean checkout of 709b5cbd as hook-root while keeping the same current oracle/runner.
The runner retains full JSON and prints a compact summary. The real Joplin recipe
is in [the shell verifier record](electron-shell-sync-2026-10-16.md); select the
current runtime-root. That workflow must remain nonzero while cleanup fails.
@@ -1,117 +0,0 @@
{"runtime":0,"mode":"plain","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"plain","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"plain","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"call-opaque","arguments":0,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-call","error":false}]}
{"runtime":0,"mode":"call-opaque","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"call-opaque","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-opaque","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-opaque","arguments":1,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"apply-opaque","arguments":3,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"call-readonly","arguments":0,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-call","error":false}]}
{"runtime":0,"mode":"call-readonly","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"call-readonly","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-readonly","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-readonly","arguments":1,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"apply-readonly","arguments":3,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"call-getter","arguments":0,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:call","opaque:call"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call","opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call","opaque:call"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-call","error":false}]}
{"runtime":0,"mode":"call-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"call-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-getter","arguments":1,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"apply-getter","arguments":3,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"call-throwing-getter","arguments":0,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:call"],"error":"Error: getter:call","listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call"],"error":"Error: getter:call","listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call"],"error":"Error: getter:call","listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-call","error":true}]}
{"runtime":0,"mode":"call-throwing-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"call-throwing-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-throwing-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-throwing-getter","arguments":1,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":true}]}
{"runtime":0,"mode":"apply-throwing-getter","arguments":3,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":true}]}
{"runtime":0,"mode":"call-non-callable","arguments":0,"native":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: this.listener.call is not a function","listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: listener.call is not a function","listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: this.listener.call is not a function","listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-call","error":true}]}
{"runtime":0,"mode":"call-non-callable","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"call-non-callable","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-non-callable","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-non-callable","arguments":1,"native":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: this.listener.apply is not a function","listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: listener.apply is not a function","listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: this.listener.apply is not a function","listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":true}]}
{"runtime":0,"mode":"apply-non-callable","arguments":3,"native":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: this.listener.apply is not a function","listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: listener.apply is not a function","listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: this.listener.apply is not a function","listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":true}]}
{"runtime":0,"mode":"inherited-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"candidate_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":0,"mode":"on-getter-listener-setter","arguments":0,"native":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"reads":1,"writes":[],"public_identity":true,"error":null},"candidate_hooked":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":0,"mode":"on-getter-native-alias","arguments":0,"native":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"candidate_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":0,"mode":"on-getter-native-alias-throws","arguments":0,"native":{"body_calls":1,"same_error":true,"public_identity":true,"listeners_after":0},"baseline_hooked":{"body_calls":1,"same_error":true,"public_identity":true,"listeners_after":0},"candidate_hooked":{"body_calls":1,"same_error":true,"public_identity":true,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":true}]}
{"runtime":0,"mode":"throwing-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"candidate_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":true},{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"readonly-emitter-methods","arguments":0,"native":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"candidate_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"plain","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"plain","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"plain","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-opaque","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-opaque","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-opaque","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-opaque","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-opaque","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-opaque","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-readonly","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-readonly","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-readonly","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-readonly","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-readonly","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-readonly","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call","opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-throwing-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call"],"error":"Error: getter:call","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-throwing-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-throwing-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-throwing-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-throwing-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-throwing-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-non-callable","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: listener.call is not a function","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-non-callable","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-non-callable","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-non-callable","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-non-callable","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: listener.apply is not a function","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-non-callable","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: listener.apply is not a function","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"inherited-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"candidate_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":1,"mode":"on-getter-listener-setter","arguments":0,"native":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"reads":1,"writes":[],"public_identity":true,"error":null},"candidate_hooked":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":1,"mode":"on-getter-native-alias","arguments":0,"native":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"candidate_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":1,"mode":"on-getter-native-alias-throws","arguments":0,"native":{"body_calls":1,"same_error":true,"public_identity":true,"listeners_after":0},"baseline_hooked":{"body_calls":1,"same_error":true,"public_identity":true,"listeners_after":0},"candidate_hooked":{"body_calls":1,"same_error":true,"public_identity":true,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":true}]}
{"runtime":1,"mode":"throwing-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"candidate_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":true},{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"readonly-emitter-methods","arguments":0,"native":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"candidate_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"plain","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"plain","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"plain","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-opaque","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-opaque","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-opaque","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-opaque","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-opaque","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-opaque","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-readonly","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-readonly","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-readonly","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-readonly","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-readonly","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-readonly","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call","opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-throwing-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call"],"error":"Error: getter:call","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-throwing-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-throwing-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-throwing-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-throwing-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-throwing-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-non-callable","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: listener.call is not a function","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-non-callable","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-non-callable","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-non-callable","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-non-callable","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: listener.apply is not a function","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-non-callable","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":[],"error":"TypeError: listener.apply is not a function","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"inherited-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"candidate_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":2,"mode":"on-getter-listener-setter","arguments":0,"native":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"reads":1,"writes":[],"public_identity":true,"error":null},"candidate_hooked":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":2,"mode":"on-getter-native-alias","arguments":0,"native":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"candidate_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":2,"mode":"on-getter-native-alias-throws","arguments":0,"native":{"body_calls":1,"same_error":true,"public_identity":true,"listeners_after":0},"baseline_hooked":{"body_calls":1,"same_error":true,"public_identity":true,"listeners_after":0},"candidate_hooked":{"body_calls":1,"same_error":true,"public_identity":true,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":true}]}
{"runtime":2,"mode":"throwing-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"candidate_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":true},{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"readonly-emitter-methods","arguments":0,"native":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"candidate_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
@@ -1,96 +0,0 @@
{"runtime":0,"mode":"plain","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"plain","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"plain","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"call-opaque","arguments":0,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-call","error":false}]}
{"runtime":0,"mode":"call-opaque","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"call-opaque","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-opaque","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-opaque","arguments":1,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"apply-opaque","arguments":3,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"call-readonly","arguments":0,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-call","error":false}]}
{"runtime":0,"mode":"call-readonly","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"call-readonly","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-readonly","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-readonly","arguments":1,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"apply-readonly","arguments":3,"native":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"call-getter","arguments":0,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:call","opaque:call"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call","opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call","opaque:call"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-call","error":false}]}
{"runtime":0,"mode":"call-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"call-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-getter","arguments":1,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"apply-getter","arguments":3,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":false}]}
{"runtime":0,"mode":"call-throwing-getter","arguments":0,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:call"],"error":"Error: getter:call","listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call"],"error":"Error: getter:call","listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call"],"error":"Error: getter:call","listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-call","error":true}]}
{"runtime":0,"mode":"call-throwing-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"call-throwing-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-throwing-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"apply-throwing-getter","arguments":1,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":true}]}
{"runtime":0,"mode":"apply-throwing-getter","arguments":3,"native":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"custom-apply","error":true}]}
{"runtime":0,"mode":"inherited-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"candidate_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":0,"mode":"on-getter-listener-setter","arguments":0,"native":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"reads":1,"writes":[],"public_identity":true,"error":null},"candidate_hooked":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":0,"mode":"throwing-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"candidate_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"readonly-emitter-methods","arguments":0,"native":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"candidate_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"plain","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"plain","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"plain","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-opaque","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-opaque","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-opaque","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-opaque","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-opaque","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-opaque","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-readonly","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-readonly","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-readonly","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-readonly","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-readonly","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-readonly","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call","opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-throwing-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call"],"error":"Error: getter:call","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-throwing-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"call-throwing-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-throwing-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-throwing-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"apply-throwing-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"inherited-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"candidate_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":1,"mode":"on-getter-listener-setter","arguments":0,"native":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"reads":1,"writes":[],"public_identity":true,"error":null},"candidate_hooked":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":1,"mode":"throwing-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"candidate_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":1,"mode":"readonly-emitter-methods","arguments":0,"native":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"candidate_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"plain","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"plain","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"plain","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-opaque","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-opaque","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-opaque","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-opaque","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-opaque","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-opaque","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-readonly","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-readonly","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-readonly","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-readonly","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-readonly","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-readonly","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call","opaque:call"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply","opaque:apply"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-throwing-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:call"],"error":"Error: getter:call","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-throwing-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"call-throwing-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-throwing-getter","arguments":0,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:0"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-throwing-getter","arguments":1,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:1"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"apply-throwing-getter","arguments":3,"native":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_hooked":{"body_calls":0,"correct_receiver":true,"trace":["get:apply"],"error":"Error: getter:apply","listeners_after":0},"candidate_hooked":{"body_calls":1,"correct_receiver":true,"trace":["body:3"],"error":null,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":true}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"inherited-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"candidate_hooked":{"body_calls":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":2,"mode":"on-getter-listener-setter","arguments":0,"native":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_hooked":{"body_calls":1,"reads":1,"writes":[],"public_identity":true,"error":null},"candidate_hooked":{"body_calls":1,"reads":1,"writes":[true],"public_identity":false,"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":2,"mode":"throwing-listener-setter","arguments":0,"native":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"candidate_hooked":{"body_calls":1,"writes":[true],"error":"Error: metadata-write","listeners_after":1},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":2,"mode":"readonly-emitter-methods","arguments":0,"native":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"candidate_hooked":{"body_calls":1,"seen":["on:true","removeListener:true"],"error":null},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"main-event-invocation","event":null,"error":false}]}
{"runtime":0,"mode":"on-getter-native-alias","arguments":0,"native":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"candidate_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":1,"mode":"on-getter-native-alias","arguments":0,"native":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"candidate_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
{"runtime":2,"mode":"on-getter-native-alias","arguments":0,"native":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"candidate_hooked":{"body_calls":1,"reads":1,"listeners_after":0},"baseline_observation":[{"kind":"main-event-invocation","event":null,"error":false}],"candidate_observation":[{"kind":"ipc-observation-gap","event":"once-metadata","error":false}]}
File diff suppressed because it is too large. Load diff
@@ -1,91 +0,0 @@
# Electron synchronous shell boundary verification — 2026-10-16
Fix #4393 reuses Nitin13-git's existing PR #4562. The boundary owns a fixed
method/return table: existing asynchronous blocks still reject, while
`showItemInFolder` returns `undefined` and `writeShortcutLink` returns `false`.
Both new blocks use the existing shape-only event recorder, shared by CLI/MCP.
No tool, schema, capture authority, analysis cache or launch behavior is added.
## Source and controlled regression
The fresh main base is `f26973a52918a938631e90fdc9116f7b85a62a52`;
implementation integration is `0386b60fb` and frozen verifier source is
`3f231735c3fbc28918590ddc61461871c8a2aa4d`.
The adjacent JSON records frozen final script/runtime/input hashes and all attempts;
unpinned exploratory helper revisions are explicitly identified.
Original contributor attribution remains in Git ancestry.
Using the candidate test with the base boundary produces **73 passes / 1 failure**:
the fake native shortcut implementation executes and returns true. With the
candidate boundary, **87 cases pass** (74 staged-hook, 5 projection, 8 MCP).
These test native dispatch suppression, synchronous results, shape-only
retention and the shared event schema. The fake Electron cases and controlled
MCP provider do not prove a real Windows shell implementation was exercised.
`npm run check:fast` passes both uncached tasks. Build-cache differences and
different case counts make the red/green timings unsuitable as a speed comparison.
## Real Joplin workflow and limits
Inputs: unchanged Joplin Desktop **3.7.21** ASAR (233,575,014 bytes), and the
explicit generic Electron **44.7.0** runtime. Acquisition/checksum references
are in `javascript-native-handoff-identity-2026-10-15.json` and
`electron-cancellation-2026-10-16.json`; this is not vendor-executable compatibility.
No executable fuse is changed. Large downloadable inputs and generated profiles
are not committed or retained as an experiment bundle.
The verifier opens Joplin's shipped **1. Welcome to Joplin!** note and real PNG
attachment. It selects Joplin's actual editor layout and resource context-menu
callbacks; Joplin's existing bridge calls the real patched shell method. The
native popup presentation is captured for automation; its application callbacks
are not replaced. Before any app actions, the verifier requires the active hook.
It requires zero earlier reveal events, one new blocked shape-only reveal event,
a still-rendered attachment and an identical event in the shared retained capture.
**Standard launch remains unsuccessful.** The earlier standard probe reports
`Unknown flag: -r` in Joplin's start-flag parser; the frozen standard verifier
times out waiting for the application search input. This is relevant to #2974,
not fixed here. A discarded NODE_OPTIONS experiment was invalid: Playwright
removes that variable, so no hook was installed. Those attempts are never used
as interception or performance evidence.
The explicit `--argv-shim-transport` test adapter loads the provider's staged
canonical hook and removes only its own exact `-r`/shim pair from app argv before
Joplin starts. It does not modify the ASAR or production provider. Its successful
operation phase is not a successful standard public CLI/MCP workflow. Provider
cleanup still fails (#4282); the verifier exits nonzero, preserving the distinction.
External owned-scope teardown does not establish provider cleanup.
The first valid shim probe reaches one blocked reveal, visible 1075×666 PNG,
no page errors and retained capture evidence. The final frozen rerun additionally
checks event causality and exact capture equality. Detailed measured results and
whole-family observation status are in the JSON. The final controlled pipeline
takes16.989s wall /16.055812 family CPU s /1,376,382,976 peak cgroup bytes
with verified payload-exit observation; the overall workflow still fails cleanup. Each final trial has a new
private config mount; earlier exploratory shared-config trials are not independent
cold runs. Filesystem/runtime/build caches are warm; no cold-system or warm-repeat
speedup is claimed. Agent/billed tokens are unmeasured; there is no token benefit claim.
## Reproduction
Use the pinned Node/npm toolchain. Install dependencies and build with
`npm ci` and `npm run build:cached`. Create an owned writable packet directory
with `tmp`, `profiles`, and `config/joplin-desktop`. On Linux, bind that private
config over the actual user config directory in a disposable `bwrap` mount
namespace (do not change HOME), keep the application resources read-only and
run under Xvfb. Set TMPDIR to the owned writable packet `tmp` directory. Run:
```sh
node experiments/analysis-efficiency/joplin-shell-boundary.mjs \
--runtime-root /absolute/rea-checkout \
--executable /absolute/generic-electron \
--application /absolute/Joplin/resources/app.asar \
--profile-root /absolute/owned-packet/profiles \
--argv-shim-transport
```
Omit the last flag for the failing standard launch. Run heavy work serially under
`resource-run.py --memory-gib 8 --observe-payload-exit`, one CPU, no swap, the
6 GiB early-stop margin and 192-task ceiling. CPU/peak memory receipts are at
payload exit with the observer alive; memory includes file cache, not just RSS.
Unverified complete-family observations are explicitly marked. No Windows host,
macOS host, vendor packaged runtime or full `check:pr` was executed here.
File diff suppressed because it is too large. Load diff
@@ -1,245 +0,0 @@
# Interrupted application processing: applicability and Evidence
Tracks #3948 under #4027. Measured baseline:
`c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb`.
The question is which processing phases remain unavailable after a source
interruption, while keeping native inventory and already collected facts.
Native identity and provider linkage must stay independent of application-wide
partial coverage. This is static artifact analysis; no target application or
native provider runs.
## Observed failure and correction
The interruption producer previously attached one generic failure to every
remaining relevant file. Graph projection interpreted it as JavaScript AST work.
Real Joplin reproduced an `analyze-javascript-source` / `ast-static-analysis`
unavailable scope on keytar's native binary and on unvisited package, HTML and
source-map files. Public CLI/MCP controls reproduced the same applicability
problem. Deterministic cancellation before native metadata additionally produced
a phantom JavaScript semantic module for the binary.
The producer now records the applicable operation/authority and whether the
phase was entered. `analysis_status: interrupted` includes worker startup and
does not imply parsing completed; `not-started` identifies unvisited phases.
Native add-ons need no post-inventory source-processing phase, so neither interrupted
nor caller-excluded native files acquire AST scopes or semantic modules.
Actual JavaScript failures, structured-file unknowns, caller selection and byte
identity remain available. The graph consumes these produced facts.
The AST-only unavailable Evidence helper is replaced by an explicitly typed
static helper. Normal package/JSON/map gaps also retain their artifact-byte
authority. Per-file progress uses the same applicability owner: JavaScript keeps
its source phase, and metadata uses `process_javascript_artifact_metadata`.
Remaining parsers do not run after interruption. Failure sharing is limited to
five applicable phases during one interruption; no persistent cache is added.
A second review found the alternate full-analysis semantic builder still
created modules for every excluded file kind. An actual filesystem-producer
regression on revision `323fae8cbf3e36677bcb7b22ba31fa1a7e3c5cd4` reproduced
phantom native/JSON/HTML/package/source-map modules, while selected and excluded
JavaScript were positive controls. Semantic applicability now belongs to the
shared `recordUnavailableFile` projection entry point, before retaining limits,
nodes, roots or unknowns. Three duplicate caller checks are removed. Both full
and incremental construction use this boundary; actual excluded JavaScript
continues to carry source-bound unknowns and partial semantic coverage.
## Real input and reproduction
Use the [official Joplin v3.7.21 acquisition and extraction instructions](https://github.com/morluto/rea/blob/c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb/docs/verification/javascript-native-handoff-identity-2026-10-15.md).
The AppImage SHA-256 is
`5d202dcaca31e14206826aa3f04125e7c218dbc3dc3d98479d811efbd6b856c1`;
ASAR SHA-256 is
`767df409b18effe60421fbefcca873de237c7e813eac744ecdeebbc5e825a33a`.
The 6,324-file inventory includes 46 unpacked entries. Both cohorts stage all
three native companions; the other 43 unpacked entries remain unavailable.
Build with pinned Node 24.18.0/npm 11.16.0 and locked dependencies. The extended
existing verifier also runs against the baseline runtime; copy the verifier and
`scripts/lib/javascript-file-scope-oracle.mjs` from the fixed revision into a
built baseline checkout when reproducing the failure.
```bash
artifact_path="/absolute/path/to/cases/available/app.asar"
common=(
--artifact "$artifact_path"
--addon-path node_modules/keytar/build/Release/keytar.node
--native-sha256 0700016bcd761cbe02d275f2046c7cc42f39f730a50d66e3d3307aa9d413373a
--source-path ElectronAppWrapper.js
--source-path ElectronAppWrapper.js.map
--source-path index.html
--source-path package.json
--source-path node_modules/keytar/build/Release/keytar.node
--structured-path ElectronAppWrapper.js.map
--structured-path index.html
--structured-path package.json
--structured-expectations '{"ElectronAppWrapper.js.map":{"operation":"parse-local-source-map","analysis_status":"not-started"},"index.html":{"operation":"parse-html-script-references","analysis_status":"not-started"},"package.json":{"operation":"parse-package-json","analysis_status":"not-started"}}'
--rounds 3 --cli-parity
--tokenizer-python /absolute/path/to/python-with-tiktoken-0.12.0
)
node scripts/verify/javascript/native-handoffs.mjs "${common[@]}" \
--analysis-timeout-ms 1 --expect-timeout --require-safe
node scripts/verify/javascript/native-handoffs.mjs "${common[@]}" \
--validate-structured-from-export --require-safe
```
Omit `--require-safe` on the baseline timeout run to record its incorrect
applicability. Its diagnostic exit 0 is not a passing analyst task. A supported
1 ms deadline includes worker startup; the verifier requires a typed timeout
and retained partial reference for that cohort. Each structured path supplies an
independent expected operation and phase-entry status; the safety oracle matches
all gaps exactly, including unavailable state and unknown confidence. Missing or
conflicting expectations do not pass.
The native path is explicitly selected. An earlier structured-only run excluded
it and therefore did not reproduce the native interruption. Input selections
and that preliminary result remain recorded. Both final cohorts preserve
partial coverage for unselected/unavailable scopes.
The supplied native Evidence is simulated solely to check exact subject linkage.
The verifier checks physical companion bytes and the exported parent's root
digest, validates public CLI/MCP native-trace parity, and reports only after
owned transport/command/private-file cleanup. Applications and large Evidence
are regenerable and are not archived.
## Two distinct task projections
The **timeout task** includes the expected typed-timeout preparation, one inline
native trace and three inline structured-path traces. It checks that native has
no AST failure and that each unvisited structured phase remains unavailable with
the appropriate artifact-byte authority and `not-started` status.
The **default-deadline control** models the summary plus one inline native trace.
Its named structured paths are additionally validated from the already exported
complete parent, explicitly labelled `exported-parent-validation`. Those checks
are diagnostic overhead outside the modeled native-task tokens and inside total
verifier resources. They are not presented as inline metadata answers.
A control that also requested the complete outgoing `package.json` feature trace
hit stdio admission twice: at least 10,587,373 bytes against a 10,484,736-byte
result budget, with identical retained parent/trace identities. It is not a
completed equivalent task or an efficiency baseline. [#4190](https://github.com/morluto/rea/issues/4190)
records the separate need for exact retained metadata/native fact views. Complete
export remains available. Do not compare costs across these different tasks.
## Measurements
| Cohort | Revision | Wall s | CPU s | Peak cgroup bytes | Applicability |
| ------------------------------ | -------- | ------: | ---------: | ----------------: | ------------- |
| Timeout, four inline traces | baseline | 60.738 | 60.289464 | 3,092,045,824 | wrong scope |
| Timeout, four inline traces | final | 57.515 | 57.089883 | 2,763,276,288 | pass |
| Default control, native inline | baseline | 61.542 | 61.135522 | 2,808,336,384 | pass |
| Default control, native inline | final | 186.085 | 142.371100 | 2,959,585,280 | pass |
| Defined task | Selected catalog + parsed/structured replies BPE | Selected catalog + complete tool replies BPE |
| -------------- | -----------------------------------------------: | -------------------------------------------: |
| Timeout | 21,136 → 20,161 | 36,468 → 34,471 |
| Native control | 11,776 → 11,720 | 17,738 → 17,632 |
The full-catalog alternatives and per-query samples are preserved in JSON.
Native content identity, observed byte provenance, source selection and handoff
provider Evidence remain equal. Corrected global provenance changes derived
parent/trace identities; null partial-Evidence subjects remain null. Both final
runs have exact CLI/MCP native-trace parity and match the earlier post-fix
controls in every recorded non-timing field.
The whole verifier includes input hashing, analysis, three native trace rounds,
applicable structured queries, export, CLI parity and tokenization. Every heavy
run uses the preserved [resource observer](https://github.com/morluto/rea/blob/b3bdabab694af1f9801eff7caf75001b92314a58/experiments/analysis-efficiency/resource-run.py):
one CPU, 8 GiB hard cap, 6 GiB early stop and no swap. Cgroup peaks include charged
file cache, not summed RSS. Counters are observed at payload exit while the
observer remains alive, not final whole-scope counters. Completed runs verify
owned cleanup and report no OOM.
Each MCP process is fresh, but input hashing warms its file cache. Build/OS caches
and shared-host scheduling are uncontrolled. First and repeated retained-query
wall samples remain separate; isolated query CPU/memory are unmeasured. An
earlier fixed timeout took 150.173 s wall / 119.468013 s CPU; its exact unchanged
runtime repeat took 58.827 s / 58.482996 s, with identical non-timing facts,
Evidence and BPE. Both receipts are retained. The final default control also took 186.085 s wall / 142.371100 s CPU; its
unchanged-runtime repeat took 62.651 s / 62.240964 s with identical non-timing
results. The slow final row remains reported. Attribution remains unresolved;
these runs establish no speedup or performance-equivalence bound.
The stricter post-review verifier reruns also passed without changing production
code: timeout 162.645 s wall / 125.876114 s CPU / 2,809,643,008 B peak; default
control 61.367 s / 60.970077 s / 2,526,949,376 B. Both preserve the original final
analytical fields, identities, coverage and BPE exactly; only timings and the new
explicit oracle-input field differ. These additional receipts do not replace the
slower rows above.
After centralizing semantic applicability, both real public controls passed again:
timeout 60.443 s wall / 59.970344 s CPU / 3,078,295,552 B peak; default control
63.574 s / 63.177884 s / 3,189,719,040 B. Analytical results, identities, coverage,
BPE and exact CLI/MCP parity remain unchanged. JSON identifies the runtime and
verifier source manifests for each cohort and keeps all earlier receipts.
Static `cl100k_base`/tiktoken 0.12.0 projections include the selected or complete
name/description/inputSchema catalog, requests and structured Evidence or parsed
text errors. Complete-tool-reply alternatives include MCP text/structured
duplication. The selected two-tool catalog is 5,570 BPE; the complete projection
is 195,522. Output schemas, host rendering/replay, notifications, model reasoning,
final answers and billing are unmeasured. Repeated rounds, export, CLI parity,
tokenization and exported-parent diagnostics are validation overhead outside the
defined task tokens but inside resource receipts. Removing unsupported claims
from the incorrect timeout baseline earns no efficiency credit.
## Verification and limitations
The initial production fix had 49 distinct passing cases across eight files. The initial
pre-progress-cleanup seven-file selection passed 44/44. After progress cleanup,
the same selection passed 43 and hit the existing 30-second test deadline in one
native identity case; an unchanged two-file rerun passed both native cases and
five public CLI cancellation cases. The original deadline was not increased.
The runtime verifier collects interruption-bearing scopes; separate regressions
cover native caller exclusion and malformed structured data. Source selection,
malformed structures, actual worker resource constraints,
retained large partial observations, cancellation/publication/cleanup, native
identity and both public adapters remain covered.
The first review found that the real verifier previously accepted any non-JavaScript
operation with artifact-byte authority and ignored phase-entry status. The
scenario now supplies exact operation/status expectations independently of the
production phase map. Six additional oracle cases use the actual retained
Joplin snapshots and reject wrong metadata operations, entered or missing
statuses, and absent or conflicting gaps. They passed, bringing the distinct
coverage to 55 cases across nine files. The production implementation did not
change during this review correction.
After the shared semantic-boundary correction from the second review, 78
distinct cases passed across ten files: the nine-file selection passed 65/65,
and the original root reconstruction file passed 13/13. This includes the
alternate-builder owning test file's 23 cases. The new producer-boundary
regression checks both construction paths, all five excluded metadata/native
kinds, and selected/excluded JavaScript controls. Real Joplin controls exercise
the public incremental workflow; the alternate full-builder path has filesystem
boundary verification rather than a separately measured real-app workflow.
Recorded attempts also include the verifier's initial non-null-subject assumption
and an invalid top-level semantic-module-path absence check. Both were corrected
before their assertions were used as proof. Corrected cancellation reproduction
shows the actual native AST scope and phantom module on the baseline. Final
source and execution-driver versions, source pins, input digests, prior attempts
and resource receipts are in the [compact JSON record](javascript-interruption-applicability-2026-10-15.json).
Before review, `npm run check && npm run docs:check` passed, including five consistency
tests: 165.553 s wall / 150.247257 s CPU /
4,232,491,008 B peak cgroup memory, clean owned exit and no OOM.
The first full check stopped on a 172-line test callback exceeding the 150-line
rule. A named assertion helper now shares scope lookup across all four public
results; the strengthened six-case file passed again before the final gates.
After the review correction, the full static/docs gate passed again, including
the five consistency tests: 111.395 s wall / 110.979710 s CPU /
4,347,125,760 B peak, with clean owned exit and no OOM.
After centralizing semantic applicability, the final full static/docs gate also
passed, including five consistency tests: 117.636 s wall / 117.194118 s CPU /
4,263,153,664 B peak, clean owned exit and no OOM.
At the initial PR revision, 36 CI checks passed; macOS `hdiutil create` failed
while creating its DMG fixture before REA verification, also failing the aggregate
check. No Apple fixture/workflow code changed. That attempt provides no passing
Apple runtime evidence.
Live Electron/application execution, real native-provider behavior, other-platform
runtime coverage and hosted-agent costs are **NOT_ENOUGH_INFO**. The verification
does not claim them.
@@ -1,547 +0,0 @@
{
"base_revision": "e9a71efa31d6c3675b67938b8a79fa4ddf01604c",
"scope": "Semantic per-value string-byte normalization; real static shipped-application control, no hosted-model performance claim",
"runtime": {
"platform": "Linux x64",
"node": "24.18.0",
"npm": "11.16.0",
"tiktoken": "0.12.0"
},
"baseline_source_sha256": {
"src/domain/javascript/javascriptSemanticValues.ts": "df3fc30b5ba91901a85fe56f200355930da32d054bb026a747e3414af233b6b5",
"src/domain/javascript/javascriptSemanticPrimitives.ts": "c12b29f0faf4b6511777cba7ed8ac007c6d6170d657f01e43e194feacb3e0601",
"src/domain/javascript/javascriptSemanticResourceLimits.ts": "0203d207e0d6bb8aaa17746090f008876a11653afd660fce3dc44f3fda646a6c",
"scripts/verify/javascript/module-references.mjs": "9d5f0b8b35ed2ebb4591f9dc3baea0fc116a0c3fd7d8e5ce30ec476c84671ed1"
},
"final_source_sha256": {
"scripts/verify/javascript/module-references.mjs": "9d5f0b8b35ed2ebb4591f9dc3baea0fc116a0c3fd7d8e5ce30ec476c84671ed1",
"src/application/javascript/JavaScriptSemanticGraphDataProjection.ts": "844d4639401a9f050ce42c80192572a6d0d74fe4f81b37e93a2c20aaca9fb9a6",
"src/domain/javascript/javascriptSemanticAnalysis.ts": "a3f802ca3446c2b5376cc58b19d818eff318e6775bd47752793c3f649994f8a2",
"src/domain/javascript/javascriptSemanticAnalysis.unions.test.ts": "2e78717d30e637b5fc5bab6d0eff063f7a62e0199d33697c1cdfaf8317baa698",
"src/domain/javascript/javascriptSemanticDataEffectHelpers.ts": "8f9cf1a36f05b03dd816eaf9a6cdba0160d34ad7d17a961206e1bc32444d2ccc",
"src/domain/javascript/javascriptSemanticDataEffects.ts": "e69408f2f5910a0107fd5d0cae0ff60ed706448857bc8e535c37cac1a0cd4d37",
"src/domain/javascript/javascriptSemanticIr.ts": "68dad360d0a9e6bd72108b2717cae756b84ca1efb48455248ded2ff699d2c113",
"src/domain/javascript/javascriptSemanticPrimitives.ts": "899eeb6ccdf666f504f8b722327599997c924c8e4fb13a1cbd13edaf08c96640",
"src/domain/javascript/javascriptSemanticResourceLimits.ts": "0993a397f2a2a48c2b6c35494e940b3fce5c2c9032cfe33c7cf0401128c79dde",
"src/domain/javascript/javascriptSemanticState.ts": "bfcface5dcda22594f47ed390efa15f9140fe41cb2d5995896e52dd0ee31b978",
"src/domain/javascript/javascriptSemanticValues.ts": "a4ba51cc60fff38ef11fd5af35a2e1ad753cdb2dea9d44895f91d89320c5ddeb",
"tests/acceptance/applications/javascriptEndpointPayload.test.ts": "b3cfcde1c5b5e0698f84afd51f4b53e42e56101267707c20c0d038320f5cfbd2",
"tests/boundary/mcp/javascriptLiteralBudget.test.ts": "070106115b482269794799e448bd20b8e02df1f511f4ceb2b8fa75612c7f78e4",
"tests/boundary/mcp/javascriptLiteralPayload.test.ts": "03618272c605f8877ed171ab39e037e4d80eac72b7478421640076f739adfb50"
},
"artifact": {
"path": "/tmp/rea-codemode-experiment-20261015/artifacts/obsidian-1.14.4.asar",
"sha256": "146ef8470d8cbb4a6db209bdc19bf2bad13350444186c0fd93c31087b142b92f"
},
"selected_source_paths": ["package.json", "main.js"],
"where": {
"path": "main.js",
"kind": "javascript-module"
},
"identical_parent_evidence_id": "ev_73ef06e3b9b944f54c5257f7960279127d8518d2a73cd8618bd045dbe44e6b5a",
"cli_parity": {
"evidence_id": "ev_b3586dfdf7d4f01157f8f2978326aaa7103987110f2df4fa5bf3331ff2898749",
"facts_sha256": "d3be5e91d2ec3fd9a95851cfbbdef9c168bb4c7153f78810b8b235e005401299",
"exact_cli_mcp_view_parity": true
},
"unchanged_query_shapes": {
"legacy": {
"calls": 24,
"structured_reply_bytes": 325201,
"facts_sha256": "d3be5e91d2ec3fd9a95851cfbbdef9c168bb4c7153f78810b8b235e005401299",
"matching_modules": 23,
"coverage": {
"status": "page",
"examined": 55,
"total": 55,
"next_offset": null,
"exhausted": true
}
},
"references": {
"calls": 1,
"structured_reply_bytes": 22158,
"facts_sha256": "d3be5e91d2ec3fd9a95851cfbbdef9c168bb4c7153f78810b8b235e005401299",
"matching_modules": 23,
"coverage": {
"status": "page",
"examined": 23,
"total": 23,
"next_offset": null,
"exhausted": true
}
}
},
"unchanged_token_costs": {
"tokenizer": "cl100k_base",
"tiktoken_version": "0.12.0",
"costs": {
"legacy": {
"selected_catalog": 7977,
"full_catalog": 195522,
"common_request": 53,
"common_summary": 2675,
"requests": 2836,
"structured_replies": 71761,
"selected_catalog_task_total": 85302,
"full_catalog_task_total": 272847
},
"references": {
"selected_catalog": 7977,
"full_catalog": 195522,
"common_request": 53,
"common_summary": 2675,
"requests": 102,
"structured_replies": 5741,
"selected_catalog_task_total": 16548,
"full_catalog_task_total": 204093
}
}
},
"cohorts": {
"baseline": {
"preparation_ms": 19089.119622,
"query_samples": [
{
"round": 0,
"mode": "legacy",
"elapsed_ms": 383.8260569999984
},
{
"round": 0,
"mode": "references",
"elapsed_ms": 15.778886999996757
},
{
"round": 1,
"mode": "references",
"elapsed_ms": 13.15173700000014
},
{
"round": 1,
"mode": "legacy",
"elapsed_ms": 240.44363500000327
},
{
"round": 2,
"mode": "legacy",
"elapsed_ms": 346.04796499999793
},
{
"round": 2,
"mode": "references",
"elapsed_ms": 13.727306999997381
}
],
"resources": {
"elapsed_seconds": 33.394,
"cpu_seconds": 33.016802,
"peak_cgroup_bytes": 1979863040,
"payload_cleanup_verified": true,
"events_at_payload_exit": {
"memory.events": {
"low": 0,
"high": 0,
"max": 0,
"oom": 0,
"oom_kill": 0,
"oom_group_kill": 0
},
"pids.events": {
"max": 0
}
}
}
},
"final": {
"preparation_ms": 19061.292544,
"query_samples": [
{
"round": 0,
"mode": "legacy",
"elapsed_ms": 344.6316079999997
},
{
"round": 0,
"mode": "references",
"elapsed_ms": 14.438351000000694
},
{
"round": 1,
"mode": "references",
"elapsed_ms": 11.38763100000142
},
{
"round": 1,
"mode": "legacy",
"elapsed_ms": 298.41579600000114
},
{
"round": 2,
"mode": "legacy",
"elapsed_ms": 211.45682099999976
},
{
"round": 2,
"mode": "references",
"elapsed_ms": 10.275370999999723
}
],
"resources": {
"elapsed_seconds": 32.949,
"cpu_seconds": 32.559187,
"peak_cgroup_bytes": 1880096768,
"payload_cleanup_verified": true,
"events_at_payload_exit": {
"memory.events": {
"low": 0,
"high": 0,
"max": 0,
"oom": 0,
"oom_kill": 0,
"oom_group_kill": 0
},
"pids.events": {
"max": 0
}
}
}
}
},
"conditions": "First query is after shared artifact analysis; subsequent queries share one MCP session. Legacy item reads are serial; a concurrent legacy baseline is unmeasured. Filesystem/build warmness uncontrolled. Token costs count one post-change catalog, preparation request/summary and each request/structured reply once; client rendering, replay, reasoning, final answer and model latency are unmeasured. Preparation and parity/tokenization overhead are outside per-query elapsed times; external family-resource receipts include the complete verifier and children. Before/after used separate fresh MCP sessions. CPU/memory includes analysis, query arms, export, CLI parity and tokenization; cgroup memory includes file cache, not summed RSS. Counters are at payload exit while observer lives, not final scope counters. One before/after control establishes no speedup or equivalence bound. Catalog BPE projection excludes annotations/output schemas.",
"resource_policy": {
"memory_max_bytes": 8589934592,
"early_stop_bytes": 6442450944,
"cpu_quota_percent": 100,
"swap": false
},
"observer_sources_sha256": {
"resource-run.py": "7728862171415e7dee2c11af2ead2b9a54265fccaf82a7113956d36b29065e33",
"resource_payload.py": "6f089e645459eba80c5d73e39c21606c78173a44daf49fabc3b88c4631ce51c6"
},
"regressions": {
"original_main": "Quoted/template oversized literals failed through public CLI/MCP; addition/small controls passed. Corrected domain boundary reproduced 2 failures/16 passes.",
"review_head": "8 failed/25 passed before fixes for projection tags, encountered-but-discarded limits and bare quoted/template defaults; includes exact null default control.",
"interim_review_fix": "65/66 focused passed; old doubling-chain expectation omitted a genuine expression-depth limit now observed. Adjusted that assertion to preserve the byte-limit requirement while allowing other observed classes.",
"final_focused": "66 passed across five files on the restored 38d263a runtime. Final corrected public selection passed 7/7 in two files: the six literal/default/member cases plus the augmented original large-endpoint acceptance. 67 distinct focused cases across invocations; not a single 67-case invocation.",
"final_semantic_suite": "932 passed in 36 files on 38d263a. Final production src tree (including these domain tests) verified byte-identical to that revision; no repeated semantic run claimed.",
"arithmetic": "Computed 174762*6+2=1048574 and 174763*6+2=1048580. Corrected the erroneous published 1048578 total.",
"final_grouped_domain": "27 passed after grouping observations/defaults/allocation within function-size rules; no scenarios removed.",
"endpoint_contract_correction": "Restored exact endpoint lookup identities rather than shrinking the existing large-endpoint fixture. Added the identical oversized string as an exported primitive in that acceptance workflow: literal normalization must report its bound while full endpoint lookup/feature trace/semantic trace/version comparison continue to work. Production src tree restored byte-identical to 38d263a; 932 semantic tests from that state remain applicable. Final corrected public tests/gates recorded after execution.",
"final_corrected_gates": "Full static gate and docs gate (5 consistency tests) passed after endpoint identity restoration and strengthened unchanged-large-input acceptance. Production src remains byte-identical to 38d263a; final public 7/7 and fresh real control passed."
},
"prior_attempts": [
{
"stage": "Initial literal normalization, incomplete for member/default paths identified in review",
"revision": "40b9d3c5b9cbeae7661d8e351e1b5ef6e5338931",
"source_sha256": {
"src/domain/javascript/javascriptSemanticValues.ts": "2debbb4f32d7d189819f2413f0f7d05b9bdcf497451a1c578475e3f2ec6c8554",
"src/domain/javascript/javascriptSemanticPrimitives.ts": "899eeb6ccdf666f504f8b722327599997c924c8e4fb13a1cbd13edaf08c96640",
"src/domain/javascript/javascriptSemanticResourceLimits.ts": "0203d207e0d6bb8aaa17746090f008876a11653afd660fce3dc44f3fda646a6c",
"src/domain/javascript/javascriptSemanticAnalysis.unions.test.ts": "747d893d6ddd91cf24d3b62b7eb50e0af9b1715ab355bbfc2e10ed0dc171ec17",
"tests/boundary/mcp/javascriptLiteralBudget.test.ts": "46ceb5a169de3eec3a335b05ef4aa7b1b341a5ac06ad325bd191e862c5b6be70",
"tests/boundary/mcp/javascriptLiteralPayload.test.ts": "03618272c605f8877ed171ab39e037e4d80eac72b7478421640076f739adfb50",
"scripts/verify/javascript/module-references.mjs": "9d5f0b8b35ed2ebb4591f9dc3baea0fc116a0c3fd7d8e5ce30ec476c84671ed1"
},
"real_control_cohort": {
"preparation_ms": 18876.764036,
"query_samples": [
{
"round": 0,
"mode": "legacy",
"elapsed_ms": 346.7870870000006
},
{
"round": 0,
"mode": "references",
"elapsed_ms": 18.34765800000241
},
{
"round": 1,
"mode": "references",
"elapsed_ms": 11.56626999999935
},
{
"round": 1,
"mode": "legacy",
"elapsed_ms": 227.17703500000061
},
{
"round": 2,
"mode": "legacy",
"elapsed_ms": 251.5148330000011
},
{
"round": 2,
"mode": "references",
"elapsed_ms": 10.888227999999799
}
],
"resources": {
"elapsed_seconds": 31.347,
"cpu_seconds": 31.05517,
"peak_cgroup_bytes": 1589915648,
"payload_cleanup_verified": true,
"events_at_payload_exit": {
"memory.events": {
"low": 0,
"high": 0,
"max": 0,
"oom": 0,
"oom_kill": 0,
"oom_group_kill": 0
},
"pids.events": {
"max": 0
}
}
}
},
"validation": {
"baseline_public": "Quoted and cooked-template cases retained 200000-unit normalized literals and failed; addition and small exact controls passed. Aggregate-capacity test passed.",
"baseline_domain_corrected": "2 over-bound failures, 16 passed. Initial combined-run domain assertions had incorrectly required an empty optional resourceLimits array; corrected before using the domain reproduction as evidence.",
"fixed_focused": "55 passed across five files.",
"semantic_suite": "923 passed across 36 files.",
"capacity_after_fixture_cleanup": "1 passed; all 16 bounded values, aggregate size >= original, typed identities and retained tracing preserved.",
"interim_static_failure": "Typecheck rejected resume() on the new test SDK stderr Stream declaration. Switched to its declared data event, matching existing typed tests; analyzer source unchanged.",
"public_boundary_after_stream_type_fix": "4 passed across actual CLI and stdio MCP; analyzer source unchanged."
}
},
{
"stage": "Projection/default correction; final review subsequently found unnormalized request endpoints",
"revision": "38d263a369e7853ccfae1c8e0a3bd387f920c7cf",
"source_sha256": {
"scripts/verify/javascript/module-references.mjs": "9d5f0b8b35ed2ebb4591f9dc3baea0fc116a0c3fd7d8e5ce30ec476c84671ed1",
"src/application/javascript/JavaScriptSemanticGraphDataProjection.ts": "844d4639401a9f050ce42c80192572a6d0d74fe4f81b37e93a2c20aaca9fb9a6",
"src/domain/javascript/javascriptSemanticAnalysis.ts": "a3f802ca3446c2b5376cc58b19d818eff318e6775bd47752793c3f649994f8a2",
"src/domain/javascript/javascriptSemanticAnalysis.unions.test.ts": "2e78717d30e637b5fc5bab6d0eff063f7a62e0199d33697c1cdfaf8317baa698",
"src/domain/javascript/javascriptSemanticDataEffectHelpers.ts": "8f9cf1a36f05b03dd816eaf9a6cdba0160d34ad7d17a961206e1bc32444d2ccc",
"src/domain/javascript/javascriptSemanticDataEffects.ts": "e69408f2f5910a0107fd5d0cae0ff60ed706448857bc8e535c37cac1a0cd4d37",
"src/domain/javascript/javascriptSemanticIr.ts": "68dad360d0a9e6bd72108b2717cae756b84ca1efb48455248ded2ff699d2c113",
"src/domain/javascript/javascriptSemanticPrimitives.ts": "899eeb6ccdf666f504f8b722327599997c924c8e4fb13a1cbd13edaf08c96640",
"src/domain/javascript/javascriptSemanticResourceLimits.ts": "0993a397f2a2a48c2b6c35494e940b3fce5c2c9032cfe33c7cf0401128c79dde",
"src/domain/javascript/javascriptSemanticState.ts": "bfcface5dcda22594f47ed390efa15f9140fe41cb2d5995896e52dd0ee31b978",
"src/domain/javascript/javascriptSemanticValues.ts": "a4ba51cc60fff38ef11fd5af35a2e1ad753cdb2dea9d44895f91d89320c5ddeb",
"tests/boundary/mcp/javascriptLiteralBudget.test.ts": "070106115b482269794799e448bd20b8e02df1f511f4ceb2b8fa75612c7f78e4",
"tests/boundary/mcp/javascriptLiteralPayload.test.ts": "03618272c605f8877ed171ab39e037e4d80eac72b7478421640076f739adfb50"
},
"real_control_cohort": {
"preparation_ms": 19599.643274,
"query_samples": [
{
"round": 0,
"mode": "legacy",
"elapsed_ms": 396.9265450000021
},
{
"round": 0,
"mode": "references",
"elapsed_ms": 15.658120000000054
},
{
"round": 1,
"mode": "references",
"elapsed_ms": 12.24905100000251
},
{
"round": 1,
"mode": "legacy",
"elapsed_ms": 237.03392900000108
},
{
"round": 2,
"mode": "legacy",
"elapsed_ms": 357.78818299999693
},
{
"round": 2,
"mode": "references",
"elapsed_ms": 14.37622100000226
}
],
"resources": {
"elapsed_seconds": 33.969,
"cpu_seconds": 33.499223,
"peak_cgroup_bytes": 1893015552,
"payload_cleanup_verified": true,
"events_at_payload_exit": {
"memory.events": {
"low": 0,
"high": 0,
"max": 0,
"oom": 0,
"oom_kill": 0,
"oom_group_kill": 0
},
"pids.events": {
"max": 0
}
}
}
},
"validation": {
"original_main": "Quoted/template oversized literals failed through public CLI/MCP; addition/small controls passed. Corrected domain boundary reproduced 2 failures/16 passes.",
"review_head": "8 failed/25 passed before fixes for projection tags, encountered-but-discarded limits and bare quoted/template defaults; includes exact null default control.",
"interim_review_fix": "65/66 focused passed; old doubling-chain expectation omitted a genuine expression-depth limit now observed. Adjusted that assertion to preserve the byte-limit requirement while allowing other observed classes.",
"final_focused": "66 passed in five files.",
"final_semantic_suite": "932 passed in 36 files.",
"arithmetic": "Computed 174762*6+2=1048574 and 174763*6+2=1048580. Corrected the erroneous published 1048578 total.",
"final_grouped_domain": "27 passed after grouping observations/defaults/allocation within function-size rules; no scenarios removed.",
"endpoint_review_baseline": "Production at 38d263a: 7 failed/14 passed across 13 new domain and 8 CLI/MCP cases before endpoint normalization. The later public linked-response case was not in this baseline run. Regression tests were uncommitted; final formatted test hashes are preserved, not claimed as the baseline test bytes.",
"endpoint_selection_attempt": "First six-file selection exited before execution because a signed-zero test filename was mistyped; corrected the exact path. No test result claimed for that attempt."
}
},
{
"stage": "Rejected endpoint normalization: violated existing full-endpoint lookup/trace contract; reverted after CI acceptance failure",
"revision": "580887209c4fceda432eac4083fac82a0dd78f15",
"source_sha256": {
"scripts/verify/javascript/module-references.mjs": "9d5f0b8b35ed2ebb4591f9dc3baea0fc116a0c3fd7d8e5ce30ec476c84671ed1",
"src/application/javascript/JavaScriptSemanticGraphDataProjection.ts": "a648f97e631985edcb5259ff4f1fdf0332dca18b8c10b57e050e36a785c1c524",
"src/domain/javascript/javascriptSemanticAnalysis.requestBudget.test.ts": "8e84ffa70d834f5589d04118f0aaf33b0383b15ea97545ff69c66a74473aca73",
"src/domain/javascript/javascriptSemanticAnalysis.ts": "a3f802ca3446c2b5376cc58b19d818eff318e6775bd47752793c3f649994f8a2",
"src/domain/javascript/javascriptSemanticAnalysis.unions.test.ts": "2e78717d30e637b5fc5bab6d0eff063f7a62e0199d33697c1cdfaf8317baa698",
"src/domain/javascript/javascriptSemanticDataEffectHelpers.ts": "8f9cf1a36f05b03dd816eaf9a6cdba0160d34ad7d17a961206e1bc32444d2ccc",
"src/domain/javascript/javascriptSemanticDataEffects.ts": "eed961e0b1d8a320e76bbba933408e950b4a4a446110401e8cf470f1e74d8315",
"src/domain/javascript/javascriptSemanticIr.ts": "3b2ede73dbcfc74c4014e4d1affcbf00ecccc29a422ed495a7a3f2f517056c9b",
"src/domain/javascript/javascriptSemanticPrimitives.ts": "899eeb6ccdf666f504f8b722327599997c924c8e4fb13a1cbd13edaf08c96640",
"src/domain/javascript/javascriptSemanticResourceLimits.ts": "0993a397f2a2a48c2b6c35494e940b3fce5c2c9032cfe33c7cf0401128c79dde",
"src/domain/javascript/javascriptSemanticState.ts": "bfcface5dcda22594f47ed390efa15f9140fe41cb2d5995896e52dd0ee31b978",
"src/domain/javascript/javascriptSemanticValues.ts": "a4ba51cc60fff38ef11fd5af35a2e1ad753cdb2dea9d44895f91d89320c5ddeb",
"tests/boundary/mcp/javascriptLiteralBudget.test.ts": "61319ea954de7f256841f43ca9355a1706ce8e93d30f2a8ba851d5e717bd19e7",
"tests/boundary/mcp/javascriptLiteralPayload.test.ts": "03618272c605f8877ed171ab39e037e4d80eac72b7478421640076f739adfb50"
},
"real_control_cohort": {
"preparation_ms": 19939.160272,
"query_samples": [
{
"round": 0,
"mode": "legacy",
"elapsed_ms": 348.3974309999976
},
{
"round": 0,
"mode": "references",
"elapsed_ms": 13.97052899999835
},
{
"round": 1,
"mode": "references",
"elapsed_ms": 12.060379000002285
},
{
"round": 1,
"mode": "legacy",
"elapsed_ms": 212.01217800000086
},
{
"round": 2,
"mode": "legacy",
"elapsed_ms": 223.73954800000138
},
{
"round": 2,
"mode": "references",
"elapsed_ms": 10.450989999997546
}
],
"resources": {
"elapsed_seconds": 33.062,
"cpu_seconds": 32.71624,
"peak_cgroup_bytes": 1897406464,
"payload_cleanup_verified": true,
"events_at_payload_exit": {
"memory.events": {
"low": 0,
"high": 0,
"max": 0,
"oom": 0,
"oom_kill": 0,
"oom_group_kill": 0
},
"pids.events": {
"max": 0
}
}
}
},
"validation": {
"original_main": "Quoted/template oversized literals failed through public CLI/MCP; addition/small controls passed. Corrected domain boundary reproduced 2 failures/16 passes.",
"review_head": "8 failed/25 passed before fixes for projection tags, encountered-but-discarded limits and bare quoted/template defaults; includes exact null default control.",
"interim_review_fix": "65/66 focused passed; old doubling-chain expectation omitted a genuine expression-depth limit now observed. Adjusted that assertion to preserve the byte-limit requirement while allowing other observed classes.",
"final_focused": "81 passed in six files; the same CLI/MCP file then passed 9/9 after adding a linked-response case. That follow-up replaces its earlier 8-case coverage; 82 distinct cases across the final six-file selection, not one 82-case invocation.",
"final_semantic_suite": "945 passed in 37 files, overlapping focused domain coverage.",
"arithmetic": "Computed 174762*6+2=1048574 and 174763*6+2=1048580. Corrected the erroneous published 1048578 total.",
"final_grouped_domain": "27 passed after grouping observations/defaults/allocation within function-size rules; no scenarios removed.",
"endpoint_review_baseline": "Production at 38d263a: 7 failed/14 passed across 13 new domain and 8 CLI/MCP cases before endpoint normalization. The later public linked-response case was not in this baseline run. Regression tests were uncommitted; final formatted test hashes are preserved, not claimed as the baseline test bytes.",
"endpoint_selection_attempt": "First six-file selection exited before execution because a signed-zero test filename was mistyped; corrected the exact path. No test result claimed for that attempt.",
"endpoint_typecheck_attempt": "Full static gate found the inferred optional dataField in the public test computed key. Replaced the in-property check with an explicit bare === true discriminant; scenario inputs and runtime implementation unchanged. Corrected static/public checks recorded separately.",
"final_gates": "Full static gate passed after the explicit test discriminant; final public file passed 9/9 again, then docs gate passed including 5 consistency tests. Runtime implementation unchanged after the 945-test semantic suite and real control."
},
"ci_failure": {
"run_id": 38758262643,
"job_id": 116503076738,
"test": "tests/acceptance/applications/javascriptEndpointPayload.test.ts",
"result": "1 failed/1573 passed/19 skipped; request endpoint no longer matched its complete source value. Other local tests and real Obsidian control passed but did not establish this compatibility contract.",
"aggregate_result": "Merged source/built report: 1 failed/15625 passed/138 skipped. Portable tests and CI required failed as aggregates of the same endpoint assertion; no separate additional failed test."
}
}
],
"review_baseline_revision": "40b9d3c5b9cbeae7661d8e351e1b5ef6e5338931",
"review_baseline_source_sha256": {
"scripts/verify/javascript/module-references.mjs": "9d5f0b8b35ed2ebb4591f9dc3baea0fc116a0c3fd7d8e5ce30ec476c84671ed1",
"src/application/javascript/JavaScriptSemanticGraphDataProjection.ts": "ee541e634264363822bf4ce05c42c72272029c7e8da72bbeed643ad1341d0756",
"src/domain/javascript/javascriptSemanticAnalysis.ts": "a1cf791a61ee4742c351c006b69b64eba6bef3068f7a8450ed8f9366bfe4ff88",
"src/domain/javascript/javascriptSemanticAnalysis.unions.test.ts": "747d893d6ddd91cf24d3b62b7eb50e0af9b1715ab355bbfc2e10ed0dc171ec17",
"src/domain/javascript/javascriptSemanticDataEffectHelpers.ts": "5ee7af18dd847726d8fe1828ea25f386ff9ef317d996a3f7969253bf73973cfa",
"src/domain/javascript/javascriptSemanticDataEffects.ts": "4c62462016246bc7198294a74a60e87598fc009c53f1601abc2d4662d41b5bd1",
"src/domain/javascript/javascriptSemanticIr.ts": "14955cb4b7912ed6a4f26f804a2480f841dcb6084dbddd15856375fa62cdcfa1",
"src/domain/javascript/javascriptSemanticPrimitives.ts": "899eeb6ccdf666f504f8b722327599997c924c8e4fb13a1cbd13edaf08c96640",
"src/domain/javascript/javascriptSemanticResourceLimits.ts": "0203d207e0d6bb8aaa17746090f008876a11653afd660fce3dc44f3fda646a6c",
"src/domain/javascript/javascriptSemanticState.ts": "d94c5a88bb105284fab192406a8c88860d59f80c93394ed3ee7264969df254a6",
"src/domain/javascript/javascriptSemanticValues.ts": "2debbb4f32d7d189819f2413f0f7d05b9bdcf497451a1c578475e3f2ec6c8554",
"tests/boundary/mcp/javascriptLiteralBudget.test.ts": "46ceb5a169de3eec3a335b05ef4aa7b1b341a5ac06ad325bd191e862c5b6be70",
"tests/boundary/mcp/javascriptLiteralPayload.test.ts": "03618272c605f8877ed171ab39e037e4d80eac72b7478421640076f739adfb50"
},
"implementation": "Per-analysis state records encountered resource classifications at expression/default normalization; final coverage consumes those facts. Slot projection preserves tagged unknown values. Removed retained-value recursive coverage scan and duplicate raw default reader. Defaults retain optional valueResourceLimit and graph value_resource_limit plus an anchored resource-limit unknown; known null/false/0/empty remain exact. Endpoint identities intentionally remain exact lookup values, outside the normalized primitive lattice; rejected endpoint normalization and its CI failure are preserved separately.",
"restored_production_revision": "38d263a369e7853ccfae1c8e0a3bd387f920c7cf",
"final_corrected_resource_receipts": {
"public_7": {
"elapsed_seconds": 43.621,
"cpu_seconds": 43.097453,
"peak_cgroup_bytes": 1520324608,
"payload_cleanup_verified": true,
"events_at_payload_exit": {
"memory.events": {
"low": 0,
"high": 0,
"max": 0,
"oom": 0,
"oom_kill": 0,
"oom_group_kill": 0
},
"pids.events": {
"max": 0
}
}
},
"static_and_docs": {
"elapsed_seconds": 111.403,
"cpu_seconds": 110.830839,
"peak_cgroup_bytes": 4268244992,
"payload_cleanup_verified": true,
"events_at_payload_exit": {
"memory.events": {
"low": 0,
"high": 0,
"max": 0,
"oom": 0,
"oom_kill": 0,
"oom_group_kill": 0
},
"pids.events": {
"max": 0
}
}
}
}
}
@@ -1,86 +0,0 @@
# Semantic literal byte-budget verification
Tracks #3933 under #4027. All normalized semantic literals and configuration
defaults use the primitive owner. Its singleton path validates strings/nonfinite
numbers/negative zero without a Set, sorting or canonical-key serialization.
Each source analysis owns a bounded set of encountered limit classifications;
coverage consumes these observations after evaluation. This replaces a recursive
scan that only saw retained binding/return values. No persistent cache is added.
## Correctness and coverage
Public CLI and actual stdio MCP cases cover quoted strings, cooked templates,
equivalent concatenation, member receivers, a configuration-only expression
statement and a small exact control. Direct/default oversized values become
`resource-limit` unknowns with partial application coverage and
`javascript_semantic_primitive_bytes = 1048576`. Defaults carry
`value_resource_limit` inline and an unknown anchored to their config node.
Known null/false/zero/empty defaults remain exact. Original source/digests and
CLI/MCP identity parity are preserved.
Member and destructuring projections use the shared slot owner's tagged value.
An encountered limit stays visible even when a subsequent projection selects a
healthy sibling: the selected value remains exactly `7`, while file coverage is
partial. This avoids inferring completeness from the final retained values alone.
The duplicate raw default reader and superseded retained-value scan are removed.
Boundary controls admit 174,762 UTF-16 units (1,048,574 estimated JSON bytes)
and reject 174,763 (1,048,580 bytes). Actual arithmetic corrected the earlier
published 1,048,578 total; the unit-count boundary assertions were already correct.
The estimate counts six bytes per unit plus two quotes. It does not establish
actual ASCII JSON size above 1 MiB or an observed OOM.
The initial main baseline reproduced both public literal failures, with addition
and small controls passing. A mistaken optional-limit-array control was corrected
before the separate domain reproduction (2 failed/16 passed). Review head
`40b9d3c5` then reproduced the additional projection/default gaps (8 failed,
25 passed). The first review correction passed 65/66 focused tests; a doubling
chain now truthfully retains an additional encountered expression-depth limit,
so its byte-growth assertion was updated to allow other recorded limits.
Prior validation on the restored runtime: **66 focused tests** in five files and **932 semantic tests**
in 36 files, with overlapping domain coverage. The large-wire fixture retains
16 individually admitted values and at least the former aggregate UTF-16 payload,
plus complete CLI/MCP delivery, typed identities, empty strings and retained
tracing. Inputs regenerate from the tests.
## Endpoint identity compatibility
An attempted endpoint normalization at `5808872` passed its new local cases and real Obsidian control, but failed the existing CI endpoint-payload acceptance workflow (1 failed/1,573 passed/19 skipped in that shard). It violated the established full endpoint lookup/trace contract. This extension was reverted; endpoint values are lookup identities, outside the normalized primitive lattice. The original large endpoint is preserved. Corrected public validation passed **7/7** across two files; this adds one acceptance workflow to the previous 66-case focused selection (**67 distinct cases**, not one 67-case invocation). Its acceptance workflow now also normalizes that identical string as an exported primitive, requiring the typed value bound while endpoint lookup, both trace workflows and version comparison remain usable. Prior measurements and failed attempts remain in the JSON record. Production source is restored byte-identical to `38d263a`; the 932-test semantic run belongs to that state. Final full static and documentation gates (five consistency tests) passed after the compatibility correction.
## Real application control and costs
Official Obsidian 1.14.4 ASAR, selected `package.json` and `main.js`. Follow the
acquisition/digest and existing verifier command in
[module-reference verification](javascript-module-references-2026-10-15.md).
Use three alternating-order query pairs with CLI parity on each revision.
Application code is not executed.
The final correction retains the exact baseline full parent/view Evidence IDs,
23-row fact digest, source coverage and unknowns. Static `cl100k_base` task costs
remain 16,548 with selected name/description/inputSchema contracts, or 204,093
with the full catalog projection, for the reference workflow. Serial legacy
reads also keep their original costs. The query projection improvement belongs
to #4097; these are controls for semantic normalization and coverage.
| Complete real verifier | Before | Final correction |
| ---------------------- | ------------: | ---------------: |
| Elapsed seconds | 33.394 | 32.949 |
| CPU seconds | 33.016802 | 32.559187 |
| Peak cgroup bytes | 1,979,863,040 | 1,880,096,768 |
Includes initial analysis, both query arms, export, CLI parity and tokenizer.
One CPU, 8 GiB hard cap, 6 GiB early stop, no swap; cleanup verified and no OOM.
Memory includes charged file cache, not summed RSS. Counters are at payload exit
while the observer remains alive. Fresh MCP sessions do not establish OS-cold
cache conditions. Shared-host scheduling and filesystem/build warmness were
uncontrolled. This one before/after control establishes neither a speedup nor
an equivalence bound. Static BPE excludes annotations/output schemas, client
rendering/replay, reasoning and final answers; no hosted agent was run. Linux
static ASAR analysis was exercised, not live Electron or other platforms.
[Compact records, samples, source hashes and prior attempts](javascript-literal-byte-budget-2026-10-15.json)
preserve the initial incomplete correction separately from the final measurements.
No downloadable application or complete bundle is archived. Reproduce boundary
outcomes through the listed public tests and reuse the existing real verifier
and preserved 8 GiB observer linked above. Observer hashes and result-affecting
touched source hashes are pinned in the records.
File diff suppressed because it is too large. Load diff
@@ -1,179 +0,0 @@
# Native handoff byte-identity verification
Tracks #3926 under #4027. Baseline: `9f8659e0536e4e50a438f5b9d5661f3c9624f6ac`.
Final integration base: `62bf09809ef7bb224028916424f8f07652a20f4f`.
The analyst already knows an ASAR-relative native path and supplies prior native
Evidence. The question is which Evidence can be linked to that component's exact
bytes. Discovery and native-provider execution are outside this task.
## Observed behavior and correction
The native-node producer distinguishes a content digest from a canonical path
whose bytes are unavailable. Its unavailable observation legitimately cites the
containing archive. The handoff consumer previously treated that supporting
artifact digest as the native component's digest.
Public CLI/stdio MCP regression: the missing-companion case failed and the
available-byte control passed. Real Joplin reproduced the same result: missing
keytar bytes produced an `evidence-linked` handoff with the ASAR digest and the
simulated container observation. CLI/MCP agreed on that incorrect answer.
The consumer now uses only the node owner's content-digest identity. The fallback
observation scan is removed. Unavailable native nodes retain their canonical
path, availability, container-backed provenance and partial coverage in the
inline graph; they yield no false actionable handoff or native Evidence link.
An empty handoff list describes eligibility, not absence of native components.
The per-query node index is allocated only after an eligible target exists; no
persistent cache, schema, tool or target authority is added.
Final real checks passed both cases with exact CLI/MCP trace parity. The available
control preserved the complete parent/trace Evidence IDs, native facts, links,
coverage and all token projections. The missing control preserved its parent,
native node, source provenance and coverage, while removing the wrong handoff
and container Evidence link.
## Real input and scope
[Official Joplin v3.7.21 Linux AppImage](https://github.com/laurent22/joplin/releases/download/v3.7.21/Joplin-3.7.21.AppImage),
published 2026-09-25, 201,462,481 bytes, SHA-256
`5d202dcaca31e14206826aa3f04125e7c218dbc3dc3d98479d811efbd6b856c1`.
Read-only 7z 26.02 inspection found 6,324 ASAR files, 46 unpacked entries and
three `.node` components. Extract only the ASAR and those three binaries:
```sh
input_root="$(mktemp -d -t rea-native-handoff-XXXXXX)"
curl --fail --location --output "$input_root/Joplin-3.7.21.AppImage" \
https://github.com/laurent22/joplin/releases/download/v3.7.21/Joplin-3.7.21.AppImage
sha256sum "$input_root/Joplin-3.7.21.AppImage"
7z x -mmt=1 "-o$input_root/extracted" "$input_root/Joplin-3.7.21.AppImage" \
resources/app.asar \
resources/app.asar.unpacked/node_modules/keytar/build/Release/keytar.node \
resources/app.asar.unpacked/node_modules/sqlite3/lib/binding/napi-v6-linux-glibc-x64/node_sqlite3.node \
resources/app.asar.unpacked/node_modules/onnxruntime-node/bin/napi-v6/linux/x64/onnxruntime_binding.node
python3 - "$input_root" <<'PY'
import os, sys
from pathlib import Path
root = Path(sys.argv[1])
source = root / 'extracted/resources'
for mode in ('available', 'missing'):
case = root / 'cases' / mode
case.mkdir(parents=True)
os.link(source / 'app.asar', case / 'app.asar')
if mode == 'available':
for native in (source / 'app.asar.unpacked').rglob('*.node'):
target = case / native.relative_to(source)
target.parent.mkdir(parents=True, exist_ok=True)
os.link(native, target)
PY
```
Verify the asset digest above before extraction. The ASAR is 233,575,014 bytes,
SHA-256 `767df409b18effe60421fbefcca873de237c7e813eac744ecdeebbc5e825a33a`.
Keytar is 76,960 bytes, SHA-256
`0700016bcd761cbe02d275f2046c7cc42f39f730a50d66e3d3307aa9d413373a`.
All extracted component hashes are in the JSON record. 7z reported one
trailing-data warning for the AppImage's embedded SquashFS and exited 0.
Both cases select only `package.json` for static source analysis while retaining
the inventory. The available case stages all three native companions; the other
43 unpacked entries are not staged. The missing case stages none. Whole-application
coverage is therefore partial in both cases, independently of the selected
native component's known or unknown byte identity. Neither the application nor
a native analysis provider is executed. Native Evidence is explicitly simulated
to test exact subject linkage. Live Electron, real Ghidra/Hopper/IDA behavior and
Windows/macOS verification are **NOT_ENOUGH_INFO**.
## Reproduce the public workflow
Use pinned Node 24.18.0/npm 11.16.0, `npm ci`, then `npm run build:cached`.
The verifier returns compact records and deletes its private exported parent and
CLI input after owned cleanup. No downloadable application or large Evidence is
archived.
```sh
for mode in available missing; do
node scripts/verify/javascript/native-handoffs.mjs \
--artifact "$input_root/cases/$mode/app.asar" \
--addon-path node_modules/keytar/build/Release/keytar.node \
--native-sha256 0700016bcd761cbe02d275f2046c7cc42f39f730a50d66e3d3307aa9d413373a \
--source-path package.json --rounds 3 --cli-parity --require-safe
done
```
Add `--tokenizer-python /absolute/path/to/python-with-tiktoken-0.12.0` for the
reported BPE projections. The npm alias `verify:javascript:native-handoffs`
builds first; recorded costs use the direct Node invocation above after building.
For a pre-fix observation, run the saved verifier on the baseline build without
`--require-safe`; `safe_identity: false` is an incorrect answer, not a passing
analyst task. Paths affect serialized requests and some Evidence identities.
The exact resource runs additionally used the preserved
[8 GiB observer](https://github.com/morluto/rea/blob/b3bdabab694af1f9801eff7caf75001b92314a58/experiments/analysis-efficiency/resource-run.py)
and adjacent `resource_payload.py`; both hashes are pinned in the JSON.
## Completed workflow costs and limits
| Case | Revision | Wall s | CPU s | Peak cgroup bytes | Identity oracle |
| ---------------------- | -------- | ------: | ---------: | ----------------: | -------------------------- |
| Native bytes available | Before | 60.369 | 59.806670 | 2,662,629,376 | pass |
| Native bytes available | After | 258.885 | 106.221003 | 2,678,456,320 | pass, exact baseline facts |
| Native bytes missing | Before | 57.930 | 57.479109 | 2,719,457,280 | wrong identity/linkage |
| Native bytes missing | After | 59.738 | 59.254776 | 2,571,235,328 | pass, unknown retained |
Whole-verifier resources include input hashing, analysis, three retained trace
queries, export, CLI parity and tokenization. One CPU, 8 GiB hard cap, 6 GiB early
stop, no swap; cleanup verified and no OOM. Memory includes charged file cache,
not summed RSS. Counters are at payload exit while the observer remains alive.
The available control's final wall and CPU times are substantially higher than
baseline. Earlier post-fix controls on the original base took 61.657/74.956 s wall
and 61.135962/60.352428 s CPU for available/missing cases; their complete receipts
remain separately recorded. The final missing case took 59.738 s wall. This
variability is unresolved and cannot be attributed to the native consumer change.
These runs establish neither speedup nor performance equivalence. Input hashing warms the ASAR
cache, build/OS caches and shared-host scheduling are uncontrolled. Fresh MCP
sessions do not establish OS-cold conditions. First post-analysis and repeated
warm-query samples are preserved separately; query CPU/memory are unmeasured.
One defined task is one analysis summary plus one retained trace, with the path
and prior Evidence already supplied. Static `cl100k_base`/tiktoken 0.12.0 counts
include both requests, replies and name/description/inputSchema contracts:
| Available-byte task, unchanged before/after | BPE tokens |
| ----------------------------------------------- | ---------: |
| Selected catalog + structured replies | 12,340 |
| Selected catalog + complete tool replies | 18,906 |
| Full catalog projection + structured replies | 202,292 |
| Full catalog projection + complete tool replies | 208,858 |
These are alternative reply/catalog projections. The selected catalog alone is
5,570 BPE; the full projection is 195,522. Output schemas, annotations, host
rendering/replay, reasoning, final answers and model billing are unmeasured.
Repeated queries/export/CLI/tokenization are validation overhead outside this
one-task token count, but inside resource receipts. Missing-case structured-task
counts change 11,372 → 11,103 by removing unsupported claims; the incorrect
baseline earns no efficiency credit.
## Regression and verification record
The initial four-file focused selection passed 24 tests. The two public cases
were rerun after adding named summary-result parsing and correcting an optional
architecture factory input. Omitting that field instead of passing null produced
byte-identical normalized simulated Evidence in all four real-case inputs.
The initial CLI-selector harness error and first typecheck failure are retained
as harness/validation attempts, not product reproductions.
After syncing the reviewed upstream changes, the updated application workflow
CLI acceptance file passed 34 tests, bringing the focused selection to 58 distinct
cases across five files. Both Joplin controls were then repeated on the final
integration base. Canonical byte identity is also used by the related version
matching/content comparison consumers; no equivalent observation-digest fallback
was found there.
Final `npm run check && npm run docs:check` passed on the integration base,
including five documentation consistency tests: 128.732 s wall, 115.518920 s CPU,
4,301,684,736 B peak cgroup memory, clean owned exit and no OOM.
Final public and static/docs outcomes are recorded in the
[compact measurements and source pins](javascript-native-handoff-identity-2026-10-15.json).
File diff suppressed because it is too large. Load diff
Loaded 100 of 1504 files, more files were not shown because too many files have changed in this diff. Show more