Route exported external import-equals declarations through the same relationship owner as plain declarations so their required target is not dropped.
Fixes#6655
Mark directories with non-UTF-8 names unsupported without following replacement-character paths, while retaining readable sibling observations.
Fixes#6653
Derive exported Docker image versions from .nvmrc through generated package metadata. Align active setup translations with patched Node release floors and verify actual CLI exports, real Docker/agentenv, package and website workflows.
Eight built-test shards pass; three unrelated managed source failures reproduce on clean main and remain tracked in #6650.
Refs #6480
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Parse complete nonzero Activity Manager reports while preserving other command failures and their captured output. Admit dollar signs only in the activity component name for nested Android classes.
Fixes#6528Fixes#6527
`mcp doctor --format` and `--format=` reported VALIDATION_ERROR
"Invalid output format: missing", although docs/cli.md documents
MISSING_OUTPUT_VALUE for valued output flags without a value and
`capabilities` already returns it. Classify absent and empty values as
missing, share the existing missing-value message, and keep
VALIDATION_ERROR for a present but unsupported format.
Fixes#6455
Claude-Session: https://claude.ai/code/session_01LjhoPGpqAwHwcCgectzRsp
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Route CLI and MCP coverage requests through the shared strict workflow boundary before authenticating source Evidence. Preserve canonical advertised schemas, use integrity errors for malformed source bundles, and use the workflow operation for input diagnostics.
Remove the unused throwing domain facade and keep semantic fixture assertions on the parsed Result APIs. Validate compiled CLI and stdio MCP parity, strict request rejection, domain authority/time semantics, generated schemas, and unexpected failure propagation. No external providers execute in these checks.
* fix(native): admit universal Mach-O files without a host slice
FAT Mach-O admission selected only the host's slice and rejected a valid
container whose slices are all foreign, so list-architectures returned
target_unavailable instead of the container's inventory. A thin foreign
image was already admitted.
Prefer the host's slice and otherwise select the first declared supported
slice. Remove the Ghidra installation probe's re-parse under other host
architectures, which existed only to work around the rejection.
Fixes#5404
* fix(native): select the first valid foreign FAT slice
Without a host slice, FAT selection took the first declared slice even when
it was too short for its Mach-O header, rejecting a container whose later
foreign slice is valid. The Ghidra decompiler probe then reported such a
foreign-only decompiler as unknown rather than incompatible. Select the first
foreign slice that can hold its header; a malformed host slice still fails.
* fix(native): select foreign FAT slices from every declaration
Foreign-slice fallback chose among architecture families after keeping only
each family's first declaration, so an undersized first arm64 subtype hid a
valid later arm64 subtype. Select from all declarations, and report the
deduplicated families separately. The host-slice rule is unchanged. Move the
FAT selection tests into their own block.
* fix(native): admit only unambiguous foreign FAT families
With no host slice, a family declared more than once, such as arm64 and
arm64e, has no provider-neutral choice: IDA analyzes the recorded slice while
Hopper prefers its own subtype. Select only families declared exactly once and
keep ambiguous foreign-only containers rejected, as on main.
* fix(ghidra): decide FAT decompiler compatibility from validated families
Slice selection now refuses a foreign-only FAT table that declares one family
more than once, such as arm64 and arm64e, and the decompiler probe reported that
refusal as unknown, so an x64 host accepted an arm64-only decompiler. When
selection fails, read the table's validated CPU families and report the
decompiler incompatible when they exclude the host. Selection and host
exclusion now have separate owners in binaryTarget.ts.
Authenticate source bundles through their shared owner and retain workspace lookup facts for evaluation. Preserve source integrity failures and precise caller constraints while allowing unexpected generated-output failures to propagate. Carry the typed closure result through the service and CLI without redundant JSON validation.
Validation: 242 focused tests, source checks, docs conformance, test discovery and duplication gate passed. Six public SDK regressions fail on the baseline. No analysis provider execution is claimed for the coverage workflow.
* fix(native): admit thin arm64_32 Mach-O targets for static inspection
Target admission mapped Mach-O CPU types only to x86, x86_64, arm and
arm64, so a thin arm64_32 object was rejected as "unsupported Mach-O
architecture" before list-architectures, inspect-macho or
inspect-signature could run, although the same slice inside a FAT file
was inventoried.
Recognize CPU_TYPE_ARM64_32 as its own Mach-O-only architecture with a
dedicated thin target variant, so ELF, PE and raw-binary paths cannot
carry it. Add its slice policy so 32-bit dispatch metadata refuses it
like other 32-bit Mach-O images instead of reporting a CPU mismatch.
Ghidra, Hopper and IDA have no verified arm64_32 lane and decline it
explicitly; Hopper's declined families now share one predicate.
Fixes#5713
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci(apple): run the thin arm64_32 CLI regression on macOS
The regression compiles an arm64_32 object with Apple clang, so it skips
on the Ubuntu jobs. List it in the macOS Apple artifact job and its
change scope so the job runs it and changes to it select that job.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Resolve raw input at the application boundary and reuse its facts in both MCP admission paths. Keep cleanup, mutation retirement and execution ordering while retaining structured correction details for rejected commands.
Validation: 186 focused tests, source checks, docs conformance and duplication gate passed. The new compiled CLI regression fails on the main baseline. Provider process controls use deterministic fixtures; no real Rizin verification is claimed.
fix: repair main after bulk merge
Restore typecheck after #3826 called uniqueBy, and align the red fixtures
with the merged pcap, browser, IDA, and Hopper contracts.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
* refactor(pcap): give TShark selection and version admission one owner
The pcap and packet-capture families wrapped the same caller-supplied
TShark with diverging rules. inspect_pcap_* accepted an absolute
REA_TSHARK_COMMAND or tshark from PATH, while inspect_packet_* and the
server availability policy required an absolute REA_TSHARK_COMMAND and
parsed the version banner with a separate regex.
PcapConfiguration now owns the rule: selectWiresharkTool selects an
absolute environment path or the bare name on PATH and refuses relative
values; locateWiresharkTool resolves a PATH selection to the first
absolute PATH entry holding an executable file; parseWiresharkVersion
admits Wireshark 4.x banners for both providers. TsharkCaptureProvider
and the session availability policy consume these facts instead of
reinterpreting REA_TSHARK_COMMAND, so all four tools accept and refuse
the same configurations. inspect_packet_* still resolves, hashes and
rechecks the located executable, and records selection_source in its
tool Evidence.
Host support and resource bounds are unchanged; unifying them is the
next milestone in #3403.
Refs #3403
* fix(pcap): execute the TShark the shared locator selects
resolvePcapTools still returned bare tool names for PATH selections, so
the operating system could run a tool from a relative PATH entry while
the packet tools skipped that entry and selected a different install.
On POSIX hosts, resolve PATH selections through locateWiresharkTool and
run that absolute executable, failing with the existing tshark_missing or
capinfos_missing code when no absolute PATH entry holds the tool. Both
selections are validated before PATH is consulted, so a relative
environment value still reports its own configuration error. Windows
keeps PATH/PATHEXT resolution in the process launcher.
Refs #3403
* chore: restore main's copies of files the merge hook reformatted
The pre-commit oxlint --fix touched two files this PR does not change; keep them identical to main.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pcap): share selected tool identity verification
* perf(pcap): retain compact executable identity
* fix(pcap): report missing selected tools clearly
* fix(pcap): read historical capture evidence
* fix(pcap): preserve executable read failures
* test(pcap): cover version refusal and packet-tool availability selection
Address review follow-ups on the shared TShark owner:
- Send a 3.x TShark banner and a non-Wireshark banner through the packet
provider, pinning the capability-unavailable reason for each and that
only the version probe ran before refusal.
- Cover the session availability rule for inspect_packet_capture over
MCP: a PATH-only install and an absolute REA_TSHARK_COMMAND are
available on Linux, a relative REA_TSHARK_COMMAND is refused even when
PATH holds TShark, and no absolute PATH entry reports provider_missing.
- Rename the locator test's missing absolute PATH entry so it no longer
shadows node:path relative.
Refs #3403
* fix(pcap): name the configured path when a selected tool is missing
Resolving the selected executable before launch replaced the runner's
"Cannot run selected tool <path>" refusal with a message that kept the
configured path only in diagnostics, so the public CLI no longer told the
caller which REA_TSHARK_COMMAND or REA_CAPINFOS_COMMAND value to fix and
the pcap CLI boundary test failed. Include the configured command in the
capability-unavailable message and assert it there.
Refs #3403
* test(captures): give the late-cancellation fixture a TShark selection source
The service fixture added on main in 719d56ebf predates the required tool.selection_source field, so its report failed output validation before reaching the late-cancellation path the test covers.
Refs #3403
* fix(pcap): report a probe's pending cleanup when a post-run check fails
When a tool probe returned with its owned process still awaiting cleanup,
a failed post-run executable re-read or identity check threw before run()
reported that cleanup. Probes have no snapshot to carry it, so callers
saw an ordinary error with cleanupIncomplete false while the provider
kept the process and refused the next request.
After the command returns, combine such a failure with the probe's
ProviderCleanupError (cancellation and other command failures keep their
own cleanup outcome). Classify request failures through one
analysisFailure owner shared by run() and executeAdmitted(), and let the
availability probe rethrow any cleanup-incomplete failure instead of
reporting the tool unavailable.
Refs #3403
* fix(pcap): keep a failed executable re-read's cleanup live with the probe's
The combined post-run failure was bound only to the probe's pending
process cleanup. When the executable re-read had also failed to close its
file, the classified failure owned that cleanup, but the combined error's
live cleanupResources omitted the file and could clear cleanupIncomplete
once the process stopped. Bind both the classified failure and the probe
cleanup as dependencies.
Refs #3403
---------
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(artifacts): reconcile ARM32 Mach-O slice names with subtypes
* test(snapshot): preserve Evidence-scoped native workflow unknowns
* test(process): assert owned snapshot cancellation outcomes
* test(process): preserve snapshot race causes and owned cleanup
* test(cli): scope runtime cleanup provider injection
CLI boundary tests share a module graph. The cleanup fixture's module mock
cannot replace a provider factory already captured by the real command
registration, leaving its close count at zero after another test imports it.
Inject a typed provider factory into the registration instance, defaulting
to the existing production factory. Both commands still create their own
provider at execution time. Remove the redundant runtime context wrapper
and the global mock state. Keep the real child CLI parity case and verify
that neither command completion nor JSON output precedes awaited cleanup;
retain the close-count, cleanup error and completed Evidence assertions.
The unchanged test passes alone but fails with the command module preloaded.
Both modes pass after the correction. Seven related files pass 28 tests;
check and docs:check also pass on Node24.18.0/npm11.16.0 macOS arm64.
* test(artifacts): use valid ASAR bytes for signature control
* test(mcp): isolate snapshot filesystem fault injection
* test(process): distinguish unacquired resources in failure progress
---------
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
rea mcp doctor rendered json with Formatter.format, which always indents, so
redirected --json, --full-output and validation errors stayed indented. The
dispatcher now passes the stdout TTY state and the doctor renders json and
jsonl through jsonOutputParts like the other commands.
Fixes#5435
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
* feat(captures): make the HAR/SAZ/qlog decoder heap configurable
REA_CAPTURE_DECODER_OLD_GENERATION_MIB keeps the 192 MiB default and
refuses values outside 8 to 16384 MiB instead of falling back.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(captures): defer decoder startup and share one parsed heap
Invalid REA_CAPTURE_DECODER_OLD_GENERATION_MIB threw while CLI commands
were registered, so doctor and help never ran. Build the capture service
only when inspect-web-network-capture runs.
Resolve the heap once in composition and pass that fact to each Node
adapter. Limitation and memory-failure reports use the selected adapter's
heap, so a decoder built with a different environment does not describe
another limit.
Mock captureDecoderProcessMemoryLimitBytes in the Node adapter test so a
Windows Bun host still exercises the unavailable-bound refusal.
Co-authored-by: morluto <morluto@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
* chore: restack environment fidelity onto main
Keep probe comparison, paging, and tied-create behavior on main after #5600. Capture parsing keeps field-path errors and records whether a probe kept request and response bodies.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(environment): keep served collection order with the fidelity checks
The tied-create collection order lives with the checks that match encoded parents. The write simulation reads field checks from that attribution, and taint uses the same segment match.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(environment): translate an object's keys only when it is keyed by learned ids
Differ.object mapped every key through the probe's id map, so a field named
like a learned id was compared with another field, and a real rename could
pass as a mapped key. Keys now translate only for an object keyed by
learned ids as learning reads one: a key both sides share needs every key
evidently an id, and otherwise each entry is an entity or each key evidently
an id. Any other object compares field by field.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Wrapper substitution keyed contextBridge findings only by the inner
exposure call's range, so every helper invocation replaced the previous
one while unioning its members: the last key survived with every
invocation's members. Substituted members also listed only immediate
object keys, dropping nested paths that direct syntax retains.
Record substituted exposures per site and per world and key, and replace
the site's syntax observation once after traversal. Invocations exposing
one key at one site describe one API covering each alternative object; a
traced invocation whose key, object or world stays unresolved or guarded
keeps the site's own unresolved observation. Enumerate member paths
through resolved objects with the direct syntax depth bound, which also
retains the depth-limit unknown that substitution previously dropped.
Fixes#5871Fixes#5870
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Setup and doctor inspect every provider. With no GHIDRA_INSTALL_DIR and no
Ghidra launcher on PATH, the Ghidra inspection still ran the host `java` from
PATH. Its result was discarded because the configuration check already
rejects Ghidra, but its owned-process cleanup could still fail closed. In CI,
that cleanup reported cleanup_incomplete for an unrelated live process whose
/proc/<pid>/environ was unreadable, so `rea setup --client hermes` exited 1.
Run Java only for a selected installation, matching the existing rule for a
relative JAVA_HOME. Hermes setup tests now report the CLI JSON when an exit
code assertion fails.
Fixes#6200
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A url-prefix runtime mapping decoded the whole pathname suffix at once, so
`child%2Fpart.js` became the nested artifact path `child/part.js` and produced
a medium-confidence location match and an inferred observed_as edge.
Decode each URL path segment separately at the mapping boundary. A segment
that decodes to contain a slash, like a malformed or non-UTF-8 escape, has no
artifact path, so the runtime script stays unknown with
no-authorized-location-mapping. Encoded spaces, Unicode, %25 and the literal
%5C backslash name keep matching.
File-root and URL-prefix mappings now share one tri-state translation
(outside, untranslatable, translated) for matching and load-state scope.
Static nodes beneath a prefix whose runtime script or worker could not be
translated stay unknown instead of becoming not-observed-in-capture.
Fixes#5878
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cli): exclude declared sensitive values from parser diagnostics
Incur rejects malformed command tokens and output-flag values before the
web capture service applies --sensitive-value declarations, so its
diagnostics repeated declared literals.
Read declarations from the tokens Incur leaves for command parsing,
independently of parse success. Commands accepting the option get an
outermost middleware that excludes declarations from parse, validation
and thrown failures while keeping type, code and exit status. Rejected
--format/--token-limit/--token-offset values are replaced by a
literal-free value Incur still rejects. The option definition and the
Incur builtin-flag rules now have one owner each.
Fixes#6252
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cli): redact whole rejected output-flag diagnostics
Incur builds its rejected --format/--token-limit/--token-offset message
from fixed text and the value, outside any middleware. Substituting only
the value left declarations that match the fixed text, such as "token"
in "--token-limit", in the diagnostic.
Report that first rejection at the serve boundary instead, redacting the
whole message as parser failures are, while keeping the UNKNOWN code and
Incur's toon or TTY rendering. Incur's message is now mirrored beside its
acceptance rule, and the value-substitution path is removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Electron and process scenario path admission caught every realpath or
stat failure as an invalid_value input issue, so a correct path beneath a
directory without search permission returned invalid_request with
schema-correction recovery instead of a host access denial.
Admission now classifies EACCES/EPERM from path resolution and metadata
reads as the existing AnalysisAccessDeniedError (selected path,
system_code, filesystem-read boundary). Missing, looping or otherwise
unresolvable paths and reachable files without execute permission keep
their input-error semantics. Electron reports invalid selections before a
denial on another field. Process PATH search still continues past a
denied directory; only an explicitly selected executable reports denial.
Fixes#6117
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(native): let callers raise the Apple dispatch metadata input budget
inspect_native_dispatch_metadata refused any Mach-O over a fixed 64 MiB
before decoding, and its recovery said there was no override. Most large
macOS binaries exceed it.
max_input_bytes (CLI --max-input-bytes) now selects the budget, default
64 MiB and at most 1 GiB, through the shared input contract, the enhanced
workflow and the native provider. Results record input_admission with the
effective budget, its source and the retained bytes. A refusal names the
observed size, the budget and its source, and the budget to select or, past
1 GiB, a deep analysis provider.
Fixes#3917
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cli): describe --max-input-bytes in inspect-native-dispatch-metadata help
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(native): cover max_input_bytes forwarding through CLI and MCP
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(artifacts): make ASAR header admission configurable
ASAR header/index admission was a fixed 16 MiB with no override, so
operators with large Electron indexes could only extract the archive.
REA_ASAR_MAX_HEADER_BYTES now sets it (default 16777216, maximum
268435456). One owner resolves the effective admission for the
classification probe, inventory, ASAR reader and Electron file scope,
including the Electron header cache budget. Startup and doctor validate
the setting; admission refuses an invalid value instead of falling back.
Recovery and error details name the effective value and its source.
Fixes#6176
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(artifacts): resolve ASAR header admission from the caller's environment
The admission read process.env, so composition roots that select their own
environment (createDirectAnalysis, createServer, CLI, optional observation
factories) could not raise or lower it, and an ambient value leaked into
callers that left it unset.
Nothing reads process.env now. ArtifactProvider and extraction resolve the
admission from their environment; JavaScript analysis parses it from the
environment its server or CLI caller passes and refuses an invalid value;
the Electron and V8 providers receive it from their factories. Inventory,
nested ASAR readers, classification probes and Electron page authorization
carry that one value. A header cached by Electron under a larger admission
is refused for a smaller one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Summary delivery with --evidence_output wrote the bundle, then let the
command's close/cancellation check replace the result. A SIGINT/SIGTERM
during staging cleanup after commit returned typed cancellation without
the receipt, and a persistent staging cleanup failure after commit was
rewrapped as a provider cleanup error that dropped published_path.
Every --evidence_output command now selects its view first and publishes
through publishEvidenceDelivery, the owner inspect-managed-members already
used. Post-commit cancellation keeps {path, bytes} under
details.diagnostics.evidence_bundle; incomplete cleanup keeps
details.published_path and bytes; a cleanup retry that succeeds returns
the normal receipt; pre-commit cancellation creates nothing and names
the command's operation.
Fixes#6095
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Fixes#5148.
Add opt-in durable managed member summaries and authenticated paging while preserving complete default output, original Evidence, cleanup ownership and queued cancellation.
Verified with bounded real Newtonsoft/Redux/Rust tasks, independent oracles, 556 focused tests and the expanded domain gate; paired token estimates and latency tradeoffs are recorded in experiments/analysis-efficiency/managed-cli.md.
* feat(environment): extract the initial state a capture's reads observed
Add the environment-state analysis view. From the parents the environment
manifest accepts, it extracts the data the capture's reads observed before
the first related write: entity types with an identity field (proved by a
path parameter or inferred from an identity name), entities with their
recorded values and provenance, documents for written non-entity paths, and
a render plan per read tool that is kept only when it reproduces the tool's
latest initial recordings from the state; every other read tool is a
recorded view with the reason. The Evidence is always inferred.
Response-body decoding moves to a domain owner shared with replay, exact
JSON parsing moves to the owner of the exact-number policy, the manifest and
state views share parent admission and record grouping, and
projectAnalysisView takes its accumulators as one object.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): bound state at redacted writes; infer identity only from items
A scenario write whose URL was redacted has no request line, so it was
dropped and reads after it counted as initial state. Such a successful
write now joins the timeline with an empty path, whose root relates to
every type, so it ends every type's state; a limitation counts them.
A list whose recordings were all empty passed the "every listed item
carries it" check vacuously and published an identity field nothing
showed; it now needs at least one item, else the view stays recorded
as no-identity.
A value that differed between two request lines of one item tool, such
as a query variant, was called volatile, and the gate then substituted
each recording's own value; only repeats of one request line now show
volatility, so differing lines go through fields-differ.
List membership is compared only while a list can still be the whole
collection, and merged entities are indexed by type and collection once,
so paged captures no longer cost pages times entities (8,000 pages of
40,000 entities: 5.7 s to 0.23 s).
Docs and the tool contract say scenario state keeps the capture's
redaction markers and how redacted writes bound it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): keep first sightings, one list pointer and linear field unions
Entities took the order of the first plan observed, and item plans run
before list plans, so a complete list read before its detail reads came
out reordered and lost "all" membership; each entity now keeps its
earliest recorded sighting.
A list plan reused the first recording's pointer for later recordings,
so a later response that was itself an entity wrapping a list was read
as that list; every recording must now locate the same list.
The field union scanned its ordered list for every key, quadratic in an
object's width; a set now answers membership.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): keep post-write values and partial lists out of the initial state
A value that changed between repeats of one request line was named
volatile whenever no write under the type's own root lay between, so a
write under another root (for example POST /api/dashboards/db before a
second GET /api/search) left its effect in the initial state. Any
recorded write between the two observations now leaves every tool of the
type recorded with reason fields-differ instead.
A list was published with membership "all" even when a total or count
envelope member exceeded the number it listed. Such a counter now makes
the membership "recorded".
Also drop a stale doc comment on ObservedEntity.order.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(environment): scope item-shaped and deleted written paths out of documents
State documents are held only for list-shaped paths a POST, PUT or PATCH
tool writes. Reads of item-shaped written paths and of paths that are only
deleted stay recorded views; the guide now says so and the spec defers them
to a later increment of #4933.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): count writes in flight when a value changes between reads
The volatility check compared write start positions with the two reads,
so a write already in flight when the earlier read started was missed and
its effect was named volatile. A write now counts when its interval
overlaps the span from the earlier read's start to the later read's end.
The check also ran once per changed field and scanned every write. It now
runs once per pair of observations, answered by a binary search over the
writes in timeline order and the latest end among each prefix.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): catch cross-tool changes across writes; read only item totals
A value that changed across a write was caught only between repeats of
one tool's request line, so a list read before a write and an item read
after it put the post-write value into the initial state. Changes are
now classified per entity in timeline order after observation: across
any recorded write, a change between repeats of a line or between two
lines of the type rewrites the type (every tool recorded as
fields-differ); with no write between, a repeat's change is volatile.
The classification lives in environmentStateMerge.ts.
Any numeric member whose name contained "total" or "count" counted as
an item total, so total_pages, account_id or page_count made complete
lists partial. Item totals are now members whose name tokens include
total or count and none of page, pages or per; a string of digits counts
as a number; and a set has_more, next or next-page token member also
marks the list partial.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): keep post-write observations out of initial state
* fix(environment): retain field provenance and bound state inference work
* feat(environment): serve tool calls from the environment state
`environment-serve --state <state.json>` serves an environment from the
initial state an environment-state view extracted. Read tools whose views
are state-backed answer from a live state store: item views render the held
entity into the recorded envelope, list views render the collection or the
recorded members, and document views return the held value; a missing entity
or one lacking a required field is refused, and requests the state cannot
answer fall back to their recordings with the reason. The /agentenv data
plane implements data/reset, data/add (a rea-state/v1 document as a data
part, base64 bytes, a file:// path or an https URL, validated and replaced
atomically) and data/get, and the card advertises those operations and an
intake declaration. Stage 1 is read-only: write tools are not served in
state mode. Without --state nothing changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(environment): record verification after merging the state view's review fixes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(environment)!: serve the environment state by default
environment-serve derives the environment state at startup by running the
environment-state view in-process on the capture with the manifest's
template rules, so an environment comes with its state and a user supplies
nothing extra. The derived Evidence is the same one inspect-analysis-view
produces by hand. --state is removed; --replay-only serves exactly the
stateless replay of main. When the state cannot be derived, or its catalog
does not fit the discovery budget, the server starts in replay mode, logs
the reason and reports it in the stop summary's `state`. Exported bundles
serve the state by default too: export derives it the same way, so the
verifier's tool count and checked answer match what is served, and the
README describes the served mode.
BREAKING CHANGE: environment-serve answers read tools from the derived
state and does not serve write tools unless --replay-only is given; the
stop summary reports `state` instead of `state_evidence_id`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): bound data-plane replies, keep batch order, cancel intake on stop
- One /agentenv response is held to 64 MiB: replies are measured as they
are produced and one past the budget becomes a -32000 error stating it.
- Every message of a batch enters the arrival-order queue on arrival, so
another request's reset never lands between them.
- Stopping the server, or a caller leaving, cancels the active download
and answers queued calls `cancelled` without running them.
- file:// URIs name only this host: another host or a network share is
refused before anything is opened.
- A loaded view value may not give an entity another identity.
- List answers refuse a member lacking a field every recording carried,
as item answers do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): keep bodies too deep for the state's nesting out of the state
A recorded body at the JSON depth limit was accepted by extraction, then
nested a few levels deeper as a document or entity value, so sealing the
state Evidence threw and environment-serve and environment-export stopped
instead of falling back. stateBodyJson, the one rule extraction and
serving share, now treats a body nesting deeper than the limit minus 16
levels as unusable, so its tool stays a recorded view.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): measure data-plane replies before building them
83fcc739 bounded one /agentenv response to 64 MiB, but it still
serialized each reply whole before measuring it, so a batch of data/get
calls on a large state built every refused reply in full only to drop
it. Each reply is now measured in bounded JSON parts (the shared
jsonParts encoder), its parts kept only while it fits; a reply past the
budget is counted for its exact reply_bytes but never assembled. A test
checks that a refused read is never handed to JSON.stringify whole and
that its reply_bytes is exact.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): release batch replies as they are encoded; judge exact numbers by value
answerBatch kept every settled reply in its pending array until the
batch ended, so a batch alternating data/add and data/get held each
loaded state alive; each reply now leaves the queue as it is encoded.
The exact-number policy judged a number by its recorded spelling, so a
state loaded with 1e20 came back from data/get as
100000000000000000000, which data/add refused, breaking the promise
that data/get output loads back unchanged. A number is exact only when
both its recorded spelling and the one serialization writes are safe,
so integers from 2^53 below 1e21 are refused in any spelling; replay
keeps such bodies as recorded text. A domain test checks that every
accepted number is accepted again once written back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): keep room for refusals and framing in the reply budget
The response budget counted accepted replies only: a budget error that
replaced a reply, and a batch's brackets and commas, were not charged,
so near 64 MiB later refusals pushed the body past the advertised
limit. Every reply still to come now keeps room for its own budget
error, and a batch keeps room for its framing, so a refusal always fits
and the body never passes the budget. Reply ids and which messages are
answered come from one place shared by the replies and the reserve.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): refuse a loaded state that data/get would write past the intake limit
data/add measured only the document it was given, while data/get
writes the state back with the members a document may omit (types, the
state Evidence id, view fields and record citations). A document just
under 32 MiB could therefore load and be reported larger than any intake
accepts, breaking the data/get then data/add round trip. replace now
measures the state as data/get writes it, part by part, and refuses it
past the limit, leaving the state unchanged. The limit moves to the
state document module, so the application store can read it; the
intake re-exports it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(environment): keep merged export checks on the shared test graph
Main's export tests installed module mocks for the whole services
project, which reuses one module graph. A tarball read failure then
missed its importer, and a one-shot heap mock could be taken by another
file. Read those through bindings the tests replace for one case.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(environment): keep a state file whose close failed owned until it closes
A file:// data/add that could not close its descriptor dropped the handle,
and an admission failure whose cleanup close failed dropped its owner, so
nothing could retry the close or report it.
The read now runs through withOwnedRegularFile, and a failed close is
retained in a server-lifetime ArtifactResourceScope. The next file read
retries it first and answers -32000 while it is still open; inline and
https documents still load. Closing the served environment retries it again
and rejects with the unfinished close.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(cancellation): preserve caller abort reasons through late finalization
Caller aborts that arrived during final provider, cleanup, or protocol
handling were dropped or replaced by I/O, cleanup, or success results.
Each affected path now samples the caller signal after its owner has
settled and returns AnalysisCancelledError carrying the exact
signal.reason, keeping any completed partial Evidence or cleanup state.
- Web script export: keep the exact reason for an interrupted output
write, and honor a cancellation fact recorded before a retried
capture close succeeds.
- Native value tracing and Hopper regex search: check the signal after
the final provider reply or regex worker settles.
- Apple asset catalog: stop assetutil with SIGTERM so cancellation
settles only after the helper exits.
- CDP observation: end an armed window on a fatal protocol failure.
- ADB bugreport: prefer cancellation over the staging-removal output
error when the caller aborted.
- JavaScript recovery: check the signal after provider success.
- export-web-scripts CLI: run under command cancellation and forward
the signal into the export workflow.
- Objdump and Rizin CLI: report cancellation after cleanup completes.
- Binary session: keep cancellation primary when previous-client
retirement fails after abort.
Fixesmorluto/rea#6042Fixesmorluto/rea#6043Fixesmorluto/rea#6048Fixesmorluto/rea#6049Fixesmorluto/rea#6057Fixesmorluto/rea#6060Fixesmorluto/rea#6078Fixesmorluto/rea#6080Fixesmorluto/rea#6108Fixesmorluto/rea#6111Fixesmorluto/rea#6115
* fix(cancellation): keep caller reasons through export rollback and commit
- Rollback failure after a caller abort now returns AnalysisCancelledError
with the exact signal.reason, attaching the rollback failure as cleanup
and retaining any published result as partial observation.
- A capture close retry that succeeds after abort returns cancellation
instead of the stale cleanup diagnostic.
- An abort that lands during the final output commit returns cancellation
carrying the completed manifest as partial observation.
- Apple assetutil stop test: abort and await the run in finally so a
timed-out wait does not leave the child running, and skip on Windows
where the JavaScript SIGTERM handler cannot run.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 35b247e9-c793-4b8f-979a-807c27112cf5
* fix(cancellation): bind export cancellations to cleanup and caller reasons
- A rollback-failure cancellation is bound to the retained cleanup lease,
so a later successful close clears cleanup_incomplete instead of
reporting a residual directory that no longer exists.
- mapExportFailure wraps the caller's own AnalysisCancelledError reason
under export_web_scripts rather than returning it as the export's error.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 35b247e9-c793-4b8f-979a-807c27112cf5
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Copilot-Session: 35b247e9-c793-4b8f-979a-807c27112cf5
#5633 gave Rust and IL2CPP input-size refusals input-allowance recovery
through fixedAllowanceOptions, but no public CLI check covered either
command, and IL2CPP had no remediation assertion at all. Add both
commands to the CLI input-limit matrix.
Go and WASM still carried a duplicated hand-written copy of the same
advice. They now use the shared "input" allowance recovery, so all four
commands name their fixed allowance from one owner.
The matrix also asserted not.toContain("evidence reply"), which the new
"evidence-reply" wording passes only because of the hyphen. Assert the
absence of the old advice text instead.
Fixes#5405
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(electron): report rejected CLI arguments with issue details
Pass schema validation issues and submitted input to inputError in list-electron-targets and inspect-electron-page commands, matching the structured diagnostics returned by browser commands.
Fixes#3865
* test(electron): assert exit code 1 on rejected CLI arguments
* fix(providers): name JEB, IDA, and one-shot command deadlines
Wire JEB catalog discovery to REA_JEB_MCP_TIMEOUT_MS, name the IDA
registration timeoutMs, and add command_timeout_ms for one-shot objdump
and rizin. Debugger, Frida, and Cutter caps stay fixed and say so.
Refs #5910
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(providers): pass remaining deadlines and name the cap that fired
Catalog discovery now sends the JEB budget still remaining to the SDK on
connect and every tools/list page. Objdump and rizin preflight share one
command_timeout_ms across stat and digest; the command still receives that
budget again. Architecture Evidence keeps a selected timeout, and Frida and
Rizin name the capture limit that actually stopped output.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(frida): preserve non-timeout device lookup failures
getDeviceById is a lookup deadline only when Frida rejects with
"Device not found" after the wait. A device-manager or backend failure
stays a capability error. Align the assertions that still expected the
previous capacity and capture sentences.
Co-authored-by: morluto <morluto@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
`copilotDirectory` used nullish coalescing, so `COPILOT_HOME=""` produced
the relative path `mcp-config.json`. Setup then planned and wrote the
GitHub Copilot CLI registration into the current working directory, not
`~/.copilot/mcp-config.json`, and doctor looked for it in the same wrong
place.
Use `||` like the sibling client homes (CODEX_HOME, KIMI_CODE_HOME,
GROK_HOME, XDG_CONFIG_HOME), and as #2686 did for DSH_HOME.
* fix(native): recover macOS command deadlines
Promote native_command_timeout_ms (default 60000), native_ui_deadline_ms
(default 180000), and pwntools_timeout_ms (default 30000) as validated
per-call settings. Keep cpuSeconds, byte allowances, LLDB grace, and plist
probes fixed, and say those caps have no runtime override.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(native): report the deadline that actually expired
Pass the selected native command timeout through xcrun resolution, thread
the pwntools deadline into pwndbg failures, and state the selected UI
deadline apart from the fixed wait-step cap. SIGXFSZ and EFBIG recovery
names the file-size allowance.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(native): honor the selected deadline on helper stages
The UI helper compile and capture subprocesses used fixed 60s and 30s
exec timeouts, so a longer native_ui_deadline_ms still failed as a generic
provider error. Preparation timeouts reported the 60000 ms default instead
of the selected native_command_timeout_ms.
Memory resource-constraint recovery names memory again, and the Darwin
plist CLI expectation matches the byte-counted input allowance.
Co-authored-by: morluto <morluto@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(javascript): name heap and semantic ceilings
Refs #5910. Heap exhaustion names max_heap_mb with its effective value,
range, and next-analysis worker restart. Semantic ceiling coverage names
the four max_semantic_* arguments. Wakaru and transfer ceilings say this
release has no runtime override.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(javascript): distinguish adjustable ceilings from fixed limits
The effective transfer file ceiling and the parent result budget follow
the CLI/MCP process heap, so recovery names NODE_OPTIONS instead of
denying an override. A provenance report over 8 MiB keeps the fixed
allowance guidance, and the Wakaru deadline says an unchanged retry may
hit it again.
Refs #5910
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(javascript): keep Bun OOM and checkpoint heap controls distinct
Bun heap-exhaustion exits no longer claim the ignored max_heap_mb V8
old-space limit. Checkpoint decode names the parent heap and Node
NODE_OPTIONS, the same control as the parent result budget.
Refs #5910
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(javascript): name semantic ceilings without claiming both were reached
Truncated semantic retention names the total and per-file controls as
effective ceilings. Callers only know that retention was truncated, so
the limitation no longer says both ceilings were reached.
Refs #5910
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(javascript): name only the semantic ceiling that stopped retention
Semantic ceiling limitations claimed both the application total and the
per-file control whenever either one truncated the graph. Record which
offered budget stopped node and unknown retention, and name only those
controls. Coverage limits still list both effective values.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(javascript): require a value in the NODE_OPTIONS heap example
A bare --max-old-space-size is an illegal V8 flag and prevents Node from
starting. Parent-heap and transfer-ceiling recovery now share
--max-old-space-size=<MiB>, and the Kuna heap remediation uses the same
complete form.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(javascript): limit the old-space placeholder to NODE_OPTIONS recovery
The review covers the CLI/MCP NODE_OPTIONS example and the transfer-ceiling
copy. The Kuna heap-headroom sentence stays unchanged.
Co-authored-by: morluto <morluto@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(android): name the JADX deadline and recover apktool decode
JADX operation timeouts now name REA_JADX_OPERATION_TIMEOUT_MS, the
effective milliseconds, the 1..2147483647 range, and that a change applies
on the next process start. Apktool decode accepts decode_timeout_ms,
omitted means 600000, and a timeout names that key. ADB deadlines and
apktool and Java version probes stay fixed and say there is no runtime
override.
Refs #5910
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(android): derive capture recovery from the fixed allowance
Main now stores a fixed allowance instead of a prebuilt remediation
string. Apktool and adb capture refusals keep the no-runtime-override
sentence in that allowance name, including that decode_timeout_ms does
not raise the apktool output cap.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test(apktool): observe a real decode deadline and process cleanup
A hanging interpreter launcher and its pipe-holding child stay alive
until decode_timeout_ms elapses. The provider then reports
provider_timeout with completed cleanup, and both processes are gone.
Co-authored-by: morluto <morluto@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
The obligation ledger flattened every contradiction entry for an obligation
into one Evidence list, so one entry naming absent Evidence suppressed a
sibling entry whose Evidence was all present. Group whole manifest entries
and evaluate each one: any complete entry still reports `contradiction`,
while absent references from any entry stay visible as
`contradiction-evidence-missing`.
Share the ready packaged-process request fixture with the CLI boundary test,
which now covers both entry orders through the public command.
Fixes#5925
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>