Share selected-file errno ownership with model inspection and codec result accounting with Rust. Verify actual descriptor exhaustion and unchanged-input recovery in an isolated child.
Fixes#6666
Centralize run-token extraction at the environment observation boundary and require an own field. Build decoded OS environment records without host prototypes while retaining source names, empty values and last-assignment precedence.
Reject inherited matching tokens before cleanup signaling, preserve normal owned-group behavior, and verify live Linux process environments alongside native CLI/MCP capture workflows.
Reuse validated class pages for inline pagination audits while retaining complete provider replies. Move retention into the shared Android workflow and remove the MCP-only service wrapper and application text reparser. Preserve unknown JSON metadata, late cancellation and retention failures.
Preserve renamed-executable identity, complete-line readiness and bounded child lifetimes. Use genuinely malformed Inspector input and explicit ADB file-probe/push/hash facts while preserving cancellation, cleanup, Evidence and completeness assertions. Adopt current main Go fixtures and retain malformed COFF coverage.
Fixes#6556
Refs #6480
Keep aliases on selected paths at clear text delimiters so a longer sibling filename is not rewritten as the executable. Version the normalization contract and cover source and actual PTY behavior.
Fixes#6586
The sparse-child capture test asserted the frame bound with a bare boolean,
so a failure only printed "expected false to be true". The assertion now
carries the running progress details (elapsed time, frames, samples,
interactions) as its failure message. This only adds diagnostics to a
failure; it does not change what passes and does not fix the flake.
Refs #5889.
🤖 Generated with Claude Code (Sonnet 5.5) 🦊
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Require Node.js ^22.23.4 || ^24.22.1 || >=26.12.1 across package engines, setup/doctor and the standalone installer. Validate patch boundaries and maintain runtime-independent listener identity, heap-option and HTTP schema-binding tests.
Closes#6283
Refs #6480
BREAKING CHANGE: Node versions below 22.23.4, 24.22.1 and 26.12.1 are no longer supported. Upgrade Node before installing or updating REA; the installer does not upgrade Node.
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
capture-process recorded exit.code 0 for a target a scenario event killed
with SIGKILL or SIGTERM, beside the nonzero exit.signal. The result builder
and the retained observation each kept any nonnegative PTY exit code for an
exited capture without consulting the signal; only finalization checked it.
Project the exit once in captureExitObservation, whose normal exit code is
null when a nonzero signal ended the target, and use the same rule for
finalization. Normal exits keep their codes, including 0 and 3, and deadline
exits remain null.
Fixes#6445
Return expected source and semantic failures from the runtime input owner as tagged Results. Bind source schema validation to concrete schemas, preserve nested active-capture paths, and let unexpected interpretation and derivation failures reach the adapter boundary.
Remove broad protocol-error wrappers, duplicate active identity validation, and redundant JSON result parsing. Migrate parsed-fact consumers and retain CLI/MCP contracts. Relevant source and public-boundary tests pass; six injected implementation-fault controls fail on the prior revision. Live Electron behavior was not exercised.
The registry fixture sent response headers before reading the upstream body,
then always wrote a 500 on error. A body failure hit ERR_HTTP_HEADERS_SENT,
which hid the real error and crashed the verifier with its helper still running.
The fixture now reads the body first, destroys a response that already started,
and the verifier rethrows the first fixture error.
Refs #6038.
🤖 Generated with Claude Code (Sonnet 5.5) 🦊
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
* fix(scripts): remove the ADB verifier's pushed probe file from the device
The verifier pushed `/data/local/tmp/rea-verify-<timestamp>.txt` for its
transfer roundtrip but never deleted it, so every successful run left a
probe behind while reporting that all checks passed.
After a successful no-overwrite push, the verifier now removes that exact
destination with the provider-reported adb client and confirms its absence
through `list_adb_directory`. Removal runs even when the pull fails, and a
removal failure is reported as a failed check instead of a pass.
`pull_adb_file` still retains device originals.
Fixes#5190
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(scripts): cover ADB probe cleanup after pull failure and leftover probes
Add verifier cases where the pull returns an error or throws after a
successful push, and where `adb shell rm` exits 0 but the listing still
shows the probe. Pull failures must still remove the probe, and a leftover
probe must fail the run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Prevent polling readers from observing truncated readiness JSON in compiler fixtures. Retain deterministic cancellation controls and strengthen the real Swift compiler case to run native identity inspection, verify parent/group facts, and check stable identity across reads.
Validated all 32 Darwin tests with the real host toolchain. A delayed write reproduces the old JSON race; delayed atomic publication passes. No CI timeout or retry changes.
* test: prefer structured assertions over recovery prose
Lock regex, IDA, Hopper/Kuna, MCP budget, capture-heap, and pcap
failures on error codes and reported limits instead of full recovery
sentences.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test: keep decoder heap negatives off the Windows reserve
"512 MiB" also appears in the Bun Windows reserve sentence. The
negative check stays on "512 MiB (source setting)", which is the other
adapter's heap.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test: keep the one-retry cap and deadline recovery tokens
The lost-connection guidance must say once only, so an unlimited
"whenever it is safe" rewrite fails. Deadline recovery still has to
name set, restart, the floor, and the maximum constant.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test: keep heap, MCP, pcap, and preload recovery tokens
Codex still wanted the set/restart/floor/maximum heap guidance, MCP
default/floor/maximum bounds, Wireshark install guidance, and the
dropped-preload attribution limit as separate tokens.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test: keep shared-context and transport recovery tokens
Shared-context capture must still exclude requests without a known root
or descendant frame. Shutdown must end the REA process before starting
again, and a failed HTTP listen must offer another port or stopping the
process that holds it.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test: keep handoff, input-check, and budget format tokens
Skill and server guidance must still tell the user to restart the MCP
client. Process failures must still say to check the input files. Invalid
MCP phase budgets must still say positive decimal integer and ms.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test: bind budget floors and active deadline sources
The phase-budget minimum is the start of "from N to M ms", so a digit
inside the maximum no longer satisfies it. Capability text must contain
the active "N ms (source ...)" pair, not the default number and a heap
source mentioned apart.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test: bind heap MiB sources and pcap host tokens
A configured 256 MiB request must appear as "256 MiB (source setting)",
so a byte-sized 256 no longer passes. Unsupported pcap hosts must still
name Linux, util-linux, Windows, and owned Job Objects as separate tokens.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test: bind the selected decoder heap to MiB and source
The two-adapter limitation must contain "256 MiB (source setting)".
The exhaustion message binds that capacity as "256 MiB V8 old-generation
heap (source setting)", so a byte-sized 256 no longer passes.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test: bind doctor client seconds and prlimit absolute guidance
Doctor recovery must name startup_timeout_sec of the policy's seconds,
so a hardcoded 60 no longer passes while the policy stays 30. A relative
prlimit must say the value must be absolute and tell the user to check
REA_TSHARK_PRLIMIT_COMMAND.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test: assert integrity codes for rehashed evidence and coverage
Independently rehashed process Evidence and a tampered digest project
evidence_integrity_mismatch. An unsupported comparison operation stays
invalid_request. Unsupported inventory coverage status is an integrity
failure whose reason carries the coverage.status schema issue.
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): retain snapshot descriptors when close fails
Preserve the stable-file diagnosis or completed copy facts when an APK
or engine snapshot close rejects, and retry that exact owner before
workspace retirement.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(kuna): retain span descriptors when close fails
Preserve completed span text or the short-read diagnostic when close
rejects, and keep session close incomplete until that handle is released.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(android): attribute snapshot cleanup to the descriptor that failed
A finished copy can be nested under another descriptor's rejected close.
Walk that chain, keep the snapshot hash on the partial observation, and
name every descriptor that is still open.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(kuna): gate span admission until a retained close releases
Overlapping requests can pass the entry cleanup check before any lease
exists. Hold each span open through its close so the next open retries
that descriptor instead of admitting another one.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(android): preserve nested snapshot facts when both closes fail
Walk nested close failures so a finished copy and a changed-APK diagnosis
survive when the source descriptor also rejects close. Attribute cleanup to
each descriptor that failed, and classify a nested close cancellation.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(kuna): release recovered span leases before the next open
Serialize span admission and close without holding the queue across the byte
read. Recheck the caller signal after that wait, and drop a recovered lease
from the resource scope as well as the span map.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(android): retain a source descriptor when admission close fails
openRegularFile can reject after the descriptor opens. If that close also
fails, keep the owner on the snapshot cleanup map instead of dropping it
when adoption never runs.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(kuna): keep cancellation when a completed span close fails
Pass the caller signal into span finalization. If the read already finished
and close then rejects, report cancellation as the primary error and keep
the span text with the retained descriptor.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* style: format Android and Kuna close-ownership changes
CI format:check rejected the four files touched by the close-ownership fixes.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(android): keep the snapshot hash inside a nested cancellation
A destination close that succeeds after abort throws RegularFileCancelled
with the finished copy. When the source close then rejects, recover that
copy so cancellation keeps the digest and file-snapshot-hash observation.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(android): keep the snapshot hash on a direct close cancellation
A finished copy whose descriptor closes successfully after abort is a
top-level RegularFileCancelled. Attach its digest and file-snapshot-hash
observation to that cancellation.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(kuna): preserve the caller abort reason after a successful span close
A completed read whose close then succeeds throws a cancellation wrapper.
Return AnalysisCancelledError with the caller's abort reason instead of
that wrapper.
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>
* feat(process): make the regex worker heap request configurable
REA_REGEX_WORKER_HEAP_REQUEST_MIB keeps the 128 MiB default and refuses
values outside 8 to 16384 MiB. A positive Node --max-old-space-size still
overrides the request and is not clamped by the setting.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(process): set the regex worker heap floor to the measured startup bound
On Node 22.23.4 a 5 MiB old-generation request aborts the regex worker
during startup, and 6 MiB starts it and returns a match. The setting floor
is that measured bound.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(process): raise the regex worker heap floor to 7 MiB
6 MiB passes configuration but returns ERR_WORKER_OUT_OF_MEMORY for a
trivial match on supported Linux Node 24 and Node 26.0.0. 7 MiB returned
that match on the measured 22, 24, and 26 lines. A clean-process test
runs the production worker at the floor.
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(ci): isolate packed Python syntax checks from ambient imports
Keep caller-local modules and site startup hooks from replacing the
standard-library AST/tar readers or executing during package validation.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
* feat(config): make the regex matching deadline configurable
REA_REGEX_MATCHING_DEADLINE_MS defaults to 5000 ms and refuses values
outside 1..2147483647. Recovery and capability text name the effective
deadline, its source, and how to change the setting.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(setup): preserve the regex matching deadline in registrations
Setup validated REA_REGEX_MATCHING_DEADLINE_MS but left it out of the
selected registration environment, so a caller override never reached
the launched server and matching fell back to 5000 ms.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test(config): restore a stubbed regex matching deadline on failure
Kuna deadline assertions now unstub the environment in finally, so a
thrown construction or expectation cannot leave the setting stubbed.
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>
Final filesystem observation reconstructed root admission from the initial
snapshot's root entries, so an initially absent root (no entry) whose ancestor
became a regular file failed capture with ENOTDIR after the child completed.
A returned initial snapshot now admits every selected root for the run. One
tagged path lookup classifies ENOENT and ENOTDIR as observed absence and other
unavailable lookups (EACCES, ELOOP, ...) as entry_unavailable omissions that
keep the root incomplete. Selected roots that are obstructed or denied before
launch still fail capture.
Fixes#6213
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>
* fix(process): settle owned cleanup with the launcher's own exit proof
When owned process-group verification fails while the supervised
launcher is still mid-exit, the supervisor now waits up to the kill grace
for its own child-exit observation and verifies once more after it
arrives. Verification is not repeated when the exit was already observed
before cleanup started, so there is no new evidence and the original
failure is kept. Nothing is signaled based on the wait.
Fixes#6134
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(process): bound Hopper session cleanup attempts by exit evidence
The fake Hopper launcher exits after its shutdown acknowledgement. When
the supervisor first observes that exit during a failed verification, it
verifies once more, so the first close makes one or two attempts depending
on timing. The test now asserts that bound. Later session retries, made
after the exit was already observed, make exactly one attempt each.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(process): report the effective regex worker heap
Node gives --max-old-space-size, including NODE_OPTIONS, precedence over
the worker's 128 MiB resourceLimits request. Name that effective
old-generation heap and stop saying the request has no runtime override.
The matching deadline stays a fixed cap.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(process): keep SIGXCPU and SIGXFSZ retries uncertain
The signal does not prove the retained rlimit was exhausted, so an
unchanged retry may succeed. Project that retry as possible instead of
saying it fails the same way.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(process): leave percentage heap overrides unestablished
--max-old-space-size-percentage takes precedence over the absolute flag
in either order. Node computes that MiB from startup memory, which a
later read does not recover, so the effective heap stays unknown instead
of the 128 MiB request or an absolute flag.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(process): read launch NODE_OPTIONS, not process.env
A preload can rewrite process.env.NODE_OPTIONS after V8 has applied the
original flags, and those flags are not copied into execArgv. Use the
initial environment block when it can be read, and leave the effective
heap unestablished when that provenance cannot be recovered.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(process): leave env-file heap overrides unestablished
--env-file and --env-file-if-exists can supply NODE_OPTIONS when that
variable was absent from the initial environment. The file is not in
/proc/self/environ, so a missing entry is not the 128 MiB request.
An initial NODE_OPTIONS is still parsed, because Node does not let the
file replace it.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(process): leave --max-heap-size old generation unestablished
A positive --max-heap-size or --max_heap_size sets the total heap, not the
old generation, and can stay below the 128 MiB worker request when an
old-space flag is also present. The effective old generation stays
unestablished while that value is in effect. Zero or empty clears it.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(process): leave config-file heap options unestablished
--experimental-config-file and --experimental-default-config-file can
apply a heap percentage from a file that is not launch provenance. The
effective old generation stays unestablished when either flag is present,
including beside an absolute --max-old-space-size.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(process): read launch exec argv from the command line
process.execArgv can be cleared after V8 applies --max-old-space-size.
Linux recovers those tokens from /proc/self/cmdline and leaves the heap
unestablished when that vector cannot be separated from the program entry.
Heap probes compare pinned absolute limits instead of a percentage of host memory.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(process): leave a title-overwritten command line unestablished
process.title and --title replace /proc/self/cmdline with the title.
A buffer without a program entry is not an empty option list, so the
heap stays unknown instead of the 128 MiB request. The command-line
probe does not read /proc off Linux.
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>
* 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>
Use compact MCP input advertisements by default while preserving explicit full, canonical validation, output contracts and complete Evidence. Require an explicit selected catalog for runtime identity and honor both profiles in CLI status.
Real ripgrep/Zellij SDK tasks, independent ELF oracle, actual client trials, profile parity workflows and CI are recorded in experiments/analysis-efficiency/mcp-input-catalog.md. SDK token estimates improve; actual Codex token savings and general latency/memory gains are not established.
Refs #5861
BREAKING CHANGE: MCP input advertisements default to compact. Set REA_MCP_INPUT_SCHEMA_PROFILE=full for complete advertised guidance and nested constraints.
Name REA_SWIFTC_COMPILE_TIMEOUT_MS, its effective milliseconds, the
1..2147483647 range, and the omitted 120000 ms default when a Darwin
ownership-helper compile times out. A change applies after REA restarts,
on the next ownership-helper compile.
Producer SIGXCPU and SIGXFSZ recovery says REA retains the tighter
inherited limit. Agent-visible fixed caps in this theme say this release
has no runtime override. Numbers are unchanged.
Refs #5910
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Bind artifact lifecycle and analysis calls to their advertised named SDK
output schemas, sharing discovery per connection and rebinding on reconnect.
Reject schema overrides and ambiguous catalogs, preserve request options,
and retain primary failures while attempting all owned cleanup.
Add real-stdio boundary regressions for malformed output, discovery reuse,
reconnection, schema ambiguity, override rejection and timeout preservation.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
resolve_adb_packages marked coverage partial when pm list packages printed
unrecognized rows, but dropped the rows themselves and could still emit a
limitation describing an unparsed_lines field the result never carried.
ADB parsers now own unrecognized-line facts as a bounded sample (first ten)
plus the exact total, and a single provider projection derives
unparsed_lines, coverage, and the truncation limitation from those facts for
every parsed listing and the package search. The resolver result schema now
carries unparsed_lines, matching list_adb_packages through CLI and MCP.
Fixes#5843
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* test(cli): keep IPC trace input under the Linux spawn limit
The listener-callsite CLI builds one trace argument from the full
application Evidence document. On 4 KiB-page Linux that string exceeds
MAX_ARG_STRLEN, so spawn throws E2BIG before the command starts. Keep the
document in a file, require the spawned argv to fit the single-argument
budget, and lock that budget through the test process registry.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* test(process): size the spawn ceiling from ARG_MAX and MAX_ARG_STRLEN
A payload at the single-string limit still fails execve with E2BIG when
the stack shrinks ARG_MAX below the rest of the image. Accept only the
bytes that fit both budgets, and skip that success spawn when the fixed
argv and environment already fill ARG_MAX.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* style(test): format files rejected by oxfmt in static checks
check:ci:fast failed format:check on the CLI fixture import and, after
merging main, on the admission test's new command-abort case.
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>
Retain process input and unexpected failure diagnostics through the shared error projector. Preserve filesystem causes and firmware validation issues, and mark unchanged invalid requests nonretryable.
Use typed stat settlement and parse unknown command failures without losing null or undefined rejection causes.
Refs #5397, #5401, #5402, #5642
Derive Darwin subprocess test budgets from the bounded ownership compiler budget while preserving short command deadlines. Always join the retained command scope after test failures.
Refs #5094.
Prepare native process ownership outside short command deadlines. Reuse the shared cleanup adapter and resource scope for direct/nested preparation failures and command cleanup.
Fixes#5094.
Use shared owned command supervision for all evaluation helpers, join streamed output, and retain/retry incomplete cleanup before deleting run files.
Fixes#5094.
Preserve listing-backed facts and explicit unavailable decompiler facets when one function fails. Retain Evidence while excluding transient failures and derived workflows from snapshot reuse; keep healthy cache reuse and owned cleanup semantics.
Fixes#4644.
Export an authenticated capture and environment manifest as a pinned agentenv bundle with provenance, a replay verifier and smoke task.
Followups preserve immutable input ownership, bounded discovery, caller paths and numeric values; bind bundle writes and package copying to retained filesystem owners; verify POSIX modes; retain cleanup authority; and verify framework/npm executable selection. Default MCP remains stdio.
Validation: pinned Linux toolchain, typecheck/build/lint/format/docs/knip, 452 focused tests, ten product-catalog cases, real GitHub response replay in the generated non-root Docker image, and the real pinned agentenv framework smoke workflow. Platform and resource-measurement limits are recorded in the feature verification document.
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Serve retained capture Evidence as a bounded MCP replay environment with discovery.
Preserve default stdio, caller-selected facts and complete source Evidence.
Fix numeric fidelity, argument identity, startup cancellation and bounded discovery,
query/path matching and output metadata. Verify real recorded API data and public
CLI/MCP workflows; preserve explicit gaps for Windows and third-party hosts.
Co-authored-by: Edgar Arakelyan <edgar.arakelyan@scale.com>
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(process): classify baseline cleanup with current ownership facts
Use the pre-launch baseline only to select candidates for current native
identity/token validation. Preserve confirmed absence and verified foreign
generations instead of carrying a premature baseline identity failure.
Exercise the real Linux enumeration/exit race and retain countercontrols for
unknown identities and live token-owned processes.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
* fix(ci): distinguish process inventory from historical PID lookups
* test(ci): verify decoded historical PID controls before tracing
* fix(ci): trace historical PID handles and signal probes
* fix(ci): resolve traced directory paths across pathname syscalls
Classify producer-decoded FD/path pairs once instead of limiting failed relative
lookup detection to openat on /proc. This preserves attempted readlinkat, statx
and newfstatat accesses with no returned descriptor.
Three regression cases fail against the previous policy and all 33 controls
pass with the shared pathname interpretation.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
* test(ci): declare unresolved legacy pathname coverage
Report the historical-PID access surfaces actually checked and explicitly mark
legacy cwd-relative pathname calls unverified. The existing tracer does not
provide their cwd identity, and a blanket rejection also rejects legitimate
GDB build-ID metadata queries.
Retain every committed access guard and document the preexisting limit without
claiming absence from missing path evidence. The complete real 44-case CLI/MCP
recorded-crash qualification passes with the coverage declaration.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
* fix(ci): reject priority access to historical PIDs
* fix(ci): preserve C-quoted components in traced path checks
strace renders non-ASCII pathname bytes as C octal escapes, not JSON strings.
Keep those components opaque when resolving literal ASCII path separators and
proc PID selectors, matching the existing absolute-path interpretation.
Two controls fail before the correction and all 35 pass afterward. An actual
strace observation independently reproduces the rejection of an unrelated
Chinese filename and verifies the corrected classification.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
* fix(ci): reject historical PID resource and scheduler calls
* fix(schema): preserve portable large base64 validation
* fix(ci): share explicit PID syscall contracts with tracing
Derive tracer selection and reported coverage from the same named target
contracts used by the access checker. Cover resource limits, scheduler calls,
process metadata, PID groups, capabilities and pidfd operations without mixing
UIDs, policy enums, self selectors or output values with target PIDs.
Interpret each target once and retain unresolved target facts as a distinct
failure. Emit the coverage catalog once per verifier result.
The previous oracle misses 28 new controls. All 83 controls pass after the
change; real native resource/scheduler probes capture 14 previously missed
calls with resource limits and affinity unchanged. All 35 selected syscall
names are accepted by the pinned local strace.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
* fix(ci): classify I/O priority and qualify PID trace coverage
* fix(process): keep ownership retries on the native clock
* fix(ci): retain process edges in ownership trace inventory
Keep fork/vfork and resumed edges along with clone events so the shared attribution owner receives the complete process relation facts it consumes.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
* fix(process): type native exit predicates and ownership fixtures precisely
* fix(ci): retain trace coverage limits after integration
Restore explicit unverified symlink aliases and same-Node stat/status purpose in the shared coverage contract and guide. The native-exit and trace-attribution integration does not establish those properties. Preserve both limitations rather than silently broadening the reported qualification.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
Add an explicit Streamable HTTP entry for environment/gateway hosts while keeping stdio registrations and default behavior. Preserve the shared provider/session owner across DELETE and replacement; fence and drain tool/completion work before handover or teardown.
Bound HTTP input and plain-response admission, cancel refused bodies, join whole exchanges and asynchronous response cleanup before provider hooks, gate startup readiness, and reject queued HTTP/1.1 pipelining while retaining sequential keep-alive.
Validation: 8 static/build tasks, 83 adapter tests and registry metadata pass. A real installed gh binary produces seven equivalent CLI/stdio/HTTP reports with DELETE/replacement and clean signal shutdown. Broader local native-provider/ownership failures reproduce on clean main and are documented with limitations in the PR.
Co-authored-by: Edgar Arakelyan <edgar.arakelyan@scale.com>
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>