* fix(ci): skip portable report merge when shards are skipped
The portable consumer can still run after an upstream build failure, even though the test-shard matrix is skipped and no Vitest blob artifacts exist. Guard artifact download and both report merge variants on successful shards; retain the required-shard gate so skipped or failed shards remain failures.
This applies the report-consumer condition from ee0256c740 to current pinned main without changing action pins or required gates.
* fix(ci): preserve failed shard diagnostics
* docs: clarify current revision CI policy
* fix(native): parse renamed dyld_info re-exports
dyld_info prints a re-export whose name differs from the source library's
symbol as `[re-export] _foo_renamed (_foo from libfoo)`. The export parser
only accepted `(from libfoo)`, so inspect_macho reported a nonexistent
export named `_foo_renamed (_foo from libfoo)` with no source, and the nm
row for `_foo_renamed` survived the name-based merge as a second export
with reexport null.
Accept the optional source symbol, trying the plain `(from lib)` form
first so a library name containing ` from ` keeps its text. The row now
reports `_foo_renamed` re-exported from libfoo and replaces the nm
duplicate. The export schema has no field for the source symbol name, so
exports coverage records a limitation when a renamed re-export is present.
The golden fixture is a dyld_info capture of a synthetic dylib linked with
-Wl,-alias,_foo,_foo_renamed.
* fix(native): split dyld re-export suffix without nested quantifiers
Replace the (?:(.+?)\s+)??from lazy-optional group with a linear string
scan so malformed lines cannot backtrack and a library path containing
" from " still keeps its whole text via the plain-form-first check.
* test(native): cover nested re-export library names
* fix(native): retain reexports missing from nm inventory
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: morluto <17176810+morluto@users.noreply.github.com>
CLI path normalization resolved every nonblank selected string against
the working directory, so executable_path "file:///opt/electron" became
an invented local path and failed with ENOENT for that location instead
of the field's local-path requirement. Leave `file:` and `scheme://`
references unchanged so the shared schema rejects them as non-local
paths. One-letter prefixes stay paths, so Windows drive paths and
relative names containing a colon resolve as before.
Fixes#2577
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Carry the require callee from dependency extraction into lexical scope
validation so optional calls remain visible without admitting shadowed
loaders.
Fixes#2883
* fix: repair the static-check failures on the default branch
The default branch fails its own required `Static checks` job three ways, so
every pull request reports that job as failed regardless of its own change.
- `npm run format:check` reports `src/domain/functionComparison.test.ts` and
`src/ida/IdaOperationRunner.ts`.
- `npm run lint` reports a duplicate `import { join } from "node:path"` in
`tests/boundary/mcp/ghidraInventoryMcp.test.ts` (lines 4 and 17).
- `npm run typecheck` reports `format: "devin"` missing from the client format
union in `src/application/SupportedClients.ts`, and an unchecked index in
`tests/boundary/cli/clientProfileLifecycle.test.ts`, whose pair array is
inferred as `string[][]`.
Apply the pinned formatter, drop the duplicate import, list the `"devin"` format
that its own definition already uses, and mark the pair array `as const`.
Validation: `npm run check:fast` and `npm run format:check` pass.
* fix(setup): keep Devin on the JSON configuration dialect
---------
Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Update Chinese README docs
Refresh the Chinese README guidance to mention IDA as a supported native analysis backend, clarify that static JavaScript analysis does not require native engines, and document global CLI installation/update steps for Bun (`bun add --global`, `bunx` usage, minimum version 1.2.17). The capability table also now includes Go binary and WASM artifact support.
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* docs(website): document Apple Silicon Cairo setup for local preview
* docs(website): scope Apple Silicon Cairo fix to preview process
* docs(website): avoid shared-prefix rewrite and clobbering backup
* docs(website): keep shared Intel libs intact with same-shell Cairo lookup
* docs(website): enter ARM shell before exporting Cairo lookup
* docs(website): use ARM brew path and unprotected Python for Cairo
* docs(website): reinstall requirements after ARM venv rebuild
* docs(website): document DejaVu font dependency
* docs(website): show ARM Python selection for venv rebuild
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(browser): attach passive tools to browsers without HTTP discovery
Accept a literal loopback browser WebSocket,
ws://127.0.0.1:PORT/devtools/browser/ID, as the cdp_endpoint of the six
passive browser tools. Discovery then reads Browser.getVersion and
Target.getTargets over that socket, and the target session adopts the
same socket, so a browser that asks for consent per connection prompts
once per call.
The socket identifier gates access, so Evidence records the endpoint as
ws://127.0.0.1:PORT/devtools/browser/[REDACTED], and runtime
reconciliation accepts that recorded form. HTTP endpoints and their
Evidence are unchanged. Electron, web runtime, scenario and Inspector
endpoints stay HTTP-only.
Refs #2288
* test(browser): match browser-socket captures against HTTP discovery
Check in the real Chrome lane that DevToolsActivePort names the same
browser socket as /json/version, and that inspecting the selected page
through that socket leaves DOM structure and scripts unchanged compared
with an inspection through HTTP discovery.
Refs #2288
* fix(browser): bound browser-socket handshake and report discovery timeouts
Run the browser-socket WebSocket handshake and both discovery commands
under one discovery deadline, so a port that accepts the connection but
never completes the upgrade times out instead of waiting forever.
Report a reached deadline as a timeout without carrying the internal
abort as its cause, so CLI and MCP project provider_timeout rather than
cancelled. Caller cancellation is still reported as cancelled.
Refs #2288
* fix: repair the static-check failures on the default branch
The default branch fails its own required `Static checks` job three ways, so
every pull request reports that job as failed regardless of its own change.
- `npm run format:check` reports `src/domain/functionComparison.test.ts` and
`src/ida/IdaOperationRunner.ts`.
- `npm run lint` reports a duplicate `import { join } from "node:path"` in
`tests/boundary/mcp/ghidraInventoryMcp.test.ts` (lines 4 and 17).
- `npm run typecheck` reports `format: "devin"` missing from the client format
union in `src/application/SupportedClients.ts`, and an unchecked index in
`tests/boundary/cli/clientProfileLifecycle.test.ts`, whose pair array is
inferred as `string[][]`.
Apply the pinned formatter, drop the duplicate import, list the `"devin"` format
that its own definition already uses, and mark the pair array `as const`.
Validation: `npm run check:fast` and `npm run format:check` pass.
* fix(setup): keep Devin on the JSON configuration dialect
---------
Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(cli): start on Windows when USERPROFILE is empty
Node's Windows home lookup throws ERR_SYSTEM_ERROR (uv_os_homedir ENOENT)
for an empty USERPROFILE instead of consulting the account profile. Incur
resolves the home while it is imported, so every command, including
`rea --version`, stopped with a raw stack trace before REA ran.
Treat the empty selection as unset in the launcher, before any runtime
import, and cover startup with a compiled-CLI regression.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(process): report no remaining time after a provider deadline fires
Node timers can fire while performance.now() is still a fraction of a
millisecond short of the monotonic deadline. ProviderStartupDeadline then
reported interruption "timeout" and an aborted signal while remainingMs()
returned ceil(0.x) = 1, so polling loops guarded by remainingMs() > 0
(Hopper and Ghidra startup) could run past an elapsed deadline, and the
real-timer test "aborts a bounded wait when its real monotonic deadline
expires" failed intermittently in CI (expected 1 to be 0).
Once the deadline's own timer has classified a timeout, report zero
remaining time. A deterministic regression test fires the timer with the
monotonic clock 0.4 ms short of the deadline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
ECMA-426 DecodeSourceMapSources reads a content slot only while its index
is within sourcesContent, so a shorter array leaves trailing sources
without content and a longer array adds no sources. Local application
analysis and browser collection rejected any length mismatch and dropped
every original from the map.
The content helper now checks only entry types. Browser collection drops
its separate check because the leaf schema already validates every
supplied entry, and the raw records are still budgeted before parsing.
Fixes#2821
* fix(setup): treat empty DSH_HOME as unset (#2666)
The released `@deepseek-ai/dsh-home-paths` package explicitly treats an
empty or whitespace-only `DSH_HOME` as unset and selects the default
Harness home patch. `dshHomeDirectory` previously used nullish coalescing
(`env.DSH_HOME ?? join(home, ".dsh")`), so an empty override flowed
straight through `join(..., "cordis.patch.yml")` and produced a
cwd-relative `cordis.patch.yml` outside the client-selected home.
Treat empty and whitespace-only overrides as unset, matching the sibling
OpenCode override resolver and the released DSH resolver. The patch now
lands at `$DSH_HOME/cordis.patch.yml` for explicit overrides, the default
`~/.dsh/cordis.patch.yml` for empty/unset, and trimmed whitespace for
padded overrides.
Adds `src/application/SupportedClients.test.ts` covering the empty,
whitespace-only, unset, padded, and explicit cases via the public
`supportedClients(...)` entrypoint. Fixes#2666.
* test(setup): remove superseded DSH path unit coverage
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(native): search analyzed memory for masked byte patterns
The diff adds search_bytes to the CLI, the shared MCP contract, Ghidra
inventory, and the headless bridge, and advertises the same operation on
Hopper as unavailable until that provider is verified. Patterns are
hexadecimal byte pairs with optional ?? wildcards and an optional
equal-length bit mask; the TypeScript boundary and the bridge both
require a nonempty pattern, equal lengths, and at least one constrained
bit. Ghidra walks initialized blocks in address order within inclusive
bounds, keeps overlapping matches inside a single block, and returns
each hit with its segment, unique source file offset, and containing
procedure, continuing through a cursor bound to the target, profile,
pattern, mask, and bounds. Each page reports the inclusive ranges
examined and the skipped uninitialized blocks; cancellation returns a
typed error and discards the active Ghidra database.
address_to_file_offset now uses the same unique-offset helper, which
rejects a mapping that is missing, ambiguous, or larger than a safe
integer.
* fix(native): limit unbounded byte search to loaded memory
Without start or end, search_bytes walked every Ghidra block, including
non-loaded file parts such as .symtab and overlay blocks, which the docs
call out of scope. Unbounded searches now skip those blocks and list them
in searched.skipped_not_loaded; explicit bounds in their address space
still search them. Document that a match must end at or before end.
* fix(native): preserve implicit address spaces in range consumers
* fix(native): reject present malformed byte search state
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(targets): compare the Info.plist bplist prefix without ASCII folding
The six-byte prefix check used an encoding that maps high-bit bytes onto bplist, so a non-binary property list could be sent to the binary decoder.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(targets): satisfy the strict index check in the plist prefix test
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(artifacts): compare plist and NIB signatures without ASCII folding
Buffer.toString("ascii") drops the high bit, so a non-plist prefix could be decoded as bplist00 or NIBArchive and sent to the binary decoder.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(artifacts): satisfy the strict index check in the signature test
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(artifacts): remove superseded signature regression causing CI failure
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(setup): add Kimi Code client support
Registers rea in ~/.kimi-code/mcp.json (or $KIMI_CODE_HOME/mcp.json), preserving unrelated settings with a .rea.backup; registration is command-based stdio with no type field, startupTimeoutMs 30000 and toolTimeoutMs 120000 from MCP_STARTUP_POLICY.
Strict JSON parsing: empty or whitespace-only files initialize; malformed JSON is rejected untouched with no backup; explicit transport other than stdio reports invalid.
Bundled skill uses the shared ~/.agents/skills destination that Kimi Code discovers, installed and verified through the shared-skill flow.
Validated by 19 Kimi-specific tests, 260 adjacent-client regressions passing, check:fast and docs:check, and real-client verification on Kimi Code 0.40.1 (173 tools discovered, real mcp__rea__analyze_javascript_application call succeeded).
* fix(setup): preserve Kimi tool filters and strict JSON coverage
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* test(mcp): expect trace_feature to report references the provider truncated
A provider that reports a capped xrefs read makes the trace truncated with a residual unknown for that target. An explicit complete report and a provider that reports nothing leave the trace as before.
* fix(mcp): report references a provider truncated in trace_feature
Executions gain an optional flag for a capped xrefs read, set by the IDA adapter from the upstream cap. trace_feature marks the trace truncated with a residual unknown for that target only when the provider reports a truncation; a provider that reports nothing keeps its previous result. The trace_feature workflow profile is revised so earlier results are not replayed.
* refactor(ida): report reference truncation whenever the runner observed an xrefs cap
* test(mcp): cover session forwarding, per-target state, native reports and failures of the trace coverage
* test(mcp): format the session forwarding test
* test(process): format processCaptureLifecycle.test.ts after the merge
* test(ida): declare the alignment each synthetic universal slice offset satisfies
* fix(process): report no remaining time after a provider deadline fires
Node timers can fire while performance.now() is still a fraction of a
millisecond short of the monotonic deadline. ProviderStartupDeadline then
reported interruption "timeout" and an aborted signal while remainingMs()
returned ceil(0.x) = 1, so polling loops guarded by remainingMs() > 0
(Hopper and Ghidra startup) could run past an elapsed deadline, and the
real-timer test "aborts a bounded wait when its real monotonic deadline
expires" failed intermittently in CI (expected 1 to be 0).
Once the deadline's own timer has classified a timeout, report zero
remaining time. A deterministic regression test fires the timer with the
monotonic clock 0.4 ms short of the deadline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit dfdaa0ca74)
* fix(process): keep monotonic deadline ownership after merge
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(host): separate REA host support from Hopper installer targets
LinuxDistribution.supported carried two meanings at once: that the host runs
REA, and that the automated Hopper installer is tested on it. The doctor read
the first meaning from the second, so Debian-derived hosts such as Kali
reported unsupported_host while their providers worked normally.
Rename the field to hopperSetupSupported, which only the Hopper installer and
setup planning consume, and derive host support from the package family
through supportsReaHost(). Any distribution with a recognized apt, dnf, or
pacman family is now a REA host. The tested Hopper installer list is
unchanged, so Debian and Kali keep falling back to configuring an existing
provider instead of downloading an untested package.
Verified on Kali 2026.3 (Debian testing, x86_64): rea doctor reports a healthy
environment with Ghidra 12.1.4, and analyze_function decompiles an x86_64 ELF
through the MCP server. npm run check, npm run docs:check, and the application
and Ghidra suites pass. No Hopper or IDA host workflow was exercised.
* fix(setup): stop skill checks after first drift
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(cli): label each uninstall skill root by its client
rea uninstall reported every managed skill destination under the
shared "skill" label (with only Claude Code special-cased), so a
retained or failed directory could not be told apart from the others.
Use the destination's client identifier so the aggregated detail names
each root: "shared: retained (...)", "claude_code: removed (...)",
"antigravity: retained (...)". Retained and failed entries now point to
the specific directory that needs attention.
Fixes#2111
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(cli): align skill summary assertions with client and path labels
---------
Co-authored-by: wjl8636 <wjl8636@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(comparison): preserve incomplete function call evidence
Keep missing, unknown, partial and unresolved call relationships unknown in function comparisons and reconstruction claims. Aggregate IDA caller and callee coverage without overwriting uncertainty.
Validate with 144 focused tests, typecheck/lint, docs checks and test discovery. Real providers were not verified; the full headless IDA session suite requires unavailable Windows native controls.
* fix(comparison): recheck historical calls-only changes
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Error results reach the wire as text plus `isError: true`, but the
text-only envelope omitted the flag. An error up to 15 bytes above the
result budget passed both the delivery and transport checks and was sent
as the original diagnostic instead of taking the oversized-error recovery
path.
Rename the error representation to "error-text" and size its envelope
with the flag, so ToolResultDelivery and the error transport share the
complete delivered shape. Successful structured results are unchanged.
Fixes#2557
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
8823c55b0 added a HashMap use without its import, so Ghidra could not
compile ReaGhidraBridge.java and every Ghidra-backed operation exited
before bridge startup.
Co-authored-by: SeokMyungSeop <SeokMyungSeop@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(apple): exclude AppleDouble sidecars from IPA components
IPA projection returned every inventoried component before the AppleDouble
sidecar filter applied to directory, ZIP and DMG roots, so ._* and
__MACOSX/ metadata appeared as native libraries and frameworks while the
result reported that sidecars are excluded. Apply the sidecar exclusion
first for every root format; IPA still keeps non-sidecar components
outside Payload/.
Fixes#2546
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(apple): exercise the __MACOSX exclusion with a non-dotfile name
The IPA fixture's __MACOSX entry also started with "._", so the AppleDouble
filename rule excluded it and a broken __MACOSX check would go unnoticed.
Use a library name that only the __MACOSX rule excludes; the native
library assertion now fails if that rule regresses.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(sqlite): keep triggers whose declaration spells the table in another case
SQLite stores a trigger's target in sqlite_schema.tbl_name exactly as
written in CREATE TRIGGER and resolves it by ASCII case folding, while an
index stores the table's own name. The selected_table scope filtered
tbl_name with COLLATE BINARY, so a trigger declared ON users for table
Users was omitted while the schema still reported complete. Match
dependents with COLLATE NOCASE, and report each trigger's table as the
stored table or view name so the selected-table contract still holds.
* fix(sqlite): refuse an inexact table before the case-folded schema scan
With the NOCASE expansion, a selection such as users for table Users
expanded the stored table's declarations before readRows reported the
missing exact name, so large trigger definitions could surface as an
output-limit failure instead of the selection error. Check the exact
table name against PRAGMA table_list first and share the selection
failure with readRows.
* fix(sqlite): fold dependent names only for a row-selectable table
An exact view, virtual or possible shadow table passed the exact-name
guard, so the NOCASE scan could still expand a differently cased trigger
past the reply budget before readRows refused the selection. Fold case
only when the selection is an ordinary table that is not a possible
shadow table, and keep the exact filter otherwise so every refused
selection fails as it did before the case-folding change.
* fix(sqlite): resolve trigger tables without folding unrelated names
The stored-name lookup case-folded every PRAGMA table_list name up front,
so a selected-table inspection of a tiny table paid for large unrelated
identifiers. A selected-table scan only returns the selected table's
dependents, so report the selected name directly; other scopes use an
exact stored name when one matches and fold the stored names once, only
when a trigger spells its target differently.
* perf(sqlite): fold each table name once when matching shadow parents
The extracted shadow-parent helper folded the table name inside the find
callback, once per unresolved virtual table, and the selected table was
checked both before and during the schema scan. Fold the name once per
call as before, and reuse the selected table's result in the scan.
* Single owner for the Chrome DevToolsActivePort startup deadline
Cold Chrome startup tolerance was spelled three ways for one wait: the helper
fell back to 15,000 ms, the runtime fixture lifecycle passed a literal 60,000,
and the real-browser verifier kept a local 60,000 constant. A per-caller literal
quietly changes how long a lane tolerates a cold browser before it fails, and
the failure reported only elapsed_ms, so a reader could not see which ceiling
was hit.
Export BROWSER_DEVTOOLS_STARTUP_TIMEOUT_MS as the owner, use it for the helper
fallback and both call sites, and report startup_timeout_ms in
BrowserStartupError. A source guard keeps callers from restating the number.
* Pin the DevToolsActivePort deadline guard to the startup call argument
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Split two over-long test functions into module-level helpers
(max-lines-per-function): IdaSessionClient transport cases, IDA provider
composition, and function comparison identity cases keep their names and
assertions.
Also fix three typecheck errors: default omitted
direct_invokes_exhaustive to null so the result schema stays JsonValue
compatible, parse the ghidra dossier before spreading it, and delete the
optional beforeCall hook instead of assigning undefined under
exactOptionalPropertyTypes.
* fix(ida): let one-shot commands exit after retaining cleanup
When a headless IDA request outlives timeoutMs (for example idb_open on
a large binary still running auto-analysis), REA cannot prove the
worker stopped and correctly retains the upstream connection and
private workspace. The retained stdio child and its pipes stayed
referenced, so a one-shot CLI printed its cleanup_incomplete result and
then never exited, keeping the supervisor, worker and database alive.
Detach the retained connection's child process and pipes from the event
loop when cleanup fails. A long-lived MCP server can still retry
through the retained connection; a one-shot CLI exits with status 1,
and the supervisor observes end of input.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): report an unverified upstream worker after failed cleanup
Upstream ida-pro-mcp spawns headless workers in their own session and
deliberately leaves them running when its supervisor exits, so neither
a retained connection nor REA exiting proves that a timed-out worker
stopped. When cleanup fails before the owned worker's release is
confirmed, the cleanup diagnostics now name its private session and
state that it may still be running until it finishes and reaches its
idle timeout. Failures after a confirmed release, or before any open
was attempted, do not report a worker.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): name the inventory sessions that block worker release
When idb_close confirmed the requested worker gone but the follow-up
inventory still found a different peer on the private input, the
upstream_worker diagnostic named the released session and could
misdirect manual cleanup. Record the session ids of the inventory
entries that actually blocked release and report those; fall back to
the requested private session only when no inventory evidence exists
(an incomplete open or an unanswered request). The field becomes
session_ids, since more than one entry can block release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): keep blocker evidence and backend in cleanup diagnostics
The release diagnostic reset its observed blockers on every close, so a
retry whose inventory was unavailable fell back to the already-released
session; and it kept only session ids, describing a blocking GUI
session with detached-worker guidance.
Blocker evidence is now replaced only by a successful inventory, and
the diagnostic becomes upstream_sessions with each session's id and
backend, with guidance that distinguishes workers from GUI sessions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): stop naming a worker after its close was confirmed
When idb_close confirmed the requested worker's release but the
following inventory failed, no blocker evidence existed yet and the
diagnostic fell back to the confirmed-absent worker. After a confirmed
close the diagnostic now reports an empty session list, meaning any
remaining same-input sessions are unknown.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): group cleanup diagnostic cases in their own suite
The added cases pushed the reaped-worker describe block past the
150-line limit enforced by lint:built.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): keep ownership and pre-close peers in cleanup diagnostics
Blocking sessions dropped the parsed ownership fact, so an external
unowned worker looked the same as REA's own; and recovery inventory
recorded same-input peers only when the requested worker was missing,
so a peer seen beside it was lost if the following close failed.
Each reported session now carries owned (null when no inventory has
reported it), and recovery records every same-input session until a
later successful inventory replaces that evidence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): drop a confirmed worker from retained cleanup blockers
Recovery inventory now records the requested worker beside any peers,
so once idb_close confirmed its release a failing follow-up inventory
still reported it as unreleased. Remove the confirmed session from the
retained blockers at close confirmation and keep the remaining peers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): retry cleanup through a detached stdio connection
The retry coverage used a recording connection whose detach() only
counts calls, so it could not show that detaching keeps a retained
connection usable. Run a real stdio supervisor in a long-lived host,
fail the first post-close inventory, and require the retry through the
same detached connection to confirm release and remove the workspace.
The test fails if detach() destroys the pipes instead of unref-ing them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): close the stdio supervisor in failed retry tests
Merge main and give its new IdaNativeProtocol connection double the
required detach() method. The real-stdio retry test now closes its
connection in an unconditional teardown, so a failing assertion cannot
leave the supervisor waiting on stdin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): share the cleanup diagnostic expectation in session tests
Repeated upstream_sessions assertions and the unrelated live peer
literal pushed repository duplication over the jscpd threshold. Build
the expected diagnostic with one helper and reuse one peer constant.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): distinguish observed ownership from unreported input bindings
* fix(ida): keep requested-ID conflicts in recovery cleanup
Recovery inventory kept only same-input entries, unlike the startup and
post-close filters. After an explicitly rejected open, an entry under
the requested session ID on another input was dropped, so cleanup could
close the connection, remove the private workspace and report success
while that session stayed registered. Match the requested ID as well so
the entry is retained as a blocker and cleanup stays incomplete.
Also split the cleanup diagnostics suite under the lint:built function
length limit, and make two startup-inventory fixtures pass a defined
session id so the test file typechecks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): preserve retained session inventory facts
---------
Co-authored-by: Xingchuan Ma <xingchuan.ma@msn.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
The attached fixture negotiates the legacy protocol, so list_procedures
calls list_functions, never list_funcs. The list_funcs mocks added in
#2449 never fired and both tests failed on arrival. No product change.
Move all 18 translated READMEs into docs/readme/ and keep the English entry at the repository root. Update navigation, guide/image paths, website discovery and documentation checks together.
Preserve the contributor's work and current main content. Cover every translated command and HTML destination, and repair the verified Persian heading fragments.
Validation: 203 focused tests on the synchronized head, plus 119 tests and documentation checks on the integration with main fc0dbe7f9; 1,501 local references and 399 authored fragments verified. The complete CI workflow passes. The upstream x64 dylib fixture correction is included; an unchanged-checkout rerun cleared the earlier deadline timing assertion.
Closes#2141
Co-authored-by: Aimal Khan <94559553+aimalexe@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
* fix(native/windows): share FILE_SHARE_DELETE so owned objects can be marked delete-pending
The Windows native authority self-test (`binding.call("inspect", [])`) fails
closed on stock Windows x64 with a non-admin user:
Delete owned object by handle failed (Win32 5): Access is denied.
Reproduced deterministically (15/15 failures) on Windows 11 x64, Node 22.22.2,
non-elevated account. Because `inspect` is a hard gate, every provider-backed
operation is rejected and the whole native authority is unusable.
Root cause: Windows requires that every handle currently open on an object
grants FILE_SHARE_DELETE before that object can be marked delete-pending via
SetFileInformationByHandle(FileDispositionInfo).
`createRelative()` creates the runtime object with FILE_SHARE_READ only, and the
returned handle is retained for the lifetime of the runtime
(`Runtime::directory`). `closeRuntime()` later needs to mark that same object
delete-pending, but the retained handle never shared DELETE, so the transition
is denied (Win32 5).
The child handles opened by `closeRuntime()` for recursive cleanup have the same
defect: they request DELETE access while sharing only FILE_SHARE_READ, so the
subsequent `dispose()` call on those very handles is denied too.
Fix: add FILE_SHARE_DELETE to both share masks, keeping FILE_SHARE_READ and
deliberately not adding FILE_SHARE_WRITE, so the existing write-exclusion
behaviour of the retained leases is preserved while the delete-pending
transition the cleanup path depends on becomes possible.
Verified end-to-end after the change: `inspect` passes, the full runtime
lifecycle (`runtime_create` / `runtime_mkdir` / `runtime_write` / `runtime_open`
/ `runtime_close`) completes with no residual directories, and a real 925 MB
application analysis (4396 files) runs through all stages.
* fix(windows): anchor private runtime cleanup to directory handles
* test(windows): assert cleanup sharing failure by code
---------
Co-authored-by: maodns <311719211+maodns@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* docs(skills): add CI and test correctness auditing
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
* fix(process): report no remaining time after a provider deadline fires
Node timers can fire while performance.now() is still a fraction of a
millisecond short of the monotonic deadline. ProviderStartupDeadline then
reported interruption "timeout" and an aborted signal while remainingMs()
returned ceil(0.x) = 1, so polling loops guarded by remainingMs() > 0
(Hopper and Ghidra startup) could run past an elapsed deadline, and the
real-timer test "aborts a bounded wait when its real monotonic deadline
expires" failed intermittently in CI (expected 1 to be 0).
Once the deadline's own timer has classified a timeout, report zero
remaining time. A deterministic regression test fires the timer with the
monotonic clock 0.4 ms short of the deadline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(process): retain the monotonic startup deadline budget
Recheck the absolute monotonic deadline when an early timer fires, and keep
polling waits pending until their own target or the shared deadline arrives.
Preserve caller cancellation, disposal and the unchanged real-timer assertion.
This replaces the earlier remainingMs workaround: an early callback must not
classify an unexpired deadline as a timeout.
Adapt the production fix and regression cases from nosmile99 PR #2793 at
5460016936, including the independently reported
both-timers-early reproduction. Preserve the prior contributor's commit.
Fixes#2760
Co-authored-by: nosmile99 <147114285+nosmile99@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
* style(tests): format the Java class fixture signature
The captured main baseline has an unformatted helper signature. Apply the
repository formatter so the required style gate can run to completion.
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
* test(ghidra): group expanded suites by their contracts
Split result-envelope and completeness checks, and Windows invocation and
runtime checks, into named describe groups within the existing lint limit.
Preserve every test, fixture, assertion and platform prerequisite.
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
---------
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nosmile99 <147114285+nosmile99@users.noreply.github.com>
* fix(ida): retain bounded stderr on upstream transport failures
* fix(ida): preserve stderr through operation and cleanup boundaries
Address review findings at their producing boundaries and preserve directly affected consumers. Source inspection and git diff --check completed. Tests and automated checks were not run at the user’s explicit request.
* fix(ida): preserve cancellation and single-owner stderr diagnostics
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(flutter): find snapshot headers that a read chunk boundary splits
Within one chunk the snapshot hash scanner resumes four bytes after each
magic, but across chunks it resumed after the whole 52-byte record and
dropped the carried bytes. A magic starting 49-51 bytes after a rejected
(non-hex) record was therefore lost when its four bytes straddled a read
boundary, so the result depended on chunking and a conflicting hash could
be omitted while coverage stayed complete. Resume after the magic in both
cases.
* refactor(flutter): drop the snapshot scanner cursor the fix superseded
After a complete record the carried tail is shorter than a magic, and a
pending magic has not been processed, so every push can rescan its carried
bytes from the start without counting a record twice. Remove the absolute
cursor and base offset, and cover sections 49-51 bytes after a rejected
record with two-chunk and byte-at-a-time feeds.
* fix(flutter): reject ambiguous mappings and bound ELF notes
Resolve PT_LOAD interpretations once for symbols and dynamic tables, including partial overlaps. Preserve equivalent mappings and leave conflicting or invalid alternate definitions unresolved.
Bound distinct nonempty ELF note ranges before retention and reads, deduplicate shared ranges, preserve observed build-ID candidates and report partial coverage on exhaustion. Correct shared verifier workspace ownership and structured Windows path assertions.
Addresses the two post-merge review findings on PR #1582. Validation: 147 focused cases across Linux, macOS Sonoma 14.8.9 and non-administrator Windows 11 build 26300.9457; real Gallery CLI/MCP checks on all three hosts; six compiler-produced ELF32/ELF64 hash-layout cases; static, docs, discovery and duplication checks. Full string-pool projections remain explicitly bounded.
* test(flutter): parse complete facts through named result schemas
---------
Co-authored-by: me <me@medz.org>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(setup): resolve the configuration MSIX Claude Desktop reads
On Windows, setup, doctor and uninstall always used
%APPDATA%\Claude\claude_desktop_config.json. The MSIX build of Claude
Desktop (package family Claude_pzs8sxrjxfjjc) virtualizes AppData writes
and reads its package-private copy under
%LOCALAPPDATA%\Packages\<family>\LocalCache\Roaming\Claude once it exists.
Setup from an ordinary process therefore wrote a file the app never reads,
and doctor reported that file healthy.
Resolve the Claude Desktop location once, in supportedClients(): the
private copy when it exists, else the AppData file the package still
reads, else a new private copy. An unrecognized Claude_* publisher or
unreadable package storage is reported instead of falling back to AppData.
Compare one of the package's private files with its AppData path through
realpath.native to learn whether the running package started this
process. From that redirected view, or when no file can be compared,
setup and uninstall refuse to change Claude Desktop's configuration,
because the running app rewrites it from memory. From a redirected view
they also refuse writes under %APPDATA% and %LOCALAPPDATA% for other
clients and skills, which would land in the package's private storage.
Setup refuses to register a launcher stored in any MSIX package's
private storage, discloses which file the package reads, and tells the
user to quit Claude Desktop fully on every platform. Configuration fails
with target_changed if the package switched to its private copy after
the plan was shown. Uninstall removes REA from both files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(setup): record the verified MSIX Claude Desktop registration
On the Windows 11 host with the MSIX build 2.31226.1.0, setup from an
ordinary terminal with the app quit wrote the package-private copy. After
the app restarted, the entry persisted, doctor reported it aligned, and
Claude Desktop's MCP log showed REA starting and answering tools/list.
Uninstall against the real app remains unverified.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* style(setup): format MSIX review corrections
* fix(setup): carry the admitted legacy path through uninstall removal
clientRegistrationRemoval returned a removeLegacy boolean, and removeClient
recomputed the legacy path separately, so TypeScript could not prove the
path existed when removeLegacy was true and `tsc --noEmit` failed in
Uninstall.ts. The decision now returns the admitted legacy path itself;
preflight and removal consume that one value.
The alias regression matched new-destination children with a "/"
separator while building paths with path.join, so it failed on Windows.
It now uses path.sep.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(setup): split MSIX Claude Desktop lifecycle cases under the function length limit
The uninstall cases pushed the registration lifecycle describe past the 150-line lint limit. Group them separately, with the AppData registration case kept among the registration cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(native): bound captured output carried by native command failures
The native command runner retains up to 64 MiB of output because
successful analysis needs it complete, and failureCapture copied all of
it into the failure. An inspect_plist whose plutil output exceeded the
budget therefore returned a 67 MB resource_constraint error whose
details.captured_output.stdout repeated the whole retained output.
Keep a 64 KiB UTF-8-safe excerpt per stream in failure diagnostics,
mark them truncated, and keep the observed stdout/stderr byte totals.
Successful captures are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(native): bound codesign failures and cover excerpt cuts
translateCodeSignExitFailure wrapped an accepted nonzero codesign capture
into a NativeCommandFailure by copying both complete streams, so
inspect_signature failures still bypassed the diagnostic bound. Route it
through the shared failureCapture builder; accepted output stays
complete until the provider decides it is a failure.
Add a focused runner test for an ordinary nonzero exit with stdout and
stderr just above the excerpt size and a two-byte character straddling
the cut, and a provider test for the codesign path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(native): build excerpt test output inside the child process
The output strings embedded in one node -e argument totalled about 133
KB, above Linux's 128 KiB per-argument limit, so spawn failed with E2BIG
on the CI runner. Generate the repeated output in the child instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(process): order interaction differences by their dispatch time
first_divergence ranks candidate differences by the earliest recorded
time of the differing observations, but eventTime read only `at_ms`.
Interaction events record their time as `dispatched_at_ms`
(and `scheduled_at_ms`), so a changed interaction always ranked as
untimed. An interaction outcome that differed at 6 ms therefore lost to
a process sample that differed at 500 ms.
Give each comparison dimension its recorded time field. Interactions use
the dispatch time, when their outcome was observed; the other
dimensions keep `at_ms`. An earlier process difference still wins.
Fixes#2645
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(process): require ordered interaction dispatch times in captures
Comparison ranks a changed interaction by its dispatch time, while
firstCollectionDivergence returns the first differing interaction by
sequence. The capture parser checked only that interaction sequences are
contiguous, so an imported capture whose dispatch times decrease could
make that first-by-sequence difference later than another differing
interaction.
Interactions are dispatched in sequence and their times come from the
monotonic capture clock, so require non-decreasing dispatch times at
parsing, as frames, rendered frames, process samples and filesystem
checkpoints already require for their timestamps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(reconstruction): reject contradictory function comparison status
* test(reconstruction): cover imported function match precedence
---------
Co-authored-by: maxazure <405711+maxazure@users.noreply.github.com>
* fix(apktool): resolve Windows PATH launchers before invocation
Resolve the default launcher through the selected PATH/PATHEXT before choosing native process creation or the existing conservative cmd.exe wrapper. Reuse the resulting selection and one canonical environment for the version probe and decode.
Follow-up to the release #1693 review of #1777. Source inspected and formatted; tests, builds, check reruns and real Windows Apktool execution were skipped at maintainer request.
* fix(apktool): bound lookup and retain only selected environment
Source inspection and targeted formatting only. Tests, builds, lint, typechecks and provider workloads were not run at the user's explicit request.
* fix(apktool): use supported timeout diagnostics
Retain lookup phase through AnalysisErrorOptions diagnostics while preserving the operation and timeout identity. Source inspection and targeted formatting only; tests, checks, builds and provider workloads were skipped at the user request.
---------
Co-authored-by: morluto <morluto@users.noreply.github.com>
Node timers can fire while performance.now() is still a fraction of a
millisecond short of the monotonic deadline. ProviderStartupDeadline then
reported interruption "timeout" and an aborted signal while remainingMs()
returned ceil(0.x) = 1, so polling loops guarded by remainingMs() > 0
(Hopper and Ghidra startup) could run past an elapsed deadline, and the
real-timer test "aborts a bounded wait when its real monotonic deadline
expires" failed intermittently in CI (expected 1 to be 0).
Once the deadline's own timer has classified a timeout, report zero
remaining time. A deterministic regression test fires the timer with the
monotonic clock 0.4 ms short of the deadline.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
observe-native-ui and capture-native-ui-scenario were registered in one
loop with a shared option schema and description. The passive command
therefore advertised `--steps` ("Observe or run a scenario"), accepted
any value, and then dispatched observe_native_ui without it, so a
caller who selected the wrong command never learned that no scenario ran.
Register each command against its own contract. Observation declares
only the passive scope options, so `--steps` is rejected as an unknown
flag; the scenario command keeps its JSON step decoding and validation.
Each command now has its own description.
Fixes#2674
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A profile mismatch reached the caller as a bare AnalysisProtocolError,
which projects to `unreadable_output` with a generic message. The error
already named every missing tool, but none of that detail survived, so
the only way to identify the cause was to log the JSON-RPC traffic and
notice the exchange stopping after `tools/list`.
Throw a ProviderAdapterError instead, carrying the mode, the expected
profile and the missing tool names through the diagnostics channel that
already surfaces in `details`. Document which upstream versions each
profile accepts, since upstream `main` now serves neither.
Refs #2301
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(ci): run the Windows native lane with its process boundary fixture
`verify-windows-native.mjs` takes the boundary executable as its second
argument and skips every observation that needs it when the argument is
absent. CI passed no argument, so the breakaway denial, caller and child
token comparison, Windows environment semantics and in-place ancestor
reparse attempt have never run there; they only ran for an operator who
built the fixture by hand, which `native/windows/README.md` described as
optional.
The fixture is an ordinary Windows executable independent of the addon,
so the lane that already installs MinGW to cross-build the artifact
cross-builds it too and uploads it beside the existing inspection
fixture. The Windows job downloads it and passes its path, matching how
that inspection fixture already crosses the same job boundary.
No observation, assertion or threshold changes; this only stops four of
them from being silently skipped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(ci): pass the process boundary fixture in the real Ghidra Windows lane
`real-ghidra-windows.yml` also runs the native lane without the boundary
executable, so its proof run skipped the same breakaway, caller and child
token, environment semantics and ancestor reparse observations. Its
artifact job already installs MinGW, so it cross-builds and uploads the
fixture the same way, and the self-hosted Windows job downloads it and
passes its path.
This makes the README's claim about both Windows workflows true rather
than narrowing it to one lane.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(process): report no remaining time after a provider deadline fires
Node timers can fire while performance.now() is still a fraction of a
millisecond short of the monotonic deadline. ProviderStartupDeadline then
reported interruption "timeout" and an aborted signal while remainingMs()
returned ceil(0.x) = 1, so polling loops guarded by remainingMs() > 0
(Hopper and Ghidra startup) could run past an elapsed deadline, and the
real-timer test "aborts a bounded wait when its real monotonic deadline
expires" failed intermittently in CI (expected 1 to be 0).
Once the deadline's own timer has classified a timeout, report zero
remaining time. A deterministic regression test fires the timer with the
monotonic clock 0.4 ms short of the deadline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit dfdaa0ca74)
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
* perf(evidence): reuse sealed bundle reads in compare and export
`rea compare`, the compare_bundles MCP tool and `rea evidence-export`
read bundles through the mutable reader, so each consumer
re-authenticated every record again: compareBundles parsed both bundles
a second time and bundleDigest's serializeEvidenceBundle a third time;
export's writer parsed the source once more before serializing.
These consumers only read the bundle, so read it through the existing
sealed reader (readImmutableEvidenceBundle). Later parses hit the
immutable bundle cache. Ordinary mutable reads, kept deliberately by
#1721, are unchanged. Output is byte-identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(process): report no remaining time after a provider deadline fires
Node timers can fire while performance.now() is still a fraction of a
millisecond short of the monotonic deadline. ProviderStartupDeadline then
reported interruption "timeout" and an aborted signal while remainingMs()
returned ceil(0.x) = 1, so polling loops guarded by remainingMs() > 0
(Hopper and Ghidra startup) could run past an elapsed deadline, and the
real-timer test "aborts a bounded wait when its real monotonic deadline
expires" failed intermittently in CI (expected 1 to be 0).
Once the deadline's own timer has classified a timeout, report zero
remaining time. A deterministic regression test fires the timer with the
monotonic clock 0.4 ms short of the deadline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(flutter): name a missing or non-file APK selection
identify_flutter_build and inspect_dart_aot reported a missing path or a
directory as "The APK could not be read as a package: <path>: ENOENT ...",
which blames the package bytes for a selection mistake. Report
"Selected APK does not exist" for ENOENT/ENOTDIR and "Selected APK is not
a regular file" for a non-regular selection, matching the SQLite
inspector's wording. The issue path and invalid_format reason are
unchanged; package format failures keep their existing message.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(filesystem): classify unopenable non-regular selections at admission
A Unix socket cannot be opened at all: open() fails with ENXIO on Linux
and EOPNOTSUPP on macOS (surfaced by libuv as "Unknown system error
-102") before openRegularFile can stat the descriptor, so such a
selection escaped NonRegularFileReadError and the Flutter provider still
blamed the package bytes.
When open fails, classify the path by its own metadata (lstat when
symlinks are rejected, stat otherwise): an existing non-regular file
becomes NonRegularFileReadError. Missing paths, permission failures,
regular files, and the O_NOFOLLOW ELOOP rejection keep their original
errors. The Flutter selection test now covers a real Unix socket.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(filesystem): reclassify only unopenable file-type errors at admission
Checking the path's metadata after any open failure turned EACCES on an
unreadable directory into NonRegularFileReadError, so callers reported
invalid input instead of access_denied. Reclassify only errors that mean
the file type cannot be opened (ENXIO, EOPNOTSUPP, ENOTSUP, matched by
errno because libuv has no name for macOS EOPNOTSUPP 102); permission,
symlink-rejection and resource failures keep their original errors.
Run the Unix socket selection check in its own test, skipped on Windows
where listen() takes named pipes, and keep the missing-path and
directory checks cross-platform.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(filesystem): keep cancellation that arrives during the non-regular probe
A caller abort while the post-open metadata probe ran was replaced by
NonRegularFileReadError, so callers such as parseBinaryTarget reported an
input-format error instead of cancellation. Recheck the signal before
substituting the non-regular classification.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(browser): keep malformed Content-Length declarations unknown
Response metadata normalized Content-Length with Number(), truncation and
clamping, so "-5", "0x10", "1e3" and "+12" became observed lengths 0, 16,
1000 and 12. RFC 9110 section 8.6 defines the field as 1*DIGIT; any other
spelling declares no length. Parse only decimal digits within the safe
integer range and keep every other value null.
Fixes#2596
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(browser): cover the largest accepted Content-Length
Pin the safe-integer boundary beside the overflow case so a future change
cannot reject the largest representable declared length unnoticed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(sqlite): classify a missing database path as an invalid value
The snapshot reported an absent selected database as an artifact path
failure, which the adapter projects as invalid_format alongside malformed
paths and content. The snapshot owns the absence observation, so it now
returns an invalid_value input issue on path directly, matching the
adapter's existing ENOENT/ENOTDIR classification.
Fixes#2614
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(sqlite): classify a missing database path as an invalid value
The snapshot reported an absent selected database as an artifact path
failure, which the adapter projects as invalid_format alongside malformed
paths and content. The snapshot owns the absence observation, so it now
returns an invalid_value input issue on path directly, matching the
adapter's existing ENOENT/ENOTDIR classification.
Fixes#2614
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Pass the tool contract's `returnsTargetContent` to
`toRecordedPartialErrorToolResult` in the shared Evidence handler, matching
the Electron call site.
The call site that records a retained partial observation was added without
the argument required by the untrusted target-content framing, so the
delivery neither marked the result nor counted the provenance marker in its
wire budget. The type gate failed on main with
`contractToolHandler.ts(69,38): error TS2554`, which also blocked every
compiled boundary test lane.
* fix(javascript): keep configuration setting reads out of endpoints
Static endpoint extraction reads the first literal argument of any call
named get as an HTTP request path unless the receiver is a provable keyed
collection. VS Code extension bundles read settings through
`workspace.getConfiguration(section).get(key)`, so every setting key
became a network endpoint: the bundled Git extension's dist/main.js
reported 173 network endpoints, nearly all of them setting names such as
`autofetchPeriod` and `blame.statusBarItem.enabled`.
The lexical receiver classifier now records a `configuration` fact for a
`.get` call whose receiver is a `getConfiguration(...)` call, inline or
through a binding whose only visible write is one unconditional
initializer. Minifiers emit `let` for these bindings, so the proof relies
on the recorded writes rather than the declaration kind, as tRPC client
root resolution already does. Endpoint extraction skips non-URL literals
for that fact in both application and web bundle analysis. Reassigned,
conditional, and shadowed receivers, URL or path literals, and other
clients such as `api.get("users")` keep their endpoints.
The receiver fact union was duplicated in three modules; consumers now
import the classifier's type.
On the Git extension bundle, network endpoints drop from 173 to 7 with
unchanged analysis time (2.1 s).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(javascript): require the workspace host for configuration receivers
A bare or differently scoped `getConfiguration(...)` may be an
application's own HTTP client factory, so `.get("users")` on its result
lost its endpoint. Only `workspace.getConfiguration(...)` and
`<x>.workspace.getConfiguration(...)` now produce the configuration fact.
Minifiers keep property names, so the bundled VS Code Git extension still
reports 7 network endpoints instead of 173.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(javascript): recognize default VS Code namespace imports
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Bind retained descriptors and runtime resources to their admitting operation until cleanup succeeds, then rebind newly admitted work. Verify failed retries, successful recovery, shutdown and CLI projection.
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
* feat(ghidra): admit recordless legacy MIPS32 ELFs with a pinned 32-bit language
Firmware built with pre-ABI-flags GNU toolchains declares EF_MIPS_ARCH_32
with an unspecified ABI field and no PT_MIPS_ABIFLAGS record. The lane
refused them before provider selection, and Ghidra's own header
auto-selection picks a 64-bit R6 language for exactly these files.
Admit ELF32 ET_EXEC headers with EF_MIPS_ARCH_32 or EF_MIPS_ARCH_32R2,
an unspecified ABI field, EF_MIPS_ABI2 clear and no observed ABI flags
record. o32 is recorded as an inferred analysis assumption
(mips_abi_basis), floating-point ABI semantics stay unverified, and the
existing refusals (FP64, NAN2008, ASEs, machine variants, ELF64) are
unchanged. The profile pins -processor MIPS:<LE|BE>:32:default through a
provider-pinned-v1 selection the bridge-reported language_id is checked
against after import; a caller-selected REA_GHIDRA_LANGUAGE_ID still
wins. The lane identity is versioned
elf32-exec-arch32-legacy-pinned-v1.
verify:ghidra:mips gains a recordless legacy round for both byte orders
that strips the ABI record declarations from a real mips32 fixture,
checks REA's interpretation against GNU readelf, asserts the pinned
language after import and the retained assumption limitations through a
snapshot round-trip.
Fixes#1620
* fix(ghidra): require an inspected absence for the recordless MIPS lane
Address review: undefined ABI flags means the record was not inspected,
not that none exists. Only an inspected absence (null) establishes the
recordless legacy admission; a merely unobserved record keeps its
specific refusal. Also document the legacy admission and its pinned
language in the MIPS provider guide.
* fix(ghidra): tighten the recordless MIPS admission boundaries
Address review: a recordless-looking header whose ABI-record inspection
left declaration sources unexamined (carved ELF with a partial section
table and no program-header record) no longer establishes the recordless
admission; it is refused with the inspection limitation retained. An
EF_MIPS_ARCH_32 header that declares an ABI is refused rather than
relabeled through the 32R2 declared-ABI lane.
* fix(ghidra): reject EF_MIPS_ABI_ON32 from the recordless MIPS lane
Address review: bit 0x40 declares the old n32 ABI. A recordless header
carrying it was admitted with the inferred-o32 assumption even though
the header itself declares n32; the recordless shape now requires the
bit clear and refuses it with a specific constraint.
* fix(ghidra): keep recordless relocatable MIPS objects off the legacy lane
The recordless admission now requires ET_EXEC: the lane and its
verification cover executable firmware images, and a recordless ET_REL
object must stay on the declared-ABI path instead of inheriting the
inferred-o32 assumption under an executable lane id. The ABI-record
requirement paragraph is scoped to the declared-ABI lane so it no longer
contradicts the recordless admission documented above it.
* fix(ghidra): name the ET_EXEC scope for recordless objects and probe the legacy lane
A recordless relocatable object is not an incomplete inspection, so its
refusal now names the ET_EXEC scope of the legacy admission instead of
claiming unavailable ABI headers remain unknown. The recordless legacy
verifier round reads the probe pair and applies the full assertMipsProbe
oracle like the standard round, and its report keeps the independent
GNU readelf receipt beside the fixture facts.
* fix(ghidra): retain the concrete ELF32 legacy compiler pin
* fix(ghidra): bind legacy profiles to fully admitted targets
---------
Co-authored-by: BaaRai <baarai@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* ci: pin GitHub Actions to full commit SHAs
Replace every third-party `uses: owner/repo@vN` reference in
.github/workflows with the 40-character commit SHA that the tag
currently resolves to, keeping the exact release as a trailing comment.
Each pin was checked with `git ls-remote --tags`: the floating major tag
and the commented release dereference to the same commit. Local
reusable workflows are unchanged.
Re-pin reactivecircus/android-emulator-runner from the SHA of the
annotated `v2` tag object (4c44018e) to the commit it points to
(a421e438, v2.38.0); Actions resolves both, but only the commit SHA is
an immutable reference that tooling can compare with the release.
Update the Windows Ghidra workflow trust-boundary test to require
SHA-pinned setup-node and upload-artifact references instead of the
previous floating tags.
Validation: actionlint v1.7.7 (-shellcheck= -pyflakes=, as in CI), YAML
parse of all workflows, no remaining unpinned third-party `uses:`, and
the workflow boundary/conformance tests.
* style(ci): format action identity assertion
Retain formatting edits produced before the user stopped validation.
Source inspection and git diff --check only. Tests, builds and typechecks skipped by explicit user request. GitHub review writes paused globally.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(ida): let one-shot commands exit after retaining cleanup
When a headless IDA request outlives timeoutMs (for example idb_open on
a large binary still running auto-analysis), REA cannot prove the
worker stopped and correctly retains the upstream connection and
private workspace. The retained stdio child and its pipes stayed
referenced, so a one-shot CLI printed its cleanup_incomplete result and
then never exited, keeping the supervisor, worker and database alive.
Detach the retained connection's child process and pipes from the event
loop when cleanup fails. A long-lived MCP server can still retry
through the retained connection; a one-shot CLI exits with status 1,
and the supervisor observes end of input.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): report an unverified upstream worker after failed cleanup
Upstream ida-pro-mcp spawns headless workers in their own session and
deliberately leaves them running when its supervisor exits, so neither
a retained connection nor REA exiting proves that a timed-out worker
stopped. When cleanup fails before the owned worker's release is
confirmed, the cleanup diagnostics now name its private session and
state that it may still be running until it finishes and reaches its
idle timeout. Failures after a confirmed release, or before any open
was attempted, do not report a worker.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): name the inventory sessions that block worker release
When idb_close confirmed the requested worker gone but the follow-up
inventory still found a different peer on the private input, the
upstream_worker diagnostic named the released session and could
misdirect manual cleanup. Record the session ids of the inventory
entries that actually blocked release and report those; fall back to
the requested private session only when no inventory evidence exists
(an incomplete open or an unanswered request). The field becomes
session_ids, since more than one entry can block release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): keep blocker evidence and backend in cleanup diagnostics
The release diagnostic reset its observed blockers on every close, so a
retry whose inventory was unavailable fell back to the already-released
session; and it kept only session ids, describing a blocking GUI
session with detached-worker guidance.
Blocker evidence is now replaced only by a successful inventory, and
the diagnostic becomes upstream_sessions with each session's id and
backend, with guidance that distinguishes workers from GUI sessions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): stop naming a worker after its close was confirmed
When idb_close confirmed the requested worker's release but the
following inventory failed, no blocker evidence existed yet and the
diagnostic fell back to the confirmed-absent worker. After a confirmed
close the diagnostic now reports an empty session list, meaning any
remaining same-input sessions are unknown.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): group cleanup diagnostic cases in their own suite
The added cases pushed the reaped-worker describe block past the
150-line limit enforced by lint:built.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): keep ownership and pre-close peers in cleanup diagnostics
Blocking sessions dropped the parsed ownership fact, so an external
unowned worker looked the same as REA's own; and recovery inventory
recorded same-input peers only when the requested worker was missing,
so a peer seen beside it was lost if the following close failed.
Each reported session now carries owned (null when no inventory has
reported it), and recovery records every same-input session until a
later successful inventory replaces that evidence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): drop a confirmed worker from retained cleanup blockers
Recovery inventory now records the requested worker beside any peers,
so once idb_close confirmed its release a failing follow-up inventory
still reported it as unreleased. Remove the confirmed session from the
retained blockers at close confirmation and keep the remaining peers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): retry cleanup through a detached stdio connection
The retry coverage used a recording connection whose detach() only
counts calls, so it could not show that detaching keeps a retained
connection usable. Run a real stdio supervisor in a long-lived host,
fail the first post-close inventory, and require the retry through the
same detached connection to confirm release and remove the workspace.
The test fails if detach() destroys the pipes instead of unref-ing them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ida): close the stdio supervisor in failed retry tests
Merge main and give its new IdaNativeProtocol connection double the
required detach() method. The real-stdio retry test now closes its
connection in an unconditional teardown, so a failing assertion cannot
leave the supervisor waiting on stdin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): share the cleanup diagnostic expectation in session tests
Repeated upstream_sessions assertions and the unrelated live peer
literal pushed repository duplication over the jscpd threshold. Build
the expected diagnostic with one helper and reuse one peer constant.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ida): distinguish observed ownership from unreported input bindings
* fix(ida): keep requested-ID conflicts in recovery cleanup
Recovery inventory kept only same-input entries, unlike the startup and
post-close filters. After an explicitly rejected open, an entry under
the requested session ID on another input was dropped, so cleanup could
close the connection, remove the private workspace and report success
while that session stayed registered. Match the requested ID as well so
the entry is retained as a blocker and cleanup stays incomplete.
Also split the cleanup diagnostics suite under the lint:built function
length limit, and make two startup-inventory fixtures pass a defined
session id so the test file typechecks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Xingchuan Ma <xingchuan.ma@msn.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
procedure_callees and procedure_callers returned a bare address list, so an
inferred no-return call that truncates Ghidra's function body silently dropped
real edges (fixes#2326). Wrap both views in the function-observation envelope
with noReturnCallLimitations, matching procedure_info, procedure_assembly,
procedure_pseudo_code, read_function_instructions, and analyze_function
(precedent: 69a8b3a95). Version the boundary-observation contract to
ghidra-terminal-call-limitations-v2 so older snapshots cannot replay
unqualified results.
Validation: red->green unit test for the envelope requirement, MCP boundary
evidence test extended for both views (limitations retained through Evidence
and snapshot replay), 8 harness test files + ghidra behavior tests green,
check:fast, docs:check, verify:test-discovery green. Real Ghidra host lane
unavailable here (no Ghidra installed); Java change mirrors the existing
procedureInfo call pattern.
* test(go): pin JVM class files as unsupported Go images
The regression fails on main: readGoBinaryImage(javaClassFile()) reports
"Universal/fat Mach-O containers require selecting a thin slice" for a
JVM class file whose bytes 4..7 are minor/major version, not nfat_arch.
* fix(go): classify JVM class files instead of universal Mach-O
Route the four FAT magics through the shared readFatContainerHeader and
classifyFatContainerIdentity facts added for the same disambiguation in
the artifact and target lanes (921bb9575). Keep the thin-slice failure
only when the container identity is confirmed Mach-O; a JVM class file
now falls through to the generic only-ELF/PE/thin-Mach-O failure.
* test(go): pin universal Mach-O thin-slice failure with FAT fixtures
Cover the kept behavior with the repository's own fatImage/machoImage
builders (narrow and FAT64 tables) so the regression also proves real
universal containers keep the slice-selection failure.
* test(go): cover little-endian FAT magics in the universal container control
* fix(go): require positive universal Mach-O identity
Require positive Mach-O identity before reporting a universal thin-slice remedy; malformed FAT-shaped bytes are not proof. Add the JVM constant-pool CPU lookalike to the existing fixture control.
Source inspection and git diff --check; tests/builds/typechecks/CI reruns skipped at explicit user request.
* fix(go): retain malformed FAT header diagnostics
Preserve the owning FAT header parser reason for malformed headers while requiring positive Mach-O proof before the universal-slice remedy.
Source inspection and git diff --check only. Tests, builds and typechecks skipped by explicit user request. GitHub review writes paused globally.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Inventory expands an ASAR-named filesystem file only when its bytes are
an ASAR. JavaScript reconstruction expanded it on the suffix alone, so
a directory holding any other file named *.asar failed the whole
analysis with an invalid ASAR header.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(native): refuse inspect_signature on non-Mach-O targets
This provider's signature inspection covers Mach-O code signatures only.
On a xar pkg, codesign's "code object is not signed" verdict cannot see
the archive-level signature layer, so a signed or invalidly-signed package
was reported as signed:false with "Artifact is not signed." Match the
existing inspect_macho/list_architectures gate and report
capability_unavailable instead of an unsigned claim for a layer that was
never evaluated.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* test(native): scope the signature-gate comment to this provider
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix(native): align signature capability discovery with Mach-O support
Bind inspect_signature availability to Mach-O targets in capability discovery and align the public tool description.
Source inspection and git diff --check; tests/builds/typechecks/CI reruns skipped at explicit user request.
---------
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(apple): report a connector that cannot name its owner as an omission
A connector is recognized by class name and then dropped by an early
`continue` when its owner cannot be resolved. Nothing recorded the drop, so
connection coverage derived `complete` with `examined: 0` and `omitted: 0`
for a connector that was present, recognized and discarded.
Both producers of that coverage contract are affected and are changed
together, because they share the facet and the reason value:
- the keyed-archive parser records the drop as `unresolvedConnections` and
reports it through the `connections:<path>` facet, the document
`connection_count` and the graph omission total;
- the NIBArchive projection in the artifact adapter recorded nothing at all,
and the projected dictionary carried no trace of the dropped connector for
a downstream consumer to find. Its count is taken where the connector is
discarded and plumbed through the same per-document omission channel that
already carries incomplete hierarchies, so the reason follows the cause.
An unresolved source cannot be represented as a connection at all, because
connection identity requires a non-empty source; that is unlike an unresolved
destination, which the graph already retains as an unresolved edge.
`connection_limit_reached` stays reserved for connections dropped by the hard
cap and `serialized_view_hierarchy_incomplete` for hierarchy omissions.
`connection_count` also includes the unresolved connectors. That field already
counts connectors the parser recognized but could not emit, because
connections dropped by the hard cap are counted there too, so unresolved
connectors follow the existing rule rather than a new one.
Verified with 98 focused Interface Builder and catalog tests, check:fast and
verify:test-discovery on macOS arm64, and through the public CLI: a rooted
archive holding one ownerless UIRuntimeOutletConnection reported complete with
examined 0 and omitted 0 before this change and reports partial with the reason
connection_unresolved and omitted 1 after it.
* fix(apple): count ownerless NIBArchive connectors and keep the limit reason
Greptile found two defects in the NIBArchive half of this change.
The document summary was left unchanged, so the same recognized connector
counted as one in a keyed archive and zero in a NIBArchive. The dictionary
parser only sees connectors that were projected, so the omission recorded
where the connector was dropped is added to the matching document here.
The facet reason was overwritten unconditionally, so a NIBArchive holding both
a connection dropped by the limit and an ownerless connector reported
connection_unresolved and lost the cause a higher limit could recover. The
existing reason is kept when the graph already named one, which is the
precedence the keyed-archive producer applies.
Verified with `npm run test:focused` over the bundle suite (42 passed, 1
skipped), `npm run lint` (0 errors) and `npm run check:fast` on macOS arm64.
Reverting the reason precedence alone fails only the limit case; reverting the
document count fails the count assertion in both cases.
The new case moved into its own describe block because the enclosing callback
crossed the repository's max-lines-per-function bound otherwise.
---------
Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
* fix(pwntools): let callers widen the artifact input bound
The pwntools adapters rejected every artifact over 32 MiB before any
analysis ran, and nothing in configuration, environment, CLI or MCP
could raise that bound, so real recorded core dumps stayed unanalyzable.
Resolve the bound from REA_PWNTOOLS_MAX_INPUT_BYTES in front of the
shipped default. An absent value keeps 32 MiB, and a value outside
1..1073741824 bytes is refused as unusable provider configuration before
the artifact is read instead of falling back silently.
* fix(pwntools): name the bound variable in its own refusal
An unusable REA_PWNTOOLS_MAX_INPUT_BYTES travelled through the shared
engine-absence helper, which always stamped configuration_key
REA_PWNTOOLS_PYTHON, so a caller following that field was pointed at the
Python executable instead of the bound it had just set. The guide also
described the refusal as an invalid request while the decoder reports
provider_unavailable.
Let the failure context carry the key under review and pass the bound's
own name at that call site, then state the code callers actually receive
in the guide. Assert the key on the projected rejection so the engine
default and the bound override each stay attributed to the right setting.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(native): keep lipo path echoes out of FAT records
Parse FAT records only after separating the exact echoed operand path. Pass the same lipo operand at all three consumers and cover multiline paths through parser, slice-reader and compiled CLI regressions.
* fix(native): use parsed lipo framing for container offsets
* test(native): use explicit FAT fixtures for CLI regressions
inspect_artifact parsed a fresh inventory and inspection report but left
both mutable, so each later Evidence boundary cloned and re-digested the
complete payload: createArtifactInspection re-authenticated the nested
inventory Evidence, createAnalysisExecution re-parsed the report, and
recordEvidence re-authenticated the outer Evidence.
Seal both exclusively owned values with freezeJsonSnapshot so those
boundaries take the existing immutable-snapshot path. Output is
byte-identical.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The CIL opcode table held five of the six ECMA-335 prefix opcodes and
omitted no. (FE 19 <unsigned int8>, III.2.2). A method body using it was
reported as malformed with "Unsupported CIL opcode 0xfe19", losing its
instruction counts and normalized IL digest.
Decode it with its one-byte check mask and treat it as a prefix, so it
shares an instruction boundary with the opcode it modifies.
Claude-Session: https://claude.ai/code/session_012pRGskbPGjT444CgJfuhhj
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The decoder already reports "Instruction X at IL offset N leaves method
body" when an operand's computed end passes the IL body, but only after
the operand was read. Operand readers use Buffer reads, so an operand
cut off by the body end threw a RangeError first. The catch-all stored
Node's message ("Attempt to access memory outside buffer bounds" or an
offset RangeError) as body.issue, dropping the instruction and offset.
A body ending in a lone 0xFE two-byte opcode prefix failed the same way.
Treat a RangeError from the operand read as the operand leaving the body
so the existing diagnostic applies, and check the second opcode byte
before reading it. Malformed status, partial coverage and earlier
decoded instructions are unchanged.
Fixes#2677
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): classify ReadyToRun images without ILONLY as modern .NET
crossgen2 clears COMIMAGE_FLAGS_ILONLY and sets IL_LIBRARY on ReadyToRun output. inspect_managed_artifact checked the clear ILONLY flag before the ReadyToRun signature, so real ReadyToRun assemblies were reported as runtime_family mixed-clr-native and implementation cpp-cli-mixed, and cil-and-ready-to-run was unreachable for crossgen2 output. Check the ReadyToRun signature first; a clear ILONLY flag without it still reports mixed CLR/native code.
* test(managed): exhaust capacity through inspected assembly references
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(ghidra): admit raw NMOS 6502 analysis
* test(ghidra): require verified POSIX verifier cleanup
* test(ghidra): verify 6502 low-memory raw imports
* docs(skill): document raw NMOS 6502 support
* fix(ghidra): preserve requested Windows raw source paths
* docs(ghidra): include raw 6502 in Windows installation scope
* test(ghidra): verify Windows raw junction rejection through CLI and MCP
* fix(validation): make fixtures portable and preserve explicit Codex home
* fix(ghidra): attest raw mapping state and address space
* fix(ghidra): align diagnostics and regression groups
* fix(ghidra): bind raw attestation to language address space
* chore(ghidra): avoid verifier insertion conflict
* docs(ghidra): align linked raw admission guides
* fix(ghidra): retain 6502 verifier workspace on failure
* test(ghidra): isolate Windows authority doctor fixture
* fix(binary): re-admit Windows raw paths on session reopen
* test(binary): require fresh provider execution after path change
* Constrain 6502 to raw lifecycle and snapshot targets
* Bypass saved reads for unadmitted Windows paths
* Guard direct CLI snapshot replay on Windows paths
* fix(snapshot): gate Windows Ghidra replay on native admission
* fix(snapshot): constrain nested 6502 subjects to raw images
* test: make dyld slice fixtures portable
* fix(javascript): keep CommonJS require file URLs unresolved
require("file:///dep.cjs") was reported as a resolved dependency of
the inventoried dep.cjs although Node rejects the string with
MODULE_NOT_FOUND. The shared module-specifier resolver decoded file URLs
before the declared CommonJS loader semantics.
File-URL decoding now applies only to non-require module specifiers, so a
CommonJS file URL reports external with its declared string and source
evidence preserved. ESM file URLs and ordinary relative require paths
keep their established lookup.
* test(javascript): consolidate CommonJS file URL public workflow coverage
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(managed): name the declaring type of call and field targets
Call edges named external targets by member name alone (Join, ToJson,
WriteAllText), and method-spec edges had no name at all, so an analyst could
not tell which library a method calls or find every use of a type without a
decompiler. Field accesses through MemberRefs had no name either.
Name each TypeDef, TypeRef, and generic-instantiation TypeSpec once, in the
namespace-qualified form TypeDef full_name uses, and add member_refs
parent_name, call_edges target_declaring_type, and field_accesses
field_declaring_type. A method-spec target reports the generic method it
instantiates. Fields, member references, methods, and method specs now
resolve through one token-keyed MemberCore lookup instead of three maps.
Evidence recorded before these fields reads them as null.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): validate spec blobs and member kinds before naming targets
Address review findings on declaring-type naming:
- A generic instantiation must name a TypeDef or TypeRef, so a TypeSpec
base is reported as malformed instead of followed. Naming no longer
recurses.
- TypeSpec and MethodSpec instantiation blobs are decoded with the
member-signature grammar. Malformed blobs and out-of-range TypeDef rows
are reported against their owning row and make coverage partial.
- A MethodSpec reads both columns. An invalid Method coded index is
reported; a readable Method keeps its name beside a malformed
instantiation.
- MemberCore carries its signature kind, so a field operand is named only
by a field or field-signature MemberRef. This replaces the token-table
guard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): validate MethodSpec arity and report unsupported spec blobs
- A MethodSpec now checks that its method signature is generic and that
the instantiation supplies as many type arguments as it declares. A
non-generic target, a field reference, or a count mismatch is reported
as invalid-row; the readable method keeps its name.
- Unsupported TypeSpec and MethodSpec forms raise an owner-scoped
unsupported-signature issue instead of reading as an intentional
unknown.
- MethodSpec reading moves to ManagedMethodSpecs.ts, and its tests get
their own describe block.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): reject non-method signature headers and invalid TypeRef scopes
The method signature header reader now owns the calling-convention rule
that only FNPTR applied: FIELD, LOCAL_SIG, PROPERTY, and GENERICINST
headers, the reserved bit, and EXPLICITTHIS without HASTHIS are malformed.
A MethodSpec whose method has a PROPERTY header is no longer accepted as a
generic method, and member signatures with such headers no longer decode
as methods.
The type-name lookup validates a TypeRef's ResolutionScope coded index and
reports an out-of-range scope as invalid-row, keeping the readable name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): hold member rows to MethodDefSig and FieldSig headers
Method signature headers are now checked in context. MethodDef and
MemberRef rows accept only the MethodDefSig/MethodRefSig headers: DEFAULT,
VARARG, or GENERIC with DEFAULT. FNPTR keeps the unmanaged conventions
compilers emit for function pointers. A field signature must be exactly
FIELD, so a flagged FIELD header is malformed and never names a field.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): accept MethodSpec arity only from a fully decoded signature
The arity check read only the target's signature header, so a truncated
generic method signature passed. Under type selection a MethodDef target
outside the selection is never decoded elsewhere, so coverage stayed
complete. The arity now comes from a transient full decode, and only a
decoded method signature supplies it. signature() keeps its raw length
and digest around the shared decodeSignature.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* perf(managed): decode each MethodSpec target signature once
edgeTargets caches the generic arity, including a failed decode, by
target method token, so many instantiations of one generic method share
a single signature decode. Unity.InputSystem has 472 distinct MethodSpecs
over about 133 target methods.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): validate spec type operands and transitive reference scopes
* fix(managed): retain readable names when a scope row is unreadable
* test(managed): pin owner-scoped spec operand and scope-chain checks
e59217c83 validates spec type operands inside specSignature, so a
malformed generic TypeSpec base is now invalid-row under its owning
TypeSpec row; the three stale expectations follow that. New cases cover
a TypeSpec argument and a MethodSpec argument that name a missing TypeRef,
and a TypeRef whose ResolutionScope names itself. The scope cases move to
their own describe block.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): keep field targets from naming MethodSpecs
A MethodSpec over a field-signature MemberRef inherited kind "field", so
an ldsfld on that MethodSpec published a field name and declaring type
for malformed IL. A MethodSpec now borrows its target's name only when
the target is not a field; the arity check still reports it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): reuse owner-decoded signatures for MethodSpec arity
MemberRef signatures, and MethodDef signatures in the type selection, are
already fully decoded, but the MethodSpec arity check decoded them again
and admitted a second transient allocation, which could exhaust the
budget. MemberCore now carries the owner's genericArity, and only a target
nothing decoded, such as an unselected MethodDef, falls back to the raw
signature. signatureGenericArity is the one rule for both paths.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Every worker "selection" rejection was projected onto the table argument,
including an exact column name that does not exist in an existing table.
Give column rejections their own worker reason and map each input reason
to the caller argument it requires correcting. Table rejections keep the
table path.
Fixes#2613
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A push without overwrite read any unclassified failure of its existence
probe as an existing path, so an offline or unauthorized device was
reported as "the device path already exists". With overwrite it pushed
after a probe that had not established anything. The probe's own
refusal is now returned in both cases.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* test(mcp): expect trace_feature to report references the provider truncated
A provider that reports a capped xrefs read makes the trace truncated with a residual unknown for that target. An explicit complete report and a provider that reports nothing leave the trace as before.
* fix(mcp): report references a provider truncated in trace_feature
Executions gain an optional flag for a capped xrefs read, set by the IDA adapter from the upstream cap. trace_feature marks the trace truncated with a residual unknown for that target only when the provider reports a truncation; a provider that reports nothing keeps its previous result. The trace_feature workflow profile is revised so earlier results are not replayed.
* refactor(ida): report reference truncation whenever the runner observed an xrefs cap
* test(mcp): cover session forwarding, per-target state, native reports and failures of the trace coverage
* test(mcp): format the session forwarding test
* test(ida): expect headless IDA to resolve containing procedures from lookups and segment facts
Cover positive and negative containment, segment boundaries including addresses above 2^53, failures of the lookup and of the segment survey, cancellation, input validation and the admitted program as the only document.
* test(ida): expect feature tracing and address context to work on headless IDA
Run trace_feature, including a capped reference read, and inspect_address_context with and without an explicit document through the IDA session client.
* test(mcp): expect trace_feature availability to follow the search operations it calls
* fix(mcp): derive trace_feature availability from the search operations it calls
* feat(ida): resolve containing procedures and report the admitted program as the document
The modern headless profile resolves an address through the function lookup and, when no function contains it, tells a mapped address from an unmapped one using the database-scoped minimal survey. A survey that is missing, truncated or inconsistent fails the read. list_documents reports the single admitted program. The attached profiles do not declare either operation.
* docs(ida): describe containing procedures, the admitted document and truncated feature traces
* test(ida): verify containing procedures, the admitted document and feature tracing on real IDA
* docs(testing): list the headless IDA workflows the real lane verifies
* test(ida): make each survey failure case isolate a single defect
* test(ida): pin large addresses, segment order, document identity, attached refusals and each trace_feature prerequisite
* test(mcp): expect a repeated reference source to be resolved once in trace_feature
* fix(mcp): resolve the containing procedure of a repeated reference source once
* test(ida): trace the fixture procedure and derive probe addresses from its facts in the real lane
* test(process): format processCaptureLifecycle.test.ts after the merge
* test(ida): declare the alignment each synthetic universal slice offset satisfies
* refactor(ida): move the real lane's feature trace assertions into a helper
* test(ida): expect the real lane's feature trace check to accept references to every matched address
* fix(ida): check each trace reference against its own matched address in the real lane
* test(ida): pin that the new operations reject a document other than the admitted program
* refactor(ida): move the real lane's mapped non-function probe into a helper
* test(ida): expect the real lane's mapped data probe to skip strings inside functions
* fix(ida): try the target's strings in order for the mapped non-function probe
* test(ida): declare the real lane helper types for the verifier tests
* test(ida): expect the real lane to reject a listed string that resolves as unmapped
* fix(ida): fail the real lane when a listed string resolves as unmapped
The Java version probe captured its output with maxBuffer set to Infinity, so a
chatty or hostile JVM selected as the Ghidra launcher could grow the captured
stdout/stderr without limit and exhaust REA's memory during installation
discovery. Bound the capture to 1 MiB, matching the budget already used for
other Java listings. A probe that exceeds the budget yields no observation and
is reported through the existing failed-probe path, the same one the Java check
already uses whenever the probe cannot produce an observation.
Co-authored-by: Claude Code <noreply@anthropic.com>
* fix(formats): preserve high bits in remaining magic-byte checks
Node's "ascii" decoder masks the high bit, so byte-for-byte signature
comparisons accepted lookalikes such as CD DA ("MZ" | 0x80) or a
high-bit "bplist00"/"NIBArchive" header. ac57c88ef fixed this for the
shared DOS/MZ reader; apply the same latin1 decoding to the remaining
signature checks: NativeAOT and Windows native loader MZ/PE, binary
plist and NIBArchive detection, and PNG IHDR checks.
Display-name decodes (section and metadata stream names) are unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* style(windows): format signature admission regressions
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(ghidra): pre-create the launch-support config directory
Ghidra's launch support resolves its JDK before the headless run starts and
persists that choice under `<config>/ghidra/<release directory>`. Inside REA's
private runtime a child JVM cannot create those directories, so the first
Windows Ghidra query aborted at ghidra.launch.AppConfig.saveJavaHome with:
java.io.IOException: Failed to create directory:
...\config\ghidra\ghidra_12.1.4_PUBLIC
at ghidra.launch.AppConfig.saveJavaHome(AppConfig.java:145)
at LaunchSupport.findJavaHome(LaunchSupport.java:210)
LaunchSupport then fell back to its interactive prompt, read EOF, and reported
"JDK 21+ (64-bit) could not be found and must be manually chosen!", so the
provider failed with "Ghidra exited before bridge startup" even though
`rea doctor` reported a valid Ghidra installation and JDK.
Create the release directory while this process still owns the runtime, leaving
Ghidra only a file write inside it. The release coordinate comes from the
installation's Ghidra/application.properties (application.version plus
application.release.name) with the extraction directory name as a fallback. On
Windows each level goes through the native private-runtime owner, which opens
every existing component and creates only the final one.
Verified on Windows x64 with Ghidra 12.1.4, a 64-bit Temurin JDK 21, and REA's
packaged native addon: `rea inspect <x64 PE DLL> --provider ghidra` and the
equivalent MCP `binary_overview` call both complete and report 21 segments,
1436 procedures, and 2761 strings. Windows Ghidra remains read-only P0; this
change does not extend that boundary.
* style(ghidra): format launch configuration regressions
* fix(ghidra): reuse Java Properties parsing for launch release identity
---------
Co-authored-by: AbdulAzizShanShi <441650742@QQ.COM>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Setup and uninstall re-printed every number in an existing Hermes
config.yaml from a JavaScript number. Hermes reads the file as YAML 1.1
with exact integers, so a Discord channel ID lost its low digits, an
octal mode such as 0600 became 600, and 0.0000001 became 1e-7, which
YAML 1.1 does not define as a float. Two IDs that round to the same
double were also rejected as duplicate keys, so setup could not
register at all.
Hermes YAML parsing and editing move to HermesConfigurationYaml. A parsed
number is written with its source spelling while that spelling still
reads as the node's value, the rule yaml's own boolean tag follows, and
two keys are duplicates only when both their value and their spelling
match. Parsed values stay JavaScript numbers.
The CLI header's 32BITREQUIRED and 32BITPREFERRED bits are one two-bit
field. Reading 32BITREQUIRED on its own reported Prefer32Bit assemblies
(flags 0x00020003) as x86-only with requires_32bit true, and left
anycpu-prefer-32 reachable only through the reserved combination.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
createCliResultOutput rendered an explicit null selected by
--filter-output as the empty document {}, the same output it uses when
the selection has no value at all. On the streamed JSON/JSONL path,
a consumer could not distinguish a selected null from a missing field.
Write a selected null as null in streamed JSON and JSONL. This also
preserves an unfiltered top-level null. The {} fallback stays for
undefined, functions and symbols. The --full-output envelope already
carried data: null for a selected null. The --token-count path still
hands results that fit the formatted-string limit back to Incur and
prints 0 for a selected null. Other formats and Incur-owned result
paths are unchanged.
Consumers must accept JSON null for a present null and distinguish it
from a missing selection. Use --full-output if an object envelope is
required. Keeping the old shared {} representation would continue
hiding this distinction.
Claude-Session: https://claude.ai/code/session_019TTGAv6fe859ebbCLLfLHP
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(call-path): keep caller-only unknown coverage from blocking not_found
build_call_path expands only callee edges, so relationship coverage that
is unknown solely because callers are unobservable (the modern headless
IDA profile) no longer marks the searched callee closure incomplete.
The caller caveat stays visible in limitations, and callee-side unknowns
still yield unknown. Fixes#2322.
* test(call-path): cover IDA-capped callees beside unknown callers
Greptile review noted the poll-timing coverage only exercised unknown
callees, leaving the partial callees IDA returns at its 500-result cap
untested. Add the combined unknown-callers/partial-callees case:
isCallerOnlyUnknownCoverage must stay false and buildCallPath must keep
search_scope.exhaustive false, so a future change cannot silently report
not_found when IDA has omitted callees.
Buffer#toString kept a leading UTF-8 byte order mark as U+FEFF, so the
strict XML parser rejected a valid .ldefs file as content outside the root
element and aborted the whole language catalog read. XML 1.0 section 4.3.3
defines the mark as an encoding signature; decode with TextDecoder, which
consumes it. Malformed XML is still rejected.
Fixes#2533
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(ghidra): decode Swift String literals in function dossiers
Swift passes a String as two words. Small literals keep their UTF-8 bytes
inside those words, and immortal large literals keep a count plus a pointer
to their bytes biased by 32. Ghidra creates no data reference for either, so
analyze_function reported no strings for Swift code.
On AArch64 programs that contain Swift metadata, the Ghidra bridge now runs
constant propagation over the function and decodes register pairs where
Swift consumes a String: consecutive argument registers at calls and tail
calls, x0 and x1 at returns, and both registers of one STP. Large literals
must resolve to terminated bytes inside one initialized block that is not
executable. A pair whose registers both come from conditional selects is
skipped, because Ghidra forks each select without correlating the
condition and could otherwise pair words from different cases.
Decoded values are a derivation from the ABI layout rather than observed
references, so they appear in a new optional swift_string_literals field
with their source instruction, registers and raw words, and in a matching
inspect_analysis_view facet. referenced_strings is unchanged.
Refs #2030
* fix(ghidra): bound Swift literal reads and compare decoded strings
Large immortal literals are measured against the remaining heap before
allocation, and a failed fit stays visible as a limitation. The canonical
empty string is kept. Small and large literals now require matching
address nullability, and function comparison treats decoded literals as
string evidence without equating a missing record to an empty one.
* fix(ghidra): budget Swift literal decoding and tighten use sites
Large literals now draw on one heap budget per dossier, measured once
before decoding, instead of a separate check per literal. A literal that
does not fit is listed in a new swift_string_literal_omissions field
with its address, byte length and reason, so consumers read omissions
from structured data rather than from limitation text.
strings_names comparison checks referenced strings and names first and
reports a change there even when Swift literal coverage differs; it
returns unknown only when those facts match and literal coverage is
absent on one side or partial.
A computed jump counts as a tail call only when it has no resolved
target inside the function, so jump tables no longer qualify, and a
return requires a RETURN p-code operation, so traps no longer qualify.
Decoded literals keep control characters, which Swift strings may
contain and JSON escapes. The Swift verifier builds the literal fixture
for arm64 on any Mac host and now also covers the empty string and a
literal containing a tab.
* fix(ghidra): charge escaped JSON and follow copied selects
The Swift literal budget now charges the worst case per UTF-8 byte: UTF-16
text, six escaped JSON characters held in Gson's growing buffer and in the
returned String, and the UTF-8 bytes written to the socket. Literals made
of control characters can no longer exceed the reserved heap.
A jump counts as a tail call only when every resolved target lies outside
the function. The conditional select check follows register copies back
to their definition, so selects copied into argument registers are
recognized like selects written there directly.
strings_names reports a change when both dossiers decoded different
literals at the same use site, even when either side has omissions; it
returns unknown only when no such use site disagrees.
* fix(ghidra): bound literal records and trace selects across branches
Every Swift literal record now pays a fixed cost against the dossier
budget in addition to its text, so many empty or small literals are
bounded as well. The first record that does not fit is kept as an
omission and decoding stops there, which keeps the omission record
itself bounded; omissions now describe small or large literals.
The conditional select check searches every predecessor path for the
reaching definitions, following register copies, so selects made
before a branch into the use block are recognized.
A dossier records Swift literals and their omissions together. Coverage
reads omissions first, and strings_names compares every use site that
neither side omitted: a decoded literal is known where it was recorded,
and an absence is known only in a dossier whose decoding examined every
use site.
* fix(ghidra): stop every flow at the literal budget and route omissions
Ending one flow from the evaluator leaves other queued flows running, so
the budget now records a shared stop that every flow checks before it
examines another instruction. A record that exceeds the budget is routed
by that capacity result rather than by whether text was decoded, so a
small literal over budget becomes an omission instead of a literal.
When coverage is partial, the per site comparison keeps each literal's
representation as well as its value, matching the full strings_names
projection.
* fix(ghidra): keep unresolved Swift tail-call sites unknown
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Select the Windows curated lane for edits to the shared runtime path matcher and its workflow suite. Strengthen the existing POSIX/Windows mapping controls with matching basis, coherent target/script coordinates, caller spelling and static load-state assertions.
Follow-up to #2422; thanks to @Aurantium-47 for identifying the recorded-path grammar issue.
Verified with actual Windows 11 x64, official Node 24.18.0 and production CLI/MCP workflows using published npm 11.16.0 module Evidence. Four exact/mismatched implicit/explicit mapping cases pass with unchanged normalized hashes. The capture provider was Node Inspector; no IDA, Ghidra or Electron GUI verification is claimed.
230 focused tests, all eight CI static tasks, architecture guards and documentation checks pass after rebasing onto main fb28ec153. The unrelated release-checkpoint and dyld fixture corrections were integrated from upstream; no patches to those files are included here. Final Windows MCP replay at e6e86946d preserves all four normalized hashes, with no owned Node processes remaining. Resource probes ran serially at BelowNormal priority with one CPU and 512 MiB Node heaps; calls took 251–620 ms and the sampled process-family working-set sum peaked at 499,380,224 bytes. Source pins, provenance and measurement limits are recorded in experiments/analysis-efficiency/windows-posix-reconciliation.md.
All 34 jobs in current-head CI run 38391921571 passed, including the Windows capability/package lane, all six portable test shards, JavaScript recovery and the required aggregate. Current-head Codex and Greptile reviews are clean; both prior scope-selection findings were fixed and resolved.
Refactor firmware verifier into staged functions
Restructure scripts/verify/firmware/analysis.mjs for readability without changing behavior.
- Move prerequisite checks into checkPrerequisites()
- Split the main flow into stageCli, stageMcp, stageExt4 and stageGhidra
- Extract timeouts and size limits into named constants
- Rename cli/call helpers to runCli/callTool
Checks, order of operations, error messages and env vars are unchanged.
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Node's path.join does not reset at an absolute segment, so
path.join(__dirname, '/preload.js') is <dir>/preload.js. The static path
projection skipped the __dirname anchor and joined the remaining parts,
which turned that common spelling into the root path /preload.js. In an
app whose main script lives in src/, the BrowserWindow preload was then
reported not-found, or resolved to an unrelated preload.js at the artifact
root, and the utilityProcess.fork target was never resolved. String
concatenation had the same defect: path.dirname(__filename) +
'/preload.js' projected to /preload.js, and __dirname + '/preload.js'
stayed unknown.
A source directory now contributes "." to a join, so path.join(__dirname)
projects to "." like path.resolve(__dirname). A concatenation that starts
with __dirname or the source file's dirname keeps text that begins with a
separator inside that directory; other text extends the directory's own
name and stays unknown. The empty-string projection of
path.dirname(__filename), which produced the wrong concatenation, is
removed, so a bare path.dirname(__filename) is unknown like a bare
__dirname.
* fix(artifacts): report malformed ZIP archives as format failures
zip.js signals archive faults (missing end-of-central-directory record,
unrecognized format, overlapping members, corrupt member data,
unsupported compression) as plain Errors. ZipArtifactReader passed them
through untyped, so the artifact provider's fallback reported every one
as `io` with no detail and told the caller to "check file access".
Type these faults at the ZIP reader boundary: structural and data
corruption become `format` failures and unsupported archive features
become `unavailable`, each carrying the zip.js reason as detail. This
covers enumeration, the getData rejection, and the WritableStream abort
path that delivers corrupt-data errors first.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(artifacts): share the ZIP inventory failure assertion
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Keep directory requests from becoming unresolved or pointing at sibling files
when constructing reference-source dependency graphs. Canonicalize index
candidates and preserve directory intent while retaining ordinary lookup rules.
Constraint: Preserve current TypeScript candidate objects and exact-before-Unicode lookup
Rejected: Reorder all file probes before index probes | Changes ordinary CommonJS candidate priority
Confidence: high
Scope-risk: narrow
Tested: Public CLI regression fails on base; focused reference and resolver suites pass; npm run check
Not-tested: Full suite on refreshed base; earlier full run had 12 baseline-reproduced failures
Add a plain x86_64 slice to the dyld fixture while retaining both same-named arm64e slices and their independent environment assertions.
The original fixture was rejected by real x64 CLI admission before tracing. The contributing PR's complete Linux CI run passes all 30 jobs, including the portable suite. Codex and Greptile reviews completed without findings; no unresolved threads remain.
This restores the main test baseline needed for #2635. The change is limited to test data and preserves the original author's contribution.
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Limit classification to five minutes, static/build/docs/report jobs to ten minutes, and each portable shard to thirty minutes. The saved successful-job sample peaked at 392 seconds per shard and 61 seconds for other core jobs, leaving generous setup and coverage headroom. Runner queue waiting is unaffected.
Scope the steps schema to the release job whose preflight is executed, allowing unrelated reusable-workflow jobs such as qualification. Preserve all four valid and invalid metadata execution checks.
Reproduced on main ec3db3745: 35 passed, 4 failed. After the fix: 104 release and CI boundary tests pass; check:fast and format:check pass.
Explain each case through the obstacle, useful hypothesis and verified result. Remove byte totals, relocation counts and trial counts from the main narrative; preserve commit references and the constant-value example that explains the oracle defect. Make the experiment table and compiler terminology easier to follow.
Validation: website.py check, formatting, preserved source links, and eight article layout checks across both preview paths and light/dark themes.
Normalize the three quoted phrases to straight English quotation marks. Website checks and formatting pass; the local preview serves the revised punctuation.
Connect the reconstruction cases to the questions about specialization, retrieval and feedback-driven search. Replace fragmented sentence sequences with explicit causal links and smooth the progression into oracle design and the proposed comparison.
Validation: website.py check, formatting, preserved source links and evidence figures, and eight desktop/mobile light/dark layout checks at both preview paths.
Indent the optional language selector with its value so a nonindexable draft does not generate a line containing only spaces. Indexed-page markup is unchanged.
Validation: website.py check passes all 12 maintenance regressions; synchronization changes only the draft header blank line.
Add an English review draft connecting Touhou reconstruction evidence with model specialization, repository knowledge and feedback-driven learning. Preserve model attribution and historical verification scope in supporting notes, and translate the new Blog listing for all existing editions.
Validation: website.py check, focused formatting checks, and 32 Chromium cases covering both preview paths, light/dark themes, responsive layouts, translated indexes and no-JavaScript reading.
* fix(artifacts): read ASCII control bytes in legacy ZIP names as ASCII
ZIP names without the UTF-8 flag were decoded with zip.js's CP437 table,
which maps bytes 0x01-0x1F and 0x7F to IBM PC display glyphs. A folder
zipped on macOS with a custom icon therefore listed and extracted
`Folder/Icon\r` as `Folder/Icon♪`, a name that is not in the archive and
differs from REA's directory inventory of the same folder. Tabs became `○`
and DEL became `⌂`.
Decode legacy names in REA's existing decodeText hook with the Unicode
CP437 mapping that Python's zipfile also uses: bytes below 0x80 as ASCII,
and the upper half with the same table zip.js uses.
Windows file names cannot contain U+0001-U+001F, so a Windows extraction
destination now refuses such a path with a typed path failure before
creating anything, as it already does for ':'.
* test(artifacts): check extracted legacy ZIP control names on disk
The control-name cases checked only the logical path that inventory
reports. Extraction writes through SafeOutputTree, so a change that
renamed the extracted files would still pass those cases.
Extract `Icon\r` and `é\t\u007F.a`, then compare the reported
relative_path, the directory listing, and the file contents. The new
cases skip on Windows, which refuses these names.
safeOutputTree.test.ts covers that refusal.
Select SQLite compatibility by explicit source, fixture, lifecycle, and script ownership while retaining every version in full qualification. Share the canonical scope inventory between planning and the required gate.
Reuse recent exact-SHA full qualification only for hourly schedules, with trusted successful-run metadata and receipts. Force a daily refresh, reject stale original runs even after retries, and never renew proof from reused validation.
Report attempt-specific queue, execution, and matched step timing in a separate completion workflow using trusted default-branch code and read-only API access. Preserve raw metadata and unknown timings without delaying validation or publication.
Validation: 177 focused tests; typecheck/lint; knip; actionlint 1.7.7; all 1046 tests discovered; live 37-job API report smoke. Remote workflow scheduling and real-provider matrices remain CI verification.
deriveFindings looked up each traced root's slice again by architecture
name. A universal executable with arm64e and arm64e.x1 slices reports
both as "arm64e", so both roots resolved to the first slice: a later
slice's LC_DYLD_ENVIRONMENT produced no finding, or the first slice's
command was reported twice. The per-slice dyld_environment arrays were
already correct.
traceDylibLoading already has the exact slice when it records a root, so
pass it to deriveFindings instead of re-deriving it from the name. The
public roots and findings shapes are unchanged.
Fixes#2661
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Remove redundant ref-based concurrency from reusable provider and website workflows. Their old groups could cancel qualification from another CI tier even though the callers used separate groups. Disposable hosted jobs now inherit caller scheduling; direct manual dispatches remain independent.
Validate every called CI workflow has no independent cancellation group. Validation: 100 focused scope/gate tests and actionlint 1.7.7.
Scope main pushes from a successful ancestor so canceled runs cannot hide changes. Keep the complete portable suite in fast feedback and move coverage plus Intel macOS to hourly, manual, explicit-full, and release qualification. Let qualification finish independently of superseded feedback.
Bind publication to full qualification at its exact revision and publish the verified tarball after checking workflow identity, version, and SHA-256. Keep trusted cache writers and reject incomplete merged test inventories.
Validation: 151 focused CI tests; typecheck/lint; actionlint 1.7.7; knip; all 1044 files discovered; bounded blob/merge smoke; macOS package verifier with retention and cleanup; npm pack dry run. Native Linux/ARM/Windows and remote workflow execution remain CI verification.
* fix(native): select one slice when universal Mach-O slices share a CPU type
On macOS 27 most system binaries are universal files whose slices share
CPU_TYPE_ARM64: arm64e + arm64e.x1 (Calculator, TextEdit), x86_64 + arm64e +
arm64e.x1 (/bin/ls), or arm64 + arm64e.x1 (ShortcutDroplet). Target admission
names slices by CPU family, so these targets have availableArchitectures
["arm64"] while the file holds two arm64 slices.
inspect_macho read that family count as a slice count and ran otool, nm,
dyld_info, dwarfdump and vtool without -arch. ShortcutDroplet failed with
"Malformed otool load-command output" (40 load commands against ncmds 20).
Calculator reported both slices' imports (4138 instead of 2069), nm's
"(for architecture ...)" header lines as exports, and no selected slice.
selectArchitecture now also filters when lipo lists more than one slice. Its
preference is unchanged: the family name, then arm64e, then the first
arm64e.<variant>.
inspect_native_dispatch_metadata matched FAT slices by CPU type only and
refused /bin/ls and TextEdit as "Ambiguous FAT architecture slice".
selectMachoSlice now ranks slices of the requested CPU type by base subtype in
the same order: arm64 (0, then 1) or x86_64 (3), then arm64e (2), then other
variants such as arm64e.x1 in FAT table order. It reports ambiguity only when
the top-ranked slices share a subtype.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(native): share Mach-O slice preference across inspections
* chore: preserve upstream process capture test during merge
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
HAR validation reported only the AJV keyword, so a capture missing
`log.version` failed with "HAR schema validation failed: required." and
the caller could not tell which property to supply. Include AJV's
constraint message, which names the missing property, expected type, or
pattern without restating captured values.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Declare the synthetic 4 KiB Mach-O slice alignment accurately while preserving the IDA thinning scenario. Share web cleanup aggregation and process-trace fixture facts instead of duplicating them across consumers and tests; keep the 3% duplication threshold unchanged.
Validation: npm run check:ci, test discovery, and 42 focused IDA, process-trace, web workflow and cleanup boundary tests. Duplication falls from 3.01% to 2.99%.
Replace the implicit local-provenance fallback with explicit locally constructed values. Keep opaque results, parameters and caught values unknown; follow assignment and sequence results while retaining exact module aliases. Clarify that alias provenance does not represent transitive data taint.
Validation: 26 focused provenance/module-link tests, 135 semantic and graph-builder tests, six application module-relationship boundary tests, and the fast typecheck/lint gate.
Keep failed stable-read handles and WABT runtime roots under retryable resource scopes. Preserve cancellation causes and primary errors, close the same service instances bound to MCP tools, and consolidate CLI operation/cleanup projection.
Validation: fast typecheck and lint, cached runtime build, docs checks, SDK schema validation, focused service and real-file cleanup tests, CLI cleanup regressions, and MCP lifecycle/shutdown workflows. Provider process fixtures simulate engine output; real WABT and Linux EVM execution are not established by this pass.
Compare import and require outcomes for static TypeScript references when compiler options are unknown. Preserve branch facts through worker IR and both graph projections; retain declaration fallbacks as candidates without changing explicitly selected paths.
Validation: 210 focused resolver and semantic tests; 21 production-boundary and source-extension tests. A bounded 2,000-reference probe adds about 16–17 ms wall time for dual resolution; full task token costs and real compiled application behavior remain unmeasured.
* perf(native): add opt-in Mach-O summary delivery and retained pages
inspect_macho returns every import and export inline. For VS Code's
Electron Framework one MCP call carries 2.5 MB of text (about 828k o200k
tokens), and the same again as structuredContent; the MCP response
budget admits it. Agents asking for slice identity, UUID or dependency
counts paid that cost on every first call.
Add the established opt-in detail selection: omitted or complete keeps
the existing complete result and Evidence identity, while summary
retains the complete Evidence and returns slice identity with
per-collection returned/total/exhaustive counts (956 tokens).
inspect_analysis_view kind macho pages the original rows of any
collection or the command provenance, repeating the producer's own
total and exhaustive flag so page exhaustion is never read as absence.
Delivery detail never reaches the native tools or the source Evidence
ID: registerEvidenceTools gains a parametersForEvidence hook, so the
summary's parent is the same Evidence as a complete call.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(mcp): refuse unretainable summary delivery before analysis
A server without Evidence retention (a fixed analysis source) ran the
complete inspect_macho or inspect_artifact analysis for detail summary
and only then refused it in summarizeRetainedAnalysis, paying the very
cost summary delivery exists to avoid. registerEvidenceTools gains a
preflight hook; both registrations check retention there, as the WASM,
EVM, managed, pcap and capture handlers already do before dispatch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(native): keep whole rows in Mach-O architecture and segment pages
The page item union listed plain-object row arrays, and zod returns the
first union member that parses while dropping unknown keys. Entrypoint
rows declare only file_offset, so every architecture and segment row
(which also carry a numeric file_offset) matched it and lost its name,
CPU fields, permissions and sections. Rows now use exact key sets, and
imports/exports share one member. The MCP test pages every facet of a
real /bin/ls and compares it with the unparsed complete rows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Once a Frida session reached its 16 MiB capture budget, every new message
evicted the oldest one with Array#shift, re-serialized it to recover its
byte charge, and searched and spliced its per-script array. Each of
those is linear in the retained messages, so with about 188k small
messages retained the cost per message rose from 0.14 µs to 32 µs and
capped the main thread at roughly 31k messages per second, which a
hooked hot function can exceed.
Keep both queues as head-offset FIFOs that compact once half their slots
are evicted, and record each message's charge when it is admitted.
Arrival order already makes the globally oldest message the oldest one
of its script, so per-script eviction becomes a head check. Eviction is
now amortized O(1) at about 0.14 µs per message; retained messages,
their order and the truncation flag are unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(native): name the ownership helper prerequisite in command failures
Every supervised native command launch needs the Darwin process-ownership
helper. When that helper cannot be compiled (relative REA_DARWIN_SWIFTC_PATH,
missing SDKROOT, a missing compiler, or an SDK/compiler mismatch), the
runner reduced the typed DarwinProcessOwnershipInspectionError to a bare
`io` failure. inspect_macho then reported `execution_failure` with no hint,
and inspect_artifact on any universal Mach-O said only "lipo could not
enumerate universal Mach-O slices".
The runner now keeps the inspection message as the failure's `detail` at
the launch boundary and carries it through xcrun resolution. The native
provider adds it to its diagnostics and the slice reader appends it to its
message, matching what the SQLite and capture providers already report.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(native): cover the provider's ownership helper diagnostics
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Android 10 and 11 print restricted entries of the requested-permissions
list as "NAME: restricted=true". The parser took the first such line as
the end of the list, so the count stopped there while coverage still
read complete.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(windows): preserve caller affinity only within one processor group
`spawnProcess` read the caller's affinity mask and applied it to the
suspended child unconditionally. A mask names processors relative to one
processor group, and Windows assigns each new process to a group of its
own choosing, so on hosts with more than 64 logical processors the child
is often placed in another group. `SetProcessAffinityMask` then rejects
the mask with ERROR_INVALID_PARAMETER (87) and the spawn fails, making
every owned provider process start intermittently on such hosts.
Affinity is a nicety, not an authority or isolation control, so it is now
applied only when the caller and the suspended child both occupy the same
single processor group. A child placed in another group keeps that group's
default affinity and the spawn proceeds. Job Object membership,
kill-on-owner-close policy, owner normalization and priority preservation
are unchanged, and the mask failure remains fatal within a shared group,
where it is not expected.
Single-group hosts, including every host with 64 or fewer logical
processors, are unaffected: `GetProcessGroupAffinity` reports one group
for both processes and the same mask is applied as before.
The optional process-boundary fixture gains an `affinity` observation,
and the native verification lane asserts that an owned spawn succeeds and
that the child's mask matches the caller's whenever both share a single
group.
Fixes#2181
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(windows): refuse to widen a pinned caller's affinity across groups
Addresses review feedback on the first commit.
An unconstrained caller loses nothing when Windows places an owned child
in another processor group, so that spawn proceeds with the group's
default. A caller deliberately pinned to fewer processors than its group
holds is a different case: silently accepting the default would hand the
provider tree the whole group, which `docs/installation.md` tells
operators to rely on affinity to prevent. Such a spawn now fails naming
the constraint instead. `GetProcessAffinityMask` already reports the
group's active set, which distinguishes the two without another query.
Selecting the caller's group at creation through
PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY was tried first and rejected:
`CreateProcessW` fails with ERROR_INVALID_PARAMETER on a host with a
single processor group, both alongside PROC_THREAD_ATTRIBUTE_JOB_LIST and
on its own, so it cannot carry the ordinary path.
The boundary fixture's affinity observation now reports a process id's
own mask rather than its own, because a separate probe process is
assigned its own group and cannot stand in for the process that spawns
the child. Masks and the group's active set cross as fixed-width
hexadecimal strings: a mask can set bits above the safe-integer range,
where `JSON.parse` would round two different masks to one value.
The verification lane asserts the mask is inherited exactly when caller
and child share a group, and otherwise that the caller was unconstrained.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(windows): record what owned-process affinity does not preserve
A mask covering its group's whole active set does not distinguish a
caller the system placed in that group from one that selected the group
deliberately, so an owned child can still be placed elsewhere with its
processor count bounded and its group placement lost. Treating that case
as constrained instead is not available: on a multi-group host an
ordinary process is assigned a group by the system and its mask is that
group's active set, so refusing it would fail every owned spawn there.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The trace specification owns the declared identifier vocabulary and the
comparison result echoes those identifiers verbatim into raw_trace[].event_id,
matched_variant and diagnostic event_ids. The result module restated the shared
IDENTIFIER_PATTERN by hand with a 64-character cap, so a specification with a
longer identifier validated and then its own comparison result failed to parse:
compareProcessTraces threw a raw ZodError at the caller instead of returning a
comparison.
Export the identifier schema from the specification as the single owner and
reuse it in the evaluation module, removing the capped copy. IDENTIFIER_PATTERN
has no length bound and every other consumer uses it unbounded, so the
duplicate was the outlier. Removing the bound rather than adding one keeps the
advertised trace_spec input contract unchanged; identifiers of 64 characters or
fewer behave exactly as before.
Verified with 48 process tests, 24 boundary CLI/MCP trace tests, check:fast and
verify:test-discovery on macOS arm64. The regression test failed with the
ZodError before the change and passes after it.
Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
* test(ida): expect the private input of a universal Mach-O to end at the selected slice
Cover a universal file larger than one read chunk with another slice after the selected one, for both a middle slice and the first slice.
* fix(ida): stop the private input of a universal Mach-O at the end of the selected slice
A read chunk that starts after the slice produced a negative end offset, and Buffer.subarray counts a negative bound from the end, so the head of the following slice was written to the private input and its digest.
Use POSIX path semantics for recorded POSIX roots when reconciling runtime Evidence on Windows. Preserve Windows mapping behavior and cover implicit and explicit file roots through the reconciliation service.
Assisted-by: OpenAI GPT-6 <noreply@openai.com>
Co-authored-by: Aurantium-47 <280805072+Aurantium-47@users.noreply.github.com>
The pcap summary sorted equal-count endpoints and protocol stacks with
String#localeCompare, and Flutter build inspection sorted APK ABI
directory names the same way. localeCompare follows the host's ICU
locale, so the same capture produced differently ordered Evidence on
different hosts: under da_DK "aarp" sorts after "zz", under lt_LT
"syslog" sorts before "ssdp", and every locale puts "fe80::1" before
"fe80:1::1". Use the repository's compareUnicodeCodePoints, as the
other Evidence producers already do.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
redactExplicitFailure rebuilds each typed failure field by field so explicit
literals are removed while the projected code stays the same. The rebuild for
AnalysisCapabilityUnavailableError carried providerId, operation, reason and
userMessage but not retryable, and the constructor defaults that field to false.
Redacting a transient capability failure therefore made it permanent and changed
the remediation shown to the caller.
Pass the field through with the same conditional-spread shape used for
userMessage. The constructor recomputes retryable from cleanupIncomplete, and
cleanup is already part of the reconstructed context, so a value that was true
before redaction stays true and a false value stays absent.
Verified with 66 error projection, access-denied, redaction and capture-failure
tests, check:fast and verify:test-discovery on macOS arm64. The regression test
failed with "expected false to be true" before the change.
Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
* fix(apple): limit already-loaded reuse to rpath dependencies
dyld reuses an already-loaded image by install name only for @rpath/
dependencies (Loader.cpp:802-816) and evaluates other dependency forms
against their expanded path for each loader. When multiple images in
different directories depend on @loader_path/ libraries sharing an
install name, checking loaded images before candidate expansion caused
subsequent loaders to bind to the first loaded image's copy or appear
resolved when their own copy was absent.
Limit byInstallName registration and lookup to install names that start
with @rpath/, leaving caller-relative and literal dependencies to expand
and evaluate their own candidate paths.
Signed-off-by: Vinícius DS Andrade <95101505+viniciusdsandrade@users.noreply.github.com>
* test(apple): verify loader_path dependencies across isolated directories
Assert that multiple images depending on @loader_path/ libraries with
the same install name do not reuse already-loaded images across loaders.
When the second loader's helper is absent, its candidate path is absent
and dyld reports required-load-unresolved; when both helpers exist, each
loader resolves to its own directory.
Signed-off-by: Vinícius DS Andrade <95101505+viniciusdsandrade@users.noreply.github.com>
---------
Signed-off-by: Vinícius DS Andrade <95101505+viniciusdsandrade@users.noreply.github.com>
The macOS installer accepted any bundle that passed `codesign --verify`
and whose `Info.plist` said `com.cryptic-apps.hopper-web-4`. An ad-hoc
signed bundle with that identifier satisfies both, so a substituted DMG
could be copied to ~/Applications and launched.
Verify a pinned code requirement instead, covering the sealed bundle
identifier and the signing team together, and report a distinct
`publisher_verification_failed` code so a vendor key change is not
confused with a corrupt package.
extract_artifact carried its own copy of the ZIP package format list with five
of the eight members the domain owner declares, and used it both as the guard
that refuses a format without an extraction reader and as the selector for the
reader itself. A .hap, .hsp or App Pack target was therefore refused with
"Artifact format has no extraction reader" even though the next branch builds a
ZipArtifactReader for exactly those formats, while inventory_artifact classifies
the same path through the owner and reads it.
Import isZipPackageFormat from the domain owner and delete the duplicate list
and its predicate, removing the second representation instead of reconciling it.
The reader branch now narrows to ZipPackageFormat, which is what the
ZipArtifactReader constructor already requires.
Verified with 41 boundary extraction, ZIP integrity and detection tests,
check:fast and verify:test-discovery on macOS arm64. Reverting only the source
change fails exactly the three added families and leaves the zip control green.
Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
Ignore generator-owned website translation staging output while preserving authored lint errors and complete diagnostics.
Verified with a real checker regression, a production translation build, complete coverage, developer/CI regression checks and native lanes.
Fixes#2508
Declare application.java.min=21 at the four synthetic installation producers so profile, PSP, lifecycle and MCP workflows exercise their intended paths under fail-closed Java admission. Keep missing-bound refusal coverage intact and format the two Ghidra tests rejected by the CI static lane.
Validation: all 82 tests across the 11 failing CI files passed; 66 Ghidra admission, doctor and snapshot tests passed, including missing Java bounds. No production admission policy changed. Full suite and real Ghidra lanes were not run.
* fix(pcap): name the host tool to configure in capability refusals
Missing or misconfigured tshark/capinfos, the unsupported macOS capture
boundary and an unusable Linux prlimit were projected with the generic
"unavailable for the current target; choose another target" advice, even
for inspect_pcap_client, which has no target. Route tool refusals through
one pcapToolUnavailable owner that names REA_TSHARK_COMMAND and
REA_CAPINFOS_COMMAND, give host-boundary refusals their own reason, and
keep the private workspace refusal's retryable flag like WABT and source
maps do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(pcap): cover the Linux prlimit refusal guidance
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
On hosts without an enforceable native bound (macOS), the provider refuses
inspect_pcap_capture with capability_unavailable before it touches the
path, which the unsupported-boundary test in the same file pins. The
missing-path test expected invalid_request on every host, so it always
failed on macOS while Linux and Windows CI stayed green.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Group observations by exact normalized instant, retaining arbitrary fractional precision and offset equivalence. Coalesce equivalent assessments and all supporting Evidence; report conflicting latest assessments as unknown with verifier-result-ambiguous. Use the same instant comparison for freshness and future checks.
Replace first-input-wins coverage with permutation, provenance, offset, sub-millisecond ordering, and future-clock regressions, including the public MCP workflow. Validation: focused reconstruction/offset tests and MCP workflow passed; converted JSON Schema validation, typecheck/lint, and docs checks passed. Full suite and real-provider lanes were not run.
Narrow WASM and EVM execution ports to file subjects and preserve supplied subject types at the shared execution factory. Authenticate format with path and digest before recording or projecting Evidence, using the existing WASM identity owner in both consumers.
Validation: focused WASM/EVM service and public MCP workflows passed, including malformed provider subjects and self-contained retained Evidence with contradictory format. Global typecheck/lint and documentation checks passed. Real WABT/Evmole execution and the full suite were not run.
Prove total orders with Kahn traversal and use ranks; stream forward and reverse reachability for general partial orders instead of retaining every closure. Aggregate unordered conflicts by declaration while preserving missing-pair counts and independent malformed-input diagnostics.
Validation: 33 focused trace domain and CLI/MCP boundary tests passed. Six bounded Flameox executions preserved answer digests and cycle rejection; combined median peak RSS fell from 391.13 to 127.72 MiB. General partial-order traversal costs more CPU; the experiment records that tradeoff. Full suite and real-provider lanes were not run.
Require terminal stderr before launching the automatic setup wizard, matching the CLI's interactive admission rule. Print the manual setup command when diagnostics are redirected.
Exercise a real PTY with stderr redirected to a fixture file and verify the installed command is not launched for setup. Installer lane: 33 tests passed; targeted regression, typecheck/lint and npm pack dry-run passed. Full package verifier was not run under the requested focused-check resource policy.
Use iterative cycle detection, memoized reachability and compact unordered-group membership. Preserve declaration diagnostics on cyclic input while skipping checks requiring a valid partial order. Report duplicate group declarations once instead of repeating pair errors.
Replace redundant source cycle/missing-pair assertions with public CLI/MCP coverage including 6000 events, dense not-before constraints and a large unordered group. Validate acyclic branching and mixed relation semantics. Document bounded Flameox CPU/latency gains and higher observed peak memory; agent/model costs remain unmeasured.
Close persisted Evidence, bundle, profile and unknown record shapes so parsing cannot silently remove caller metadata before checking semantic identity. Keep constructor provider projection explicit and JSON payload fields open.
Exercise actual MCP export/import with independent record and manifest mutations, unchanged state after rejection, and a valid round trip. Prune duplicate source assertions. Validation: focused domain/CLI/MCP/filesystem checks, converted JSON Schemas, docs and typecheck/lint.
Bind the owned demo helper to REA's private stdin stream and unwind child
cleanup on EOF during startup or analysis. Verify graceful and SIGKILL owner
exit through real CLI/MCP workflows and preserve unrelated processes.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
Summarize saved Wireshark4.x captures with enforced native resource limits, serialized admission, stable snapshot verification and retained fact/text pages. Preserve complete inventories within resource budgets and source uncertainty; report cleanup failure with partial Evidence and retained ownership.
Verified six recorded corpora /13026 packets with independent Scapy/Python oracles, real CLI/MCP/schema parity,60 SNI names,132 DNS addresses and1000 URIs. Real TShark CI now exercises summary/paging. Actual Windows/Bun Wireshark remains unverified; macOS capture requires a separate enforceable-bound decision.
Co-authored-by: 3QL <85309073+3QL@users.noreply.github.com>
Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
Follow-up to #2345; thanks to @gefrezim for the import-time home lookup diagnosis.
Normalize only an empty Windows USERPROFILE before runtime dependency imports, preserving all nonempty caller selections. Reuse the existing public setup dry-run regression in the Windows curated CI lane. No additional filesystem query, engine call, cache or retry.
Verified real Windows Node 24.18.0 CLI unset/empty/selected-profile controls, setup dry-run home selection and unchanged configuration, and baseline/candidate SDK stdio MCP catalogue parity. Nine related tests and static/docs checks passed. No IDA or Ghidra engine was used. Scoped resource observations and measurement limits are recorded in experiments/analysis-efficiency/windows-empty-profile.md.
Fixed the review finding and original CI package-scope ownership failure. Current-head CI is green; the unrelated MCP identity timeout passed on a failed-job rerun without changing its code or timeout. Current-head review completed with no further findings.
inspect_macho launched otool, nm, two dyld_info reads, dwarfdump and
vtool one at a time. Each launch also resolves the tool through
`xcrun --find`, so a warm call spent about 350 ms in eight serial
supervised launches. The slice commands only read the selected
artifact, so launch them together. Every launch still settles before
the result, and declared order still fixes provenance and which
failure is reported.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
When a pwntools or pwndbg stage cannot confirm that its owned process
group stopped, the cleanup_incomplete result listed only the run ID and
runtime directory, although a descendant can still be live. Add the
retained supervisor's pid and process-group coordinates, as
OwnedCommand reports for a non-transferred cleanup failure.
Fixes#2274
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Reuse the domain ZIP format list for session schemas, verify full Harmony
CLI/MCP lifecycles, and correct native view guidance and audited docs drift.
Refresh locked dependency notices and gate inventory/provenance consistency,
including notice inputs in the cached documentation gate.
Fixes#2454
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Reuse the current advertised binary_session definition for real SDK reply
validation while preserving all inventory assertions and the 10-second deadline.
Avoid initializing validators for unrelated tools in this correctness check.
Closes#2453.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
Fixes#2257. Thanks to @chqcjq for the native self-test retry diagnosis in #2266.
Preserve retry disposition through analysis workflows. Native warm admission requires exact sharing/lock codes and affirmative pre-allocation evidence; cleanup ownership takes precedence. No automatic retry or new analysis cache.
Verified with real Windows 11 CLI, same-connection SDK MCP normal/conflict/recovery, the Windows native verifier, 99 focused tests and static/docs gates. Official npm 11.16.0 launcher sources were the application input. No IDA or Ghidra engine was used for this change. Win32 5 was not reproduced; no resolution claim for #1701/#2196. Performance measurements and limits are recorded in experiments/analysis-efficiency/windows-runtime-retry.md.
Add explicit MCP Dart AOT summary delivery and exact retained string-pool pages while preserving complete defaults, CLI behavior, ABI selection, original Evidence identity, partial coverage and lower bounds.
Real LocalSend SDK replies shrink 92.05% with approximately unchanged SDK time. Two actual Codex pairs preserve all selected facts and reduce total input 48.75% / 42.38%, uncached input 33.63% / 42.52%, and task time 23.95% / 30.30%; all client errors/repeated calls remain counted. Preserve old portable Evidence and the real CLI complete result after rebasing onto SAZ/qlog main. Curated results keep measured and integration runtime pins separate; raw artifacts stay outside Git.
Refs #2016.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Inspect bounded recorded raw HTTP/XML SAZ archives and page retained capture Evidence. Preserve exact stored bytes and provenance, validate ZIP/XML integrity, and require an enforceable decoder memory bound.
Verified 356 real recorded sessions against independent byte and metadata oracles, public CLI/MCP parity, retained pages, and related interface checks. Current Fiddler Everywhere GUI and non-Linux producer workflows remain unverified.
Co-authored-by: zahhak <1792039+zahhak@users.noreply.github.com>
Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
Add explicit package summary delivery and exact retained manifest pages while preserving complete MCP defaults, one-shot CLI output, provider requests, source identity and session lifetime. Return distinct linked Evidence and preserve partial/null facts; reject unavailable retention before engine work.
Validation: 27 relevant SDK/domain/Android boundary checks, focused test-only correction rerun, full supported compiler/lint and docs checks, real NewPipe SDK pairs, authentic old Evidence continuation, four actual Codex trials with failures/regressions retained, and all 39 exact-head CI checks. Package replies shrink 119,527 to 8,659 bytes; no model-token or time gain is established.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add opt-in, owned payload-completion cgroup witnesses without changing default receipts, terminal-counter semantics, resource limits, or REA public APIs. Preserve unknown and nonzero outcomes; verify ownership, observer capacity, cleanup, and actual SDK/model workflows.
Validation: eleven Python semantic tests, supported full-project typecheck and lint, controlled Linux failure/cancellation/capacity probes, real managed/WASM/Android SDK and Codex runs, and all 39 exact-head CI checks. Curated evidence retains mixed timings and whole-scope uncertainty.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Scope source-file cleanup fault injection without poisoning enclosing Git
metadata reads. Cover both environments and verify that the retained native
handle stays live through retry, then closes successfully.
Closes#2428.
Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
Verify the static EVM descriptor operation, CLI command, factory and input/output schema bindings with compiler-backed negative assignability checks. Prove SDK duplicate registration and invalid target input fail before provider invocation, preserving named bindings and separate lazy owners.
Validated complete supported single-thread typecheck, focused12 SDK/composition cases plus a targeted2-case provider-spy rerun, static checks, checked pre-push, manual review and all exact-head CI checks. Production behavior/defaults and provider identity remain unchanged. Dynamic third-party module admission and ABI negotiation remain deferred.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add optional owned Codex tool/usage capture and exact-name discovery experiments while preserving default ephemeral trials and all REA public APIs. Retain scoped managed and actual Android results, mixed outcomes, source identities and resource unknowns.
Six semantic Python tests, full checked pre-push, byte-identical own-file rebase verification, manual review and all 39 exact-head CI checks pass. Historical main fixture failures and their independent repair remain documented; measured source/runtime pins are unchanged.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Reject native callee successes without an explicit truncation marker while preserving provider failure reasons. Verify positive procedure inventory/search and function-result parity in the real-provider lane; support independent string/xref oracles and label their absence as unverified.
Verified with Windows IDA Pro 9.3: eight normal production CLI/MCP checks passed, and six real-provider response-fault cases reproduced old false positives and validated the correction. Windows IDA Free was not used. No personal paths or license registration information are included.
Repair inconsistent complete-file Ghidra test probe sizes after the shared ELF-header validation change, deriving sizes from the fixture buffers. Reproduced the three failures before the correction; 115 related installation/doctor and ELF tests pass afterward. Runtime parsing and installation behavior are unchanged; no real-Ghidra verification is claimed.
207 focused IDA tests and static/documentation checks passed. Automated review completed on d1e0b1095 without findings. CI run 38327862093 passed all 36 jobs, including Windows, all six test shards, coverage/timing, and real Apple CLI/MCP workflows.
Follow-up to #1544.
Retain list_unknowns paging guidance in docs/reference/mcp-contracts.md and verify the public routes and affected MCP regressions.
Co-Authored-By: Codex <noreply@openai.com>
@modelcontextprotocol/client 2.3.1 declares callTool(params, options).
Three verifiers still used the v1 shape callTool(params, undefined,
{ timeout }), so the third argument was dropped and those calls ran
under the SDK's 60 s default instead of the 150-180 s they request.
Pass the options second.
Preserve upstream managed summaries and signal guides; verify public routes, source paths and anchors in documentation CI.
Co-Authored-By: Codex <noreply@openai.com>
Use the shared resource scope and private runtime root for signature snapshots. Retain failed file-handle/root cleanup, preserve primary failures alongside cleanup diagnostics, and wait for binding operations during client close before retrying owned resources.
Validate root cleanup failure, blocked retry, repeated client close and in-flight acquisition. Existing provider/MCP/CLI tests and the real Darwin codesign ancestor-swap case pass. Dedicated native file-handle close-failure injection remains unverified.
Keep complete default delivery and exact filters. Select stable ID pages at the ledger owner before cloning, return filtered totals and continuation offsets, and preserve detached records through the shared session port.
Validate public MCP paging, safe-integer edges, snapshot replay and converted JSON Schemas. Document the bounded Flameox workflow comparison and its token/CPU/latency measurement limits; no real model performance claim.
Validate ELF identification/header versions and declared header bounds at the shared owner. Reuse parsed facts in target selection, Go, Dart and MIPS readers while preserving their stricter format policies and x32 support.
Repair synthetic ELF fixtures and remove a superseded Go error-text assertion. Validation: 74 source tests, 202 filesystem/Go/MIPS boundary tests, typecheck and lint. No new real-provider claims.
Resolve upstream changes without dropping translations or the signal-recording guide. Add a production HTML regression for stable routes, edit links, assets and fragment targets.
Refs #2401
Co-Authored-By: Codex <noreply@openai.com>
Add caller-selected managed metadata summaries and original collection pages while preserving complete CLI/MCP defaults and previous-runtime Evidence. Real SDK replies shrink substantially; actual Codex token/latency results remain mixed and are documented without a token-saving claim.
Validated focused SDK/domain tests, full static/docs checks, real two-assembly repeated workflows and portable old Evidence, real SQLite WASM, and all exact-head CI checks. Raw experimental artifacts remain private.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
* fix(javascript): resolve module-relative Worker URL references
* fix(javascript): validate Worker URL paths independently of suffixes
* fix(javascript): preserve directory-form Worker URL paths
* fix(javascript): unwrap type assertions in Worker URL references
* fix(javascript): validate Worker bindings before URL resolution
* fix(javascript): leave drive-letter Worker URLs unresolved
Use WHATWG file URL parsing before pathname decoding to detect drive-letter
forms whose resource identity depends on the unmodeled source URL scheme.
Preserve encoded and ordinary relative pipe paths, and cover false matches
through the compiled CLI and resolver boundary tests.
* fix(javascript): preserve Worker URL identity boundaries
Recognize known Worker bindings before filtering callee spellings so ESM
aliases and transparent constructor wrappers reach URL analysis. Keep
root-relative module URLs unknown without a modeled runtime base root.
Index direct source-local global writes with the shared mutation collector
before promoting URL and browser Worker constructors. Preserve lexical
shadowing and unrelated property identities, and exercise all three review
regressions through the compiled CLI.
* fix(javascript): invalidate mutated import.meta URL bases
Track source-local import.meta writes alongside ambient global writes so
Worker URL expressions keep an unknown base after a possible URL mutation.
Tag the identity roots independently and cover direct mutation and unrelated
property cases through the compiled CLI.
* fix(javascript): close Worker URL identity and pathname gaps
Resolve ambient object identities before appending written properties, and
retain possible source-local aliases across rebinding. Reuse intrinsic
invocation handling for aliased and bound mutators, array spreads, and
transparent TypeScript wrappers while preserving Electron write semantics.
Keep malformed-percent nested Worker URL pathnames unknown because the base
scheme is unavailable and Node rejects these file URLs. Preserve tolerant
HTML URL handling, valid escapes, and query/fragment evidence.
Cover the new cases and unrelated writes through the compiled CLI with
existing-file decoys. All 591 targeted tests and npm run check pass.
* fix(javascript): bound alias expansion and classify Worker paths
Join ambient identity projections instead of enumerating alias histories.
Memoize repeated value and provenance queries while preserving capture,
depth, and cycle-dependent uncertainty.
Keep Node Worker string arguments unresolved without filesystem or cwd
context, and admit qualified global URL constructors through identity checks.
Validate three 40-level alias branch shapes through the compiled CLI,
925 source tests, 25 CLI/boundary tests, and the full npm run check gate.
* fix(server): preserve partial Evidence target-content provenance
Pass the exact named contract returnsTargetContent flag through the shared partial-Evidence error delivery path introduced by the shortlist integration.
Exercise successful and failed recording through in-memory MCP for marked and unmarked contracts, preserving source payload and original failures. Observe both shared-handler emission and wire delivery so the SDK error-marker fallback cannot hide omissions. Suppressing the flag fails exactly the two marked cases.
Validation: check:fast, check, 736 semantic tests, 29 MCP transport/error tests and six compiled static Worker CLI journeys pass. No live target/provider execution or hosted publication.
* fix(javascript): structurally share semantic dependency proofs
---------
Co-authored-by: baron <richstyles@gmail.com>
* fix(native): honor Mach-O chained pointer locations and library ordinals
Walk declared page starts and next links before decoding chained pointers,
preserving plain pointers between fixups, zero-offset rebases, and known
facts in malformed chains. Interpret positive dylib ordinals with dyld's
special-ordinal cutoff so valid dependency provenance is retained.
Give the Swift verification fixture an explicit module name so link-mode
filenames do not produce invalid identifiers.
Validation: 46 focused regressions; pre-fix reproductions in an isolated
copy; real macOS CLI/MCP verification of 10 compiled Objective-C/Swift,
arm64/arm64e, chained/legacy and symbols/stripped fixture variants.
* perf(native): reuse parsed Mach-O chain membership
* test(native): validate parsed-chain repair against local gates
* test(native): pin chained fixup page failure provenance
* fix(native): bound parsed chained page facts and metadata
* test(server): pin shared partial Evidence provenance
---------
Co-authored-by: baron <richstyles@gmail.com>
Verify unchanged real EVMole worker replies through compiled CLI and stdio MCP, including late SDK cancellation, permission-induced retained cleanup failure/retry, preserved malformed-input diagnostics and a healthy real SQLite WASM peer. Add launcher receipts to prove blocked retries do not start another EVM worker.
Preserve production contracts/defaults and explicit frozen-runtime/platform/measurement boundaries. Final head cf558a0661 passes all 36 CI checks (run38313631216); manual final review and related real Factory rerun pass. Raw artifacts and receipts remain outside Git.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Group all existing authored guides by domain and ownership, expose complete navigation, and preserve their public routes. Update physical path consumers and release configuration while retaining historical records. Document domain-based specs and ADR slugs without global numbering.
Co-Authored-By: Codex <noreply@openai.com>
* fix(browser): compare PNG IHDR bytes without ASCII folding
Screenshot checks already compare the PNG signature as raw bytes, then decoded the chunk type with an encoding that maps high-bit bytes onto IHDR.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(browser): satisfy the strict index check in the IHDR test
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(browser): share byte-faithful PNG header facts
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: REA preparation lane <rea-preparation@localhost>
* fix(artifacts): bound archive decompression by source size
A ZIP/APK/IPA/MSIX member is attacker-controlled and can expand far
beyond the archive that carries it. Inventory hashed every member to EOF
and extraction wrote every member with no ceiling, so a ~2 MiB archive
could drive ~30 s of CPU during inventory and ~150 s plus 2 GiB of disk
writes during extraction.
A fixed per-entry byte cap is the wrong shape: it rejects legitimately
large members inside large packages. The ceiling instead scales with the
archive's own size (500x, with a 256 MiB floor), so large packages keep a
proportionally large budget while a small archive cannot amplify into
unbounded work. The cumulative declared size is charged from the central
directory before any entry is decompressed, and zip.js already verifies
streamed output against each declaration, so the check is exact and
covers both inventory and extraction through the shared reader.
* fix(artifacts): own decompression accounting per traversal
* test(artifacts): verify declared ZIP output enforcement
---------
Co-authored-by: baron <richstyles@gmail.com>
Verify existing caller-selected Ghidra profiles and immutable JSON snapshot boundaries through real CLI/MCP workflows on GNU true and shipped jq. Preserve exact task facts, profile/source identity, original snapshot records and existing defaults; require actual stored query entries and scoped headless launch evidence.
Exercise pending startup cancellation with production token/native start-identity inspection, recovery under the selected target, controlled real permission cleanup failure, retained ownership and restored-permission close retry. Independently confirm recovered socket/root cleanup. Preserve failed observer assumptions, source fingerprints, measured scope and final-resource counter unknowns. No general fast preset, product API change or new performance claim.
Refs #2016
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Command Line Tools install the /usr/bin/ibtool and xcrun shims without ibtool itself, so the existing /usr/bin/ibtool existence guard never skipped the storyboard test, and the native NIB hierarchy suite had no guard. On a Command Line Tools-only macOS host these seven tests failed at fixture compilation. Probe xcrun --find ibtool once and use it for both suites.
* fix(artifacts): name CPU_SUBTYPE_ARM64E_X1 Mach-O slices arm64e
macOS 27 system binaries such as /bin/ls carry a third FAT slice with
cpusubtype 0x8000000c. The SDK defines subtype 12 as
CPU_SUBTYPE_ARM64E_X1, and CPU_SUBTYPE_HAS_ARM64E puts it in the arm64e
family. architectureName knew only subtype 2, so it named the slice
arm64, lipoNameMatches rejected lipo's arm64e.x1 name, and
inspect-artifact /bin/ls failed with integrity_mismatch.
The arm64e.x1 test fixture now uses the real subtype. It fails without
this change.
Refs #1168, #1765
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(artifacts): classify en-GB hdiutil verify refusals as format failures
hdiutil follows AppleLanguages. With en-GB it writes "image not
recognised", and verifyFailureReason matched only the US spelling, so a
file that is not a disk image got the reason unavailable. Both spellings
now give format. Other languages still give unavailable.
Refs #1765
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(process): read the full process table in the lifecycle cleanup check
The check ran ps -axo command= with the Node default maxBuffer of 1 MiB.
On a host with 1905 processes, the output is 1.52 MB, and the test failed
with "stdout maxBuffer length exceeded".
Refs #1765
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(process): bound cleanup observations to sampled descendants
* fix(apple): retain CPU subtype identity during dylib resolution
* test(process): retain OS PIDs for descendant observations
---------
Co-authored-by: David Lee <davidlee@Dav3Book-Pro-M4-Max.local>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(server): frame analysis-target content as untrusted data
Strings, decompiled code, page text, scripts, captures and logs returned
by REA originate from the analysed target, which can embed text aimed at
the agent. Nothing marked that content, so a prompt injection inside a
binary or page could steer the agent toward tools that run code.
- Server instructions now state that target-derived tool output is data,
never instructions, and that any request in it to run, install,
download or send something is a prompt-injection attempt to report.
- Tool contracts declare returnsTargetContent. It is on by default; only
seven tools whose results hold REA session state or caller-supplied
values (binary_session, close_binary, export_evidence_bundle,
record_unknown, update_unknown, inspect_adb_client,
inspect_apktool_client) are audited exceptions, so new tools start
marked.
- Successful results of marked tools carry
_meta.provenance = { untrusted_content: true, source: "analysis_target" }.
content and structuredContent are unchanged, and the response budget
accounts for the fixed marker bytes.
Tests cover the encoding and budget accounting, the audited exception
list against the contract catalog, and an in-memory MCP client that sees
the instructions and the marker on a marked tool but not on
binary_session.
* fix(server): mark failed target-content results as untrusted too
The untrusted provenance marker was attached only on the success branch
of ToolResultDelivery, but failures can carry target-derived text as
well: error messages, captured output, and partial observations such as
the terminal frames a failed capture_process_scenario retains in
partial_observation. A host gating later process or device actions on the
marker would have treated an adversarial error payload as trusted.
Every error path in src/server now carries the failing tool's provenance:
- toErrorToolResult and toRecordedPartialErrorToolResult take the tool's
target-content flag explicitly, so each caller is audited by the type
checker; toCallToolResult, toEvidenceToolResult (recording failure), the
response-budget error that replaces an oversized success, and the
Electron partial-evidence path pass contract.returnsTargetContent.
- Admission failures in runAdmittedToolOperation resolve the flag from the
tool name through the new toolReturnsTargetContent, the same predicate
the contract metadata uses; unknown names stay marked.
- The transport's oversized-error replacement keeps the original's marker
and counts it in its budget check, matching the projected error.
- Errors the MCP SDK builds itself (input validation, thrown handlers) are
marked in the transport for target-content tools only.
Error encoding accounts for the marker bytes exactly as success encoding
does. docs/mcp-contracts.md now states that error results carry the
marker. Tests cover marked and unmarked error results, the
capture_process_scenario partial-observation errors in-process and over
the SDK transport, the recorded partial-evidence path, the budget
replacement, the oversized-error replacement, and SDK validation errors
for a marked and a content-free tool.
* fix(contracts): mark session status, close and client probes as target content
The content-free exception set was audited against successful results
only. Now that failures carry the marker too, every exception was
re-audited against its error paths with one question: can the result
include text produced by an external process, provider or device, or
stored content REA did not author?
Removed from TARGET_CONTENT_FREE_TOOLS:
- close_binary: a failed provider cleanup (GhidraClient cleanup error via
createGhidraDiagnostics) projects the launcher's captured stdout and
stderr, which can contain target-derived log text.
- binary_session: capability status reports runtime unavailability as the
provider error message (ProviderAdapterError and similar), and the
provider candidate and Android availability diagnostics include probe
output such as the apktool stderr excerpt.
- inspect_adb_client: the success result carries the version and
installed path parsed from `adb version` stdout, and a failed probe
keeps a stderr_excerpt.
- inspect_apktool_client: the success result carries the first line of
the launcher's `--version` output, and a failed probe keeps a
stderr_excerpt.
- update_unknown: the new revision carries forward the stored question
and domain, which an imported evidence bundle can supply; list_unknowns
and get_evidence_bundle already return that data marked.
The set now holds only export_evidence_bundle (path, byte and record
counts; failures are filesystem, cancellation, or a fixed integrity
message) and record_unknown (the caller's input plus REA-computed ids
and digests; registry errors project only a reason code).
The conformance test pins the reduced set and asserts each removed tool
is marked. Tests that used binary_session as the unmarked example now use
record_unknown. docs/mcp-contracts.md lists the remaining exceptions and
why the removed tools stay marked.
* fix(contracts): include target-content policy in the catalog identity
createToolCatalog() and CATALOG_IDENTITY.tools projected every
client-visible contract field except returnsTargetContent. Because the
untrusted-content framing left schemas, effects, prompts, CLI names and
the package version unchanged, a same-version MCP process started before
the update digested equal to the new server and binary_session reported
it aligned although it never emits _meta.provenance.
Project the flag as returns_target_content in both the digested tool
catalog and CATALOG_IDENTITY.tools, and export createCatalogDigests so a
boundary test proves that toggling the flag on one tool changes the
tools and combined digests.
URL.search and URL.hash are empty for both a missing component and an explicit empty one, so endpoint and origin checks were accepting URLs the callers meant to reject.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(javascript): bound value evaluation through nested closure aliases
A closure that aliases a binding from its enclosing scope evaluates that
binding once live and once at its own capture point. The capture cannot
order a binding declared in another function, so it fell back to a second
live evaluation. Only primitive results were kept, so every level of
nesting doubled the work: 20 nested closures over a non-constant value
took about 14 s, and a 443 KB generated wrapper reached the 300 s
analysis timeout.
Keep a live binding value when no caller could change it: no alias cycle
closes on or above the binding and the expression depth budget was not
reached. Bindings on a cycle are still re-evaluated, so their values and
reasons are unchanged.
Found while building a source-owned reproduction for #1847; that report's
worker heap exhaustion is a separate, already closed defect.
* fix(javascript): keep the expression depth budget for retained values
Reusing a retained composite value from any depth let a chain of wrappers
(s1 = {x: s0}, s2 = {x: s1}, ...) nest past the expression depth budget:
300 wrappers produced a 299-level value where the budget stops at 86, the
serialized IR grew quadratically, and 3,000 wrappers overflowed the stack
in JSON.stringify.
Record the expression depth at which each caller-independent value was
derived and reuse it only at that depth or shallower. A deeper reader
derives the value again and reaches the budget exactly as before. Closure
aliases read their outer binding at one depth on both paths, so nested
closures stay linear.
inspect_wasm_artifact's configuration-phase error handler assumed every
non-OwnedCommandFailure thrown before the artifact phase was about WABT
tool/directory resolution, and unconditionally appended "Supply WABT 1.0.42
via absolute REA_WABT_BIN_DIRECTORY; REA does not install tools." to the
reason. WabtArtifactProvider.inspect() also allocates its PrivateRuntimeRoot
during the configuration phase, so a PrivateRuntimeRootUnavailableError (the
Windows native-authority capability, unrelated to WABT) got the same false
remediation glued onto its own already-correct message, misdirecting anyone
troubleshooting a correctly-configured WABT install toward re-checking WABT
instead of the real blocker.
Classify PrivateRuntimeRootUnavailableError before the generic
configuration-phase branch, matching the existing convention already used
in JavaScriptAnalysisWorker.ts and SourceMapCommand.ts: surface it as its
own AnalysisCapabilityUnavailableError with no userMessage override, letting
its own message stand.
Verified against a real WABT 1.0.42 Windows release (hash-checked against
GitHub release metadata) and a real compiled .wasm module: before the fix,
`reason` read "REA Windows native controls are unavailable: ENOENT: ...
Supply WABT 1.0.42 ..." even with a fully correct REA_WABT_BIN_DIRECTORY;
after, `reason` reports only the real cause.
* fix(reference): report sloppy scripts, PHP, C# and enclosing Git facts
Importing the source/ subtree of a legacy PHP and C# checkout produced
four wrong or missing facts:
- Babel's unambiguous mode parses a module first and keeps its
strict-mode recovery errors after falling back to a script, so a valid
sloppy-mode `delete messages;` was reported as a parse failure and the
semantic IR marked the file as parser-recovered. Parsing now goes
through one owner that re-parses such a script as a script.
- .php and .cs files had no language; they are now detected as PHP and
C# (detection only, no parsing).
- A root without its own .git was reported as having no version
control even inside a checkout. The adapter now resolves the nearest
enclosing repository, as Git does, and reports `none` only when no
ancestor has one.
- The CLI recorded importer_version as null although the package
version is known.
* fix(reference): keep module strictness and classify C# and PHP as source
Review follow-up. `.mjs` and `.mts` files are modules by extension, but
the script fallback re-parsed them in sloppy mode and erased real
strict-mode errors. The parser boundary now owns the extension rule,
parses explicit modules as modules and applies the fallback only when
the mode is ambiguous; the require-binding analysis uses the same rule.
`.cs` and `.php` received a language but stayed classified as unknown,
so source-to-bundle comparison dropped them. Both are now source
extensions, like the other detected languages.
* fix(reference): honor package module scope and keep unknown-mode strict errors
Review follow-up. A `.js` file under a package.json with `"type":
"module"` is an ES module, but it went through the script fallback that
erases strict-mode errors. The import now reads each in-inventory
package.json and parses `.js` files in a module scope as modules. Other
`.js` and `.ts` sources keep an unknown mode, because bundlers treat them
as modules without that field: they are no longer forced to script, and
errors that only the module parse reports are kept as an entry limitation.
* fix(reference): bound package scopes and keep application parsing unchanged
Review follow-up.
- `.cjs` files parse as scripts, so module-only strict errors no longer
become limitations on CommonJS trees. `.cts` keeps an unknown mode
because TypeScript compiles ES import syntax there.
- An unreadable or linked package.json now bounds the module scope with
an unknown type instead of letting an outer `"type": "module"` apply.
- The application pipeline parses as on main again. Its module-only
strict errors keep a source partial; package-mode handling stays in the
reference importer.
* refactor(reference): keep unmarked module modes unknown instead of resolving package scope
Review follow-up. Resolving Node package scope for `.js` kept pulling in
more of Node's lookup semantics (require bindings, excluded or
directory-named manifests). Only extensions now select a mode: `.mjs`
and `.mts` parse as modules and `.cjs` as scripts. Every other source
keeps an unknown mode, so module-only strict errors stay visible as an
entry limitation instead of being dropped or asserted. This matches the
require-binding analysis, which also treats unmarked paths as unknown.
Carry the source relationship coverage into the synthetic counterpart used by public function comparison and reconstruction verification. Keep missing coverage unresolved rather than weakening comparison completeness.
Keep the ARM64 dossier boundary assertion aligned with caller/callee coverage ownership while preserving unknown coverage, diagnostics, and observed callee assertions.
Validation: recorded IDA protocol and callee relationship boundary tests (22 passed). Live IDA was not exercised.
Decode MZ and Windows signature bytes without ASCII high-bit masking. Move malformed signature cases into the shared Go diagnostics fixtures so provider, compiled CLI, and MCP workflows cover NE, LE, LX, and PE lookalikes; remove the superseded provider-only cases.
Validation: runtime build, check:ci, and focused DOS/Go/target/CLI/MCP tests. Windows-only reference-import cases await CI.
Use the existing pinned cross-spawn dependency at the command-spawn boundary instead of forcing every Windows executable and argument vector through cmd.exe. Preserve native executable arguments while retaining PATH/PATHEXT and command-shim support.
Validation: public runner argv and lock/cancellation tests passed on POSIX. Windows-only tests cover an executable path with spaces, bare node, npm, and the local turbo shim; native Windows execution remains unverified.
Fixes#2319
Resolve each caller-selected Electron path once at the application boundary, collect field-specific failures with original causes, and pass canonical paths directly to the provider. Update direct provider consumers and route the real verifier through the shared application workflow.
Validation: public CLI/MCP invalid-path acceptance, canonicalization boundary, provider tests, and cancellation/cleanup checks. Live Electron launch was not verified. This does not address the separate Playwright launch-rejection crash in #2269.
Fixes#2272
Treat missing, partial, unknown, and unresolved call coverage as insufficient for call-set equality. Combine IDA caller/callee coverage without losing either explanation and recheck source coverage when verifying historical comparisons.
Scope generated function-comparison unknowns with optional typed comparison/dimension facts, preserving legacy IDs and revision digests when absent. Keep unrelated dimensions conclusive, explicit dependencies applicable, and ambiguous function identity unknown. A confirmed change for matched functions remains a failure even if calls are incomplete.
Validation: function/reconstruction/residual-unknown and bundle tests, recorded IDA protocol regression, public MCP comparison/verification, and advertised SDK JSON Schema checks. Real IDA provider execution was not verified.
Fixes#2222
Evaluate stdout and stderr together, giving hard errors and non-ok wait statuses precedence over an attempted Starting line. Retain raw streams and typed partial launch facts when Activity Manager refuses or times out; retain successful raw output too.
Validation: parser/provider tests and public MCP app/activity starts through a fake executable at the real process boundary. Real Android device behavior was not verified; device-reported timeout remains distinct from a host deadline.
Fixes#2225
Identify the factory exports parameter through the existing semantic binding owner, including renamed and minified Webpack parameters. Reject nested targets, bare alias rebinding, and shadowed identifiers. Prune the duplicated source happy path after validating the public CLI workflow.
Validation: public analyze-javascript-application CLI acceptance and focused semantic traversal/module-index tests.
Fixes#2171
Classify FAT containers using shared architecture, range, and observed slice-header facts rather than the CAFEBABE signature alone. Preserve typed unsupported and malformed reasons, reject malformed sibling slices consistently, and remove repeated range parsing in consumers.
Validation: valid small and large JVM classes in public JAR/ZIP inspection, four FAT width/byte-order controls, and focused executable/Mach-O boundary tests. The class fixtures were checked with JDK javap; no new JVM analysis capability is advertised.
The Apple selection and Hopper readers retain their existing parsing because they also own oversized-count diagnostics, reserved fields, streaming final-size validation, or source freshness that the shared header result does not represent.
Representative public mixed-ZIP inventory probe, four fresh processes with an already warm filesystem cache: first process elapsed 626.8 -> 548.3 ms, CPU 740 -> 740 ms, sampled family peak RSS 375.5 -> 345.4 MiB. Subsequent three-process medians: elapsed 767.2 -> 454.0 ms, CPU 890 -> 640 ms, peak RSS 368.7 -> 346.2 MiB. Estimated output tokens 2310 -> 2292. Concurrent load was uncontrolled, so these observations do not establish a speed improvement. Whole-agent task tokens and schema/call overhead were not measured.
Fixes#2317
Skip empty home environment values while preserving nonempty caller selections and platform precedence. Setup, doctor, and uninstall now use the same fallback home instead of writing relative paths in the current directory.
Validation: focused home tests and the public setup/doctor/uninstall lifecycle under Node 24.18. Package verification and pack dry run are included in the integrated gate.
Fixes#2325
Share contextBridge argument ownership between direct and wrapped analysis, seed intact isolated-world calls, and preserve dynamic world IDs and conditional metadata as unknown. Keep callee evaluation scoped to each invocation.
Validation: 99 focused source tests and bundled isolated-world acceptance through dedicated and generic CLI routes. Removed duplicate literal source regression in favor of public workflow coverage. Fixes#2174.
Classify coverage once at inventory production and require it in current outputs. Normalize older retained Evidence at the inventory parser, reject inconsistent page statuses, and remove comparison heuristics over limitation prose.
Validation: public CLI-to-MCP plist comparison, changed-behavior and unknowns workflow; boundary checks for legacy Evidence, partial coverage, page disagreement, content and executable changes; generated docs checks. Fixes#2173.
Select authoritative connection fields by runtime class in a shared owner used by keyed archives and NIBArchive projection. Preserve archive identities, endpoint relationships and coverage, and replace duplicate synthetic outlet assertions with a rooted public CLI fixture.
Validation: compiled CLI acceptance against the issue-sourced rooted UIKit fixture and 41 filesystem tests. Native UIKit framework validation was not rerun. Fixes#2177.
Validate unmapped segment file ranges without adding virtual mappings or fallback metadata addresses. Keep mapped-segment bounds and reject build-info sections declared in unmapped segments.
Validation: real unstripped Go 1.26.5 Darwin arm64 and amd64 artifacts passed CLI/MCP oracle, Evidence, source-range and unchanged-byte checks. Retained malformed-input regressions; removed the weaker synthetic acceptance test. Full cross-platform verifier not run. Fixes#2167.
Observe MZ header declarations and signature uncertainty at the domain boundary, then reuse those facts in bounded target resolution, inventory, and Go PE parsing. Preserve DOS relocation ownership and fail closed when the relevant bytes remain unexamined.
Validation: 59 domain tests, 130 target/Go boundary tests, and public CLI inspection of a clang/lld-link PE DLL with a short DOS header. Fixes#2172.
Inspect selected fields in existing captures through shared CLI/MCP Evidence.
Page matching frames without changing dissection or two-pass read coverage;
retain failed descriptor/process cleanup ownership and reject excess admission.
Verified with real TShark 4.0.17 and 4.2.2, public Wireshark recordings,
owned HTTP application traffic, real CLI/MCP workflows and schema checks.
Co-authored-by: Olorinm <59321404+Olorinm@users.noreply.github.com>
Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
Collect stage and check references at their owning stage boundary before evaluating required checks. Emit one missing-reference finding per stage and Evidence ID, including stages with no supplied checks, while preserving independent failed checks and cross-stage identity. The 21 readiness tests pass.
Normalize empty XDG config homes once for configuration writers and registration readers. Render the resolved plan for terminal dry runs while preserving structured output. Cover registration placement and a real PTY dry run, including absence of configuration writes.
Classify unresolvable and unusable executable or working-directory selections before launch, retaining field paths, attempted candidates and OS diagnostics. Preserve tagged analysis errors through capture lifecycle handling. Replace duplicate missing-path source assertions with public CLI/MCP regression coverage and retain distinct permission, file-kind and PATH checks.
Reuse the immutable domain parser at the file boundary instead of rebuilding and revalidating an already authenticated bundle. Existing filesystem and integrity regressions pass (27 tests); a 4 MiB parsing probe preserves immutable output and reduces repeated validation work.
* test(mcp): fix three MCP boundary suites on native Windows
* test(mcp): report unavailable root symlink coverage as a skip
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Add an explicit attached native IDA MCP compatibility profile while preserving the legacy and headless workflows. Keep recorded input identity, complete source observations and the user's open GUI database. Batch unique callee lookups, conservatively prefilter literal strings, preserve Unicode matching and unavailable caller coverage, and require distinct-function switching in native verification.
Verified with Windows IDA Pro 9.3 and the native MCP plugin built from c9d15d98e8a143fc74f6e14037c48f63889b6d6c with a loopback listener. Production CLI/MCP and an unchanged Windows whoami.exe passed. Windows IDA Free was not used. No personal paths or license registration information are included.
Validation: 200 focused tests, static and documentation checks, architecture guards and discovery passed. Historical same-main warm task measurements improved from 675 to 317 ms; response token estimates fell from 16618 to 11509. Fresh-start, overall CPU and memory improvement were not established. Detailed scope is in experiments/analysis-efficiency/ida-native-windows.md.
Co-authored-by: imissapixel <140405963+imissapixel@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
Add opt-in EVM MCP summary delivery and retained/portable function and text views. Keep existing complete defaults, provider arguments and original full Evidence identities and records usable. Require retention before selected analysis; preserve inferred candidates, nulls, diagnostics, provenance and explicit unknowns.
Verify old schemas, historical Evidence migration, 64 focused feature checks, 30 affected MCP checks after latest-main rebase, 59 real EVM CLI/MCP cases and six shared-domain artifact workflows. Repeated SDK delivery is smaller; all real model trials and mixed token/time outcomes, limitation failures and resource qualification gaps remain documented without a uniform performance claim.
Refs #2016
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
* fix(cli): retain correction details across browser commands
Fold the complementary implementation from #2247 into the earlier #2230 proposal, retaining the original contribution history.
Co-authored-by: LouisChen <3361008+chqcjq@users.noreply.github.com>
* fix(browser): retain diagnostics from the selected input branch
* fix(cli): recognize incomplete browser scenarios by their owned fields
---------
Co-authored-by: LouisChen <3361008+chqcjq@users.noreply.github.com>
Add offline SQLite database/WAL inspection through the shared CLI/MCP.
Use compact inventory, selected-table schema, exact ordered columns and
bounded row samples while preserving source identity and lossless values.
Retain completed Evidence through late cancellation and private-root cleanup
failures, bound concurrent inspections, and recheck journal validity after
acquisition. Reuse prepared CI runtime artifacts across supported Node lines.
Co-authored-by: Y0UW1SH <29498139+Y0UW1SH@users.noreply.github.com>
Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
Reuse the shared safe issue projection for all six CLI validation boundaries
and cover malformed inputs, credential safety, and parser diagnostics.
Fixesmorluto/rea#2180
Developed with assistance from OpenAI Codex.
* fix(apple): join recognized keys from NIBArchive field maps
inspect-asset-catalog returned no resource-key matches for a decoded
NIBArchive resource whose recognized image key is present in the archive. The
NIBArchive projection groups an object's decoded fields under the node's
nibValues attribute beside the class, label and ID it derives from the same
archive, while the AppKit keyed-archive parser flattens the same fields onto
the node. The catalog join read only the top level, so a recognized NSImageName
on a decoded resource produced no row, and the empty-catalog limitation still
claimed resource keys were reported as unmatched.
Read an archive object's fields from both shapes, and give the namespace one
owner by exporting NIB_VALUES_ATTRIBUTE from the projection that writes it.
The recognized-field set stays in the catalog analysis, which owns that
contract.
Verified with 5 focused catalog tests, check:fast and verify:test-discovery on
macOS arm64, and through the public CLI against the reported NIBArchive
fixture. The keyed-archive control keeps its existing row, and a NIBArchive
with only an unrecognized title still produces none. The ibtool-dependent
native hierarchy lane requires full Xcode and was unavailable here.
* fix(apple): normalize resource keys at the NIBArchive producer
Fold the complementary implementation from #2256 into the earlier #2248 proposal, retaining the original contribution history.
Co-authored-by: Thang Luu <76550342+thangldw@users.noreply.github.com>
* fix(apple): restrict catalog joins to parsed resource nodes
---------
Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: Thang Luu <76550342+thangldw@users.noreply.github.com>
Let the fixture lifecycle own CDP readiness with the same 60-second startup deadline as the broader browser verifier. Return the discovered port to both consumers and clean up failed startup before returning a lease.
Validation: five startup/cleanup boundary tests, npm run check, and real Chrome 154 runtime and source-map CLI/MCP verifiers passed on macOS arm64. Hosted Linux verification follows the push.
* fix(adb): count UTF-8 bytes in logcat total_bytes
read_adb_logcat assigned the decoded stdout string's UTF-16 code-unit
length to total_bytes, undercounting non-ASCII dumps (a 37-byte CJK line
reported 33). Measure the UTF-8 byte length instead, matching the field's
byte-unit contract and the repo's Buffer.byteLength convention.
Fixes#2175
* fix(adb): count raw captured bytes in logcat total_bytes
Carry the pre-decode stdout byte length through runAdb so malformed
UTF-8 (replaced by U+FFFD on decode) still reports the true captured
byte count instead of the re-encoded replacement size.
* fix(native): retain failed pwntools process and runtime cleanup
Keep failed worker/debugger cleanup owners and their private files until
verified process shutdown and successful directory removal. Retry cleanup
before another inspection and expose shutdown through the shared services,
CLI and MCP server. Serialize acquisition without delaying cancellation of
queued callers, and preserve primary diagnostics when CLI cleanup fails.
The original decoder reproduction left a live owned Node child with its
runtime deleted and no retained cleanup owner; the regression now verifies
retention, admission blocking, retries and eventual process/file cleanup.
Validation: 10 lifecycle/public CLI/MCP tests, 20 service tests, test
discovery 814/814, build:cached and full check including architecture guards.
Actual POSIX process/filesystem boundaries used injected Node workers on
macOS; real Linux pwntools/GDB provider parsing was not exercised.
* test(native): verify retained recorded-crash cleanup lifecycle
* fix(native): finalize diagnostic cleanup before publishing results
* fix(native): retire decoder stages before reading runtime evidence
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Bind existing EVM CLI/MCP metadata and the legacy service factory through one static descriptor, and register the same selected service that owns cleanup. Preserve original names, schemas, inputs/full defaults, configuration, Evidence and injection identity.
Verified exact SDK catalog/fact parity across six real EVM pairs, 59 actual EVM CLI/MCP cases, six real cross-domain workflows, six actual Codex CLI fact/reference/lifecycle trials and relevant local checks. CI run 38283026233 succeeds for exact head d999d9874b. No token reduction from wiring or fully qualified resource claim; final counters remain unknown. Continues #2016.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Keep static feedback concise while retaining complete diagnostic reports,
visible lint errors, module-boundary checks, and the 3% duplication gate.
Upload complete reports after static failures and restore their outputs
from Turbo caches. Preserve unambiguous, checkout-relative clone locations.
Bind both lint caches to the website, documentation configuration and
experiment sources actually scanned by oxlint, including ignore policy.
Guard this ownership by comparing live checker discovery with resolved
Turbo inputs. A real website syntax error now invalidates a cached pass.
Validation: full current-head CI and the separate Go lane passed. Seven
real-checker regressions passed; failure-status and stale-report mutations
were rejected, and restored source passed. Actual Turbo restored both
reports byte-for-byte; full static/docs/workflow checks passed.
Closes#2238.
Refs #2190.
Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
Set agent tokens and context first, analysis time second, and CPU and memory
third while preserving correctness, Evidence and existing contracts.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
* fix(adb): preserve existing bugreport archives
* fix(adb): retain bugreports after publication failure
Record acquired archive facts before publishing, preserve the staging archive when the exclusive copy fails, and keep retained evidence out of automatic cleanup. Reuse the same observation through publication and digest failures.
Add a real-filesystem ENOSPC regression covering error projection, existing evidence, subsequent collection and provider shutdown. Verified 96 focused tests, static checks and docs on macOS with simulated ADB; no real-device verification.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
observeSettlement classified a group as alive_at_deadline when the settlement
budget expired after one empty observation, though no live member was ever
seen. Track observed liveness and return unverifiable when the deadline ends
observation with only empty rounds. The two-consecutive-empty rule for
quiesced is unchanged, and the cleanup_outcome projection for non-quiesced
settlements stays cleaned.
Fixes#2170.
* feat(ghidra): admit RISC-V ELF analysis through a pinned generic lane
Refs #2063.
Recognize `EM_RISCV` (243) as a provider-neutral family that carries its own ELF
facts, and bound the first Ghidra lane to little-endian `ET_EXEC` images that
declare the double-float ABI, pinned to `RISCV:LE:32:default` or
`RISCV:LE:64:default` with the `gcc` compiler specification.
Ghidra 12.1.4 is not reliable without the pin: its `riscv.opinion` pins
`variant="default"` for the 64-bit constraint and leaves the 32-bit constraint
with the comment that the loader "must choose between 'default' and 'AndeStar'
variants". Measured on the installed release tree, a source-owned generic RV32
ELF with no Andes declaration imports as `RISCV:LE:32:AndeStar_v5:gcc`, while
RV64 resolves to `RISCV:LE:64:default:gcc`. The lane therefore states the
language per width and refuses any caller-selected processor outside it instead
of inheriting the header guess.
Refusals name the declaration rather than falling back to a guessed profile:
big-endian images (Ghidra 12.1.4 ships no big-endian RISC-V language),
non-`ET_EXEC` images, `EF_RISCV_RVE`, `EF_RISCV_TSO`, and every float ABI other
than double, which the pinned generic compiler specifications model. The raw
e_flags bits stay in Evidence as declarations, not as instruction semantics.
Family recognition now has one owner for the ELF-metadata families:
`ELF_METADATA_ARCHITECTURES`, `isElfMetadataArchitecture`, and
`HeaderArchitecture` replace ten `Exclude<BinaryArchitecture, "mips">` sites that
would each have needed a second hand-edited member. `ghidraPinnedLanguage` is
that owner for the import commitment: the session readback previously re-derived
only the MIPS pin, so a profile committing any second pinned language failed with
a language-mismatch error before the bridge started.
Hopper and IDA refuse RISC-V by name, matching the MIPS wording. Caller-supplied
raw-binary entry keeps its existing four-family list; this lane is ELF-header
admission only.
Verification on macOS 15.7.7 arm64, Node 24.18.0, Ghidra 12.1.4 PUBLIC and JDK
21.0.12.1, with the host decompiler built from the release sources for
`os/mac_arm_64`: `npm run check` passes; `npm run test:fast` passes 396 test
files; `npm run verify:test-discovery` discovers all 917 test files exactly once.
Source-owned RV32 and RV64 double-float `ET_EXEC` fixtures complete
`rea analyze --provider ghidra` and `rea decompile rea_riscv_entry`, committing
`RISCV:LE:32:default` and `RISCV:LE:64:default` with `language_selection:
provider-pinned-v1`; the soft-float RV64 shape is refused with the named
float-ABI reason, and the full refusal matrix including the RV32 and
width-mismatch shapes is covered by unit tests. No `verify:ghidra:riscv` lane
script is included in this change; the runs above were performed manually against
the installed engine. Fork pull requests receive no CI check runs, so the
real-provider scope above is the evidence available for review.
* fix(ghidra): bound the RISC-V lane by declared flags and document it
Address review feedback on #2151.
`e_flags` bits outside `EF_RISCV_RVC | EF_RISCV_FLOAT_ABI` are now refused with
the offending value named, so a reserved or newer producer declaration cannot
enter the verified generic lane by falling through the RVE, TSO and float-ABI
checks.
Admission reads `e_type` only, so the refusal text no longer calls `ET_EXEC`
static: a fixed-address declaration does not establish static linkage, and
`PT_INTERP` and dynamic dependencies are not inspected. The session records that
boundary as a limitation rather than inferring a load model.
Add `docs/ghidra-riscv.md` in the shape of the MIPS lane guide (admission
boundary, refusal table, why the language is pinned per class, Evidence fields,
and what the fixtures do not establish), and correct
`docs/firmware-analysis.md`, which still told users that MIPS and RISC-V
decompilation had not been added.
Verification after the change: `npm run check` and `npm run docs:check` pass; the
RISC-V module tests pass (17 lane cases plus 9 parser cases); on Ghidra 12.1.4
with JDK 21.0.12.1 the RV32 and RV64 double-float fixtures still analyze and
decompile with `RISCV:LE:32:default` / `RISCV:LE:64:default` and
`language_selection: provider-pinned-v1`, the soft-float fixture is still refused
by name, and the new linkage limitation appears in the emitted Evidence.
* fix(ghidra): align RISC-V pinning with admission
Reuse the complete lane admission boundary when selecting a language, retain unsigned unsupported flag bits in diagnostics, and derive float ABI metadata from the source declaration.
* test(ghidra): verify RISC-V CLI and MCP workflows
Build source-owned RV32/RV64 fixtures with Clang and LLD, establish independent ELF and symbol facts with LLVM readelf, and verify real provider evidence, instruction bytes, calls, decompilation, schema projections, snapshot replay, refusal diagnostics, source immutability and cleanup.
Verified on macOS ARM64 with Ghidra 12.1.4, JDK 21 and LLVM/LLD 23.1.2. Dynamic linkage, big-endian, Andes and RVE/TSO workflows remain unverified; ISA attributes are not inspected.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Record real Ghidra/MCP and Codex CLI verification of shipped ShareX native PE and FreeDOS DOS MZ entry views. Preserve original Evidence provenance, separate run-specific references from facts, and reject stale/colliding producer identities or unsupported model claims.
Sixteen focused experiment regression cases, original public-reply/transcript replays, and CI run 38273269072 pass for head 0667f7cb7c. No production API/default change or general native speedup claim; final resource counters remain unknown. Continues #2016.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Run the existing README consistency and Python producer guards from their
CI owners. Execute full local validation fresh while preserving cached
preparation, and permit scoped reuse of earlier portable build entries.
Collect failed-shard diagnostics before enforcing success and publish
compact, portable timing history only after a complete successful merge.
Preserve installer truncation failure across supported Bash versions.
Keep cancellation tests focused on the called MCP tool, observe server
progress before timing target readiness, and retain delayed-startup,
cancellation, cleanup, and live follow-up request assertions.
Validation: all 32 CI jobs and the separate Go lane passed; 935 files,
9,630 cases, 9,544 passed, 86 skipped, zero failed. Controlled regressions
and fault/restoration probes are recorded in PR #2210.
Refs #2190.
Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
Report malformed Hermes and DeepSeek Harness documents as YAML. Carry the
compiled setup/uninstall diagnostics coverage from #2153 onto the existing
validation from #2157, including unchanged files and no backup writes.
Add malformed YAML scenarios for both clients.
Validation: 174 focused tests, npm run check, test discovery, package
verification, and npm pack --dry-run.
Co-authored-by: Jax367 <239124526+Jax367@users.noreply.github.com>
Define REA contribution scope and fail closed on unresolved integration boundaries.
Make proposal forms easier to complete with structured choices, explicit unknowns, and optional technical details; welcome exploratory drafts while retaining maintainer review before integration.
* fix(setup): name invalid client config shape errors clearly
Setup was dumping raw Zod issues for non-object roots or server tables,
and uninstall always claimed the file was not valid JSON. Report the
structural problem instead, and reserve parse failures for real syntax errors.
Fixes#2152
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(setup): preserve client configuration record validation
Keep descriptive shape errors while retaining Zod record validation and its own-property copy. Reject tagged YAML objects before setup or uninstall writes and prevent inherited JSONC properties from fabricating client registrations.
Add production-boundary regressions for tagged YAML roots and server tables, plus inherited Cursor and OpenCode settings. All 91 focused tests, npm run check, verify:test-discovery, verify:package, and npm pack --dry-run passed.
---------
Co-authored-by: Beqa Ksovreli <beqa@Beqas-Macbook-Pro-2.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(apple): preflight XML plist nesting before keyed archive decoding
inspect_keyed_archive documented a 128-level nesting limit, but the XML
plist path reached recursive decoding before any depth check: plist and
the prototype-key traversal in parseXmlPropertyList recurse once per
nesting level, so a ~75 KiB, 3000-level XML plist exhausted the call
stack and reported Maximum call stack size exceeded instead of the
bounded-resource limit that shallower over-limit documents (129, 200)
already produced. The CLI classified both as truncated, so no crash or
classification bypass was involved; the diagnostic was the defect.
Reject excessive nesting in parseXmlPropertyList before any recursive
pass, using the projection's own limit (MAX_PLIST_DEPTH) so the error is
identical to the one projectPlistValue raises: callers keep the
limit/truncated classification with no error-handler translation. Depth
counts values the way the projection does - container members nest one
level deeper, dictionary keys name members rather than nesting, and a
self-closing element is the value at its own level - so the guard
rejects exactly the documents the projection rejected, at the same
boundary, and every in-limit document decodes unchanged. The guard sits
at the shared decoder boundary, so Interface Builder, app Info.plist
resolution and native inspect_plist gain the same deterministic limit;
the binary plist path keeps its existing expansion preflight.
Binary plist behavior, ordinary XML decode, __proto__ omission counting,
and archive digest/Evidence provenance are unchanged. OpenStep
autodetection is untouched by this guard, as the existing Interface
Builder preflight also scopes its depth check to XML.
Regression coverage: decoder unit tests at and just past the limit for
dictionary and array nesting with self-closing and opaque markup,
module tests through decodeKeyedArchiveBytes including a valid
NSKeyedArchiver XML envelope at the limit, a production-boundary test
through inspectBundleKeyedArchive, and the compiled public CLI
reporting code truncated / reason limit for a 3000-level plist.
* fix(apple): check XML nesting against parsed element structure
Reuse the iterative XML decoder document for depth preflight and prototype-key lookup. Bound recursive plist wrappers alongside dictionaries and arrays without interpreting markup inside attributes or DOCTYPE declarations as values.
Validated with 104 focused tests including compiled CLI, MCP prototype-key, and Interface Builder coverage; npm run check and verify:test-discovery passed. No real-provider verification was run.
---------
Co-authored-by: Zburgers <Zburgers@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(frida): reject an unreadable script file before starting a session
The shared instrument_with_frida workflow started the Frida session, which
attaches or spawns the target, before the provider read a file script
source. A missing script file then failed loadScript with a bare
invalid_request, and session cleanup resumed the paused spawn, so the
target ran without instrumentation. Check that the selected file is a
readable regular file first and report the path, or access_denied for
EACCES/EPERM, before any device effect.
Fixes#2209
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(frida): let cancellation win over the script file check
An already-aborted request with an unreadable file source returned the
input or access-denied error instead of AnalysisCancelledError. Check the
signal before the script file preflight and again after it, so file
sources keep the existing cancellation semantics.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(frida): keep the pre-start checks out of instrument
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Keep the former native-ui-and-dispatch-investigation fragment after the
page title was changed in #2207. The old and current fragments resolve to
the same heading position in the generated page.
Validation: VitePress production build, generated-document checks, format
and link checks, and real Chrome navigation to both fragments.
Refs #2156.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Frida session lookups, script lookups, unreadable script files and the
instrument-with-frida PID and script checks returned invalid_request with
no issues, while the remediation told callers to correct the listed
arguments. Attach the session_id, script_id, path, target or script issue
with the reason so CLI and MCP callers can see what to fix.
Fixes#2213
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(clients): register Qoder CLI during setup
- SupportedClients: qoder definition (~/.qoder/settings.json, format
json, QODER_CONFIG_DIR override honored)
- Qoder CLI documents mcpServers as the user-scope server table with
command/args/env and stdio as the default transport; no personal
skills directory is documented, so setup skips the skill copy
- tests: qoderClientConfiguration.test.ts (path resolution and
QODER_CONFIG_DIR override, upsert preserving unrelated settings,
fresh/empty configs, uninstall)
Verified: tsc --noEmit clean; vitest run
tests/boundary/filesystem/qoderClientConfiguration.test.ts 6/6.
* fix(clients): install Qoder CLI's personal REA skill
Review follow-up (#1572): the Qoder CLI Skills documentation lists
~/.qoder/skills/{skill-name}/SKILL.md with automatic discovery, so the
definition now carries skillPath following Qoder's configuration
location (QODER_CONFIG_DIR honored) and setup installs the bundled
skill copy there. The installation docs no longer claim Qoder has no
personal skills directory, and the bundled REA skill's supported
client list includes qoder.
Verified: tsc --noEmit clean; vitest run
tests/boundary/filesystem/qoderClientConfiguration.test.ts 7/7.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-12 22:55:55 +08:00
1494 changed files with 170746 additions and 41750 deletions
description:Audit REA CI and test suites for correctness, fixture drift, false passes, and measured performance; use for suite or workflow investigations and efficiency changes, rather than ordinary feature testing or a single test failure.
---
# REA CI and tests audit
Establish which checks still catch real regressions and which costs can be
removed without losing that protection. The outcome may be a verified fix,
an evidence-backed recommendation, or an explicit decision to stop.
Follow the checkout's `AGENTS.md`, [testing guide](../../../docs/development/testing.md),
and [contribution rules](../../../CONTRIBUTING.md). Use their current commands
and pinned toolchain, rather than commands remembered from an earlier audit.
Preserve the requested scope: investigation alone does not authorize edits;
this skill does not grant permission to publish issues, push, or merge. Existing
user authorization still applies. Keep audit notes and raw results outside the
tracked tree, normally in a task-specific `/tmp` directory.
## Establish the executed baseline
Fetch when the user asks for latest main. Pin the baseline SHA and inspected
workflow revision; use an isolated worktree when changing or comparing code.
Do not modify another task's checkout. Record dirty changes and the exact
command, toolchain, host, selected tests, instrumentation, and prerequisites.
An old run is evidence for its executed revision, even if main advances.
description:Reverse engineer native, managed, Electron/JavaScript, packaged, firmware, and browser targets with REA. Use shipped-artifact or requested runtime evidence to explain features, compare versions, decompile code, or guide a reconstruction. Skip REA for ordinary source-repository architecture analysis.
metadata:
version:"40"
version:"41"
---
# REA
@@ -56,43 +56,91 @@ explicit path or endpoint and do not need it.
- Firmware image: `inspect_firmware_regions` when advertised. Use
`extract_firmware` when extraction is requested, with a caller-selected new
absolute output directory. These tools use caller-supplied Binwalk/Unblob on
Linux; see the [firmware guide](https://github.com/morluto/rea/blob/main/docs/firmware-analysis.md).
Linux; see the [firmware guide](https://github.com/morluto/rea/blob/main/docs/guides/firmware/firmware-analysis.md).
segments and provenance. `source_exhaustive: false` means unreturned symbols
may exist.
To see which functions or Objective-C methods a Mach-O actually calls in one
run, use `observe_native_calls` with explicit breakpoints and a bounded
`duration_ms`/`max_events`. It launches a new process under LLDB, so the target
@@ -96,6 +119,8 @@ loaded bytes, file mappings, relocations and the entry against the immutable
snapshot. Keep `mismatch` and `unsupported` explicit. Verified import covers the
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.
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
- label:I understand the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope) must be reviewed before integration; open questions are welcome here.
required:true
- label:This discussion does not include credentials, private samples, or sensitive target data.
required:true
- type:textarea
id:decision
attributes:
label:Decision needed
description:State the exact question maintainers need to resolve.
description:What would you like maintainers to help decide? A short question is enough.
placeholder:Should REA ... or ...?
validations:
required:true
@@ -34,23 +41,57 @@ body:
id:context-evidence
attributes:
label:Context and evidence
description:Explain why the decision is needed now. Separate observed behavior, derived evidence, and inference.
description:Explain the problem or motivation. If you have evidence, distinguish observed behavior from ideas or guesses.
validations:
required:true
- type:dropdown
id:target-interaction
attributes:
label:Expected interaction with targets
description:>-
Select all known effects, including upstream tool behavior. Add "Not sure
yet" if anything is unclear. Use "No target interaction" only on its own.
These selections help discussion and do not establish scope approval.
multiple:true
options:
- Read existing files or captured data
- Launch or attach to a process
- Inject instrumentation or run scripts/code
- Change process memory or registers
- Write or change files/configuration
- Contact network services
- Recover protected code or work around protections
- Notarget interaction (documentation or usability only)
- Not sure yet
validations:
required:true
- type:textarea
id:boundary-invariants
attributes:
label:Boundary and invariants
description:Identify the owning layer, provider/bridge boundary, artifact or evidence invariants, and any process or authorization constraints.
validations:
required:true
label:Boundary details (optional)
description:>-
If known, clarify target selection, selected effects, provider boundaries,
non-goals, or evidence invariants. Leave blank if you need help identifying
them. Do not include private samples or proof-of-authorization documents.
- type:textarea
id:options
attributes:
label:Options and tradeoffs
description:Compare a small number of viable approaches, including platform, compatibility, safety, evidence, and maintenance costs.
description:Optional approaches or tradeoffs. One idea is enough; maintainers can help compare alternatives.
- type:dropdown
id:verification-readiness
attributes:
label:Verification available so far
description:Pick the closest match. An idea without samples or test results is welcome.
options:
- Idea only; I need help defining checks
- I can suggest a sample or manual check
- I have a prototype or observed results
- Not sure yet
validations:
required:true
@@ -58,9 +99,10 @@ body:
id:success-criteria
attributes:
label:Success criteria and open questions
description:State what outcome would settle the decision and list only unresolved questions that could change the choice.
validations:
required:true
description:>-
Optional expected output, sample, possible check, or unresolved question.
A complete test plan is not required to start; maintainers and implementers
will resolve material verification gaps before integration.
- label:I understand the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope) must be reviewed before integration; open questions are welcome here.
required:true
- label:This request does not include credentials, private samples, or sensitive target data.
required:true
- type:dropdown
@@ -36,6 +42,7 @@ body:
- MCP or agent integration
- Documentation
- Other
- Not sure yet
validations:
required:true
@@ -43,7 +50,7 @@ body:
id:current-limitation
attributes:
label:Current limitation
description:What user or agent workflow is blocked, ambiguous, or unnecessarily difficult today?
description:What are you trying to understand or do, and what is difficult today? A short example is enough.
validations:
required:true
@@ -51,23 +58,69 @@ body:
id:use-cases
attributes:
label:Use cases
description:Give concrete applications, targets, callers, or investigation workflows. Explain why current tools are insufficient.
validations:
required:true
description:Optional additional examples of applications, targets, or callers. Leave blank if covered above.
- type:textarea
id:desired-outcome
attributes:
label:Desired outcome and success criteria
description:Describe observable behavior, inputs, outputs, evidence, and compatibility criteria that would make this useful.
description:What would a useful result look like? Describe the output or behavior you want; implementation details are optional.
placeholder:For a selected APK, show whether it is packed and include the detection evidence.
validations:
required:true
- type:dropdown
id:target-interaction
attributes:
label:Expected interaction with targets
description:>-
Select all known effects, including upstream tool behavior. Add "Not sure
yet" if anything is unclear. Use "No target interaction" only on its own.
These selections help discussion and do not establish scope approval.
multiple:true
options:
- Read existing files or captured data
- Launch or attach to a process
- Inject instrumentation or run scripts/code
- Change process memory or registers
- Write or change files/configuration
- Contact network services
- Recover protected code or work around protections
- Notarget interaction (documentation or usability only)
- Not sure yet
validations:
required:true
- type:textarea
id:boundaries
attributes:
label:Authority boundaries and non-goals
description:Call out process execution, target mutation, provider licensing, evidence provenance, supported platforms, and work that should remain out of scope.
label:Target and scope details (optional)
description:>-
If known, name the target/platform, clarify selected effects, or list a
non-goal or scope question. You can leave this blank; maintainers can help.
Do not include private samples or proof-of-authorization documents.
- type:dropdown
id:verification-readiness
attributes:
label:Verification available so far
description:Pick the closest match. An idea without samples or test results is welcome.
options:
- Idea only; I need help defining checks
- I can suggest a sample or manual check
- I have a prototype or observed results
- Not sure yet
validations:
required:true
- type:textarea
id:verification
attributes:
label:Verification details (optional)
description:>-
Share an expected output, a possible check, or existing results if you have
them. Self-owned or appropriately licensed samples can help, but are not
required to open a request. Do not attach private or sensitive data.
@@ -19,17 +19,39 @@ describe the use case and observable outcome. -->
<!-- Explain the chosen approach, why it fits REA's architecture, and what is
intentionally not included. -->
Follow the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope).
Unresolved scope, authority, side effects, or required verification block
integration. Link the required maintainer scope decision for new providers or
capabilities involving target execution, injection, mutation, or protection
recovery; ordinary fixes within existing boundaries may state "not applicable".
Draft PRs may leave the scope decision pending and the final review checklist
unchecked. Maintainers can help resolve open questions.
## Contract and boundary impact
<!-- Complete the applicable lines; use "none" or "not applicable" explicitly. -->
<!-- Short answers are welcome. Complete applicable lines; mark unresolved facts as "unknown".
Use "none" or "not applicable" only when established. -->
- Semantic owner and earliest changed stage:
- Contribution scope fit and linked maintainer decision:
- CLI and MCP/tool-catalog contract:
- Provider, bridge, target-format, or platform compatibility:
- Evidence, artifact, provenance, or reconstruction contract:
-Process execution, authorization, cleanup, or containment impact:
-Target selection, authority, upstream behavior, and cleanup details (if applicable):
- Generated metadata (`docs/public/product-catalog.json`), package, or installation impact (CI generates and validates ignored catalogs and `skills/`; edit authored instructions in `.agents/skills/reverse-engineer-anything/` and never commit build outputs):
Expected effects (check known effects; use documentation-only on its own).
Unchecked items do not establish absence; leave uncertainties visible.
- [ ] Read existing files or captured data.
- [ ] Launch or attach to a process.
- [ ] Inject instrumentation or run scripts/code.
- [ ] Change process memory, registers, files, or configuration.
- [ ] Contact network services.
- [ ] Recover protected code or work around protections.
- [ ] Documentation or usability only; no target interaction.
- [ ] Not sure yet; investigation or maintainer guidance needed.
## Evidence and regression coverage
<!-- State whether evidence is executed, source-derived, or proposed. For fixes,
"_comment":"Test files remain included so the gate measures duplication across both src/ and tests/. The 3.0% limit leaves headroom for ordinary changes while keeping duplication visible.",
REA is a local-only reverse-engineering tool with shared CLI/MCP workflows. Distinguish observations, derivations, inferences, and unknowns; preserve Evidence provenance and session semantics through both adapters. Provider support and setup live in [README.md](README.md#choosing-a-deep-analysis-provider) and its linked guides.
Follow the [contribution scope and fail-closed integration rule](CONTRIBUTING.md#contribution-scope). Do not integrate capabilities while material scope, authority, side-effect, or required verification questions remain unresolved. For new providers or capabilities involving target execution, injection, mutation, or protection recovery, seek the required maintainer scope decision before substantial implementation for integration. Welcome early proposals, small exploratory prototypes, and draft PRs that help resolve questions; they do not authorize integration.
Ghidra uses ephemeral databases without modifying executable bytes or controlling a GUI; Windows Ghidra P0 has no mutation authority. IDA analysis is read-only; never save or close an attached GUI database.
Configuration changes must be additive and idempotent, with backups. Installers must not install or upgrade unrelated software, including Homebrew, Node.js, npm, Java, or Ghidra. Ghidra and IDA are bring-your-own. `rea setup` must show its planned changes and require approval before writing files or installing Hopper.
@@ -12,7 +14,7 @@ Preserve caller-selected inputs and local evidence, including output, URLs, path
## Architecture and Cleanup
Dependencies flow inward: domain semantics and contracts, provider adapters, shared application workflows, then CLI/MCP adapters. Keep engine protocols and provider-specific code out of domain/application layers. See [docs/architecture.mermaid](docs/architecture.mermaid) when changing composition.
Dependencies flow inward: domain semantics and contracts, provider adapters, shared application workflows, then CLI/MCP adapters. Keep engine protocols and provider-specific code out of domain/application layers. See [docs/architecture/architecture.mermaid](docs/architecture/architecture.mermaid) when changing composition.
Give each interpretation and resource a clear owner. Consumers must use that owner's parsed facts rather than reinterpret raw source. Preserve identity, omission, uncertainty, and source evidence across boundaries. Retain ownership of resources whose cleanup failed. Reuse `src/process/` supervision and identity primitives; a PID and executable path alone do not establish ownership after exit or reuse.
@@ -22,12 +24,45 @@ Assess brittleness in touched code during implementation, debugging, review, and
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.
When addressing a review thread, inspect the producing boundary and affected consumers for brittleness. Complete directly related refactoring in the same change. Before resolving the thread, explain the root cause, structural fix, validation, and any remaining cleanup.
Parse unknown boundary values and model expected failures with the tagged error algebra and `Result`. Preserve partial facts and meaningful failure reasons. Keep identity and lookup values separate from display formatting; preserve source values and explicit unknowns when normalization loses information. Absolute paths, file URLs, and HTTP paths have different semantics.
Validate advertised JSON Schemas after SDK conversion against their declared dialect and actual clients. Bind handlers to named contracts with exact types; catalog ordering must never select an operation or schema.
## Performance
Design analysis workflows and agent interfaces for efficiency from the first
compatibility and safe resource bounds remain required.
Optimize in this order:
1. Agent tokens and context. Return the smallest sufficient answer with
necessary provenance, coverage and limitations. Use task selection,
summaries, paging and retained Evidence where supported; honor requested
detail and keep complete Evidence accessible. Count the whole task,
including schemas, extra calls and retries.
2. Analysis time. Reuse validated results and shared work. Cache keys must
cover result-affecting inputs; define invalidation and lifetime. Validate
freshness before reporting cached live state as current.
3. CPU and memory. Avoid unnecessary work and copies; bound concurrency,
retained state and serialization growth.
For changes affecting these costs, measure representative completed tasks and
compare equivalent workflows before and after where available. Report token
usage, elapsed time, CPU time and peak process-family memory. Separate cold
and warm runs, label estimates, and state unmeasured costs. Fewer bytes alone
do not establish fewer tokens or faster analysis.
## Development
Documentation ownership and authoring conventions live in
[docs/development/documentation.md](docs/development/documentation.md). A feature
uses `docs/specs/<domain>/<feature-slug>/spec.md`, one `plan.md` and `tasks.md`;
individual architectural decisions use `docs/adr/<domain>/<decision-slug>.md`.
Consult the [documentation directory](docs/README.md) before adding a guide.
Use [.nvmrc](.nvmrc) and `package.json#packageManager` for the pinned toolchain. Cursor Cloud may place older Node.js first on `PATH`; environment setup installs the pinned toolchain under `/usr/local/bin`.
-`npm ci`: install locked dependencies.
@@ -43,9 +78,9 @@ Use relevant checks for the change. The complete local gate, `npm run check:pr`,
## Tool and Test Changes
For tool design, follow [docs/tool-design.md](docs/tool-design.md): start from the analyst question, reuse existing contracts, preserve caller choices, and return useful evidence inline. Limits must follow real format, protocol, authority, or resource constraints. Account for representation expansion before allocation; derive completeness from examined coverage.
For tool design, follow [docs/development/tool-design.md](docs/development/tool-design.md): start from the analyst question, reuse existing contracts, preserve caller choices, and return useful evidence inline. Limits must follow real format, protocol, authority, or resource constraints. Account for representation expansion before allocation; derive completeness from examined coverage.
For test changes or provider claims, use [docs/testing.md](docs/testing.md). Prefer real public CLI/MCP workflows, then production-boundary integration, then producer goldens. Keep module tests for distinct semantics stronger workflows cannot reliably reproduce. Preserve malformed-input, cancellation, cleanup, permission, capacity, and target-identity coverage when pruning. Report unverified coverage explicitly; simulated providers do not establish real-provider behavior.
For test changes or provider claims, use [docs/development/testing.md](docs/development/testing.md). Prefer real public CLI/MCP workflows, then production-boundary integration, then producer goldens. Keep module tests for distinct semantics stronger workflows cannot reliably reproduce. Preserve malformed-input, cancellation, cleanup, permission, capacity, and target-identity coverage when pruning. Report unverified coverage explicitly; simulated providers do not establish real-provider behavior.
Use Conventional Commit subjects and PR titles. Mark breaking changes with `!` or a `BREAKING CHANGE:` footer. Describe behavior changes, relevant validation, and real-provider verification scope.
@@ -69,7 +69,7 @@ Full contribution record: [336 commits and 163 merged PRs](https://github.com/mo
### ⚠ BREAKING CHANGES
* **captures:** Historical captures without current producer accounting or transaction identity, and web diffs missing accessibility or storage dimensions, are rejected. Preserve original captures and recapture with the current producer; update comparison consumers to include every dimension rather than synthesizing missing observations. See the [process capture guide](docs/process-capture.md) and [browser scenario contract](docs/browser-scenario-contract.md). ([3283a45](https://github.com/morluto/rea/commit/3283a45d09457c79e3adadb50a48620926d4bc5b))
* **captures:** Historical captures without current producer accounting or transaction identity, and web diffs missing accessibility or storage dimensions, are rejected. Preserve original captures and recapture with the current producer; update comparison consumers to include every dimension rather than synthesizing missing observations. See the [process capture guide](docs/guides/runtime/process-capture.md) and [browser scenario contract](docs/guides/web/browser-scenario-contract.md). ([3283a45](https://github.com/morluto/rea/commit/3283a45d09457c79e3adadb50a48620926d4bc5b))
* **browser:** JSON shape paths now contain typed property and array-element segments. WebMCP input_schema_shape is replaced by input_schema and input_schema_sha256, retaining declared examples and defaults.
* **process:** Filesystem digest omission entries now require system_code; budget and changed-file omissions use null, and unavailable-file omissions preserve the operating-system error code.
* **contracts:** Provider analysis outputs must explicitly supply metadata previously repaired with defaults; unsupported nullable facets must be reported as null.
@@ -237,7 +237,7 @@ Full contribution record: [336 commits and 163 merged PRs](https://github.com/mo
### ⚠ BREAKING CHANGES
Read the [6.1 to 6.2 migration guide](docs/migration-6.2.md) before upgrading. REA's `always-bump-minor` policy includes breaking changes; 6.2 is not a backward-compatibility promise. Preserve original saved files and regenerate missing observations rather than fabricating identities or facts.
Read the [6.1 to 6.2 migration guide](docs/migrations/migration-6.2.md) before upgrading. REA's `always-bump-minor` policy includes breaking changes; 6.2 is not a backward-compatibility promise. Preserve original saved files and regenerate missing observations rather than fabricating identities or facts.
* **MCP / Evidence / snapshots / artifacts:** Success results are direct canonical Evidence; read `normalized_result` rather than the old `result`/`evidence` wrapper. Evidence requires nullable `analysis_profile`, session provider aliases are removed, snapshots require complete profile-bound query records, and artifact roles/permissions belong to occurrences. Recreate incompatible saved data; adding fields without recomputing their semantic identity is invalid. ([63bf914](https://github.com/morluto/rea/commit/63bf91405cf97b114a84f337fb1272d98a267999))
* **Process captures:** Legacy v3 conversion is removed. Explicit executable identity and `event_journal` are required; retain old captures and recapture when current comparisons are needed instead of inventing launch identity or event order. ([2a77469](https://github.com/morluto/rea/commit/2a7746998d47446c4db6d4f524e0f183d6803f3f))
@@ -11,20 +11,120 @@ incorrect user instructions warrant standalone corrections. Collect other
cosmetic-only suggestions in an issue rather than separate PRs.
For capability organization and provider composition, use the
[architecture map](docs/architecture.mermaid). Production factories in
[architecture map](docs/architecture/architecture.mermaid). Production factories in
`src/composition/` construct fresh providers without starting engines or acquiring
targets; optional adapter failures must preserve successful peers. Run
`npm run verify:test-discovery` after adding or moving tests. Resolved import
boundaries are checked by `npm run verify:module-boundaries`, included in lint.
When adding or changing an MCP tool, follow the [tool design guide](docs/tool-design.md) and preserve the canonical contracts and generated catalog.
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.
When adding or changing an MCP tool, follow the [tool design guide](docs/development/tool-design.md) and preserve the canonical contracts and generated catalog.
## Contribution scope
REA focuses on software structure, runtime behavior, and evidence through
general-purpose reverse-engineering workflows. Evaluate a proposal by its actual
capabilities, side effects, defaults, and complete workflow. A tool name or a
reference to vulnerability research, malware analysis, or CTFs does not determine
whether it belongs in REA.
Supported contributions include format inspection, ordinary archive and standard
compression extraction, disassembly, decompilation, cross-references, general
static deobfuscation, vulnerability analysis, and evidence reporting. Static
protection detection is distinct from defeating that protection. Security fixes
and isolated regression tests remain in scope.
Runtime investigation needs explicit boundaries. Launching or attaching to a
process, injecting instrumentation, running scripts, and changing memory or
registers require review of target selection, execution and mutation authority,
provenance, resource limits, cancellation, and cleanup. General Frida or debugger
support is not inherently read-only, and existing support does not authorize
every workflow built on it. General-purpose interfaces are not classified as
dedicated bypass workflows solely because caller-provided code could be misused;
their execution and mutation authority must still be reviewed.
REA does not integrate or officially distribute:
- Purpose-built workflows to defeat commercial packing or code-virtualization
protections and automatically recover protected code.
- Anti-debugging or anti-instrumentation evasion, or DRM, license, anti-cheat, or
access-control bypass workflows.
- Exploit or attack-payload automation, credential theft, covert persistence,
unauthorized access, or bulk attack workflows.
These boundaries apply to first-party providers, adapters, plugins, bundled
scripts, defaults, examples, and documentation. Moving a capability into an
optional dependency or plugin does not exempt it. Review what the integration
exposes, including upstream defaults and raw-command or script execution paths.
Ordinary extraction and general static deobfuscation are not excluded merely
because the input is packed or obfuscated; assess added bypass or execution
behavior separately.
This is a product and maintenance boundary, not a judgment about a contributor's
intentions or a declaration that all excluded research is unlawful. Contributors
must have the rights and authorization needed for their work. A local-only design
or an "authorized use only" disclaimer does not establish containment or settle
legal and scope questions.
### Fail-closed integration
If scope fit, target or authorization boundaries, side effects, or the verification
needed to establish those boundaries remain materially unresolved, **do not merge,
enable, or include the capability in official packages or distributions**. Keep
the proposal pending, narrow it, or decline it. Record unknowns explicitly; do not
turn them into "none" or assumed safety. Passing CI, completed implementation,
upstream popularity, or silence from maintainers is not scope approval.
For a new provider or a capability involving target execution, injection,
mutation, or protection recovery, seek an explicit maintainer scope decision in
the linked issue or design discussion before substantial implementation intended
for integration. Small exploratory prototypes and draft PRs may help inform that
decision; they do not authorize integration. The decision must cover the final
proposed behavior; a scope expansion needs a new decision. Routine fixes and
documentation changes within existing boundaries do not need a separate advance
decision, but must not silently expand those boundaries.
### Starting a proposal
To open a feature request or design discussion, describe the problem and desired
outcome or decision. Short answers and the forms' "Not sure yet" options are
welcome. You do not need code, a complete design or test plan, legal analysis, or
private proof-of-authorization documents to start a discussion. Share what you
know and leave optional details blank when you need help.
Form selections guide triage; they are not proof of authorization or scope
approval. Unselected effects must not be treated as established absence.
Maintainers and implementers work together to resolve the following before
integration:
- The concrete analyst question, requested inputs and outputs, and why existing
REA operations are insufficient.
- Why the workflow fits this scope, its non-goals, and any protection recovery,
bypass, or attack automation it would expose.
- The selected targets and every execution, injection, mutation, network, or
persistence effect, including behavior inherited from upstream tools.
- How the boundaries and outcome will be verified with self-owned or appropriately
licensed samples; identify real CLI/MCP and provider coverage, cleanup and
resource checks, and remaining unknowns. Do not publish private binaries,
credentials, or sensitive target data; follow [SECURITY.md](SECURITY.md) for
private vulnerability reports.
Mixed proposals should separate acceptable analysis capabilities from excluded
workflows so each can be decided independently. An issue may discuss unresolved
questions; opening an issue or PR does not authorize integration. This is a
maintainer integration gate, not a per-call confirmation requirement or a sandbox
guarantee.
## Development setup
Use the development toolchain pinned in `.nvmrc` and
`package.json#packageManager`. Run `nvm use` before installing dependencies;
installed-package runtime support is documented in
| Native binaries | Pseudocode, assembly, strings, symbols, calls and references | Hopper, Ghidra or IDA; [native analysis](https://rea.tools/guides/native/) |
| Offline ELF layout | Sections, segments, original symbols/relocations and static mitigation candidates | Caller-supplied pwntools on Linux x64; [binary diagnostics](docs/binary-diagnostics.md) |
| Go binaries | Embedded compiler version, modules, replacements and build settings | Built-in static ELF/PE/thin Mach-O inspection; no Go installation required |
| WASM artifact | Validation, sections, exact import/export WAT forms and decoded WAT | Caller-supplied WABT 1.0.42; `inspect_wasm_artifact` |
| EVM bytecode | Dispatch selectors, byte offsets, inferred arguments and mutability | Local raw/hex carrier on Linux x64; [offline EVM guide](docs/evm-bytecode.md) |
| Recorded Linux crashes | Raw notes, every recorded thread's registers/signals and optional mapping candidates | Caller-supplied pwntools on Linux x64; optional GDB/pwndbg; [recorded crashes](docs/recorded-crashes.md) |
| JavaScript / Electron | Modules, imports, source maps, routes, IPC and native add-on relationships | Node.js and npm; [application analysis](https://rea.tools/guides/javascript/) |
| Websites | Page structure, scripts, network observations and requested screenshots | A Chrome-family browser; [browser analysis](https://rea.tools/guides/browser/) |
| Saved network captures | Requests, responses, exposed payloads and source locations | HAR; mitmdump on Linux for native mitmproxy captures; [capture guide](docs/web-network-captures.md) |
| Android APKs | Manifest declarations, classes, decompiled methods and references | Headless JADX and a full JDK on Linux/macOS/Windows x64; [Android guide](docs/android-analysis.md) |
| JEB projects | Engine-backed project units, artifact digests and type/method pseudo-code | A caller-started JEB client serving MCP, selected with REA_JEB_MCP_URL; [JEB guide](docs/jeb-analysis.md) |
| Android resources | Decoded manifest, string tables, locales and version facts | Caller-supplied Apktool launcher; [resource guide](docs/apktool-resource-analysis.md) |
| Firmware | Regions, extraction results and native-analysis handoffs | Binwalk / Unblob on Linux; [firmware guide](docs/firmware-analysis.md) |
| Packages and resources | File inventories, digests, plists, Apple bundle anatomy and extracted resources | [Artifact and JavaScript guide](docs/javascript-artifact-reconstruction.md), [Apple applications](docs/apple-application-analysis.md) |
| Process behavior | Terminal output, interactions, exit and filesystem observations, and run comparisons | Linux/macOS with a native PTY; [process capture](docs/process-capture.md) |
| Target | What REA returns | Requirements and guide |
| Native binaries | Pseudocode, assembly, strings, symbols, calls and references | Hopper, Ghidra or IDA; [native analysis](https://rea.tools/guides/native/) |
| Offline ELF layout | Sections, segments, original symbols/relocations and static mitigation candidates | Caller-supplied pwntools on Linux x64; [binary diagnostics](docs/guides/native/binary-diagnostics.md) |
| Go binaries | Embedded compiler version, modules, replacements and build settings | Built-in static ELF/PE/thin Mach-O inspection; no Go installation required |
| WASM artifact | Validation, sections, exact import/export WAT forms and decoded WAT | Caller-supplied WABT 1.0.42; `inspect_wasm_artifact`|
| EVM bytecode | Dispatch selectors, byte offsets, inferred arguments and mutability | Local raw/hex carrier on Linux x64; [offline EVM guide](docs/guides/evm/evm-bytecode.md) |
| SQLite databases | Tables, columns, indexes, views, triggers and selected ordinary-table rows | Local database/WAL snapshot; Node.js 24.x >=24.15 or 26+ with native SQLite limits |
| Recorded Linux crashes | Raw notes, every recorded thread's registers/signals and optional mapping candidates | Caller-supplied pwntools on Linux x64; optional GDB/pwndbg; [recorded crashes](docs/guides/native/recorded-crashes.md) |
| JavaScript / Electron | Modules, imports, source maps, routes, IPC and native add-on relationships | Node.js and npm; [application analysis](https://rea.tools/guides/javascript/) |
| Websites | Page structure, scripts, network observations and requested screenshots | A Chrome-family browser; [browser analysis](https://rea.tools/guides/browser/) |
| Saved network captures | Requests, responses, exposed payloads and source locations | HAR or Fiddler Everywhere SAZ; mitmdump on Linux for native mitmproxy; [capture guide](docs/guides/web/web-network-captures.md) |
| Android APKs | Manifest declarations, classes, decompiled methods and references | Headless JADX and a full JDK on Linux/macOS/Windows x64; [Android guide](docs/guides/android/android-analysis.md) |
| JEB projects | Engine-backed project units, artifact digests and type/method pseudo-code | A caller-started JEB client serving MCP, selected with REA_JEB_MCP_URL; [JEB guide](docs/providers/jeb-analysis.md) |
| Android resources | Decoded manifest, string tables, locales and version facts | Caller-supplied Apktool launcher; [resource guide](docs/guides/android/apktool-resource-analysis.md) |
| Packet summaries | Endpoints, DNS, TLS SNI, protocol distribution and HTTP requests | Caller-supplied tshark and capinfos (Linux-verified); [pcap guide](docs/guides/data/pcap-analysis.md) |
| Recorded logic signals | Decoder annotations, sample ranges and diagnostics | Linux: sigrok-cli 0.7.2 + prlimit; [signal recordings](docs/guides/signals/signal-recordings.md) |
| Packages and resources | File inventories, digests, plists, Apple bundle anatomy and extracted resources | [Artifact and JavaScript guide](docs/guides/javascript/javascript-artifact-reconstruction.md), [Apple applications](docs/guides/apple/apple-application-analysis.md) |
| Process behavior | Terminal output, interactions, exit and filesystem observations, and run comparisons | Linux/macOS with a native PTY; [process capture](docs/guides/runtime/process-capture.md) |
Static JavaScript and .NET inspection read the supplied files without running
the application. Runtime capture runs or interacts with the selected target
@@ -178,14 +182,14 @@ using your user permissions; each runtime guide describes its effects.
<a id="choosing-a-deep-analysis-provider"></a>
Native formats and host support vary by provider. See
[Hopper and Ghidra setup](docs/installation.md#hopper), the
[IDA guide](docs/ida-provider.md), and
[experimental Windows Ghidra support](docs/windows-ghidra-p0.md).
Ghidra also supports [16-bit DOS analysis](docs/ghidra-dos.md).
[Hopper and Ghidra setup](docs/getting-started/installation.md#hopper), the
[IDA guide](docs/providers/ida-provider.md) (including an optional native MCP bridge), and
[experimental Windows Ghidra support](docs/providers/windows-ghidra-p0.md).
Ghidra also supports [16-bit DOS analysis](docs/providers/ghidra-dos.md).
For large binaries, raise the provider's startup deadline with
`REA_GHIDRA_STARTUP_TIMEOUT_MS` or `REA_HOPPER_STARTUP_TIMEOUT_MS`.
For provider selection, see the [CLI guide](docs/cli.md#choose-a-provider).
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 references to an exact class or unique method; source lines are unresolved.";
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.";
@@ -1252,6 +1549,20 @@ public final class ReaGhidraBridge extends HeadlessScript {
limitations.add(
"Synthetic Ghidra entry-point references without actionable memory sources are omitted."
);
if(swift&&aarch64){
limitations.add(
"Swift String literals are decoded from constant register pairs at calls, returns and paired stores; literals stored one word at a time, chosen by conditional selects, passed through unresolved jumps, or built at runtime are not reported."
);
if(swiftLiterals.omissions().size()>0){
limitations.add(
"Swift String literal records listed in swift_string_literal_omissions could not be retained or decoded within this dossier's remaining heap budget; later symbolic flows remain unexamined."
);
}
}elseif(swift){
limitations.add(
"Swift String literal decoding is implemented for AArch64 register pairs only; no Swift literals were decoded for this architecture."
". Choose an observed analysis address. CLI: rea search <path> . --kind procedures --mode regex --provider ghidra --json; "+
"MCP: list_procedures. Inspect the loaded base and source mappings with CLI rea analyze <path> --provider ghidra --json "+
"and rea inspect-native-load-image <path> --provider ghidra --json, or MCP binary_overview and inspect_native_load_image. "+
"Repeat the original target options. For decompile, select source coordinates explicitly with --file-offset=0x... or MCP procedure file-offset:0x....");
# Other declared OSABIs must never select Linux note ctypes.
ifcontent[7]notin(0,3)orcontent[8]!=0:
raiseCoreFailure("unsupported-target","Initial recorded-core profile requires System V or GNU/Linux OSABI with ABI version zero; selected OSABI="+str(content[7])+", ABI version="+str(content[8])+".")
"limitations":["The initial Linux note profile accepts System V/unspecified or GNU/Linux OSABI with ABI version zero; an unspecified OSABI alone does not prove operating-system origin.",
Source projects also contain large capacity regressions; `test:fast` promises
no compiled-runtime prerequisite, not a fixed time budget.
`npm run lint` prints errors and a warning summary; `npm run jscpd` prints
duplication statistics. Complete reports remain in `.cache/static-checks/` and
CI uploads them as `static-check-reports`, including after a failed static gate.
Use `npm run lint:details` or `npm run jscpd:details` for all console diagnostics.
Both duplicate commands scan production and test code with the same 3% limit;
the summary commands preserve checker failures and restore reports from cached
static tasks. Both lint caches include the website, documentation configuration,
and experiment code scanned by the checker; a regression compares the actual
lint inventory with Turbo's resolved inputs.
Routine iterations and rebases need focused regressions and relevant checks.
Before handing off a PR, run `npm run check` and generated-document checks when
applicable; CI owns the full suite and coverage. Use the full local gate for
@@ -97,6 +108,12 @@ runner. Preserve simultaneous launches where concurrency is itself under test.
Build/documentation writers hold checkout-local output locks. Tests do not
hold a broad command lock; `check:pr` finishes tests before document validation.
Turbo caches deterministic preparation and static checks, but `test:run` always
executes. Repository files do not fully describe installed tool contents or host
state. A previous test pass therefore cannot replace current validation, even
when the source tree is unchanged. `check:pr` also runs the fast Python producer
suite; CI runs it in the static job for code changes. These producer tests do not
establish real LLDB engine coverage.
Vitest's persistent compile cache remains disabled. The `cliTest` fixture shares
a temporary Node compile cache among its fresh CLI subprocesses. The worker
@@ -220,7 +237,7 @@ logic.
reconstruction, native-boundary relationships and application graphs without
executing fixture PE files. Operator-local manifests and actual ILSpy oracles
remain optional, separately reported checks; the real Ghidra NativeAOT lane has
its own toolchain prerequisites. See [the managed guide](managed-code-analysis.md)
its own toolchain prerequisites. See [the managed guide](../guides/managed/managed-code-analysis.md)
for those configurations. Generated completion-ledger checks use the same owning
entrypoint and include its verifier/fixture files in their cache inputs.
@@ -246,18 +263,71 @@ CI owns coverage; aggregate and domain/contract thresholds are maintained in
Coverage does not replace named boundary or real-provider scenarios.
CI runs six native Vitest shards without retries. Each shard emits a blob
report; the merge job produces aggregate coverage plus JUnit and JSON timing
reports, uploads them together, and writes the slowest files to the workflow
summary. Static checks, documentation, build, package verification, and
report; the merge job produces JUnit and JSON diagnostics, a module timing
report, plus aggregate coverage during full qualification. It retains available
reports even when a shard fails, uploads available diagnostics, and writes the
slowest files to the workflow summary. Partial reports are marked diagnostic
only. Failed, cancelled, or missing selected shards still fail the required gate,
and aggregate coverage thresholds remain enforced in full qualification.
Only successful complete full-tier merges publish the small `test-timings` artifact, with
checkout-relative paths; the build job downloads that artifact for the sequencer
instead of the coverage/JUnit bundle. Timing weights come from Vitest module
diagnostics and include tests and hooks, worker preparation, environment,
imports, and setup. Import timings already include transform waits, which are
not added again. The weights describe file costs under the measured worker and
coverage settings; their sum is not workflow elapsed time. The diagnostic
artifact retains the phase breakdown, while shard history keeps only each
file's total. Legacy test-body-only history and missing history fall back to native
sharding. Static checks, documentation, build, package verification, and
real-system lanes remain separate jobs so one kind of evidence cannot stand in
for another.
for another. Workflow syntax and expression validation runs inside the required
static-check job when workflow changes select it, avoiding a separate runner.
Native, provider, fixture, SQLite compatibility, and website lanes wait for
static checks to succeed before allocating their runners. This avoids spending
those runner slots on revisions that already fail static validation. Portable
test shards and documentation checks remain independent of static results, so
they can still provide diagnostic feedback. The required gate rejects skipped
selected lanes when static checks fail; passing revisions retain all selected
coverage. This ordering reduces peak demand on invalid revisions but can add
static-check waiting to otherwise passing runs; it is not a measured reduction
in end-to-end latency.
Core jobs have execution limits of five minutes for classification, ten minutes
for static checks, builds, docs, and report merging, and thirty minutes per
portable test shard. These limits leave headroom for cold setup and full coverage
while preventing a hung job from holding the active main run for hours. They do
not bound runner queue waiting. Timeouts still fail the required gate.
The separate `CI timings` workflow batches recent completed CI and Release runs
hourly or on manual dispatch. It uploads `ci-job-timings-batch` with raw API pages and
a normalized point-in-time report for each collected workflow attempt, plus a
batch manifest describing examined coverage, failures, and limits. Overlapping
lookback windows may collect an attempt again; identify records by run ID and
attempt. Each batch examines at most 100 completed runs per workflow created in
the preceding 24 hours, with a four-minute API collection budget. It collects the
latest attempt of each selected run and does not claim an exhaustive archive.
It runs the reporter from the trusted default branch with read-only permissions,
treating workflow runs as API data. It does not allocate a new reporter job for
every completed, cancelled, or skipped workflow. Reports separate queue
waiting (`created_at` to `started_at`) from completed execution and report
percentiles plus matched `npm ci` and artifact-step durations.
Queue excludes dependency waiting before job creation and does not establish
whether account concurrency or runner availability caused the wait. Queued jobs with
placeholder start times, skipped jobs, and missing or invalid timestamps remain
unknown. The reporter targets each selected run and attempt explicitly.
Summed job elapsed time is parallel work, not workflow wall time, CPU time,
memory usage, or billing. Step names identify samples, not complete transfer
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 restore this cache without waiting for the build job. The shared action
derives its key from `test:prepare --dry=json` task hashes, runner OS and
architecture, and`.npmrc`; test-only changes can reuse compiled outputs. Every
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
rebuilds misses. There is no prefix fallback to accumulate older build outputs.
rebuilds misses. A restore prefix with the same platform and toolchain permits
partial task reuse when one generator's inputs change; Turbo still invalidates
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
@@ -266,9 +336,10 @@ commands, which restore matching outputs or rebuild on a cache miss. Native
artifacts, dependency installs, package archives, and runtime verification remain
host-local. Keep platform-dependent outputs out of this shared cache.
The PR acceptance target is a median `npm run check:pr` wall time below three
minutes across three warm-build runs on the benchmark host. Keep Vitest caches
cold unless separately identified. A PR that touches packaging or real-system
Record cold and warm preparation separately from fresh test execution when
benchmarking the optional `npm run check:pr` gate. Compare multiple runs on the
same host, including subprocess and queue costs; a cached pass is not a test
runtime measurement. A PR that touches packaging or real-system
behavior requires the applicable `verify:*` lanes; packaging and installation
changes also require `npm run verify:package`. The full-gate benchmark measures
that explicit lane, not the routine iteration requirement.
@@ -292,6 +363,7 @@ prove behavior on the verified Ghidra 12.1.4 and JDK 21 build.
| `npm run verify:ghidra` | Linux x64/arm64 ELF or macOS x64/arm64 Mach-O | Host C compiler, Ghidra 12.1.4, and full JDK 21 |
| `npm run verify:ghidra:seeds` | POSIX; raw x86 fixture; seed ordering, BSS labels, analyzer readback and unknown-name rejection | Ghidra 12.1.4 and full JDK 21 |
| `npm run verify:ghidra:swift` | macOS x64/arm64 Mach-O | Host Swift compiler, Ghidra 12.1.4, and full JDK 21 |
| `npm run verify:ghidra:riscv` | Linux/macOS x64/arm64 host; source-owned RV32/RV64 ELF through CLI and MCP | RISC-V Clang, LLD, LLVM readelf, Ghidra 12.1.4, and full JDK 21 |
| `npm run verify:ghidra:switch` | Linux x64 ELF; GCC/Clang optimized and stripped switch fixtures | GCC, Clang, GNU nm/objdump/strip, Ghidra 12.1.4, and full JDK 21 |
| `npm run verify:ghidra:aarch64-jump-table` | Any supported Ghidra host; AArch64 ELF; signed/unsigned byte/halfword tables; host ARM64 Mach-O | Clang with AArch64 target support, Ghidra 12.1.4, and full JDK 21 |
| `npm run verify:ghidra:cross-format` | Any supported Ghidra host; also analyzes AArch64 ELF, x86-64 PE, and x86-64 Mach-O | `clang`, LLD, and `lld-link` in addition to host-lane prerequisites |
@@ -442,14 +514,14 @@ fixed public ApiDemos v6.0.18 fixture. Obtain both with the explicit
kept under ignored `_reference/`. No Gradle build, Android SDK, emulator or
application execution is required. The lane compares real CLI/MCP package,
class search, class inventory, method decompilation and incoming references.
See [Android analysis](android-analysis.md) for boundaries and resource budgets.
See [Android analysis](../guides/android/android-analysis.md) for boundaries and resource budgets.
`verify:jeb` requires a caller-started JEB client serving MCP at
`REA_JEB_MCP_URL` (default `http://127.0.0.1:8425/mcp`) with a project
already open, and verifies real CLI client inspection, unit listing coverage,
and method decompilation. The script records the engine's exact response to
`open_jeb_project`; JEB 5.48.0 headless instances do not advertise that tool.
REA does not install or launch JEB; see [JEB analysis](jeb-analysis.md) for
REA does not install or launch JEB; see [JEB analysis](../providers/jeb-analysis.md) for
the bring-your-own boundary. Verified against JEB 5.48.0 serving
`jeb-mcp-server` 1.3.0 at four scales: a compiled Java class fixture, a
locally built signed probe APK with a launcher activity (manifest, v1/v2/v3
@@ -463,7 +535,7 @@ CLI and MCP with explicit unit selection, plus the thin Java wrapper and
decoded manifest. The dedicated Dart snapshot processor and `run_script`
remain GUI-only surfaces in JEB 5.48.0 headless.
Authenticated IPA and macOS application inventory projection is documented in
input, original-input preservation, and lifecycle cleanup. For headless
input, original-input preservation, and lifecycle cleanup. The headless
profile also checks containing procedures, the admitted program as the
document, address context, and feature tracing. For headless
analysis it confirms that the owned database IDs disappear from upstream
discovery and private workspaces are removed. For attached analysis it confirms
the existing GUI target remains reachable with the same input identity.
@@ -630,7 +711,11 @@ symbols carry a leading underscore). Before the headless session waited out
the transient `busy` health a worker can report right after opening, that lane
failed intermittently on that host. Linux headless, modern attached GUI tools,
other engine versions and architectures remain unverified; see the
[provider guide](ida-provider.md).
[provider guide](../providers/ida-provider.md).
Native IDA MCP verification uses `"protocol": "native"` with an already-running native plugin and requires `--second-procedure other_function --second-marker unique_second_body_text` to exercise GUI function switching and a return to the first function. These options remain optional for other profiles. The literal marker must appear in the second function's pseudocode and be absent from the first. Native cloud/widget failures are reported without hidden retries.
The initial Linux x64 IDA Free 9.4 run used native MCP 1.1.2 with a local navigation correction. Windows x64 verification uses **IDA Pro 9.3**, the two-function public fixture, and the shipped Windows `whoami.exe` application. The native plugin was built from upstream `c9d15d98e8a143fc74f6e14037c48f63889b6d6c`, including the merged navigation fix, with a local loopback-listener change. Production CLI/MCP parity, switching, identity and cleanup passed. Correctness and performance measurements are recorded in the [Windows native verification notes](https://github.com/morluto/rea/blob/main/experiments/analysis-efficiency/ida-native-windows.md). Stock 1.1.2 switching, native macOS, and Windows IDA Free remain unverified. See the [native bridge prerequisites](../providers/ida-provider.md#optional-native-ida-mcp-bridge).
@@ -98,11 +98,13 @@ section, symbol, mitigation or linkage views. The default `complete` detail and
CLI output are unchanged.
Complete results have a 32 MiB input, 64 MiB reply, 1 MiB combined diagnostics
and 30-second owned command deadline. The reply budget applies to the decoder
record; the CLI/MCP Evidence envelope adds copies and encoding overhead. The
and 30-second owned command deadline. `REA_PWNTOOLS_MAX_INPUT_BYTES` raises the
input bound alone, up to 1 GiB; the reply and deadline bounds are unchanged. The
reply budget applies to the decoder record; the CLI/MCP Evidence envelope adds
copies and encoding overhead. The
pinned MCP SDK defaults to a 10 MiB receive buffer. Large complete results need
a caller-configured `StdioClientTransport({ maxBufferSize: ... })` and a matching
server `REA_MCP_MAX_RESPONSE_BYTES`. See [MCP delivery budgets](mcp-contracts.md#tool-results).
server `REA_MCP_MAX_RESPONSE_BYTES`. See [MCP delivery budgets](../../reference/mcp-contracts.md#tool-results).
These settings affect delivery, not decoder coverage or limits. The large
extended-index verification uses 256 MiB and an explicit five-minute request
timeout in its separate opt-in MCP lane. REA does not silently truncate the result. Python lowers resource soft limits to at most 3 GiB virtual address space,
@@ -8,6 +8,10 @@ exported script's native imports under an explicit URL/import-map context.
REA can attach to a user-owned Chrome-family browser through the Chrome DevTools Protocol (CDP) and produce bounded Evidence about an existing page. This is a passive reverse-engineering capability, not a general browser automation or remote-control surface.
For request/response bodies and traffic debugging, see
[Fiddler Everywhere captures and MCP](web-network-captures.md#reading-fiddler-captures-saz).
Inspect native SAZ or HAR 1.2 offline with REA, or connect Everywhere's separate MCP server.
## Shipped surfaces
- `list_browser_targets` / `rea list-browser-targets` discovers all eligible page targets at the endpoint by default, with an optional exact-origin filter.
@@ -47,7 +51,7 @@ Caller-owned JSON/base64 strings, input parsing and validation, transport
buffers, garbage-collector behavior, and other runtime memory are outside this
estimate; the budget does not promise a bound on total process memory.
Electron `file://` pages use a separate provider and target boundary; see [electron-observation.md](electron-observation.md).
Electron `file://` pages use a separate provider and target boundary; see [electron-observation.md](../javascript/electron-observation.md).
## Provider authorities
@@ -61,7 +65,7 @@ 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
REA does not launch, own, or terminate this browser. Use a dedicated profile and stop it yourself when the investigation is complete. Do not expose the debugging port on a non-loopback interface.
Other Chromium-family browsers, such as Chromium or Brave, work the same way
with the same two flags. On macOS, run the executable inside the application
bundle, for example
`"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"` or
`ws://127.0.0.1:PORT/devtools/browser/ID`; `[::1]` may replace `127.0.0.1`.
`localhost`, private-LAN addresses, HTTPS and `wss:` endpoints, credentials,
queries, fragments, implicit ports, and any other path are not valid CDP
endpoints. Origin filters contain only scheme,
host, and port; paths, credentials, queries, fragments, and wildcards are not
valid origins.
@@ -203,7 +273,7 @@ commands fail closed. A correlated reply's session ID must match the command's
selected session. An optional method is unavailable only when the browser
rejects it as unknown; other command rejections retain their reported failure.
Network and console coverage starts only after REA attaches and enables the relevant CDP domains. `prior_activity_available` is always `false`; absence from these arrays is not evidence that an event never occurred. If CDP reuses a request ID without supplying redirect metadata, REA retains the predecessor observation and marks network coverage incomplete.
Network and console coverage starts only after REA attaches and enables the relevant CDP domains. `prior_activity_available` is always `false`; absence from these arrays is not evidence that an event never occurred. Scripts are different: scripts the page parsed before REA attached are still reported under `scripts`. A page that loaded before attach can therefore list its scripts while `network.requests` lacks the requests that fetched them. If CDP reuses a request ID without supplying redirect metadata, REA retains the predecessor observation and marks network coverage incomplete.
Source maps are not fetched by inspection. Bundle analysis fetches them only when `fetch_source_maps` is selected, with exact-origin redirect checks and no credentials, cookies, or referrer. Each fetch operation has a 30-second deadline and a 64 MiB aggregate streamed-response budget across redirects. A deadline or byte-limit failure remains explicitly unavailable and makes bundle completeness partial. Source-map decoding also bounds raw resolved identities to 64 MiB and aggregate inline evidence to 32 MiB. Failed maps preserve their failure context when it fits; if another context cannot fit, collection stops with the full requested count, the returned processed count, and an explicit unknown-results limitation. Retained mappings and original sources are returned inline. See [source-location limits](web-source-location.md) for the structural decoder bounds. Original source artifacts with `.ts`, `.tsx`, `.mts`, or `.cts` suffixes carry `text/typescript`; other source names retain `text/javascript`.
@@ -312,3 +312,9 @@ artifacts carry their normalized before/after digests and capture states.
Every changed or unknown artifact record is returned inline for each aligned
step. Missing, truncated, or mismatched capture coverage remains unknown
instead of being treated as equality.
`scenario.event_families` records the sorted, de-duplicated `capture.events`
selection. Captures with different selections report event evidence as unknown
with a recovery instruction, even when no selected family emitted an event.
Captures written before this field existed omit it, so their event evidence is
also unknown.
Loaded 100 of 1494 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.