Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a606f2ae52 | ||
|
|
b1c7c27d3c | ||
|
|
2edf3b23c1 | ||
|
|
e7c90802e9 | ||
|
|
c8ed328538 | ||
|
|
ef5ab1f1f2 | ||
|
|
14877a069b | ||
|
|
d85e0fffe4 | ||
|
|
37e61613d9 | ||
|
|
7aa1b51282 | ||
|
|
538017d1d2 | ||
|
|
b8c1b45316 | ||
|
|
407a718050 | ||
|
|
51be954c4b | ||
|
|
c537c52c96 | ||
|
|
6f96d7a3fa | ||
|
|
7590b50801 | ||
|
|
bd5d189a8f | ||
|
|
89268f4a45 | ||
|
|
3637205622 | ||
|
|
b4f9f0deac | ||
|
|
ec0e663cca | ||
|
|
26356dc34a | ||
|
|
b928963675 | ||
|
|
8451b961ad | ||
|
|
4a4bbab3c3 | ||
|
|
e5d2805b42 | ||
|
|
6f28b3633b | ||
|
|
c0eb612780 | ||
|
|
27dc9735e4 | ||
|
|
51e0df97e9 | ||
|
|
292fd532c9 | ||
|
|
aa7d960ef5 | ||
|
|
0b7213c890 | ||
|
|
63fe0eb5db | ||
|
|
ddce4bb446 | ||
|
|
dd3497e133 | ||
|
|
4f54379831 | ||
|
|
d77bc0e8a0 | ||
|
|
527ade245a | ||
|
|
dbcec4cf56 | ||
|
|
34fd7bdf7d | ||
|
|
81ab0ddc95 | ||
|
|
306ca984bc | ||
|
|
dd46a13dec | ||
|
|
ce5bc8cb01 | ||
|
|
b88bdfccd2 | ||
|
|
34aa22d0aa | ||
|
|
719d56ebfe | ||
|
|
87c8086fc1 | ||
|
|
eab4e47916 | ||
|
|
db87917daa | ||
|
|
183b4d4e7e | ||
|
|
00819258a7 | ||
|
|
c465ff5a81 | ||
|
|
1ac7ce3f3b | ||
|
|
55f5c8db69 | ||
|
|
5b0373db11 | ||
|
|
73be86c39e | ||
|
|
8dbe92a4a3 | ||
|
|
5a28a147f1 | ||
|
|
13a8640204 | ||
|
|
09b29436f4 | ||
|
|
421d527bfe | ||
|
|
24bd2b989a | ||
|
|
b2fad362f2 | ||
|
|
247c8f4eab | ||
|
|
adfde012ec | ||
|
|
57fd3ea5d8 | ||
|
|
d8948efb81 | ||
|
|
3966c92c71 | ||
|
|
1fbfbf74ef | ||
|
|
2604059961 | ||
|
|
6b44e35bec | ||
|
|
20bf7d957f | ||
|
|
c9f95eaf90 | ||
|
|
a2805bc934 | ||
|
|
b7529304f0 | ||
|
|
22c4b528d2 | ||
|
|
1158dc2a94 | ||
|
|
2765fc12bb | ||
|
|
18669641e9 | ||
|
|
cdd718ffb0 | ||
|
|
c5c5ff45aa | ||
|
|
5da3b7c393 | ||
|
|
2451e187be | ||
|
|
5e6529521c | ||
|
|
7cec547ecc | ||
|
|
c1a0561bf3 | ||
|
|
fafc1881b5 | ||
|
|
a59abe932e | ||
|
|
452e3ccad1 | ||
|
|
8413ec08f7 | ||
|
|
603a7d022c | ||
|
|
b2dc45006d | ||
|
|
1828cf87a0 | ||
|
|
a73eac190b | ||
|
|
0e5c511c01 | ||
|
|
2e6b38cef0 | ||
|
|
d7ca93cc2c | ||
|
|
82e4e032df | ||
|
|
ca2ca16146 | ||
|
|
14c4c2a1d7 | ||
|
|
4842f23765 | ||
|
|
7721d59e1a | ||
|
|
76dbc32f39 | ||
|
|
f23066f0da | ||
|
|
cbbd317fb5 | ||
|
|
d54c4345d3 | ||
|
|
bdf0be87c6 | ||
|
|
0155b89953 | ||
|
|
166fb0820f | ||
|
|
3dbe314ada | ||
|
|
f5acf82a78 | ||
|
|
a721c42c07 | ||
|
|
087813fb88 | ||
|
|
4e28166626 | ||
|
|
7ffae5a791 | ||
|
|
2aadcf7d04 | ||
|
|
b0a554cc3a | ||
|
|
414ad52b20 | ||
|
|
3cfdc585b4 | ||
|
|
4fe88a7e3f | ||
|
|
f4cabe535f | ||
|
|
6bc4ec3a74 | ||
|
|
1dcaa77693 | ||
|
|
0da36910dc | ||
|
|
55c3129224 | ||
|
|
dbd556043c | ||
|
|
b28f6c0953 | ||
|
|
3220e17b8b | ||
|
|
cc4ed5b904 | ||
|
|
126b6e20d4 | ||
|
|
8fe8622e09 | ||
|
|
1a945ce9ff | ||
|
|
d8199ab6af | ||
|
|
f6e4e0296f | ||
|
|
4c20744f1c | ||
|
|
3dce8326c9 | ||
|
|
fd64b1c240 | ||
|
|
d2015e94f3 | ||
|
|
7fdf7a5b79 | ||
|
|
7cdf8bc5cf | ||
|
|
465e1a1f36 | ||
|
|
f3537db34f | ||
|
|
48e7470041 | ||
|
|
2947a77507 | ||
|
|
ae09e3fe70 | ||
|
|
67a6477f01 | ||
|
|
3dde9a5e1c | ||
|
|
07fd426e9a | ||
|
|
0583fc69be | ||
|
|
a0214e0e0e | ||
|
|
01788bac86 | ||
|
|
aa51e43439 | ||
|
|
01ee6551b4 | ||
|
|
d8a9673fc4 | ||
|
|
f86206535f | ||
|
|
8e3bf56e11 | ||
|
|
dc53c11f6d | ||
|
|
d4c637f4cf | ||
|
|
4dfa1c67dc | ||
|
|
1f92c77398 | ||
|
|
2319166c2e | ||
|
|
63b43b69bb | ||
|
|
c8d3f8f8ec | ||
|
|
4423b6fff2 | ||
|
|
5df59ee1fd | ||
|
|
6d356b8434 | ||
|
|
c538a843cb | ||
|
|
25e1a24a3e | ||
|
|
705058f3e2 | ||
|
|
35d6d5bb0a | ||
|
|
5b014a739e | ||
|
|
ce1f4b1bba | ||
|
|
d124809950 | ||
|
|
7f9a492a8d | ||
|
|
c2bee63e99 | ||
|
|
905cbaf239 | ||
|
|
33f912919d | ||
|
|
aa53c06538 | ||
|
|
bcfcd8b6e2 | ||
|
|
efab044f30 | ||
|
|
647717c050 | ||
|
|
c76edbebbe | ||
|
|
c324d31b45 | ||
|
|
5eebe2fdf8 | ||
|
|
ea3534759f | ||
|
|
19f2969c56 | ||
|
|
d9767eb48f |
No files matched your search
@@ -167,7 +167,9 @@ explicit path or endpoint and do not need it.
|
||||
ambiguity. No implicit fetch or target execution; WAT is not original source.
|
||||
See the [WASM guide](https://github.com/morluto/rea/blob/main/docs/wasm-artifacts.md).
|
||||
- Explicit local EVM bytecode carrier: `inspect_evm_interface` with caller-selected
|
||||
`raw` or `hex` encoding. Preserve carrier/decoded digests and treat selectors,
|
||||
`raw` or `hex` encoding. The owned worker deadline is `timeout_ms` (default
|
||||
30000 ms, range 1..2147483647, next call). It does not raise the fixed byte,
|
||||
address-space, or CPU allowances. Preserve carrier/decoded digests and treat selectors,
|
||||
argument strings and mutability as inferred candidates; this performs no chain
|
||||
lookup or target execution. For the complete inferred interface without hex or
|
||||
duplicate stdout, discover support and select `detail: "summary"`; complete
|
||||
@@ -181,6 +183,8 @@ explicit path or endpoint and do not need it.
|
||||
absent metadata does not prove a binary is not Go, and unparsed text records
|
||||
remain explicit. See the
|
||||
[Go binary guide](https://github.com/morluto/rea/blob/main/docs/go-binaries.md).
|
||||
- Embedded CUDA/HIP code objects: `inspect_gpu_code_objects`; inventory targets
|
||||
first, then decode selected payloads and query retained GPU Evidence.
|
||||
- Bundled GGUF or safetensors model declarations: `inspect_model_artifact`
|
||||
with the explicit local file. Default header hashing leaves full-file identity
|
||||
unknown; `hash: "full"` additionally reads all weights for SHA-256. MCP returns
|
||||
@@ -215,6 +219,12 @@ explicit path or endpoint and do not need it.
|
||||
delivery requires `--evidence_output`.
|
||||
See the
|
||||
[Rust binary guide](https://github.com/morluto/rea/blob/main/docs/rust-binaries.md).
|
||||
- ELF note tables: `inspect_elf_notes` with the explicit local ELF32/ELF64
|
||||
file. This built-in target-free inspection requires no disassembler. Preserve
|
||||
PT_NOTE and SHT_NOTE ranges, owners, types, descriptor SHA-256, and GNU
|
||||
build-id or ABI-tag fields. A missing table is observed absence of those
|
||||
declarations, not proof the image never carried notes. See the
|
||||
[ELF notes guide](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
|
||||
- Explicit local SQLite database snapshot: `inspect_sqlite_database`. Inspect
|
||||
with Node.js 24.x >=24.15 or 26+ providing native SQLite limits. Read schema
|
||||
|
||||
@@ -25,8 +25,9 @@ stdio. A full JDK, including `jdk.compiler`, is required on every host; Windows
|
||||
`JAVA_HOME` selects `bin\java.exe`. Consult the Android guide for actual host
|
||||
verification coverage. Calls use one worker and provider deadlines; optional
|
||||
`REA_JADX_HEAP_MIB` selects the JVM heap and `REA_JADX_OPERATION_TIMEOUT_MS`
|
||||
the per-operation deadline (default 120000 ms; the MCP client's tool timeout
|
||||
must also allow it). The APK is never launched,
|
||||
the per-operation deadline (integer milliseconds from 1 to 2147483647, default
|
||||
120000; a change applies on the next process start; the MCP client's tool
|
||||
timeout must also allow it). The APK is never launched,
|
||||
and no emulator is required.
|
||||
|
||||
Manifest entries and decompiled text are static observations, not execution or
|
||||
|
||||
@@ -93,4 +93,14 @@ Use `view: {kind: "environment-state"}` with the manifest's `template_rules` to
|
||||
extract the data those reads observed instead: entity types and identity
|
||||
fields, entities with recorded values, documents, and per-tool render plans
|
||||
checked against the recordings. The state comes only from reads before the
|
||||
first related write; types, identity and list membership are inferences.
|
||||
first related write; types, identity and list membership are inferences. The
|
||||
view also gives each state-changing tool a write plan, served only when a later
|
||||
recorded read confirms its effect and none contradicts it.
|
||||
`rea environment-serve manifest.json --evidence capture.json` derives that
|
||||
state at startup, answers read tools from it, serves the write tools whose plan
|
||||
is served, each applying its effect to that state, and serves `data/reset`,
|
||||
`data/add` and `data/get` on `/agentenv`; other write tools are not served, and
|
||||
each plan states why in its `reason`. It replays the capture instead with
|
||||
`--replay-only` or when the state is unavailable (not derivable, or a catalog
|
||||
over the discovery budget), and its stopped document's `state` says which
|
||||
applied.
|
||||
@@ -22,6 +22,11 @@ requires complete application analysis; `source_paths: []` is invalid, not an
|
||||
unfiltered request. `detail: "summary"` reduces delivery
|
||||
and does not by itself reduce analysis work.
|
||||
|
||||
ASAR header/index admission defaults to 16 MiB / 16777216 bytes;
|
||||
`REA_ASAR_MAX_HEADER_BYTES` (at most 256 MiB, set where REA starts) changes it.
|
||||
`source_paths`, `detail`, and `max_heap_mb` do not bypass or raise it. Or
|
||||
analyze an extracted directory.
|
||||
|
||||
Exact `#alias` specifiers resolve through the importer's
|
||||
enclosing package `imports` map to package-local files; nested `node_modules`
|
||||
packages use their own map. Wildcard, recursive, and external-package import
|
||||
|
||||
@@ -45,7 +45,8 @@ See [desktop installations](https://github.com/morluto/rea/blob/main/docs/deskto
|
||||
|
||||
## Go build metadata
|
||||
|
||||
Use `inspect_go_binary` for an explicit local ELF, PE or thin Mach-O when the
|
||||
Use `inspect_go_binary` for an explicit local ELF, PE or Mach-O (universal
|
||||
files need `architecture`) when the
|
||||
question concerns the embedded compiler version, module/dependency versions,
|
||||
local replacements or build settings. No `open_binary`, Go installation or
|
||||
target execution is required. The CLI equivalent is `inspect-go-binary PATH`.
|
||||
@@ -84,7 +85,8 @@ See [IL2CPP metadata](https://github.com/morluto/rea/blob/main/docs/il2cpp-metad
|
||||
|
||||
## Rust dependency metadata
|
||||
|
||||
Use `inspect_rust_binary` for an explicit local ELF, PE, or thin Mach-O when
|
||||
Use `inspect_rust_binary` for an explicit local ELF, PE, or Mach-O (universal
|
||||
files need `architecture`) when
|
||||
the question concerns the cargo-auditable crate list embedded in `.dep-v0`
|
||||
(Mach-O: `__DATA,.dep-v0`). No `open_binary`, Rust installation, or target
|
||||
execution is required. The CLI equivalent is `inspect-rust-binary PATH`.
|
||||
@@ -94,6 +96,17 @@ dependencies. An omitted package kind stays null. A rustc commit hash is
|
||||
inferred from a read-only `/rustc/<40-hex>/` path and does not by itself
|
||||
identify the compiler. See [Rust binaries](https://github.com/morluto/rea/blob/main/docs/rust-binaries.md).
|
||||
|
||||
## ELF note tables
|
||||
|
||||
Use `inspect_elf_notes` for an explicit local ELF32/ELF64 image when the
|
||||
question concerns PT_NOTE/SHT_NOTE owners, GNU build-id, or GNU ABI-tag
|
||||
fields. No `open_binary` or target execution is required. The CLI equivalent
|
||||
is `inspect-elf-notes PATH`. Preserve artifact SHA-256, table file ranges,
|
||||
descriptor hashes, and original owner spellings. A missing table is observed
|
||||
absence of those declarations, not proof the image never carried notes in
|
||||
another container. See
|
||||
[ELF note tables](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
|
||||
## SQLite snapshots
|
||||
|
||||
Use `inspect_sqlite_database` with an explicit local database snapshot for its
|
||||
@@ -345,8 +358,8 @@ every executable in the bundle. It also lists missing or weak loads and earlier
|
||||
`architecture`. System paths stay undetermined because the dyld shared cache
|
||||
provides them.
|
||||
|
||||
Use `extract_artifact` when materialized files are needed. It extracts the active
|
||||
target and accepts optional `integrity_policy`; see the [MCP contracts](https://github.com/morluto/rea/blob/main/docs/mcp-contracts.md).
|
||||
Use `extract_artifact` when materialized files from a supported format are needed.
|
||||
It extracts the active target and accepts optional `integrity_policy`; see the [MCP contracts](https://github.com/morluto/rea/blob/main/docs/mcp-contracts.md).
|
||||
It materializes all regular files into a fresh temporary directory chosen by
|
||||
REA. Symlinks and encrypted entries are inventory facts, not extractable files.
|
||||
The result reports the materialized directory; callers do not choose the
|
||||
@@ -355,14 +368,19 @@ destination. No separate permission grant is needed.
|
||||
Native DMG traversal automatically uses a read-only mount on supported macOS
|
||||
hosts, with an owned temporary mount directory and cleanup. It needs no approval
|
||||
flag. Unsupported hosts or mount failures remain explicit limitations; do not
|
||||
claim child inventory when only root identity is available. Extraction is a
|
||||
separate filesystem-writing operation.
|
||||
claim child inventory when only root identity is available. DMG extraction is
|
||||
unavailable through `extract_artifact`. To access DMG files on macOS, create a
|
||||
read-only mount with your own tools, select files from that mount for analysis,
|
||||
and detach the mount you created when finished. REA's inspection mount is
|
||||
temporary, not a retained export of the image's contents.
|
||||
|
||||
For headerless DOS COM, explicitly open with `format: "dos-com"` (CLI
|
||||
`--target-format dos-com`). Inspect the load image before trusting function
|
||||
analysis: the entry is `0x10100`, file offset zero, with imposed real-mode segment
|
||||
context. PSP/stack/device state remains unmodeled. See [DOS guide](https://github.com/morluto/rea/blob/main/docs/ghidra-dos.md).
|
||||
|
||||
Use `inspect_byte_entropy` to triage high- and low-entropy ranges before extraction.
|
||||
|
||||
For other headerless images (embedded firmware without ELF/Mach-O/PE/MZ
|
||||
headers), open with `format: "raw-binary"`, `architecture` (`x86`, `x86_64`,
|
||||
`arm`, `arm64`, `6502`, or `m68k`), and `entry_point` (`0x` hex). File offset 0 is mapped at
|
||||
|
||||
@@ -819,6 +819,11 @@ jobs:
|
||||
with:
|
||||
save: "true"
|
||||
- run: npm ci
|
||||
- name: Typecheck with the official Windows compiler
|
||||
env:
|
||||
GOMAXPROCS: "2"
|
||||
GOMEMLIMIT: "3GiB"
|
||||
run: npm run typecheck -- --checkers 2
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: rea-build-cache
|
||||
@@ -849,7 +854,11 @@ jobs:
|
||||
npx vitest run --coverage.enabled=false
|
||||
src/process/capture/FilesystemSnapshot.test.ts
|
||||
tests/process-global/filesystemSnapshotFallbackCancellation.test.ts
|
||||
tests/boundary/filesystem/typescriptCompiler.test.ts
|
||||
tests/boundary/filesystem/binaryTarget.test.ts
|
||||
src/contracts/sessionPathInputs.test.ts
|
||||
tests/boundary/filesystem/directAnalysisSnapshotReplay.test.ts
|
||||
tests/boundary/mcp/rawBinaryMcp.test.ts
|
||||
tests/boundary/filesystem/safeOutputTree.test.ts
|
||||
tests/boundary/providers/native/artifactProvider.archiveSafety.test.ts
|
||||
tests/boundary/providers/native/artifactProvider.extractionCompleteness.test.ts
|
||||
@@ -866,6 +875,7 @@ jobs:
|
||||
tests/boundary/process/packageNpmInvocation.test.ts
|
||||
tests/boundary/process/packedBridgeVerification.test.ts
|
||||
tests/boundary/process/windowsOutputCapture.test.ts
|
||||
tests/boundary/process/windowsPrivateRuntimeAclObserver.test.ts
|
||||
tests/acceptance/webModuleCli.test.ts
|
||||
tests/acceptance/webSourceLocationCli.test.ts
|
||||
tests/boundary/cli/referenceSourceImportStatus.test.ts
|
||||
|
||||
@@ -90,6 +90,12 @@ Setup supports Claude Code, Codex, Cursor, Gemini CLI, Grok Build and
|
||||
[installation and setup](docs/installation.md) for provider configuration and
|
||||
manual MCP registration.
|
||||
|
||||
MCP uses compact input schemas by default to reduce context overhead. Set
|
||||
`REA_MCP_INPUT_SCHEMA_PROFILE=full` in your MCP registration when you need the
|
||||
complete advertised field guidance and nested validation details. Both profiles
|
||||
keep the full tool set and canonical server validation. See
|
||||
"Compact input schema profile" in the MCP contracts guide.
|
||||
|
||||
### Ask your agent
|
||||
|
||||
```text
|
||||
@@ -180,10 +186,12 @@ Additional tools and host support depend on the target:
|
||||
| Native binaries | Pseudocode, assembly, strings, symbols, calls and references | Hopper, Ghidra or IDA; [native analysis](docs/native-investigation.md) |
|
||||
| Offline ELF layout | Sections, segments, original symbols/relocations and static mitigation candidates | Caller-supplied pwntools on Linux x64; [binary diagnostics](docs/binary-diagnostics.md) |
|
||||
| Go binaries | Embedded compiler version, modules, replacements and build settings | Built-in static ELF/PE/thin Mach-O inspection; no Go installation required |
|
||||
| GPU code objects | CUDA/HIP targets, selected kernel parameters and resources, retained PTX text | Built-in static ELF/PE/fatbin/CUBIN/PTX inspection; [GPU code objects](docs/gpu-code-objects.md) |
|
||||
| Model artifacts | GGUF / safetensors metadata, tensor declarations and derived totals | Built-in header inspection; optional full-file hash; [model files](docs/model-artifacts.md) |
|
||||
| IL2CPP metadata | Unity global-metadata.dat assembly images, type and method names and index ranges | Built-in static decoding of versions 24, 27, 29, 31 and 39; no Unity required |
|
||||
| Godot PCK | Archive inventory and extraction, original header/directory facts and selected content identities | Built-in static formats 2, 3 and 4; no Godot required |
|
||||
| Rust binaries | Embedded cargo-auditable crate names, versions, sources and dependency edges | Built-in static ELF/PE/thin Mach-O inspection; [Rust binaries](docs/rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](docs/elf-notes.md) |
|
||||
| WASM artifact | Validation, sections, exact import/export WAT forms and decoded WAT | Caller-supplied WABT 1.0.42; `inspect_wasm_artifact` |
|
||||
| EVM bytecode | Dispatch selectors, byte offsets, inferred arguments and mutability | Local raw/hex carrier on Linux x64; [offline EVM guide](docs/evm-bytecode.md) |
|
||||
| SQLite databases | Tables, columns, indexes, views, triggers and selected ordinary-table rows | Local database/WAL snapshot; Node.js 24.x >=24.15 or 26+ with native SQLite limits |
|
||||
|
||||
@@ -32,6 +32,7 @@ export default defineConfig({
|
||||
{ text: "IL2CPP metadata", link: "/il2cpp-metadata" },
|
||||
{ text: "Model artifacts", link: "/model-artifacts" },
|
||||
{ text: "Rust dependencies", link: "/rust-binaries" },
|
||||
{ text: "ELF notes", link: "/elf-notes" },
|
||||
{
|
||||
text: "JavaScript and Electron",
|
||||
link: "/javascript-artifact-reconstruction",
|
||||
|
||||
@@ -162,8 +162,9 @@ and during shutdown.
|
||||
APKs keep other names report the `unknown` role rather than guessing.
|
||||
- **Partial results keep facts.** Failed individual pulls return successful
|
||||
artifacts with `coverage: "partial"` and per-file `failures`. Listings
|
||||
that contain unrecognized lines report them as `unparsed_lines` and mark
|
||||
partial coverage instead of dropping rows.
|
||||
and package searches that contain unrecognized lines report the first ten
|
||||
as `unparsed_lines`, state the exact total in a limitation when more were
|
||||
seen, and mark partial coverage instead of dropping rows.
|
||||
- **Mutations are explicit.** `push_adb_file`, `install_adb_package`, and
|
||||
`uninstall_adb_package` declare `mutatesTarget` and never run implicitly:
|
||||
pushes check for existing device files before transfer and refuse them
|
||||
@@ -171,7 +172,9 @@ and during shutdown.
|
||||
transfer even with `overwrite`; only a clean `test -e` exit of 1 with no
|
||||
output is interpreted as absence. The check is not atomic, so a different
|
||||
process can create the path before `adb push` writes it. When available, the device's
|
||||
`sha256sum` verifies the transfer; installs preserve the
|
||||
`sha256sum` verifies the transfer. A missing command or output without a
|
||||
recognizable digest reports `device_digest_source: "unavailable"` with an
|
||||
unverified-transfer limitation; installs preserve the
|
||||
device's `Failure [...]` reason verbatim.
|
||||
- **Producer identity stays attached.** Every result embeds the producing
|
||||
adb client (`binary_path`, `path_source`, `version`, `installed_path`).
|
||||
@@ -183,9 +186,11 @@ and during shutdown.
|
||||
The app/activity lifecycle tools use `am start -W` and `am force-stop`.
|
||||
- Per-invocation budgets: client/devices 10-20 s, shell reads 20-60 s with
|
||||
64 KiB-8 MiB capture caps (logcat 4 MiB, screen 32 MiB), transfers and
|
||||
bugreports 600 s. Output capture overflow reports `resource_constraint`;
|
||||
deadline expiration, including the client-version probe, reports
|
||||
`provider_timeout`. Command cancellation preserves the caller's exact reason;
|
||||
bugreports 600 s. Output capture overflow reports `resource_constraint`
|
||||
and names the byte allowance. Deadline expiration, including the
|
||||
client-version probe, reports `provider_timeout` and names the effective
|
||||
milliseconds. This release has no runtime override for those deadlines or
|
||||
capture caps. Command cancellation preserves the caller's exact reason;
|
||||
a later abort does not replace an already completed command failure.
|
||||
- Pull and capture outputs are additive: the destination must not already
|
||||
exist. Re-running a completed pull refuses the existing directory instead
|
||||
|
||||
+374
-51
@@ -1,11 +1,16 @@
|
||||
# Agent environments from recorded captures
|
||||
|
||||
Use `rea environment-serve` to serve an environment manifest as an agent
|
||||
environment: an MCP server whose tools answer from the records of one retained
|
||||
web network capture, plus the environment card the agentenv framework reads to
|
||||
discover it. Nothing is fetched from the recorded application; every answer is
|
||||
retained Evidence. `rea environment-export` writes the same pair as a bundle
|
||||
folder `agent-env run` builds and runs; see [Export a bundle](#export-a-bundle).
|
||||
environment: an MCP server whose tools answer from what one retained web
|
||||
network capture observed, plus the environment card the agentenv framework
|
||||
reads to discover it. By default the server derives the
|
||||
[state the capture observed](#the-state-a-capture-observed) at startup and
|
||||
answers read tools from it, and the write tools whose effect the capture
|
||||
confirmed by changing it; `--replay-only` replays the capture's records
|
||||
instead. Nothing is fetched from the recorded application; every answer comes
|
||||
from retained Evidence. `rea environment-export` writes the same pair as a
|
||||
bundle folder `agent-env run` builds and runs; see
|
||||
[Export a bundle](#export-a-bundle).
|
||||
|
||||
```sh
|
||||
rea inspect-web-network-capture /absolute/session.har har --format json > capture.json
|
||||
@@ -27,9 +32,10 @@ it, where `view.json` wraps the capture Evidence as the inline source:
|
||||
}
|
||||
```
|
||||
|
||||
The third command serves that manifest. Both served files are complete REA
|
||||
Evidence JSON as the commands write it with `--format json`; the `evidence`
|
||||
member of `view.json` is the whole of `capture.json`.
|
||||
The third command serves that manifest from the state it derives from the
|
||||
capture; see [Serve from the state](#serve-from-the-state). Both served files
|
||||
are complete REA Evidence JSON as the commands write it with `--format json`;
|
||||
the `evidence` member of `view.json` is the whole of `capture.json`.
|
||||
|
||||
## From a browser scenario
|
||||
|
||||
@@ -110,7 +116,9 @@ record's ordinal is its zero-based position; a transaction whose URL carried a
|
||||
redacted secret is left unrepresented rather than templated, and one the
|
||||
capture cannot attribute to a single request and response is left
|
||||
unrepresented too. Tools are chosen by response media type, so a scenario that
|
||||
selected neither response bodies nor header values is refused. The browser
|
||||
selected neither response bodies nor header values is refused; one that
|
||||
selected header values but no response bodies yields a manifest but no state,
|
||||
so it is served by replay. The browser
|
||||
scenario redacts credential headers and the secrets it declares; values the
|
||||
application returns in response bodies, such as session tokens, are kept, and
|
||||
the replayed body is the bytes the browser exposes for each response, with any
|
||||
@@ -144,10 +152,16 @@ This was calibrated with 1500 query fields and eight concurrent SDK discovery
|
||||
requests (183,798-byte card, 507.27 MiB sampled process-family RSS). Over-capacity
|
||||
catalogs return `resource_constraint`, retain complete input Evidence, and require
|
||||
a smaller capture or manifest. Fields and tools are never silently omitted.
|
||||
Served from the state, each description is longer and the card declares the
|
||||
data plane, so a catalog replay admits can exceed the reservation; the state
|
||||
is then unavailable and the server serves replay instead (see
|
||||
[Serve from the state](#serve-from-the-state)).
|
||||
|
||||
## What replay means and does not mean
|
||||
|
||||
Each MCP tool call selects one of the records its manifest tool cites and
|
||||
Replay answers every tool with `--replay-only` or when the state is unavailable,
|
||||
and, served from the state, each read tool whose view the state does not back.
|
||||
Each such MCP tool call selects one of the records its manifest tool cites and
|
||||
returns that record's recorded response. Selection compares the supplied path
|
||||
parameters against the record's path segments at the parameter indexes, then
|
||||
the supplied query values against the record's query string, and keeps the
|
||||
@@ -202,7 +216,8 @@ degrades into an omitted one.
|
||||
Replay is not emulation. A served environment does not establish the
|
||||
application's authorization model, response semantics or state transitions,
|
||||
which the manifest lists as unknowns; it does not validate supplied values; and
|
||||
it does not answer requests the capture never recorded. Replayed content is
|
||||
it answers only from the capture's recordings and the state they observed or a
|
||||
caller loaded through `data/add`. Replayed content is
|
||||
target content: every tool result, including the argument errors the MCP server
|
||||
returns before a replay runs, carries `_meta.provenance.untrusted_content: true`
|
||||
with `source: "analysis_target"`. The server advertises REA's untrusted-content
|
||||
@@ -220,17 +235,23 @@ moment of the capture recorded them. The
|
||||
[environment state](web-network-captures.md#environment-state) view extracts
|
||||
instead the data the capture's reads observed before the first related write:
|
||||
entity types with an identity field, entities with their recorded values,
|
||||
documents for written paths, and a render plan per read tool, kept only where
|
||||
it reproduces that tool's recordings from the state. It is the starting state
|
||||
an environment can hold, load and report; serving from it is a later increment
|
||||
and does not change replay.
|
||||
documents for reads that are not entities, and a render plan per read tool,
|
||||
kept only where it reproduces that tool's recordings from the state. It is the
|
||||
starting state an environment holds, loads and reports: `environment-serve`
|
||||
derives it from the capture at startup; see
|
||||
[Serve from the state](#serve-from-the-state). With `--replay-only`, replay is
|
||||
unchanged.
|
||||
|
||||
## Serve a manifest
|
||||
|
||||
```sh
|
||||
rea environment-serve manifest.json --evidence capture.json [--host 127.0.0.1] [--port 0]
|
||||
rea environment-serve manifest.json --evidence capture.json [--replay-only] [--host 127.0.0.1] [--port 0]
|
||||
```
|
||||
|
||||
The server derives the state from the capture before it binds and serves from
|
||||
it, or serves replay with `--replay-only` or when the state is unavailable;
|
||||
see [Serve from the state](#serve-from-the-state).
|
||||
|
||||
`--host` and `--port` default to `MCP_HOST` and `MCP_PORT` from the
|
||||
environment, then to `127.0.0.1` and an ephemeral port, exactly as
|
||||
[`rea mcp --http`](cli.md#serve-mcp-over-streamable-http) resolves them. The
|
||||
@@ -242,7 +263,8 @@ manifest's `name` is used, and a set but blank value is refused as
|
||||
listener serves one MCP client at a time with the same session, `Host` header
|
||||
and shutdown contract as [transports](mcp-contracts.md#transports) describes.
|
||||
It runs until SIGINT or SIGTERM, then closes the listener, prints one
|
||||
`{"status":"stopped", …}` document and exits `130` or `143`.
|
||||
`{"status":"stopped", …}` document whose `state` member says whether it served
|
||||
from the state, and exits `130` or `143`.
|
||||
Signals during input loading or DNS/bind cancel the owning reader/listener before
|
||||
a listening announcement;
|
||||
that path returns a structured `cancelled` result instead of a stopped-listener
|
||||
@@ -250,19 +272,19 @@ document, with the same signal exit status.
|
||||
|
||||
Three routes are served:
|
||||
|
||||
| Route | Answer |
|
||||
| --------------------------------- | ---------------------------------------------------------------------- |
|
||||
| `POST /mcp` | The MCP server: one tool per manifest tool, replaying retained records |
|
||||
| `GET /.well-known/agent-env.json` | The environment card |
|
||||
| `POST /agentenv` | JSON-RPC `-32601 method not found: <method>` for every method |
|
||||
| Route | Answer |
|
||||
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `POST /mcp` | The MCP server: from the state, one tool per read tool, answering from the state where it backs them, and one per write tool whose effect the capture confirmed, applying it to the state; in replay, one tool per manifest tool, replaying records |
|
||||
| `GET /.well-known/agent-env.json` | The environment card |
|
||||
| `POST /agentenv` | From the state, `data/reset`, `data/add` and `data/get`; in replay, JSON-RPC `-32601 method not found: <method>` for every method |
|
||||
|
||||
Numeric JSON-RPC IDs outside JavaScript's safe range or whose precision would
|
||||
be lost are refused as invalid requests with a null ID. They are never echoed
|
||||
as a different number.
|
||||
|
||||
The data plane at `/agentenv` is advertised by the card but carries no
|
||||
operations in this release; the error names the requested method so a caller
|
||||
can see that the method, not the transport, is unsupported. Its request body is
|
||||
In replay the data plane at `/agentenv` is advertised by the card but carries
|
||||
no operations; the error names the requested method so a caller can see that
|
||||
the method, not the transport, is unsupported. Its request body is
|
||||
read within the same 4 MiB bound the MCP endpoint applies: a larger body is
|
||||
answered `413` with a JSON-RPC `-32000` error before any of it is parsed, and a
|
||||
body that is not JSON is answered `400` with `-32700`. A notification (no `id`)
|
||||
@@ -274,7 +296,7 @@ that are not an object or array) gets `-32600 invalid request`.
|
||||
## The environment card
|
||||
|
||||
The card is the discovery document the agentenv framework reads before
|
||||
connecting to `/mcp`:
|
||||
connecting to `/mcp`. A replay environment's card reads:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -288,7 +310,7 @@ connecting to `/mcp`:
|
||||
"tools": [
|
||||
{
|
||||
"name": "get_users_by_id",
|
||||
"description": "GET /api/users/{numeric}; replays retained records [5, 6]; evidence ev_…",
|
||||
"description": "Untrusted captured API catalog: … GET /api/users/{numeric}; returns a JSON object with fields \"id\", \"uid\", \"login\", \"email\"; recorded statuses 200; replays retained records [5, 6]; evidence ev_…",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -309,7 +331,38 @@ connecting to `/mcp`:
|
||||
```
|
||||
|
||||
`capabilities.tools` lists the same names, descriptions and input schemas that
|
||||
`tools/list` advertises over MCP. Path parameters are required strings whose
|
||||
`tools/list` advertises over MCP. After the catalog warning, each description
|
||||
names the method and path template, then what the tool returns, one level deep:
|
||||
`returns a JSON object with fields …`, `returns a JSON array of objects with
|
||||
fields …` or `returns a JSON object whose <member> lists objects with fields …`,
|
||||
where a list is an array of objects found by the
|
||||
[environment state](web-network-captures.md#environment-state)'s list rule (the
|
||||
root array, or the one array of objects an envelope carries). Field and member
|
||||
names are written as JSON strings, so a captured name cannot read as more of
|
||||
the description; a member name too long to show whole is a quoted prefix marked
|
||||
as truncated. The summary comes
|
||||
from the first cited `2xx` record that replay answers as JSON; only when none
|
||||
did, the first cited JSON record of another status gives it, labelled with that
|
||||
status (`status 401 returns …`). It describes one recorded response, not a
|
||||
contract. Field names are sampled within the same budget as other captured
|
||||
values, and the manifest's `statuses` for the tool follow; a tool with no JSON
|
||||
record states only its statuses. The description then lists the replayed
|
||||
records and the evidence ID, and the whole catalog stays within its
|
||||
serialization reservation, which the summaries and MCP annotations are charged
|
||||
to.
|
||||
|
||||
Over MCP, every tool also carries annotations: `readOnlyHint` is true for the
|
||||
safe methods (`GET`, `HEAD`, `OPTIONS` and `TRACE`) and for query `POST`s (a
|
||||
path segment such as `search` or `query`); `destructiveHint` is true for `DELETE` and left unset for other
|
||||
writes, so the MCP default (destructive) applies to them, and read-only tools
|
||||
omit it because clients ignore it there; `idempotentHint` is true for the safe
|
||||
methods, `PUT` and `DELETE`; and `openWorldHint` is false for every tool,
|
||||
because answers come from the capture rather than the captured application. The
|
||||
hints describe the captured method; replay itself changes nothing. The card
|
||||
keeps the `name`, `description` and `inputSchema` of the echo example's tool
|
||||
shape and carries no annotations.
|
||||
|
||||
Path parameters are required strings whose
|
||||
description names the segment index, the templating rule and the observed
|
||||
values (sampled within the list budget above; the manifest keeps them all);
|
||||
query parameter names are optional strings; write methods accept an
|
||||
@@ -320,9 +373,254 @@ advertised as `query_<name>`, a query name longer than 64 characters as
|
||||
and the write body as `request_body` when a query parameter is named `body`. Every
|
||||
schema closes with `additionalProperties: false`, a key the echo example's
|
||||
schema does not carry.
|
||||
`extensions`, `operations` and `children_environments` are fixed to `null`,
|
||||
`[]` and `null`: a replay environment declares no extensions, no data-plane
|
||||
operations and no children.
|
||||
In replay, `extensions`, `operations` and `children_environments` are fixed to
|
||||
`null`, `[]` and `null`: a replay environment declares no extensions, no
|
||||
data-plane operations and no children. Served
|
||||
[from the state](#serve-from-the-state), the card declares the three data-plane
|
||||
operations and one intake extension instead, and the catalog holds the read
|
||||
tools and only the write tools whose effect the capture confirmed: a read tool
|
||||
is described as answering from the state where the state backs it, and a
|
||||
served write tool by the effect it applies to the state and the body members it
|
||||
accepts.
|
||||
|
||||
## Serve from the state
|
||||
|
||||
```sh
|
||||
rea environment-serve manifest.json --evidence capture.json
|
||||
```
|
||||
|
||||
Before it binds, the server derives the
|
||||
[environment state](web-network-captures.md#environment-state) the capture
|
||||
observed: it runs the `environment-state` view on the capture in-process with
|
||||
the manifest's `template_rules` in the same order, exactly as
|
||||
`inspect-analysis-view` projects it from the same capture, so the state
|
||||
Evidence id it reports is the one that projection produces. The view's own
|
||||
budget and refusals apply, and the result is checked like the view's Evidence
|
||||
for this manifest: extracted from the served capture, with the manifest's
|
||||
rules, naming only manifest tools. The server keeps one live state, shared by
|
||||
every MCP session and the data plane, starting from the derived state.
|
||||
|
||||
A state that is unavailable does not stop the server: it logs a warning naming
|
||||
the error `code` and message before it binds, then serves replay. The state is
|
||||
unavailable when it cannot be derived, such as from a
|
||||
`capture_browser_scenario` capture that selected header values but no response
|
||||
bodies or over the view's budget, when `data/get` would write it past the 32 MiB
|
||||
`data/add` intake limit, and when its catalog under the served name
|
||||
exceeds the [discovery reservation](#what-a-manifest-is). That check runs
|
||||
first, so no state is derived for it, and replay is then admitted exactly as
|
||||
with `--replay-only`. `--replay-only`
|
||||
serves replay without deriving anything; the card, tools and `/agentenv`
|
||||
answers are then exactly those of replay. The stopped document's `state`
|
||||
member reports which applied:
|
||||
|
||||
- `{"served": true, "evidence_id": "ev_…"}`: served from the derived state.
|
||||
- `{"served": false, "reason": "replay-only"}`: `--replay-only` was given.
|
||||
- `{"served": false, "reason": "unavailable", "code": "unsupported_target", "message": "…"}`:
|
||||
the state is unavailable; `code` and `message` are those of the refusal
|
||||
(`resource_constraint` for a catalog over the reservation), as the warning
|
||||
logged them.
|
||||
|
||||
Each read tool answers according to its view in the state:
|
||||
|
||||
| View | Answer |
|
||||
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `item` | The entity the path arguments name, rendered into the recorded envelope of `envelope_ordinal`. Arguments match as replay matches them: each collection segment equals the held collection's segment as written or after percent-decoding, and the identity is the last argument percent-decoded, then as written; values are never re-split on `/`. Any entity the state holds answers, including one `data/add` loaded; query arguments only decide `replay.exact_match`. An entity the state does not hold answers the tool's latest recorded 400, 404 or 410 response with `state.view` `missing`, or is a tool error when none was recorded; one lacking a field every recording carried is a tool error; a body is never invented. |
|
||||
| `list` | When the arguments name one of the lines the view checked exactly (its latest recordings before the first related write; every path and query value equal to the recording's, and every recorded query parameter supplied), that recorded envelope with its array rendered from the state: every entity of the collection in state order for `membership: "all"`, or the recorded members still held. A call with no query argument to a `membership: "all"` view answers from a checked line of the collection its path arguments name that only pages its list, with `replay.exact_match` false. A member lacking a field every recording carried makes the call a tool error rather than a partial list. |
|
||||
| `document` | When the arguments name the document's checked line exactly, the state's value for it; a tool error when the state holds none. |
|
||||
| `recorded` | The recording, as replay answers it. |
|
||||
|
||||
A list or document call that names no checked line, including a line recorded
|
||||
after a write or with other query values, answers from the recording. Every
|
||||
answer has the replay shape plus `state`: `{"source": "state", "view": …}`
|
||||
naming the entity, collection or document path, or `{"source": "recording",
|
||||
"reason": …}` with the view's reason, `no-view`, `unrecorded-request` or `page-exceeded` (a call naming a page of a whole list that the collection has outgrown). A
|
||||
state answer carries the base record's status, content type and `replay`
|
||||
provenance with `truncated: false`; one whose JSON would exceed 256 KiB is
|
||||
refused as a `resource_constraint` tool error rather than cut. Extraction does
|
||||
not state-back a document whose rendered JSON exceeds 256 KiB; that read stays
|
||||
recorded (`rendered-oversize`) and replays the captured body. Query `POST`s
|
||||
stay served and answer from their recordings with the reason `query-body`.
|
||||
|
||||
`POST`, `PUT`, `PATCH` and `DELETE` tools are served only when the state's
|
||||
[write plan](web-network-captures.md#environment-state) for them is served:
|
||||
the capture's later reads confirmed the effect the plan models. Other write
|
||||
tools are not served, so no call claims a change it does not make; each one's
|
||||
plan states why in its `reason`. A served write changes the live state, which
|
||||
every MCP session and `data/get` then see:
|
||||
|
||||
| Effect | Call |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `create` | Adds an entity to the collection the path names, built from the observed entity with each ruled field taken from the call or generated, at the plan's `insert` position. A plan tied to its exemplar's collection writes only there. |
|
||||
| `update` | Sets the sent members on the entity the path names, constants for members accepted only with their recorded value, and the clock, increment and slug changes the plan models. |
|
||||
| `delete` | Removes the entity the path names. |
|
||||
| `document` | Merges the body into the plan's document object, or replaces it for `PUT`. |
|
||||
|
||||
Its answer has the status and content type of the plan's recorded response,
|
||||
with the written entity or its identity rendered in, no body, or the recorded
|
||||
body. A call whose body is not an object, sends a member the capture did not
|
||||
show stored, sends a fixed member with another value or a member of another
|
||||
JSON type, or lacks a required member is a tool error naming the accepted
|
||||
members; so is a rendered answer missing a field the recorded response
|
||||
carried, and an update or delete of an entity the state does not hold answers
|
||||
the recorded 400, 404 or 410 of the tool or of an item view of the type, if
|
||||
any. A refused call leaves the state unchanged. Values a write generates are
|
||||
deterministic: the clock starts at `write_clock` and advances one second per
|
||||
served write, sequences take one past both the largest held value and the
|
||||
largest they generated, and UUIDs and tokens derive from the state Evidence
|
||||
id, tool, field and write count, skipping held values. `data/reset` and
|
||||
`data/add` restart the clock, counter and sequences, so the same calls after a
|
||||
reset give the same state. Answers carry `state: {"source": "state", "view":
|
||||
"create" | "update" | "delete", …}` or `"document-write"`.
|
||||
|
||||
The data plane serves three JSON-RPC methods:
|
||||
|
||||
| Method | Result |
|
||||
| ------------ | --------------------------------------------------------------------------------------------------------- |
|
||||
| `data/reset` | `{}` after restoring the state the Evidence holds |
|
||||
| `data/add` | `{}` after replacing the whole state with one valid `rea-state/v1` document |
|
||||
| `data/get` | `{"parts": [{"kind": "data", "data": <rea-state/v1 document>}]}` with `state_evidence_id` and the `types` |
|
||||
|
||||
Calls run one at a time in arrival order across requests. Every message of a
|
||||
batch is queued when the batch arrives, so another request's call never lands
|
||||
between them and each message sees the changes of those before it; a reset
|
||||
sent while a download is loading applies after that load. `data/add`
|
||||
takes exactly one part: a `data` part whose `data` is the document, or a
|
||||
`file` part whose `file` carries `bytes` (base64 of UTF-8 JSON) or a `uri`,
|
||||
either a `file://` URL of a local regular file, whose host is empty or
|
||||
`localhost`, or an `https://` URL fetched without following redirects and
|
||||
within 30 seconds, including reading the body; `mimeType`, when given, is
|
||||
`application/json`. A `file://` URL naming another host, or a UNC path such as
|
||||
`file:////server/share/state.json`, is refused before anything is opened, so a
|
||||
load never reaches a network share. A loaded document is at most 32
|
||||
MiB, and so is the state as `data/get` writes it back with the members a
|
||||
document may omit (`types`, `state_evidence_id`, record citations), so a
|
||||
reported state always loads again; an inline part also stays within the 4 MiB
|
||||
request body bound, so larger states arrive by `uri`. Anything else, including `{"parts": []}`, is `-32602
|
||||
invalid params`; a download that fails or answers a non-2xx status is
|
||||
`-32000`. Errors never echo the uri or the content; a file or download failure
|
||||
names its category in `error.data.reason`: `not-found`, `permission`,
|
||||
`not-regular-file`, `changed` or `read-failed` for files, `timeout`,
|
||||
`http-status` or `network` (connection, TLS or a refused redirect) for
|
||||
downloads, and `cancelled` for a download the server's stop or its caller's
|
||||
departure ended.
|
||||
|
||||
Served creates also bound additional collection history since the last reset
|
||||
or `data/add` to 1 MiB of deterministic accounting: UTF-8 bytes for each new
|
||||
collection spelling and its possible sequence keys, plus a 64-byte allowance
|
||||
per collection and potential sequence-key record. The score bounds identifier
|
||||
payload and a fixed record allowance; it is not a measurement or guarantee of
|
||||
process memory. Collections
|
||||
already present in the Evidence or loaded state are part of the state itself;
|
||||
the store indexes their unique spellings so they remain known after deletion,
|
||||
but they do not consume this additional-history budget. A create that would
|
||||
exceed the budget is refused before the state changes. `data/reset` or `data/add`
|
||||
clears generated history; if the same calls would hit the limit again, use
|
||||
fewer distinct collection paths. The 1 MiB score ceiling is 1/32 of the
|
||||
separate 32 MiB state-intake ceiling, reserving a small, explicit allowance
|
||||
for identifiers retained beyond the loaded state. A loaded-state path that is
|
||||
later deleted and then introduced again may consume the additional-history
|
||||
budget when the store must retain it beyond the source entity.
|
||||
|
||||
Stopping the server cancels every pending call, and a caller that leaves before
|
||||
its reply cancels its own: a download in progress ends, and calls not yet run
|
||||
are answered `-32000` with `error.data.reason` `cancelled` without running. A
|
||||
cancelled call leaves the state unchanged, and shutdown never waits for a
|
||||
download.
|
||||
|
||||
One `/agentenv` response carries at most 64 MiB of replies, twice the 32 MiB
|
||||
a loaded document may hold: room for a `data/get` of a loaded state, while a
|
||||
batch of reads cannot multiply a large state into one body. Replies are
|
||||
measured in order as they are produced, in bounded parts and before they are
|
||||
assembled, and room is kept for every later reply's budget error and the
|
||||
batch's brackets and commas, so one that would take the response past the
|
||||
budget is never built whole and is answered instead with `-32000` whose `error.data` gives
|
||||
`max_response_bytes` and the `reply_bytes` it would have taken. That call still
|
||||
ran, so repeat such a read in another request. A reply no larger than that
|
||||
error, such as a write's `{}`, is always kept.
|
||||
|
||||
```json
|
||||
{
|
||||
"rea_state": {
|
||||
"version": 1,
|
||||
"entities": [
|
||||
{
|
||||
"type": "/api/users",
|
||||
"collection": "/api/users",
|
||||
"id": "2",
|
||||
"fields": { "id": 2, "login": "probe" }
|
||||
}
|
||||
],
|
||||
"documents": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Each entity's `type` is a state type's `collection_template`, its `collection`
|
||||
matches that template segment by segment (a template parameter matches any one
|
||||
segment), its identity field's value is its `id`, and its type, collection and
|
||||
id are unique; `view_fields` is optional and names item or list views of its
|
||||
type. Views render their values over the entity's fields, so a view's values
|
||||
must not set the type's identity field to a value whose text differs from the
|
||||
entity's `id`. Spell a collection as requests spell it, as `data/get` reports it: list
|
||||
calls find entities under the checked line's recorded path. Each document
|
||||
names a `document` view once, at its initial document's `path`. The `version`,
|
||||
and the `state_evidence_id` and `types` that `data/get` reports, must match
|
||||
the served state, so a `data/get` result loads back unchanged. A number without
|
||||
an exact native value, or whose serialized spelling would not be read as exact
|
||||
(an integer from 2^53 below 1e21, such as `1e20`, in any spelling), or a
|
||||
`__proto__` member is refused rather than altered.
|
||||
An invalid document is `-32602` naming the first problem by JSON pointer, as in
|
||||
`/rea_state/entities/3/collection` (also in `error.data.path`); a problem
|
||||
inside caller data (`fields`, `value`, `types`) is located at that member, so
|
||||
the pointer never names the caller's keys. A refused document changes nothing;
|
||||
a valid one replaces the whole state at once. The order of `entities` is the
|
||||
state order lists use.
|
||||
|
||||
Record citations stay Evidence provenance. An entity's `record_ordinals` may
|
||||
be omitted or empty and a document's `record_ordinal` omitted; otherwise they
|
||||
must be the served Evidence's citations for that entity or document, or the
|
||||
document is refused. After loading, an entity or document whose values equal the Evidence's cites
|
||||
the Evidence's records, and one whose values were edited or added cites none
|
||||
(`record_ordinals: []`, no `record_ordinal`), so `data/get` never presents a
|
||||
loaded value as recorded.
|
||||
|
||||
The card declares the operations and what `data/add` accepts:
|
||||
|
||||
```json
|
||||
{
|
||||
"extensions": [
|
||||
{
|
||||
"uri": "urn:agentenv:intake/v1",
|
||||
"description": "data/add replaces the whole environment state with one rea-state/v1 document; data/get returns the current state in the same format.",
|
||||
"params": {
|
||||
"add": [
|
||||
{ "part": "data", "format": "rea-state/v1", "load": "replace" },
|
||||
{
|
||||
"part": "file",
|
||||
"format": "rea-state/v1",
|
||||
"mimeTypes": ["application/json"],
|
||||
"load": "replace"
|
||||
}
|
||||
],
|
||||
"get": [{ "part": "data", "format": "rea-state/v1" }]
|
||||
}
|
||||
}
|
||||
],
|
||||
"operations": ["data/reset", "data/add", "data/get"]
|
||||
}
|
||||
```
|
||||
|
||||
The state starts as a projection of recorded reads and changes only through
|
||||
served write tools and the data plane. List and document calls answer from the
|
||||
state only for the lines their views checked, and every recorded view answers
|
||||
from recordings; item calls answer for any held entity but render only the
|
||||
envelope one recording carried. Values copied outside entity objects, derived
|
||||
values and counters other than those that count a list stay as recorded, and a
|
||||
served write changes only the one entity or document it writes: side effects
|
||||
on counters, relations and copies of entities in other collections, reordering
|
||||
after an update and referential rules on delete are not modelled. An exported
|
||||
bundle carries no state file: its server derives the state at startup, as the
|
||||
export does to predict what it serves.
|
||||
|
||||
## Export a bundle
|
||||
|
||||
@@ -336,12 +634,12 @@ agent-env run ./grafana-example
|
||||
|
||||
```text
|
||||
grafana-example/
|
||||
README.md provenance, replay limits, run command, rights note
|
||||
README.md provenance, what it serves, run command, rights note
|
||||
envs/grafana-example/Dockerfile pinned image: node:24.18.0-bookworm-slim + rea-agents@<this version>
|
||||
envs/grafana-example/env.toml environment_name = "grafana-example"
|
||||
envs/grafana-example/manifest.json byte-exact copy of manifest.json
|
||||
envs/grafana-example/evidence.json byte-exact copy of capture.json
|
||||
artifacts/check_grafana-example/verify.py the replay verifier
|
||||
artifacts/check_grafana-example/verify.py the verifier
|
||||
tasks/smoke.json deploy_env (local sandbox), then env_outcome_verifier
|
||||
```
|
||||
|
||||
@@ -352,8 +650,12 @@ pair as `environment-serve` does, so a manifest projected from another capture
|
||||
is refused with the same `invalid_request` before anything is written, and the
|
||||
bytes it copies are the bytes it authenticated. The bundle directory must be
|
||||
absent or empty; an occupied directory is refused and nothing in it changes.
|
||||
The complete tool catalog must also fit the server's advertised catalog budget
|
||||
before any files are written. Privately parsed JSON is sealed once so authentication
|
||||
After checking the bundle name, the export prepares the state from the capture
|
||||
exactly as the bundle's server will at startup under that name, to predict what
|
||||
the bundle serves; an unavailable state, including one whose catalog exceeds
|
||||
the discovery reservation, does not stop the export, and the bundle then
|
||||
serves replay. The complete tool catalog the bundle serves must also fit the
|
||||
server's advertised catalog budget before any files are written. Privately parsed JSON is sealed once so authentication
|
||||
and replay share immutable response trees rather than copying the capture repeatedly.
|
||||
`--name` replaces the manifest's portable kebab-case name as the env folder and env id
|
||||
(Windows device names such as `con` and `lpt1` are refused);
|
||||
@@ -361,7 +663,9 @@ and replay share immutable response trees rather than copying the capture repeat
|
||||
folder and makes the Dockerfile install it instead of the registry package and
|
||||
remove it in the same layer, which is how a checkout rather than a release is
|
||||
run. The command prints the
|
||||
written files with their sizes and the pinned package source.
|
||||
written files with their sizes, the pinned package source, the number of tools
|
||||
the bundle serves as `tool_count`, and in `state` whether it serves from the
|
||||
state, in the shape of the serve command's stopped document.
|
||||
|
||||
Export uses the shared output-tree owner to check directory identities around
|
||||
exclusive creates, verify written bytes, and reject unowned entries before
|
||||
@@ -383,21 +687,32 @@ user, so a private host umask cannot leave them unreadable, runs as that user an
|
||||
name from Python sources the image does not have.
|
||||
|
||||
`verify.py` is the framework's `async def verify(mcp_url)` shape over its
|
||||
Python MCP client: it lists the tools and checks the count equals the
|
||||
manifest's, calls the first `GET` tool without path parameters with no
|
||||
arguments and checks the call did not fail and its replayed `status` equals the
|
||||
recorded status of that tool's first cited record (an unknown recorded status
|
||||
stays unknown; it is not borrowed from another record), and returns one
|
||||
`replay` result whose description
|
||||
reports both checks. A manifest with no such tool yields a verifier that checks
|
||||
the count only and says so. `tasks/smoke.json` deploys the env on the local
|
||||
Python MCP client: it lists the tools and checks the count equals the number
|
||||
the bundle serves (from the state, the manifest's read tools and the write
|
||||
tools whose effect the capture confirmed; every manifest tool in replay), calls one tool with no arguments and checks the call did not
|
||||
fail and its `status` is the expected one, and returns one `serve` result
|
||||
whose description reports both checks. The tool is the first served `GET` tool
|
||||
without path parameters whose answer to no arguments is not an error, and the
|
||||
expected status is the status of that answer: the export calls the same answer
|
||||
function the server uses, from the derived state or by replay, so a state
|
||||
answer carries its base record's status and a replayed one its record's (an
|
||||
unknown recorded status stays unknown; it is not borrowed from another
|
||||
record). A bundle with no such tool yields a verifier that checks the count
|
||||
only and says so. `tasks/smoke.json` deploys the env on the local
|
||||
sandbox and runs that verifier against the env's MCP endpoint; the first run
|
||||
also builds the framework's own infrastructure, and the run tears everything
|
||||
down when it ends.
|
||||
|
||||
The README written into the bundle records the capture artifact's SHA-256, the
|
||||
capture and manifest Evidence ids, the manifest view digest, the tool count and
|
||||
the package source, and states that the recorded content belongs to the
|
||||
capture and manifest Evidence ids, the manifest view digest, the served tool
|
||||
count, the derived state's Evidence id or that no state is served, and the
|
||||
package source. It says what the environment serves: read tools from the state
|
||||
the capture observed, the `/agentenv` data plane on it and the write tools
|
||||
whose effect the capture's later reads confirmed, replay when the state is
|
||||
unavailable, and `--replay-only` for pure replay; it
|
||||
says which applies to this bundle, with the error code and message when the
|
||||
state is unavailable, and that neither is emulation and served
|
||||
content is untrusted data. It states that the recorded content belongs to the
|
||||
captured application and must not be published without the rights to it.
|
||||
|
||||
## Compatibility verification
|
||||
@@ -414,13 +729,21 @@ framework versions.
|
||||
|
||||
## Resource and lifecycle boundaries
|
||||
|
||||
Both Evidence files are read once at startup through the bounded JSON input
|
||||
The Evidence files are read once at startup through the bounded JSON input
|
||||
reader and authenticated as Evidence before the listener binds; a file that is
|
||||
not Evidence, a manifest of another view kind, a capture of another format, or
|
||||
a manifest projected from a different capture is refused before any port is
|
||||
opened. Because authentication covers the capture's records, a manifest whose
|
||||
opened. The state is derived once, in-process and before binding, from the
|
||||
already authenticated capture: it is projected as retained Evidence, so the
|
||||
capture's strings are not charged again as inline view input, and the view's
|
||||
96 MiB budget bounds the derivation. Because authentication covers the capture's records, a manifest whose
|
||||
parent check passes cites only records the capture retains. The server keeps
|
||||
only the cited records' request lines and response text in memory. No outbound
|
||||
network request is made, no process is launched and nothing is written to
|
||||
disk. A listener that fails after binding is logged and ends the command with
|
||||
only the cited records' request lines and response text in memory, plus the
|
||||
live state when it serves from one: the derived initial state, or one
|
||||
validated document whose JSON was at most 32 MiB. Data-plane calls run one at a time, so
|
||||
at most one loaded document is being read and parsed at once; `data/get`
|
||||
serializes the held state whole. No process is launched and nothing is
|
||||
written to disk. No outbound network request is made unless a `data/add` call names an
|
||||
`https://` uri, which is fetched once within the limits above; a `file://` uri
|
||||
is read once. A listener that fails after binding is logged and ends the command with
|
||||
a `resource_constraint` error and exit `1` instead of serving nothing.
|
||||
@@ -335,9 +335,12 @@ export REA_JADX_OPERATION_TIMEOUT_MS=600000
|
||||
```
|
||||
|
||||
The value must be a decimal millisecond count from 1 to 2147483647; anything
|
||||
else is refused before Java starts. The same deadline bounds each upstream
|
||||
call, a timeout reports the selected value, and a passing JADX configuration
|
||||
check in `rea doctor` reports the effective `operation_timeout_ms`. Explicit
|
||||
else is refused before Java starts. REA reads it from the environment captured
|
||||
at process start. A change applies on the next process start; an already
|
||||
running server keeps the deadline it started with. The same deadline bounds
|
||||
each upstream call. A timeout names `REA_JADX_OPERATION_TIMEOUT_MS`, the
|
||||
effective milliseconds, and that range. A passing JADX configuration check in
|
||||
`rea doctor` reports the effective `operation_timeout_ms`. Explicit
|
||||
cancellation still ends the operation immediately, and partial observations
|
||||
and owned-process cleanup are unchanged. Raising the deadline does not extend
|
||||
the bridge's 30-second startup handshake or the upstream **90-second**
|
||||
|
||||
@@ -65,6 +65,7 @@ rea decode-android-resources /targets/Example.apk --locale de
|
||||
rea decode-android-resources /targets/Example.apk --locales de --locales pt-BR
|
||||
rea decode-android-resources /targets/Example.apk --locales de --locales pt-BR --string-tables-only
|
||||
rea decode-android-resources /targets/Example.apk --no-strings
|
||||
rea decode-android-resources /targets/Example.apk --decode-timeout-ms 900000
|
||||
```
|
||||
|
||||
Equivalent MCP methods are `inspect_apktool_client` and
|
||||
@@ -133,9 +134,14 @@ still suppresses all string projection, including in this mode.
|
||||
|
||||
## Resource and lifecycle limits
|
||||
|
||||
- The decode runs with a 600 s deadline and a 4 MiB output capture budget;
|
||||
a stopped decode reports `provider_timeout` and exceeded budgets report
|
||||
`resource_constraint`.
|
||||
- The decode wall clock is `decode_timeout_ms` (CLI `--decode-timeout-ms`).
|
||||
Omitted means 600000 ms. The integer range is 1 to 2147483647. A change
|
||||
applies on the next decode. It does not raise the 4194304-byte (4 MiB)
|
||||
output capture budget. That capture budget has no runtime override. A
|
||||
stopped decode reports `provider_timeout` and names the effective
|
||||
milliseconds; an exceeded capture budget reports `resource_constraint`.
|
||||
- The version probe waits 20000 ms and retains 65536 bytes. This release has
|
||||
no runtime override for that probe. `decode_timeout_ms` does not raise it.
|
||||
- Manifest reads are bounded to 512 KiB before decoding UTF-8. Strings XML
|
||||
reads are bounded to 8 MiB; larger documents are skipped with partial
|
||||
coverage and an explicit limit, rather than reported as missing.
|
||||
|
||||
@@ -215,3 +215,87 @@ Large Evidence envelopes may require a caller-configured MCP transport receive
|
||||
buffer because envelope copies add overhead. Requests honor cancellation during
|
||||
snapshot reading, directory traversal and payload hashing. The operation reads
|
||||
regular files only and rejects symbolic links.
|
||||
|
||||
## Byte entropy triage
|
||||
|
||||
`inspect_byte_entropy` / `inspect-byte-entropy` profiles any local regular file
|
||||
without an analysis engine, execution, extraction or network access.
|
||||
|
||||
```sh
|
||||
rea inspect-byte-entropy ./firmware.bin --block-size 4096 --json
|
||||
rea inspect-byte-entropy ./firmware.bin --offset 4096 --length 65536 --json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_byte_entropy",
|
||||
"arguments": { "path": "/artifacts/firmware.bin", "detail": "summary" }
|
||||
}
|
||||
```
|
||||
|
||||
Complete Evidence includes `artifact` (original path, byte size and SHA-256),
|
||||
`block_size`, `window`, `file_entropy`, `thresholds`, `blocks`, `runs` and
|
||||
`limitations`. For a 4096-byte zero-filled file, the entropy fields are:
|
||||
|
||||
```json
|
||||
{
|
||||
"block_size": 4096,
|
||||
"window": { "offset": 0, "length": 4096 },
|
||||
"file_entropy": 0,
|
||||
"thresholds": { "high": 7.2, "low": 1 },
|
||||
"blocks": [{ "offset": 0, "length": 4096, "entropy": 0 }],
|
||||
"runs": [{ "offset": 0, "length": 4096, "classification": "low" }]
|
||||
}
|
||||
```
|
||||
|
||||
Offsets and lengths are decimal byte counts. Blocks begin at the requested
|
||||
`offset` (default zero); omitted `length` extends to EOF. Explicit windows past
|
||||
EOF fail rather than silently clipping. The final block may be shorter.
|
||||
`block_size` must be a power of two from 256 through 65536, default 4096. A
|
||||
window may produce at most 32,768 block rows; larger requests fail before the
|
||||
file scan with a capacity error. Choose a shorter window or larger block size.
|
||||
SHA-256 and `file_entropy` always cover the entire file, including when a window
|
||||
is selected. Empty files and empty windows are accepted; empty entropy is zero
|
||||
by convention. The tool reads the size the file reports. A file that reports size
|
||||
0, such as a Linux `/proc` entry, returns no blocks with a limitation that the
|
||||
result does not show the file is empty. File identity, size and timestamps are checked across the read;
|
||||
detected changes produce an error rather than Evidence.
|
||||
|
||||
Shannon entropy is reported in bits per byte from 0 to 8, rounded to four decimal
|
||||
places. Adjacent blocks with reported entropy at least 7.2 form `high` runs;
|
||||
blocks at most 1.0 form `low` runs. Other blocks interrupt runs. Entropy does not
|
||||
prove encryption, and this measure cannot distinguish encrypted from compressed
|
||||
data. Small blocks can underestimate entropy; the result is a triage clue.
|
||||
|
||||
MCP `detail: "summary"` retains complete Evidence in the session and returns
|
||||
file entropy, block/run counts, thresholds, the selected window, and the ten
|
||||
longest runs (ties ordered by file offset). Use its `parent_evidence_id` to
|
||||
retrieve complete Evidence, or request its summary with `inspect_analysis_view`.
|
||||
The CLI returns complete Evidence through the same service. Summary detail
|
||||
requires a session capable of retaining Evidence.
|
||||
|
||||
Reads use one block-sized buffer and a 256-entry histogram. Complete output
|
||||
can become very large because it includes one row per selected block, and
|
||||
summary delivery still retains that full list. Use a shorter length or a
|
||||
larger block size to reduce it. Full Evidence and its serialization require
|
||||
memory proportional to the number of selected blocks. The 32,768-row ceiling bounds the actual retained block objects and
|
||||
their serialized representation: a cap-sized run below produced 1,514,877
|
||||
serialized bytes and increased V8 heap use by 21.2 MiB on the measured host.
|
||||
The cap therefore bounds this output independently of file size; it is not a
|
||||
portable process-memory guarantee. Narrow the window or increase block size to
|
||||
reduce retained rows further.
|
||||
|
||||
Local service measurement (macOS arm64, Node 24.18.0, 100,000,000-byte file,
|
||||
4096-byte blocks, file already in the OS cache): first process run took 1.113 s
|
||||
wall / 1.148 s CPU with 145.3 MiB peak RSS; a second run in the same process took
|
||||
1.015 s / 1.035 s CPU, with cumulative peak RSS 155.8 MiB. Each read 100,000,000
|
||||
bytes and produced 24,415 blocks. Measurements include Evidence construction,
|
||||
summary projection and JSON serialization, with no child processes. Complete
|
||||
Evidence serialized to 1,122,303 bytes and its summary to 2,705 bytes. A
|
||||
cap-sized 134,217,728-byte sparse file with 4096-byte blocks produced 32,768
|
||||
rows and 1,514,877 serialized bytes; V8 heap use increased by 21.2 MiB and RSS
|
||||
by 18.1 MiB in that process. This separate measurement used the same macOS
|
||||
arm64 host and Node version. Cold disk I/O, token counts and an agent
|
||||
investigation were not measured; there was no previous equivalent tool to
|
||||
benchmark. These figures do not establish a portable peak-memory bound,
|
||||
constant memory for retained Evidence or faster agent task completion.
|
||||
+50
-30
@@ -18,7 +18,7 @@ Inspect native SAZ or HAR 1.2 offline with REA, or connect Everywhere's separate
|
||||
- `inspect_web_page` / `rea inspect-web-page` captures DOM structure, accessibility nodes, scripts, resources, safe response/DOM metadata, attach-window network and console metadata, WebSocket frame sizes, workers, quota, and optionally selected storage key names, redacted storage-content fingerprints, or script sources.
|
||||
- `analyze_web_bundle` / `rea analyze-web-bundle` parses selected script artifacts without execution and derives chunk edges, route and endpoint candidates, vendor fingerprints, static WebMCP declarations, and optionally source-map/original-source evidence.
|
||||
- `observe_web_session` / `rea observe-web-session` arms an observation window of the requested duration for an external user action and records ordered reload, SPA navigation, redirect, failure, lifecycle, and target-termination metadata.
|
||||
- `discover_webmcp_tools` / `rea discover-webmcp-tools` uses the experimental CDP WebMCP domain to return every in-scope registration and its complete observed `input_schema` declaration and canonical `input_schema_sha256` digest inline. Declarations are untrusted JSON data, including declared types, required fields, enums, examples and reference URLs. REA does not resolve schema references. These fields replace `input_schema_shape`. Registrations with the same name and URL in distinct observed frames retain separate identities. `tool_key` includes the observed frame ID; it is not a stable identity across navigation or browser sessions. Same-frame registration updates replace that owner only, and removal leaves other owners intact. Declared `readOnly`, `untrustedContent`, `consequential`, and `autosubmit` annotation hints are reported per registration: `true`/`false` are declared values, `null` means the declaration did not provide the hint in that capture, and a missing `consequential` key means the hint was not recorded, either in a historical capture or because the observed annotation was invalid. Consult discovery completeness and exclusions to distinguish these cases. Malformed annotation values retain the registration with incomplete coverage and an `invalid_protocol_value` exclusion. Other malformed protocol payloads can fail discovery explicitly. REA never exposes `WebMCP.invokeTool`.
|
||||
- `discover_webmcp_tools` / `rea discover-webmcp-tools` uses the experimental CDP WebMCP domain to return every in-scope registration and its complete observed `input_schema` declaration and canonical `input_schema_sha256` digest inline. Declarations are untrusted JSON data, including declared types, required fields, enums, examples and reference URLs. REA does not resolve schema references. These fields replace `input_schema_shape`. Registrations with the same name and URL in distinct observed frames retain separate identities. `tool_key` includes the observed frame ID; it is not a stable identity across navigation or browser sessions. Same-frame registration updates replace that owner only, and removal leaves other owners intact. Declared `readOnly`, `untrustedContent`, `consequential`, and `autosubmit` annotation hints are reported per registration: `true`/`false` are declared values, `null` means the declaration did not provide the hint in that capture, and a missing `consequential` key means the hint was not recorded, either in a historical capture or because the observed annotation was invalid. Consult discovery completeness and exclusions to distinguish these cases. Malformed annotation values or registration stacks retain the registration with incomplete coverage and an `invalid_protocol_value` exclusion. Other malformed protocol payloads can fail discovery explicitly. REA never exposes `WebMCP.invokeTool`.
|
||||
|
||||
- `compare_web_captures` / `rea compare-web-captures` compares passive captures or exact-step-aligned browser scenarios. Scenario results commit reproducible literal normalization and expose alignment failures plus artifact-level action, screenshot, DOM, accessibility, URL, history, storage, and event differences. Missing or truncated evidence is never treated as equivalence.
|
||||
|
||||
@@ -125,14 +125,11 @@ bundle, for example
|
||||
`"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"`. Fedora installs
|
||||
Chromium as `chromium-browser`.
|
||||
|
||||
REA needs the browser's HTTP discovery endpoint on a loopback port. A browser
|
||||
driven over `--remote-debugging-pipe` or a private channel, for example by an
|
||||
automation SDK, exposes no such endpoint, so `list_browser_targets` has nothing
|
||||
to attach to. Connection failures report `endpoint_unreachable`; a reachable
|
||||
HTTP service that returns a non-200 or non-JSON discovery response reports
|
||||
`invalid_endpoint_response`.
|
||||
Reproduce that flow in a Chromium-family browser started with
|
||||
`--remote-debugging-port`.
|
||||
REA attaches through the browser's HTTP discovery endpoint on a loopback port,
|
||||
or, for some passive tools, through a
|
||||
[browser socket](#browsers-without-http-discovery). Connection failures report
|
||||
`endpoint_unreachable`; a reachable HTTP service that returns a non-200 or
|
||||
non-JSON discovery response reports `invalid_endpoint_response`.
|
||||
|
||||
In a minimal Linux container, headed Chromium under Xvfb can keep running while
|
||||
its DevTools port never opens. Install the GLES, EGL, and Mesa DRI libraries
|
||||
@@ -184,7 +181,9 @@ file for you.
|
||||
the origins you are investigating.
|
||||
|
||||
A browser driven only through `--remote-debugging-pipe` or a vendor's private
|
||||
automation channel has neither endpoint, and REA cannot attach to it.
|
||||
automation channel has neither endpoint, and REA cannot attach to it. To
|
||||
inspect such a page, reproduce it in a Chromium-family browser started with
|
||||
`--remote-debugging-port`.
|
||||
|
||||
## Request boundary
|
||||
|
||||
@@ -361,7 +360,7 @@ REA retains local observation data and removes only URL userinfo credentials, ex
|
||||
WebSocket stream inventories and connection counts likewise require complete
|
||||
WebSocket coverage. Redirect resource types use only shared known metadata:
|
||||
an omitted type leaves equality unknown rather than proving a modification.
|
||||
- Console observations with a stack source retain call type, argument types, the CDP `Runtime.Timestamp` in milliseconds since Unix epoch, and source location. An absent or invalid timestamp is `null` and makes `console_events` incomplete; an observed zero remains zero. This epoch-millisecond clock is separate from the monotonic-second timestamps in `observe-web-session`. When console text capture is selected, already-delivered primitive values are retained verbatim; objects, getters, and remote properties are never expanded.
|
||||
- Console observations with a stack source retain call type, argument types, the CDP `Runtime.Timestamp` in milliseconds since Unix epoch, and source location. An absent or invalid timestamp is `null` and makes `console_events` incomplete; an observed zero remains zero. Argument types are listed by CDP argument position. An absent or non-array argument inventory is `null`, and a malformed argument keeps its position as `unknown`; either makes `console_events` incomplete, while an observed empty inventory remains `[]`. A malformed stack or top stack frame is not replaced by its caller: the console event is excluded, and a request initiator location or WebMCP `registration_source` is `null`; each is reported as `invalid_protocol_value`. This epoch-millisecond clock is separate from the monotonic-second timestamps in `observe-web-session`. When console text capture is selected, already-delivered primitive values are retained verbatim with their original `argument_index`; objects, getters, and remote properties are never expanded. Text capture is `unavailable` when the argument inventory is unknown.
|
||||
- WebSocket observations retain direction, opcode, and payload byte length. A missing or malformed CDP opcode is returned as `null`, with opcode-dependent payload byte length and shape also `null`, and marks `websocket_frames` incomplete. Missing or wrong-typed payload data is not treated as empty; its byte length is `null`, and a text payload shape is unknown. Numeric opcode `0` and an observed empty payload remain distinct from missing data. Opcode is nullable in the public inspection schema, so clients must handle unknown protocol values. When shape capture is selected, text messages are classified as text or complete value-free JSON shape; binary bytes, hashes, prefixes, and raw payloads are never retained.
|
||||
- Storage observations always redact values. Key names, IndexedDB names, and cache names require `include_storage_keys`; stable content fingerprints require the additional `include_storage_fingerprints` selection. Cookie fingerprints cover cookies applicable to the current main-frame URL, including its path, rather than every cookie path on that origin. Other storage remains scoped to the origin. Cache fingerprints hash all decoded response bytes, including bodies above 64 KiB, subject to the [64 MiB per-message CDP limit](#request-boundary). Missing or undecodable cache bodies and partial IndexedDB remote objects make fingerprint coverage incomplete, so identical observations remain `unknown`.
|
||||
- Unavailable or malformed storage inventories mark `storage_keys` unavailable, even without fingerprints. Comparisons suppress inferred key additions and removals while preserving modifications proven by complete fingerprints on both sides. Previously exported captures are not retroactively corrected; recapture them to obtain these coverage markers.
|
||||
@@ -386,7 +385,8 @@ section explicitly truncated.
|
||||
Disallowed-origin entries are filtered before retention.
|
||||
|
||||
Selected script-source collection shares a 32 MiB aggregate UTF-8 retention
|
||||
budget and a 20-second deadline across the capture. An oversized source is
|
||||
budget and the `command_timeout_ms` deadline (default 20000 ms) across the
|
||||
capture. The byte budget has no runtime override. An oversized source is
|
||||
omitted while later smaller sources may still fit. When the deadline expires,
|
||||
remaining source reads are skipped. Script metadata, per-item omission reasons,
|
||||
and `script_sources` completeness remain available. A single CDP response can
|
||||
@@ -394,19 +394,25 @@ still be materialized up to the separate 64 MiB transport limit before source
|
||||
admission; the retention budget does not bound that transient allocation.
|
||||
|
||||
Bundle parsing and semantic inspection run sequentially in an owned child,
|
||||
without executing captured code. `max_heap_mb` defaults to 1024 MiB V8
|
||||
old-space; `analysis_timeout_ms` defaults to 30000 per script, including startup
|
||||
and transfer. A failed or timed-out script becomes an explicit unknown while
|
||||
completed findings and later scripts remain available. `total_analysis_timeout_ms`
|
||||
defaults to 300000 across script analysis; expiry returns a typed timeout with
|
||||
partial Evidence and identifies unstarted scripts. These controls are also
|
||||
available as CLI flags with hyphenated names. Capture and optional source-map
|
||||
fetching have separate budgets.
|
||||
without executing captured code. These are separate phases. `max_heap_mb`
|
||||
defaults to 1024 MiB V8 old-space (range 128..16384). `analysis_timeout_ms`
|
||||
defaults to 30000 per script, including startup and transfer.
|
||||
`total_analysis_timeout_ms` defaults to 300000 across script analysis. A
|
||||
per-script deadline above the effective total is rejected. A failed or
|
||||
timed-out script becomes an explicit unknown while completed findings and later
|
||||
scripts remain available. Total-deadline expiry returns a typed timeout with
|
||||
partial Evidence and identifies unstarted scripts. `source_map_fetch_timeout_ms`
|
||||
defaults to 30000 and is an item limitation, not that analysis timeout. These
|
||||
controls are also available as CLI flags with hyphenated names. Worker protocol
|
||||
and result byte budgets have no runtime override.
|
||||
|
||||
One web-bundle capture/analysis is admitted per REA process at a time. Completed
|
||||
script results share an 8 MiB serialized transfer budget, with host heap
|
||||
reservation checked before decoding and validating another result.
|
||||
Exhausted result capacity stops further script launches and returns a typed
|
||||
When the host reservation is what reaches zero, the failure names that heap
|
||||
headroom and the remaining fixed budget. When the 8 MiB allowance itself is
|
||||
exhausted, the failure names that fixed budget and says it has no runtime
|
||||
override. Either stop ends further script launches and returns a typed
|
||||
resource failure with completed facts and explicit unstarted-script unknowns.
|
||||
Worker control frames are limited to 64 KiB. Cleanup must confirm child termination
|
||||
before releasing its private files; failed cleanup retains its exact owner and
|
||||
@@ -416,8 +422,10 @@ facts, including cancellation during final cleanup.
|
||||
The worker heap setting is not a process-family RSS limit. Node enforces V8
|
||||
old-space flags; Bun ignores them. Windows Bun instead uses an owned process
|
||||
commit limit with a 512 MiB runtime reserve; other Bun hosts have no enforced
|
||||
memory limit. These bounds do not establish an aggregate host-memory limit
|
||||
across other REA operations or external processes.
|
||||
memory limit. An allocation failure before that Windows limit is reported as
|
||||
reached still names the configured limit and says it was not reached. These
|
||||
bounds do not establish an aggregate host-memory limit across other REA
|
||||
operations or external processes.
|
||||
|
||||
Resource-tree inventories distinguish a valid empty `resources` array from a
|
||||
missing or malformed collection. Invalid resource entries are omitted with
|
||||
@@ -431,12 +439,24 @@ an invalid supplied size remains unknown with incomplete resource coverage while
|
||||
the resource's other facts are retained. Zero and nonnegative fractional sizes
|
||||
are preserved.
|
||||
|
||||
CDP discovery has a 10-second deadline. Each WebSocket handshake and command
|
||||
response has its own 20-second deadline, separate from the caller-selected
|
||||
observation window. A stalled handshake or command reports `provider_timeout`;
|
||||
caller cancellation still reports cancellation. WebSocket messages remain subject
|
||||
to the [64 MiB limit](#request-boundary). REA does not impose a message-count or
|
||||
pending-command quota. On cancellation, it closes only its own WebSocket,
|
||||
CDP discovery has a 10-second response deadline. HTTP discovery documents
|
||||
use an 8 MiB budget. Browser-socket discovery (`Browser.getVersion`,
|
||||
`Target.getTargets`) uses the 64 MiB protocol message budget. Neither budget
|
||||
nor the discovery deadline has a runtime override. `list_browser_targets` accepts no
|
||||
`command_timeout_ms`: HTTP discovery and browser-socket discovery
|
||||
(`Browser.getVersion`, `Target.getTargets`) stay on that fixed deadline, and
|
||||
the socket closes without a later command. Other CDP tools use
|
||||
`command_timeout_ms` (default 20000) for each WebSocket handshake and command
|
||||
response, separate from the caller-selected observation window, discovery, and
|
||||
the 5000 ms cleanup grace. A browser-level socket's handshake and the following
|
||||
`Target.attachToTarget` each receive that full deadline; they do not share one
|
||||
budget. A stalled handshake or command reports
|
||||
`provider_timeout` and names `command_timeout_ms` only when that operation
|
||||
accepts it; caller cancellation still reports cancellation. WebSocket messages
|
||||
remain subject to the [64 MiB limit](#request-boundary), which has no runtime
|
||||
override. REA does
|
||||
not impose a message-count or pending-command quota. On cancellation, it closes
|
||||
only its own WebSocket,
|
||||
waiting up to one second before terminating it. Malformed unsolicited events
|
||||
and malformed replies to pending commands poison the connection so later
|
||||
commands fail closed. A correlated reply's session ID must match the command's
|
||||
@@ -445,7 +465,7 @@ rejects it as unknown; other command rejections retain their reported failure.
|
||||
|
||||
Network and console coverage starts only after REA attaches and enables the relevant CDP domains. `prior_activity_available` is always `false`; absence from these arrays is not evidence that an event never occurred. Scripts are different: scripts the page parsed before REA attached are still reported under `scripts`. A page that loaded before attach can therefore list its scripts while `network.requests` lacks the requests that fetched them. If CDP reuses a request ID without supplying redirect metadata, REA retains the predecessor observation and marks network coverage incomplete.
|
||||
|
||||
Source maps are not fetched by inspection. Bundle analysis fetches them only when `fetch_source_maps` is selected, with exact-origin redirect checks and no credentials, cookies, or referrer. Each fetch operation has a 30-second deadline and a 64 MiB aggregate streamed-response budget across redirects. A deadline or byte-limit failure remains explicitly unavailable and makes bundle completeness partial. Source-map decoding also bounds raw resolved identities to 64 MiB and aggregate inline evidence to 32 MiB. Failed maps preserve their failure context when it fits; if another context cannot fit, collection stops with the full requested count, the returned processed count, and an explicit unknown-results limitation. Retained mappings and original sources are returned inline. See [source-location limits](web-source-location.md) for the structural decoder bounds. Original source artifacts with `.ts`, `.tsx`, `.mts`, or `.cts` suffixes carry `text/typescript`; other source names retain `text/javascript`.
|
||||
Source maps are not fetched by inspection. Bundle analysis fetches them only when `fetch_source_maps` is selected, with exact-origin redirect checks and no credentials, cookies, or referrer. Each fetch operation uses `source_map_fetch_timeout_ms` (default 30000) and a 64 MiB aggregate streamed-response budget across redirects. The byte budget has no runtime override. A fetch overrun is an item limitation, not a thrown analysis timeout. A deadline or byte-limit failure remains explicitly unavailable and makes bundle completeness partial. Source-map decoding also bounds raw resolved identities to 64 MiB and aggregate inline evidence to 32 MiB. Failed maps preserve their failure context when it fits; if another context cannot fit, collection stops with the full requested count, the returned processed count, and an explicit unknown-results limitation. Retained mappings and original sources are returned inline. See [source-location limits](web-source-location.md) for the structural decoder bounds. Original source artifacts with `.ts`, `.tsx`, `.mts`, or `.cts` suffixes carry `text/typescript`; other source names retain `text/javascript`.
|
||||
|
||||
source-map items retain the script's `declared_url` separately from the observed
|
||||
`effective_url`. successful maps use the latter as their source-resolution base.
|
||||
|
||||
@@ -23,9 +23,21 @@ that rejection does not roll back browser effects. REA removes its owned
|
||||
future-document scripts, restores live frame methods, then disconnects.
|
||||
Add secret declarations, storage seeds, and additional artifact or event
|
||||
capture only when needed. Action, secret, and storage counts are not capped.
|
||||
Duration, action, and navigation timeouts remain fixed provider-owned liveness
|
||||
limits. `capture.limits` controls retained event and network-content budgets;
|
||||
it does not change those liveness deadlines.
|
||||
Duration, action, and navigation timeouts remain separate from CDP command
|
||||
deadlines. `command_timeout_ms` (default 20000; omit it to keep that default
|
||||
and leave it out of Evidence) bounds launch startup, the connect-over-CDP
|
||||
handshake, target lookup, environment commands, and storage CDP commands,
|
||||
including replies from attached child targets. Set it in the scenario JSON.
|
||||
`capture-browser-scenario` has no `--command-timeout-ms` option.
|
||||
It does not change action `timeout_ms`, `wait_for_timeout.duration_ms`, or
|
||||
navigation. Service-worker restoration keeps a fixed 5000 ms grace and does
|
||||
not inherit a raised `command_timeout_ms`. CDP discovery stays on its own
|
||||
fixed deadline. When service workers are blocked, the registration check
|
||||
before discovery has its own fixed 10000 ms deadline; `command_timeout_ms`
|
||||
does not apply because discovery has not started. The discovery deadline
|
||||
covers endpoint discovery only. The following WebSocket handshake and
|
||||
`Target.attachToTarget` each use `command_timeout_ms`. `capture.limits` controls retained event and network-content
|
||||
budgets; it does not change those liveness deadlines.
|
||||
|
||||
## Minimal launch example
|
||||
|
||||
@@ -212,7 +224,9 @@ statements remain under the attached debugger client's control.
|
||||
The result is Evidence with an initial state followed by one record per
|
||||
declared action. Each step reports action status, elapsed time, sanitized URLs,
|
||||
event bounds, and independently typed capture states for screenshot, DOM,
|
||||
accessibility, URL, history, and storage. Console, page-error, network,
|
||||
accessibility, URL, history, and storage. Actions after a failed or cancelled
|
||||
action are not run and are recorded as `cancelled` with a not-executed error.
|
||||
Console, page-error, network,
|
||||
WebSocket, frame, worker, popup, and cancelled-download events are attributed to
|
||||
steps. Retained events and requested artifacts are returned inline; omitted
|
||||
events are counted by kind and identify affected network transactions.
|
||||
|
||||
+70
-21
@@ -63,6 +63,16 @@ or repeat it to select several types.
|
||||
Selection limits decoding to the selected types; member references remain an
|
||||
assembly-wide inventory, so the output can still be large.
|
||||
|
||||
Select `--detail summary --evidence-bundle /absolute/path/members.json` to
|
||||
receive identity, selection, coverage, limitations and collection counts while
|
||||
saving the complete original Evidence in a new bundle. Summary requires that
|
||||
explicit destination; existing files are preserved. Later
|
||||
`inspect-analysis-view` calls can page the exact parent from the saved bundle
|
||||
without reopening the assembly. See
|
||||
[CLI summary and saved member rows](managed-code-analysis.md#cli-summary-and-saved-member-rows)
|
||||
for the complete command sequence. Omitted or `--detail complete` retains the
|
||||
full inline response.
|
||||
|
||||
Choose the workflow from the artifact's contents rather than its `.exe` or
|
||||
`.dll` extension. The managed parser requires PE/CLI metadata; it does not
|
||||
unpack .NET single-file hosts or decode IL2CPP. For the image, type and method
|
||||
@@ -145,6 +155,16 @@ dependency edges, and the section's file range. A missing `.dep-v0` section is
|
||||
null metadata, not proof that the binary has no dependencies. See
|
||||
[Rust binaries](rust-binaries.md).
|
||||
|
||||
Inspect ELF PT_NOTE and SHT_NOTE tables without executing the image:
|
||||
|
||||
```bash
|
||||
rea inspect-elf-notes /absolute/path/to/program --json
|
||||
```
|
||||
|
||||
The workflow reports note owners, types, descriptor hashes, and GNU build-id
|
||||
or ABI-tag fields when those descriptors match. A missing note table is
|
||||
observed absence of those declarations. See [ELF note tables](elf-notes.md).
|
||||
|
||||
Configure [Hopper or Ghidra](installation.md#hopper), the
|
||||
[IDA adapter](ida-provider.md), or [Kuna](kuna-provider.md) before analyzing a
|
||||
native target. Substitute
|
||||
@@ -204,7 +224,7 @@ The selected provider remains bound to the session until an explicit switch
|
||||
or close. Provider failures are returned with their original reason. For an
|
||||
`ambiguous` selection error, choose from `details.candidate_ids`; for
|
||||
`provider_unavailable`, follow `message`, `remediation.action`, and the original
|
||||
reasons in `details.rejections`. For Hopper, Ghidra, IDA, and JADX, run
|
||||
reasons in `details.rejections`. For Hopper, Ghidra, IDA, JADX, and Kuna, run
|
||||
`rea doctor --provider ID --json` to diagnose the selected engine. Other adapters,
|
||||
such as `pwntools-elf`, report their configuration requirements directly and are
|
||||
not accepted by `doctor --provider`. See
|
||||
@@ -279,7 +299,12 @@ Exports preserve an existing destination unless `--overwrite` is explicit.
|
||||
For application traces and version comparisons, see
|
||||
[JavaScript application workflows](javascript-application-workflows.md).
|
||||
MCP [retained Evidence references](mcp-contracts.md#retained-application-evidence-inputs)
|
||||
belong to one connection. Separate CLI calls consume full saved records.
|
||||
belong to one connection. Separate CLI calls can consume full saved records.
|
||||
`inspect-analysis-view REQUEST.json --evidence-bundle BUNDLE.json` resolves
|
||||
the request's `retained-evidence` source ID from that authenticated bundle,
|
||||
including bundles exported from an MCP session. The same view JSON works for
|
||||
every supported parent kind; no target is reopened and no record is selected
|
||||
by file order. Omit `--evidence-bundle` when the request supplies inline Evidence.
|
||||
|
||||
## Import historical source
|
||||
|
||||
@@ -390,14 +415,26 @@ entry keep stdio.
|
||||
|
||||
## Serve an environment manifest
|
||||
|
||||
`rea environment-serve <manifest.json> --evidence <capture.json> [--host H]
|
||||
[--port N]` serves an environment manifest projected by `inspect-analysis-view`
|
||||
as an agent environment: an MCP server at `/mcp` with one tool per manifest
|
||||
tool, each replaying the retained capture records it cites, the environment
|
||||
card at `/.well-known/agent-env.json`, and a `/agentenv` data plane that
|
||||
answers every method with JSON-RPC `-32601`. The manifest's
|
||||
`parent_evidence_id` must equal the evidence file's `evidence_id`; otherwise
|
||||
the command refuses with `invalid_request` before binding.
|
||||
`rea environment-serve <manifest.json> --evidence <capture.json>
|
||||
[--replay-only] [--host H] [--port N]` serves an environment manifest
|
||||
projected by `inspect-analysis-view` as an agent environment: an MCP server at
|
||||
`/mcp`, the environment card at `/.well-known/agent-env.json`, and a
|
||||
`/agentenv` data plane. The manifest's `parent_evidence_id` must equal the
|
||||
evidence file's `evidence_id`; otherwise the command refuses with
|
||||
`invalid_request` before binding. Before binding it derives the
|
||||
`environment-state` view of the capture with the manifest's `template_rules`,
|
||||
as `inspect-analysis-view` would, and serves from it: read tools whose views
|
||||
are state-backed answer from a live state, write tools are served only where
|
||||
the capture's later reads confirmed their effect, and
|
||||
`/agentenv` serves `data/reset`, `data/add` and `data/get`. When the state
|
||||
cannot be derived, or its catalog exceeds the discovery reservation, it logs a
|
||||
warning with the error code and message and serves replay; `--replay-only` serves replay without deriving. In replay every
|
||||
manifest tool replays the retained capture records it cites and `/agentenv`
|
||||
answers every method with JSON-RPC `-32601`. The stopped document's `state`
|
||||
member is `{"served": true, "evidence_id": …}`,
|
||||
`{"served": false, "reason": "replay-only"}` or
|
||||
`{"served": false, "reason": "unavailable", "code": …, "message": …}`; see
|
||||
[serve from the state](agent-environments.md#serve-from-the-state).
|
||||
|
||||
```sh
|
||||
rea environment-serve manifest.json --evidence capture.json --port 8765
|
||||
@@ -408,8 +445,8 @@ rea environment-serve manifest.json --evidence capture.json --port 8765
|
||||
the served environment; set but blank, it is refused as `configuration_invalid`
|
||||
like a blank `MCP_HOST`. The bound URL is written to stderr as one JSON log line
|
||||
(`"msg":"MCP transport listening"`). See
|
||||
[agent environments](agent-environments.md) for what replay returns and does
|
||||
not establish.
|
||||
[agent environments](agent-environments.md) for what the state and replay
|
||||
return and do not establish.
|
||||
|
||||
## Export an environment bundle
|
||||
|
||||
@@ -417,9 +454,11 @@ not establish.
|
||||
[--package-tarball <path>] [--name <override>]` writes the same manifest and
|
||||
capture pair as a bundle folder the agentenv framework runs with
|
||||
`agent-env run <dir>`. It reads each file once, authenticates and cross-checks
|
||||
the pair with the same checks as `environment-serve`, copies the bytes it
|
||||
authenticated, refuses to write into a directory that exists and is not empty,
|
||||
and never overwrites a file.
|
||||
the pair with the same checks as `environment-serve`, checks the bundle name,
|
||||
then prepares the state under that name as the bundle's server will at startup
|
||||
to predict what the bundle serves (replay when the state is unavailable),
|
||||
copies the bytes it authenticated, refuses to write into a directory that
|
||||
exists and is not empty, and never overwrites a file.
|
||||
|
||||
```sh
|
||||
rea environment-export manifest.json --evidence capture.json ./grafana-example --json
|
||||
@@ -429,14 +468,16 @@ The folder holds a `README.md` with the bundle's provenance, an env folder
|
||||
`envs/<name>/` with a `Dockerfile` that installs this exact `rea-agents`
|
||||
version and serves the copied `manifest.json` and `evidence.json` (written
|
||||
with mode `0600` on POSIX; Windows retains inherited ACLs) with
|
||||
`environment-serve`, a Python verifier under `artifacts/check_<name>/` and the
|
||||
smoke task `tasks/smoke.json`. `--package-tarball` copies a packed `rea-agents`
|
||||
`environment-serve` (from the state by default), a Python verifier under
|
||||
`artifacts/check_<name>/` that checks the served tool count and one served
|
||||
answer, and the smoke task `tasks/smoke.json`. `--package-tarball` copies a packed `rea-agents`
|
||||
tarball into the env folder and installs it instead of the registry package,
|
||||
which is how the hosted lane proves a checkout rather than a release. `--name`
|
||||
replaces the manifest's kebab-case name as the env folder and env id; a device
|
||||
name Windows reserves (`con`, `nul`, `com1` and the like) is refused. The
|
||||
command prints one JSON document listing the written files with their sizes
|
||||
and the pinned package source. See
|
||||
command prints one JSON document listing the written files with their sizes,
|
||||
the pinned package source, the served `tool_count`, and `state` in the shape
|
||||
of the serve command's stopped document. See
|
||||
[agent environments](agent-environments.md#export-a-bundle) for the folder
|
||||
layout and what the smoke task checks.
|
||||
|
||||
@@ -488,8 +529,8 @@ SIGTERM, closes the listener, then prints one structured
|
||||
`{"status":"stopped", …}` document naming the URL, environment and tool count
|
||||
and exits `130` or `143` through the shared cancellation handler below.
|
||||
Refusals before binding (unreadable files, non-Evidence JSON, capture Evidence
|
||||
in a format other than HAR, a manifest whose parent is not the supplied
|
||||
evidence, an unbindable port) print a structured
|
||||
in a format other than HAR, a manifest or state whose parent is not the
|
||||
supplied evidence, an unbindable port) print a structured
|
||||
error and exit `1`, as does a listener that fails after binding.
|
||||
`rea environment-export` is one-shot: it prints the written files and exits
|
||||
`0`, or prints a structured `invalid_request` error and exits `1` for the same
|
||||
@@ -521,6 +562,14 @@ command, objdump, Rizin and GDB, and the agent environment server
|
||||
signal-derived status. This describes the current source routing; it is not a
|
||||
claim that every command or provider runtime has been independently exercised.
|
||||
|
||||
Commands with `--evidence_output` select their delivered view, then publish the
|
||||
complete Evidence bundle atomically. Cancellation before publication leaves no
|
||||
new file. A publication that has committed can win a later cancellation; the
|
||||
`cancelled` result then keeps the written path and byte count under
|
||||
`details.diagnostics.evidence_bundle`. If staging cleanup stays incomplete
|
||||
after commit, the `cleanup_incomplete` error reports the same file as
|
||||
`details.published_path` and `details.bytes`.
|
||||
|
||||
When the reader of piped output closes early, as `rea ... | head` does, the
|
||||
CLI stops writing, prints no error and exits `141` (`128 + 13`, the status of a
|
||||
SIGPIPE-terminated writer). The operation itself may have completed; only its
|
||||
|
||||
@@ -153,8 +153,8 @@ headroom. The default is 450000 ms, covering the default 330-second Ghidra
|
||||
startup; an explicit Ghidra startup timeout of 2700000 ms produces a 2820000 ms
|
||||
tool timeout. The startup allowance follows an explicitly selected Ghidra or
|
||||
Hopper provider, and otherwise uses the larger known Ghidra/Hopper deadline.
|
||||
An explicit `REA_JEB_MCP_TIMEOUT_MS` request budget also contributes to that
|
||||
maximum. For `ida` or `auto` selection, a valid IDA registration's parsed
|
||||
An explicit `REA_JEB_MCP_TIMEOUT_MS` deadline, shared by catalog discovery and
|
||||
each tools/call, also contributes to that maximum. For `ida` or `auto` selection, a valid IDA registration's parsed
|
||||
`timeoutMs` also contributes to that maximum; its default is 300000 ms.
|
||||
Setup forwards these explicitly selected REA deadlines and the input schema
|
||||
profile into the registration; unrelated process values are omitted. An
|
||||
|
||||
@@ -17,8 +17,8 @@ shared form would leave later fields unknown instead. The existing
|
||||
`REA_MCP_INPUT_SCHEMA_PROFILE=compact` profile lets callers stay below
|
||||
its character limit by advertising reduced nested validation structure, while
|
||||
REA continues to validate calls against the complete canonical input schema.
|
||||
Compact applies to the server's advertised inputs and is not an automatic
|
||||
full-profile fallback; see the [compact input schema profile](mcp-contracts.md#compact-input-schema-profile)
|
||||
Compact is the default for the server's advertised inputs; an explicit `full`
|
||||
choice is preserved. See the [compact input schema profile](mcp-contracts.md#compact-input-schema-profile)
|
||||
for details of its reduced forms.
|
||||
|
||||
Custom renderer hosts can raise `inputMaxChars` through `renderToolSignature` or
|
||||
|
||||
@@ -116,7 +116,9 @@ The CLI and MCP surfaces accept the same schema. For a JSON request file:
|
||||
rea capture-electron-scenario scenario.json --json
|
||||
```
|
||||
|
||||
The result records action status and targets, correlated app/window/WebContents,
|
||||
The result records one status and target per declared action; actions after a
|
||||
failed or cancelled action are not run and are recorded as `cancelled` with a
|
||||
not-executed error. It also records correlated app/window/WebContents,
|
||||
preload, session, navigation, shell, permission, popup, download, protocol,
|
||||
native-addon, process, and IPC timeline events. IPC channels and argument-shape
|
||||
metadata retain their observed lengths; payload values are never retained.
|
||||
@@ -243,4 +245,10 @@ application path and capture outcome to the static graph, while frames, scripts,
|
||||
workers, and execution claims remain unavailable until a separate passive runtime
|
||||
capture provides them.
|
||||
|
||||
ASAR observation reads the header through one open file handle, validates its declared lengths against the archive size, and limits encoded JSON headers to 16 MiB before parsing. The header cache also retains at most 16 MiB of encoded headers across eight archives. Oversized headers produce a scope refusal.
|
||||
ASAR observation reads the header through one open file handle and validates its
|
||||
declared lengths against the archive size. Header/index admission is the same
|
||||
budget used by static ASAR reads: 16 MiB / 16777216 bytes by default, or
|
||||
`REA_ASAR_MAX_HEADER_BYTES` (at most 256 MiB) when set. An oversized header is
|
||||
not parsed; selecting a member path does not bypass admission, and the page
|
||||
stays unauthorized. The header cache separately retains at most that many bytes
|
||||
of already-admitted encoded headers across eight archives. Evicting that cache does not raise admission.
|
||||
@@ -0,0 +1,53 @@
|
||||
# ELF note tables
|
||||
|
||||
`inspect_elf_notes` / `inspect-elf-notes` answers whether one selected local
|
||||
ELF32/ELF64 image declares `PT_NOTE` program headers or `SHT_NOTE` sections,
|
||||
which note owners and types those tables store, and which GNU build-id or
|
||||
ABI-tag fields those notes carry. It reads the file without executing it and
|
||||
does not require a disassembler, debug package, or package catalog.
|
||||
|
||||
```bash
|
||||
rea inspect-elf-notes /absolute/path/to/program --json
|
||||
```
|
||||
|
||||
The CLI resolves relative paths against the caller's working directory. MCP
|
||||
requires an absolute filesystem path and preserves that exact selection:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_elf_notes",
|
||||
"arguments": { "path": "/artifacts/program" }
|
||||
}
|
||||
```
|
||||
|
||||
## Observations
|
||||
|
||||
The inline Evidence result contains the artifact path, SHA-256, and byte length.
|
||||
`tables` lists each declared note program header or section, including the
|
||||
section name when a string table is present. Each `entries[]` item reports owner,
|
||||
type, descriptor SHA-256, and a hex preview for descriptors of 64 bytes or less.
|
||||
|
||||
For GNU notes, `gnu.build_id_hex`, `gnu.abi_tag`, or `gnu.gold_version` are
|
||||
filled when the descriptor matches that type. Other owners keep `gnu` null.
|
||||
|
||||
`PT_NOTE` and `SHT_NOTE` are examined independently. The same file range may
|
||||
appear twice when both tables declare it.
|
||||
|
||||
A missing table list is observed absence of those declarations. It is not proof
|
||||
the image never carried notes in another container or overlay.
|
||||
|
||||
## Limits and failures
|
||||
|
||||
The selected file is limited to 64 MiB by default (512 MiB maximum). At most
|
||||
32 note entries are examined by default across every table. Retained note
|
||||
names, section names, and GNU descriptor text share that file's byte budget,
|
||||
and repeated table ranges count again. Each descriptor range is hashed once,
|
||||
and each GNU version's trailing NUL run is scanned once; neither walk may
|
||||
exceed that byte ceiling. Malformed ELF headers, truncated header
|
||||
tables, declared note tables that extend past the file, and truncated
|
||||
note entries fail without partial success. ELF extended
|
||||
numbering (`PN_XNUM`, including a section count stored when `e_shnum` is 0) is
|
||||
unsupported.
|
||||
|
||||
This workflow does not execute the image or verify GNU build-id uniqueness
|
||||
against package catalogs.
|
||||
@@ -106,7 +106,11 @@ CLI keeps its existing complete result.
|
||||
|
||||
Inputs are limited to 4 MiB, complete replies to 16 MiB and combined diagnostic
|
||||
output to 1 MiB. An owned worker has a 256 MiB JavaScript heap, 3 GiB virtual
|
||||
address-space limit, 30 CPU seconds and a 30-second command deadline. Virtual
|
||||
address-space limit and 30 CPU seconds. The worker command deadline is
|
||||
`timeout_ms` (default 30000 ms, integer 1 through 2147483647) on the next call,
|
||||
or `--timeout-ms` on `rea inspect-evm-interface`. Omission keeps 30000 ms.
|
||||
Those byte, address-space, and CPU ceilings have no runtime override, and
|
||||
`timeout_ms` does not raise them. Virtual
|
||||
address space differs from resident memory. The worker retains inherited tighter
|
||||
soft/hard limits, reports its configured soft limits inline and leaves hard limits
|
||||
unchanged. WASM trap reservations are disabled
|
||||
|
||||
@@ -158,7 +158,13 @@ tree semantics, vulnerability scanning, emulation or hardware runtime capture.
|
||||
Supply a stable copy within the allowance. No in-place source modification.
|
||||
- One queued heavy operation per provider instance; Binwalk one thread and
|
||||
Unblob one worker. No automatic parallel extraction engines.
|
||||
- **120-second** analysis deadline through inventory. Publication and final
|
||||
- Analysis defaults to **120 seconds**, from tool resolution and input snapshot
|
||||
through inspection and its final private-workspace cleanup, or extraction
|
||||
through report consumption and inventory, excluding queue waiting and retained
|
||||
cleanup admission. Inspection has no publication phase. Select `analysis_timeout_ms` in either MCP operation or
|
||||
`--analysis-timeout-ms` in either CLI command for slower analysis. Current
|
||||
results retain the actual budget; an absent historical value means unknown.
|
||||
Extraction publication and its final
|
||||
cleanup start a separate **120-second** budget; select
|
||||
`publication_timeout_ms` in MCP or `--publication-timeout-ms` in CLI for a slow
|
||||
destination. Valid budgets are integers from 1 through 2,147,483,647 ms (the
|
||||
@@ -168,10 +174,18 @@ tree semantics, vulnerability scanning, emulation or hardware runtime capture.
|
||||
both phases and final cleanup. Phase handoff, publication commit and final
|
||||
completion also check monotonic elapsed time, so delayed timer callbacks
|
||||
cannot revive an expired budget.
|
||||
- Analysis timeout recovery names the selected budget and the analysis control,
|
||||
not the later publication control. Keep the client call timeout above analysis,
|
||||
publication and cleanup headroom; keep the input/range/question unchanged.
|
||||
Resolve any reported incomplete cleanup before retrying. Raising wall time
|
||||
does not raise fixed CPU, memory, report, diagnostic or input limits.
|
||||
- Inherited **1 GiB per-process address-space** limit,
|
||||
120 CPU seconds and zero core-dump allowance through `prlimit`.
|
||||
- JSON reports: at most **8 MiB** and valid UTF-8; malformed encoding and
|
||||
oversized reports fail without repairing or truncating producer data.
|
||||
Exit status 0 is not an empty result: a missing, empty, malformed or
|
||||
oversized report fails with `unreadable_output`, its `report_state`, the
|
||||
command, exit status and captured output. REA does not retry automatically.
|
||||
Diagnostic output is bounded with exact captured byte counts.
|
||||
- Default staging budget: **256 MiB** and **10,000 entries**, configurable using
|
||||
`max_output_bytes` / `max_output_files` (CLI `--max-output-bytes` /
|
||||
|
||||
@@ -24,6 +24,6 @@ Use `get_evidence_bundle` with `detail="summary"` and `filters={"evidence_id":"P
|
||||
|
||||
Failed startup cleanup retains acquired Frida handles, including a paused spawn that has not attached, for later cleanup retries. Its remote connection stays leased until session detach and target resume complete. CLI commands await provider cleanup before returning; MCP retains these resources for cleanup when its server closes. Server shutdown stops admitting new Frida operations and waits for admitted startup, discovery, and queued work before releasing their resources. A failed cleanup remains reported and can be retried by closing the server again, rather than treating an unregistered session as fully released.
|
||||
|
||||
Frida scripts execute inside the selected target with that process's memory, filesystem, and network authority. Message capture is bounded to 16 MiB and reports truncation. Script source is not stored in Evidence; its selected path and SHA-256 digest are. For a file, `source_sha256` identifies the original selected bytes. Invalid UTF-8 continues to use replacement decoding; Evidence then records that limitation and `raw_result.source_representation` with the encoding, decoding mode, and `loaded_source_sha256` of the UTF-8 string passed to Frida. Valid UTF-8 files and inline scripts do not need this additional representation fact. Evidence retains non-authentication target selection such as device or endpoint, mode, program or PID, and spawn arguments. Authentication values remain excluded. Results report the observed session and messages, while unsupported platform metadata remains unknown. A request cancelled before a Frida operation starts has no provider effects. If cancellation arrives during a native Frida call, REA waits for that call to return, then closes any session it created and returns the observed session as a partial observation. A cancelled script load on an existing session releases only its new script before queued operations can run; the session and previously loaded scripts remain available. If cancellation is observed when the native call returns, partial Evidence retains the source identity and captured messages even if that call rejects, including messages emitted during awaited cleanup. The caller's cancellation reason remains primary and a native rejection is retained as a sanitized diagnostic. A failure already observed before cleanup stays primary if cancellation arrives during cleanup. The cancellation cutoff is REA's observation of native completion, rather than a claim about unobservable native event order. `script_id` is REA's load-attempt identity. When creation rejects without returning a handle, `script_cleanup: "no_handle"` means REA acquired no handle to unload; it does not prove that the engine performed no work. Once the provider commits a successful load, later request cancellation does not unload that script; use `unload_frida_script` to release it. If script cleanup fails, the script remains owned and a paused target cannot resume until the pending instrumentation is released. Queued script loads, resumes, and unloads check cancellation before dispatching native effects. Cancellation Evidence separately reports whether a target resume was observed, whether instrumentation cleanup completed, and that final target liveness remains unknown. REA does not kill the target. Remote discovery retains its observations and reports a separate cleanup error if the temporary connection cannot be removed.
|
||||
Frida scripts execute inside the selected target with that process's memory, filesystem, and network authority. Local device lookup waits 1000 ms. This release has no runtime override for that lookup; another REA timeout does not raise it. Remote endpoints do not use that lookup. Message capture is bounded to 16 MiB and reports truncation. Metadata, type, and text field caps, and the JSON node cap, are also fixed. Evidence names a cap when that observation actually dropped data. This release has no runtime override for those capture caps. Script source is not stored in Evidence; its selected path and SHA-256 digest are. For a file, `source_sha256` identifies the original selected bytes. Invalid UTF-8 continues to use replacement decoding; Evidence then records that limitation and `raw_result.source_representation` with the encoding, decoding mode, and `loaded_source_sha256` of the UTF-8 string passed to Frida. Valid UTF-8 files and inline scripts do not need this additional representation fact. Evidence retains non-authentication target selection such as device or endpoint, mode, program or PID, and spawn arguments. Authentication values remain excluded. Results report the observed session and messages, while unsupported platform metadata remains unknown. A request cancelled before a Frida operation starts has no provider effects. If cancellation arrives during a native Frida call, REA waits for that call to return, then closes any session it created and returns the observed session as a partial observation. A cancelled script load on an existing session releases only its new script before queued operations can run; the session and previously loaded scripts remain available. If cancellation is observed when the native call returns, partial Evidence retains the source identity and captured messages even if that call rejects, including messages emitted during awaited cleanup. The caller's cancellation reason remains primary and a native rejection is retained as a sanitized diagnostic. A failure already observed before cleanup stays primary if cancellation arrives during cleanup. The cancellation cutoff is REA's observation of native completion, rather than a claim about unobservable native event order. `script_id` is REA's load-attempt identity. When creation rejects without returning a handle, `script_cleanup: "no_handle"` means REA acquired no handle to unload; it does not prove that the engine performed no work. Once the provider commits a successful load, later request cancellation does not unload that script; use `unload_frida_script` to release it. If script cleanup fails, the script remains owned and a paused target cannot resume until the pending instrumentation is released. Queued script loads, resumes, and unloads check cancellation before dispatching native effects. Cancellation Evidence separately reports whether a target resume was observed, whether instrumentation cleanup completed, and that final target liveness remains unknown. REA does not kill the target. Remote discovery retains its observations and reports a separate cleanup error if the temporary connection cannot be removed.
|
||||
|
||||
The [Frida Core API](https://frida.re/docs/frida-core-api/) documents device management, sessions, and script loading; the [JavaScript API](https://frida.re/docs/javascript-api/) documents target-side instrumentation. [Luma](https://luma.frida.re/) is Frida's standalone GUI; REA does not automate or control it. `npm run verify:frida` requires a Linux host with the optional Frida binding and uses a short-lived local Node.js fixture created by the verifier. Add `-- --address HOST:PORT --pid PID` to run the separate remote attach lane against a caller-selected target. Mock tests do not establish real device/server compatibility.
|
||||
+15
-5
@@ -109,11 +109,21 @@ module record and no dependency records has an observed empty dependency list.
|
||||
|
||||
## Supported boundary
|
||||
|
||||
The built-in TypeScript reader supports ELF, PE and thin Mach-O images with Go's
|
||||
inline or historical pointer build-info encoding. Source ranges refer to the
|
||||
original stable file snapshot, including pointer-backed strings. It does not
|
||||
scan arbitrary byte strings as compiler metadata or interpret a fat Mach-O
|
||||
container as one selected architecture.
|
||||
The built-in TypeScript reader supports ELF, PE and thin Mach-O images, and one
|
||||
selected slice of a universal Mach-O, with Go's inline or historical pointer
|
||||
build-info encoding. Source ranges refer to the original stable file snapshot,
|
||||
including pointer-backed strings. It does not scan arbitrary byte strings as
|
||||
compiler metadata.
|
||||
|
||||
A universal (FAT) Mach-O needs `architecture` (`x86`, `x86_64`, `arm`
|
||||
or `arm64`; CLI `--architecture`). REA reads its own FAT table, without `lipo`,
|
||||
and validates the selected slice's range, alignment and Mach-O header CPU
|
||||
against the table. The result keeps the universal file as `artifact` (its
|
||||
SHA-256 and size), adds `selected_slice` with the slice offset, length, raw CPU
|
||||
type/subtype and the FAT table digest, and reports every source range as a
|
||||
file offset inside that slice. Without `architecture`, or when the file has no
|
||||
such slice or several, the request fails on `architecture` and lists the slices
|
||||
present. `architecture` on any other image is rejected rather than ignored.
|
||||
|
||||
For ELF images without a named build-info section, discovery checks each
|
||||
nonempty writable, non-executable load segment in program-header order. This
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
# Static CUDA and HIP code objects
|
||||
|
||||
`inspect_gpu_code_objects` answers which GPU targets and kernel declarations a
|
||||
local artifact carries. It reads ELF/PE sections, standalone CUDA fatbins,
|
||||
CUBIN/PTX and Clang HIP bundles, including CCOB v1/v2/v3. It neither executes the
|
||||
artifact nor invokes CUDA/ROCm tools. GPU execution, SASS disassembly and host
|
||||
launch correlation remain outside coverage.
|
||||
|
||||
Start with a target inventory:
|
||||
|
||||
```json
|
||||
{ "path": "/artifacts/library.so", "view": { "collection": "targets" } }
|
||||
```
|
||||
|
||||
Target rows aggregate inventoried payloads and distinguish an unrequested kernel
|
||||
analysis from a complete or partial one. `objects` pages expose exact object
|
||||
IDs, compression declarations and encoded/header locations. Fields, exact
|
||||
filters, batch IDs and stable pagination select the facts delivered to the
|
||||
caller. IDs are positional within the recorded artifact SHA-256. Selecting `object_ids`
|
||||
in a new inspection requires `expected_sha256` from that inventory; a changed
|
||||
file is rejected before parsing selected payloads.
|
||||
|
||||
`target` is the inventory declaration used for selection; `payload_target` is
|
||||
the independently observed inner declaration when available. Object pages keep
|
||||
both values, their kind, `target_consistency` and inspection coverage even with
|
||||
selected fields.
|
||||
Conflicting base architectures retain both values, mark object/report/target
|
||||
coverage partial and annotate the affected kernels. CUBIN flags establish a base
|
||||
architecture: `base-only` explicitly leaves feature-profile agreement unknown,
|
||||
including `a` variants. A standalone declaration is `single-source`, and
|
||||
unexamined payloads remain `unexamined`. An exact AMDGPU target is normalized at
|
||||
its note owner for comparison with a Clang bundle declaration; raw values remain
|
||||
intact. Unresolved feature comparisons stay `unknown`.
|
||||
|
||||
`cuda_target_header` retains the OS ABI, normalized raw `e_flags` and exact
|
||||
header location. CUDA OS ABI `0x33` and the observed `0x41` flags layout use
|
||||
different architecture fields; they are decoded at one ABI-aware owner.
|
||||
Unrecognized layouts keep the header and an unknown target instead of
|
||||
inventing an SM label. Header provenance is validated against its CUBIN object.
|
||||
|
||||
Target filters select inventory declarations. An unselected payload's inner
|
||||
target remains unexamined; an empty filtered result does not establish that
|
||||
no enclosed code declares that target. Discovering every inner declaration
|
||||
requires decoding those payloads.
|
||||
|
||||
HIP IDs with one or two separators before the architecture retain the declared
|
||||
target. If a recognized AMDGPU bundle ID does not expose a target, the same
|
||||
bounded note-discovery owner used for standalone AMDGPU files establishes it
|
||||
before filtering. Those directory/note reads share the inspection work budget;
|
||||
successive queries can select the target returned by inventory.
|
||||
|
||||
Decode selected targets and return a kernel page in the same call:
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/artifacts/library.so",
|
||||
"analysis": "kernels",
|
||||
"targets": ["sm_100"],
|
||||
"view": {
|
||||
"collection": "kernels",
|
||||
"names": ["kernel_name"],
|
||||
"fields": [
|
||||
"name",
|
||||
"parameter_count",
|
||||
"parameter_bytes",
|
||||
"parameters",
|
||||
"registers",
|
||||
"shared_bytes"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Only selected payloads are decoded. Other inventory entries remain present with
|
||||
`not-selected` states, and overall payload coverage remains partial. An empty
|
||||
kernel page proves no matching retained fact; it does not establish that an
|
||||
unexamined payload contains no kernel. Missing fields remain null.
|
||||
|
||||
Kernel representations have different meanings:
|
||||
|
||||
- PTX reports parameter declarations and virtual registers. Shared bytes cover
|
||||
supported static declarations inside that entry; they do not establish module
|
||||
shared memory, dynamic allocation or physical device resources.
|
||||
Scalar register declarations count each bare or percent-prefixed name and
|
||||
each parameterized range. Unsupported declaration forms or overflowing totals
|
||||
retain an unknown count and partial decoding coverage. Unsupported parameter
|
||||
layouts and unknown shared-memory declarations likewise retain their known
|
||||
facts, explicit limitations and partial coverage through retained pages.
|
||||
- CUBIN identifies CUDA entry symbols and reads numeric `nv.info` records and
|
||||
native section declarations. Global register declarations also cover compiler
|
||||
versions that leave the older text-section register field empty.
|
||||
- AMDGPU reads v3+ MessagePack notes. Argument counts include hidden ABI arguments
|
||||
when present; SGPR/VGPR counts and fixed group/private segment sizes retain
|
||||
their declared meanings. Legacy YAML metadata remains unsupported.
|
||||
|
||||
Each selected PTX payload becomes a retained UTF-8 text artifact with a SHA-256,
|
||||
byte length and source coordinates. It is omitted from compact replies. Read it
|
||||
with `inspect_analysis_view` and the parent Evidence ID returned by the compact
|
||||
receipt:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": { "kind": "retained-evidence", "evidence_id": "ev_..." },
|
||||
"view": {
|
||||
"kind": "gpu-code-objects",
|
||||
"collection": "ptx",
|
||||
"object_id": "...",
|
||||
"offset": 0,
|
||||
"limit": 4096
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Text offsets use UTF-16 code units and must fall on Unicode scalar boundaries.
|
||||
Complete Evidence retains the selected text; `export_evidence_bundle` provides
|
||||
its portable source record. Historical pages never reopen the input file.
|
||||
|
||||
A location with `container_id: null` uses original file offsets. Other locations
|
||||
use that inventoried object's decoded byte coordinates. Follow its parent,
|
||||
encoded location and digest to trace decompressed metadata back to a native
|
||||
section and the original file. Decoded offsets are never presented as physical
|
||||
file offsets.
|
||||
|
||||
The CLI uses the same service and contracts:
|
||||
|
||||
```sh
|
||||
rea inspect-gpu-code-objects /artifacts/library.so --analysis kernels \
|
||||
--targets '["sm_100"]' --detail summary \
|
||||
--view '{"collection":"kernels","names":["kernel_name"]}' \
|
||||
--evidence_output /analysis/library-gpu.evidence.json --json
|
||||
```
|
||||
|
||||
A full-file SHA-256 always streams every byte. Inventory then reads bounded
|
||||
native directories and bundle headers; CCOB requires decompression to discover
|
||||
its inner directory. Kernel analysis reads selected payloads. `bytes_read`
|
||||
includes hashing and subsequent descriptor reads, so this is not a header-only
|
||||
hashing workflow.
|
||||
|
||||
CUDA raw LZ4 blocks and Zstd, and CCOB zlib/Zstd are supported. Unknown versions
|
||||
or codecs retain declarations with explicit limitations. Lengths are checked
|
||||
before decoding, and CCOB's truncated MD5 is verified against decoded bytes.
|
||||
Resource limits are one active inspection, 128 MiB per input/output buffer,
|
||||
512 MiB of payload input, decoded output and AMD note-read work per inspection,
|
||||
and 16 MiB retained facts including selected PTX. Payload work is reserved before
|
||||
reading or allocating; a capacity refusal does not reread an aliased payload.
|
||||
Native tables and decoded section names each have a 16 MiB structural budget;
|
||||
AMDGPU ELF note discovery admits at most 8 MiB of source note bytes, with
|
||||
bounded depth and container/string allocations. Standalone AMD targets are read
|
||||
from those notes before target selection; selected kernel analysis reuses the
|
||||
same parsed declarations. Pages have a
|
||||
1 MiB response budget. Resource refusals and interrupted observations preserve
|
||||
known facts and explicit uncertainty.
|
||||
|
||||
CUDA ELF parsing additionally shares a 262,144 record/symbol visit limit,
|
||||
128 MiB of cumulative metadata section reads, and a 16 MiB serialized-size
|
||||
accounting budget for temporary index facts. These limits are checked before
|
||||
index growth; they are not claims about JavaScript heap size. Equivalent scoped
|
||||
metadata byte ranges and repeated equal register declarations are coalesced;
|
||||
conflicting values remain unknown. Parameter sections are parsed once per ELF.
|
||||
|
||||
Missing CUBIN symbol tables or unresolved section names produce `partial`
|
||||
object, report and target coverage even when some kernel facts survive. AMD note
|
||||
failures preserve earlier successfully parsed declarations and the original
|
||||
failure reason. Standalone PTX recognition tries a small header first, then
|
||||
continues within the existing 16 MiB text budget when leading comments or
|
||||
whitespace obscure its directives; admitted full-file probe bytes are reused.
|
||||
@@ -142,7 +142,7 @@ Use a package version that actually includes this adapter; repository main can b
|
||||
{"name":"close_binary","arguments":{}}
|
||||
```
|
||||
|
||||
Opening an MCP target starts its selected provider session; headless opening waits for auto-analysis. Set the agent's MCP request deadline long enough for the target. The registration's optional `timeoutMs` defaults to 300000 for upstream requests. An upstream SDK request that reaches this limit returns `provider_timeout` with its operation and actual request budget. A freshly opened headless worker can briefly report `status: "busy"` from `server_health`; REA re-reads health every 100 ms until the worker answers, the caller cancels, or `timeoutMs` has elapsed since the first read. Each health request is capped by the time remaining in that overall wait, so a stalled read cannot extend the readiness deadline by another full request timeout. Expiry while the worker is still busy produces a retryable `provider_timeout`; no further read is started after the deadline. That error names the busy tool from the last observation, or `unknown` when the worker reported none or a value that is not tool-name-shaped. If a health request itself consumes the remaining wait budget, the same last-busy timeout is returned with the stalled request's captured output. Cancellation during the wait produces `cancelled`. Any other unexpected health payload, including a busy payload with an invalid shape, remains `unreadable_output`. Cancellation drains the current upstream request before cleanup; it does not force-stop GUI analysis. An open request that times out without a completed response retains the private workspace because worker inventory alone cannot prove the request has stopped. `binary_session` reports actual tool availability. Repeated doctor/setup calls are unnecessary when the registration already works.
|
||||
Opening an MCP target starts its selected provider session; headless opening waits for auto-analysis. Set the agent's MCP request deadline long enough for the target. The registration JSON named by `REA_IDA_MCP_CONFIG` has an optional `timeoutMs` integer from 1 to 2147483647. Omitted means 300000. REA applies an edited value on the next IDA connection after it re-reads that file; an already open session keeps the timeout it connected with. Changing the `REA_IDA_MCP_CONFIG` path itself is read at process start. An upstream SDK request that reaches this limit returns `provider_timeout` naming the effective milliseconds and `timeoutMs`. A shorter inner request is the time remaining inside that ceiling, and the error names both when they differ. A freshly opened headless worker can briefly report `status: "busy"` from `server_health`; REA re-reads health every 100 ms until the worker answers, the caller cancels, or `timeoutMs` has elapsed since the first read. Each health request is capped by the time remaining in that overall wait, so a stalled read cannot extend the readiness deadline by another full request timeout. Expiry while the worker is still busy produces a retryable `provider_timeout`; no further read is started after the deadline. That error names the busy tool from the last observation, or `unknown` when the worker reported none or a value that is not tool-name-shaped. If a health request itself consumes the remaining wait budget, the same last-busy timeout is returned with the stalled request's captured output. Cancellation during the wait produces `cancelled`. Any other unexpected health payload, including a busy payload with an invalid shape, remains `unreadable_output`. Cancellation drains the current upstream request before cleanup; it does not force-stop GUI analysis. An open request that times out without a completed response retains the private workspace because worker inventory alone cannot prove the request has stopped. `binary_session` reports actual tool availability. Repeated doctor/setup calls are unnecessary when the registration already works.
|
||||
|
||||
For guided registration, set `REA_IDA_MCP_CONFIG` before `rea setup --client <client>`. Setup includes that file reference in its reviewed plan and preserves it after approval; it does not copy upstream credentials into the agent configuration. For `ida` or `auto` selection, Codex/Kimi setup and doctor use the effective client registration's parsed `timeoutMs` (default 300000 ms) when recommending the agent's per-tool deadline. Existing positive client deadlines remain caller choices. `rea doctor --provider ida --json` validates the registration without starting IDA and explicitly leaves runtime compatibility and target binding for analysis.
|
||||
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ For runtime instrumentation, see the [Frida guide](./frida-instrumentation.md).
|
||||
| Task | Guides |
|
||||
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Identify a desktop installation | [Runtime candidates, evidence and follow-up files](desktop-applications.md) |
|
||||
| Inspect native functions, references, or types | [Native binaries](native-investigation.md), [Go metadata](go-binaries.md), [Rust dependencies](rust-binaries.md), [offline ELF layout](binary-diagnostics.md), [recorded crashes](recorded-crashes.md) |
|
||||
| Inspect native functions, references, or types | [Native binaries](native-investigation.md), [Go metadata](go-binaries.md), [Rust dependencies](rust-binaries.md), [ELF notes](elf-notes.md), [offline ELF layout](binary-diagnostics.md), [recorded crashes](recorded-crashes.md) |
|
||||
| Select a native provider or import format | [Ghidra semantics](ghidra-provider.md), [Windows](windows-ghidra-p0.md), [DOS](ghidra-dos.md), [raw bytes](raw-binary.md), [MIPS](ghidra-mips.md), [PSP](ghidra-psp.md), [NativeAOT](ghidra-nativeaot.md), [IDA](ida-provider.md), [Kuna](kuna-provider.md), [JEB](jeb-analysis.md) |
|
||||
| Analyze JavaScript or Electron artifacts | [Static analysis](javascript-artifact-reconstruction.md), [tracing and comparisons](javascript-application-workflows.md), [application graph](javascript-application-graph.md), [source recovery](javascript-recovery.md) |
|
||||
| Compare static JavaScript with runtime observations | [Runtime attribution](javascript-runtime-observation.md), [reconciliation](javascript-runtime-reconciliation.md), [Electron observation](electron-observation.md), [Electron fuses](electron-fuses.md) |
|
||||
|
||||
@@ -24,6 +24,10 @@ Restart the agents named in the completion message. Quit Claude Desktop fully
|
||||
before approving, because a running app can overwrite the registration; on
|
||||
Windows, see [where Claude Desktop reads its configuration](client-configuration.md#claude-desktop).
|
||||
|
||||
During package resolution, npm may print a deprecation warning for `prebuild-install`
|
||||
from transitive native dependencies (such as Frida). This warning originates from
|
||||
the upstream dependency tree and does not affect REA or indicate setup failure.
|
||||
|
||||
For the latest published release, use `npx rea-agents@latest setup`.
|
||||
[Package-runner and global-installation options](#package-runners-and-global-installation)
|
||||
cover explicit versions, Bun, runtime requirements, and the curl wrapper.
|
||||
@@ -1189,8 +1193,10 @@ truncation markers. Darwin ownership-helper compilation failures also retain
|
||||
the compiler outcome, exit code or signal, and bounded stderr; a timed-out
|
||||
compiler remains distinguishable from a compiler that exited with an error.
|
||||
The helper compile deadline defaults to 120,000 ms; set
|
||||
`REA_SWIFTC_COMPILE_TIMEOUT_MS` to an integer between 1 and 2,147,483,647 when
|
||||
a busy host needs longer.
|
||||
`REA_SWIFTC_COMPILE_TIMEOUT_MS` to an integer between 1 and 2,147,483,647 in
|
||||
the environment that starts REA when a busy host needs longer. Restart REA to
|
||||
apply a change; the next ownership-helper compile uses the new value. A
|
||||
timeout names that effective deadline.
|
||||
On macOS, the Java prerequisite probe waits for this independently bounded
|
||||
preparation before starting its five-second command deadline. Caller cancellation
|
||||
still interrupts preparation, and failed helper cleanup remains owned for retry.
|
||||
|
||||
@@ -106,6 +106,18 @@ only reduces delivery; source selection reduces text acquisition and analysis.
|
||||
Explicit native provider or snapshot routing rejects `--source-path` rather
|
||||
than ignoring it.
|
||||
|
||||
ASAR header/index admission defaults to 16 MiB / 16777216 bytes. Set
|
||||
`REA_ASAR_MAX_HEADER_BYTES` in the environment that starts REA to a decimal
|
||||
byte count of at most 268435456 (256 MiB) to raise or lower it; restart REA
|
||||
after changing it. Invalid values are configuration errors, never a silent
|
||||
fallback. The archive index is read before any member can be selected, so
|
||||
`source_paths`, `--source-path`, `detail: "summary"`, `max_heap_mb`, and
|
||||
available host memory do not bypass or raise it. When the header exceeds the
|
||||
effective allowance, the failure names it, whether it came from the default or
|
||||
the setting, and the setting's limits. Alternatively, analyze an extracted
|
||||
application directory, which does not admit an ASAR header. Repeating the unchanged
|
||||
request fails the same way.
|
||||
|
||||
## Read the analysis
|
||||
|
||||
`analyze_javascript_application` returns the complete analysis Evidence by
|
||||
@@ -172,7 +184,8 @@ for the tool-result contract.
|
||||
|
||||
Use MCP `detail: "summary"` for a large application, then read selected views of
|
||||
the retained analysis. Summary changes delivery only. To reduce source parsing,
|
||||
select exact [source paths](#select-sources-before-analysis).
|
||||
select exact [source paths](#select-sources-before-analysis). Source selection
|
||||
does not bypass ASAR header/index admission.
|
||||
|
||||
If a complete response exceeds the transport budget, use its retained Evidence
|
||||
ID for a summary, module page, or item, or export the bundle. See
|
||||
@@ -371,7 +384,15 @@ Recognized literal module-table bootstraps also support bounded lexical
|
||||
substitution through module exports, import helper bodies, local wrapper calls,
|
||||
returned closures, object spreads, and callback parameters. Recovered Electron
|
||||
paths retain source ranges, module identities, literal channels and branch
|
||||
conditions as static candidates. Unknown spreads, reassigned bindings, accessors,
|
||||
conditions as static candidates. A channel the IPC call site itself
|
||||
determines, such as a local constant, resolves that call's observation rather
|
||||
than adding a second one. A channel or registration handler supplied through
|
||||
a wrapper argument is a candidate beside the call's own unresolved
|
||||
observation, because callers outside the traced paths may pass other values.
|
||||
A wrapper call that is both its own entry and reached through another entry
|
||||
is recorded once when both paths find the same facts; calls that supply
|
||||
different handlers or channels stay distinct.
|
||||
Unknown spreads, reassigned bindings, accessors,
|
||||
dynamic channels and unsupported syntax do not become exact implementations.
|
||||
This pass neither executes the bundle nor proves that runtime guards pass.
|
||||
An ambiguous or unresolved handler retains its channel registration but does
|
||||
@@ -589,8 +610,9 @@ The default semantic capacities are 100000 nodes across the application and
|
||||
`--max-semantic-nodes-per-file`), each from 1 to 1000000. The per-file offer is
|
||||
also bounded by the remaining application capacity. Raising these controls does
|
||||
not bypass worker heap, execution deadline or parent result admission. Truncated
|
||||
coverage reports both effective node ceilings; omitted relationships remain
|
||||
unknown.
|
||||
coverage lists both effective ceilings, `max_semantic_nodes` and
|
||||
`max_semantic_nodes_per_file`. The limitation names only the ceiling that
|
||||
stopped retention. Omitted relationships remain unknown.
|
||||
|
||||
Unknown records have independent defaults of 100000 across the application and
|
||||
20000 per source. Select `max_semantic_unknowns` and
|
||||
@@ -598,8 +620,10 @@ Unknown records have independent defaults of 100000 across the application and
|
||||
`--max-semantic-unknowns-per-file`), each from 1 to 1000000. The parent offers the
|
||||
remaining capacity to the worker, and rejects excess records before adoption.
|
||||
Unknown admission happens before canonical identity and provenance construction.
|
||||
When capacity is exhausted, coverage is partial and truncated and names both
|
||||
effective unknown ceilings. `coverage.omitted_unknown_occurrences` counts examined
|
||||
When capacity is exhausted, coverage is partial and truncated. Coverage lists
|
||||
both effective unknown ceilings, `max_semantic_unknowns` and
|
||||
`max_semantic_unknowns_per_file`. The limitation names only the ceiling that
|
||||
stopped retention. `coverage.omitted_unknown_occurrences` counts examined
|
||||
emission occurrences by family and reason, including repeated emissions. It does
|
||||
not claim distinct discarded identities or count frontiers in unexamined source.
|
||||
Omitted unknown provenance and IDs are not retained. Existing source, node,
|
||||
@@ -612,12 +636,35 @@ checkpoint at its 8 MiB bound with the same 6x retention expansion used at
|
||||
admission. Earlier checkpoints are already charged to retained bytes; the
|
||||
remaining inventory does not multiply the reserve. Streamed file transfers keep the default 512 MiB
|
||||
allowance, and can grow with the parent's offered retention budget (8x byte
|
||||
expansion), up to 2 GiB. Individual records remain bounded to 8 MiB. The parent
|
||||
expansion), up to 2 GiB. Individual records remain bounded to 8 MiB. The 8 MiB
|
||||
record ceiling and the 2 GiB file maximum have no runtime override, and raising
|
||||
`max_heap_mb` does not raise them. The effective file ceiling follows the
|
||||
parent's offered result budget. On Node, a larger CLI/MCP process heap
|
||||
(`NODE_OPTIONS`, for example `--max-old-space-size=<MiB>`, after restarting that
|
||||
process) can raise it up to 2 GiB. Selecting fewer `source_paths` can also
|
||||
raise that effective allowance, because the reserve for remaining sources and
|
||||
earlier retained results reduce the offered budget. Neither change raises the
|
||||
record ceiling or the 2 GiB maximum. The parent
|
||||
still independently checks actual bytes, record overhead, digests and source
|
||||
identities before adopting results.
|
||||
|
||||
A source that exhausts the analyzer heap does not terminate the CLI/MCP
|
||||
process. Completed static facts are retained, other files can still be analyzed,
|
||||
process. On Node, the failure names `max_heap_mb` (CLI `--max-heap-mb`), the
|
||||
effective mebibytes, the inclusive range 128 to 16384, and the 1024 MiB
|
||||
default. A changed value applies on the next analysis, which starts a new
|
||||
worker. It does not change a worker that is already running and does not
|
||||
require restarting the REA server. On Bun, the same heap-exhaustion diagnostic
|
||||
is not attributed to that V8 old-space limit, because Bun ignores the flag.
|
||||
Raising `max_heap_mb` does not raise the parent result budget,
|
||||
the transfer record ceiling, the 2 GiB transfer file maximum, the CLI/MCP
|
||||
process heap, or fixed parser limits. The parent result budget follows that
|
||||
process heap. On Node, set `NODE_OPTIONS` (for example `--max-old-space-size=<MiB>`)
|
||||
in the environment that starts the CLI or MCP server, then restart that
|
||||
process, to raise the parent heap and the result budget. A completed static
|
||||
checkpoint that does not fit the parent's remaining heap names that parent
|
||||
process heap. Increasing `max_heap_mb` does not raise it. On Node, the same
|
||||
`NODE_OPTIONS` restart can raise the parent heap and admit the checkpoint.
|
||||
Completed static facts are retained, other files can still be analyzed,
|
||||
and unexamined semantic relationships remain explicit unknowns. The parent
|
||||
also checks transfer expansion and accumulated results against its remaining
|
||||
heap before accepting semantic facts. A resource-limited result has partial
|
||||
|
||||
@@ -129,10 +129,15 @@ equivalence remain unknown. No network fetching occurs.
|
||||
|
||||
## Resource policy and verification
|
||||
|
||||
Each operation uses one worker, a 1 GiB address-space ceiling and a 120-second
|
||||
deadline; it accepts up to 64 MiB of total input across all selected files and
|
||||
128 MiB/10000 entries of staged
|
||||
output, with 8 MiB per diagnostic/report stream. Exceeding a limit is an explicit
|
||||
Each operation uses one worker, a 1 GiB address-space ceiling and a 120000 ms
|
||||
deadline. That deadline has no runtime override: raising `analysis_timeout_ms`
|
||||
or `max_heap_mb` does not raise it. An unchanged retry may hit the deadline
|
||||
again. The operation accepts up to 64 MiB of total
|
||||
input across all selected files and 128 MiB/10000 entries of staged output,
|
||||
with 8 MiB per diagnostic/report stream. A `provenance.json` over that report
|
||||
allowance names the fixed limit: this release has no runtime override, and
|
||||
raising `max_heap_mb` or `analysis_timeout_ms` does not raise it. Malformed
|
||||
reports stay distinct from that size refusal. Exceeding a limit is an explicit
|
||||
failure with rollback. Selected inputs beyond the total input allowance return a
|
||||
non-retryable `resource_constraint` with `resource: "file-size"` and
|
||||
`reported_limits.maximum_input_bytes`/`remaining_input_bytes`; input that is not
|
||||
|
||||
@@ -106,7 +106,12 @@ nodes. REA evaluates compatible static candidates conservatively:
|
||||
that disagreement. If a mapped candidate's digest is unavailable and no
|
||||
mapped content match is known, the comparison remains `unknown`.
|
||||
6. Missing authorization mappings and incomplete or truncated input coverage
|
||||
remain unknown or truncated rather than becoming absence claims.
|
||||
remain unknown or truncated rather than becoming absence claims. A runtime
|
||||
location with no automatic artifact-root or caller-declared mapping into
|
||||
any layer, and no content match, is `unknown` with
|
||||
`no-authorized-location-mapping`, with or without captured bytes; several
|
||||
content matches remain `ambiguous` under rule 4. Only a mapped location can
|
||||
be `unmatched` with `no-static-content-match`.
|
||||
|
||||
Every successful cross-layer `observed_as` edge has
|
||||
`authority: cross-layer-reconciliation` and `state: inferred`. The underlying
|
||||
|
||||
+12
-10
@@ -28,17 +28,19 @@ JEB service is reachable or that a project is open; use the existing
|
||||
MCP `binary_session` probes the live JEB service and its advertised tool catalog.
|
||||
Availability is reported per operation: a reachable headless client can support
|
||||
inspection and decompilation while refusing `open_jeb_project`. Catalog discovery
|
||||
uses one 60-second deadline across connection and pagination; a responsive server
|
||||
cannot keep discovery running indefinitely by returning more pages.
|
||||
is one deadline across connection and pagination; a responsive server cannot keep
|
||||
discovery running indefinitely by returning more pages.
|
||||
|
||||
Each upstream tool call has an absolute 60-second request deadline by default.
|
||||
Set `REA_JEB_MCP_TIMEOUT_MS` to a positive decimal number of milliseconds to
|
||||
select a different per-request budget, for example `REA_JEB_MCP_TIMEOUT_MS=300000`
|
||||
for a five-minute decompilation. This budget starts after discovery and applies
|
||||
to each individual `tools/call`; it does not extend the separate catalog deadline
|
||||
or establish one end-to-end deadline across a whole CLI or MCP operation. A
|
||||
request that reaches its budget returns a typed timeout, while caller
|
||||
cancellation remains a cancellation.
|
||||
Catalog discovery and each `tools/call` share `REA_JEB_MCP_TIMEOUT_MS`. Set it
|
||||
in REA's launch environment to an integer from 1 to 2147483647 milliseconds,
|
||||
for example `REA_JEB_MCP_TIMEOUT_MS=300000` for a five-minute budget. Omitted
|
||||
means the pinned MCP client SDK default of 60000 ms (`@modelcontextprotocol/client`
|
||||
2.3.1). Restart REA and reconnect to apply a change. Raising the setting raises
|
||||
both phases. It does not make one end-to-end deadline across a whole CLI or MCP
|
||||
operation: discovery and each `tools/call` each get that budget. A request that
|
||||
reaches its budget returns a typed timeout naming the phase and the effective
|
||||
milliseconds, while caller cancellation remains a cancellation. Allow execution,
|
||||
cleanup, and delivery headroom in the outer MCP client deadline.
|
||||
|
||||
Earlier verification used JEB 5.48.0 (Linux x64, licensed build) serving `jeb-mcp-server` 1.3.0 over streamable HTTP. The official Linux x64 CE build `5.48.0.202610071539` was also verified through real CLI and production stdio MCP native-code workflows; see the [Linux CE audit](../experiments/analysis-efficiency/jeb-linux-native.md) for measurements and limits. CE verification does not establish licensed/Demo Android decompilation or GUI behavior.
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ The background export belongs to the session. `close_binary`, or the end of a CL
|
||||
|
||||
The assembly label index is scanned once per export reader. Cancelling a request stops its wait without interrupting other readers; closing the session aborts and drains the shared scan before releasing its files.
|
||||
|
||||
Regex procedure and string search uses ECMAScript Unicode matching in a cancellable worker with a five-second matching deadline. Literal matching remains the default. Cancellation or a matching deadline leaves the session available.
|
||||
Regex procedure and string search uses ECMAScript Unicode matching in a cancellable worker with a five-second matching deadline and a worker old-generation heap. Literal matching remains the default. Cancellation or a matching deadline leaves the session available. This release has no runtime override for that deadline. The worker requests 128 MiB. A positive Node.js `--max-old-space-size` on the process that starts REA, including `NODE_OPTIONS`, overrides that request and sets the effective heap. `--max-old-space-size-percentage` takes precedence over that flag in either order. REA does not turn the percentage into a MiB, so the effective heap stays unestablished instead of the 128 MiB request or the absolute flag. The reported `NODE_OPTIONS` value is the process initial environment when that block can be read. A later edit to the environment is not the value Node applied, and an unreadable initial value leaves the effective heap unestablished. The launch Node options are the initial command line on Linux when that buffer still has a program entry, not a later edit to `process.execArgv`. A preload can clear that array after V8 has applied the flags. Setting `process.title` or `--title` overwrites the command line, so a buffer without a program entry leaves the effective heap unestablished. `--env-file` or `--env-file-if-exists` can supply `NODE_OPTIONS` when the initial environment has none. That file is not part of the initial environment block, so the effective heap stays unestablished instead of the 128 MiB request. An initial `NODE_OPTIONS` is still used, because Node does not let the file replace it. A positive `--max-heap-size`, including the underscore form and launch `NODE_OPTIONS` on Node versions that allow it, sets the total heap rather than the old generation and can be lower than the 128 MiB request. The effective old generation stays unestablished while that value is in effect. A zero or empty value clears it. `--experimental-config-file` or `--experimental-default-config-file` can set `nodeOptions`, including a heap percentage, from a file that is not read back. The effective heap stays unestablished when either flag is present, including when an absolute `--max-old-space-size` is also on the command line or in the recovered `NODE_OPTIONS`. Node accepts the config path as `=` or the next argument.
|
||||
|
||||
Single-function subprocess output and each cached source facet share a 16 MiB buffered-text capacity. Cached spans are checked before allocation; larger text remains in the local export and the error identifies the file and range. `analyze_function` initially returns the complete dossier, which can still be large; later retained views do not remove that first transfer. Prefer the individual text tools for a focused question.
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ rejects selected summary before analysis; complete delivery remains available.
|
||||
|
||||
Complete `inspect_managed_members` delivery always includes the assembly-wide
|
||||
`member_refs` and `exported_types`, which `type_names` does not narrow, so even
|
||||
one selected or unmatched type can return megabytes. Select
|
||||
one selected or unmatched type can return megabytes. In MCP, select
|
||||
`{"path":"/absolute/path/Assembly.dll","type_names":["Namespace.Type"],"detail":"summary"}`
|
||||
to keep the complete source in the session and receive identity, metadata
|
||||
status, the selection with its unmatched names, coverage/issues, the separate
|
||||
@@ -115,6 +115,49 @@ literal pool's own coverage. Older Evidence that never examined exported types
|
||||
or user strings reports a null count and refuses those pages rather than
|
||||
returning an empty one.
|
||||
|
||||
#### CLI summary and saved member rows
|
||||
|
||||
The CLI accepts the same `complete` and `summary` detail choices. Omitted or
|
||||
`--detail complete` returns complete Evidence. To receive a summary, choose a
|
||||
new Evidence bundle destination so its original complete parent remains
|
||||
available after the command exits:
|
||||
|
||||
```bash
|
||||
rea inspect-managed-members /absolute/path/Assembly.dll --type Namespace.Type \
|
||||
--detail summary --evidence-bundle /absolute/path/evidence/members.json --json
|
||||
```
|
||||
|
||||
`--evidence-bundle` writes the complete original Evidence in REA's canonical
|
||||
bundle format. Its parent directory must exist, and it never replaces an
|
||||
existing path. Relative paths resolve against the command's working directory.
|
||||
The option also works with complete delivery when a saved bundle is useful.
|
||||
Summary without a destination is rejected before analysis. A publication failure
|
||||
returns a typed error with the completed Evidence under
|
||||
`details.partial_observation`; it does not report successful summary delivery.
|
||||
Cancellation before publication prevents the new output. Once atomic
|
||||
publication has started, it can complete despite cancellation; a cancelled
|
||||
delivery then retains the committed path and byte count under
|
||||
`details.diagnostics.evidence_bundle`.
|
||||
|
||||
Copy `normalized_result.parent_evidence_id` from the summary into the
|
||||
`source.evidence_id` field of the `managed-members` request above, then save that
|
||||
small request as `members-page.json` and run:
|
||||
|
||||
```bash
|
||||
rea inspect-analysis-view /absolute/path/evidence/members-page.json \
|
||||
--evidence-bundle /absolute/path/evidence/members.json --json
|
||||
```
|
||||
|
||||
The view command authenticates the selected bundle and resolves that exact
|
||||
parent ID. It does not reopen the assembly, so the original target may have
|
||||
been moved or removed. Subsequent calls can select another collection or use
|
||||
the returned `coverage.next_offset` to continue the same collection. An inline
|
||||
source already includes its parent and cannot also select `--evidence-bundle`.
|
||||
|
||||
Summary changes delivery, while type selection still controls decoding and the
|
||||
same inspection resource limits apply. Each separate CLI page reads and
|
||||
authenticates the saved bundle; the full source is retained on disk.
|
||||
|
||||
## Shipped scope
|
||||
|
||||
The canonical parser admits PE/CLI bytes and their metadata/CIL without loading
|
||||
@@ -622,6 +665,9 @@ which managed methods executed or how the CLR resolved them.
|
||||
|
||||
Managed member comparisons report a `metadata` dimension when an observed
|
||||
MethodDef flags or implementation flags value differs, including accessibility
|
||||
or synchronization changes. This is separate from the CIL/signature matching
|
||||
tiers: identical instructions do not establish unchanged method metadata. The
|
||||
reported difference is static metadata evidence, not proof of runtime behavior.
|
||||
or synchronization changes. Observed method-body `init_locals` and `max_stack`
|
||||
differences also contribute to `metadata`, even when CIL decoding is incomplete.
|
||||
An unavailable header value keeps body coverage unknown rather than establishing
|
||||
equality or a difference. These comparisons are separate from the CIL/signature
|
||||
matching tiers: identical instructions do not establish unchanged method metadata.
|
||||
The reported difference is static metadata evidence, not proof of runtime behavior.
|
||||
+56
-20
@@ -234,11 +234,14 @@ The destination changes only when a complete export is atomically published.
|
||||
|
||||
Clients that explicitly configure a larger receive buffer can set the REA
|
||||
server's `REA_MCP_MAX_RESPONSE_BYTES` environment variable to the same byte
|
||||
count. This setting must be a safe decimal integer at least 10485760; REA
|
||||
reserves 1024 bytes for the envelope. Raising it restores complete inline
|
||||
delivery for responses that fit that buffer and Node's single-string limit.
|
||||
It does not change the client's buffer, analysis coverage, or retained content.
|
||||
Ordinary responses keep their existing complete result contract.
|
||||
count. This setting must be a safe decimal integer at least 10485760 (10 MiB);
|
||||
REA reserves 1024 bytes for the envelope. The value is read when the REA
|
||||
process starts, so a change requires a restart and a matching client receive
|
||||
buffer. Raising it restores complete inline delivery for responses that fit
|
||||
that buffer. It does not raise REA's reserved single-string limit, which is
|
||||
1024 UTF-16 code units below Node's single-string ceiling, and it does not
|
||||
raise that Node ceiling. It does not change analysis coverage or retained
|
||||
content. Ordinary responses keep their existing complete result contract.
|
||||
|
||||
### Error recovery and deadline ownership
|
||||
|
||||
@@ -329,7 +332,7 @@ See [environment manifests](web-network-captures.md#environment-manifest).
|
||||
|
||||
`inspect_analysis_view` also accepts `environment-state` for the same parents,
|
||||
extracting the initial state the recorded reads observed: entity types with an
|
||||
identity field, entities, documents for written non-entity paths, and a render
|
||||
identity field, entities, documents for non-entity reads, and a render
|
||||
plan per read tool that reproduces its recordings from the state or names why it
|
||||
cannot. Types and identity are inferences, so the Evidence is always inferred.
|
||||
See [environment state](web-network-captures.md#environment-state).
|
||||
@@ -352,10 +355,41 @@ application and semantic coverage. The result carries a digest of the selected
|
||||
facts. Actual serialized size determines MCP transport admission: reduce the
|
||||
page size or export retained Evidence if the view is too large.
|
||||
|
||||
`compare_source_to_bundle` accepts the committed historical graph inline or as
|
||||
`reference: {"kind":"file","path":"/absolute/reference.json"}`. The shared
|
||||
reader checks resource bounds and the graph's root commitment on every read. File-backed
|
||||
comparison Evidence records `parameters.reference_source`: the exact
|
||||
`requested_path` and the reader's absolute selected `path`, preserving POSIX
|
||||
`..`/symlink semantics. Normalized comparison facts and mapping identities agree
|
||||
with inline input; Evidence IDs distinguish caller-selected file origins.
|
||||
Omitting `view` preserves the complete comparison. For a compact initial reply,
|
||||
select `view: {"kind":"summary"}` or a `source-to-bundle` page; the session retains
|
||||
the complete comparison before delivery. Later calls use `inspect_analysis_view`
|
||||
with the returned `parent_evidence_id`.
|
||||
|
||||
A `source-to-bundle` view selects `collection: "mappings"` or `"candidates"` with
|
||||
exact `source_paths`, `mapping_ids`, `statuses`, `fields`, `offset` and `limit`.
|
||||
Omitted filters select all; empty arrays select none. The default mapping fields
|
||||
include status, confidence, source digest/language and candidate/mapped counts.
|
||||
Candidate defaults include kind, score and confidence; request `signals` for exact
|
||||
supporting values. Mapping identity and `source_index` always remain; candidates
|
||||
also retain `current_node_id`, `candidate_index` and whether they were actually
|
||||
mapped. Indices refer to the complete comparison's item array and that item's
|
||||
candidate array. All classifications are computed before selection. The original
|
||||
`source_coverage` remains separate from page `coverage`; exhausting a page never
|
||||
turns unknown correspondence into absence or proves behavioral equivalence.
|
||||
|
||||
The CLI accepts the same reference-file alternative (relative paths resolve from
|
||||
the working directory). Save its complete `--json` Evidence, then use
|
||||
`inspect-analysis-view` with an `evidence-file` source and the same view. Neither
|
||||
adapter executes the target or repeats analysis for retained queries.
|
||||
|
||||
Completed `inspect_artifact` and atomic `inventory_artifact` Evidence also
|
||||
support summary and inventory views. A summary reports the manifest's expected
|
||||
counts separately from available record counts, observed entry kinds, inventory
|
||||
Evidence IDs and inspection coverage. An inventory view selects `nodes`,
|
||||
Evidence IDs, the inventory producer's traversal `source_coverage` and
|
||||
inspection coverage. Inspection coverage is `partial` when that traversal
|
||||
coverage is unknown. An inventory view selects `nodes`,
|
||||
`occurrences`, `edges`, or `integrity_contradictions`, with `offset` and `limit`
|
||||
defaulting to 0 and 64. For occurrences, optional `logical_paths` matches exact
|
||||
recorded strings: omission selects all available records; `[]` selects none.
|
||||
@@ -805,13 +839,13 @@ auto-analysis, bridge connection, and health readiness before returning analysis
|
||||
|
||||
These deadlines have different owners:
|
||||
|
||||
| Deadline | Owner and effect |
|
||||
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| MCP initialize | The client bounds transport/REA connection startup, before any target query. |
|
||||
| Hopper startup | REA allows 120,000 ms by default; `REA_HOPPER_STARTUP_TIMEOUT_MS` accepts decimal integers from 1–2,147,483,647 ms. Invalid values fail configuration validation. Startup failure is reported by the first provider query. |
|
||||
| Ghidra startup | REA allows 330,000 ms by default; `REA_GHIDRA_STARTUP_TIMEOUT_MS` accepts decimal integers from 1–2,147,483,647 ms. Invalid supplied values fail configuration validation. Startup failure is reported by the first provider query. |
|
||||
| Darwin swiftc helper | REA allows 120,000 ms by default for ownership-helper compilation; `REA_SWIFTC_COMPILE_TIMEOUT_MS` accepts decimal integers from 1–2,147,483,647 ms. Invalid values fail configuration validation. |
|
||||
| Individual tool call | The client bounds its wait, including cold engine startup. The pinned client SDK 2.3.1 defaults to 60,000 ms and can cancel earlier than REA's startup deadline. |
|
||||
| Deadline | Owner and effect |
|
||||
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| MCP initialize | The client bounds transport/REA connection startup, before any target query. |
|
||||
| Hopper startup | REA allows 120,000 ms by default; `REA_HOPPER_STARTUP_TIMEOUT_MS` accepts decimal integers from 1–2,147,483,647 ms. Invalid values fail configuration validation. Startup failure is reported by the first provider query. |
|
||||
| Ghidra startup | REA allows 330,000 ms by default; `REA_GHIDRA_STARTUP_TIMEOUT_MS` accepts decimal integers from 1–2,147,483,647 ms. Invalid supplied values fail configuration validation. Startup failure is reported by the first provider query. |
|
||||
| Darwin swiftc helper | REA allows 120,000 ms by default for ownership-helper compilation; `REA_SWIFTC_COMPILE_TIMEOUT_MS` accepts decimal integers from 1–2,147,483,647 ms. Invalid values fail configuration validation. Set it in the environment that starts REA and restart REA; the next ownership-helper compile uses the new value. |
|
||||
| Individual tool call | The client bounds its wait, including cold engine startup. The pinned client SDK 2.3.1 defaults to 60,000 ms and can cancel earlier than REA's startup deadline. |
|
||||
|
||||
For [Codex and Kimi registrations](client-configuration.md), setup supplies
|
||||
missing tool deadlines from the known provider allowance plus 120 seconds of
|
||||
@@ -819,7 +853,8 @@ operation headroom: 450 seconds with the default Ghidra allowance, or 2820
|
||||
seconds with `REA_GHIDRA_STARTUP_TIMEOUT_MS=2700000`. Positive caller-selected
|
||||
deadlines remain unchanged. Doctor reports an informational recommendation
|
||||
when a configured deadline is shorter than the known provider allowance. An
|
||||
explicit JEB upstream request budget also contributes to that allowance.
|
||||
explicit JEB upstream deadline (`REA_JEB_MCP_TIMEOUT_MS`, shared by catalog
|
||||
discovery and each tools/call) also contributes to that allowance.
|
||||
|
||||
For an already connected client using the pinned SDK, request options are the
|
||||
**second** argument of `callTool`:
|
||||
@@ -1018,14 +1053,15 @@ verify the compact advertisement through the same client boundary.
|
||||
|
||||
Some function-calling providers reject a request while any single tool's
|
||||
`parameters` schema exceeds a literal serialized size cap; Moonshot clients
|
||||
such as kimi-cli fail every request while the default catalog is attached
|
||||
such as kimi-cli have reported failures with the full catalog attached
|
||||
([#1484](https://github.com/morluto/rea/issues/1484)). Setting the server's
|
||||
`REA_MCP_INPUT_SCHEMA_PROFILE` environment variable to `compact` renders every
|
||||
advertised input schema within a 13,312-byte budget, measured to sit below
|
||||
`REA_MCP_INPUT_SCHEMA_PROFILE` environment variable to `compact` (the default)
|
||||
renders every advertised input schema within a 13,312-byte budget, measured to sit below
|
||||
Moonshot's observed cap (community measurements: a 13.7 KB schema is accepted
|
||||
while a ~15 KB one is rejected). The setting is read at startup; restart the
|
||||
server to apply changes, as with `REA_MCP_MAX_RESPONSE_BYTES`. The default
|
||||
value `full` keeps the complete advertisement unchanged. Compact presentation
|
||||
server to apply changes, as with `REA_MCP_MAX_RESPONSE_BYTES`. Explicitly select
|
||||
`full` to retain complete advertised input guidance and nested validation detail.
|
||||
Existing explicit profile choices are preserved. Compact presentation
|
||||
also reduces schemas whose expanded JSON tree exceeds ten levels, the limit
|
||||
reported by strict-depth MCP clients in [#2813](https://github.com/morluto/rea/issues/2813).
|
||||
WorkBuddy/CodeBuddy gateways have also rejected full REA catalogs with an
|
||||
|
||||
@@ -202,8 +202,38 @@ Function dossiers retain this same string evidence. Native call edges retain
|
||||
Hopper's partial `CallReference` classification and exact endpoints; detailed
|
||||
reference flags remain unavailable rather than being invented.
|
||||
Regex searches use ECMAScript Unicode syntax in a cancellable worker with a
|
||||
five-second matching deadline. Deadline or cancellation stops matching while
|
||||
leaving the Hopper API available. Literal mode retains Unicode casefold matching.
|
||||
five-second matching deadline and a worker old-generation heap. Deadline or
|
||||
cancellation stops matching while leaving the Hopper API available. This
|
||||
release has no runtime override for that deadline. The worker requests 128
|
||||
MiB. A positive Node.js `--max-old-space-size` on the process that starts
|
||||
REA, including `NODE_OPTIONS`, overrides that request and sets the effective
|
||||
heap. `--max-old-space-size-percentage` takes precedence over that flag in
|
||||
either order. REA does not turn the percentage into a MiB, so the effective
|
||||
heap stays unestablished instead of the 128 MiB request or the absolute flag.
|
||||
The reported `NODE_OPTIONS` value is the process initial environment when that
|
||||
block can be read. A later edit to the environment is not the value Node
|
||||
applied, and an unreadable initial value leaves the effective heap
|
||||
unestablished. The launch Node options are the initial command line on Linux
|
||||
when that buffer still has a program entry, not a later edit to
|
||||
`process.execArgv`. A preload can clear that array after V8 has applied the
|
||||
flags. Setting `process.title` or `--title` overwrites the command line, so a
|
||||
buffer without a program entry leaves the effective heap unestablished.
|
||||
`--env-file` or `--env-file-if-exists` can supply `NODE_OPTIONS`
|
||||
when the initial environment has none. That file is not part of the initial
|
||||
environment block, so the effective heap stays unestablished instead of the
|
||||
128 MiB request. An initial `NODE_OPTIONS` is still used, because Node does
|
||||
not let the file replace it. A positive `--max-heap-size`, including the
|
||||
underscore form and launch `NODE_OPTIONS` on Node versions that allow it,
|
||||
sets the total heap rather than the old generation and can be lower than the
|
||||
128 MiB request. The effective old generation stays unestablished while that
|
||||
value is in effect. A zero or empty value clears it.
|
||||
`--experimental-config-file` or `--experimental-default-config-file` can set
|
||||
`nodeOptions`, including a heap percentage, from a file that is not read
|
||||
back. The effective heap stays unestablished when either flag is present,
|
||||
including when an absolute `--max-old-space-size` is also on the command
|
||||
line or in the recovered `NODE_OPTIONS`. Node accepts the config path as
|
||||
`=` or the next argument.
|
||||
Literal mode retains Unicode casefold matching.
|
||||
|
||||
## Bounded static traces
|
||||
|
||||
@@ -302,8 +332,13 @@ Binary plist inspection reads the original bytes through an owned file descripto
|
||||
so conversion cannot erase control characters, fractional dates, negative zero,
|
||||
or the high word of a 128-bit integer. It accepts at most 64 MiB of input and
|
||||
reserves an estimated 64 MiB decode budget before parsing; this estimate is not
|
||||
a hard process-memory bound. Binary-source provenance records the `file`
|
||||
classification without claiming a `plutil` conversion.
|
||||
a hard process-memory bound. A refused input reports non-retryable
|
||||
`resource_constraint` with `reported_limits.maximum_input_bytes`,
|
||||
`maximum_decoded_bytes` or, for nesting deeper than 128 levels,
|
||||
`maximum_nesting_depth`. These are fixed allowances: worker limits and host
|
||||
memory do not raise them, and the unchanged request fails the same way.
|
||||
Binary-source provenance records the `file` classification without claiming a
|
||||
`plutil` conversion.
|
||||
|
||||
A plist explicitly selected through the path input or as the active plist target
|
||||
reports an unreadable or malformed selection as `invalid_request`. A missing or
|
||||
@@ -432,6 +467,14 @@ complete observation.
|
||||
vtable descriptors. Records include exact virtual addresses/file offsets and
|
||||
artifact evidence. Vtable indexes are metadata word offsets; witness indexes
|
||||
start after the conformance header. Names unavailable in metadata remain null.
|
||||
The byte reader holds the whole selected file in memory, so it admits files up
|
||||
to 64 MiB / 67108864 bytes by default. Select a larger budget with
|
||||
`max_input_bytes` (CLI `--max-input-bytes`), at most 1 GiB / 1073741824
|
||||
bytes. The whole file counts, including every slice of a universal Mach-O.
|
||||
Results record `input_admission` with the effective budget, its source
|
||||
(`default` or `caller`) and the bytes retained. A refusal names the observed
|
||||
file size, the effective budget and its source, and either the budget to
|
||||
select or, above 1 GiB, a deep analysis provider.
|
||||
The `swift_class_vtable_descriptors` coverage counters count examined vtable
|
||||
slots and successfully decoded slots, rather than type-section entries.
|
||||
The `objc_class_method_ivar_metadata` counters count admitted class and
|
||||
@@ -532,8 +575,10 @@ cleanup. A later abort does not replace an earlier helper or output failure.
|
||||
Cleanup failures retain their runtime owner until a confirmed cleanup retry.
|
||||
|
||||
Scenarios accept caller-selected action lists and accessibility node counts.
|
||||
Individual waits cannot exceed the operation's 180-second deadline, and the
|
||||
complete scenario result has a 64 MiB output budget. Screenshots are scaled to
|
||||
One wait step stays capped at 180000 ms. That cap has no runtime override.
|
||||
The operation deadline is `native_ui_deadline_ms` (omitted means 180000 ms)
|
||||
and does not raise the wait-step cap. The complete scenario result has a
|
||||
64 MiB output budget. Screenshots are scaled to
|
||||
at most 2,048 pixels and captured only for the selected window. REA compiles one
|
||||
owned helper per scenario, removes its temporary compiler cache and stops its
|
||||
helper on cancellation. It does not launch or own the selected application. UI
|
||||
|
||||
@@ -545,6 +545,15 @@ missing or relative SDK/compiler path fails with an actionable prerequisite
|
||||
error before compilation. An incompatible installation reports the compiler's
|
||||
bounded diagnostics; REA does not repair or replace the toolchain.
|
||||
|
||||
The compile deadline is `REA_SWIFTC_COMPILE_TIMEOUT_MS`. An omitted value is
|
||||
120,000 ms, and accepted values are integers from 1 to 2,147,483,647. REA reads
|
||||
the variable from the environment that starts the process and keeps that
|
||||
deadline for every helper compile in that process. Restart REA to apply a
|
||||
change; the next ownership-helper compile uses the new value. A timeout names
|
||||
the effective milliseconds. Invalid values fail configuration validation at
|
||||
startup. Embedded compiler diagnostics are cut at 512 bytes, and this release
|
||||
has no runtime override for that excerpt.
|
||||
|
||||
For example, select paths from your existing Xcode or Command Line Tools
|
||||
installation **before** entering an enforced write boundary:
|
||||
|
||||
|
||||
@@ -145,6 +145,7 @@ npx rea-agents@latest setup
|
||||
| بنية ELF دون تشغيل | الأقسام والمقاطع والرموز ومعلومات إعادة التموضع الأصلية، وآليات الحماية المحتملة المستدلّ عليها بالفحص الثابت | pwntools يوفّره المستدعي على Linux x64؛ [تشخيص الملفات الثنائية](../binary-diagnostics.md) |
|
||||
| شيفرة EVM البايتية | محددات التوجيه، وإزاحات البايتات، والمعاملات المستنتجة، وقابلية تغيير الحالة | مدخل محلي يحمل بايتات خامًا أو تمثيلًا سداسيًا عشريًا على Linux x64؛ [دليل EVM دون تشغيل](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| أعطال Linux المسجّلة | سجلات note الخام، ومسجّلات المعالج/الإشارات لكل خيط مسجّل، وترشيحات اختيارية لخرائط الذاكرة | pwntools يوفّره المستدعي على Linux x64؛ GDB/pwndbg اختياريان؛ [الأعطال المسجّلة](../recorded-crashes.md) |
|
||||
| تثبيتات سطح المكتب | عائلات وقت التشغيل، والملفات الداعمة، وعلامات المكونات، والخطوات التالية | فحص محدود للملفات والترويسات;[تطبيقات سطح المكتب](../desktop-applications.md) |
|
||||
| JavaScript / Electron | الوحدات، وعمليات الاستيراد، وخرائط المصدر، والمسارات، وIPC، وعلاقات إضافات الشيفرة الأصلية | Node.js وnpm؛ [تحليل التطبيقات](../javascript-application-workflows.md) |
|
||||
@@ -267,6 +268,7 @@ npx rea-agents@latest setup
|
||||
|
||||
- [التثبيت والإعداد](../installation.md): تسجيل الوكلاء، وتهيئة الموفّرين، والتحديثات، وإلغاء التثبيت.
|
||||
- [الجاهزية واستكشاف الأخطاء](../installation.md#check-readiness-for-your-task): تشخيص وكيل أو محرك تحليل محدد.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI وEvidence](../cli.md): الأوامر، واختيار الموفّر، واللقطات، والاستيراد/التصدير، وحالات الخروج.
|
||||
- [عقود MCP](../mcp-contracts.md) و[تعليمات الوكلاء](../mcp-prompts.md): نتائج الأدوات، والجلسات، والاستقصاءات الموجّهة.
|
||||
|
||||
@@ -145,6 +145,7 @@ REA benötigt Node.js 22.x (>=22.19), 24.x (>=24.11) oder 26+ sowie npm. Zusätz
|
||||
| Offline-ELF-Struktur | Sektionen, Segmente, ursprüngliche Symbole/Relokationen und mögliche Schutzmaßnahmen aus statischer Analyse | Vom Aufrufer bereitgestelltes pwntools unter Linux x64; [Binärdiagnostik](../binary-diagnostics.md) |
|
||||
| EVM-Bytecode | Dispatch-Selektoren, Byte-Offsets, abgeleitete Argumente und Veränderbarkeit des Zustands | Lokale Eingabe mit Rohbytes oder Hexdarstellung unter Linux x64; [Offline-EVM-Leitfaden](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Aufgezeichnete Linux-Abstürze | Unverarbeitete Note-Einträge, Register/Signale aller aufgezeichneten Threads und optionale Zuordnungskandidaten | Vom Aufrufer bereitgestelltes pwntools unter Linux x64; optional GDB/pwndbg; [aufgezeichnete Abstürze](../recorded-crashes.md) |
|
||||
| Desktop-Installationen | Laufzeitkandidaten, Quelldateien, Komponenten und nächste Schritte | Begrenzte Verzeichnis- und Headerprüfung;[Desktop-Anwendungen](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Module, Imports, Source Maps, Routen, IPC und Beziehungen zu nativen Add-ons | Node.js und npm; [Anwendungsanalyse](../javascript-application-workflows.md) |
|
||||
@@ -265,6 +266,7 @@ Beginne mit den [praxisnahen Anleitungen](https://rea.tools/de/guides/) auf der
|
||||
|
||||
- [Installation und Einrichtung](../installation.md): Agentenregistrierung, Provider-Konfiguration, Updates und Deinstallation.
|
||||
- [Bereitschaft und Fehlerbehebung](../installation.md#check-readiness-for-your-task): Diagnose eines bestimmten Agenten oder einer Analyse-Engine.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI und Evidence](../cli.md): Befehle, Provider-Auswahl, Snapshots, Import/Export und Exit-Status.
|
||||
- [MCP-Kontrakte](../mcp-contracts.md) und [Agenten-Prompts](../mcp-prompts.md): Werkzeugergebnisse, Sitzungen und geführte Untersuchungen.
|
||||
|
||||
@@ -149,6 +149,7 @@ npx rea-agents@latest setup
|
||||
| Δομή ELF χωρίς εκτέλεση | Ενότητες, τμήματα, αρχικά σύμβολα/εγγραφές μετεγκατάστασης και ενδείξεις πιθανών μέτρων προστασίας από στατική ανάλυση | pwntools που παρέχει ο χρήστης σε Linux x64· [διαγνωστικά δυαδικών αρχείων](../binary-diagnostics.md) |
|
||||
| Δυαδικά αρχεία Go | Ενσωματωμένη έκδοση μεταγλωττιστή, modules, αντικαταστάσεις και ρυθμίσεις μεταγλώττισης | Ενσωματωμένη στατική εξέταση ELF/PE/thin Mach-O· δεν απαιτείται εγκατάσταση του Go |
|
||||
| Δυαδικά αρχεία Rust | Ενσωματωμένα ονόματα, εκδόσεις, πηγές και σχέσεις εξάρτησης των crates από το cargo-auditable | Ενσωματωμένη στατική εξέταση ELF/PE/thin Mach-O· [δυαδικά αρχεία Rust](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Αρχείο WASM | Έλεγχο εγκυρότητας, ενότητες, ακριβείς μορφές εισαγωγών/εξαγωγών σε WAT και αποκωδικοποιημένο WAT | WABT 1.0.42 που παρέχει ο χρήστης· `inspect_wasm_artifact` |
|
||||
| Bytecode EVM | Selectors επιλογής συνάρτησης, μετατοπίσεις σε bytes, εκτιμώμενα ορίσματα και δυνατότητα μεταβολής της κατάστασης | Τοπική είσοδος σε ακατέργαστα bytes ή δεκαεξαδική μορφή σε Linux x64· [οδηγός EVM χωρίς εκτέλεση](../evm-bytecode.md) |
|
||||
| Βάσεις δεδομένων SQLite | Πίνακες, στήλες, ευρετήρια, όψεις, triggers και επιλεγμένες γραμμές κανονικών πινάκων | Τοπικό στιγμιότυπο βάσης δεδομένων/WAL· Node.js 24.x >=24.15 ή 26+ με εγγενή όρια SQLite |
|
||||
@@ -278,6 +279,7 @@ npx rea-agents@latest setup
|
||||
|
||||
- [Εγκατάσταση και ρύθμιση](../installation.md): καταχώριση agents, ρύθμιση παρόχων ανάλυσης, ενημερώσεις και απεγκατάσταση.
|
||||
- [Έλεγχος ετοιμότητας και αντιμετώπιση προβλημάτων](../installation.md#check-readiness-for-your-task): διάγνωση ενός agent ή μιας μηχανής ανάλυσης.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI και Evidence](../cli.md): εντολές, επιλογή παρόχου, στιγμιότυπα, εισαγωγή/εξαγωγή και κωδικοί εξόδου.
|
||||
- [Προδιαγραφές MCP](../mcp-contracts.md) και [prompts για agents](../mcp-prompts.md): αποτελέσματα εργαλείων, συνεδρίες και καθοδηγούμενες διερευνήσεις.
|
||||
|
||||
@@ -145,6 +145,7 @@ REA requiere Node.js 22.x (>=22.19), 24.x (>=24.11) o 26+, además de npm. Las h
|
||||
| Estructura ELF sin ejecutar | Secciones, segmentos, símbolos/reubicaciones originales y posibles medidas de mitigación detectadas mediante análisis estático | pwntools proporcionado por quien llama, en Linux x64; [diagnóstico de binarios](../binary-diagnostics.md) |
|
||||
| Bytecode EVM | Selectores de despacho, desplazamientos en bytes, argumentos inferidos y mutabilidad | Entrada local con bytes sin procesar o representación hexadecimal, en Linux x64; [guía de EVM sin ejecutar](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Fallos de Linux registrados | Registros note sin procesar, registros/señales de cada hilo registrado y posibles correspondencias de memoria opcionales | pwntools proporcionado por quien llama, en Linux x64; GDB/pwndbg opcionales; [fallos registrados](../recorded-crashes.md) |
|
||||
| Instalaciones de escritorio | Posibles entornos de ejecución, archivos de evidencia, componentes y siguientes pasos | Inspección acotada de directorios y cabeceras;[Aplicaciones de escritorio](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Módulos, importaciones, mapas de código fuente, rutas, IPC y relaciones con complementos nativos | Node.js y npm; [análisis de aplicaciones](../javascript-application-workflows.md) |
|
||||
@@ -265,6 +266,7 @@ Empieza con las [guías prácticas](https://rea.tools/es/guides/) del sitio web.
|
||||
|
||||
- [Instalación y configuración](../installation.md): registro de agentes, configuración de proveedores, actualizaciones y desinstalación.
|
||||
- [Preparación y resolución de problemas](../installation.md#check-readiness-for-your-task): diagnóstico de un agente o motor de análisis concreto.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI y Evidence](../cli.md): comandos, selección de proveedores, instantáneas, importación/exportación y estados de salida.
|
||||
- [Contratos de MCP](../mcp-contracts.md) y [prompts para agentes](../mcp-prompts.md): resultados de herramientas, sesiones e investigaciones guiadas.
|
||||
|
||||
@@ -137,6 +137,7 @@ REA به Node.js 22.x (>=22.19)، 24.x (>=24.11) یا 26+، بههمراه np
|
||||
| ساختار ELF آفلاین | بخشها، سگمنتها، نمادها و relocationهای اصلی و گزینههای احتمالی کاهش آسیبپذیری ایستا | pwntools تأمینشده توسط فراخواننده روی Linux x64؛ [تشخیص باینری](../binary-diagnostics.md) |
|
||||
| بایتکد EVM | selectorهای dispatch، offsetهای بایتی، آرگومانهای استنباطشده و قابلیت تغییر وضعیت | دادهٔ خام/hex محلی روی Linux x64؛ [راهنمای EVM آفلاین](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| کرشهای ثبتشدهٔ لینوکس | یادداشتهای خام، رجیسترها/سیگنالهای تمام threadهای ثبتشده و گزینههای احتمالی نگاشت | pwntools تأمینشده توسط فراخواننده روی Linux x64؛ GDB/pwndbg اختیاری؛ [کرشهای ثبتشده](../recorded-crashes.md) |
|
||||
| نصبهای دسکتاپ | نامزدهای زمان اجرا، فایلهای شاهد، نشانههای مؤلفهها و مراحل بعدی | بررسی محدود پوشهها و سرآیندها;[برنامههای دسکتاپ](../desktop-applications.md) |
|
||||
| JavaScript / Electron | ماژولها، importها، source mapها، مسیرها، IPC و ارتباط افزونههای بومی | Node.js و npm؛ [تحلیل برنامه](../javascript-application-workflows.md) |
|
||||
@@ -250,6 +251,7 @@ npx rea-agents@latest setup
|
||||
|
||||
- [نصب و راهاندازی](../installation.md): ثبت ایجنت، پیکربندی ارائهدهنده، بهروزرسانی و حذف نصب.
|
||||
- [آمادگی و رفع اشکال](../installation.md#check-readiness-for-your-task): عیبیابی یک ایجنت یا موتور تحلیل.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI و شواهد](../cli.md): دستورات، انتخاب ارائهدهنده، snapshotها، ورود/خروج داده و وضعیتهای خروج.
|
||||
- [قراردادهای MCP](../mcp-contracts.md) و [پرامپتهای ایجنت](../mcp-prompts.md): نتایج ابزارها، نشستها و بررسیهای هدایتشده.
|
||||
|
||||
@@ -149,6 +149,7 @@ REA nécessite Node.js 22.x (>=22.19), 24.x (>=24.11) ou 26+, ainsi que npm. Les
|
||||
| Artefact WASM | Validation, sections, formes WAT exactes d'import/export et WAT décodé | WABT 1.0.42 fourni par l'utilisateur ; `inspect_wasm_artifact` |
|
||||
| Bytecode EVM | Sélecteurs de dispatch, offsets en octets, arguments inférés et mutabilité | Fichier local brut ou hexadécimal sous Linux x64 ; [guide EVM hors ligne](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Crashs Linux enregistrés | Notes brutes, registres et signaux de chaque thread enregistré, et correspondances de mappings facultatives | pwntools fourni par l'utilisateur sous Linux x64 ; GDB/pwndbg en option ; [crashs enregistrés](../recorded-crashes.md) |
|
||||
| Installations de bureau | Environnements candidats, fichiers justificatifs, composants et étapes suivantes | Inspection bornée des répertoires et en-têtes;[Applications de bureau](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Modules, imports, source maps, routes, IPC et relations avec les modules natifs | Node.js et npm ; [analyse d'applications](../javascript-application-workflows.md) |
|
||||
@@ -269,6 +270,7 @@ Commencez par les [guides pas à pas](https://rea.tools/fr/guides/) du site web.
|
||||
|
||||
- [Installation et configuration](../installation.md) : enregistrement des agents, configuration des fournisseurs, mises à jour et désinstallation.
|
||||
- [Vérification et dépannage](../installation.md#check-readiness-for-your-task) : diagnostiquer un agent ou un moteur d'analyse donné.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI et Evidence](../cli.md) : commandes, choix du fournisseur, snapshots, import/export et codes de sortie.
|
||||
- [Contrats MCP](../mcp-contracts.md) et [prompts pour agents](../mcp-prompts.md) : résultats des outils, sessions et investigations guidées.
|
||||
|
||||
@@ -152,6 +152,7 @@ Alat tambahan dan dukungan sistem host bergantung pada target yang dianalisis:
|
||||
| Artefak WASM | Validasi, bagian, bentuk WAT import/ekspor yang tepat, dan WAT yang didekode | WABT 1.0.42 yang disediakan pemanggil; `inspect_wasm_artifact` |
|
||||
| Bytecode EVM | Selector dispatch, offset byte, argumen yang disimpulkan, dan sifat mutabilitas | Pembawa data raw/hex lokal; [panduan EVM offline](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Crash Linux yang direkam | Catatan mentah, register/sinyal setiap thread yang direkam, dan kandidat pemetaan opsional | pwntools yang disediakan pemanggil; GDB/pwndbg opsional; [crash yang direkam](../recorded-crashes.md) |
|
||||
| Instalasi desktop | Kandidat runtime, berkas pendukung, penanda komponen, dan langkah berikutnya | Pemeriksaan direktori dan header terbatas;[Aplikasi desktop](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Modul, impor, source map, rute, IPC, dan hubungan add-on native | Node.js dan npm; [analisis aplikasi](../javascript-application-workflows.md) |
|
||||
@@ -290,6 +291,7 @@ Untuk mengetahui opsi, prasyarat, dan kontrak hasil secara tepat:
|
||||
|
||||
- [Instalasi dan penyiapan](../installation.md): pendaftaran agen, konfigurasi penyedia, pembaruan, dan penghapusan instalasi.
|
||||
- [Kesiapan dan pemecahan masalah](../installation.md#check-readiness-for-your-task): mendiagnosis satu agen atau mesin analisis.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI dan Bukti](../cli.md): perintah, pemilihan penyedia, snapshot, impor/ekspor, dan status keluar.
|
||||
- [Kontrak MCP](../mcp-contracts.md) dan [prompt agen](../mcp-prompts.md): hasil alat, sesi, dan investigasi terpandu.
|
||||
|
||||
@@ -149,6 +149,7 @@ REA richiede Node.js 22.x (>=22.19), 24.x (>=24.11) o 26+, oltre a npm. Strument
|
||||
| Artefatto WASM | Convalida, sezioni, forme WAT di import/export esatte e WAT decodificato | WABT 1.0.42 fornito dal chiamante; `inspect_wasm_artifact` |
|
||||
| Bytecode EVM | Selettori di dispatch, offset dei byte, argomenti inferiti e mutabilità | Carrier raw/hex locale; [guida EVM offline](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Crash Linux registrati | Note grezze, registri/segnai di ogni thread registrato e candidati mapping opzionali | pwntools fornito dal chiamante; GDB/pwndbg opzionale; [crash registrati](../recorded-crashes.md) |
|
||||
| Installazioni desktop | Runtime candidati, file di supporto, componenti e passi successivi | Ispezione limitata di directory e intestazioni;[Applicazioni desktop](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Moduli, import, source map, route, IPC e relazioni con add-on nativi | Node.js e npm; [analisi delle applicazioni](../javascript-application-workflows.md) |
|
||||
@@ -269,6 +270,7 @@ Inizia dalle [guide pratiche](https://rea.tools/it/guides/) del sito web. Per op
|
||||
|
||||
- [Installazione e configurazione](../installation.md): registrazione agente, configurazione provider, aggiornamenti e disinstallazione.
|
||||
- [Pronto all'uso e risoluzione dei problemi](../installation.md#check-readiness-for-your-task): diagnostica un agente o un motore di analisi.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI ed Evidence](../cli.md): comandi, selezione provider, snapshot, import/export e stati di uscita.
|
||||
- [Contratti MCP](../mcp-contracts.md) e [prompt agente](../mcp-prompts.md): risultati degli strumenti, sessioni e indagini guidate.
|
||||
|
||||
@@ -145,6 +145,7 @@ REA には Node.js 22.x(>=22.19)、24.x(>=24.11)、または 26+ と npm
|
||||
| オフライン ELF レイアウト | セクション、セグメント、元のシンボル/再配置情報、静的解析によるセキュリティ対策の候補 | Linux x64 で利用者が用意する pwntools;[バイナリ診断](../binary-diagnostics.md) |
|
||||
| EVM バイトコード | ディスパッチセレクター、バイトオフセット、推定された引数と状態変更の可否 | Linux x64 上のローカルの生バイト/16 進数の入力ファイル;[オフライン EVM ガイド](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| 記録済みの Linux クラッシュ | 生の note レコード、記録された全スレッドのレジスター/シグナル、任意のマッピング候補 | Linux x64 で利用者が用意する pwntools;GDB/pwndbg は任意;[記録済みクラッシュ](../recorded-crashes.md) |
|
||||
| デスクトップのインストール先 | ランタイム候補、根拠ファイル、コンポーネントの目印、次の調査手順 | 上限付きのディレクトリ・ヘッダー検査;[デスクトップアプリ](../desktop-applications.md) |
|
||||
| JavaScript / Electron | モジュール、インポート、ソースマップ、ルート、IPC、ネイティブアドオンの関係 | Node.js と npm;[アプリケーション分析](../javascript-application-workflows.md) |
|
||||
@@ -267,6 +268,7 @@ npx rea-agents@latest setup
|
||||
|
||||
- [インストールとセットアップ](../installation.md):エージェントの登録、プロバイダーの設定、更新、アンインストール。
|
||||
- [準備状況の確認とトラブルシューティング](../installation.md#check-readiness-for-your-task):特定のエージェントや分析エンジンを診断。
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI と Evidence](../cli.md):コマンド、プロバイダーの選択、スナップショット、インポート/エクスポート、終了ステータス。
|
||||
- [MCP 契約](../mcp-contracts.md)と[エージェント向けプロンプト](../mcp-prompts.md):ツールの結果、セッション、ガイド付き調査。
|
||||
|
||||
@@ -153,6 +153,7 @@ REA에는 Node.js 22.x(>=22.19), 24.x(>=24.11) 또는 26+와 npm이 필요합니
|
||||
| 오프라인 ELF 레이아웃 | 섹션, 세그먼트, 원본 심볼/재배치 정보, 정적 분석으로 얻은 보안 완화 기법 후보 | Linux x64에서 호출자가 제공하는 pwntools; [바이너리 진단](../binary-diagnostics.md) |
|
||||
| Go 바이너리 | 내장된 컴파일러 버전, 모듈, `replace` 지시어, 빌드 설정 | REA 내장 ELF/PE/thin Mach-O 정적 검사; Go 설치 불필요 |
|
||||
| Rust 바이너리 | cargo-auditable이 내장한 크레이트 이름, 버전, 소스, 의존성 관계 | REA 내장 ELF/PE/thin Mach-O 정적 검사; [Rust 바이너리](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| WASM 아티팩트 | 유효성 검사, 섹션, import/export의 정확한 WAT 형식, 디코딩된 WAT | 호출자 제공 WABT 1.0.42; `inspect_wasm_artifact` |
|
||||
| EVM 바이트코드 | 디스패치 선택자, 바이트 오프셋, 추론한 인자와 상태 변경 가능 여부 | Linux x64의 로컬 원시 바이트/16진수 입력 파일; [오프라인 EVM 가이드](../evm-bytecode.md) |
|
||||
| SQLite 데이터베이스 | 테이블, 열, 인덱스, 뷰, 트리거, 선택한 일반 테이블의 행 | 로컬 데이터베이스/WAL 스냅샷; Node.js 24.15 이상의 24.x 또는 26 이상(네이티브 SQLite 한도 적용) |
|
||||
@@ -280,6 +281,7 @@ npx rea-agents@latest setup
|
||||
|
||||
- [설치 및 설정](../installation.md): 에이전트 등록, 제공자 설정, 업데이트, 제거.
|
||||
- [준비 상태 확인 및 문제 해결](../installation.md#check-readiness-for-your-task): 특정 에이전트 또는 분석 엔진 진단.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI 및 Evidence](../cli.md): 명령, 제공자 선택, 스냅샷, 가져오기/내보내기, 종료 상태.
|
||||
- [MCP 계약](../mcp-contracts.md) 및 [에이전트 프롬프트](../mcp-prompts.md): 도구 결과, 세션, 안내에 따른 조사.
|
||||
|
||||
@@ -151,6 +151,7 @@ REA-യ്ക്ക് Node.js 22.x (>=22.19), 24.x (>=24.11), അല്ലെ
|
||||
| Offline ELF layout | Sections, segments, യഥാർത്ഥ symbols/relocations, static mitigation candidates | Linux x64-ൽ caller നൽകുന്ന pwntools; [binary diagnostics](../binary-diagnostics.md) |
|
||||
| Go binaries | ഉൾച്ചേർത്ത compiler version, modules, replacements, build settings | Built-in static ELF/PE/thin Mach-O പരിശോധന; Go installation ആവശ്യമില്ല |
|
||||
| Rust binaries | ഉൾച്ചേർത്ത cargo-auditable crate പേരുകൾ, versions, sources, dependency edges | Built-in static ELF/PE/thin Mach-O പരിശോധന; [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| WASM artifact | Validation, sections, കൃത്യമായ import/export WAT രൂപങ്ങൾ, decoded WAT | Caller നൽകുന്ന WABT 1.0.42; `inspect_wasm_artifact` |
|
||||
| EVM bytecode | Dispatch selectors, byte offsets, അനുമാനിച്ച arguments, mutability | Linux x64-ൽ local raw/hex carrier; [offline EVM guide](../evm-bytecode.md) |
|
||||
| SQLite databases | Tables, columns, indexes, views, triggers, തിരഞ്ഞെടുത്ത സാധാരണ table rows | Local database/WAL snapshot; native SQLite പരിമിതികളോടെ Node.js 24.x >=24.15 അല്ലെങ്കിൽ 26+ |
|
||||
@@ -283,6 +284,7 @@ npx rea-agents@latest setup
|
||||
|
||||
- [Installation and setup](../installation.md): agent registration, provider configuration, updates, uninstall.
|
||||
- [Readiness and troubleshooting](../installation.md#check-readiness-for-your-task): ഒരു agent-ന്റെയോ analysis engine-ന്റെയോ പ്രശ്നങ്ങൾ കണ്ടെത്തുക.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI and Evidence](../cli.md): commands, provider തിരഞ്ഞെടുക്കൽ, snapshots, import/export, exit statuses.
|
||||
- [MCP contracts](../mcp-contracts.md), [agent prompts](../mcp-prompts.md): tool results, sessions, guided investigations.
|
||||
|
||||
@@ -145,6 +145,7 @@ REA wymaga Node.js 22.x (>=22.19), 24.x (>=24.11) lub 26+ oraz npm. Dodatkowe na
|
||||
| Układ pliku ELF w trybie offline | Sekcje, segmenty, oryginalne symbole/relokacje i potencjalne mechanizmy zabezpieczeń wskazane przez analizę statyczną | pwntools dostarczone przez użytkownika w systemie Linux x64; [diagnostyka plików binarnych](../binary-diagnostics.md) |
|
||||
| Kod bajtowy EVM | Selektory wywołań, przesunięcia bajtowe, wywnioskowane argumenty i mutowalność | Lokalny plik z surowymi bajtami lub zapisem szesnastkowym w systemie Linux x64; [przewodnik EVM offline](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Zarejestrowane awarie systemu Linux | Surowe rekordy note, rejestry/sygnały każdego zarejestrowanego wątku i opcjonalni kandydaci na mapowania | pwntools dostarczone przez użytkownika w systemie Linux x64; opcjonalnie GDB/pwndbg; [zarejestrowane awarie](../recorded-crashes.md) |
|
||||
| Instalacje desktopowe | Kandydaci środowisk uruchomieniowych, pliki źródłowe dowodów, komponenty i dalsze kroki | Ograniczona inspekcja katalogów i nagłówków;[Aplikacje desktopowe](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Moduły, importy, mapy źródeł, trasy, IPC i powiązania z natywnymi dodatkami | Node.js i npm; [analiza aplikacji](../javascript-application-workflows.md) |
|
||||
@@ -265,6 +266,7 @@ Zacznij od [przewodników z przykładami](https://rea.tools/pl/guides/) na stron
|
||||
|
||||
- [Instalacja i konfiguracja](../installation.md): rejestracja agentów, konfiguracja dostawców analizy, aktualizacje i odinstalowanie.
|
||||
- [Gotowość i rozwiązywanie problemów](../installation.md#check-readiness-for-your-task): diagnostyka jednego agenta lub silnika analizy.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI i Evidence](../cli.md): polecenia, wybór dostawcy, migawki, import/eksport i kody zakończenia.
|
||||
- [Kontrakty MCP](../mcp-contracts.md) i [prompty dla agentów](../mcp-prompts.md): wyniki narzędzi, sesje i prowadzone analizy.
|
||||
|
||||
@@ -145,6 +145,7 @@ O REA requer Node.js 22.x (>=22.19), 24.x (>=24.11) ou 26+, além do npm. As fer
|
||||
| Estrutura ELF sem execução | Seções, segmentos, símbolos/relocações originais e possíveis mecanismos de mitigação identificados por análise estática | pwntools fornecido pelo chamador no Linux x64; [diagnóstico de binários](../binary-diagnostics.md) |
|
||||
| Bytecode EVM | Seletores de despacho, offsets de bytes, argumentos inferidos e mutabilidade | Entrada local com bytes brutos ou representação hexadecimal no Linux x64; [guia de EVM sem execução](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Falhas do Linux registradas | Registros note brutos, registradores/sinais de cada thread registrada e candidatos opcionais a mapeamentos | pwntools fornecido pelo chamador no Linux x64; GDB/pwndbg opcionais; [falhas registradas](../recorded-crashes.md) |
|
||||
| Instalações desktop | Ambientes candidatos, arquivos de evidência, componentes e próximos passos | Inspeção limitada de diretórios e cabeçalhos;[Aplicações desktop](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Módulos, importações, source maps, rotas, IPC e relações com complementos nativos | Node.js e npm; [análise de aplicativos](../javascript-application-workflows.md) |
|
||||
@@ -265,6 +266,7 @@ Comece pelos [guias práticos](https://rea.tools/pt-BR/guides/) do site. Para op
|
||||
|
||||
- [Instalação e configuração](../installation.md): registro de agentes, configuração de provedores, atualizações e desinstalação.
|
||||
- [Prontidão e solução de problemas](../installation.md#check-readiness-for-your-task): diagnóstico de um agente ou motor de análise específico.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI e Evidence](../cli.md): comandos, seleção de provedores, snapshots, importação/exportação e status de saída.
|
||||
- [Contratos MCP](../mcp-contracts.md) e [prompts para agentes](../mcp-prompts.md): resultados das ferramentas, sessões e investigações guiadas.
|
||||
|
||||
@@ -145,6 +145,7 @@ REA требует Node.js 22.x (>=22.19), 24.x (>=24.11) или 26+, а так
|
||||
| Структура ELF без запуска | Секции, сегменты, исходные символы/релокации и возможные механизмы защиты по данным статического анализа | pwntools, предоставленный вызывающей стороной, в Linux x64; [диагностика бинарных файлов](../binary-diagnostics.md) |
|
||||
| Байт-код EVM | Селекторы диспетчеризации, смещения байтов, предполагаемые аргументы и изменяемость состояния | Локальные необработанные байты или шестнадцатеричное представление в Linux x64; [руководство по EVM без запуска](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Записанные сбои Linux | Необработанные записи note, регистры/сигналы каждого записанного потока и необязательные кандидаты сопоставления с памятью | pwntools, предоставленный вызывающей стороной, в Linux x64; необязательные GDB/pwndbg; [записанные сбои](../recorded-crashes.md) |
|
||||
| Установленные настольные приложения | Возможные среды выполнения, файлы с доказательствами, компоненты и дальнейшие шаги | Ограниченная проверка каталогов и заголовков;[Настольные приложения](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Модули, импорты, карты исходного кода, маршруты, IPC и связи с нативными дополнениями | Node.js и npm; [анализ приложений](../javascript-application-workflows.md) |
|
||||
@@ -265,6 +266,7 @@ npx rea-agents@latest setup
|
||||
|
||||
- [Установка и настройка](../installation.md): регистрация агентов, настройка провайдеров, обновление и удаление.
|
||||
- [Готовность и устранение неполадок](../installation.md#check-readiness-for-your-task): диагностика конкретного агента или движка анализа.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI и Evidence](../cli.md): команды, выбор провайдера, снимки, импорт/экспорт и коды завершения.
|
||||
- [Контракты MCP](../mcp-contracts.md) и [промпты агентов](../mcp-prompts.md): результаты инструментов, сеансы и исследования с подсказками.
|
||||
|
||||
@@ -145,6 +145,7 @@ REA ต้องใช้ Node.js 22.x (>=22.19), 24.x (>=24.11) หรือ 26
|
||||
| โครงสร้าง ELF แบบออฟไลน์ | เซกชัน เซกเมนต์ สัญลักษณ์/รีโลเคชันต้นฉบับ และตัวเลือกกลไกป้องกันที่พบจากการวิเคราะห์แบบสถิต | pwntools ที่ผู้ใช้จัดเตรียมบน Linux x64; [การวินิจฉัยไบนารี](../binary-diagnostics.md) |
|
||||
| ไบต์โค้ด EVM | ตัวเลือกฟังก์ชันสำหรับการเรียก ออฟเซ็ตไบต์ อาร์กิวเมนต์และความสามารถในการเปลี่ยนสถานะที่อนุมานได้ | ไฟล์บนเครื่องที่มีไบต์ดิบหรือข้อมูลเลขฐานสิบหกบน Linux x64; [คู่มือ EVM แบบออฟไลน์](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| ข้อมูลการแครชของ Linux ที่บันทึกไว้ | ระเบียน note ดิบ รีจิสเตอร์/สัญญาณของทุกเธรดที่บันทึกไว้ และตัวเลือกการแมปเพิ่มเติม | pwntools ที่ผู้ใช้จัดเตรียมบน Linux x64; เลือกใช้ GDB/pwndbg เพิ่มเติมได้; [การแครชที่บันทึกไว้](../recorded-crashes.md) |
|
||||
| ไดเรกทอรีติดตั้งแอปเดสก์ท็อป | รันไทม์ที่เป็นไปได้ ไฟล์หลักฐาน ตัวบ่งชี้ส่วนประกอบ และขั้นตอนถัดไป | ตรวจสอบไดเรกทอรีและส่วนหัวโดยจำกัดขอบเขต;[แอปเดสก์ท็อป](../desktop-applications.md) |
|
||||
| JavaScript / Electron | โมดูล การนำเข้า ซอร์สแมป เส้นทาง IPC และความสัมพันธ์กับส่วนเสริมเนทีฟ | Node.js และ npm; [การวิเคราะห์แอปพลิเคชัน](../javascript-application-workflows.md) |
|
||||
@@ -265,6 +266,7 @@ npx rea-agents@latest setup
|
||||
|
||||
- [การติดตั้งและตั้งค่า](../installation.md): การลงทะเบียนเอเจนต์ การตั้งค่าผู้ให้บริการ การอัปเดต และการถอนการติดตั้ง
|
||||
- [ความพร้อมใช้งานและการแก้ไขปัญหา](../installation.md#check-readiness-for-your-task): ตรวจวินิจฉัยเอเจนต์หรือเอนจินวิเคราะห์หนึ่งตัว
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI และ Evidence](../cli.md): คำสั่ง การเลือกผู้ให้บริการ สแนปช็อต การนำเข้า/ส่งออก และรหัสการสิ้นสุด
|
||||
- [สัญญา MCP](../mcp-contracts.md) และ[พรอมป์ต์สำหรับเอเจนต์](../mcp-prompts.md): ผลลัพธ์เครื่องมือ เซสชัน และการตรวจสอบตามคำแนะนำ
|
||||
|
||||
@@ -147,6 +147,7 @@ REA; Node.js 22.x (>=22.19), 24.x (>=24.11) veya 26+ ve npm gerektirir. Ek araç
|
||||
| Çevrimdışı ELF yapısı | Bölümler, segmentler, özgün semboller/yeniden konumlandırmalar ve statik analizden olası güvenlik önlemleri | Linux x64 üzerinde çağıranın sağladığı pwntools; [ikili dosya tanılama](../binary-diagnostics.md) |
|
||||
| Go ikili dosyaları | Gömülü compiler sürümü, modüller, replacement'lar ve build ayarları | Yerleşik statik ELF/PE/thin Mach-O incelemesi; Go kurulumu gerekmez |
|
||||
| Rust ikili dosyaları | Gömülü cargo-auditable crate adları, sürümleri, kaynakları ve bağımlılık ilişkileri | Yerleşik statik ELF/PE/thin Mach-O incelemesi; [Rust ikili dosyaları](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| WASM artefaktı | Doğrulama, bölümler, tam import/export WAT biçimleri ve decode edilmiş WAT | Çağıranın sağladığı WABT 1.0.42; `inspect_wasm_artifact` |
|
||||
| EVM bayt kodu | Yönlendirme seçicileri, bayt ofsetleri, çıkarımla belirlenen argümanlar ve durum değiştirilebilirliği | Linux x64 üzerinde yerel ham bayt/onaltılık girdi; [çevrimdışı EVM rehberi](../evm-bytecode.md) |
|
||||
| SQLite veritabanları | Tablolar, sütunlar, index'ler, view'lar, trigger'lar ve seçilen sıradan tablo satırları | Yerel database/WAL snapshot'ı; native SQLite sınırlarıyla Node.js 24.x >=24.15 veya 26+ |
|
||||
@@ -270,6 +271,7 @@ Web sitesindeki [uygulamalı rehberlerden](https://rea.tools/tr/guides/) başlay
|
||||
|
||||
- [Yükleme ve kurulum](../installation.md): ajan kaydı, sağlayıcı yapılandırması, güncellemeler ve kaldırma.
|
||||
- [Hazırlık ve sorun giderme](../installation.md#check-readiness-for-your-task): belirli bir ajanı veya analiz motorunu tanılama.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI ve Evidence](../cli.md): komutlar, sağlayıcı seçimi, anlık görüntüler, içe/dışa aktarma ve çıkış durumları.
|
||||
- [MCP sözleşmeleri](../mcp-contracts.md) ve [ajan istemleri](../mcp-prompts.md): araç sonuçları, oturumlar ve yönlendirmeli araştırmalar.
|
||||
|
||||
@@ -145,6 +145,7 @@ REA потребує Node.js 22.x (>=22.19), 24.x (>=24.11) або 26+, а та
|
||||
| Структура ELF без запуску | Секції, сегменти, початкові символи/релокації та можливі захисні механізми за даними статичного аналізу | pwntools, наданий стороною, що викликає інструмент, у Linux x64; [діагностика бінарних файлів](../binary-diagnostics.md) |
|
||||
| Байт-код EVM | Селектори диспетчеризації, зміщення байтів, виведені припущення про аргументи та змінюваність стану | Локальні необроблені байти або шістнадцяткове представлення у Linux x64; [посібник EVM без запуску](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Записані аварійні завершення в Linux | Необроблені записи note, регістри/сигнали кожного записаного потоку й необов'язкові кандидати зіставлення пам'яті | pwntools, наданий стороною, що викликає інструмент, у Linux x64; необов'язкові GDB/pwndbg; [записані аварійні завершення](../recorded-crashes.md) |
|
||||
| Встановлені настільні програми | Можливі середовища виконання, файли доказів, компоненти та наступні кроки | Обмежена перевірка каталогів і заголовків;[Настільні програми](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Модулі, імпорти, карти вихідного коду, маршрути, IPC і зв'язки з нативними доповненнями | Node.js і npm; [аналіз застосунків](../javascript-application-workflows.md) |
|
||||
@@ -265,6 +266,7 @@ npx rea-agents@latest setup
|
||||
|
||||
- [Встановлення й налаштування](../installation.md): реєстрація агентів, конфігурація провайдерів, оновлення та видалення.
|
||||
- [Готовність та усунення неполадок](../installation.md#check-readiness-for-your-task): діагностика конкретного агента або рушія аналізу.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI та Evidence](../cli.md): команди, вибір провайдера, знімки, імпорт/експорт і статуси завершення.
|
||||
- [Контракти MCP](../mcp-contracts.md) і [промпти агентів](../mcp-prompts.md): результати інструментів, сеанси й керовані дослідження.
|
||||
|
||||
@@ -145,6 +145,7 @@ REA yêu cầu Node.js 22.x (>=22.19), 24.x (>=24.11) hoặc 26+, cùng với np
|
||||
| Bố cục ELF ngoại tuyến | Các section, segment, ký hiệu/thông tin tái định vị gốc và các biện pháp giảm thiểu có thể có từ phân tích tĩnh | pwntools do bên gọi cung cấp trên Linux x64; [chẩn đoán tệp nhị phân](../binary-diagnostics.md) |
|
||||
| Bytecode EVM | Bộ chọn điều phối, độ lệch byte, tham số suy luận và khả năng thay đổi trạng thái | Đầu vào cục bộ chứa byte thô hoặc dạng thập lục phân trên Linux x64; [hướng dẫn EVM ngoại tuyến](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Sự cố Linux đã ghi lại | Bản ghi note thô, thanh ghi/tín hiệu của mọi luồng được ghi lại và các ứng viên ánh xạ tùy chọn | pwntools do bên gọi cung cấp trên Linux x64; GDB/pwndbg tùy chọn; [sự cố đã ghi lại](../recorded-crashes.md) |
|
||||
| Thư mục cài đặt ứng dụng máy tính | Các runtime có khả năng được dùng, tệp bằng chứng, dấu hiệu thành phần và bước tiếp theo | Kiểm tra thư mục và phần đầu tệp có giới hạn;[Ứng dụng máy tính](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Mô-đun, các khai báo import, source map, tuyến, IPC và quan hệ với tiện ích mở rộng mã máy | Node.js và npm; [phân tích ứng dụng](../javascript-application-workflows.md) |
|
||||
@@ -265,6 +266,7 @@ Bắt đầu với [hướng dẫn thực hành](https://rea.tools/vi/guides/) t
|
||||
|
||||
- [Cài đặt và thiết lập](../installation.md): đăng ký tác nhân, cấu hình trình phân tích, cập nhật và gỡ cài đặt.
|
||||
- [Kiểm tra mức sẵn sàng và khắc phục sự cố](../installation.md#check-readiness-for-your-task): chẩn đoán một tác nhân hoặc bộ máy phân tích cụ thể.
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI và Evidence](../cli.md): lệnh, lựa chọn trình phân tích, ảnh chụp trạng thái, nhập/xuất và trạng thái thoát.
|
||||
- [Hợp đồng MCP](../mcp-contracts.md) và [prompt cho tác nhân](../mcp-prompts.md): kết quả công cụ, phiên làm việc và điều tra có hướng dẫn.
|
||||
|
||||
@@ -149,6 +149,7 @@ REA 需要 Node.js 22.x(>=22.19)、24.x(>=24.11)或 26+,以及 npm。
|
||||
| WASM 工件 | 驗證、節、精確的匯入/匯出 WAT 形式及解碼後的 WAT | 呼叫方提供的 WABT 1.0.42;`inspect_wasm_artifact` |
|
||||
| EVM 位元組碼 | 分派選擇器、位元組偏移、推斷的參數和狀態可變性 | Linux x64 上的本地原始位元組/十六進位輸入載體;[離線 EVM 指南](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| 已記錄的 Linux 崩潰 | 原始 note 記錄、每個已記錄執行緒的暫存器/訊號及可選的對映候選項 | Linux x64 上由呼叫方提供的 pwntools;可選的 GDB/pwndbg;[已記錄崩潰](../recorded-crashes.md) |
|
||||
| 桌面安裝目錄 | 執行階段候選、支持檔案、元件標記與後續操作 | 有界的目錄與檔頭檢查;[桌面應用](../desktop-applications.md) |
|
||||
| JavaScript / Electron | 模組、匯入、source map、路由、IPC 和原生附加元件關係 | Node.js 和 npm;[應用分析](../javascript-application-workflows.md) |
|
||||
@@ -271,6 +272,7 @@ npx rea-agents@latest setup
|
||||
|
||||
- [安裝與設定](../installation.md):AI 代理註冊、提供者組態、更新和卸載。
|
||||
- [就緒檢查與故障排查](../installation.md#check-readiness-for-your-task):診斷特定 AI 代理或分析引擎。
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI 與 Evidence](../cli.md):命令、提供者選擇、快照、匯入/匯出和退出狀態。
|
||||
- [MCP 契約](../mcp-contracts.md)和[AI 代理提示詞](../mcp-prompts.md):工具結果、會話和引導式調查。
|
||||
|
||||
+28
-26
@@ -141,32 +141,33 @@ npx rea-agents@latest setup
|
||||
|
||||
REA 需要 Node.js 22.x(>=22.19)、24.x(>=24.11)或 26+,以及 npm。额外工具和主机支持取决于分析目标:
|
||||
|
||||
| 目标 | REA 返回的内容 | 要求与指南 |
|
||||
| --------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| 原生二进制文件 | 伪代码、汇编、字符串、符号、调用和引用 | Hopper、Ghidra 或 IDA;[原生分析](../native-investigation.md) |
|
||||
| 离线 ELF 布局 | 节、段、原始符号/重定位信息及静态防护机制候选项 | Linux x64 上由调用方提供的 pwntools;[二进制诊断](../binary-diagnostics.md) |
|
||||
| Go 二进制文件 | 内嵌编译器版本、模块、替换项和构建设置 | 内置静态 ELF/PE/thin Mach-O 检查;无需安装 Go |
|
||||
| WASM 工件 | 验证、节、精确的导入/导出 WAT 形式及解码后的 WAT | 调用方提供的 WABT 1.0.42;`inspect_wasm_artifact` |
|
||||
| EVM 字节码 | 分派选择器、字节偏移、推断的参数和状态可变性 | Linux x64 上的本地原始字节/十六进制输入载体;[离线 EVM 指南](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| 已记录的 Linux 崩溃 | 原始 note 记录、每个已记录线程的寄存器/信号及可选的映射候选项 | Linux x64 上由调用方提供的 pwntools;可选的 GDB/pwndbg;[已记录崩溃](../recorded-crashes.md) |
|
||||
| 桌面安装目录 | 运行时候选、支持文件、组件标记和后续操作 | 有界的目录与文件头检查;[桌面应用](../desktop-applications.md) |
|
||||
| JavaScript / Electron | 模块、导入、source map、路由、IPC 和原生扩展关系 | Node.js 和 npm;[应用分析](../javascript-application-workflows.md) |
|
||||
| 网站 | 页面结构、脚本、网络观察结果和按请求获取的截图 | Chrome 系浏览器;[浏览器分析](../browser-observation.md) |
|
||||
| 已保存的网络捕获 | 请求、响应、可访问的载荷和来源位置 | HAR;原生 mitmproxy 捕获需要 Linux 上的 mitmdump;[捕获指南](../web-network-captures.md) |
|
||||
| 数据包捕获 | 端点、DNS、TLS SNI、协议分布和 HTTP 请求 | 调用方提供的 tshark 和 capinfos;[pcap 指南](../pcap-analysis.md) |
|
||||
| .NET 程序集 | 元数据、CIL 指令、声明的原生依赖和构建对比 | 静态检查;[托管代码指南](../managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Android APK | 清单声明、类、反编译的方法和引用 | Linux/macOS/Windows x64 上的无界面 JADX 和完整 JDK;[Android 指南](../android-analysis.md) |
|
||||
| Android 设备 | 设备、软件包、进程、日志、转储、屏幕截图以及 APK/文件传输 | 调用方提供的 adb(模拟器或实体设备);[ADB 指南](../adb-device-analysis.md) |
|
||||
| JEB 项目 | 引擎支持的项目单元、工件摘要和类型/方法的伪代码 | 由调用方启动、提供 MCP 的 JEB 客户端,通过 REA_JEB_MCP_URL 选择;[JEB 指南](../jeb-analysis.md) |
|
||||
| Android 资源 | 解码后的清单、字符串表、语言区域和版本信息 | 调用方提供的 Apktool 启动器;[资源指南](../apktool-resource-analysis.md) |
|
||||
| Flutter 应用 | Dart 快照哈希、按 ABI 的库摘要及引擎构建溯源 | 无(静态 APK 解析);[Flutter 指南](../flutter-analysis.md) |
|
||||
| 固件 | 区域、提取结果和转交原生分析的内容 | Linux 上的 Binwalk / Unblob;[固件指南](../firmware-analysis.md) |
|
||||
| 抓包文件 | 指定字段、重复值、过滤条件与解码规则 | Linux: TShark 4.x + prlimit; [抓包分析指南](../packet-captures.md) |
|
||||
| 录制的逻辑信号 | 解码注释、样本范围和诊断信息 | Linux: sigrok-cli 0.7.2 + prlimit; [信号记录指南](../signal-recordings.md) |
|
||||
| 软件包与资源 | 文件清单、摘要、plist、Apple bundle 结构和提取的资源 | [制品与 JavaScript 指南](../javascript-artifact-reconstruction.md)、[Apple 应用](../apple-application-analysis.md) |
|
||||
| 进程行为 | 终端输出、交互、退出和文件系统观察结果,以及运行对比 | 支持原生 PTY 的 Linux/macOS;[进程捕获](../process-capture.md) |
|
||||
| 目标 | REA 返回的内容 | 要求与指南 |
|
||||
| --------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| 原生二进制文件 | 伪代码、汇编、字符串、符号、调用和引用 | Hopper、Ghidra 或 IDA;[原生分析](../native-investigation.md) |
|
||||
| 离线 ELF 布局 | 节、段、原始符号/重定位信息及静态防护机制候选项 | Linux x64 上由调用方提供的 pwntools;[二进制诊断](../binary-diagnostics.md) |
|
||||
| Go 二进制文件 | 内嵌编译器版本、模块、替换项和构建设置 | 内置静态 ELF/PE/thin Mach-O 检查;无需安装 Go |
|
||||
| WASM 工件 | 验证、节、精确的导入/导出 WAT 形式及解码后的 WAT | 调用方提供的 WABT 1.0.42;`inspect_wasm_artifact` |
|
||||
| EVM 字节码 | 分派选择器、字节偏移、推断的参数和状态可变性 | Linux x64 上的本地原始字节/十六进制输入载体;[离线 EVM 指南](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| 已记录的 Linux 崩溃 | 原始 note 记录、每个已记录线程的寄存器/信号及可选的映射候选项 | Linux x64 上由调用方提供的 pwntools;可选的 GDB/pwndbg;[已记录崩溃](../recorded-crashes.md) |
|
||||
| 桌面安装目录 | 运行时候选、支持文件、组件标记和后续操作 | 有界的目录与文件头检查;[桌面应用](../desktop-applications.md) |
|
||||
| JavaScript / Electron | 模块、导入、source map、路由、IPC 和原生扩展关系 | Node.js 和 npm;[应用分析](../javascript-application-workflows.md) |
|
||||
| 网站 | 页面结构、脚本、网络观察结果和按请求获取的截图 | Chrome 系浏览器;[浏览器分析](../browser-observation.md) |
|
||||
| 已保存的网络捕获 | 请求、响应、可访问的载荷和来源位置 | HAR;原生 mitmproxy 捕获需要 Linux 上的 mitmdump;[捕获指南](../web-network-captures.md) |
|
||||
| 数据包捕获 | 端点、DNS、TLS SNI、协议分布和 HTTP 请求 | 调用方提供的 tshark 和 capinfos;[pcap 指南](../pcap-analysis.md) |
|
||||
| .NET 程序集 | 元数据、CIL 指令、声明的原生依赖和构建对比 | 静态检查;[托管代码指南](../managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Android APK | 清单声明、类、反编译的方法和引用 | Linux/macOS/Windows x64 上的无界面 JADX 和完整 JDK;[Android 指南](../android-analysis.md) |
|
||||
| Android 设备 | 设备、软件包、进程、日志、转储、屏幕截图以及 APK/文件传输 | 调用方提供的 adb(模拟器或实体设备);[ADB 指南](../adb-device-analysis.md) |
|
||||
| JEB 项目 | 引擎支持的项目单元、工件摘要和类型/方法的伪代码 | 由调用方启动、提供 MCP 的 JEB 客户端,通过 REA_JEB_MCP_URL 选择;[JEB 指南](../jeb-analysis.md) |
|
||||
| Android 资源 | 解码后的清单、字符串表、语言区域和版本信息 | 调用方提供的 Apktool 启动器;[资源指南](../apktool-resource-analysis.md) |
|
||||
| Flutter 应用 | Dart 快照哈希、按 ABI 的库摘要及引擎构建溯源 | 无(静态 APK 解析);[Flutter 指南](../flutter-analysis.md) |
|
||||
| 固件 | 区域、提取结果和转交原生分析的内容 | Linux 上的 Binwalk / Unblob;[固件指南](../firmware-analysis.md) |
|
||||
| 抓包文件 | 指定字段、重复值、过滤条件与解码规则 | Linux: TShark 4.x + prlimit; [抓包分析指南](../packet-captures.md) |
|
||||
| 录制的逻辑信号 | 解码注释、样本范围和诊断信息 | Linux: sigrok-cli 0.7.2 + prlimit; [信号记录指南](../signal-recordings.md) |
|
||||
| 软件包与资源 | 文件清单、摘要、plist、Apple bundle 结构和提取的资源 | [制品与 JavaScript 指南](../javascript-artifact-reconstruction.md)、[Apple 应用](../apple-application-analysis.md) |
|
||||
| 进程行为 | 终端输出、交互、退出和文件系统观察结果,以及运行对比 | 支持原生 PTY 的 Linux/macOS;[进程捕获](../process-capture.md) |
|
||||
|
||||
静态 JavaScript 和 .NET 检查读取提供的文件,不运行应用。运行时捕获会以你的用户权限运行目标或与之交互;各运行时指南说明了具体影响。
|
||||
|
||||
@@ -271,6 +272,7 @@ npx rea-agents@latest setup
|
||||
|
||||
- [安装与设置](../installation.md):智能体注册、提供方配置、更新和卸载。
|
||||
- [就绪检查与故障排查](../installation.md#check-readiness-for-your-task):诊断特定智能体或分析引擎。
|
||||
- [CUDA / HIP](../gpu-code-objects.md)
|
||||
- [GGUF / safetensors](../model-artifacts.md)
|
||||
- [CLI 与 Evidence](../cli.md):命令、提供方选择、快照、导入/导出和退出状态。
|
||||
- [MCP 契约](../mcp-contracts.md)和[智能体提示词](../mcp-prompts.md):工具结果、会话和引导式调查。
|
||||
|
||||
@@ -320,6 +320,13 @@ close a `packaged-process` obligation. A static-only source cannot close a
|
||||
runtime or process claim. Marking a claim `blocked` or `out-of-scope` records the
|
||||
disposition but does not silently count it as verified.
|
||||
|
||||
The `summary` counts obligations. `by_status`, `by_application_layer`, and
|
||||
`by_source_state` place each obligation in exactly one bucket.
|
||||
`by_evidence_authority` groups obligations by the Evidence `authority` of their
|
||||
`authority_references`: an obligation counts once under each distinct authority
|
||||
it cites, so those counts can exceed `total`. A reference's own `state` and the
|
||||
obligation's `source_state` do not affect its authority bucket.
|
||||
|
||||
The tool returns every obligation inline. Its `ledger_id` and `closure_digest`
|
||||
identify the complete result, including summaries, reports, ownership and
|
||||
dependency graphs, Evidence links, and limitations.
|
||||
|
||||
@@ -27,11 +27,13 @@ rea inspect-with-objdump ./program dwarf
|
||||
rea inspect-with-objdump ./program dwarf --follow-debug-links
|
||||
```
|
||||
|
||||
Captured stdout and stderr are retained up to a 16 MiB combined limit; `output_truncated` marks output beyond that limit.
|
||||
Captured stdout and stderr are retained up to a 16 MiB combined limit; `output_truncated` marks output beyond that limit. That cap has no runtime override.
|
||||
|
||||
`inspect_with_objdump`, `rea list-objdump-architectures`, and one-shot `execute_rizin_command` accept `command_timeout_ms` (CLI: `--command-timeout-ms`). Omitted means 120000. The integer range is 1 to 2147483647. Target preflight shares one budget across stat and digest. The one-shot command receives that budget again. It applies on the next call; no restart is required. It does not raise the 16 MiB cap, a Ghidra or Hopper startup deadline, or a debugger session deadline.
|
||||
|
||||
## GDB
|
||||
|
||||
Persistent GDB sessions, including the MCP workflow and one-shot `rea debug-with-gdb` CLI, are available only on Linux. REA verifies a live inferior's output descriptors through `/proc` before detaching it; it does not claim equivalent descriptor verification on macOS. Windows is also unsupported because owned Job Object cleanup can terminate debugger inferiors. On supported Linux hosts, `start_gdb_session`, `gdb_console`, `gdb_session_status`, and `close_gdb_session` manage a persistent GDB/MI session in MCP. The one-shot CLI requires a caller-selected durable TTY: `rea debug-with-gdb --inferior-tty /dev/pts/7 'file ./program'`. The TTY must remain available after GDB exits so a detached inferior can continue writing. MCP starts GDB with `--nx --quiet --interpreter=mi3`, retries initialization with MI2 if MI3 initialization returns an error and cleanup succeeds, waits for its prompt, and disables auto-loading. Pass optional `inferior_tty` to select the terminal that future inferior runs use; REA configures it before the session becomes ready and checks the exact value with GDB/MI. `gdb_session_status` reports the selected path, whether REA still considers the configuration verified, and whether invalid UTF-8 has been observed in MI bytes (`mi_invalid_utf8`) or stderr (`stderr_invalid_utf8`). Commands that can change the inferior TTY or redirect a run revoke that verification permanently for the session, so close retains GDB ownership if a live inferior remains. Closing a session with one live inferior and a verified TTY automatically detaches the target, which can resume execution; MCP clients receive destructive-operation annotations for this behavior. The console remains unrestricted and can run shell commands, change target state, access files, and use network in the REA process user's security context. Raw MI records and console/target/log streams are returned with Evidence; command output is retained up to 16 MiB and explicitly marked when truncated.
|
||||
Persistent GDB sessions, including the MCP workflow and one-shot `rea debug-with-gdb` CLI, are available only on Linux. REA verifies a live inferior's output descriptors through `/proc` before detaching it; it does not claim equivalent descriptor verification on macOS. Windows is also unsupported because owned Job Object cleanup can terminate debugger inferiors. On supported Linux hosts, `start_gdb_session`, `gdb_console`, `gdb_session_status`, and `close_gdb_session` manage a persistent GDB/MI session in MCP. The one-shot CLI requires a caller-selected durable TTY: `rea debug-with-gdb --inferior-tty /dev/pts/7 'file ./program'`. The TTY must remain available after GDB exits so a detached inferior can continue writing. MCP starts GDB with `--nx --quiet --interpreter=mi3`, retries initialization with MI2 if MI3 initialization returns an error and cleanup succeeds, waits for its prompt, and disables auto-loading. Pass optional `inferior_tty` to select the terminal that future inferior runs use; REA configures it before the session becomes ready and checks the exact value with GDB/MI. `gdb_session_status` reports the selected path, whether REA still considers the configuration verified, and whether invalid UTF-8 has been observed in MI bytes (`mi_invalid_utf8`) or stderr (`stderr_invalid_utf8`). Commands that can change the inferior TTY or redirect a run revoke that verification permanently for the session, so close retains GDB ownership if a live inferior remains. Closing a session with one live inferior and a verified TTY automatically detaches the target, which can resume execution; MCP clients receive destructive-operation annotations for this behavior. The console remains unrestricted and can run shell commands, change target state, access files, and use network in the REA process user's security context. Raw MI records and console/target/log streams are returned with Evidence; command output is retained up to 16 MiB and explicitly marked when truncated. GDB startup waits 10000 ms and each MI command waits 120000 ms. This release has no runtime override for those deadlines, the 16 MiB command output budget, session capacity, or the pending-command queue. `command_timeout_ms` does not change them.
|
||||
|
||||
Before a normal close, REA checks for live GDB thread groups. If one remains and a durable `inferior_tty` is verified, REA asks GDB to detach it and confirms the detach before stopping the debugger. Without that sink, select and apply a disposition to each inferior through `gdb_console` (for example, detach or kill as appropriate), then retry close. REA never infers target ownership from a PID or path. When the MCP server shuts down, REA terminates only its directly owned GDB process after confirming no inferior or a sink-backed detach; otherwise it retains the process and its output streams for retry.
|
||||
|
||||
@@ -49,7 +51,7 @@ close_gdb_session {"session_id":"…"}
|
||||
|
||||
Persistent command Evidence retains the caller-selected and resolved startup paths in `parameters.launch_provenance`. These paths describe launch provenance, not the current target after unrestricted commands. `rizin_debug_session_status.output_invalid_utf8` reports whether lossy frame decoding has been observed during the session. Command Evidence sets `output_invalid_utf8` only when loss was observed in frames collected for that command, including retained partial output; earlier startup or command frames do not mark later valid output as lossy.
|
||||
|
||||
Session status retains up to 64 recent protocol frames. Each history entry keeps a complete-character UTF-8 prefix of at most 16 KiB, plus a truncation marker when needed; `recent_output_truncated` reports omitted history. This history budget also accounts for replacement characters from invalid UTF-8. It does not shorten command Evidence, which has its own 16 MiB output budget.
|
||||
Session status retains up to 64 recent protocol frames. Each history entry keeps a complete-character UTF-8 prefix of at most 16 KiB, plus a truncation marker when needed; `recent_output_truncated` reports omitted history. This history budget also accounts for replacement characters from invalid UTF-8. It does not shorten command Evidence, which has its own 16 MiB output budget. Rizin debug startup waits 30000 ms and each command frame waits 120000 ms. This release has no runtime override for those deadlines, the 16777216 byte frame cap, the 16777216 byte command-output cap, the 4096 frame command cap, session capacity, or the pending-command queue. Evidence names the cap that stopped the command. The one-shot `command_timeout_ms` setting does not change a debug session.
|
||||
|
||||
```sh
|
||||
rea debug-with-rizin --inferior-tty /dev/pts/7 ./program dr
|
||||
@@ -61,7 +63,7 @@ rea debug-with-rizin --inferior-tty /dev/pts/7 ./program dr
|
||||
rea execute-rizin-command ./program iI
|
||||
```
|
||||
|
||||
Captured stdout and stderr are retained up to a 16 MiB combined limit; `output_truncated` marks output beyond that limit.
|
||||
Captured stdout and stderr are retained up to a 16 MiB combined limit; `output_truncated` marks output beyond that limit. One-shot commands use the `command_timeout_ms` budget described above. That 16 MiB cap has no runtime override.
|
||||
|
||||
## Cutter bridge
|
||||
|
||||
@@ -70,8 +72,11 @@ The client and plugin must support the current v2 handshake; older peers are
|
||||
rejected before dispatch because they cannot preserve cross-caller recovery proof.
|
||||
The client checks the final encoded request against the bridge's 16 MiB frame
|
||||
limit before dispatch; an oversized command does not retain a cleanup owner.
|
||||
Discovery admits at most 256 descriptor candidates and reads and probes at most
|
||||
eight concurrently. A larger directory reports `bridge_directory_capacity_exceeded`.
|
||||
Each bridge request waits 25000 ms. Discovery admits at most 256 descriptor
|
||||
candidates and reads and probes at most eight concurrently. A larger directory
|
||||
reports `bridge_directory_capacity_exceeded`. This release has no runtime
|
||||
override for the 25000 ms request deadline, the 16777216 byte frame, or the
|
||||
256-candidate discovery budget.
|
||||
|
||||
Terminal receipts are recovered before another command, including from a new CLI
|
||||
invocation. A signed status response also confirms completion of older bridge
|
||||
|
||||
+12
-3
@@ -86,7 +86,7 @@ The inline Evidence result contains the artifact path, SHA-256, byte length,
|
||||
container format, architecture, word size, and byte order. When a `.dep-v0`
|
||||
section is present, `auditable_metadata` contains:
|
||||
|
||||
- `section_name`, `.dep-v0` for ELF and PE or `__DATA,.dep-v0` for thin Mach-O;
|
||||
- `section_name`, `.dep-v0` for ELF and PE or `__DATA,.dep-v0` for Mach-O;
|
||||
- `file_offset` and `section_bytes`, the exact file range of the compressed section;
|
||||
- `compressed_bytes` and `uncompressed_bytes`;
|
||||
- `format_version`, the embedded integer, or `null` when the field is omitted;
|
||||
@@ -124,8 +124,17 @@ verified. An omitted revision remains `null` and follows revision 0 semantics.
|
||||
Embedded names and versions are file content. They do not authenticate the
|
||||
packages or the compiler.
|
||||
|
||||
Universal Mach-O containers are unsupported. Select a thin slice first. ELF,
|
||||
PE, and thin Mach-O are the supported containers.
|
||||
ELF, PE, thin Mach-O and one selected slice of a universal Mach-O are the
|
||||
supported containers.
|
||||
A universal (FAT) Mach-O needs `architecture` (`x86`, `x86_64`, `arm`
|
||||
or `arm64`; CLI `--architecture`). REA reads its own FAT table, without `lipo`,
|
||||
and validates the selected slice's range, alignment and Mach-O header CPU
|
||||
against the table. The result keeps the universal file as `artifact` (its
|
||||
SHA-256 and size), adds `selected_slice` with the slice offset, length, raw CPU
|
||||
type/subtype and the FAT table digest, and reports the section and rustc-path offsets as a
|
||||
file offset inside that slice. Without `architecture`, or when the file has no
|
||||
such slice or several, the request fails on `architecture` and lists the slices
|
||||
present. `architecture` on any other image is rejected rather than ignored.
|
||||
|
||||
Package and dependency counts are checked against the minimum required JSON
|
||||
representation before graph allocation or schema cloning. Oversized graphs
|
||||
|
||||
@@ -126,6 +126,9 @@ matching help retains original one-based line numbers. Empty query selects all.
|
||||
returns all remaining matches; CLI `--all` and `--limit` conflict.
|
||||
The window reports examined, matching and returned records and `has_more`.
|
||||
A filtered empty page is not evidence that the installation has no decoders.
|
||||
When sigrok reports a selected decoder ID as not installed, help and decoding
|
||||
return `invalid_request` naming `decoder` or `decoders`; omit `decoder` to list
|
||||
installed IDs. An installed decoder that fails to load remains an execution failure.
|
||||
|
||||
Discovery refuses more than 65,535 line separators before constructing record
|
||||
objects (65,536-line representation budget), in addition to the 4 MiB output cap.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Plan
|
||||
|
||||
1. Move tool naming (`parameterNames`, `pathTemplate`, `toolName`,
|
||||
`compareTools`) from `environmentManifestRules.ts` to a new
|
||||
`environmentManifestNames.ts`, so the rules module has room for the rule.
|
||||
2. Add `prefix-variance` to `TEMPLATE_RULES`. A `prefix-variance` parameter
|
||||
records the rule it shares (`sharedRule`), which names it and keys it.
|
||||
3. Add the pass after `sibling-variance`: walk positions in order, index the
|
||||
opt-in parameters at each position by their preceding parts, template
|
||||
qualifying literals, then rebucket by naming key, keeping a tool's own rule
|
||||
for each merged position.
|
||||
4. Share the 32-segment split between the three comparing passes and list the
|
||||
segment-limited rules once for the limitation.
|
||||
5. Document the rule in the view schema description and in
|
||||
`docs/web-network-captures.md`.
|
||||
6. Tests: shared positions across methods and depths, the spelling condition,
|
||||
merges that keep a tool's own rule, pairs, format-rule positions and the
|
||||
segment limit.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Share templated positions across tools
|
||||
|
||||
Issue: https://github.com/morluto/rea/issues/4933
|
||||
|
||||
## Outcome
|
||||
|
||||
A session usually edits one scratch entity: it creates it, then updates and
|
||||
deletes it at a fixed path such as `/api/v1/collections/0RZ576QZQA5KG`. The
|
||||
manifest templates a segment only when sibling routes of the same method vary
|
||||
there, so those writes stay literal tools (`patch_collections_0rz576qzqa5kg`)
|
||||
even though the reads of the same collection were templated as
|
||||
`/api/v1/collections/{collection_id}`. A literal write tool addresses one
|
||||
entity that may not exist in a later state, and nothing can model its effect.
|
||||
|
||||
A new opt-in template rule, `prefix-variance`, templates such a literal with
|
||||
the parameter another tool already uses at that position, so the write becomes
|
||||
`patch_collections_by_collection_id` on the same template as the read.
|
||||
|
||||
## Requirements
|
||||
|
||||
- `prefix-variance` applies only when listed, after every other opt-in rule, so
|
||||
it can share the parameters they produce.
|
||||
- A literal at position `p` is templated when another tool on the same origin,
|
||||
of any method and any segment count, has a parameter at `p` from one of the
|
||||
other opt-in rules, after the same preceding parts. Parameters in the
|
||||
preceding parts compare by the rule that names them, so a position templated
|
||||
by `prefix-variance` matches the parameter it shares.
|
||||
- The literal qualifies when it is one of the values such a parameter
|
||||
observed at that position, when it carries a digit and has the length and
|
||||
character classes (digits, lower case, upper case, each other character) of
|
||||
one of them, or when every value the parameter observed, one or more, has one
|
||||
length of eight or more characters, as generated identifiers often do, and
|
||||
the literal has that length and uses only their character classes, so an
|
||||
identifier that happens to hold no digit still qualifies. An empty literal, a
|
||||
stop word or a `v1`-style version never qualifies. Each parameter's spelling
|
||||
is summarised once, so a literal is checked without rescanning its values,
|
||||
and a value longer than 128 characters is compared only exactly, so a huge
|
||||
segment costs no classification.
|
||||
- Positions templated by the four format rules are never shared, so
|
||||
`/api/teams/{numeric}` still absorbs no literal.
|
||||
- Values stay with the parameter that observed them: when parameters of
|
||||
different rules share a position, the literal shares the one that observed
|
||||
it, else the earliest one it is spelled like.
|
||||
- The parameter takes the name of the parameter it shares (`collection_id`,
|
||||
`uid`, a pair's `_namespace` and `_name`) and is labelled `prefix-variance`.
|
||||
- Tools whose routes now match, by method and by the rule that names each
|
||||
parameter, merge. A merged parameter keeps the rule of a tool that templated
|
||||
that position itself, when one did.
|
||||
- Like the sibling rules, it compares routes of at most 32 segments and says so
|
||||
in a limitation when a longer route exists.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- No change to the default rules or to any other rule: manifests that do not
|
||||
list `prefix-variance` are byte-for-byte unchanged.
|
||||
- No templating from response bodies, such as an id a create returned; the
|
||||
manifest reads request lines only.
|
||||
- No change to which groups are excluded: a write whose response has no body
|
||||
or content type outside `/api/` is still excluded as `non-json`.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Record the outcome, requirements and non-goals.
|
||||
- [x] Move tool naming into its own module.
|
||||
- [x] Add the `prefix-variance` rule, its names, its merge and its limitation.
|
||||
- [x] Document the rule in the schema and the capture guide.
|
||||
- [x] Add rule tests.
|
||||
- [x] Run static, formatting, duplication, documentation and test gates.
|
||||
- [x] Project the 51 corpus captures with and without the rule and record the results.
|
||||
- [x] Rebuild five randomly drawn environments end to end and compare them with their published versions and the live applications.
|
||||
@@ -0,0 +1,149 @@
|
||||
# Verification
|
||||
|
||||
Verified base: 33b0643e on main 1629266e (the rule, the alias removal `knip`
|
||||
asked for, and the fixed-length clause the end-to-end runs below led to). Executed on macOS with Node v22.23.1 (the repository pins
|
||||
24.18.0 in `.nvmrc`, which was not installed).
|
||||
|
||||
## Gates
|
||||
|
||||
- `npm run build:cached`, `npm run check:fast` (typecheck and lint),
|
||||
`npm run format:check`, `npx knip`, `npm run scan:todos`,
|
||||
`npm run docs:check`, `npm run verify:test-discovery` and
|
||||
`npm run mcp-catalog:check`: passed.
|
||||
- `npm run jscpd`: 3.49% duplicated lines over 3561 files with 3067 clones;
|
||||
main measures 3.49% with 3068, since the shared segment-limit split removes
|
||||
one clone.
|
||||
- oxlint reports no new finding on the changed files. The manifest accumulator
|
||||
keeps main's three warnings (file length, and the complexity and parameter
|
||||
count of its record append), one line longer.
|
||||
- `npx vitest run --project domain --project services`: 7119 passed, 5
|
||||
pre-existing skips.
|
||||
- `npm run test:prepare`, then `npm run test:focused --` the analysis-view MCP
|
||||
and CLI boundaries, the compact input schema and tool schema validity
|
||||
boundaries, and the environment serve and export boundaries:
|
||||
7 files, 76 passed.
|
||||
|
||||
New tests in `environmentManifestView.test.ts` cover:
|
||||
|
||||
- a literal shared across methods and depths, and the same capture without the rule;
|
||||
- the spelling condition: same classes and length, case, missing digit, a colon word, a version;
|
||||
- a digit-free member of a fixed-length identifier family, against a shorter word, a hyphenated
|
||||
value and a family shorter than eight characters;
|
||||
- merges that keep a tool's own rule, including a sibling-variance parameter under a shared one;
|
||||
- both halves of a templated pair;
|
||||
- format-rule positions and the segment limit.
|
||||
|
||||
## The showcase captures
|
||||
|
||||
The 50 showcase captures (45 HAR inspections and 5 `capture_browser_scenario`
|
||||
captures) were projected with main's build and this branch's.
|
||||
|
||||
- Without the rule, both builds give identical results for every capture: the
|
||||
manifest with no rules, the manifest with `after-uid-literal`,
|
||||
`opaque-token`, `sibling-variance` and `sibling-pair-variance`, and the
|
||||
environment-state view. 150 of 150 outputs hash equal.
|
||||
- With `prefix-variance` added to `after-uid-literal`, `opaque-token` and
|
||||
`sibling-variance`, 69 literal tools in 10 captures are templated, 25 of them
|
||||
writes:
|
||||
- Komga: collection and readlist `PATCH` and `DELETE`, book pages.
|
||||
- n8n: workflow `PATCH`, `DELETE` and archive, and the reads of a workflow
|
||||
whose id holds no digit.
|
||||
- Memos: memo `PATCH` and `DELETE`, user settings reads, and the reads of
|
||||
two memos whose ids hold no digit.
|
||||
- Navidrome: playlist `PUT` and `DELETE`.
|
||||
- Mealie: recipe `PATCH` and `DELETE`.
|
||||
- Grist: document `PATCH` and `DELETE`, and table record writes.
|
||||
- Redpanda Console: subject and topic writes.
|
||||
- Sentry: release `PUT` and `DELETE`.
|
||||
- Shlink: short URL `PATCH`.
|
||||
- Mattermost: `me` reads, which `sibling-variance` already folds into the
|
||||
user parameter.
|
||||
|
||||
Tools go from 1591 to 1578, because Redpanda Console's per-subject reads and
|
||||
the per-memo and per-workflow reads merge.
|
||||
|
||||
- Literals the rule leaves alone, as intended, include Espo CRM `layout`,
|
||||
Federal Register `facets`, Ghost `slug`, Shlink `stats`, Lychee
|
||||
`Metrics::photo` and Vault's path names.
|
||||
- The environment-state view succeeds on every capture with the rule. Its types
|
||||
move to the templated collections (531 become 526 as literal ones merge); the
|
||||
one fewer item view is the Redpanda Console merge.
|
||||
|
||||
With the write plans of #5600 (its branch with this commit and main merged in,
|
||||
locally):
|
||||
|
||||
- Served write tools rise from 33 to 39: Komga collection create, update and
|
||||
delete; n8n workflow delete; Sentry release update and delete.
|
||||
- Write tools with no state target fall from 102 to 87.
|
||||
- The newly modelled tools that stay unserved are limited by the capture:
|
||||
- no read after the write: Komga readlists, Mealie, Navidrome, Redpanda Console;
|
||||
- n8n's item read shows an expanded `shared` relation its create response
|
||||
never returned;
|
||||
- Shlink returns `tags` sorted while the update echoes the request's order.
|
||||
|
||||
## Five environments end to end
|
||||
|
||||
Five of the ten environments the rule changes were drawn at random, redrawing
|
||||
until the draw held one whose new writes are served: Komga, Mealie, n8n,
|
||||
Sentry and Shlink. Each was rebuilt on its own Linux VM with `npm pack` of
|
||||
#5600, main and this branch merged locally, from the same scoped HAR as its
|
||||
published version: manifest with `prefix-variance`, exported bundle, smoke
|
||||
task, the generated retrieval tasks for `gpt-oss-120b` and `GLM-5.3-Flash`, and
|
||||
a dry-run dataset. Where writes are served, hand-written write tasks ask for a
|
||||
change in plain language and are graded from the environment's state through
|
||||
`data/get`. The first n8n run found that a digit-free workflow id stayed
|
||||
literal; the fixed-length clause fixed it, and n8n was rebuilt.
|
||||
|
||||
| Environment | Tools (published → rebuilt) | Served from state (reads / writes) | Retrieval gpt-oss | Retrieval GLM | Writes gpt-oss | Writes GLM |
|
||||
| ----------- | --------------------------- | ---------------------------------- | ----------------- | ------------- | -------------- | ---------- |
|
||||
| Komga | 42 → 46 | 26 / 3 | 12/12 (was 11/12) | 12/12 (11/12) | 3/4 | 4/4 |
|
||||
| Mealie | 39 → 39 | 36 / 0 | 12/12 (12/12) | 12/12 (12/12) | – | – |
|
||||
| n8n | 30 → 33 | 17 / 1 | 9/9 (9/9) | 9/9 (9/9) | 2/2 | 2/2 |
|
||||
| Sentry | 34 → 34 | 26 / 3 | 12/12 (12/12) | 11/12 (12/12) | 2/4, rerun 0/4 | 4/4 |
|
||||
| Shlink | 17 → 17 | 5 / 0 | 5/7, rerun 7/7 | 7/7 (7/7) | – | – |
|
||||
|
||||
Every smoke task passed. The misses:
|
||||
|
||||
- Sentry writes with gpt-oss: every failed episode passed `id: "sentry"` for
|
||||
the `/api/0/` segment the tool schema describes as `observed: 0`, so its calls
|
||||
addressed `/api/sentry/…`; every passing episode, and every GLM episode, passed
|
||||
`0`. The served tools work; the format-rule parameter for a segment that only
|
||||
ever held `0` invites the guess.
|
||||
- Komga update with gpt-oss and Shlink's first gpt-oss run: the model provider
|
||||
rejected tool calls the model generated (`null` and `undefined` for optional
|
||||
query arguments) before the environment saw them.
|
||||
- Sentry `qa-03` with GLM: the model never called the alert-rules tool.
|
||||
|
||||
The same calls were also replayed against the live applications, seeded by
|
||||
the same scripts (ids differ, so each side maps its ids to names):
|
||||
|
||||
- Komga 1.29.1, 9 of 12 steps equal: create, update and delete of a
|
||||
collection and the reads after them agree except for the generated id. The
|
||||
collection list after a create omits the new collection, because that list
|
||||
keeps its recorded membership, and the 404 for a deleted collection replays
|
||||
the recorded body with its path and timestamp.
|
||||
- n8n 1.123.85, 3 of 8 steps equal: n8n refuses to delete a workflow that is
|
||||
not archived (400) and the environment deletes it; the workflow list replays
|
||||
its recorded response, so a delete does not show in it; archiving is not
|
||||
served. The read of the digit-free workflow failed in the first build (the
|
||||
state held only its list fields) and agrees in the second, apart from ids the
|
||||
seed generates.
|
||||
|
||||
## After the review round
|
||||
|
||||
The branch merged main at 52c84f6f, then kept each shared position's values
|
||||
with the parameter that observed them (one donor per naming rule, the literal
|
||||
taking the donor that observed it, else the earliest it is spelled like),
|
||||
summarised each donor's spelling once, and let one observation form a
|
||||
fixed-length family, as the requirement states. Two new tests, a mixed-rule
|
||||
position and a single observed workflow id, fail on the previous head and pass
|
||||
here. The gates above passed again (domain and services 7255 passed with 5
|
||||
pre-existing skips; the focused boundaries 76; `jscpd` 3.49%). Over the 50
|
||||
showcase captures the tools with and without `prefix-variance` are unchanged,
|
||||
name for name: 69 literal tools templated, 25 of them writes.
|
||||
|
||||
A second review round bounded the spelling summary: characters are classified
|
||||
in one pass, and a value longer than 128 characters is compared only exactly.
|
||||
Its test fails on the previous head, the gates passed again (domain and
|
||||
services 7257, focused boundaries 76, `jscpd` 3.49%), and the census over the 50
|
||||
captures is again unchanged.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Implementation plan
|
||||
|
||||
1. In `environmentStateRules.ts`, parse pointers into tokens and let `at` and
|
||||
`replaceAt` read and replace element 0 of a one-element array at the root
|
||||
or in one member; extend `locateItem` with those forms after the object
|
||||
forms, requiring an identity name there; add `identityCandidates`, the
|
||||
identity names then suffix-named fields, and let `locateList` prefer arrays
|
||||
identified by name, then arrays of two or more items identified by suffix.
|
||||
2. In `EnvironmentStateExtraction.ts`, plan lists with the shared candidates,
|
||||
treat an empty recording as unconstraining, accept a suffix-named field only
|
||||
once a recording shows it distinct across two or more items, leave reads
|
||||
without a list or identity to documents, drop the written-path requirement
|
||||
and the `not-entity` fallback, record `path-varies` apart from
|
||||
`query-varies`, and keep each entity's earliest sighting;
|
||||
`environmentStateMerge.ts` cites records in timeline order. Remove
|
||||
`not-entity` from the reason type and result schema, add `path-varies`, and
|
||||
describe the new pointer forms and `field-name` basis.
|
||||
3. Move the classification of retained bodies (none, base64, cut, JSON, text)
|
||||
into `replayedBody` in `environmentSource.ts`, which owns recorded
|
||||
exchanges; replay renders from it and tool descriptions read its JSON case.
|
||||
4. Make `environmentToolDefinitions` take the `EnvironmentSource`; describe the
|
||||
first `2xx` JSON record, else the first JSON record labelled with its status,
|
||||
one level deep with the state's list rule and the existing sample budget;
|
||||
list the manifest tool's statuses; and charge the whole description and the
|
||||
tool's MCP annotations to the catalog reservation. Update the serve and
|
||||
bundle callers.
|
||||
5. Let the tool definitions own the MCP annotations derived from the method and
|
||||
the query-`POST` rule; `serveEnvironment.ts` registers them and the card
|
||||
leaves them out.
|
||||
6. Cover domain, services, adapters and the compiled MCP boundary; document the
|
||||
rules in the capture guide, descriptions and hints in the agent environments
|
||||
guide, and the contract text.
|
||||
@@ -0,0 +1,99 @@
|
||||
# Wider environment state coverage and tool descriptions
|
||||
|
||||
Issue: https://github.com/morluto/rea/issues/4933
|
||||
|
||||
## Outcome
|
||||
|
||||
The `environment-state` view backs more read tools with state, and a served
|
||||
environment tells agents more about each tool. Read-only paths whose responses
|
||||
are not entities become documents, listed items may be identified by an
|
||||
`…Id` or `…_id` field, an item wrapped in a one-element array is located
|
||||
inside it, and reads that vary by path get their own recorded reason. Each tool description says what the tool returns and which statuses
|
||||
were recorded, and every MCP tool carries method hints. This increment adds no
|
||||
tool, view kind, provider, network activity or write effect.
|
||||
|
||||
## Requirements
|
||||
|
||||
- A `GET` list tool (its template does not end in a parameter) that yields no
|
||||
item or list plan holds its latest initial value as a `document` when its
|
||||
initial reads have one request line, whether or not the capture writes its
|
||||
path, unless its value changed between two of those reads across any
|
||||
recorded write (even under another root), which leaves it `fields-differ`. A
|
||||
value whose rendered JSON exceeds 256 KiB stays `rendered-oversize` and is
|
||||
replayed from the recorded body, which itself fit. More request lines give
|
||||
`path-varies` when they differ by path (a template with a parameter before
|
||||
its end) and `query-varies` when they share one path. With every such read
|
||||
now a document, `path-varies`, `query-varies`, `body-unusable` or
|
||||
`rendered-oversize`, the unreachable `not-entity` reason leaves the result
|
||||
schema, and `no-identity` names item tools only. A document holds the value
|
||||
of its one `path`.
|
||||
- When no path parameter proves an identity and no identity name identifies
|
||||
the listed items, the `field-name` identity is the first key of the first
|
||||
listed item, in its order, whose name ends in `Id` or `_id`, that every item
|
||||
carries as a distinct string or number, and that at least one initial
|
||||
recording shows distinct across two or more items. The last condition goes
|
||||
beyond "every item carries it distinctly": one item satisfies that
|
||||
vacuously, and a lone item's suffix-named fields are often foreign keys (a
|
||||
reaction keyed by its user, a comment by its post), so a list that only ever
|
||||
held one item stays a document. Empty recordings constrain no field.
|
||||
Identity names keep precedence, also when choosing among an envelope's
|
||||
arrays, where a suffix-named field identifies only an array of two or more
|
||||
items.
|
||||
- An item response that is a root array of exactly one object, or an object
|
||||
with one member holding such an array, locates its entity at `/0` or
|
||||
`/<member>/0` when one of the identity names in that object repeats the path
|
||||
value. Objects at the root or in one member keep precedence. `at` and
|
||||
`replaceAt` read and replace exactly these forms besides the root and one
|
||||
member, so the gate and renderers run unchanged.
|
||||
- An entity's state order is its earliest sighting on the timeline and it cites
|
||||
its records in timeline order, whichever plan observed it first.
|
||||
- Each tool description reads `METHOD template; <returns>; recorded statuses
|
||||
…; replays retained records […]; evidence ev_…` after the untrusted-catalog
|
||||
warning. `<returns>` describes one level deep the first cited `2xx` record
|
||||
replay answers as JSON: an object's fields, an array of objects' fields, or
|
||||
an envelope whose member lists objects, where a list is an array of objects
|
||||
found by the state's list rule; an empty field set reads `with no fields`.
|
||||
Only when no `2xx` record replays as JSON does the first cited JSON record of
|
||||
another status give it, labelled `status <code> returns …`; with no JSON
|
||||
record it is omitted. The statuses are the manifest tool's `statuses`, the
|
||||
one owner of that set (`no recorded status` when it is empty). Field names
|
||||
and statuses are sampled within the description sample budget and charged
|
||||
with the whole description to the catalog reservation before it is retained.
|
||||
One owner in the environment source classifies each retained body as none,
|
||||
base64, cut, JSON or text; replay answers from that classification and
|
||||
descriptions read only its JSON case.
|
||||
- MCP tools carry `readOnlyHint` (true for the safe methods `GET`, `HEAD`,
|
||||
`OPTIONS` and `TRACE`, and for query `POST`s),
|
||||
`destructiveHint: true` for `DELETE` (unset for other writes, so the MCP
|
||||
default applies, and for reads, where clients ignore it), `idempotentHint`
|
||||
(true for the safe methods, `PUT` and `DELETE`) and `openWorldHint: false`. The
|
||||
tool definitions own the hints and charge them to the catalog reservation;
|
||||
the environment card keeps its `name`, `description`, `inputSchema` tool
|
||||
shape.
|
||||
|
||||
## Acceptance and limits
|
||||
|
||||
Synthetic captures cover read-only documents, `path-varies` and
|
||||
`query-varies`, suffix-named identities with their key order, their
|
||||
two-item proof, empty first recordings and their precedence (including the
|
||||
choice between an envelope's arrays), a Ghost-like `{"posts":[...]}` item under
|
||||
a trailing-slash path merging with its list view, a root one-element array, a
|
||||
one-element filtered list that stays unidentified, and the pointer forms. The
|
||||
Grafana-shaped fixture covers documents for its read-only paths (its one-member
|
||||
team list among them) and object, array and enveloped-list descriptions;
|
||||
synthetic sources cover the `2xx` preference over an earlier error body, the
|
||||
first of several JSON records, the labelled fallback, the manifest's statuses,
|
||||
empty, scalar and fieldless bodies, a truncated member name, a name whose
|
||||
JSON quoting exceeds the sample, a recorded body under 256 KiB whose rendered
|
||||
JSON exceeds it, non-JSON bodies and the catalog budget; the in-process and
|
||||
compiled MCP servers advertise the
|
||||
hints. A filtered list may still answer with one element whose identity name
|
||||
repeats the requested value; list filters, pagination, lossless big integers
|
||||
and cross-endpoint entity linking remain out of scope. Documents inline whole
|
||||
recorded values and enlarge the state result; agent tokens, CPU time and peak
|
||||
memory of the state and description build were not measured.
|
||||
|
||||
## Deferred issue criteria
|
||||
|
||||
Serving from the state, the AgentEnv data plane and write effects remain later
|
||||
increments of #4933. This PR must reference rather than close the issue.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Record the coverage and description contract and its limits.
|
||||
- [x] Extend pointers, item location and identity candidates.
|
||||
- [x] Require two distinct items before a suffix-named field identifies a list.
|
||||
- [x] Hold read-only non-entity reads as documents, retire `not-entity` and
|
||||
separate `path-varies` from `query-varies`.
|
||||
- [x] Order entities by earliest sighting and cite records in timeline order.
|
||||
- [x] Classify retained bodies in one owner and describe tool responses,
|
||||
preferring `2xx` records, with the manifest's statuses.
|
||||
- [x] Advertise MCP tool annotations, charged to the catalog, without changing
|
||||
the card.
|
||||
- [x] Add domain, services, adapters and compiled-boundary coverage.
|
||||
- [x] Document the rules, descriptions and hints; update the contract text.
|
||||
- [x] Run static, formatting, duplication, documentation and test gates and the
|
||||
real-capture measurement.
|
||||
@@ -0,0 +1,123 @@
|
||||
# Verification
|
||||
|
||||
Verified base: 7a668b73f4783b42eb0e8ce1eeff079f86d53e22 (the environment-state
|
||||
view branch).
|
||||
|
||||
Executed on the implementation worktree with its existing locked installation
|
||||
under Node.js v22.23.1 (the repository pins 24.18.0, which was not available);
|
||||
every check below ran as written in this pass, after the last source change.
|
||||
|
||||
- `npm run format` then `npm run format:check`: passed.
|
||||
- `npm run check:fast`: typecheck and lint passed (3959 files, no errors). The
|
||||
touched files carry two lint warnings, both present on the base: `max-params`
|
||||
in `environmentReplay.ts` and an unused `_` in `environmentCapacity.test.ts`.
|
||||
- `npx knip`: passed (exit 0).
|
||||
- `npm run jscpd`: 3.40% duplicated lines over 3348 files, under the 3.5%
|
||||
gate. The three clones that touch changed test files pair the same blocks as
|
||||
on the base; none involves code this change adds.
|
||||
- `npm run scan:todos`: no markers.
|
||||
- `npm run docs:check`: the built documentation checks and the README
|
||||
consistency conformance test (5 tests) passed.
|
||||
- `npx vitest run --project domain --project services`: 341 files, 5859 tests
|
||||
passed, 5 pre-existing skips.
|
||||
- `npm run build:cached`: passed.
|
||||
- `npm run test:focused --` the environment serve adapters and capacity tests,
|
||||
the environment serve MCP boundary, the environment serve and export CLI
|
||||
boundaries, the environment serve shutdown process boundary, the
|
||||
analysis-view MCP and CLI boundaries, the compact input-schema contract and
|
||||
MCP boundary, the tool-schema validity boundary, the analysis-detail and
|
||||
advertised-input-example contracts and the qlog acceptance test: 14 files,
|
||||
113 tests passed, 1 pre-existing skip.
|
||||
|
||||
Real captures (outside the test suite): the built view ran through the
|
||||
application service on the same 44 recorded captures (39 HAR, 5 browser
|
||||
scenario) with all three template rules, in 7 to 50 ms each. 42 produced a
|
||||
state, and the same two browser-scenario captures are refused with
|
||||
`resource_constraint` as on the base. The base column is the brief's baseline,
|
||||
which the same script reproduced on the base build in an earlier pass; this
|
||||
pass did not rebuild the base.
|
||||
|
||||
| Measure | Base | This change |
|
||||
| ---------------------------------- | ----- | ----------- |
|
||||
| Types | 568 | 576 |
|
||||
| Entities | 2,213 | 2,246 |
|
||||
| Documents | 2 | 299 |
|
||||
| Item views | 211 | 213 |
|
||||
| List views | 497 | 504 |
|
||||
| Document views | 2 | 299 |
|
||||
| State-backed read tools (of 1,258) | 710 | 1,016 |
|
||||
| Recorded: `not-entity` | 306 | (retired) |
|
||||
| Recorded: `no-identity` | 129 | 32 |
|
||||
| Recorded: `path-varies` | (new) | 32 |
|
||||
| Recorded: `query-varies` | 5 | 69 |
|
||||
| Recorded: `body-unusable` | 32 | 32 |
|
||||
| Recorded: `list-differs` | 31 | 31 |
|
||||
| Recorded: `no-init-recording` | 26 | 26 |
|
||||
| Recorded: `query-body` | 12 | 12 |
|
||||
| Recorded: `fields-differ` | 3 | 4 |
|
||||
| Recorded: `envelope-varies` | 4 | 4 |
|
||||
|
||||
Seven list types gained a suffix-named identity (`permissionId`, `product_id`,
|
||||
`ItemId`, `user_id`, `channel_id`, `spl_id` and `eventId`). Seven more had one
|
||||
before the two-item proof and lost it, because every initial response listed a
|
||||
single item: an Airbyte organization, a Mattermost reaction and team
|
||||
membership, and a Redpanda broker and schema reference became documents; a
|
||||
NOAA station read is `query-varies` and a Redpanda consumer read
|
||||
`path-varies`. Two Ghost item tools render from `/members/0` and `/tags/0`. A
|
||||
third Ghost item tool is located at `/posts/0` but stays `fields-differ`: its
|
||||
recordings differ by an `include` query.
|
||||
|
||||
State result size, as the JSON length of each Evidence summed over the 42
|
||||
states: 2,677 KiB on the base and 3,196 KiB now (+19%), measured by the same
|
||||
script. The largest growth per capture is Metabase (133 to 236 KiB), Directus
|
||||
(21 to 93), Redpanda Console (26 to 68) and Vault (9 to 43). Documents take
|
||||
492,516 of the 3,274,243 UTF-8 bytes of the results now; the base held two.
|
||||
Agent tokens, CPU time and peak memory of the state view were not measured.
|
||||
|
||||
Tool descriptions on the 44 captures' manifests: all 44 catalogs were admitted
|
||||
within their reservation. 1,336 of 1,400 tools state what they return: 1,333
|
||||
from a `2xx` record and three labelled with another status (Miniflux and
|
||||
NocoDB 404, Shlink 501), because none of their records succeeded as JSON. The
|
||||
summaries add 261,502 bytes to a 1,185,893-byte catalog of names, descriptions
|
||||
and input schemas (median 136, 95th percentile 554, maximum 1,133 bytes per
|
||||
tool); five reached the field sample bound (one Keycloak, one Lychee and three
|
||||
Sentry tools with 46 to 105 fields). The MCP annotations add 113,182 bytes to
|
||||
`tools/list` and none to the card. Building a catalog took a median 1.6 ms and
|
||||
at most 7.6 ms (Metabase), after the source was loaded. Agent tokens, CPU time
|
||||
and peak memory of the description build were not measured.
|
||||
|
||||
After merging the environment state view's review fixes (its branch at
|
||||
6ad63bcc, which also brings main's evidence-file sources), every gate ran
|
||||
again on the merged tree: `npm run check:fast`, `npm run format:check`,
|
||||
`npx knip`, `npm run scan:todos` and `npm run docs:check` passed; `npm run
|
||||
jscpd`: 3.39% duplicated lines over 3362 files; `npx vitest run --project
|
||||
domain --project services`: 344 files, 5914 tests passed, 5 pre-existing
|
||||
skips; `npm run build:cached`, then `npm run test:focused --` the serve and
|
||||
tool-definition adapters, the serve MCP and CLI boundaries, the export CLI
|
||||
boundary, the analysis-view MCP and CLI boundaries, the compact input-schema
|
||||
budget and the analysis-detail and advertised-input-example contracts: 10
|
||||
files, 98 tests passed.
|
||||
|
||||
The real-capture comparison was repeated on the merged code, with the base
|
||||
measured on the merged state view without this change: all 44 captures now
|
||||
produce a state, and 1,011 of 1,277 read tools are state-backed against 625
|
||||
on the base (216 item, 416 list and 379 document views against 214, 409 and
|
||||
2). Recorded reasons: `no-identity` 216 to 32 and `not-entity` 310 to none;
|
||||
`query-varies` 5 to 76 and `path-varies` 36 are document reads under more
|
||||
than one query or path; `list-differs` 35, `body-unusable` 33,
|
||||
`no-init-recording` 28, `query-body` 12, `envelope-varies` 4 are unchanged,
|
||||
and `fields-differ` is 9 to 10.
|
||||
|
||||
Not covered here: serving from the state, the AgentEnv data plane and write
|
||||
effects, which are later increments.
|
||||
|
||||
## After the squash onto main
|
||||
|
||||
The branch was squashed onto main once the state-serve branch merged (166fb082). Against a merge of the previous head
|
||||
into that main, the squash keeps both sides of every conflict and drops nothing of this branch. Two tests then failed
|
||||
on it and were refitted with the oversized-document fix in 2a926a0a: the bundle test of a state catalog over the
|
||||
discovery budget uses 300 read tools, inside the window where the state's catalog is refused and replay's, with its
|
||||
response summaries, still fits (280–320 by a probe), and the rea-state validation test names the pushed document by
|
||||
the count of documents the state holds. The replay-only card test pinned main's 11,131-byte card; it now pins this
|
||||
branch's 12,818-byte card, whose descriptions name each tool's recorded responses. The branch then merged main at
|
||||
d7ca93cc without conflicts.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Implementation plan
|
||||
|
||||
1. Export the Evidence file authenticator from `environmentSource.ts` with a
|
||||
`state` role, and validate a HAR capture there with the owned borrowing
|
||||
parse so later views reuse it. Add `environmentState.ts` to check state
|
||||
Evidence against a loaded source, build the served catalog (the tools a
|
||||
state serves and the data plane its card declares), derive the state from
|
||||
the capture through the analysis view service with the capture as retained
|
||||
Evidence, and prepare it: unavailable when its catalog exceeds the
|
||||
discovery budget under the served name or it cannot be derived.
|
||||
2. Add `environmentStateDocument.ts` to validate `rea-state/v1` documents
|
||||
against the served types and views, and `environmentStateStore.ts` for the
|
||||
live store with reset, atomic replace and the `data/get` snapshot.
|
||||
3. Export `selectsRecordedLine`, the body-taking `replayAnswer` and the path
|
||||
rule `pathValueMatches` from `environmentReplay.ts`, export one recorded-body
|
||||
predicate `stateBodyJson` from the state accumulator and `changesState` from
|
||||
the state rules, and widen `collectionPathOf` to any value with a path, so
|
||||
state answers reuse selection, matching, body and write rules.
|
||||
4. Add `environmentStateAnswer.ts` for item, list and document answers, the
|
||||
recorded fallback and the answer function serve and export share.
|
||||
5. Declare the state data plane on the card in `environmentTools.ts`, taking
|
||||
the data plane in an options object so the discovery budget reserves the
|
||||
card and descriptions actually served.
|
||||
6. Add `stateIntake.ts` for parts, files on this host and downloads
|
||||
(injectable fetcher and timeout, cancellation, coarse failure categories)
|
||||
and `environmentDataPlane.ts` for the three methods, run one at a time in
|
||||
arrival order and cancelled by the server's stop or the caller's
|
||||
departure; let `serveEnvironment.ts` serve the shared catalog and answer
|
||||
function, queue every message of a batch at arrival, bound the replies of
|
||||
one response and stop the data plane before closing the listener.
|
||||
7. Make `environment-serve` prepare the state under its served name after
|
||||
loading the source, add `--replay-only`, log an unavailable state as a
|
||||
warning before binding, and report `state` in the stopped document.
|
||||
8. Let `environment-export` prepare the state the same way under the bundle
|
||||
name, only after the name checks, and plan the served
|
||||
tool count, the verifier check from the shared answer function, the `serve`
|
||||
verifier and the README's serving section from it; report `state` in the
|
||||
export output and expect the served count in the hosted-lane script.
|
||||
9. Cover services, adapters, cli-boundary, mcp-boundary and process-boundary
|
||||
behaviour; document default serving, `--replay-only`, the fallback, the
|
||||
answers, the data plane, the card and the export.
|
||||
|
||||
No dependency, provider or REA tool contract changes. The only new network
|
||||
activity is an `https://` download that a `data/add` call names.
|
||||
@@ -0,0 +1,196 @@
|
||||
# Serve the environment from its state by default
|
||||
|
||||
Issue: https://github.com/morluto/rea/issues/4933
|
||||
|
||||
## Outcome
|
||||
|
||||
`rea environment-serve <manifest> --evidence <capture>` serves the environment
|
||||
from the initial state the capture observed, with nothing else to supply: at
|
||||
startup it derives the `environment-state` view of the capture in-process with
|
||||
the manifest's `template_rules`. Read tools whose views are state-backed answer
|
||||
from one live state, the `/agentenv` data plane implements `data/reset`,
|
||||
`data/add` and `data/get` against it, and the card advertises those operations
|
||||
and an intake declaration. `--replay-only` serves exactly the stateless replay
|
||||
main serves: every manifest tool replays its recordings, `/agentenv` answers every method as not found and the card is
|
||||
byte-identical. A state that cannot be derived, or whose catalog exceeds the
|
||||
discovery budget, starts the server in replay mode, logs why and reports it. Exported bundles serve the state by default,
|
||||
and their verifier and README match what they serve. Serving is read-only in
|
||||
this increment: write tools are not served from the state.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Derive the state in the application layer, shared by serve and export:
|
||||
`deriveEnvironmentState(source, capture, operation)` authenticates the
|
||||
capture value the command already read (an owned snapshot authenticated by
|
||||
the source load is reused, not parsed again), projects the
|
||||
`environment-state` view with the manifest's `template_rules` through
|
||||
`inspectAnalysisViewValidated` with the capture as retained Evidence (the
|
||||
Evidence id equals that of a projection by hand, and the capture's strings
|
||||
are not charged again as inline input, which refuses captures of a few MiB),
|
||||
then applies `loadEnvironmentState`: `inspect_analysis_view` Evidence of kind
|
||||
`environment-state`, its `parent_evidence_id` equal to the capture's, its
|
||||
`template_rules` equal to the manifest's in the same order, and every view
|
||||
naming a manifest tool, refusing otherwise with `invalid_request` whose issue
|
||||
path starts with `state`. The source validates a HAR capture with the owned
|
||||
borrowing parse, so the view reuses that validation.
|
||||
- `prepareServedState(source, capture, {name, operation})` first builds the
|
||||
state catalog under the served name, then derives the state, and reports
|
||||
`{served: true, evidence_id}` or
|
||||
`{served: false, reason: "unavailable", code, message}` with the refusal's
|
||||
projected code and message: a state catalog over the discovery budget is
|
||||
unavailable with `resource_constraint`, and no state is derived for it. A
|
||||
derived state whose catalog fits always serves from the state. The CLI
|
||||
reports `{served: false, reason: "replay-only"}` itself for `--replay-only`
|
||||
and derives nothing.
|
||||
- Keep one state store per server process, shared by every MCP session and the
|
||||
data plane: entities keyed by type, collection and id with per-collection
|
||||
order taken from the entities array, documents keyed by tool. `reset`
|
||||
restores the Evidence state, `replace` installs a validated document whole,
|
||||
and mutations are synchronous.
|
||||
- Answer item views by rendering the entity the path arguments name into the
|
||||
recorded envelope of `envelope_ordinal`. Match arguments as replay does: a
|
||||
held collection segment equal to the argument as written or after
|
||||
percent-decoding, preferring verbatim spellings, and the identity as the last
|
||||
argument percent-decoded, then as written, never re-split on `/`. Any held
|
||||
entity answers, and query arguments only set `replay.exact_match`. Refuse an
|
||||
entity the state does not hold, or one lacking a required field, as a tool
|
||||
error and never invent a body.
|
||||
- Answer list views from the state only when the arguments name one of the
|
||||
view's `checked_record_ordinals` exactly (every path and query value equal and
|
||||
no recorded query parameter unsupplied), choosing among them as replay
|
||||
chooses: every collection entity in state order for `membership: "all"`,
|
||||
otherwise the recorded members the state still holds. A member lacking one
|
||||
of the view's `required_fields` makes the call a tool error stating that the
|
||||
state holds no complete member, never a partial body, as for items. Lines
|
||||
recorded after a write or with other filters were never checked and answer
|
||||
from recordings.
|
||||
- Answer document views with the state's value when the arguments name the
|
||||
document's checked line exactly.
|
||||
- Answer recorded views, tools without a view and unrecorded requests from the
|
||||
recording, labelled `state: {source: "recording", reason}`; label state
|
||||
answers `state: {source: "state", view, …}` with the base record's replay
|
||||
provenance and `truncated: false`; refuse a state answer over 256 KiB as a
|
||||
tool error rather than cut it.
|
||||
- Serve `data/reset` (`{}`), `data/add` with exactly one `data` or `file` part
|
||||
(`bytes`, a `file://` regular file or an `https://` download with a 30 s
|
||||
timeout covering the body, no redirects and a streamed 32 MiB cap;
|
||||
`mimeType` when given is `application/json`) and `data/get` (`{parts:
|
||||
[{kind: "data", data: rea_state}]}`). A `file://` uri whose host is neither
|
||||
empty nor `localhost`, or whose path is a UNC path, is `-32602` before
|
||||
anything is opened. A document that `data/get` would write back past 32 MiB,
|
||||
once it adds the members a document may omit, is `-32602`, so a reported
|
||||
state always loads again. Anything else is `-32602`, including empty `parts`; a
|
||||
failed download is `-32000`; errors never echo a uri or content and name a
|
||||
coarse failure category in `error.data.reason`. Calls run one at a time in
|
||||
arrival order across requests; every message of a batch is queued when the
|
||||
batch arrives, so no other request's call lands between them, and
|
||||
notifications run without a reply.
|
||||
- Stopping the server (`close` or `prepareShutdown`) aborts the data plane's
|
||||
stop signal, and a request's own signal aborts when its client leaves: the
|
||||
download in progress ends with reason `cancelled`, queued calls are answered
|
||||
`-32000` with reason `cancelled` without running, and a `data/add` whose
|
||||
file read finished after the cancellation does not replace the state.
|
||||
- A `file://` read whose descriptor close fails answers `-32000` and keeps the
|
||||
descriptor in a server-lifetime owner. The next file read retries the close
|
||||
first and, while it still fails, answers `-32000` without opening the file.
|
||||
`close` retries it again and rejects while it is still open.
|
||||
- Bound one `/agentenv` response to 64 MiB of replies (twice the intake
|
||||
limit). Each reply is measured in bounded JSON parts as it is produced, in
|
||||
message order, and assembled only when it fits, so a reply past the budget is
|
||||
counted but never serialized whole. Room is kept for every later reply's
|
||||
budget error and for a batch's brackets and commas, so the body never
|
||||
passes the budget; a reply that does not fit is replaced by `-32000` with
|
||||
`data: {max_response_bytes, reply_bytes}`, unless that error is no smaller
|
||||
than the reply, so the body is never built past the budget and small write
|
||||
replies are kept.
|
||||
- Validate `rea-state/v1` documents against the served types and views: known
|
||||
types, collections that instantiate their template, ids equal to the identity
|
||||
field, unique keys, `view_fields` naming item or list views of the type
|
||||
without setting the type's identity field to a value whose scalar text
|
||||
differs from the entity's id (refused at that view's `fields`),
|
||||
documents naming document views once at the initial path, and the optional
|
||||
`state_evidence_id` and `types` that `data/get` reports equal to the served
|
||||
ones. Refuse numbers without an exact native value and `__proto__` members.
|
||||
Name the first problem by JSON pointer, never deeper than a caller-data
|
||||
member (`fields`, `value`, `types`), and leave the state unchanged.
|
||||
- Keep record citations Evidence provenance: refuse `record_ordinals` or a
|
||||
`record_ordinal` other than the Evidence's for that entity or document, and
|
||||
hold the Evidence's citations only for loaded values equal to the Evidence's;
|
||||
edited or added values cite none.
|
||||
- In state mode, declare `operations: ["data/reset", "data/add", "data/get"]`
|
||||
and the `urn:agentenv:intake/v1` extension, describe tools as answering from
|
||||
the state where it backs them, and leave out `POST`, `PUT`, `PATCH` and
|
||||
`DELETE` tools other than query `POST`s. The discovery budget reserves the
|
||||
card and descriptions actually served (`servedCatalog` returns the tools and
|
||||
the data plane the card declares). A state catalog can exceed the budget a
|
||||
replay catalog fits, so such a state is unavailable and the environment and
|
||||
its export serve replay: everything main served and exported is still
|
||||
served and exported.
|
||||
- The CLI has no `--state`; `--replay-only` (default false) serves replay
|
||||
without deriving. Otherwise it prepares the state under the name it serves
|
||||
(`ENVIRONMENT_NAME` or the manifest's). When the state is unavailable the
|
||||
command logs a warning with the code and message through its listener logger
|
||||
before binding, and serves replay. The stopped document's `state` member is
|
||||
the report. `serveEnvironment` keeps taking an optional prepared state and
|
||||
serves replay without one; the served catalog (`servedCatalog`) and the
|
||||
answer function (`environmentToolAnswer`) are shared with export.
|
||||
- `environment-export` keeps the bundle command
|
||||
`rea environment-serve /env/manifest.json --evidence /env/evidence.json` and,
|
||||
after its name checks, prepares the state under the bundle name as that
|
||||
server will, to predict what it serves, so a refused `--name` derives
|
||||
nothing; its report is served or unavailable, never replay-only. The
|
||||
verifier's `TOOL_COUNT` and the command's `tool_count` are the served tool
|
||||
count, and its check tool and expected status come from calling the server's
|
||||
answer function with `{}` on the first served `GET` tool without path
|
||||
parameters whose answer is not an error. The verifier and smoke task use the
|
||||
id `serve`. The README's "What the environment serves" section describes
|
||||
serving from the state, the replay fallback and `--replay-only`, says which
|
||||
applies to the bundle (with the code and message when the state is
|
||||
unavailable), and keeps the not-emulation and untrusted-content caveats. The
|
||||
export output adds `state`. The hosted-lane verifier script expects the
|
||||
served count.
|
||||
|
||||
## Acceptance and limits
|
||||
|
||||
Services tests cover derivation (the by-hand Evidence id and state, a capture
|
||||
the manifest was not projected from, a capture inline admission refuses),
|
||||
the prepared reports (served, unavailable for a `capture_browser_scenario`
|
||||
capture with header values but no response bodies, unavailable with
|
||||
`resource_constraint` for a 350-tool read-only manifest whose replay catalog
|
||||
fits), bundle plans served from the state and in replay (tool count, check tool
|
||||
and status, a check whose state answer differs from replay's in record and
|
||||
status, a check that skips a tool the server cannot answer, the replay fallback
|
||||
of that 350-tool manifest, name refusals before any preparation, a manifest
|
||||
neither mode admits, verifier, smoke task and README wording), the loader
|
||||
refusals, store reset, order, round trip and
|
||||
atomic replace, the first-problem pointers, citation provenance after a load and
|
||||
every answer path: item (including percent-encoded collection segments and
|
||||
ids), list `all`, list `recorded`, lines recorded after a write or with other
|
||||
filters, a line replay's tie-break would not pick, document, recorded view, tool
|
||||
without a view, unrecorded request, missing entity, missing required field and
|
||||
the body limit, a view value that changes an entity's identity, and a list
|
||||
member missing a required field. Adapters tests cover the data-plane shapes,
|
||||
`-32602` for empty and malformed parts and invalid documents, inexact numbers,
|
||||
bytes, `file://` and its failure categories, `file://` uris naming another
|
||||
host or a UNC path, injected https downloads (status, declared and streamed
|
||||
size, the timeout whether or not the fetcher honours its signal), the default
|
||||
fetch's refused redirects, arrival-order application across requests, a batch
|
||||
another request's reset cannot split, cancellation by the server's stop and by
|
||||
a departed caller, a server that closes while a download is stalled, a
|
||||
retained state-file close that the next file read and `close` retry, the
|
||||
response budget, batches and notifications, the card declaration, absent write
|
||||
tools, a served query `POST`, the per-mode discovery reservation and a
|
||||
`data/add` that changes the next tool answer over MCP. The mcp-boundary tests serve the state the
|
||||
built CLI derives from only a manifest and a capture, and `--replay-only` with
|
||||
every manifest tool, `-32601` data-plane answers and a card whose SHA-256
|
||||
equals that of the card main serves for the fixture; the process-boundary test checks the stopped document's
|
||||
`state` for a derived state, `--replay-only` and an unavailable state, and the
|
||||
warning logged before binding; the cli-boundary export test checks the served
|
||||
tool count, the verifier and the README of an exported bundle. No test reaches
|
||||
an external network. Write effects, list filters beyond recorded lines and
|
||||
`tables` in the intake declaration are out of scope.
|
||||
|
||||
## Deferred issue criteria
|
||||
|
||||
Write effects are a later increment of #4933. This PR must reference rather
|
||||
than close the issue.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Record the serving contract, requirements and deferred increments.
|
||||
- [x] Load and cross-check state Evidence for a served source.
|
||||
- [x] Add the store, the document validator and the snapshot.
|
||||
- [x] Answer item, list and document views from the state with recorded
|
||||
fallbacks.
|
||||
- [x] Serve the data plane and declare it on the card; leave write tools out.
|
||||
- [x] Address review: answer lists and documents only from checked lines,
|
||||
match item arguments as replay does, reserve the served card only, keep
|
||||
record citations Evidence provenance, and run data-plane calls in arrival
|
||||
order with a tested download timeout.
|
||||
- [x] Derive the state from the capture at startup, as retained Evidence, with
|
||||
the loader's checks; reuse the capture's validation.
|
||||
- [x] Replace `--state` with `--replay-only`, fall back to replay with a logged
|
||||
warning when no state can be derived, and report `state` when stopped.
|
||||
- [x] Derive the state in `environment-export` to plan the served tool count,
|
||||
the verifier check and the README; report `state` in its output.
|
||||
- [x] Add services, adapters and boundary coverage; remove the `--state` flag
|
||||
tests.
|
||||
- [x] Document default serving, `--replay-only`, the fallback, answers, data
|
||||
plane, document format, card and export.
|
||||
- [x] Address review: serve and export replay when the state's catalog
|
||||
exceeds the discovery budget, check the bundle name before preparing the
|
||||
state, keep replay-only out of export plans, test a check the state
|
||||
answers differently from replay, and pin main's replay card digest.
|
||||
- [x] Address review: bound one `/agentenv` response's replies, queue a
|
||||
batch's messages together at arrival, cancel the running download and
|
||||
queued calls when the server stops or the caller leaves, refuse
|
||||
`file://` uris naming another host or a UNC path, refuse view values
|
||||
that change an entity's identity, and apply list views' required fields.
|
||||
- [x] Run static, formatting, duplication, documentation and test gates.
|
||||
@@ -0,0 +1,79 @@
|
||||
# Verification
|
||||
|
||||
Verified base: 6676582675e08574146a812ae58cff67e2e53282 (this branch's head),
|
||||
with the review fixes of this pass uncommitted.
|
||||
|
||||
Executed on the implementation worktree on macOS with Node v22.23.1 (the
|
||||
repository pins 24.18.0 in `.nvmrc`, which was not installed). Every check
|
||||
below ran as written after the last source change, in this order.
|
||||
|
||||
- `npm run format` then `npm run format:check`: passed (4330 files).
|
||||
- `npm run check:fast`: typecheck and lint passed. The lint report holds 0
|
||||
errors and no diagnostic in any file this pass touches.
|
||||
- `npx knip`: passed (exit 0, no findings).
|
||||
- `npm run jscpd`: 3.37% duplicated lines over 3373 files (2800 clones), under
|
||||
the 3.5% gate; no clone involves a file this pass changed.
|
||||
- `npm run scan:todos`: passed, no markers.
|
||||
- `npm run docs:check`: the built documentation checks (6 tasks) and the README
|
||||
consistency conformance test (5 tests) passed.
|
||||
- `npx vitest run --project domain --project services`: 347 files, 5948 tests
|
||||
passed, 5 pre-existing skips.
|
||||
- `npm run build:cached` (the built output already included this pass's
|
||||
sources), then `npm run test:focused --` the serve CLI, MCP and process
|
||||
boundaries, the export CLI boundary, the CLI startup imports, the agentenv
|
||||
verifier identity boundary, the bundle package pin conformance test, the CI
|
||||
change scope boundary, the analysis-view CLI and MCP boundaries, and the
|
||||
`serveEnvironment`, `serveEnvironmentState`, `environmentCapacity` and
|
||||
`stateIntake` adapters tests: 14 files, 335 tests passed.
|
||||
- After this file was written: `npm run format`, `npm run format:check`,
|
||||
`npm run scan:todos` and `npm run docs:check` passed again.
|
||||
|
||||
The review fixes are covered by these tests, all passing in the runs above:
|
||||
|
||||
- Response budget: a batch of four `data/get`s over a loaded state of about a
|
||||
third of the budget keeps two results, answers the other two with `-32000`
|
||||
and `max_response_bytes`, keeps the trailing reset's `{}`, and its body stays
|
||||
within the budget.
|
||||
- Batch order: a batch `[data/add (gated download), data/get]` with a
|
||||
`data/reset` from another request sent while the download is held reports
|
||||
the loaded state from its `data/get`, and the reset applies last.
|
||||
- Cancellation: aborting the data plane's stop signal ends a stalled download
|
||||
(its fetcher's signal is aborted) and answers the queued reset as
|
||||
`cancelled` without running it; a call made after the stop does not run; a
|
||||
caller whose request signal aborts gets `cancelled` and the state is
|
||||
unchanged. Over loopback HTTP, `close()` of a served state returned while a
|
||||
download that never answers was in progress, and that download's signal was
|
||||
aborted.
|
||||
- File closes: with an injected close failure, `data/add` of a `file://` uri
|
||||
answered `-32000` without echoing the uri. The descriptor stayed open, and
|
||||
the next file load closed it before loading. While the close kept failing,
|
||||
over loopback HTTP the next file load answered `-32000` ("still open") and
|
||||
an inline `data` part still loaded. `close()` rejected with the unfinished
|
||||
close, then resolved and closed the descriptor once the close succeeded.
|
||||
Both tests fail on the previous head, which dropped the descriptor.
|
||||
- File hosts: `file://remote.example.test/...` and
|
||||
`file:////remote.example.test/...` are refused with the network-share
|
||||
message and no failure category; a `file://localhost/...` uri loads.
|
||||
- Loaded identity: `view_fields` setting `id` to `3`, `"3"` or `null` on user 2
|
||||
is refused at `/rea_state/entities/7/view_fields/0/fields`; `"2"` loads.
|
||||
- List required fields: a folder without `title` makes `get_folders` a tool
|
||||
error naming the incomplete entity.
|
||||
|
||||
That each test fails without its fix is source-derived; the fixes were not
|
||||
reverted to show it.
|
||||
|
||||
Not covered here: a Windows host (the UNC refusal ran on macOS, where
|
||||
`file:////host/share` converts to `//host/share`; the host check runs before
|
||||
any path conversion on every platform), a real `https://` download (tests
|
||||
inject the fetcher), the memory and time of a budgeted batch (not measured),
|
||||
agent token usage, a real AgentEnv framework run, a real-world capture, and
|
||||
write effects, which are a later increment.
|
||||
|
||||
After refusing bodies too deep for the state's own nesting (a recorded body
|
||||
must nest at most the JSON depth limit minus 16 levels to enter the state):
|
||||
`npm run check:fast`, `npm run format:check`, `npx knip`, `npm run scan:todos`
|
||||
passed; `npm run jscpd`: 3.37% over 3373 files; `npx vitest run --project
|
||||
domain --project services`: 347 files, 5950 tests passed, 5 pre-existing
|
||||
skips; `npm run build:cached`, then `npm run test:focused --` the serve CLI,
|
||||
MCP and process boundaries, the export CLI boundary and the two serve adapter
|
||||
tests: 6 files, 48 tests passed.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Implementation plan
|
||||
|
||||
The branch builds on the state-serving and coverage branches (merged into it).
|
||||
|
||||
1. **Write plan types and request bodies.** Add the plan, rule and reason types
|
||||
beside the state rules, and have the state accumulator lend extraction
|
||||
parsed request bodies under the same budget, admitted like response bodies.
|
||||
2. **Field rules.** Add a module that explains an observed entity against the
|
||||
call that wrote it (echo, copy, path, slug, clock, sequence, unique,
|
||||
template and constant) and that recognises and formats clock values,
|
||||
UUIDs and tokens.
|
||||
3. **Effects.** Add one apply module that both the gate and the server use. It
|
||||
applies a create, update, delete or document write to a writable state
|
||||
interface from a plan, a call and a value source: the recorded values in
|
||||
the gate, the store's generators when served.
|
||||
4. **Gate.** Add a simulation that:
|
||||
- classifies every write tool;
|
||||
- builds each plan from its exemplar;
|
||||
- walks the timeline over a copy of the initial state;
|
||||
- checks state-answered reads;
|
||||
- attributes passes and mismatches;
|
||||
- learns the insert rule;
|
||||
- records verdicts.
|
||||
|
||||
Extraction runs it after the read gate and returns `writes` and
|
||||
`write_clock`; the view schema and its unknowns state the write model.
|
||||
|
||||
5. **Serving.**
|
||||
- The loaded state carries the plans and the clock.
|
||||
- The store gains atomic mutations, the clock and the counter (all reset by
|
||||
`data/reset` and `data/add`).
|
||||
- A write answer module validates the body, applies the effect and renders
|
||||
the response.
|
||||
- Item reads of missing entities answer recorded 404s.
|
||||
- The served catalog adds served write tools, with descriptions charged to
|
||||
the discovery budget.
|
||||
6. **Export.** Count served write tools in the bundle plan and README.
|
||||
7. **Tests.** Domain, services, adapters and MCP-boundary coverage as the
|
||||
spec's acceptance lists.
|
||||
8. **Documentation.** Document the write model in the environment-state and
|
||||
serving sections, and record the real-capture results, the AgentEnv run
|
||||
and the live comparison in `verification.md`.
|
||||
|
||||
There are no dependency, provider or REA tool contract changes beyond the
|
||||
`environment-state` result members, and no new network activity.
|
||||
@@ -0,0 +1,427 @@
|
||||
# Apply write effects to the served state
|
||||
|
||||
Issue: https://github.com/morluto/rea/issues/4933
|
||||
|
||||
## Outcome
|
||||
|
||||
An environment served from its state also serves the write tools whose effects
|
||||
the capture itself confirms:
|
||||
|
||||
- a create adds an entity;
|
||||
- an update changes the fields the call sends;
|
||||
- a delete removes the entity;
|
||||
- a document write changes a document.
|
||||
|
||||
Later reads, list membership and `data/get` show the change, and `data/reset`
|
||||
undoes it.
|
||||
|
||||
The `environment-state` view decides which write tools are served. It replays
|
||||
the capture's own timeline on the extracted initial state: each recorded write
|
||||
applies its modelled effect, and each later read that the state answers is
|
||||
rendered and compared with the recorded response. A write tool is served only
|
||||
when at least one later read reproduces after its effect and none contradicts
|
||||
it. Every other write tool stays unserved, listed with the reason.
|
||||
|
||||
Values the application generates are deterministic: identities, sequences and
|
||||
clock values follow the formats the capture recorded, so the same calls after
|
||||
a reset give the same state.
|
||||
|
||||
## Write plans
|
||||
|
||||
The view adds two members to its result:
|
||||
|
||||
- `writes`: one plan per manifest tool whose method may change state
|
||||
(`changesState`);
|
||||
- `write_clock`: the instant the served clock starts from.
|
||||
|
||||
**Effects.** Each plan classifies its tool:
|
||||
|
||||
| Effect | Tool | Target |
|
||||
| ---------- | --------------------------------------------------------------------- | ------------------------- |
|
||||
| `create` | `POST` to a state type's `collection_template` | an entity of that type |
|
||||
| `update` | `PUT`, `PATCH` or `POST` to that template plus one trailing parameter | the entity the path names |
|
||||
| `delete` | `DELETE` to that same item template | the entity the path names |
|
||||
| `document` | `PUT`, `PATCH` or `POST` to a document view's path | that document |
|
||||
| `none` | anything else | reason `no-state-target` |
|
||||
|
||||
**Exemplar.** A plan is built from its first successful (2xx) recorded call,
|
||||
the exemplar.
|
||||
|
||||
- **Request body.** The exemplar's request body must be a JSON object that
|
||||
could enter the state: a JSON-like media type, complete UTF-8 text within
|
||||
256 KiB, exact numbers, no `__proto__` member. Otherwise the reason is
|
||||
`body-unusable`. A `DELETE` takes no body.
|
||||
- **The written entity.** The entity is observed in the exemplar's response,
|
||||
located by its identity value at the root, in one member, or in a
|
||||
one-element array, as item views locate it. When the response does not carry
|
||||
it, the entity is observed in the first later read that shows it: an item
|
||||
read of that entity, or for a create, the one entity a collection read newly
|
||||
lists. A create whose response names its id alone (a scalar, the identity
|
||||
field, or one member) is observed only through a read of that id. With
|
||||
neither, the reason is `no-observation`.
|
||||
|
||||
**Field rules for creates.** Each field of the observed entity gets the first
|
||||
rule that explains its value. Rules that read the call come first, so an
|
||||
identity the client sends is an echo:
|
||||
|
||||
1. **Echo.** A body member of the same name with an equal value.
|
||||
2. **Copy.** A body string of 8 or more characters, found at a JSON pointer of
|
||||
the body (the shallowest match).
|
||||
3. **Path.** The value of a path parameter of the call, percent-decoded.
|
||||
Serving decodes it from the collection the call names, whichever spelling
|
||||
the call uses, and the gate fills a recorded call's path fields from that
|
||||
collection too.
|
||||
4. **Slug.** The slug of a body string member: lower case, runs of other
|
||||
characters joined by `-`.
|
||||
5. **Identity.** The type's `id_field` is generated. A sequence when it is an
|
||||
integer (or a string of digits); otherwise a UUID when it has the
|
||||
`8-4-4-4-12` hex shape; otherwise a token of the same length and character
|
||||
classes.
|
||||
6. **Clock.** A timestamp within 10 minutes of the exemplar's start time. The
|
||||
format is kept: ISO-8601 with its separator, fraction digits and zone, or
|
||||
epoch seconds or milliseconds.
|
||||
7. **Sequence.** An integer one greater than the largest value of the field in
|
||||
the collection, else in the type.
|
||||
8. **Unique.** A UUID-shaped string that no other entity of the type shares.
|
||||
9. **Template.** A string containing a generated value as a delimited token
|
||||
(for example a URL that ends in the new id). It is rebuilt around the new
|
||||
value.
|
||||
10. **Constant.** Otherwise the exemplar's value.
|
||||
|
||||
When a constant, or the text a template keeps, contains a path value of the
|
||||
exemplar's call as a delimited token, the create is served only for calls
|
||||
naming the exemplar's collection.
|
||||
|
||||
**Body members of a create.** A member is either accepted or not:
|
||||
|
||||
- **Accepted.** An echoed member, or the identity field's value. Every member
|
||||
the exemplar sent is required.
|
||||
- **Not accepted.** A member the application stored with a different value
|
||||
(transformed), or one it did not show. A call that sends such a member is a
|
||||
tool error naming the accepted members.
|
||||
|
||||
**Updates.** Body members follow the same accepted and not-accepted rules,
|
||||
except that a member the application stored differently is accepted only with
|
||||
the value a recorded call sent it with, and then stores the value that call
|
||||
recorded (its `constant` rule carries it). The type's identity field never
|
||||
takes a rule: sent as the path's id it is the identity member, sent as another
|
||||
value the application ignored it is accepted with that value and stores
|
||||
nothing, and a stored id that changed is `unexplained-change`. A plan whose
|
||||
calls use a member both as the identity and as a fixed member, or fix it at
|
||||
different values, is `unexplained-change`, as serving could not take every
|
||||
recorded call. So is an update a later read shows dropped a field the
|
||||
entity held, since serving keeps every field an update does not write; a write's
|
||||
own response may leave fields out. A member a later call is the first to store,
|
||||
which the plan's observation does not show, keeps the JSON type that call stored
|
||||
it as (the body's `kinds`), as an exemplar's member keeps the observation's.
|
||||
`PUT` requires every member the exemplar sent; `PATCH` and `POST` require at
|
||||
least one. A field the exemplar's update changed without sending it is
|
||||
explained as one of:
|
||||
|
||||
- clock;
|
||||
- an increment by one;
|
||||
- a slug of an echoed member.
|
||||
|
||||
A field the entity lacked before is a change too when the view that observed
|
||||
the update had shown the entity, so a field the application fills in on update
|
||||
follows its rule. Any other change is `unexplained-change`. An increment or a slug applies to
|
||||
every call that could take it, so the plan is also `unexplained-change` when
|
||||
such a rule would give a call of the tool another value than the one it
|
||||
recorded, or when a later call treats a member otherwise than the plan: one
|
||||
call echoes it and another stores something else, or the two rule it
|
||||
differently.
|
||||
|
||||
**Deletes.** A delete removes the entity. Its response is the exemplar's
|
||||
response, with the entity re-rendered when the response carries it.
|
||||
|
||||
**Documents.** A document write merges the body's members (replaces them, for
|
||||
`PUT`) into the document object that holds most of them: the root or one
|
||||
member. Later calls write at the exemplar's object. Document reads answer only on their recorded line, so a write is
|
||||
served only at the path the state holds the document at, and the gate treats a
|
||||
recorded write at another path as an unmodelled write. A recorded write whose
|
||||
body serving would refuse (a member of another JSON type than the document
|
||||
holds) is `unexplained-change`.
|
||||
|
||||
**Responses.** A write answers with the status and content type of one
|
||||
recorded response:
|
||||
|
||||
| Response | Body |
|
||||
| ---------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| `entity` | the written entity, rendered into the recorded envelope at the plan's pointer through the recorded fields |
|
||||
| `identity` | the recorded body with the new identity at the plan's pointer |
|
||||
| `empty` | no body |
|
||||
| `recorded` | the recorded body |
|
||||
|
||||
A rendered body missing a field the recorded response carried is a tool error,
|
||||
and the state is left unchanged.
|
||||
|
||||
**List position.** A create's `insert` rule places the new entity in its
|
||||
collection's order: sorted by the identity field or a clock field (ascending
|
||||
or descending), `first` or `last`. The rule is the first candidate consistent
|
||||
with both the initial `all`-membership recordings and the position a later
|
||||
recorded list shows. With no evidence, the rule is `last`.
|
||||
|
||||
## The gate
|
||||
|
||||
The view replays every primary-origin record in timeline order on a copy of
|
||||
the initial state.
|
||||
|
||||
**Writes.** Only a 2xx write is modelled. A modelled write applies its effect, using the values it recorded
|
||||
for generated fields and the stored values for fields it transformed. A
|
||||
modelled write whose call the plan does not explain brings its entity to the
|
||||
recorded outcome instead, without attribution. So does an update of an unknown
|
||||
entity (below): its call cannot be checked, so it adds nothing to a built plan.
|
||||
A later create whose generated
|
||||
values take another form than serving gives them (a sequence value out of
|
||||
order, a clock in another format, a non-UUID unique value) makes the plan
|
||||
`unexplained-change`; integer identities are left to the id mapping. An update or
|
||||
delete names its entity as an item read does (below). A later update that does
|
||||
not answer with its entity is observed only by a read whose view shows every
|
||||
clock the plan learned, since serving stamps them; without one it is unmodelled.
|
||||
|
||||
Any other write that may have changed state, including a redirected or
|
||||
unanswered one, is unmodelled, and what it may have changed
|
||||
depends on where its path lies relative to each type's collection paths
|
||||
(segment-prefix related, parameters matching any segment):
|
||||
|
||||
- **Below an item path:** the named entity is unknown until a read shows it
|
||||
again. When the path names no held entity, every entity of that collection
|
||||
is unknown.
|
||||
- **At a collection path:** that collection is not checked again.
|
||||
- **Above collection paths:** everything under the path is not checked again.
|
||||
|
||||
The path names its entity as an update's does and its collection as a create's
|
||||
does, so a plain spelling reaches a collection held under an encoded one; a
|
||||
path above collections covers each collection whose segments are its own
|
||||
verbatim or once percent-decoded.
|
||||
|
||||
An item read of an unknown entity shows it again: the copy takes its recorded
|
||||
values. A failed read that is no absence shows nothing, and the entity stays
|
||||
unknown. Writes that changed it since its last check are checked only on the
|
||||
members they sent, less those the view treats as volatile, which show nothing
|
||||
of a write.
|
||||
|
||||
**Reads.** A read is checked when the served environment would answer it
|
||||
from the state:
|
||||
|
||||
- an item read of a state-backed item view, of the entity serving would name:
|
||||
in a held collection the read's path matches, each segment verbatim or once
|
||||
percent-decoded and verbatim spellings first, the id percent-decoded once,
|
||||
then as written;
|
||||
- a list or document read on one of its view's checked request lines,
|
||||
chosen as replay chooses the line for the read's call: each path parameter
|
||||
the read's value verbatim or once percent-decoded, preferring verbatim
|
||||
spellings, then recorded order, and the query values decoded, in any order.
|
||||
A read with no query on a whole list falls back, as serving does, on a
|
||||
checked line that only pages it. A line whose query repeats a name with
|
||||
different values is never chosen, since no call's arguments can name it; one
|
||||
repeating a name with one value is, as a call naming it matches both. A list
|
||||
is compared as served from the collection of that line. A read on a page
|
||||
(`limit`, `size`, `per_page` and the like, or a `_start`–`_end` range; a size
|
||||
of zero is no bound on a line whose recording listed items under it, while its
|
||||
other sizes and range still bound the page) of a
|
||||
whole list checks nothing once the collection holds more entities than the
|
||||
page, which serving then answers from its recording.
|
||||
- A read made while a modelled write to its entity or collection was still
|
||||
running, starting before that write ended, checks nothing: it may show the
|
||||
state before or after the write. Nor does such a read show an unknown entity
|
||||
again.
|
||||
- A read a write's effect was learned from checks nothing of that write, but
|
||||
still contradicts the other writes it exercises.
|
||||
|
||||
**Comparison.** The read's answer is the full response serving would give from
|
||||
the copy: an item read's entity rendered into its item view's base recording,
|
||||
or a list read's members as serving would list them (so a member the copy no
|
||||
longer holds fails the check) rendered into its line's base recording. It is
|
||||
compared with the recording, as the read gate compares, with volatile fields taking the
|
||||
observed values. A recorded 400, 404 or 410, or a 2xx with a JSON `null`
|
||||
body, for an entity the copy does not hold agrees with it. A successful read
|
||||
whose usable body no longer holds the entity or the list fails, as does one of
|
||||
an entity lacking a field every recording of its view carried, which serving
|
||||
refuses to answer with.
|
||||
|
||||
**Attribution.**
|
||||
|
||||
- A check exercises the write tools that changed its entity or collection
|
||||
since the previous check of it, less those whose effect later writes erased.
|
||||
An update's effect is the fields it sent or changed, derived ones included.
|
||||
A later update overwrites the fields it sets (an increment adds to its field
|
||||
instead), a recorded outcome every field, and a create or delete the whole
|
||||
entity. A document write's effect is the members it merged at its
|
||||
object, or everything under the object it replaces, the whole document at the
|
||||
root; an entity's fields match by name only, whatever their names look like. A write with nothing left on an entity no
|
||||
longer counts there, nor in a collection where no entity it changed keeps any
|
||||
of its effect. A mismatch contradicts them. A pass confirms those it shows
|
||||
something of: a create's or delete's membership, or a changed field the
|
||||
read's view shows and does not treat as volatile; a read that shows none of
|
||||
an update's changes confirms nothing of it, and leaves it for a later check
|
||||
of that entity or collection.
|
||||
- A mismatch contradicts each exercised write that no unmodelled write came
|
||||
after its latest call on any of the read's entities or collections where its
|
||||
effect survives, whatever earlier write is still pending. For a failed list read the unmodelled write must
|
||||
also follow the last check and pending writes of each member that differs, so an older change elsewhere
|
||||
does not excuse a newer write the list shows undone. An item read checks the writes an unmodelled
|
||||
write did follow only on the members they sent, and a list with such a write
|
||||
is not checked again: the unmodelled write may explain the rest.
|
||||
- A mismatch on an entity or collection that no write changed contradicts,
|
||||
as `side-effect`, the modelled writes since that previous check whose paths
|
||||
are segment-prefix related to the read's path.
|
||||
- After a failed item check, the copy takes the read's recorded values (or
|
||||
drops the entity on a recorded absence). A list whose check failed is not
|
||||
checked again.
|
||||
- A list that fails only for where one create placed its entity passes when
|
||||
another of that create's insert candidates reproduces it, which then
|
||||
becomes the plan's rule, unless an earlier list check relied on the rule
|
||||
(an item read's confirmation does not fix it).
|
||||
- The read that supplied a create's or update's observation does not check
|
||||
it, but checks the other writes it exercises.
|
||||
|
||||
**Verdicts.** A plan is served when at least one check confirms it and none
|
||||
contradicts it. Otherwise the reason, in this precedence, is:
|
||||
|
||||
1. the first build reason;
|
||||
2. `contradicted`, with `contradicted_by` naming the first contradicting read;
|
||||
3. `side-effect`;
|
||||
4. `unconfirmed`;
|
||||
5. `incomplete-entities`: an update or delete that answers with the entity,
|
||||
when no initial entity holds every field its recorded answer shows (for
|
||||
example a delete that answers with an edit view of the entity the reads
|
||||
never showed), so it could answer only for entities the environment itself
|
||||
created. An update's answer renders the entity it wrote, so a field one of
|
||||
its rules writes counts as held, except an increment's, which adds only to
|
||||
a held value.
|
||||
|
||||
`checked_record_ordinals` lists the confirming reads.
|
||||
|
||||
## Serving
|
||||
|
||||
**Catalog.** In state mode, the catalog adds the write tools whose plan is
|
||||
served. Their descriptions say the tool:
|
||||
|
||||
- applies its effect to the served state;
|
||||
- names its target type;
|
||||
- lists its required and accepted body members, quoted and sampled within the
|
||||
description budget as response fields are.
|
||||
|
||||
The discovery budget charges them. `--replay-only` and the replay fallback are
|
||||
unchanged.
|
||||
|
||||
**Calls.** A served write answers synchronously against the live store and
|
||||
changes it atomically, so every MCP session and `data/get` see one state.
|
||||
|
||||
**Refusals.** These are tool errors that leave the state unchanged:
|
||||
|
||||
- a body that is not an object;
|
||||
- a missing required member;
|
||||
- a member that is not accepted;
|
||||
- a value of another JSON type than the exemplar's (for a member only a later
|
||||
update stored, that call's), for documents as well as entities;
|
||||
- an update or delete of an entity the state does not hold;
|
||||
- a create in another collection when the plan is tied to its own;
|
||||
- a document write at a path other than the one the state holds it at;
|
||||
- a body member or a resulting value `data/add` would refuse (a number not
|
||||
exact as `data/get` writes it, a `__proto__` member, nesting past the
|
||||
limit), increments included, so `data/get` always loads back;
|
||||
- a create, update or document write that would take what `data/get` reports
|
||||
past the 32 MiB `data/add` intake limit, as a `resource_constraint` error;
|
||||
- a rendered response missing a recorded field.
|
||||
|
||||
When the tool, or else an item view of the type, recorded a 400, 404 or 410
|
||||
response, an update or delete of a missing entity answers with the latest such
|
||||
recording instead.
|
||||
|
||||
A create in a collection held under more than one spelling (`acme1` and
|
||||
`%61cme1`) goes to the one the call spells verbatim, as item calls choose their
|
||||
entity; a collection keeps its spelling after its last entity is deleted. A
|
||||
reset or load knows the spellings of the Evidence's state, of the state it
|
||||
installs and of the type's checked list lines (so a collection the capture
|
||||
listed empty keeps its spelling), never those of a state it replaced. When two
|
||||
spellings fit a call equally, the one holding entities wins. `data/add` refuses a document that `data/get` would write back past the
|
||||
32 MiB intake limit once it adds the members a document may omit, such as
|
||||
`types` and the state Evidence id. A derived state `data/get` would write
|
||||
past that limit is not served: the environment serves replay and reports the
|
||||
state `unavailable`.
|
||||
|
||||
**Clock and generators.** The store's clock starts at `write_clock` and
|
||||
advances one second before each served write; clock fields take its value in
|
||||
their recorded format.
|
||||
|
||||
- **Sequences:** one more than the largest current value in their scope, the
|
||||
largest the state started with at its last reset or load, and the largest
|
||||
value they generated, so a deleted entity's value is not reused, as database
|
||||
sequences do not reuse values.
|
||||
- **UUIDs and tokens:** derived from a SHA-256 of the state Evidence id, the
|
||||
tool, the field and a write counter, skipping values the type already holds.
|
||||
|
||||
`data/reset` and `data/add` restart the clock, the counter and the
|
||||
sequences.
|
||||
|
||||
**Missing entities.** An item read of an entity the state does not hold
|
||||
answers with the tool's latest recorded 400, 404 or 410 response, or 2xx JSON
|
||||
`null` response, the absences the gate accepts, when it has one, labelled
|
||||
`state.view: "missing"`. Otherwise it stays a tool error.
|
||||
|
||||
**Lists of a whole collection.** Written entities matter only if lists show
|
||||
them, so the read gate's `membership: "all"` also covers a line that only pages
|
||||
its list (`limit`, `offset`, `page`, `per_page`, `perpage`, `page_size`,
|
||||
`pagesize`, `size`, `start`, `_start`, `_end`) when its recording listed the
|
||||
whole collection. A list call with no query argument answers from such a line
|
||||
of an `all` view of the collection its path arguments name, with
|
||||
`replay.exact_match` false; a collection with no such line answers from its
|
||||
recording. A call that asks for a page
|
||||
still answers from its recording.
|
||||
|
||||
**Provenance.** Write answers carry `state: {source: "state", view: "create" |
|
||||
"update" | "delete", type, collection, id}`, or `{source: "state", view:
|
||||
"document-write", path}`.
|
||||
|
||||
**Data plane and export.**
|
||||
|
||||
- `data/get` reports written entities without record citations; they load
|
||||
back through `data/add` unchanged.
|
||||
- `environment-export` counts served write tools in the bundle's tool count
|
||||
and README. Its check stays a read tool.
|
||||
|
||||
## Not modelled
|
||||
|
||||
These stay unserved, or are labelled in the description:
|
||||
|
||||
- side effects on counters, relations and copies of entities in other
|
||||
collections;
|
||||
- inputs the application transforms;
|
||||
- members the capture never sent;
|
||||
- reordering after an update;
|
||||
- membership of filtered or paged lists, which answer their recorded members;
|
||||
- write paths the manifest left literal;
|
||||
- writes whose request body the capture did not retain;
|
||||
- referential rules on delete: a delete removes the entity alone, so an
|
||||
application that refuses to delete a referenced entity, or deletes its
|
||||
dependents with it, is not modelled;
|
||||
- authorization.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- **Domain tests:** classification, every field rule, request-body admission,
|
||||
observation from a later read, the insert rules, every verdict and reason,
|
||||
attribution and resynchronisation, and taint by an unmodelled write.
|
||||
- **Services tests:**
|
||||
- store mutations and their atomicity;
|
||||
- every refusal;
|
||||
- generated values and their determinism across reset;
|
||||
- `data/get` round trips of written entities;
|
||||
- the recorded 404 for missing entities;
|
||||
- the catalog and descriptions in each mode.
|
||||
- **Boundary test:** a write tool changes the next read over MCP.
|
||||
|
||||
**Real captures.**
|
||||
|
||||
- The view runs over every showcase capture within its budget, and the
|
||||
verification reports, per capture, the write tools served and the reasons
|
||||
for the rest.
|
||||
- One environment, chosen at random among those serving a write tool, is
|
||||
exported, run in the AgentEnv framework, and graded from `data/get` after an
|
||||
agent's create, update and delete.
|
||||
- The served model is compared with that application running live on the same
|
||||
calls.
|
||||
|
||||
No test reaches an external network.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Record the write model, the gate and the serving contract.
|
||||
- [x] Admit request bodies and add the plan types.
|
||||
- [x] Explain created and updated entities with field rules.
|
||||
- [x] Apply create, update, delete and document effects in one shared module.
|
||||
- [x] Simulate the capture's timeline and decide each plan's verdict.
|
||||
- [x] Leave entities below an unmodelled write unknown until a read shows them
|
||||
again, and check writes such a write follows only on the members they
|
||||
sent.
|
||||
- [x] Serve gated write tools from the live store with deterministic values.
|
||||
- [x] Answer recorded 400, 404 and 410 responses for missing entities.
|
||||
- [x] Let lines that only page a whole collection back `membership: "all"`,
|
||||
and answer argument-less list calls from them.
|
||||
- [x] Count served write tools in exports and describe them in bundle READMEs.
|
||||
- [x] Add domain, services, adapters and boundary coverage.
|
||||
- [x] Document the write model and serving.
|
||||
- [x] Run the view over every showcase capture and report per-capture verdicts.
|
||||
- [x] Export one randomly chosen environment, run write tasks in the AgentEnv
|
||||
framework and grade them from `data/get`.
|
||||
- [x] Compare the served model with the live application on the same calls.
|
||||
- [x] Run static, formatting, duplication, documentation and test gates.
|
||||
@@ -0,0 +1,376 @@
|
||||
# Verification
|
||||
|
||||
Verified base: cbb7b613 (this branch before this file). Executed on macOS with
|
||||
Node v22.23.1 (the repository pins 24.18.0 in `.nvmrc`, which was not
|
||||
installed); the AgentEnv runs and the live comparison ran on a disposable Linux
|
||||
VM. Every check below ran as written after the last source change.
|
||||
|
||||
## Gates
|
||||
|
||||
- `npm run build:cached`, `npm run check:fast` (typecheck and lint),
|
||||
`npm run format:check`, `npx knip`, `npm run scan:todos`, `npm run docs:check`
|
||||
and `npm run verify:test-discovery`: passed.
|
||||
- `npm run jscpd`: 3.43% duplicated lines over 3538 files, under the 3.5% gate.
|
||||
- `npx vitest run --project domain --project services`: 7407 passed, 5
|
||||
pre-existing skips.
|
||||
- `npm run test:prepare`, then `npm run test:focused --` the new write MCP
|
||||
boundary, the serve MCP, CLI and process boundaries, the export CLI
|
||||
boundary, the analysis-view CLI and MCP boundaries, the compact input schema
|
||||
boundary and the contract description tests: 10 files, 72 passed.
|
||||
- `npm run mcp-catalog:check`: passed.
|
||||
|
||||
New tests: `environmentStateWriteValues` (94), `environmentStateWriteExplain`
|
||||
(101), `environmentStateWriteApply` (52), `environmentStateWrites` (16, the gate
|
||||
through the view), `environmentStateWriteAnswer` (14, serving) and
|
||||
`environmentServeWritesMcp` (1, the built CLI over MCP). The replay card pinned
|
||||
by the serve MCP boundary changed with the response summaries tool descriptions
|
||||
carry; its digest now matches the combined branch.
|
||||
|
||||
## Real captures
|
||||
|
||||
The `environment-state` view ran over the 50 showcase captures (45 HAR
|
||||
inspections and 5 `capture_browser_scenario` captures), each within its budget in
|
||||
8–110 ms. It served 33 write tools in 16 captures (11 creates, 12 updates, 10
|
||||
deletes). Of the other 150 state-changing tools, 102 name no state type or
|
||||
document (most write to literal single-entity paths the manifest left
|
||||
untemplated, or to collections whose reads are not state-backed), and 48 are
|
||||
modelled but not served:
|
||||
|
||||
- 15 unconfirmed (no later read checked them);
|
||||
- 13 no-observation;
|
||||
- 8 contradicted, for example a deleted Airbyte source and EspoCRM task still
|
||||
readable, Immich and BookStack item reads showing fields the create
|
||||
response lacked, and Sonarr's tag list ordering;
|
||||
- 7 unexplained-change, such as BookStack's description_html and Paperless's
|
||||
derived text colour;
|
||||
- 4 side-effect, for example a Sonarr tag also listed by `/tag/detail`;
|
||||
- 1 incomplete-entities: WordPress answers a delete with the post in its edit
|
||||
context, which the reads never showed for seeded posts.
|
||||
|
||||
| Capture | Served (create / update / delete) | Not served |
|
||||
| ---------------- | --------------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| airbyte | 2 / 2 / 0 | create contradicted, delete contradicted, delete unconfirmed |
|
||||
| baserow | none | no-state-target ×3 |
|
||||
| bookstack | 0 / 0 / 1 | create contradicted, create side-effect, update unexplained-change |
|
||||
| directus | none | no-state-target ×2 |
|
||||
| espocrm | none | create unconfirmed, delete contradicted, update unexplained-change |
|
||||
| ghost | none | no-state-target ×2 |
|
||||
| gitea | 1 / 1 / 0 | no-state-target ×2 |
|
||||
| grafana | none | create unconfirmed, no-state-target ×5 |
|
||||
| grist | none | create no-observation, no-state-target ×5 |
|
||||
| grocy | none | create no-observation, delete no-observation, update no-observation, no-state-target ×2 |
|
||||
| healthchecks | none | create no-observation, delete no-observation, update no-observation, no-state-target ×2 |
|
||||
| homebox | none | document no-observation, no-state-target ×3 |
|
||||
| immich | 0 / 0 / 1 | create contradicted, update contradicted |
|
||||
| jellyfin | none | no-state-target ×2 |
|
||||
| keycloak | none | no-state-target ×1 |
|
||||
| komga | none | create unconfirmed ×2, no-state-target ×4 |
|
||||
| linkding | 2 / 2 / 2 | create unconfirmed, delete unconfirmed, update unconfirmed, no-state-target ×2 |
|
||||
| listmonk | 1 / 1 / 1 | — |
|
||||
| lychee | none | no-state-target ×4 |
|
||||
| mailpit | none | document no-observation, no-state-target ×5 |
|
||||
| mattermost | 1 / 1 / 1 | no-state-target ×3 |
|
||||
| mealie | none | create no-observation, no-state-target ×2 |
|
||||
| memos | none | no-state-target ×3 |
|
||||
| metabase | 0 / 0 / 1 | create side-effect, update unexplained-change |
|
||||
| miniflux | 0 / 1 / 0 | no-state-target ×3 |
|
||||
| n8n | none | create unconfirmed, no-state-target ×6 |
|
||||
| navidrome | none | create no-observation, no-state-target ×2 |
|
||||
| netbox | 1 / 1 / 1 | — |
|
||||
| nocodb | none | create no-observation, no-state-target ×4 |
|
||||
| nomad | none | no-state-target ×4 |
|
||||
| paperless | 0 / 0 / 1 | create unconfirmed, update unexplained-change, no-state-target ×3 |
|
||||
| photoprism | 1 / 1 / 0 | delete unconfirmed |
|
||||
| pinry | none | create unconfirmed, delete unconfirmed, update unexplained-change |
|
||||
| pocketbase | none | no-state-target ×4 |
|
||||
| redpanda-console | none | document no-observation, no-state-target ×5 |
|
||||
| sentry | 1 / 0 / 0 | update unexplained-change, no-state-target ×3 |
|
||||
| shlink | none | create unconfirmed, no-state-target ×1 |
|
||||
| sonarr | 0 / 1 / 0 | create contradicted, create side-effect, update contradicted |
|
||||
| tandoor | none | no-state-target ×4 |
|
||||
| umami | 1 / 1 / 1 | — |
|
||||
| vault | none | no-state-target ×7 |
|
||||
| vikunja | none | no-state-target ×4 |
|
||||
| wordpress | none | create side-effect, delete incomplete-entities, document unconfirmed, update unexplained-change |
|
||||
|
||||
An in-process smoke derived each capture's served state and called every served
|
||||
write tool once with a varied body: all 33 applied (status equal to the
|
||||
recording), and every created or updated entity read back from the state;
|
||||
deleted entities answered the recorded 400 or 404 where one was recorded. Eight
|
||||
older published manifests no longer match the tool names the current view
|
||||
derives, so their state is unavailable and they serve replay, as designed;
|
||||
none of them has a served write tool.
|
||||
|
||||
## End to end on a published environment
|
||||
|
||||
Five published environments serve a create, an update and a delete (Linkding,
|
||||
Listmonk, Mattermost, NetBox, Umami); `random.SystemRandom().choice` picked
|
||||
NetBox (NetBoxEnv-REA, NetBox 4.7.3).
|
||||
|
||||
- `rea environment-export` (packed from this branch) wrote the bundle; its
|
||||
smoke task passed in AgentEnv framework 0.9.1334 with 42 served tools (39
|
||||
reads and `post_dcim_sites`, `patch_dcim_sites_by_id`,
|
||||
`delete_dcim_sites_by_id`).
|
||||
- Four write tasks, each graded by an `env_outcome_verifier` that reads the
|
||||
environment's state through `/agentenv` `data/get` (not the agent's reply),
|
||||
with the replay-qa agent over the Hugging Face router, one run per task and
|
||||
model:
|
||||
|
||||
| Task | gpt-oss-120b | GLM-5.3-Flash | Tool calls (gpt-oss) |
|
||||
| ----------------------------------------------- | ------------ | ------------- | ------------------------------------------------------------ |
|
||||
| Create a site in the Copper Valley region | 1.0 | 1.0 | get_dcim_regions, post_dcim_sites |
|
||||
| Update a seeded site's facility and description | 1.0 | 1.0 | get_dcim_sites, patch_dcim_sites_by_id |
|
||||
| Delete one seeded site and only it | 1.0 | 1.0 | get_dcim_sites, delete_dcim_sites_by_id |
|
||||
| Create a site, then set its facility | 1.0 | 1.0 | get_dcim_regions, post_dcim_sites, patch_dcim_sites_by_id ×2 |
|
||||
|
||||
- The bundle's 12 retrieval tasks (one per seeded object) passed 12/12 for both
|
||||
models, as they did on the published replay bundle.
|
||||
|
||||
## The served model against the live application
|
||||
|
||||
The same NetBox 4.7.3 image ran on the VM, seeded by the capture's own seed
|
||||
script (the same ids), and one scenario ran against both the live API and the
|
||||
environment served from the capture. Only `created` and `last_updated` were
|
||||
normalised; every other member had to be equal:
|
||||
|
||||
| Step | Live | Environment | Equal |
|
||||
| ----------------------------------------- | ---- | ----------- | ---------------------------- |
|
||||
| List sites | 200 | 200 | yes |
|
||||
| Create Tide Gauge Annex (id 5) | 201 | 201 | yes |
|
||||
| Read it | 200 | 200 | yes |
|
||||
| List after the create (sorted by name) | 200 | 200 | yes |
|
||||
| Patch its description and facility | 200 | 200 | yes |
|
||||
| Read after the patch | 200 | 200 | yes |
|
||||
| Create Granite Spur (id 6) | 201 | 201 | yes |
|
||||
| Patch a seeded site | 200 | 200 | yes |
|
||||
| Delete Tide Gauge Annex | 204 | 204 | yes |
|
||||
| Read the deleted site | 404 | 404 | yes |
|
||||
| Create Ledger Point (id 7, not reusing 5) | 201 | 201 | yes |
|
||||
| Delete a seeded site with devices | 409 | 204 | no |
|
||||
| Final list | 200 | 200 | no (follows from the delete) |
|
||||
|
||||
11 of 13 steps were equal. The difference is NetBox's referential protection:
|
||||
it refuses to delete a site that devices reference, while the environment's
|
||||
delete removes the entity alone. The capture only deleted a scratch site with
|
||||
no dependents, so the gate could not see the rule; it is listed under what is
|
||||
not modelled.
|
||||
|
||||
## Not covered
|
||||
|
||||
- A run of the hosted `real-agentenv` lane in CI (the AgentEnv runs here used
|
||||
the published framework release on a VM).
|
||||
- Document writes on a real capture: the four modelled ones are unserved.
|
||||
- Collections tied to a create's own collection on a real capture, and UUID
|
||||
or token identities through an AgentEnv run (both are covered by tests).
|
||||
- Agent token usage and cost.
|
||||
|
||||
## After merging the base branches and main
|
||||
|
||||
The branch then merged the serving branch at 5a61853a, the coverage branch at
|
||||
b4b7ebc7 (their review fixes) and main at edbd291a, then main at 17f581ff
|
||||
(the analysis-view tool description string, which main changes often). The gates above ran again
|
||||
and passed: `npm run jscpd` 3.44% over 3579 files; domain and services 7442
|
||||
passed with 5 pre-existing skips; the focused boundary set 72 passed. The
|
||||
write verdicts over the 50 captures were unchanged plan by plan, and the
|
||||
in-process smoke again applied all 33 served write tools. The AgentEnv runs
|
||||
and the live comparison above ran on cbb7b613, before these merges.
|
||||
After the second main merge: `npm run check:fast`, `npm run format:check`,
|
||||
`npm run docs:check` and `npm run mcp-catalog:check` passed; the contracts,
|
||||
analysis-view and environment tests 857 passed with 3 pre-existing skips; the
|
||||
analysis-view and environment MCP and CLI boundaries 53 passed.
|
||||
|
||||
## After the review round
|
||||
|
||||
The branch then merged the serving branch at c00fde41, the coverage branch at
|
||||
f6c756aa and main at 1629266e, and took the review fixes (82556cd5, 138ea4b1,
|
||||
6d21b62e). The coverage branch quotes field names in response summaries, so the
|
||||
replay card pinned by the serve MCP boundary is now 12,818 bytes; removing
|
||||
those quotes gives back the previous 12,618-byte digest exactly. The gates ran
|
||||
again and passed: `npm run check:fast`, `npm run format:check`, `npx knip`,
|
||||
`npm run scan:todos`, `npm run docs:check`, `npm run verify:test-discovery`,
|
||||
`npm run verify:module-boundaries` and `npm run mcp-catalog:check`;
|
||||
`npm run jscpd` 3.47% over 3601 files; domain and services 7463 passed with 5
|
||||
pre-existing skips; the focused boundary set 75 passed; conformance 279
|
||||
passed. The gate is stricter, but the write verdicts over the 50 captures were
|
||||
unchanged plan by plan, and the in-process smoke again applied all 33 served
|
||||
write tools. The AgentEnv runs and the live comparison above ran on cbb7b613,
|
||||
before these merges and fixes.
|
||||
|
||||
A second review round then made the gate and serving agree in five more places
|
||||
(reads matched to checked lines as serving matches calls, increments and slugs
|
||||
held for every call, insert rules still learned after an item read, the
|
||||
document body check in the gate, and decoded parent path values). Each new test
|
||||
fails on the previous head and passes here. The same gates passed again
|
||||
(domain and services 7468 passed with 5 pre-existing skips, the focused
|
||||
boundary set 75, conformance 279, `jscpd` 3.47%), the write verdicts over the 50
|
||||
captures were again unchanged plan by plan, and the smoke applied all 33 served
|
||||
write tools.
|
||||
|
||||
A third round kept a checked line's path spelling (replay prefers a verbatim
|
||||
one, so two spellings of one parent stay separate lines) and compared a later
|
||||
slug rule with the values earlier calls recorded rather than only their member
|
||||
names; both new tests fail on the previous head. A fourth round chose a read's
|
||||
line as replay does, so a read spelled plainly is checked against the encoded
|
||||
line that answers it, and its list against that line's collection; its test
|
||||
fails on the previous head.
|
||||
|
||||
A review of the fidelity branch built on this one found four more places: a
|
||||
document write at another path is now unmodelled in the gate, a create picks
|
||||
the collection the call spells verbatim, a missing entity is answered with a
|
||||
recorded 2xx `null` the gate accepted as an absence, and `data/add` refuses a
|
||||
document whose `data/get` form would exceed the intake limit. Each new test
|
||||
fails on the previous head. The gates passed again (domain and services 7475
|
||||
with 5 pre-existing skips, boundaries 75, conformance, `jscpd` 3.46%), the
|
||||
verdicts over the 50 captures were unchanged plan by plan, and the smoke
|
||||
applied all 33 served write tools.
|
||||
|
||||
A sixth round, after merging the serving and coverage branches and main
|
||||
335c042d, settled five more findings: a read whose usable body no longer holds
|
||||
the entity or list fails its check, an entity lacking a field its view always
|
||||
carried confirms nothing, a write a later write replaced is not confirmed by
|
||||
reads of the replacement, sequences never reuse a value the state started
|
||||
with, and a collection keeps its spelling after it empties. Each new test fails
|
||||
on the previous head. Over the 50 captures one capture's verdicts change:
|
||||
Linkding's bundle create and patch, confirmed only by a list read after the
|
||||
same bundle was deleted, are now unconfirmed, so 31 write tools are served (10
|
||||
creates, 11 updates, 10 deletes) and the in-process smoke applies all 31. The
|
||||
gates passed again (domain and services, boundaries, conformance and `jscpd`).
|
||||
|
||||
A seventh round settled two more findings. An update keeps its confirmation
|
||||
when a later write overwrites only part of what it changed: a derived change,
|
||||
such as an incremented version, counts as part of the update's effect, and a
|
||||
later increment adds to the field rather than replacing it. A reset or load
|
||||
forgets the collection spellings of the state it replaced. Both new tests fail
|
||||
on the previous head. The verdicts over the 50 captures are unchanged plan by
|
||||
plan, the in-process smoke applies all 31 served write tools, and the gates
|
||||
passed again.
|
||||
|
||||
An eighth round settled three more. A later write erases the fields of an
|
||||
earlier effect it overwrites, so two writes that together overwrite all of an
|
||||
update's changes leave it nothing to be confirmed by. A recorded outcome erases
|
||||
what earlier writes changed on its entity. A load keeps the Evidence's own
|
||||
collection spellings, so a create in a collection the loaded state does not
|
||||
hold keeps its recorded spelling. Each new test fails on the previous head. The
|
||||
verdicts over the 50 captures are unchanged plan by plan, the smoke applies all
|
||||
31 served write tools, and the gates passed again.
|
||||
|
||||
A ninth round made a create prefer a collection the state holds over an equally
|
||||
fitting spelling known only from the Evidence, so a create after a load lands in
|
||||
the loaded collection and reads back. Its test fails on the previous head; the
|
||||
verdicts and the smoke are unchanged and the gates passed again.
|
||||
|
||||
A tenth round settled six findings Greptile raised on the list-lines branch
|
||||
against this branch's code:
|
||||
|
||||
- a read with no query on a whole list is checked on the paging line serving
|
||||
answers it from, and a line whose query repeats a name is never checked;
|
||||
- a read made while a write to its targets was still running checks nothing;
|
||||
- a later call that stores a member otherwise than the plan refuses the plan;
|
||||
- a create keeps the spelling of a collection the capture listed empty;
|
||||
- a wide array no longer overflows the stack while checking path-dependent
|
||||
values;
|
||||
- the guide counts served write tools among the catalog's.
|
||||
|
||||
Each new test fails on the previous head. The verdicts over the 50 captures
|
||||
are unchanged plan by plan, the smoke applies all 31 served write tools, and
|
||||
the gates passed again.
|
||||
|
||||
An eleventh round settled six more findings, five raised on this branch and one on the fidelity branch:
|
||||
|
||||
- a passing read confirms only the writes it shows something of;
|
||||
- an item read names its entity as serving does, percent-decoded spellings included;
|
||||
- a read a write's effect was learned from still contradicts the other writes;
|
||||
- a line repeating a query name with one value stays checkable;
|
||||
- document writes join the effect tracking, so a replacement overwrites an earlier merge;
|
||||
- a call naming a page that the collection has outgrown answers from its recording (`page-exceeded`), and the gate does not check such reads.
|
||||
|
||||
Each new test fails on the previous head. The verdicts over the 50 captures are unchanged plan by plan, the smoke
|
||||
applies all 31 served write tools, and the gates passed again.
|
||||
|
||||
A twelfth round settled four findings Greptile raised on the list-lines branch against this branch's code:
|
||||
|
||||
- a create that answers with its id alone is observed only through a read of that id;
|
||||
- a later call that is the first to send the path's id in its body adds the identity member to the plan;
|
||||
- the copy search walks a request body with an index, so a wide body no longer takes quadratic time (500,000 zeros: 63 s
|
||||
before, 74 ms after);
|
||||
- the sent values of fixed members a plan keeps are counted against the view's allowance.
|
||||
|
||||
Each new test fails on the previous head. The verdicts over the 50 captures are unchanged plan by plan, the smoke
|
||||
applies all 31 served write tools, and the gates passed again.
|
||||
|
||||
A thirteenth round settled seven findings Greptile raised on this branch, the fidelity branch and the list-lines branch:
|
||||
|
||||
- a passing read that shows nothing of a write leaves it for a later check, instead of clearing it;
|
||||
- a read begun while a write to an unknown entity still ran neither checks nor shows the entity again;
|
||||
- a later create whose sequence fields do not follow the learned sequence refuses the plan;
|
||||
- a document replacement below the root overwrites only what it replaced;
|
||||
- a built document plan writes later calls at its own object, even one sharing no member with the document;
|
||||
- an update or delete finds its entity as an item read does, percent-decoded spellings included;
|
||||
- a `_start`–`_end` range bounds a page as `limit` does, in serving and in the gate.
|
||||
|
||||
Each new test fails on the previous head. The verdicts over the 50 captures are unchanged plan by plan, the smoke
|
||||
applies all 31 served write tools, and the gates passed again.
|
||||
|
||||
A fourteenth round settled two findings Greptile raised on the list-queries branch against this branch's code:
|
||||
|
||||
- the type's identity field never becomes a constant: an update whose id member the application ignored no longer
|
||||
writes the exemplar's id into the entity another call names;
|
||||
- a page size of zero bounds nothing, so a whole line recorded with `limit=0` answers from the state.
|
||||
|
||||
Both tests fail on the previous head. The verdicts over the 50 captures are unchanged plan by plan, the smoke applies
|
||||
all 31 served write tools, and the gates passed again.
|
||||
|
||||
A fifteenth round settled nine findings Greptile raised on this branch, the fidelity branch and the list-lines branch,
|
||||
five of them on the previous rounds' own changes:
|
||||
|
||||
- an entity field whose name looks like a pointer is matched by name; only a document's pointers cover the members
|
||||
under them;
|
||||
- a failed read contradicts each exercised write no unmodelled write came after, rather than skipping all of them
|
||||
when the oldest pending write came before one;
|
||||
- an item read, update or delete names its entity as serving does, decoding the id once, so `book%2531` no longer
|
||||
reaches `book1`;
|
||||
- a plan whose calls use a member both as the identity and as a fixed member, or fix it at different values, is
|
||||
refused;
|
||||
- a size of zero bounds nothing only on a line whose recording listed items under it;
|
||||
- an update whose observation drops a field the entity held is refused;
|
||||
- a later create whose clock takes another format, or whose unique value is not a UUID, is refused;
|
||||
- a derived state `data/get` would write past 32 MiB is not served.
|
||||
|
||||
Each new test fails on the previous head. The verdicts over the 50 captures are unchanged plan by plan, the smoke
|
||||
applies all 31 served write tools, and the gates passed again.
|
||||
|
||||
A sixteenth round settled four findings Greptile raised on the fifteenth round's changes, here and on the fidelity,
|
||||
list-lines and list-queries branches:
|
||||
|
||||
- a size of zero is no bound only by itself: a range or another size on the same line still bounds the page;
|
||||
- an update is refused for a dropped field only when a later read shows it dropped, since a write's own response may
|
||||
leave fields out;
|
||||
- interference is weighed against a tool's latest call on the read's entity or collection, not its latest call
|
||||
anywhere.
|
||||
|
||||
Each new test fails on the previous head. The verdicts over the 50 captures are unchanged plan by plan, the smoke
|
||||
applies all 31 served write tools, and the gates passed again.
|
||||
|
||||
A seventeenth round settled two more findings Greptile raised on the list-queries branch against this branch's
|
||||
interference rule: an unmodelled write counts against a tool when it followed the tool's call on any target the read
|
||||
covers, so a later call on another entity does not hide it; and a failed item read contradicts the writes no
|
||||
unmodelled write followed, checking only the others on their members. Both tests fail on the previous head. The
|
||||
verdicts over the 50 captures are unchanged plan by plan, the smoke applies all 31 served write tools, and the gates
|
||||
passed again. A follow-up weighs interference only on targets where the tool's effect survives, so a call
|
||||
whose effect a later write overwrote no longer excuses a later mismatch; its test fails on the previous head.
|
||||
|
||||
## Collection-history accounting check
|
||||
|
||||
On 2026-10-22, Node 24.18.0, I compared the source before the write-history
|
||||
change (`cfb42ddde`) with the bounded-history implementation. Each operation
|
||||
inserted an entity at a new collection path with a 128-character repeated
|
||||
suffix and immediately deleted it. Across five fresh Vitest worker processes,
|
||||
the median for 1,000 completed cycles was 14.57 ms wall / 23,867 us CPU before
|
||||
and 9.98 ms / 16,914 us after. The process RSS samples were 381.1–387.9 MiB
|
||||
before and 380.9–387.6 MiB after. This fixture benchmark measures one matched
|
||||
completed trace, not a representative user task or process-family peak memory.
|
||||
The values include Vitest and V8 and are noisy; they do not establish a memory
|
||||
bound. The 1 MiB policy is a deterministic accounting allowance for
|
||||
additional identifier history, set to 1/32 of the separate 32 MiB state-intake
|
||||
ceiling; it is not derived from RSS samples and does not bound total store or
|
||||
process memory.
|
||||
@@ -57,7 +57,12 @@ triggers or arbitrary SQL.
|
||||
Rows are optional. `table` selects one exact ordinary-table name. `columns`
|
||||
(CLI repeated `--column`) selects exact visible column names in the requested
|
||||
order; omission selects all visible columns, including generated columns.
|
||||
Unselected cells are not evaluated or projected. Malformed column-name bytes
|
||||
Unselected cells are not evaluated or projected. A selected virtual generated
|
||||
column whose expression needs a function REA's connection lacks (extensions and
|
||||
application functions are not loaded), or raises an SQL error for a sampled
|
||||
row, is refused as `capability_unavailable`. The error names the table and
|
||||
each failing selected column with SQLite's message, and recommends only columns
|
||||
whose sampled values were read; stored and other generated cells stay readable. Malformed column-name bytes
|
||||
cause a format refusal when all columns are requested. In inventory scope, an explicit valid subset can
|
||||
still be sampled without decoding unrelated malformed column names.
|
||||
Column selection requires a
|
||||
|
||||
+79
-6
@@ -46,7 +46,37 @@ without executing tests or building. A missing Git base reports how to fetch
|
||||
it or select another revision.
|
||||
|
||||
Source typechecking needs no compiled runtime or generated test metadata.
|
||||
Typecheck, runtime compilation, and Frida binding verification share
|
||||
`scripts/run-typescript.mjs`. The pinned tsrs package supplies Linux x64/arm64
|
||||
(GNU and musl) and macOS arm64 compilers. Windows and other unsupported hosts
|
||||
retain the existing stable official TypeScript compiler. Its upstream version
|
||||
can differ from tsrs, so both compiler tasks hash the selected package and version
|
||||
through `scripts/run-turbo.mjs` before cache lookup. Outputs from different
|
||||
compilers occupy different cache entries. Repository npm scripts and focused-test
|
||||
preparation use that entrypoint; a raw Turbo compiler task without matching
|
||||
identity fails instead of publishing an ambiguous successful cache entry.
|
||||
A missing binary on a supported host also fails without silently falling back.
|
||||
|
||||
The Rust compiler defaults to at most two checker threads. For `--noEmit` checks,
|
||||
`--maxMemory 3G` also sets a soft memory target; emit builds do not use that target.
|
||||
Explicit compiler arguments can override the defaults. These controls do not
|
||||
impose a process-family memory limit. Termux's explicit build, Stryker's compiler
|
||||
API dependency, and independent fixture compiler oracles keep their existing
|
||||
TypeScript versions.
|
||||
|
||||
`npm run build:cached` compiles the CLI/MCP runtime and its packaged skill.
|
||||
The build also records `dist/mcp-catalog.json` (compact inputs) and
|
||||
`dist/mcp-catalog-full.json` from the canonical SDK registrations and binds
|
||||
each to the runtime with its own SHA-256 digest. These are
|
||||
runtime artifacts, separate from the test catalog below. Default target-free
|
||||
MCP startup serves its schemas without constructing analysis validators;
|
||||
the first tool or guided-workflow request materializes the canonical runtime
|
||||
on that same SDK server. Explicit compact/full input selections preserve
|
||||
their advertised schemas throughout materialization. Initial-target,
|
||||
HTTP and output-schema-off startup keep the eager path; source runs without
|
||||
recorded artifacts also use eager composition. Compare memory both after discovery and after a completed
|
||||
request; report diagnostic GC separately from normal resident memory.
|
||||
|
||||
Turbo's strict task environment preserves caller-selected `GOMAXPROCS`,
|
||||
`GOMEMLIMIT`, and `UV_THREADPOOL_SIZE` for resource-constrained builds and
|
||||
checks. These execution controls do not change artifact content, so changing
|
||||
@@ -233,6 +263,27 @@ and retain representative compiled CLI parity checks. Every distinct source
|
||||
scenario still runs through the public workflow; session-lifecycle scenarios
|
||||
need their own sessions and cleanup assertions.
|
||||
|
||||
When a matrix already holds a named tool definition from live `tools/list`,
|
||||
pass that definition through the SDK's `toolDefinition` call option. This keeps
|
||||
the selected output-schema validation without eagerly compiling unrelated
|
||||
catalog schemas. Re-read definitions if the server advertises a changed list.
|
||||
|
||||
Artifact verification uses `artifactMcpCall` for both lifecycle and analysis
|
||||
calls. A fresh SDK client has no held tool listing, so a bare `callTool` can
|
||||
skip output-schema validation. The helper discovers actual advertised
|
||||
definitions, rejects missing or ambiguous schemas, and validates the requested
|
||||
tool without compiling unrelated catalog schemas. REA registers process-static
|
||||
tool contracts; bindings share one discovery per negotiated connection and are
|
||||
discarded on reconnect or failed discovery. Keep raw artifact calls on this
|
||||
shared path and retain explicit request options such as timeouts.
|
||||
Caller-supplied tool definitions are rejected: the helper owns selection from
|
||||
the advertised catalog so a stale or permissive schema cannot bypass it.
|
||||
|
||||
The regression fixture changes only `canonical_path` in a real stdio response
|
||||
to a number. The old helper accepts that response; the named schema must reject
|
||||
it. This client-boundary fault injection does not establish native Apple
|
||||
behavior, which remains covered by the macOS verification lane.
|
||||
|
||||
Report unavailable authority as a named skip. Await owned cleanup before a
|
||||
verifier reports success. Native process inspectors are released at Vitest
|
||||
worker teardown; fork termination does not run Node exit hooks, and per-file
|
||||
@@ -648,11 +699,29 @@ missing entries are omitted as whole entries, and consumers rebuild cache misses
|
||||
including when every entry is unavailable. Malformed plans, non-file entries,
|
||||
and I/O errors other than disappearance still fail publication. After a trusted
|
||||
static run, superseded cross-run Turbo snapshots for that OS and architecture
|
||||
are deleted down to the two newest generations. The Windows lane relies on the Linux static job for typechecking. They retain the normal build and prepack
|
||||
commands, which restore matching outputs or rebuild on a cache miss. Native
|
||||
are deleted down to the two newest generations. The Windows lane also runs the
|
||||
official compiler's complete source typecheck with two checker threads,
|
||||
independently of the accelerated Linux checker. Both lanes retain the normal
|
||||
build and prepack commands, which restore matching outputs or rebuild on a cache
|
||||
miss. Native
|
||||
artifacts, dependency installs, package archives, and runtime verification remain
|
||||
host-local. Keep platform-dependent outputs out of this shared cache.
|
||||
|
||||
The Windows native verifier's private-runtime ACL observer reads SID rules once
|
||||
for both trustee validation and counting, using .NET APIs and a fixed JSON
|
||||
projection of booleans and a count. Module autoloading is disabled; the observer
|
||||
does not need PowerShell utility cmdlets or account-name resolution. A separate
|
||||
PowerShell regression checks the shared projection with utility cmdlet traps
|
||||
and strict property access on a language-defined ACL fixture that has no `Access`
|
||||
convenience property. Fixture setup also avoids utility cmdlets. It covers
|
||||
foreign trustees, different owners, an unprotected DACL, and empty/single rules;
|
||||
these substitutes do not establish real Windows ACL behavior. The observer's
|
||||
`private-runtime-acl` stderr markers report completed phases and elapsed time;
|
||||
inspect these on a timeout
|
||||
before attributing it to startup, ACL reads, or identity lookup. The original
|
||||
15-second deadline and all ownership, DACL, and readonly assertions remain in
|
||||
force. A passing retry alone does not explain a previous timeout.
|
||||
|
||||
Record cold and warm preparation separately from fresh test execution when
|
||||
benchmarking the optional `npm run check:pr` gate. Compare multiple runs on the
|
||||
same host, including subprocess and queue costs; a cached pass is not a test
|
||||
@@ -1181,7 +1250,9 @@ host behavior or native process-supervision controls.
|
||||
real `.nib` with Xcode `ibtool`, wraps it in a temporary app bundle, and runs
|
||||
the compiled CLI and stdio MCP server with production providers. It compares
|
||||
their decoded results and checks the view hierarchy, outlet, action, evidence coverage, and truncation
|
||||
status. Storyboard compilation additionally requires an installed iOS platform.
|
||||
status. It also recompiles the XIB with toggled control booleans and requires
|
||||
both decodes to match `ibtool --export` for each source. Storyboard compilation
|
||||
additionally requires an installed iOS platform.
|
||||
|
||||
Keep the provider-specific acceptance path independent from optional
|
||||
cross-compilers. Cross-format failures belong to the cross-format lane and must
|
||||
@@ -1754,9 +1825,11 @@ projects the `environment-manifest` view with all three template rules through
|
||||
the built CLI, packs the checkout with `npm pack`, exports the bundle with
|
||||
`--package-tarball` so the image installs this checkout rather than the
|
||||
registry package, and runs `agent-env run` on the bundle. It checks that the
|
||||
export reports the planned file set with the inputs copied byte-exact, that
|
||||
the runner exits `0` with `tasks/smoke.json` reported as passed and the
|
||||
verifier's description naming the tool count, and that no container exists
|
||||
export reports the planned file set with the inputs copied byte-exact and a
|
||||
bundle served from the derived state, which serves fewer tools than the
|
||||
manifest because write tools the capture did not confirm are not served, that the runner exits `0` with
|
||||
`tasks/smoke.json` reported as passed and the verifier's description naming
|
||||
that served tool count, and that no container exists
|
||||
after the run that did not exist before; the container inventory runs even when
|
||||
the run fails or times out, so a failed receipt still lists what it left. The one exception is the framework's
|
||||
own image-store helper, `agentenv-registry` (or `agentenv-registry-<port>`),
|
||||
|
||||
@@ -59,7 +59,7 @@ harm_rank,location,trigger,current_copy,user_risk,proposed_replacement,implement
|
||||
46,src/application/Uninstall.ts:removeManagedPath symlink,Managed cache/state/skill path is a symbolic link,Refused to follow symlink {path}.,Exposes local path and does not explain manual safety check,"REA did not remove this item because its managed path is a symbolic link. Verify the link target before removing it manually.",implemented,focused assertion passed
|
||||
47,src/application/Uninstall.ts:removeManagedPath failure,Managed item removal fails,{path} could not be removed.,Exposes local path and gives no recovery,"This item could not be removed. Check file permissions, then rerun uninstall.",implemented,verified by injected managed-path removal failure test
|
||||
48,src/application/DoctorDiagnostics.ts:node,Runtime version is outside supported ranges,"Install Node.js 22.x (>=22.19), 24.x (>=24.11), or 26+.",Low risk; exact dependency recovery,Keep current copy,unchanged,verified by doctor unit test
|
||||
49,src/application/Doctor.ts:host,Host OS/distribution is unsupported,"REA supports macOS 12+, Ubuntu 24.04+, Fedora 41+, Nobara 44+, 64-bit Arch Linux, and CachyOS.",Low risk; clearly states supported choices,Keep current copy,unchanged,verified by doctor unit tests
|
||||
49,src/application/DoctorDiagnostics.ts:host,Host OS/distribution is unsupported,"REA supports macOS 12+, Linux distributions with a recognized apt, dnf, or pacman package family, and the experimental Windows x64 Ghidra P0 boundary; automated Hopper setup additionally requires Ubuntu 24.04+, Fedora 41+, Nobara 44+, 64-bit Arch Linux, CachyOS, or Omarchy.",Low risk; clearly states supported choices,Keep current copy,unchanged,verified by doctor unit tests
|
||||
50,src/application/Doctor.ts:analysis engine,Optional deep-analysis executable cannot be found,"Run rea setup to install Hopper, or set HOPPER_LAUNCHER_PATH.",Low risk in setup-specific diagnostic; exact recovery paths,Keep current copy,unchanged,verified by doctor unit tests
|
||||
51,src/application/Doctor.ts:target,Optional target path fails shared validation,Supply a readable local app or program path.,Low risk; tells caller valid target class,Keep current copy,unchanged,verified by doctor unit test
|
||||
52,src/application/Setup.ts:approval,Setup plan lacks approval,"Review the setup plan, then rerun interactively or with --yes.",Low risk; exact authorization recovery,Keep current copy,unchanged,verified by setup unit tests
|
||||
@@ -70,7 +70,7 @@ harm_rank,location,trigger,current_copy,user_risk,proposed_replacement,implement
|
||||
57,src/application/Setup.ts:unsupported platform,Platform is neither macOS nor Linux,REA supports Hopper on macOS and selected 64-bit Linux distributions.,Low risk; states support boundary,Keep current copy,unchanged,verified by setup unit test
|
||||
58,src/application/SetupHost.ts:unsupported Node,Runtime version cannot run setup,"Install Node.js 22.x (>=22.19), 24.x (>=24.11), or 26+ and rerun setup.",Low risk; exact dependency and retry,Keep current copy,unchanged,verified by setup host tests
|
||||
59,src/application/Setup.ts:unsupported macOS,macOS version is missing or older than 12,Upgrade to macOS 12 or newer.,Low risk; exact support floor,Keep current copy,unchanged,verified by setup host tests
|
||||
60,src/application/Setup.ts:unsupported Linux,Linux distribution is outside supported set,"REA supports Hopper on Ubuntu 24.04+, Fedora 41+, Nobara 44+, 64-bit Arch Linux, and CachyOS.",Low risk; exact supported alternatives,Keep current copy,unchanged,verified by setup unit test
|
||||
60,src/application/SetupHost.ts:unsupported Linux,Linux distribution is outside supported set,"Automated Hopper setup supports Ubuntu 24.04+, Fedora 41+, Nobara 44+, 64-bit Arch Linux, CachyOS, and Omarchy; configure an existing supported provider instead.",Low risk; exact supported alternatives,Keep current copy,unchanged,verified by setup unit test
|
||||
61,src/application/process/ProcessCli.ts:readJson read,Process scenario or evidence file cannot be read,Raw filesystem exception through CLI framework,Can expose local paths/codes and no recovery,"Process input file could not be read. Check that the path exists and is readable.",implemented,verified by focused CLI test
|
||||
62,src/application/JsonInputFile.ts:memory admission,Projected process JSON value exceeds available heap headroom,Insufficient heap headroom to materialize the complete JSON value,Heap admission depends on live runtime capacity rather than a fixed 64 MiB file limit,"Provide a smaller valid JSON value. For Evidence workflows, re-analyze a smaller selection of the original target and use its complete Evidence; splitting JSON text or trimming Evidence fields does not produce valid workflow input.",implemented,Source verified against shared JSON reader and recovery constant; former fixed-size refusal is superseded
|
||||
63,src/application/process/ProcessCli.ts:readJson parse,Process scenario or evidence file is malformed JSON,Raw JSON parser exception through CLI framework,Can expose parser implementation and lacks recovery,"Process input file is not valid JSON. Repair the file, then try again.",implemented,verified by focused CLI test
|
||||
@@ -116,3 +116,5 @@ Then rerun this installer.",implemented,verified by shell branch inspection
|
||||
90,install.sh:version mismatch,Installed rea reports a different version,installed version ACTUAL does not match EXPECTED.,Low risk; gives exact integrity mismatch,Keep current copy,unchanged,verified by exact installer test
|
||||
90.5,@modelcontextprotocol/server:tool input validation,Caller sends arguments that violate a declared tool schema,"Canonical invalid_request with the SDK diagnostic plus recovery.kind=inspect_input_contract and a bounded instruction to read the advertised schema or call tools/list",Keeps field/type correction while telling the agent how to recover; diagnostics over 4 KiB stay on the existing retained-error path,Normalize ordinary validation failures and retain oversized diagnostics,verified by real in-memory and stdio MCP client/server calls with wrong argument types
|
||||
90.6,incur:unknown CLI command,Caller enters an unknown REA command,"'COMMAND' is not a command for 'rea'. Suggested command: rea --help",Low risk; identifies input and exact discovery action,Keep framework-generated copy,unchanged,verified by real packaged dispatcher invocation
|
||||
91,src/application/binaryDiagnostics/ByteEntropyService.ts,Invalid file or window,"Expected a regular file.; Selected file could not be found.; Selected byte window extends beyond the end of the file.; File size exceeds exact numeric offset representation.",Invalid selection cannot produce complete entropy Evidence,Choose a readable regular file and a window within its byte size,implemented,entropy service and MCP boundary tests
|
||||
92,src/domain/analysisView/byteEntropyView.ts,Non-summary entropy view,Byte entropy Evidence supports the summary view; retrieve parent Evidence for the complete block series.,Unsupported view selection,Use the summary view or retrieve complete parent Evidence,implemented,typed input rejection
|
||||
|
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,286 @@
|
||||
# Static GPU code-object verification
|
||||
|
||||
The [receipts](gpu-code-objects-2026-10-21.json) pin the measured runtime tree,
|
||||
publisher URLs/digests, actual commands, completed answers and resource costs.
|
||||
Downloaded binaries, toolchains and complete Evidence bundles remain outside Git.
|
||||
|
||||
## Correctness
|
||||
|
||||
NVIDIA CUDA 12.9.1 redistribution archives were verified against their publisher
|
||||
manifest. nvcc 12.9.86 compiled a small owned kernel for sm_80 and sm_90a with
|
||||
uncompressed, size-compressed and speed-compressed fatbins. cuobjdump 12.9.82
|
||||
independently confirmed two parameters at offsets 0/8 with sizes 8/4, 12 parameter
|
||||
bytes, 10 physical registers and architecture-dependent shared memory. Separate
|
||||
PTX/CUBIN and a host ELF object exercised the same parser boundaries.
|
||||
|
||||
Clang 14 produced a gfx900 HIP bundle and AMDGPU ELF object; llvm-readelf supplied
|
||||
the MessagePack metadata oracle. An LLVM 19 offload bundler produced a real CCOB
|
||||
v2 Zstd bundle. All nine producer artifacts were reread on the final runtime
|
||||
source with complete payload coverage. CCOB v1/v3 and zlib have portable boundary
|
||||
fixtures, rather than real producer verification.
|
||||
|
||||
Released Linux and Windows nvJPEG 12.4.0.76 artifacts each contain 165 CUBIN and
|
||||
10 PTX payloads, with 3,968 kernel declarations across 15 target declarations.
|
||||
Independent extraction matched all 165 decoded CUBIN hashes and all 10 PTX byte
|
||||
sequences; cuobjdump resource output matched all 3,720 native kernel
|
||||
name/register/shared-memory tuples. Pre-review MCP workflows rechecked the Linux
|
||||
sm_100 subset's 248 complete kernel facts against those prior oracle facts.
|
||||
The pre-review public CLI analyzed the entire Windows DLL, exported complete
|
||||
Evidence, and reproduced all previously verified facts exactly.
|
||||
|
||||
Windows validation ran on Linux: LLVM independently identified the PE section
|
||||
coordinates, and cuobjdump consumed its extracted fatbin. cuobjdump did not
|
||||
recognize the DLL directly. This does not establish Windows runtime behavior,
|
||||
GPU execution, host launch correlation or legacy AMDGPU YAML support.
|
||||
|
||||
## Initial completed MCP workflows
|
||||
|
||||
Both fresh stdio MCP sessions analyzed only `sm_100` in the same Linux library,
|
||||
retained 176 inventory objects and 248 kernel facts, queried the same named
|
||||
kernel, exported Evidence, and repeated the historical query three times.
|
||||
The complete variant returned the selected-target report; the selected variant
|
||||
returned a same-call kernel page. Both preserved the exact answer: one parameter
|
||||
of 168 bytes, 31 physical registers and 9,216 shared bytes.
|
||||
|
||||
| Cost | Complete report | Selected page |
|
||||
| --------------------------------------------------------------- | ----------------: | -----------------: |
|
||||
| Used input declarations + three primary calls, estimated tokens | 406,862 | 26,106 |
|
||||
| All input declarations + primary calls, estimated tokens | 635,381 | 254,625 |
|
||||
| Full advertised catalog + all six calls, estimated tokens | 1,475,258 | 1,094,502 |
|
||||
| Process-family elapsed seconds | 15.492 | 15.443 |
|
||||
| Process-family CPU seconds | 18.220 | 18.074 |
|
||||
| Sampled peak family RSS bytes | 1,139,601,408 | 1,321,566,208 |
|
||||
| First inspection milliseconds | 8,572 | 8,810 |
|
||||
| Three warm retained-page calls, milliseconds | 10.7 / 10.6 / 9.8 | 12.0 / 11.4 / 10.6 |
|
||||
|
||||
Tokenx estimates include advertised schemas, arguments and full SDK replies;
|
||||
they are not actual model usage. Text and structured reply representations are
|
||||
both counted. Initialization and JSON-RPC envelopes are unmeasured. Complete
|
||||
catalog discovery substantially reduces the overall percentage saving.
|
||||
|
||||
These are workflow variants on the same implementation, not a before/after
|
||||
parser speed benchmark. Node compile caching was disabled, but OS caches and
|
||||
unrelated host load were uncontrolled. No general latency, CPU or memory
|
||||
improvement is established. The selected workflow used more peak memory in this
|
||||
pair. An earlier all-target complete reply exceeded the existing transport guard;
|
||||
that incomplete attempt is excluded from the completed comparison.
|
||||
|
||||
The full Windows DLL CLI task took 4.064 seconds / 4.909 CPU seconds /
|
||||
503,459,840 peak family RSS bytes. All profiled completed tasks stayed within
|
||||
the 8 GiB and 420 second guards, using two CPU affinities. Peak RSS sums payload
|
||||
descendants every 20 ms and is approximate; the observer is excluded.
|
||||
|
||||
## Regression checks
|
||||
|
||||
- The initial focused run passed 265 tests in 19 files: GPU domain/codec/parser
|
||||
cases, public CLI/MCP, retained views, output profiles, cancellation and cleanup,
|
||||
plus shared ELF/PE Go, Rust and IL2CPP consumers.
|
||||
- Full static checks passed before the catalog/docs-only follow-up; its receipt
|
||||
records 6,866,296,832 peak family RSS bytes. The final CI run qualifies the PR.
|
||||
- Documentation/catalog/license checks passed after fixing missing catalog
|
||||
ownership, translated README links and the new MessagePack dependency notices.
|
||||
- An earlier combined schema run hit two 30 second timeouts on two CPUs. The
|
||||
isolated canonical schema suite passed all 15 cases without increasing limits.
|
||||
This is recorded as a successful isolation, not a proven baseline failure.
|
||||
|
||||
Retention caches are scoped to immutable Evidence through a WeakMap; historical
|
||||
pages do not reopen files. Live inspections always stream a fresh full-file hash
|
||||
and revalidate the descriptor/path. No live-state freshness cache is claimed.
|
||||
|
||||
## Review follow-up
|
||||
|
||||
At `36b87ed`, the public CLI reproduced both review findings: selecting
|
||||
`amdgcn-amd-amdhsa--gfx900` in the real Clang-produced standalone object returned
|
||||
zero kernels with an unknown target, and malformed `--targets` JSON was reported
|
||||
at the `view` issue path.
|
||||
|
||||
At `09c6062`, AMD ELF note parsing owns target discovery and prepared kernel
|
||||
declarations. Inventory reads those bounded notes before selection; selected
|
||||
analysis reuses them without decoding MessagePack twice. Aggregate encoded note
|
||||
bytes are limited to 8 MiB before reads, with existing per-value/depth limits;
|
||||
the parsed JavaScript representation expands beyond that source-byte count.
|
||||
The prepared declarations live only for the current payload inspection. Named
|
||||
CLI option parsing also supplies the actual parsed input to schema diagnostics.
|
||||
|
||||
The real public CLI now inventories the gfx900 target, returns the producer's
|
||||
one kernel/two parameters/12-byte parameter area/6 SGPR/2 VGPR when selected,
|
||||
and preserves an unselected object without kernel facts for a different target.
|
||||
Those three complete CLI tasks together took 5.974 seconds / 6.951 CPU seconds /
|
||||
383,623,168 sampled peak family RSS bytes, including the Python task driver.
|
||||
All nine producer artifacts were reread with complete payload coverage.
|
||||
|
||||
The review regression run passed 35 cases in four files, including public CLI,
|
||||
MCP, metadata capacity and cleanup. A further 10 product-catalog cases passed
|
||||
after adding the missing CLI `analysis` option description identified by CI.
|
||||
The earlier paired nvJPEG measurements remain pinned to their original runtime;
|
||||
these follow-ups do not establish a new CUDA performance result.
|
||||
|
||||
## Bounded metadata and partial-fact review
|
||||
|
||||
The latest qualification at `ad1e17a` rebases onto main `5241597`, preserving
|
||||
both Rust and GPU retained views. All 70 focused cases in nine files passed,
|
||||
including both public CLI/MCP workflows; the separate SDK-converted canonical
|
||||
schema suite passed all 15 cases.
|
||||
|
||||
CUDA parsing shares an aggregate 262,144 record/symbol visit budget, 128 MiB
|
||||
section-read budget and 16 MiB serialized-size accounting budget for index facts.
|
||||
Equal scoped byte ranges and duplicate register values are coalesced before
|
||||
index growth; conflicting values survive. Parsed parameter metadata is reused.
|
||||
The public CLI completed an 861,896-byte CUBIN containing 1,024 headers aliasing
|
||||
65,536 records and retained the correct physical count. The old 67-million-entry
|
||||
expansion is source-derived; it was not run to exhaustion.
|
||||
|
||||
Decoder coverage now reaches object, report and target pages: absent CUBIN
|
||||
symbol tables and unknown section names remain partial. AMD note parsing uses
|
||||
a tagged Result that retains earlier parsed notes on later malformed, capacity,
|
||||
unsupported or interrupted reads; retained kernel facts are emitted before the
|
||||
original failure is propagated. Standalone PTX recognition continues beyond the
|
||||
64 KiB fast path up to its actual 16 MiB text budget and reuses complete probe
|
||||
bytes. Unsupported/overflowing register counts stay null instead of low totals.
|
||||
|
||||
The public CLI verified an AMD valid-note/truncated-note input and a PTX file
|
||||
with a 70 KiB leading comment, in addition to the alias case. Those three tasks
|
||||
together took 5.132 seconds / 6.222 CPU seconds / 405,835,776 peak family RSS
|
||||
bytes, including the Python driver. Regression cases additionally cover invalid
|
||||
MessagePack and unsupported extensions in standalone and bundled AMD objects.
|
||||
|
||||
The revised Windows DLL workflow preserved all 165 decoded CUBIN hashes, all
|
||||
10 PTX byte identities and all 3,720 native kernel facts. Independently counting
|
||||
register declarations in cuobjdump-extracted PTX verified all 248 PTX kernels;
|
||||
20 kernel totals now correctly include previously missed declarations. This
|
||||
is a virtual-declaration oracle, not physical allocation or GPU execution.
|
||||
The Linux sm_100 workflows still match all 248 independently checked native
|
||||
kernel facts. All nine real producer artifacts retain complete payload coverage.
|
||||
|
||||
The latest complete/selected MCP pair performed the same six calls and answered
|
||||
the same question as the initial pair. Receipts retain both measurement stages.
|
||||
|
||||
| Cost | Complete report | Selected page |
|
||||
| --------------------------------------------------------- | --------------: | ------------: |
|
||||
| Used input declarations + primary calls, estimated tokens | 407,368 | 26,612 |
|
||||
| All input declarations + primary calls, estimated tokens | 636,495 | 255,739 |
|
||||
| Full catalog + all six calls, estimated tokens | 1,480,698 | 1,099,942 |
|
||||
| Process-family elapsed seconds | 15.487 | 15.923 |
|
||||
| Process-family CPU seconds | 18.404 | 18.760 |
|
||||
| Peak family RSS bytes | 1,251,254,272 | 1,201,774,592 |
|
||||
|
||||
These remain tokenizer estimates and same-code workflow variants. The single
|
||||
latest pair establishes no general latency/CPU/memory improvement; OS caches
|
||||
and host contention remain uncontrolled. The Windows CLI rerun completed in
|
||||
4.078 seconds / 4.880 CPU seconds / 498,380,800 peak family RSS bytes.
|
||||
|
||||
Main CI independently reproduced the browser termination and WASM optional-input
|
||||
assertion failures without GPU changes. Cancelled fail-fast shards are not
|
||||
counted as passing. Those baseline failures are outside this feature's fixes.
|
||||
|
||||
## Target declaration and CUDA ABI qualification
|
||||
|
||||
The latest code `f5be46f` is based on main `f801b2f`. Inventory and payload
|
||||
target declarations remain separate, with typed consistency and inspection
|
||||
coverage preserved in object pages even with selected fields. A mismatched
|
||||
outer/inner base target remains partial and annotates affected kernels; CUDA
|
||||
base-only agreement does not establish agreement on a feature profile. Target
|
||||
filters select inventory declarations, and unexamined inner targets stay unknown.
|
||||
|
||||
Standalone and unknown-ID bundled AMDGPU files use the same bounded target
|
||||
discovery owner before filtering. Portable controls wrap the same real Clang
|
||||
ELF with two-separator, one-separator and opaque HIP IDs. All three inventory
|
||||
then exact-target CLI workflows retain the verified kernel. They are alternate
|
||||
wrapper controls, not verification of an actual legacy compiler producer.
|
||||
|
||||
The shared fixed ELF header owner now retains OS ABI. NVIDIA's released CUBINs
|
||||
include distinct `0x33` and `0x41` flag layouts. The earlier low-byte-only
|
||||
interpretation falsely produced `sm_2` for 55 modern payloads; that attempted
|
||||
target-check implementation and its timings are superseded diagnostic evidence,
|
||||
not a correctness-qualified benchmark. The ABI-qualified decoder retains raw
|
||||
flags and exact fixed-header coordinates, and leaves unrecognized patterns unknown.
|
||||
Header ownership is checked when importing portable Evidence.
|
||||
|
||||
All 165 released Windows CUBIN targets and header values were checked against
|
||||
cuobjdump-extracted files: 110 use OS ABI `0x33`, 55 use `0x41`; no false conflicts
|
||||
remain. All 3,968 corrected kernel facts and 10 PTX byte identities match the
|
||||
prior independent oracle. The nine real producer artifacts retain complete
|
||||
payload coverage. Unsupported layout controls retain their headers and make
|
||||
unknown target discovery partial in the default MCP summary.
|
||||
|
||||
After the shared-header change, 251 cases in nine files passed, including
|
||||
Go/Rust/IL2CPP consumers, GPU CLI/MCP and provenance forgery. The last uncertainty
|
||||
propagation check passed 46 public/boundary cases. The separate SDK-converted
|
||||
canonical schema suite passed all 15 cases on the current base.
|
||||
|
||||
The latest qualified complete/selected pair retains the same sm_100 question,
|
||||
answer and six-call workflow. It runs at `21eaa0d`, before the final unresolved-
|
||||
discovery-only guard.
|
||||
|
||||
| Cost | Complete report | Selected page |
|
||||
| --------------------------------------------------------- | --------------: | ------------: |
|
||||
| Used input declarations + primary calls, estimated tokens | 418,967 | 26,653 |
|
||||
| All input declarations + primary calls, estimated tokens | 648,242 | 255,928 |
|
||||
| Full catalog + all six calls, estimated tokens | 1,493,041 | 1,100,727 |
|
||||
| Process-family elapsed seconds | 21.307 | 24.604 |
|
||||
| Process-family CPU seconds | 23.538 | 26.454 |
|
||||
| Peak family RSS bytes | 1,146,519,552 | 1,341,333,504 |
|
||||
|
||||
Selected replies save context but do not establish faster analysis. The latest
|
||||
pair used more elapsed/CPU time and peak memory for selected delivery; variability
|
||||
is visible across the preserved trials. Fresh process lifetime is controlled;
|
||||
OS caches, frequency and unrelated load are not. A same-code diagnostic timing
|
||||
repeat varied substantially, and no cause or persistent speedup is inferred.
|
||||
The tokenizer/client scope and omitted initialization costs remain as above.
|
||||
|
||||
The final Windows CLI task took 5.446 seconds / 5.916 CPU seconds / 498,192,384
|
||||
peak family RSS bytes. The six HIP wrapper CLI tasks took 15.696 seconds /
|
||||
16.427 CPU seconds / 382,410,752 peak family RSS bytes. All completed tasks stayed
|
||||
within the 8 GiB family guard.
|
||||
|
||||
## Payload admission and PTX uncertainty follow-up
|
||||
|
||||
At `893e04d`, PTX parsing owns typed per-kernel coverage and limitations for
|
||||
unknown parameter layouts, shared declarations and virtual register counts.
|
||||
Inventory forwards that coverage to objects, reports and historical pages.
|
||||
The old register-only interpretation in inventory was removed.
|
||||
|
||||
A 67-case focused run passed across five files, including parser, public CLI/MCP,
|
||||
provider boundary and lifecycle tests. Three source admission cases also passed
|
||||
(one overlaps the focused run). NVIDIA `ptxas 12.9.86` accepted a pointer-parameter
|
||||
PTX control; the public CLI retained its unknown layout and reported partial
|
||||
coverage. A released nvJPEG example independently extracted by cuobjdump uses
|
||||
`.param .u64 .ptr .align 1`; this remains outside supported layout interpretation.
|
||||
|
||||
The revised Windows DLL report retains all 176 object factual fields, all 3,968
|
||||
kernel factual fields and all 10 exact PTX byte identities. Eight PTX objects and
|
||||
59 kernels now expose their pre-existing unknown parameter layouts with partial
|
||||
coverage and added limitations. The earlier complete payload-coverage claim for
|
||||
those PTX objects is superseded; decoded numerical facts are unchanged. Nine real
|
||||
producer artifacts still retain complete payload coverage.
|
||||
|
||||
The shared work owner now reserves uncompressed payload input once, and compressed
|
||||
input plus decoded output atomically, before reading/allocating. CCOB uses the
|
||||
same admission owner as payload analysis and AMD note reads. The allowance is
|
||||
512 MiB of that work, with 128 MiB per input/output buffer. Admitted failed work
|
||||
remains charged. A real sparse HIP file contains twelve aliases of one 128 MiB
|
||||
ELF payload: file-read instrumentation observed four full payload reads and eight
|
||||
capacity refusals with no payload read or decoded digest; the earlier four kernel
|
||||
facts survive. CUDA and CCOB oversized-output controls likewise prove refusal
|
||||
before the compressed input read. Old rejected-alias rereads are source-derived;
|
||||
they were not run to exhaustion.
|
||||
|
||||
The nine-producer pass took 1.148 seconds / 1.100 CPU seconds / 122,732,544 peak
|
||||
family RSS bytes. The pointer-PTX and released-DLL public CLI tasks together took
|
||||
10.102 seconds / 11.302 CPU seconds / 512,335,872 peak family RSS bytes. The focused
|
||||
run took 142.441 seconds / 211.528 CPU seconds / 3,478,200,320 peak family RSS bytes,
|
||||
including the required artifact build. No resource guard stopped these tasks.
|
||||
The earlier MCP cost pairs remain pinned to their measured revisions; no new
|
||||
speedup is inferred from this follow-up.
|
||||
|
||||
Three verifier attempts are retained as unsuccessful in the JSON record: an
|
||||
incorrect bare-record assumption for the Evidence bundle, refusal to overwrite
|
||||
an existing export, and a stale expectation that the now-corrected PTX coverage
|
||||
would stay complete. The successful comparison requires all factual values and
|
||||
PTX bytes to match while checking the intended uncertainty changes explicitly.
|
||||
|
||||
`npm run check` passed at this source revision, including type/lint/format, module
|
||||
boundaries and architecture guards: 135.345 seconds / 266.563 CPU seconds /
|
||||
5,371,879,424 sampled peak family RSS bytes; no resource guard stop.
|
||||
|
||||
`npm run docs:check` also passed, including all five README conformance cases.
|
||||
+115
-32
@@ -120,6 +120,8 @@ HTTP fields and ordered duplicate headers are retained, with stored body bytes
|
||||
in binary sidecars. Bodies are not dechunked or decompressed. Metadata is an
|
||||
XML node tree; optional `_w.txt` and `_g.txt` files retain opaque WebSocket and
|
||||
gRPC message bytes. Missing members remain null, distinct from empty bodies.
|
||||
A zero-byte `_c.txt` or `_s.txt` member, which Fiddler writes for a session
|
||||
without that message, is also null and adds a record limitation.
|
||||
See Telerik's [SAZ format reference](https://www.telerik.com/fiddler/fiddler-everywhere/documentation/knowledge-base/fiddler-archives).
|
||||
|
||||
## Protobuf and gRPC bodies
|
||||
@@ -178,6 +180,9 @@ sanitized source even with explicit sensitivity options. If that source pass
|
||||
is interrupted, unchecked bodies are not published as partial Evidence.
|
||||
Framing overrides apply only to format-owned body coordinates and preserve
|
||||
exclusions for the transport declared in MIME metadata.
|
||||
Explicitly excluded or conflicting MIME metadata is not treated as absent:
|
||||
automatic framing leaves such a non-empty body uninterpreted, adds a record
|
||||
limitation and keeps `protobuf_coverage` partial unless `framing` is selected.
|
||||
Unknown or explicitly excluded HTTP coding metadata is not treated as absent:
|
||||
SAZ/native bodies remain opaque until identity coding is established. Raw
|
||||
header values and retained body bytes remain available in source Evidence.
|
||||
@@ -449,12 +454,13 @@ template and `params` carry the four format rules with names `id`, `uuid`,
|
||||
only when listed, each at most once (a repeated rule is an `invalid_request`),
|
||||
in this order:
|
||||
|
||||
| Rule | Applies to | Parameter |
|
||||
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------- |
|
||||
| `after-uid-literal` | The literal segment right after a literal `uid`, unless it is a stop word | `uid` |
|
||||
| `opaque-token` | A lowercase alphanumeric segment of twelve or more characters mixing letters and digits that is not a `v1`-style version | `uid` |
|
||||
| `sibling-pair-variance` | Groups equal in method, origin and segment count that differ in two adjacent literals right after a plural literal at index 2 or later and followed by a literal, with at least three distinct pairs and both positions varying (`/repos/{owner}/{repo}/issues`); stop words and `v1`-style versions never qualify | singular plural literal plus `_namespace`, then `_name` |
|
||||
| `sibling-variance` | Groups equal in method, origin and segment count that differ in one literal at index 2 or later; the siblings whose literal is identifier-like (a digit or `:`, or three or more hyphenated names under a plural literal) merge, never a stop word, and the other literals stay their own tools | singular previous literal plus `_id`, else `id` |
|
||||
| Rule | Applies to | Parameter |
|
||||
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
||||
| `after-uid-literal` | The literal segment right after a literal `uid`, unless it is a stop word | `uid` |
|
||||
| `opaque-token` | A lowercase alphanumeric segment of twelve or more characters mixing letters and digits that is not a `v1`-style version | `uid` |
|
||||
| `sibling-pair-variance` | Groups equal in method, origin and segment count that differ in two adjacent literals right after a plural literal at index 2 or later and followed by a literal, with at least three distinct pairs and both positions varying (`/repos/{owner}/{repo}/issues`); stop words and `v1`-style versions never qualify | singular plural literal plus `_namespace`, then `_name` |
|
||||
| `sibling-variance` | Groups equal in method, origin and segment count that differ in one literal at index 2 or later; the siblings whose literal is identifier-like (a digit or `:`, or three or more hyphenated names under a plural literal) merge, never a stop word, and the other literals stay their own tools | singular previous literal plus `_id`, else `id` |
|
||||
| `prefix-variance` | A literal at a position that another tool, of any method or segment count, templates by one of the rules above after the same preceding segments, when the literal is one of that parameter's observed values, carries a digit and has the length and character classes (digits, lower case, upper case, each other character) of one, or has the single length of eight or more characters every observed value has and only their character classes; stop words and `v1`-style versions never qualify, and tools that now match merge | the name of the parameter it shares |
|
||||
|
||||
With `sibling-variance` selected, literal siblings within its comparison scope
|
||||
fold into existing opt-in parameters as observed values unless they are stop words.
|
||||
@@ -471,7 +477,17 @@ cut to their first label, `_by_<params>` appended when parameters exist,
|
||||
sanitized to `[a-z0-9_]`, at most 60 characters and made unique with numeric
|
||||
suffixes: `get_dashboards_by_uid`, `get_plugins_settings_by_plugin_id`.
|
||||
|
||||
`sibling-variance` and `sibling-pair-variance` compare routes of at most 32 segments; longer routes keep
|
||||
`prefix-variance` runs last so it can share the parameters the other rules
|
||||
produce: with `sibling-variance`, a `PATCH` or `DELETE` of the one entity a
|
||||
session edited, `/api/v1/collections/0RZ576QZQA5KG`, becomes
|
||||
`/api/v1/collections/{collection_id}` beside the reads that varied there, and
|
||||
so do deeper routes such as `/api/v1/collections/{collection_id}/books`. Its
|
||||
parameter is labelled `prefix-variance`, unless a merged tool templated the
|
||||
position by its own rule. When parameters of different rules share a position,
|
||||
a literal shares the one that observed it, else the earliest one it is spelled
|
||||
like.
|
||||
|
||||
`sibling-variance`, `sibling-pair-variance` and `prefix-variance` compare routes of at most 32 segments; longer routes keep
|
||||
their grouped templates and the manifest says so in a limitation. `body_shape`
|
||||
is derived for `POST`, `PUT` and `PATCH` from the tool's earliest record when it
|
||||
carries an `application/json` or `application/*+json` request body: top-level
|
||||
@@ -506,9 +522,9 @@ Pass the same parent to `inspect_analysis_view` with
|
||||
`view: {"kind":"environment-state"}` to extract the initial state the
|
||||
capture's reads observed, and a render plan per read tool that reproduces those
|
||||
reads from it. Where the environment manifest names an application's tools, the
|
||||
state holds its data: entities by type and identity, plus documents for written
|
||||
paths whose reads are not entities. Use the `template_rules` of the manifest the
|
||||
state accompanies so tool names match; the view groups records the same way.
|
||||
state holds its data: entities by type and identity, plus documents for reads
|
||||
that are not entities. Use the `template_rules` of the manifest the state
|
||||
accompanies so tool names match; the view groups records the same way.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -544,13 +560,27 @@ refused for them, as the manifest is not.
|
||||
|
||||
Each `GET` tool whose template ends in a parameter is an item tool, and its
|
||||
type's `collection_template` is the template without that parameter; any other
|
||||
`GET` tool is a list tool of its own template. An item tool proves its type's
|
||||
`GET` tool is a list tool of its own template. Empty segments are ignored, so a
|
||||
trailing slash names the same collection. An item tool proves its type's
|
||||
`id_field` when every initial response carries the requested path value in the
|
||||
same field, at the root or in one wrapper member (`id_basis: "path-parameter"`).
|
||||
Otherwise the field is the first of `id`, `uid`, `uuid`, `_id`, `ID`, `UID`,
|
||||
`Id`, `guid`, `key`, `slug` and `name` that every listed item carries as a
|
||||
distinct string or number (`id_basis: "field-name"`). A list is the response
|
||||
array, or the one array of objects in an envelope that is not itself an entity.
|
||||
same field of one entity object (`id_basis: "path-parameter"`). The object is
|
||||
the response itself or one wrapper member; failing both, it is the only element
|
||||
of a one-element array at the root (pointer `/0`) or in one member
|
||||
(`/<member>/0`), as in `{"posts":[{...}]}` or `{"data":[{...}]}`, provided one
|
||||
of the identity names below repeats the value, since a filtered list may also
|
||||
answer with one element that repeats its parent's value. Otherwise the field is
|
||||
the first of `id`, `uid`, `uuid`, `_id`, `ID`, `UID`, `Id`, `guid`, `key`,
|
||||
`slug` and `name` that every listed item carries as a distinct string or
|
||||
number; when none does, it is the first key of the first listed item, in its
|
||||
order, whose name ends in `Id` or `_id` (such as `orgId` or `user_id`), that
|
||||
every item carries as a distinct string or number, and that at least one
|
||||
initial response shows distinct across two or more items
|
||||
(`id_basis: "field-name"`). A single listed item is distinct from nothing, and
|
||||
its suffix-named fields are often foreign keys, so a list that only ever held
|
||||
one item is left to a document. Empty initial lists constrain no field. A list
|
||||
is the response array, or the one array of objects in an envelope that is not
|
||||
itself an entity, preferring an array whose items an identity name identifies,
|
||||
then an array of two or more items a suffix-named field identifies.
|
||||
|
||||
`entities` merge every initial observation of one identity within one
|
||||
collection path: an item view's latest values win over a list view's, a view
|
||||
@@ -565,12 +595,12 @@ Every entity cites its `record_ordinals`.
|
||||
|
||||
`views` lists one plan per read tool in tool order:
|
||||
|
||||
| Shape | Plan |
|
||||
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `item` | The entity object at `pointer` (the root or one member), the ordered `fields` the view shows and the `required_fields` every recording had, and `envelope_ordinal`: the recording whose response, with the entity replaced, every item response shares |
|
||||
| `list` | The array at `pointer`, its `fields`, `membership` (`all`: every entity of the collection in state order, when each recording listed exactly that, had no query, no item-total member (`total`, `count`, `totalCount`, `item_count`, `totalcount`, `itemcount`, but not `total_pages` or `per_page`; a number or a string of digits) differing from the number listed, and no `has_more`, `next` or next-page token member set; `recorded`: the entities each recording listed) and `counters` that equal the number listed |
|
||||
| `document` | The path's latest initial value, held in `documents` |
|
||||
| `recorded` | A `reason` the tool replays its recordings instead |
|
||||
| Shape | Plan |
|
||||
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `item` | The entity object at `pointer` (the root, one member, or `/0` or `/<member>/0`), the ordered `fields` the view shows and the `required_fields` every recording had, and `envelope_ordinal`: the recording whose response, with the entity replaced, every item response shares |
|
||||
| `list` | The array at `pointer`, its `fields`, `membership` (`all`: every entity of the collection in state order, when each recording listed exactly that, had no query or only paging parameters (`limit`, `offset`, `page`, `per_page`, `perpage`, `page_size`, `pagesize`, `size`, `start`, `_start`, `_end`), no item-total member (`total`, `count`, `totalCount`, `item_count`, `totalcount`, `itemcount`, but not `total_pages` or `per_page`; a number or a string of digits) differing from the number listed, and no `has_more`, `next` or next-page token member set; `recorded`: the entities each recording listed) and `counters` that equal the number listed |
|
||||
| `document` | The latest initial value of a list tool whose responses hold no identified list, when its initial reads share one request line; held in `documents` with that `path`, whether or not the capture writes it, unless its value changed across any recorded write between those reads (`fields-differ`) |
|
||||
| `recorded` | A `reason` the tool replays its recordings instead |
|
||||
|
||||
An item or list plan is kept only when it reproduces the latest initial
|
||||
recording of each request line from the state, comparing JSON values without
|
||||
@@ -578,35 +608,88 @@ regard to member order; a volatile field compares its recorded value. Each
|
||||
plan lists the `checked_record_ordinals`. Otherwise the tool is a recorded view
|
||||
with reason `envelope-varies`, `fields-differ` or `list-differs`; the other
|
||||
reasons are `query-body` (a query `POST`), `no-init-recording`,
|
||||
`body-unusable`, `not-entity`, `no-identity` and `query-varies` (a document
|
||||
read under several queries). Documents are held only for list-shaped paths
|
||||
that a `POST`, `PUT` or `PATCH` tool writes: a non-entity read of an item path
|
||||
such as `/api/files/{id}`, or of a path that is only deleted, stays recorded
|
||||
with `no-identity` or `not-entity`. A body is usable when its content type is
|
||||
`body-unusable`, `no-identity` (an item read without a proved identity),
|
||||
`path-varies` (another read under more than one path, as a template with a
|
||||
parameter before its end), `query-varies` (another read of one path under
|
||||
more than one query) and `rendered-oversize` (a document value whose JSON
|
||||
renders to more than 256 KiB). A document holds the value of its one `path`, so for such
|
||||
a template it says nothing about the template's other paths. A body is usable
|
||||
when its content type is
|
||||
JSON-like, it is UTF-8 text of at most 256 KiB, every number survives native
|
||||
conversion exactly, and no member is named `__proto__`.
|
||||
|
||||
`writes` lists one plan per tool whose request may change state, in tool
|
||||
order. Its `effect` is `create` for a `POST` to a type's
|
||||
`collection_template`, `update` for a `PUT`, `PATCH` or `POST` to that template
|
||||
plus one trailing parameter, `delete` for a `DELETE` to it, `document` for a
|
||||
`PUT`, `PATCH` or `POST` to a document's path, and otherwise `none` with reason
|
||||
`no-state-target`. A plan is built from the tool's first successful call: its
|
||||
request body must be a usable JSON object (as response bodies are usable), and
|
||||
the written entity must show in that call's response or in a later read before
|
||||
the next write. Each field of a created entity gets the first rule that
|
||||
explains it: generated `identity` (a sequence, UUID or token, by the recorded
|
||||
value's shape), `echo` of a body member, `copy` of a body string of 8 or more
|
||||
characters, a `path` value, a `slug` of a body member, a `clock` value within 10
|
||||
minutes of the request in its recorded format, a `sequence` one past the
|
||||
largest value of its collection or type, a `unique` UUID, or a `template` around
|
||||
a generated value; other fields keep the observed value. An update's members
|
||||
echo when stored as sent; a member stored differently is accepted only with its
|
||||
recorded value (`body.fixed`) and stores the value the call that showed it
|
||||
recorded (the `value` of its `constant` rule), and a field it changed without
|
||||
sending must be a clock, an increment or a slug, or the plan is
|
||||
`unexplained-change`; an increment or slug must hold for every call of the
|
||||
tool. Every member the first call sent is required, except by `PATCH` and
|
||||
`POST` updates.
|
||||
|
||||
The view then replays the timeline on a copy of the initial state. Modelled
|
||||
writes apply their effect; only a `2xx` write is modelled or an example, and
|
||||
any other write (a redirect, an unanswered or unmodelled one) leaves the entity
|
||||
below whose item path it wrote unknown until a read shows it again (a whole
|
||||
collection when the path names no held entity), and taints what it wrote at or
|
||||
above. A read the served environment would answer from the state is compared
|
||||
with its recording as the read plans are, as the whole response it would serve:
|
||||
the entity or list rendered into the envelope of the item view's or the line's
|
||||
base recording, with the members the state still holds. A 400, 404 or 410 (or a
|
||||
`null` body) agrees with an entity the copy does not hold. A match confirms
|
||||
the writes that changed its entity or collection since it was last read; a
|
||||
mismatch contradicts them, or, when an unmodelled write came after them, is
|
||||
checked only on the members they sent; a mismatch no write explains marks the related writes since as
|
||||
`side-effect`. A plan is `served` when a read confirmed it and none
|
||||
contradicted it; otherwise its `reason` is the first of its build reason
|
||||
(`no-call`, `body-unusable`, `no-observation`, `unexplained-change`),
|
||||
`contradicted` (with `contradicted_by`), `side-effect`, `unconfirmed` and `incomplete-entities` (an update or delete that answers with the entity, when no initial entity holds every field its recorded answer shows, counting for an update the fields its rules write, so it could answer only for entities the environment created).
|
||||
`checked_record_ordinals` lists the confirming reads, `insert` places created
|
||||
entities (sorted by a field the collection's recorded order shows, else last),
|
||||
and `write_clock` is the end of the last timed record, to the next second.
|
||||
|
||||
Values in the state are recorded data, so the view refuses the same parents as
|
||||
the manifest, including those inspected with `sensitive_values`, and a
|
||||
`capture_browser_scenario` parent must have selected response bodies. Types and
|
||||
identity are inferences, so the Evidence is always inferred. `unknowns` states
|
||||
that the state establishes no authorization model, no way the application
|
||||
computes responses or derived values, and no effects of writes. The state
|
||||
computes responses or derived values, and write effects only as modelled from
|
||||
recorded calls. The state
|
||||
accumulator charges the manifest's admission and grouping, every record line,
|
||||
each body as temporary bytes before it is decoded and parsed, and every value
|
||||
it keeps, within the same 96 MiB budget. The view performs no network activity
|
||||
and serves nothing.
|
||||
it keeps, within the same 96 MiB budget. Documents hold whole recorded response
|
||||
values whose recorded text and rendered JSON are each at most 256 KiB, so a
|
||||
capture with many read-only paths yields a correspondingly larger state result.
|
||||
The view performs no network activity and serves nothing; `rea environment-serve`
|
||||
derives it from the capture at startup, serves read tools and the served write
|
||||
plans from it and loads replacement states through the AgentEnv data plane, as
|
||||
[serve from the state](agent-environments.md#serve-from-the-state) describes.
|
||||
|
||||
## Resource and lifecycle boundaries
|
||||
|
||||
Complete evidence has a 32 MiB input, 96 MiB decoder reply and 64-level nesting
|
||||
budget. Exceeding a budget returns no partial success.
|
||||
budget. Those budgets have no runtime override. `capture_timeout_ms` does not
|
||||
raise them. Exceeding a budget returns no partial success.
|
||||
Oversized selected captures return an input error identifying `capture_path`
|
||||
and the byte budget; owned reply/output failures remain output or provider errors.
|
||||
HAR, SAZ and qlog run in an owned
|
||||
192 MiB Node old-generation heap with one V8 worker. Mitmproxy decoding applies
|
||||
Linux limits of 768 MiB address space, 30 seconds CPU and 96 MiB file output;
|
||||
both commands have a 30-second wall deadline and independently supervised
|
||||
both commands use `capture_timeout_ms` (default 30000) and independently supervised
|
||||
process cleanup. Owned decoder diagnostics retain at most 1 MiB across stdout
|
||||
and stderr; the collector drops overflow as it arrives, reports the limit
|
||||
failure and verifies cleanup. Heap limits alone do not establish aggregate RSS limits.
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ The result contains directly registered listener types/flags, callback coordinat
|
||||
|
||||
## Bounds and verification
|
||||
|
||||
Each protocol message has a 64 MiB budget; script/context metadata and request metadata each have an 8 MiB retained budget. Complete retained source text has a 32 MiB budget. Oversized or malformed evidence returns no partial successful result. Each command and the complete inspection/source-join phase have a 20-second deadline; cleanup has a separate 5-second command deadline plus transport closure. The selected observation duration must fit the host timer's positive 32-bit millisecond range. REA does not control the externally owned browser's CPU or memory.
|
||||
Each protocol message has a 64 MiB budget; script/context metadata and request metadata each have an 8 MiB retained budget. Complete retained source text has a 32 MiB budget. Oversized or malformed evidence returns no partial successful result. Each command and the complete inspection/source-join phase use `command_timeout_ms` (default 20000). Cleanup uses a separate 5000 ms grace; `command_timeout_ms` does not raise or shorten it, and this release has no runtime override for that grace. Transport closure follows the grace. The selected observation duration must fit the host timer's positive 32-bit millisecond range. REA does not control the externally owned browser's CPU or memory.
|
||||
|
||||
`npm run verify:browser:runtime` uses caller-supplied `REA_BROWSER_EXECUTABLE` and the native `ps` command on Linux/macOS against an owned synthetic fixture, through real public CLI and stdio MCP. It checks exact Unicode/CRLF text/digests, same-URL identities, same-document navigation, inert declared names, executed and zero-count branches, function-only unknowns on repeated observation, listener selection, initiator association, actual arming and preservation of the external page. A separate fixture page closes during an armed MCP window to verify prompt termination and inline cleanup diagnostics. The optional positional entrypoint to `scripts/verify-browser-runtime.mjs` permits the same checks against an isolated installed tarball.
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ implement every current source-map extension.
|
||||
One owned Node subprocess decodes the map. Its private request directory is
|
||||
removed before success is returned. Only this child's inherited `NODE_OPTIONS`
|
||||
is removed; explicit V8 flags set a 192 MiB old-generation and 8 MiB semi-space
|
||||
budget, one V8 worker and a 20-second deadline. Reported actual V8 heap limits
|
||||
budget, one V8 worker and `decode_timeout_ms` (default 20000). The codec heap, map budget, and reply budget have no runtime override. Reported actual V8 heap limits
|
||||
are checked. These are heap limits, not an aggregate process RSS limit. When
|
||||
REA runs on Bun, the subprocess is Bun, which ignores these V8 flags: `runtime`
|
||||
records `id: "bun"`, the Bun version, its Node.js compatibility version and a
|
||||
@@ -86,7 +86,8 @@ cleanup overrides success with `cleanup_incomplete` and the owning
|
||||
operation/resources.
|
||||
|
||||
Complete evidence is bounded by a 4 MiB map, 32 MiB codec reply, 262144 decoded
|
||||
rows/segments and 64 nested section levels. Exceeding a budget returns an explicit
|
||||
rows/segments and 64 nested section levels. Those structural budgets and the
|
||||
192 MiB codec heap have no runtime override. Exceeding a budget returns an explicit
|
||||
failure, without partial results. The existing 32 MiB manifest and 16 MiB selected
|
||||
script boundaries also apply. No global toolchain or browser configuration changes
|
||||
are made.
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
"""Read archived AppKit connector UIDs independently with Python's plistlib."""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import plistlib
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--bundle', type=Path, required=True)
|
||||
parser.add_argument('--document', required=True)
|
||||
parser.add_argument('--baseline', type=Path, required=True,
|
||||
help='Complete pre-change 64-document Evidence; equality control, not the oracle')
|
||||
parser.add_argument('--small-baseline', type=Path, required=True,
|
||||
help='Complete pre-change 1-document Evidence')
|
||||
parser.add_argument('--output', type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
data = (args.bundle / args.document).read_bytes()
|
||||
objects = plistlib.loads(data)['$objects']
|
||||
connections = []
|
||||
for index, value in enumerate(objects):
|
||||
if not isinstance(value, dict) or not {'NSSource', 'NSLabel'} <= value.keys():
|
||||
continue
|
||||
classname = objects[value['$class'].data]['$classname']
|
||||
if classname not in ('NSNibOutletConnector', 'NSNibControlConnector'):
|
||||
continue
|
||||
connections.append({
|
||||
'archive_index': index,
|
||||
'kind': 'outlet' if classname == 'NSNibOutletConnector' else 'action',
|
||||
'name': objects[value['NSLabel'].data],
|
||||
'source': str(value['NSSource'].data),
|
||||
'destination': str(value['NSDestination'].data),
|
||||
})
|
||||
if not connections:
|
||||
raise ValueError('No supported archived connectors; choose a keyed AppKit document')
|
||||
args.output.write_text(json.dumps({
|
||||
'document': args.document,
|
||||
'archive_sha256': hashlib.sha256(data).hexdigest(),
|
||||
'connections': connections,
|
||||
'complete_result_paths': {
|
||||
'1': str(args.small_baseline.resolve()),
|
||||
'64': str(args.baseline.resolve()),
|
||||
},
|
||||
}, indent=2) + '\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,225 @@
|
||||
# Retained Interface Builder graph validation
|
||||
|
||||
Issue #5855. Baseline `f801b2fbfd28f4e3713adefddc7bd73db44c284c`, Linux
|
||||
x86_64 / AMD EPYC 7B12 / Node 24.18.0 / npm 11.16.0. This is static archive
|
||||
analysis on Linux, without executing an app or using ibtool or a native
|
||||
analysis provider.
|
||||
|
||||
## Question and oracle
|
||||
|
||||
Identify the AAC settings outlets and VBR action in the official
|
||||
[XLD 20250302 app](https://tmkk.undo.jp/xld/index_e.html), including archive
|
||||
source/destination object identities, connection evidence and limitations.
|
||||
|
||||
- [Official DMG](https://tmkk.undo.jp/xld/xld-20250302.dmg) SHA-256:
|
||||
`0032a5470ea4e32a11a35b8077ebf4986102891f8eb82743094f2c6621ad8aeb`.
|
||||
- Selected document:
|
||||
`Contents/PlugIns/XLDAacOutput.bundle/Contents/Resources/English.lproj/XLDAacOutput.nib`.
|
||||
- Archive SHA-256:
|
||||
`4fdbfba451ee64b1d333c96a4f3d1a0c4b543a36b9b3686e1151b51e4dd14c72`.
|
||||
- Python's independent `plistlib` reads the actual `$objects` table and
|
||||
`NSNibOutletConnector` / `NSNibControlConnector` records. Observed connections:
|
||||
|
||||
| Kind | Label | Source UID | Destination UID |
|
||||
| ------ | ------------- | ---------- | --------------- |
|
||||
| outlet | o_bitrate | 2 | 10 |
|
||||
| outlet | o_gaplessFlag | 2 | 41 |
|
||||
| outlet | o_prefPane | 2 | 53 |
|
||||
| outlet | o_quality | 2 | 62 |
|
||||
| outlet | o_useVBR | 2 | 58 |
|
||||
| action | vbrChecked: | 58 | 2 |
|
||||
|
||||
The benchmark checks each connector, both endpoint records, relationship kinds,
|
||||
archive path/digest and page coverage against these independent facts. It also
|
||||
compares all returned document rows with the exported complete parent; all
|
||||
64-document normalized results match the pre-change complete CLI Evidence.
|
||||
The complete exported parent Evidence is equal across versions for both
|
||||
admission sizes. The reproduction oracle requires a separate pre-change
|
||||
complete Evidence file for each size, and the harness compares the entire
|
||||
parent, including its identity and parameters, for the selected limit. Equality is a preservation control, not an independent proof
|
||||
of every decoded fact.
|
||||
|
||||
The default 64-document report contains 6,528 nodes and 1,378 edges. The small
|
||||
control admits one document from the same unmodified real app, with 80 nodes
|
||||
and 13 edges. Both reports retain truncation and hierarchy limitations. Resource
|
||||
sessions have no executable subject or executable digest; archive identities
|
||||
must not be promoted to executable identity.
|
||||
|
||||
## Completed workflow and accounting
|
||||
|
||||
`interface-builder-views.mjs` uses the real SDK and compiled stdio MCP server:
|
||||
connect, discover the full catalog, open bundle resources, decode with summary
|
||||
delivery, exhaust three 32-row node pages and one edge page for the selected
|
||||
document, repeat those same four pages as a warm query diagnostic, export the
|
||||
complete Evidence, verify the answer and complete parent, and await cleanup.
|
||||
The repeat is included in all whole-task costs. Each run starts a fresh server
|
||||
and isolated account. Decoding is the first decode in that server; retained
|
||||
queries follow the summary's first validation. OS caches were not flushed, so
|
||||
these are not disk-cold measurements.
|
||||
|
||||
Artifact acquisition/extraction, build time and independent oracle preparation
|
||||
are outside this analysis task. No actual model session or billed model token
|
||||
usage was measured. The SDK benchmark answers a fixed factual question; it does
|
||||
not establish agent usability or general provider performance.
|
||||
|
||||
Experiments ran serially using `resource-run.py --observe-payload-exit`: one CPU
|
||||
(affinity 15), 100% quota, 4 GiB hard memory / 3 GiB early stop, no swap and a
|
||||
192-task ceiling. CPU and peak memory cover the SDK, server and observer family.
|
||||
Peak is cgroup memory.peak, including charged page cache, rather than summed RSS.
|
||||
Payload-exit cgroup counters are authenticated and cleanup is verified; final
|
||||
whole-scope counters are unavailable after the transient scope disappears.
|
||||
Every accepted and failed task has exit/cleanup verification and zero observed
|
||||
memory high/max/OOM/OOM-kill and PID-limit events. Missing final counters are
|
||||
not interpreted as zero.
|
||||
|
||||
## Observations
|
||||
|
||||
Medians across all accepted baseline runs and the measured optimized
|
||||
production-source cohort. The later harness-only review fix does not change
|
||||
those production files; its revalidation is recorded separately. Five
|
||||
earlier candidate runs remain labeled pre-review diagnostics and are excluded
|
||||
from the final-source medians. One failed initial harness run is also retained.
|
||||
All individual runs, phase timings, token estimates and raw receipt hashes are
|
||||
in `interface-builder-views.json`.
|
||||
|
||||
| Admitted documents | Revision | Runs | Whole wall s | Family CPU s | Family peak MiB | First four pages ms | Repeated four pages ms |
|
||||
| ------------------ | -------- | ---- | ------------ | ------------ | --------------- | ------------------- | ---------------------- |
|
||||
| 64 | baseline | 5 | 30.798 | 30.532 | 1614.7 | 2606.3 | 1817.8 |
|
||||
| 64 | final | 5 | 27.683 | 27.424 | 1551.1 | 338.8 | 94.3 |
|
||||
| 1 | baseline | 4 | 15.702 | 15.456 | 952.6 | 389.5 | 101.0 |
|
||||
| 1 | final | 4 | 18.101 | 17.822 | 944.8 | 367.5 | 101.7 |
|
||||
|
||||
The larger sampled task has about 10% lower whole wall/CPU medians and 94.8%
|
||||
lower repeated-page latency. Whole-task ranges overlap substantially:
|
||||
27.420–51.481 s baseline and 25.247–45.451 s final. Startup/initial decoding
|
||||
vary independently of the retained-query change; these observations do not
|
||||
establish a general whole-task speedup or stable memory reduction. Both
|
||||
versions' slow first runs remain included.
|
||||
|
||||
The small sampled task is slower overall (15.3% wall), with no repeat-page
|
||||
benefit. In the two later interleaved small pairs, baseline took 16.883/18.317 s
|
||||
and final took 16.988/20.276 s. Do not interpret the earlier unpaired small
|
||||
measurements as evidence of a cold-start improvement. Startup variance remains
|
||||
unexplained; this optimization is justified by repeated large-parent queries,
|
||||
not a claim that every completed task becomes faster.
|
||||
|
||||
An additional production-boundary diagnostic isolates the changed projection
|
||||
from startup, decoding and transport. It imports both compiled owners, seals
|
||||
separate clones of the actual exported parent with each owner's snapshot
|
||||
module, and alternates version order for three epochs. Each epoch projects a
|
||||
summary and the same eight pages; every resulting payload is equal. Median
|
||||
projection CPU falls from 157.4 to 30.3 ms for the one-document parent and
|
||||
6003.5 to 914.7 ms for the 64-document parent. Snapshot preparation, Evidence
|
||||
authentication and all adapters are excluded from this diagnostic; the public
|
||||
tasks above account for their whole costs. First large-summary CPU rises from
|
||||
620.2 to 879.8 ms because representation comparison is paid up front. This is a
|
||||
reuse tradeoff, not a faster first decode. The diagnostic source/receipt hashes,
|
||||
per-call wall/CPU times and bounded process-family counters are retained in the
|
||||
JSON; it does not replace real public workflow evidence.
|
||||
|
||||
Selection still scans retained rows to count every match; no additional
|
||||
per-document index is retained. The whole original graph and serialization
|
||||
costs still exist.
|
||||
|
||||
Public input/output contracts and complete parent Evidence are unchanged.
|
||||
Tokenizer estimates count the entire 212-tool input catalog once, every RPC's
|
||||
arguments and text response, including warm diagnostics and export. The raw SDK
|
||||
catalog, including output schemas, is reported separately. Structured content
|
||||
and model-specific discovery/exposure may incur different costs. The 64-document task estimates are 282,885 baseline and 282,887 for the
|
||||
initial candidate (198,492 input-catalog tokens in each); the two-token change
|
||||
comes solely from the export destination. The first ten RPC requests and
|
||||
replies are exactly equal. Raw SDK catalog exposure estimates 891,652 tokens
|
||||
including output schemas. Final-source values and every run are retained in
|
||||
the JSON. There is no claimed token reduction.
|
||||
|
||||
## Ownership and reuse
|
||||
|
||||
The Interface Builder view owner validates an unknown normalized result with
|
||||
its existing schema. Reuse requires the application's seal plus exact owned
|
||||
immutable snapshot identity and representation-preserving comparison against
|
||||
the parsed result. A weak set records only successful snapshots. It retains no
|
||||
second graph, file-path cache, index, transient errors or failed subject
|
||||
bindings. Every view still checks its current parent's target binding and
|
||||
constructs current parent provenance and limitations. Different results,
|
||||
mutable imports, forged seals and schema normalization revalidate normally.
|
||||
|
||||
Document selection uses the shared matching pager to count all matching rows
|
||||
while retaining only the requested page. Unfiltered requests keep direct
|
||||
slicing. Row IDs, ordering, provenance, decoder truncation and unknowns remain
|
||||
unchanged. CLI and MCP share the same application/domain implementation.
|
||||
|
||||
The snapshot comparison helper's type accepts owning schemas with optional
|
||||
undefined members; its runtime comparison is unchanged and refuses a parsed
|
||||
representation that actually adds an undefined field.
|
||||
|
||||
## Reproduction and limits
|
||||
|
||||
Extract the official app without running it. On the baseline, save complete
|
||||
CLI JSON with `rea decode-interface-builder <XLD.app> --format json` and a
|
||||
separate control with `rea decode-interface-builder <XLD.app> --max-documents 1
|
||||
--format json` (without profiler logging mixed into either JSON). Then:
|
||||
|
||||
```sh
|
||||
python3 experiments/analysis-efficiency/interface-builder-oracle.py \
|
||||
--bundle '<XLD.app>' \
|
||||
--document 'Contents/PlugIns/XLDAacOutput.bundle/Contents/Resources/English.lproj/XLDAacOutput.nib' \
|
||||
--baseline '<complete-64-document-evidence.json>' \
|
||||
--small-baseline '<complete-1-document-evidence.json>' --output '<oracle.json>'
|
||||
python3 experiments/analysis-efficiency/resource-run.py --observe-payload-exit -- \
|
||||
node experiments/analysis-efficiency/interface-builder-views.mjs \
|
||||
--runtime '<absolute baseline or candidate checkout>' --input '<XLD.app>' \
|
||||
--oracle '<oracle.json>' --output '<new output directory>' --documents 64
|
||||
```
|
||||
|
||||
Repeat with `--documents 1`. Paths must be absolute. The oracle uses standard
|
||||
Python only; token estimates use offline tiktoken 0.12.0 / cl100k_base. Count
|
||||
compact JSON tool name/description/inputSchema entries once, compact
|
||||
`{name,arguments}` for every transcript event, and every returned text block;
|
||||
these are estimates, not actual model usage.
|
||||
|
||||
Failed attempts remain visible. `base64-a` completed all eight page RPCs but the
|
||||
first harness incorrectly expected an action-source `contains` edge. Production
|
||||
correctly returned `target_action`; the harness was corrected before accepted
|
||||
runs. That failure's costs/receipt remain in the JSON. An initial typecheck
|
||||
refused the snapshot helper's unnecessarily narrow generic constraint for the
|
||||
optional resource root; the constraint was corrected without changing runtime
|
||||
comparison. Build resource observations with a still-exiting Turbo child are
|
||||
not qualified task measurements.
|
||||
|
||||
KeepingYouAwake 1.6.8 (official ZIP SHA-256
|
||||
`8001a149b4490c008fdac19898bce9902d516c4aa6412a7eb0f9a37443b15c6b`)
|
||||
was also downloaded and smoke-decoded through the real CLI
|
||||
(17 documents, 1,369 nodes, 542 edges), but its NIBArchive records cannot be read
|
||||
by this plistlib oracle. It is not a comparative benchmark or independent NIB
|
||||
correctness claim. macOS ibtool, runtime UI, other archive variants, globally
|
||||
complete hierarchy/class interpretation, #5720/#5721 and the remaining source
|
||||
decoder issues are unverified or unchanged here.
|
||||
|
||||
## Integration verification
|
||||
|
||||
The measured comparison above was pinned to `f801b2fbf`. The branch was then
|
||||
rebased onto `f5410bdc4` (the separate #5806 scalar-record fix). All six recorded owned-source
|
||||
fingerprints remained identical across that rebase. On the rebased runtime both real SDK
|
||||
tasks passed again, with the complete retained parent equal to the original
|
||||
baseline for both admission sizes. The complete real CLI Evidence and portable
|
||||
CLI page also equal the baseline/MCP results. These integration runs are recorded
|
||||
separately in the JSON and excluded from the pinned comparison medians.
|
||||
|
||||
The relevant 12-file suite passed 204 tests after the paging refactor. After
|
||||
rebasing, another six-file run passed 78 tests covering scalar source facts,
|
||||
keyed archive number metadata, Interface Builder views, production MCP summary
|
||||
paging and compiled CLI numeric/hierarchy boundaries. Both cohorts verified
|
||||
owned cleanup with no observed memory/PID limit events; tests used the bounded
|
||||
two-CPU, 4 GiB guard. Native ibtool/macOS runtime behavior is not established by
|
||||
these tests.
|
||||
|
||||
Greptile identified that the original script only enforced the pre-change
|
||||
comparison for 64 documents; the one-document equality above had been checked
|
||||
manually. The oracle now requires both baseline files and the harness compares
|
||||
the selected complete parent, including its Evidence ID and parameters, for
|
||||
either limit. Both real workflows passed again. An intentional wrong baseline
|
||||
(the 64-document parent supplied for the 1-document task) is rejected after all
|
||||
other real-task checks succeed, with cleanup verified. These review checks and
|
||||
updated harness fingerprints are recorded separately. Production source and
|
||||
original comparison medians are unchanged; original measured fingerprints are
|
||||
preserved rather than relabeled as the new harness.
|
||||
@@ -0,0 +1,238 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { createHash } from "node:crypto";
|
||||
import { createWriteStream } from "node:fs";
|
||||
import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
|
||||
import { createRequire } from "node:module";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
import { finished } from "node:stream/promises";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { parseArgs } from "node:util";
|
||||
import { createRetainedQueryCaller } from "./retained-query-calls.mjs";
|
||||
import { finalizeRetainedQueryReceipt } from "./retained-query-finalization.mjs";
|
||||
|
||||
const { values } = parseArgs({
|
||||
options: {
|
||||
runtime: { type: "string" },
|
||||
input: { type: "string" },
|
||||
oracle: { type: "string" },
|
||||
output: { type: "string" },
|
||||
documents: { type: "string", default: "64" },
|
||||
},
|
||||
});
|
||||
for (const key of ["runtime", "input", "oracle", "output"])
|
||||
assert.equal(values[key], resolve(values[key]));
|
||||
const maxDocuments = Number(values.documents);
|
||||
assert.ok([1, 64].includes(maxDocuments));
|
||||
const oracle = JSON.parse(await readFile(values.oracle, "utf8"));
|
||||
const baselinePath = oracle.complete_result_paths?.[String(maxDocuments)];
|
||||
assert.equal(
|
||||
typeof baselinePath,
|
||||
"string",
|
||||
"Provide a pre-change baseline for the selected document limit.",
|
||||
);
|
||||
assert.equal(baselinePath, resolve(baselinePath));
|
||||
const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
||||
assert.equal(
|
||||
sha256(await readFile(join(values.input, oracle.document))),
|
||||
oracle.archive_sha256,
|
||||
);
|
||||
const require = createRequire(join(values.runtime, "package.json"));
|
||||
const { Client } = await import(
|
||||
pathToFileURL(require.resolve("@modelcontextprotocol/client"))
|
||||
);
|
||||
const { StdioClientTransport } = await import(
|
||||
pathToFileURL(require.resolve("@modelcontextprotocol/client/stdio"))
|
||||
);
|
||||
await mkdir(values.output, { mode: 0o700 });
|
||||
const account = await mkdtemp(join(tmpdir(), "rea-interface-builder-views-"));
|
||||
const report = {
|
||||
question:
|
||||
"Identify archived AAC settings outlets and the VBR action with source/destination object identities, coverage and complete Evidence access.",
|
||||
max_documents: maxDocuments,
|
||||
calls: [],
|
||||
};
|
||||
const client = new Client({
|
||||
name: "rea-interface-builder-views",
|
||||
version: "1",
|
||||
});
|
||||
const transport = new StdioClientTransport({
|
||||
command: process.execPath,
|
||||
args: [join(values.runtime, "scripts/rea.mjs"), "mcp"],
|
||||
env: {
|
||||
HOME: account,
|
||||
PATH: process.env.PATH,
|
||||
NODE_OPTIONS: "--max-old-space-size=2048",
|
||||
UV_THREADPOOL_SIZE: "1",
|
||||
REA_LOG_LEVEL: "silent",
|
||||
},
|
||||
stderr: "pipe",
|
||||
});
|
||||
const serverLog = createWriteStream(join(values.output, "server.log"));
|
||||
const serverLogFinished = finished(serverLog);
|
||||
serverLogFinished.catch(() => {});
|
||||
transport.stderr?.pipe(serverLog);
|
||||
const transcript = [];
|
||||
const call = createRetainedQueryCaller(client, (receipt, event) => {
|
||||
report.calls.push(receipt);
|
||||
transcript.push(event);
|
||||
});
|
||||
async function result(name, input, phase = name) {
|
||||
const reply = await call(name, input, phase);
|
||||
assert.ok(!reply.isError, JSON.stringify(reply));
|
||||
assert.ok(reply.structuredContent);
|
||||
assert.equal(reply.content.length, 1);
|
||||
assert.equal(reply.content[0].type, "text");
|
||||
assert.deepEqual(JSON.parse(reply.content[0].text), reply.structuredContent);
|
||||
return reply.structuredContent;
|
||||
}
|
||||
try {
|
||||
await client.connect(transport);
|
||||
const catalog = await client.listTools();
|
||||
assert.equal(catalog.nextCursor, undefined);
|
||||
report.catalog_tools = catalog.tools.length;
|
||||
await writeFile(join(values.output, "catalog.json"), JSON.stringify(catalog));
|
||||
await result("open_bundle_resources", { path: values.input });
|
||||
const initial = await result("decode_interface_builder", {
|
||||
max_documents: maxDocuments,
|
||||
detail: "summary",
|
||||
});
|
||||
const summary = initial.normalized_result;
|
||||
report.parent_evidence_id = summary.parent_evidence_id;
|
||||
assert.equal(summary.resource_root.executable_sha256, null);
|
||||
assert.equal(summary.artifact.sha256, null);
|
||||
assert.equal(summary.summary.truncated, true);
|
||||
assert.ok(
|
||||
summary.summary.documents.some(
|
||||
(d) =>
|
||||
d.relative_path === oracle.document &&
|
||||
d.archive_sha256 === oracle.archive_sha256,
|
||||
),
|
||||
);
|
||||
const collections = {};
|
||||
for (const pass of ["first", "warm"]) {
|
||||
for (const collection of ["nodes", "edges"]) {
|
||||
const rows = [];
|
||||
let offset = 0;
|
||||
for (;;) {
|
||||
const selected = await result(
|
||||
"inspect_analysis_view",
|
||||
{
|
||||
source: {
|
||||
kind: "retained-evidence",
|
||||
evidence_id: report.parent_evidence_id,
|
||||
},
|
||||
view: {
|
||||
kind: "interface-builder",
|
||||
collection,
|
||||
document: oracle.document,
|
||||
offset,
|
||||
limit: 32,
|
||||
},
|
||||
},
|
||||
`retained:${pass}:${collection}:${offset}`,
|
||||
);
|
||||
const page = selected.normalized_result;
|
||||
assert.equal(page.parent_evidence_id, report.parent_evidence_id);
|
||||
assert.equal(page.source_truncated, true);
|
||||
assert.ok(page.unknowns.length > 0);
|
||||
rows.push(...page.items);
|
||||
if (page.coverage.exhausted) {
|
||||
assert.equal(rows.length, page.coverage.total);
|
||||
break;
|
||||
}
|
||||
assert.ok(page.items.length > 0);
|
||||
offset += page.items.length;
|
||||
}
|
||||
if (pass === "warm") assert.deepEqual(rows, collections[collection]);
|
||||
else collections[collection] = rows;
|
||||
}
|
||||
}
|
||||
const byId = new Map(collections.nodes.map((n) => [n.id, n]));
|
||||
for (const expected of oracle.connections) {
|
||||
const connector = collections.nodes.find(
|
||||
(n) => n.kind === expected.kind && n.name === expected.name,
|
||||
);
|
||||
assert.ok(connector);
|
||||
const sourceRelation =
|
||||
expected.kind === "outlet" ? "contains" : "target_action";
|
||||
const source = collections.edges.find(
|
||||
(e) => e.to === connector.id && e.relation === sourceRelation,
|
||||
);
|
||||
assert.equal(
|
||||
byId.get(source.from).attributes.interface_builder_object_id,
|
||||
expected.source,
|
||||
);
|
||||
const relation = expected.kind === "outlet" ? "outlet_to" : "target_action";
|
||||
const destination = collections.edges.find(
|
||||
(e) =>
|
||||
e.from === connector.id &&
|
||||
e.relation === relation &&
|
||||
byId.get(e.to)?.attributes.interface_builder_object_id ===
|
||||
expected.destination,
|
||||
);
|
||||
assert.equal(
|
||||
byId.get(destination.to).attributes.interface_builder_object_id,
|
||||
expected.destination,
|
||||
);
|
||||
for (const row of [connector, source, destination])
|
||||
assert.ok(
|
||||
row.evidence.some(
|
||||
(e) =>
|
||||
e.artifact_path === oracle.document &&
|
||||
e.artifact_sha256 === oracle.archive_sha256,
|
||||
),
|
||||
);
|
||||
}
|
||||
report.answer = oracle.connections;
|
||||
await result("export_evidence_bundle", {
|
||||
path: join(values.output, "evidence.json"),
|
||||
});
|
||||
const bundle = JSON.parse(
|
||||
await readFile(join(values.output, "evidence.json"), "utf8"),
|
||||
);
|
||||
const parent = bundle.records.find(
|
||||
(e) => e.evidence_id === report.parent_evidence_id,
|
||||
);
|
||||
assert.equal(parent.subject, null);
|
||||
assert.equal(parent.operation, "decode_interface_builder");
|
||||
const full = parent.normalized_result;
|
||||
for (const collection of ["nodes", "edges"])
|
||||
assert.deepEqual(
|
||||
collections[collection],
|
||||
full.graph[collection].filter((r) =>
|
||||
r.evidence.some((e) => e.artifact_path === oracle.document),
|
||||
),
|
||||
);
|
||||
const baselineBytes = await readFile(baselinePath, "utf8");
|
||||
const expectedParent = JSON.parse(baselineBytes);
|
||||
report.baseline_sha256 = sha256(baselineBytes);
|
||||
report.baseline_evidence_id = expectedParent.evidence_id;
|
||||
const mismatch = `Complete retained Evidence differs from the pre-change ${maxDocuments}-document baseline.`;
|
||||
assert.equal(parent.evidence_id, expectedParent.evidence_id, mismatch);
|
||||
assert.deepEqual(parent, expectedParent, mismatch);
|
||||
report.available_counts = {
|
||||
nodes: full.graph.nodes.length,
|
||||
edges: full.graph.edges.length,
|
||||
};
|
||||
report.oracle_sha256 = sha256(await readFile(values.oracle));
|
||||
report.status = "passed";
|
||||
} catch (cause) {
|
||||
report.status = "failed";
|
||||
report.failure = String(cause?.stack ?? cause);
|
||||
process.exitCode = 1;
|
||||
} finally {
|
||||
if (
|
||||
!(await finalizeRetainedQueryReceipt({
|
||||
report,
|
||||
client,
|
||||
transport,
|
||||
account,
|
||||
serverLog,
|
||||
serverLogFinished,
|
||||
output: values.output,
|
||||
transcript,
|
||||
}))
|
||||
)
|
||||
process.exitCode = 1;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
"""Summarize completed CLI trials; token counts are estimates, not model usage."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import statistics
|
||||
from pathlib import Path
|
||||
import tiktoken
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('root', type=Path)
|
||||
parser.add_argument('--output', type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
root = args.root
|
||||
inputs = json.loads((root / 'measurement-inputs.json').read_text())
|
||||
expected = inputs['expected_runtime_bindings']
|
||||
assert expected['complete']['git_revision'] == inputs['baseline_revision']
|
||||
assert expected['selected']['git_revision'] == inputs['feature_parent_revision']
|
||||
assert expected['complete']['root'] != expected['selected']['root']
|
||||
assert expected['complete']['compiled_cli_sha256'] != expected['selected']['compiled_cli_sha256']
|
||||
assert expected['complete']['source_diff_sha256'] == hashlib.sha256(b'').hexdigest()
|
||||
assert expected['complete']['untracked_source_sha256'] == hashlib.sha256(b'[]').hexdigest()
|
||||
enc = tiktoken.get_encoding('cl100k_base')
|
||||
count = lambda text: len(enc.encode(text, disallowed_special=()))
|
||||
compact = lambda obj: json.dumps(obj, ensure_ascii=False, separators=(',', ':'))
|
||||
runs = []
|
||||
for case in sorted(root.glob('pair-*')):
|
||||
if not case.is_dir():
|
||||
continue
|
||||
report = json.loads((case / 'report.json').read_text())
|
||||
assert report['status'] == 'passed' and report['cleanup_verified']
|
||||
assert report['runtime_binding_verified']
|
||||
assert report['runtime_binding'] == expected[report['mode']], case.name
|
||||
assert str(Path(report['runtime']).resolve()) == report['runtime_binding']['root']
|
||||
receipt = next(json.loads(line) for line in reversed(case.with_name(case.name + '.log').read_text().splitlines()) if line.startswith('{"resource_scope":'))
|
||||
obs = receipt['payload_resource_observation']
|
||||
assert receipt['abort'] is None and receipt['payload_resource_observation_verified']
|
||||
assert obs['payload_exit_code'] == 0 and obs['payload_cleanup_verified']
|
||||
assert obs['resource_events']['memory.events']['oom_kill'] == 0
|
||||
tokens = {'question_and_recipe': count(report['question'] + '\n' + report['recipe']),
|
||||
'arguments': sum(count(compact(call['arguments'])) for call in report['calls']),
|
||||
'help_and_replies': sum(count((case / call['stdout_file']).read_text()) for call in report['calls'])}
|
||||
tokens['whole_task'] = sum(tokens.values())
|
||||
runs.append({'case': case.name, 'mode': report['mode'], 'cache': report['cache'], 'runtime': report['runtime'], 'runtime_binding': report['runtime_binding'], 'runtime_binding_audit_ms': report['runtime_binding_audit_ms'],
|
||||
'wall_seconds': receipt['elapsed_seconds'], 'cpu_seconds': obs['cpu_stat']['usage_usec'] / 1e6,
|
||||
'peak_process_family_bytes_including_page_cache': obs['memory_peak_bytes'],
|
||||
'tokens_estimated': tokens, 'calls': report['calls'],
|
||||
'parent_evidence_id': report['parent_evidence_id'], 'parent_semantic_sha256': report['parent_semantic_sha256'],
|
||||
'answer_sha256': report['answer_sha256'], 'oracle_verified': report['oracle_verified'],
|
||||
'cleanup_verified': True, 'resource_events': obs['resource_events']})
|
||||
assert len(runs) == 12
|
||||
for key in ['answer_sha256', 'parent_semantic_sha256', 'parent_evidence_id']:
|
||||
assert len({row[key] for row in runs}) == 1, key
|
||||
summary = {}
|
||||
for cache in ['cold', 'warm']:
|
||||
summary[cache] = {}
|
||||
for mode in ['complete', 'selected']:
|
||||
rows = [r for r in runs if r['mode'] == mode and r['cache'] == cache]
|
||||
assert len(rows) == 3
|
||||
summary[cache][mode] = {key: {'median': statistics.median(r[key] for r in rows), 'min': min(r[key] for r in rows), 'max': max(r[key] for r in rows)} for key in ['wall_seconds', 'cpu_seconds', 'peak_process_family_bytes_including_page_cache']}
|
||||
summary[cache][mode]['whole_task_tokens_estimated'] = [r['tokens_estimated']['whole_task'] for r in rows]
|
||||
result = {'status': 'passed', 'tokenizer': 'tiktoken==0.12.0/cl100k_base; estimates, not model usage',
|
||||
'context_scope': 'Question, supplied command recipe, actual selected-command help, all logical CLI argv and all stdout. No model invoked; reasoning, framing, irrelevant tool discovery and actual native-agent usage unmeasured.',
|
||||
'cache_scope': 'cold disables Node compile cache; warm primes the identical workflow once per runtime/mode before timing. Fresh processes and isolated HOME each trial; OS page cache uncontrolled.',
|
||||
'resource_scope': 'Whole task driver plus all CLI children; includes pre/post source-and-compiled-runtime binding verification, bundle publication/authentication, help, extra calls and local answer/oracle checking. Kernel cgroup peak includes file cache; not sampled RSS. Download/build/oracle preparation and priming excluded.',
|
||||
'acquisition': json.loads((root / 'acquisition.json').read_text()), 'measurement_inputs': inputs,
|
||||
'summary': summary, 'runs': runs}
|
||||
native = root / 'native-control'
|
||||
if native.exists():
|
||||
binding = json.loads((native / 'runtime-binding.json').read_text())
|
||||
assert binding['runtime_binding_verified'] and binding['runtime_binding'] == expected['complete']
|
||||
assert str(Path(binding['runtime']).resolve()) == binding['runtime_binding']['root']
|
||||
receipt = next(json.loads(line) for line in reversed((root / 'native-control.log').read_text().splitlines()) if line.startswith('{"resource_scope":'))
|
||||
obs = receipt['payload_resource_observation']
|
||||
assert receipt['abort'] is None and receipt['payload_resource_observation_verified'] and obs['payload_exit_code'] == 0 and obs['payload_cleanup_verified']
|
||||
baseline_case = root / next(run['case'] for run in runs if run['mode'] == 'complete')
|
||||
assert json.loads((native / 'answer.json').read_text()) == json.loads((baseline_case / 'answer.json').read_text())
|
||||
control_source = Path(__file__).with_name('managed-cli-local-control.py').read_text()
|
||||
result['existing_native_control'] = {'runtime': binding['runtime'], 'runtime_binding': binding['runtime_binding'], 'runtime_binding_audit_ms': binding['runtime_binding_audit_ms'], 'repetitions': 1,
|
||||
'tokens_estimated_script_plus_help_plus_answer': count(control_source) + count((native / 'help.txt').read_text()) + count((native / 'answer.json').read_text()),
|
||||
'token_scope': 'Projection source, original CLI help and returned answer; excludes shared question and launcher argv. No actual model usage measured.',
|
||||
'wall_seconds': receipt['elapsed_seconds'], 'cpu_seconds': obs['cpu_stat']['usage_usec'] / 1e6,
|
||||
'peak_process_family_bytes_including_page_cache': obs['memory_peak_bytes'], 'answer_matches': True, 'cleanup_verified': True}
|
||||
args.output.write_text(json.dumps(result, indent=2) + '\n')
|
||||
print(json.dumps(summary, indent=2))
|
||||
@@ -0,0 +1,44 @@
|
||||
"""Existing native code-composition control: save complete stdout, return selected facts."""
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('runtime', type=Path)
|
||||
parser.add_argument('target', type=Path)
|
||||
parser.add_argument('output', type=Path)
|
||||
parser.add_argument('--measurement-inputs', type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
args.output.mkdir()
|
||||
node = 'node'
|
||||
inputs = json.loads(args.measurement_inputs.read_text())
|
||||
expected = inputs['expected_runtime_bindings']['complete']
|
||||
assert expected['git_revision'] == inputs['baseline_revision']
|
||||
helper = Path(__file__).with_name('managed-cli-runtime.mjs')
|
||||
def capture_binding():
|
||||
return json.loads(subprocess.check_output([node, str(helper), str(args.runtime)], text=True))
|
||||
binding_started = time.monotonic()
|
||||
binding = capture_binding()
|
||||
binding_audit_ms = {'before': (time.monotonic() - binding_started) * 1000}
|
||||
assert binding == expected
|
||||
|
||||
entry = str(args.runtime / 'scripts/rea.mjs')
|
||||
help_result = subprocess.run([node, entry, 'inspect-managed-members', '--help'], check=True, capture_output=True, text=True)
|
||||
(args.output / 'help.txt').write_text(help_result.stdout)
|
||||
with (args.output / 'parent.json').open('w') as file:
|
||||
subprocess.run([node, entry, 'inspect-managed-members', str(args.target), '--type', 'Newtonsoft.Json.JsonConvert', '--json'], check=True, stdout=file)
|
||||
parent = json.loads((args.output / 'parent.json').read_text())
|
||||
data = parent['normalized_result']
|
||||
answer = {'parent_evidence_id': parent['evidence_id'], 'artifact_sha256': data['artifact']['sha256'],
|
||||
'selection': data['selection'], 'source_coverage': data['coverage'],
|
||||
'total_methods': len(data['methods']), 'total_member_refs': len(data['member_refs']),
|
||||
'methods': data['methods'][:8], 'member_refs': data['member_refs'][:16],
|
||||
'limitation': 'MemberRef rows are assembly-wide; methods are selected-type rows. Page exhaustion is not an absence claim.'}
|
||||
(args.output / 'answer.json').write_text(json.dumps(answer))
|
||||
binding_finished = time.monotonic()
|
||||
assert capture_binding() == binding
|
||||
binding_audit_ms['after'] = (time.monotonic() - binding_finished) * 1000
|
||||
(args.output / 'runtime-binding.json').write_text(json.dumps({'runtime': str(args.runtime), 'runtime_binding': binding, 'runtime_binding_verified': True, 'runtime_binding_audit_ms': binding_audit_ms}))
|
||||
print(json.dumps(answer))
|
||||
@@ -0,0 +1,18 @@
|
||||
import json,hashlib,argparse
|
||||
from pathlib import Path
|
||||
import dnfile
|
||||
parser=argparse.ArgumentParser();parser.add_argument('root',type=Path);root=parser.parse_args().root;path=root/'Newtonsoft.Json.dll'
|
||||
pe=dnfile.dnPE(str(path));assert pe.net is not None
|
||||
counts={name:len(getattr(pe.net.mdtables,name).rows) if getattr(pe.net.mdtables,name,None) else 0 for name in ['TypeDef','MethodDef','MemberRef','Field','Property','Event','Param','StandAloneSig','TypeSpec','ExportedType']}
|
||||
selected=[]
|
||||
for index,row in enumerate(pe.net.mdtables.TypeDef.rows,1):
|
||||
name=(str(row.TypeNamespace)+'.' if str(row.TypeNamespace) else '')+str(row.TypeName)
|
||||
if name!='Newtonsoft.Json.JsonConvert':continue
|
||||
selected.append({'token':f'0x{0x02000000|index:08x}','name':name,'methods':[{'token':f'0x{0x06000000|m.row_index:08x}','name':str(m.row.Name),'rva':m.row.Rva,'signature_hex':m.row.Signature.value.hex()} for m in row.MethodList]})
|
||||
assert len(selected)==1
|
||||
refs=[{'token':f'0x{0x0a000000|i:08x}','name':str(row.Name),'signature_hex':row.Signature.value.hex()} for i,row in enumerate(pe.net.mdtables.MemberRef.rows[:16],1)]
|
||||
assembly=pe.net.mdtables.Assembly.rows[0]
|
||||
oracle={'decoder':'dnfile==0.18.0 (independent Python PE/CLI parser)','assembly_sha256':hashlib.sha256(path.read_bytes()).hexdigest(),'assembly_name':str(assembly.Name),'assembly_version':'.'.join(str(getattr(assembly,k)) for k in ['MajorVersion','MinorVersion','BuildNumber','RevisionNumber']),'row_counts':counts,'selected_types':selected,'member_refs_first_16':refs,'target_execution':False}
|
||||
(root/'oracle.json').write_text(json.dumps(oracle,indent=2)+'\n')
|
||||
print(json.dumps({'assembly':oracle['assembly_name'],'version':oracle['assembly_version'],'row_counts':counts,'selected_type':selected[0]['name'],'selected_methods':len(selected[0]['methods']),'target_execution':False}))
|
||||
pe.close()
|
||||
@@ -0,0 +1,106 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import { readFile, readdir, realpath } from "node:fs/promises";
|
||||
import { join, relative } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
const sha = (value) => createHash("sha256").update(value).digest("hex");
|
||||
|
||||
/** Bind a trial to its source checkout and compiled runtime, including deferred assets. */
|
||||
export const captureRuntimeBinding = async (runtime, kind = "cli") => {
|
||||
assert.ok(kind === "cli" || kind === "mcp", "Unknown runtime entry");
|
||||
const root = await realpath(runtime);
|
||||
const git = (args) =>
|
||||
execFileSync("git", args, { cwd: root, maxBuffer: 16 * 1024 * 1024 });
|
||||
const gitRevision = git(["rev-parse", "HEAD"]).toString().trim();
|
||||
const sourcePaths = ["src", "scripts", "package.json", "package-lock.json"];
|
||||
const sourceDiff = git([
|
||||
"diff",
|
||||
"--no-ext-diff",
|
||||
"--no-textconv",
|
||||
"--binary",
|
||||
"HEAD",
|
||||
"--",
|
||||
...sourcePaths,
|
||||
]);
|
||||
const untracked = git([
|
||||
"ls-files",
|
||||
"--others",
|
||||
"--exclude-standard",
|
||||
"-z",
|
||||
"--",
|
||||
...sourcePaths,
|
||||
])
|
||||
.toString()
|
||||
.split("\0")
|
||||
.filter(Boolean)
|
||||
.sort();
|
||||
const untrackedEntries = [];
|
||||
for (const name of untracked)
|
||||
untrackedEntries.push([name, sha(await readFile(join(root, name)))]);
|
||||
const files = ["scripts/rea.mjs", "package.json", "package-lock.json"];
|
||||
const visit = async (directory) => {
|
||||
const entries = await readdir(directory, { withFileTypes: true });
|
||||
for (const entry of entries.sort((a, b) =>
|
||||
a.name < b.name ? -1 : a.name > b.name ? 1 : 0,
|
||||
)) {
|
||||
const path = join(directory, entry.name);
|
||||
assert.ok(!entry.isSymbolicLink(), `Unbound compiled CLI link: ${path}`);
|
||||
if (entry.isDirectory()) await visit(path);
|
||||
else if (entry.isFile() && /\.(?:[cm]?js|json)$/.test(entry.name))
|
||||
files.push(relative(root, path));
|
||||
}
|
||||
};
|
||||
// MCP materializes additional workers and reads build-owned JSON after
|
||||
// discovery. Bind every compiled JS/JSON asset, rather than only its entry.
|
||||
await visit(join(root, kind === "mcp" ? "dist" : "dist/cli-runtime"));
|
||||
assert.ok(
|
||||
files.includes(
|
||||
kind === "mcp"
|
||||
? join("dist", "mcp", "main.js")
|
||||
: join("dist", "cli-runtime", "cli.js"),
|
||||
),
|
||||
"Missing compiled runtime entry",
|
||||
);
|
||||
const hash = createHash("sha256");
|
||||
let bytes = 0;
|
||||
for (const name of files.sort()) {
|
||||
const value = await readFile(join(root, name));
|
||||
bytes += value.length;
|
||||
hash.update(JSON.stringify([name, value.length, sha(value)]) + "\n");
|
||||
}
|
||||
return {
|
||||
binding_version: kind === "mcp" ? 2 : 1,
|
||||
root,
|
||||
node: process.version,
|
||||
git_revision: gitRevision,
|
||||
source_diff_sha256: sha(sourceDiff),
|
||||
untracked_source_sha256: sha(JSON.stringify(untrackedEntries)),
|
||||
...(kind === "mcp"
|
||||
? {
|
||||
compiled_runtime_sha256: hash.digest("hex"),
|
||||
compiled_runtime_files: files.length,
|
||||
compiled_runtime_bytes: bytes,
|
||||
}
|
||||
: {
|
||||
compiled_cli_sha256: hash.digest("hex"),
|
||||
compiled_cli_files: files.length,
|
||||
compiled_cli_bytes: bytes,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
export const assertRuntimeBinding = (actual, expected, mode) => {
|
||||
assert.ok(expected, `Missing expected runtime binding for ${mode}`);
|
||||
assert.deepEqual(actual, expected, `Runtime binding differs for ${mode}`);
|
||||
};
|
||||
|
||||
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
await captureRuntimeBinding(process.argv[2], process.argv[3]),
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"scope": "Single completed SDK regression after shared JSON reader/admission changes; not a new paired source-to-bundle performance comparison. Existing semantic-node cap one answers static correspondence only; no equal semantic-graph coverage claim. Corpus/reference preparation performed earlier and excluded.",
|
||||
"artifact": {
|
||||
"name": "Redux Toolkit 2.2.7",
|
||||
"tarball_sha256": "f2517c466b50424b661a27e48039f15db7783e5822f46b5c7d39f20104ac67a9"
|
||||
},
|
||||
"runtime_parent_revision": "4fab2dfda16236dc407aa179920780d6a970dda3",
|
||||
"production_manifest": "managed-cli.json#measurement_inputs.production_sources_sha256",
|
||||
"input_schema_profile": "default compact",
|
||||
"output_schema_profile": "full",
|
||||
"tokens_estimated": {
|
||||
"input_catalog_once": 49054,
|
||||
"arguments": 307,
|
||||
"text_replies": 7017,
|
||||
"whole_task": 56378
|
||||
},
|
||||
"token_scope": "tiktoken==0.12.0/cl100k_base; one name/description/input-schema catalog plus actual arguments and MCP text replies; excludes output schemas, framing, model prompts/reasoning and actual model usage. Not actual native-agent token usage.",
|
||||
"actual_model_usage": null,
|
||||
"wall_seconds": 21.38,
|
||||
"cpu_seconds": 21.022683,
|
||||
"peak_process_family_bytes_including_page_cache": 974041088,
|
||||
"calls": [
|
||||
{
|
||||
"name": "analyze_javascript_application",
|
||||
"elapsed_ms": 9837.265845000002,
|
||||
"is_error": false,
|
||||
"reply_bytes": 25941
|
||||
},
|
||||
{
|
||||
"name": "compare_source_to_bundle",
|
||||
"elapsed_ms": 256.3669919999993,
|
||||
"is_error": false,
|
||||
"reply_bytes": 13199
|
||||
},
|
||||
{
|
||||
"name": "inspect_analysis_view",
|
||||
"elapsed_ms": 3012.057904000001,
|
||||
"is_error": false,
|
||||
"reply_bytes": 19393
|
||||
},
|
||||
{
|
||||
"name": "export_evidence_bundle",
|
||||
"elapsed_ms": 148.9011160000009,
|
||||
"is_error": false,
|
||||
"reply_bytes": 364
|
||||
}
|
||||
],
|
||||
"independent_proof": {
|
||||
"status": "passed",
|
||||
"method": "Independent Python JSON/SHA-256/POSIX path and basename joins; no REA parser or matcher.",
|
||||
"source_files": 180,
|
||||
"embedded_nodes": 99,
|
||||
"candidate_relations": 210,
|
||||
"strong_location_rows": 33,
|
||||
"limitation": "Static multiple-location projections; no semantic-equivalence or removal claim."
|
||||
},
|
||||
"resource_events": {
|
||||
"memory.events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
},
|
||||
"pids.events": {
|
||||
"max": 0
|
||||
}
|
||||
},
|
||||
"cleanup_verified": true
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
import {
|
||||
captureRuntimeBinding,
|
||||
assertRuntimeBinding,
|
||||
} from "./managed-cli-runtime.mjs";
|
||||
import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
import { createHash } from "node:crypto";
|
||||
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
||||
import { join, resolve } from "node:path";
|
||||
const execute = promisify(execFile);
|
||||
const [runtime, root, output, mode, cache = "cold"] = process.argv.slice(2);
|
||||
for (const value of [runtime, root, output])
|
||||
assert.equal(resolve(value), value);
|
||||
assert.ok(["complete", "selected"].includes(mode));
|
||||
assert.ok(["cold", "warm"].includes(cache));
|
||||
await mkdir(output);
|
||||
await mkdir(join(output, "tmp"));
|
||||
const oracle = JSON.parse(await readFile(join(root, "oracle.json"), "utf8"));
|
||||
const target = join(root, "Newtonsoft.Json.dll");
|
||||
const hash = (value) => createHash("sha256").update(value).digest("hex");
|
||||
assert.equal(hash(await readFile(target)), oracle.assembly_sha256);
|
||||
const stable = (value) =>
|
||||
Array.isArray(value)
|
||||
? value.map(stable)
|
||||
: value !== null && typeof value === "object"
|
||||
? Object.fromEntries(
|
||||
Object.keys(value)
|
||||
.sort()
|
||||
.map((key) => [key, stable(value[key])]),
|
||||
)
|
||||
: value;
|
||||
const report = {
|
||||
status: "incomplete",
|
||||
runtime,
|
||||
mode,
|
||||
cache,
|
||||
node: process.version,
|
||||
question:
|
||||
"Report identity/selection/source coverage for JsonConvert, its total method count and the first eight complete method records, plus the first sixteen assembly-wide MemberRef records and continuation coverage.",
|
||||
recipe:
|
||||
mode === "selected"
|
||||
? "Use --detail summary --evidence-bundle FILE; pass the exact parent_evidence_id to inspect-analysis-view --evidence-bundle FILE with source kind retained-evidence and view {kind:managed-members,collection:methods|member_refs,offset:0,limit:8|16}."
|
||||
: "Use inspect-managed-members --type Newtonsoft.Json.JsonConvert; the completed full Evidence supplies the requested rows and remains accessible.",
|
||||
calls: [],
|
||||
cleanup_verified: false,
|
||||
};
|
||||
const began = performance.now();
|
||||
const environment = {
|
||||
PATH: process.env.PATH,
|
||||
HOME: output,
|
||||
TMPDIR: join(output, "tmp"),
|
||||
LANG: "C.UTF-8",
|
||||
REA_LOG_LEVEL: "silent",
|
||||
UV_THREADPOOL_SIZE: "1",
|
||||
NODE_OPTIONS: "--max-old-space-size=2048",
|
||||
...(cache === "cold"
|
||||
? { NODE_DISABLE_COMPILE_CACHE: "1" }
|
||||
: { NODE_COMPILE_CACHE: join(root, `compile-cache-${mode}`) }),
|
||||
};
|
||||
const call = async (label, args, json = true) => {
|
||||
const started = performance.now();
|
||||
const result = await execute(
|
||||
process.execPath,
|
||||
[join(runtime, "scripts/rea.mjs"), ...args],
|
||||
{
|
||||
cwd: output,
|
||||
env: environment,
|
||||
maxBuffer: 16 * 1024 * 1024,
|
||||
timeout: 120000,
|
||||
},
|
||||
);
|
||||
await writeFile(join(output, label + ".stdout"), result.stdout);
|
||||
await writeFile(join(output, label + ".stderr"), result.stderr);
|
||||
report.calls.push({
|
||||
label,
|
||||
arguments: ["rea", ...args],
|
||||
elapsed_ms: performance.now() - started,
|
||||
stdout_bytes: Buffer.byteLength(result.stdout),
|
||||
stdout_file: label + ".stdout",
|
||||
});
|
||||
return json ? JSON.parse(result.stdout) : result.stdout;
|
||||
};
|
||||
let parent, summary, methods, refs;
|
||||
try {
|
||||
const inputs = JSON.parse(
|
||||
await readFile(join(root, "measurement-inputs.json"), "utf8"),
|
||||
);
|
||||
const expected = inputs.expected_runtime_bindings?.[mode];
|
||||
assert.ok(expected, `Missing expected runtime for ${mode}`);
|
||||
assert.equal(
|
||||
expected.git_revision,
|
||||
mode === "complete"
|
||||
? inputs.baseline_revision
|
||||
: inputs.feature_parent_revision,
|
||||
);
|
||||
assert.notEqual(
|
||||
inputs.expected_runtime_bindings.complete.root,
|
||||
inputs.expected_runtime_bindings.selected.root,
|
||||
);
|
||||
assert.notEqual(
|
||||
inputs.expected_runtime_bindings.complete.compiled_cli_sha256,
|
||||
inputs.expected_runtime_bindings.selected.compiled_cli_sha256,
|
||||
);
|
||||
const bindingStarted = performance.now();
|
||||
report.runtime_binding = await captureRuntimeBinding(runtime);
|
||||
report.runtime_binding_audit_ms = {
|
||||
before: performance.now() - bindingStarted,
|
||||
};
|
||||
assertRuntimeBinding(report.runtime_binding, expected, mode);
|
||||
await call("help-members", ["inspect-managed-members", "--help"], false);
|
||||
if (mode === "complete") {
|
||||
parent = await call("complete", [
|
||||
"inspect-managed-members",
|
||||
target,
|
||||
"--type",
|
||||
"Newtonsoft.Json.JsonConvert",
|
||||
"--json",
|
||||
]);
|
||||
methods = parent.normalized_result.methods.slice(0, 8);
|
||||
refs = parent.normalized_result.member_refs.slice(0, 16);
|
||||
} else {
|
||||
await call("help-view", ["inspect-analysis-view", "--help"], false);
|
||||
const bundlePath = join(output, "parent.json");
|
||||
summary = await call("summary", [
|
||||
"inspect-managed-members",
|
||||
target,
|
||||
"--type",
|
||||
"Newtonsoft.Json.JsonConvert",
|
||||
"--detail",
|
||||
"summary",
|
||||
"--evidence-bundle",
|
||||
bundlePath,
|
||||
"--json",
|
||||
]);
|
||||
const id = summary.normalized_result.parent_evidence_id;
|
||||
assert.ok(id);
|
||||
const bundle = JSON.parse(await readFile(bundlePath, "utf8"));
|
||||
assert.equal(bundle.records.length, 1);
|
||||
parent = bundle.records[0];
|
||||
assert.equal(parent.evidence_id, id);
|
||||
for (const [collection, limit] of [
|
||||
["methods", 8],
|
||||
["member_refs", 16],
|
||||
]) {
|
||||
const value = await call(collection, [
|
||||
"inspect-analysis-view",
|
||||
JSON.stringify({
|
||||
source: { kind: "retained-evidence", evidence_id: id },
|
||||
view: { kind: "managed-members", collection, offset: 0, limit },
|
||||
}),
|
||||
"--evidence-bundle",
|
||||
bundlePath,
|
||||
"--json",
|
||||
]);
|
||||
const page = value.normalized_result;
|
||||
assert.equal(page.parent_evidence_id, id);
|
||||
assert.deepEqual(page.source_coverage, parent.normalized_result.coverage);
|
||||
assert.deepEqual(
|
||||
page.page.rows,
|
||||
parent.normalized_result[collection].slice(0, limit),
|
||||
);
|
||||
assert.equal(
|
||||
page.coverage.total,
|
||||
parent.normalized_result[collection].length,
|
||||
);
|
||||
assert.equal(page.coverage.next_offset, limit);
|
||||
assert.equal(page.coverage.exhausted, false);
|
||||
if (collection === "methods") methods = page.page.rows;
|
||||
else refs = page.page.rows;
|
||||
}
|
||||
}
|
||||
const data = parent.normalized_result;
|
||||
assert.equal(data.artifact.sha256, oracle.assembly_sha256);
|
||||
assert.equal(data.methods.length, 72);
|
||||
assert.equal(data.member_refs.length, 2149);
|
||||
assert.equal(data.types.length, 1);
|
||||
assert.equal(data.types[0].token, oracle.selected_types[0].token);
|
||||
for (let i = 0; i < data.methods.length; i++) {
|
||||
const row = data.methods[i],
|
||||
wanted = oracle.selected_types[0].methods[i];
|
||||
assert.equal(row.token, wanted.token);
|
||||
assert.equal(row.name, wanted.name);
|
||||
assert.equal(row.rva, wanted.rva);
|
||||
assert.equal(
|
||||
row.signature.raw_sha256,
|
||||
hash(Buffer.from(wanted.signature_hex, "hex")),
|
||||
);
|
||||
}
|
||||
for (let i = 0; i < refs.length; i++) {
|
||||
const row = refs[i],
|
||||
wanted = oracle.member_refs_first_16[i];
|
||||
assert.equal(row.token, wanted.token);
|
||||
assert.equal(row.name, wanted.name);
|
||||
assert.equal(
|
||||
row.signature.raw_sha256,
|
||||
hash(Buffer.from(wanted.signature_hex, "hex")),
|
||||
);
|
||||
}
|
||||
assert.equal(methods.length, 8);
|
||||
assert.equal(refs.length, 16);
|
||||
if (summary) {
|
||||
assert.equal(summary.normalized_result.summary.reported_counts.methods, 72);
|
||||
assert.equal(
|
||||
summary.normalized_result.summary.reported_counts.member_refs,
|
||||
2149,
|
||||
);
|
||||
assert.deepEqual(summary.normalized_result.summary.coverage, data.coverage);
|
||||
assert.deepEqual(
|
||||
summary.normalized_result.summary.selection,
|
||||
data.selection,
|
||||
);
|
||||
}
|
||||
const answer = {
|
||||
parent_evidence_id: parent.evidence_id,
|
||||
artifact_sha256: oracle.assembly_sha256,
|
||||
selection: data.selection,
|
||||
source_coverage: data.coverage,
|
||||
total_methods: data.methods.length,
|
||||
total_member_refs: data.member_refs.length,
|
||||
methods,
|
||||
member_refs: refs,
|
||||
limitation:
|
||||
"MemberRef rows are assembly-wide; methods are selected-type rows. Page exhaustion is not an absence claim.",
|
||||
};
|
||||
report.parent_evidence_id = parent.evidence_id;
|
||||
report.parent_semantic_sha256 = hash(JSON.stringify(stable(parent)));
|
||||
report.answer_sha256 = hash(JSON.stringify(stable(answer)));
|
||||
report.oracle_verified = {
|
||||
all_selected_method_metadata: 72,
|
||||
returned_methods: 8,
|
||||
returned_member_refs: 16,
|
||||
};
|
||||
const bindingFinished = performance.now();
|
||||
assertRuntimeBinding(
|
||||
await captureRuntimeBinding(runtime),
|
||||
report.runtime_binding,
|
||||
mode,
|
||||
);
|
||||
report.runtime_binding_audit_ms.after = performance.now() - bindingFinished;
|
||||
report.runtime_binding_verified = true;
|
||||
report.status = "passed";
|
||||
await writeFile(join(output, "parent-evidence.json"), JSON.stringify(parent));
|
||||
await writeFile(join(output, "answer.json"), JSON.stringify(answer));
|
||||
} finally {
|
||||
report.elapsed_ms = performance.now() - began;
|
||||
report.cleanup_verified = true;
|
||||
await writeFile(
|
||||
join(output, "report.json"),
|
||||
JSON.stringify(report, null, 2) + "\n",
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
status: report.status,
|
||||
mode,
|
||||
cache,
|
||||
parent: report.parent_evidence_id,
|
||||
answer: report.answer_sha256,
|
||||
calls: report.calls.map((c) => ({
|
||||
label: c.label,
|
||||
elapsed_ms: c.elapsed_ms,
|
||||
bytes: c.stdout_bytes,
|
||||
})),
|
||||
}),
|
||||
);
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,219 @@
|
||||
# Portable managed CLI member views
|
||||
|
||||
Issue #5148 / PR #5167. Baseline `main@3dbe314ada9f6dcc994ca4655dc0faf082503847`;
|
||||
feature integrates the original `7b3ed4d025edd24d062cde0327a53bd311e174fc`.
|
||||
The measured production-file SHA-256 manifest is in [managed-cli.json](managed-cli.json).
|
||||
These are working-tree measurements. Each trial verifies both source and the
|
||||
complete compiled CLI graph before and after execution against its explicitly
|
||||
selected build. The two roles have distinct checkout roots and compiled digests.
|
||||
Identity-audit time is included in whole-task costs and recorded separately.
|
||||
The audit reads compiled files before timing individual CLI calls, warming those
|
||||
filesystem pages; cold means disabled Node compile cache, not disk-cold startup.
|
||||
|
||||
## Question and independent checks
|
||||
|
||||
Report identity, selected type, source coverage, the total method count, the first
|
||||
eight complete method records, and the first sixteen assembly-wide MemberRef
|
||||
records, including continuation coverage. Keep complete original Evidence available.
|
||||
The question deliberately does not ask for every method or reference.
|
||||
|
||||
Public artifact: [Newtonsoft.Json 13.0.3](https://www.nuget.org/packages/Newtonsoft.Json/13.0.3),
|
||||
from the NuGet flat-container archive. The 2,441,966-byte archive SHA-256 is
|
||||
`872fc189e638ab1056555b03aaa38f68bcb54286e221aa646eb1129babf63c77`.
|
||||
Selected member `lib/net6.0/Newtonsoft.Json.dll`, 712,464 bytes, SHA-256
|
||||
`22c649f75fce5be7c7ccda8880473b634ef69ecf33f5d1ab8ad892caf47d5a07`.
|
||||
Package version 13.0.3 is distinct from metadata assembly version 13.0.0.0.
|
||||
No library code is executed; REA parses PE/CLI statically.
|
||||
|
||||
An independent Python oracle uses `dnfile==0.18.0` and `pefile==2024.8.26`.
|
||||
It finds 494 TypeDefs, 4,208 MethodDefs and 2,149 MemberRefs. The selected
|
||||
`Newtonsoft.Json.JsonConvert` has 72 methods. Every trial checks all 72 method
|
||||
tokens, names, RVAs and original signature hashes, plus the sixteen returned
|
||||
MemberRef tokens, names and signature hashes, against this oracle. This does
|
||||
not independently establish complete CIL semantics or opcode correctness.
|
||||
The full parent Evidence and requested answers are identical across all twelve
|
||||
trials; returned rows equal the exact parent slices. Selection and source
|
||||
coverage remain distinct from page exhaustion. MemberRefs remain assembly-wide.
|
||||
|
||||
## Completed-task cost
|
||||
|
||||
Linux x64, Node 24.18.0/npm 11.16.0. Three alternating pairs per cache condition,
|
||||
serial, one CPU; 4 GiB hard / 3 GiB early-stop family guard, no swap, 192-task
|
||||
ceiling. Every task includes actual selected-command help, all CLI calls,
|
||||
provider parsing, bundle publication/authentication, local answer extraction
|
||||
and oracle comparisons, plus both runtime-identity audits. Build, download, oracle preparation and warm priming
|
||||
are excluded. OS page cache is uncontrolled. No build/test overlapped timing.
|
||||
|
||||
Complete mode starts two CLI processes (help plus analysis). Selected mode starts
|
||||
five (two help commands, summary/publication, methods page, MemberRef page).
|
||||
Cold disables the Node compile cache; warm primes the exact workflow once per
|
||||
runtime/mode, then still starts fresh processes with isolated HOME each trial.
|
||||
All trials complete with verified process cleanup and no OOM/resource-stop event.
|
||||
|
||||
| Whole task, median | Complete | Summary + two pages |
|
||||
| ----------------------------------------------- | -------: | ------------------: |
|
||||
| Estimated context tokens, both cache conditions | 451,373 | 13,078 |
|
||||
| Cold wall seconds | 9.969 | 14.801 |
|
||||
| Cold family CPU seconds | 9.743 | 14.555 |
|
||||
| Cold kernel family peak MiB | 393.281 | 400.098 |
|
||||
| Warm wall seconds | 10.339 | 24.141 |
|
||||
| Warm family CPU seconds | 10.097 | 23.842 |
|
||||
| Warm kernel family peak MiB | 401.809 | 407.164 |
|
||||
|
||||
Context estimates include the question, supplied command recipe, all logical
|
||||
argv, actual help and stdout. Tokenizer `tiktoken==0.12.0`, `cl100k_base`.
|
||||
The reduction is 97.1% for this fixed task. There is no model invocation;
|
||||
actual billed/native-agent usage, reasoning and transport framing are unmeasured.
|
||||
The memory counter is the kernel cgroup process-family peak including file
|
||||
cache, not sampled RSS. Ranges and individual receipts are in the JSON.
|
||||
|
||||
This is an opt-in context/portability improvement with extra latency and CPU,
|
||||
not a speed or memory optimization. Complete provider parsing and full authentication of file-supplied bundles
|
||||
remain. Fresh managed Evidence is sealed at its producing factory and reused
|
||||
without another payload clone, including low-headroom error projection. Complete output remains the default and is preferable
|
||||
for small outputs or questions requiring every row. No cache or parser cap
|
||||
was introduced.
|
||||
|
||||
## Existing native code composition
|
||||
|
||||
The unchanged baseline can already redirect full stdout to a file and select
|
||||
rows in code. [The measured control](managed-cli-local-control.py) returns the
|
||||
identical answer and retains the complete original Evidence. One cold run:
|
||||
11.249 s wall, 11.000 s family CPU,
|
||||
375.3 MiB kernel peak. Projection source,
|
||||
original help and returned answer together estimate 10,555 tokens; the shared
|
||||
question and launcher argv are excluded. This single-run control does not
|
||||
establish stable performance or actual native-agent usage. It does demonstrate
|
||||
that raw CLI reply savings are not universal savings over code composition.
|
||||
The additive interface supplies authenticated reusable projections through the
|
||||
same application/domain owner as MCP, without caller-maintained JSON slicing.
|
||||
|
||||
## Correctness and resource boundaries
|
||||
|
||||
The public CLI regression pages all eight managed collections after process
|
||||
exit, target deletion and a working-directory change. Complete parent identity,
|
||||
original row order, signatures, source/page coverage and unknowns survive.
|
||||
Existing outputs are not replaced; failed publication retains completed facts.
|
||||
|
||||
The Evidence factory parses mutable caller data into independent trees, computes
|
||||
identity, then seals its fresh owned snapshot with active ancestry/iterators.
|
||||
It does not retain a set/array of every completed object. Existing sealed roots
|
||||
can be shared; mutable input aliases are cloned independently. General graph
|
||||
sealing keeps its separate cycle, sharing, hidden-field and atomic-failure rules.
|
||||
Managed and derived-view factories seal their own completed Evidence, so CLI
|
||||
error projection can borrow it without reauthentication or another payload copy.
|
||||
The view owner retains strict JSON normalization for optional-field contracts;
|
||||
the CLI no longer copies its already validated completed projection again.
|
||||
|
||||
Shared heap admission traverses by depth rather than queueing every report row
|
||||
or allocating an entries array. It reserves parsed working copies and actual
|
||||
escaping expansion before cloning/hashing, reporting UTF-16 storage explicitly.
|
||||
Canonical bundle equality streams existing ordinary JSON encoder parts, preserving
|
||||
native key order, omission, negative zero and Unicode semantics without two
|
||||
whole-document strings. All production bundle readers explicitly pass their
|
||||
operation: CLI import/export/compare/inspection, retained views, MCP import/
|
||||
comparison and both native-matching read passes. Errors retain the original
|
||||
cause, cleanup primary and lease through retry.
|
||||
|
||||
One process primitive dispatches queued callbacks and then their OS signal
|
||||
notifications. The managed producer checks it before accepting complete Evidence.
|
||||
Publication/read stages use it before their final checks. Inline, file and bundle
|
||||
CLI views share the existing command finalizer and actual resource scope; the
|
||||
finalizer checks interruption after close while preserving any primary/cleanup
|
||||
failure. Existing inline error labels remain intact. Synchronous analysis is
|
||||
cooperatively cancellable between stages, not preemptible.
|
||||
|
||||
Four compiled publication cases (SIGINT/SIGTERM × event/actual POSIX signal)
|
||||
fail without their checkpoint and pass restored. Eight additional compiled
|
||||
completion cases cover default complete delivery and inline projection; all fail
|
||||
with only their new completion checkpoints removed and pass restored. Fixture
|
||||
hooks match the selected target path or exact parent ID. Two real Newtonsoft
|
||||
publication runs and four real default/inline completion runs retain the identical
|
||||
parent or independently checked selected summary, exit 130/143 and preserve
|
||||
committed receipts where applicable. No target library code is executed.
|
||||
|
||||
All 556 focused tests across 36 files pass, including direct
|
||||
finalizer/cleanup ownership, WASM/Android cancellation and native matching.
|
||||
All six `npm run check` tasks plus architecture guards, and all six
|
||||
`npm run docs:check` tasks plus five README tests pass. The expanded domain
|
||||
project passes 5,617 tests in 287 files with
|
||||
3 skipped cases; this overlaps the focused gate. Its first
|
||||
batched shard hit two existing 30-second timeouts in unchanged large synthetic
|
||||
tests. Both passed isolated and in the fresh shard rerun under the same timeout;
|
||||
the cause of the batch variation is unverified. No production/timeout change
|
||||
was made for those cases. An earlier unsplit expansion was manually stopped
|
||||
before its heap ceiling; that incomplete attempt is not counted as a pass.
|
||||
|
||||
Eight producing/operation negative controls also catch graph-sized sealing/
|
||||
admission scratch and wrong operation attribution, including native reload.
|
||||
Native built-in instrumentation is confined to the isolated process-global lane.
|
||||
Initial test-only spy/probe/schema-import issues were corrected before these
|
||||
passing gates. No actual heap exhaustion is induced. Simulated providers do not
|
||||
qualify foreign engines; Windows OS signals remain unverified locally.
|
||||
|
||||
## Shared-reader real-artifact regression
|
||||
|
||||
The existing Redux Toolkit 2.2.7 source/bundle task also completes through the
|
||||
updated reader with default full output schemas and compact input schemas.
|
||||
An independent Python SHA-256/path oracle verifies 180 historical files,
|
||||
99 embedded source nodes and 210 candidate relations (33 strong-location rows,
|
||||
147 unknown). Original signals and partial source coverage remain visible.
|
||||
This uses the existing explicit semantic-node cap of one for static correspondence;
|
||||
it does not establish equivalent semantic-graph coverage or behavioral equivalence.
|
||||
|
||||
One completed task: 21.380 s wall,
|
||||
21.023 s family CPU,
|
||||
928.9 MiB kernel family peak,
|
||||
56,378 estimated context tokens (one input catalog,
|
||||
all arguments and MCP text replies; excludes output schemas, framing and model
|
||||
reasoning). Corpus/reference preparation was performed earlier and excluded.
|
||||
This is a regression verification with resource observation, not a new paired
|
||||
performance comparison. Actual model usage remains unmeasured. Details:
|
||||
[managed-cli-shared-read.json](managed-cli-shared-read.json).
|
||||
|
||||
## Reproduction
|
||||
|
||||
Extract the selected DLL to a private lab as `Newtonsoft.Json.dll`. Create an
|
||||
`acquisition.json` containing the URL, hashes, sizes and selected ZIP member
|
||||
shown above; never commit the DLL. Prepare the independent oracle:
|
||||
|
||||
```bash
|
||||
uv run --no-project --with dnfile==0.18.0 --with pefile==2024.8.26 python \
|
||||
experiments/analysis-efficiency/managed-cli-oracle.py /absolute/lab
|
||||
```
|
||||
|
||||
Build baseline and feature separately with the pinned toolchain. Run each under
|
||||
the shared resource guard, alternating complete/selected, selected/complete,
|
||||
complete/selected for cold and warm. Use a new output directory for every run:
|
||||
|
||||
```bash
|
||||
python3 experiments/analysis-efficiency/resource-run.py --observe-payload-exit -- \
|
||||
node experiments/analysis-efficiency/managed-cli-task.mjs \
|
||||
/absolute/runtime /absolute/lab /absolute/lab/pair-cold-1-selected selected cold
|
||||
```
|
||||
|
||||
Save each guard output to the adjacent `pair-*.log`. Warm mode uses the lab's
|
||||
mode-specific compile-cache directory; prime each identical workflow once first.
|
||||
Supply a `measurement-inputs.json` with exact revisions and production hashes,
|
||||
plus `expected_runtime_bindings.complete` and `.selected`. Capture each with
|
||||
`node experiments/analysis-efficiency/managed-cli-runtime.mjs /absolute/runtime`
|
||||
after building. Bind complete to the clean baseline revision, selected to the
|
||||
feature parent revision plus tracked/untracked source digests, with different
|
||||
roots and compiled-graph digests. The collector rejects a wrong build before any
|
||||
CLI call, rechecks it afterward, and aggregation independently enforces identity.
|
||||
A real wrong-runtime attempt is rejected before analysis. A copied trial with a
|
||||
tampered revision fails aggregation; removing only that consumer guard accepts it.
|
||||
The twelve-trial aggregation reproduces without private pilots. The native
|
||||
control also requires `--measurement-inputs /absolute/lab/measurement-inputs.json`
|
||||
and performs the same before/after identity checks.
|
||||
Then aggregate with:
|
||||
|
||||
```bash
|
||||
uv run --no-project --with tiktoken==0.12.0 python \
|
||||
experiments/analysis-efficiency/managed-cli-costs.py /absolute/lab \
|
||||
--output /absolute/results.json
|
||||
```
|
||||
|
||||
The original issue reporter's executable, foreign operating systems and actual
|
||||
model sessions remain unverified. Setup pilots and earlier unbound cohorts, including one failed setup run
|
||||
while compiled artifacts were absent after a typecheck failure, are excluded.
|
||||
@@ -0,0 +1,90 @@
|
||||
"""Account for catalog, complete SDK tasks and separately recorded model trials."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import tiktoken
|
||||
|
||||
|
||||
def compact(value):
|
||||
return json.dumps(value, ensure_ascii=False, separators=(",", ":"), allow_nan=False)
|
||||
|
||||
|
||||
def resource(case):
|
||||
path = case.with_name(case.name + ".log")
|
||||
scope = next(json.loads(line) for line in reversed(path.read_text().splitlines())
|
||||
if line.startswith('{"resource_scope":'))
|
||||
observation = scope["payload_resource_observation"]
|
||||
assert scope["abort"] is None and scope["payload_resource_observation_verified"]
|
||||
assert observation["payload_cleanup_verified"] and observation["payload_exit_code"] == 0
|
||||
assert all(observation["resource_events"]["memory.events"][key] == 0
|
||||
for key in ["high", "max", "oom", "oom_kill"])
|
||||
return {"wall_seconds": scope["elapsed_seconds"],
|
||||
"cpu_seconds": observation["cpu_stat"]["usage_usec"] / 1e6,
|
||||
"kernel_family_peak_bytes_including_page_cache": observation["memory_peak_bytes"],
|
||||
"resource_stop": scope["abort"], "cleanup_verified": True,
|
||||
"final_whole_scope_counters": scope["resource_events_final"],
|
||||
"guard_sources_sha256": scope["payload_observer_sources_sha256"],
|
||||
"log_sha256": hashlib.sha256(path.read_bytes()).hexdigest()}
|
||||
|
||||
|
||||
def sdk(case, count):
|
||||
report = json.loads((case / "report.json").read_text())
|
||||
assert report["status"] == "passed" and report["cleanup_verified"]
|
||||
catalog = json.loads((case / "catalog.json").read_text())
|
||||
calls = json.loads((case / "transcript.json").read_text())
|
||||
inputs = [{key: tool[key] for key in ["name", "description", "inputSchema"]}
|
||||
for tool in catalog["tools"]]
|
||||
arguments = sum(count(compact({"name": call["name"], "arguments": call["arguments"]}))
|
||||
for call in calls)
|
||||
text = sum(count(block["text"]) for call in calls for block in call["reply"]["content"]
|
||||
if block["type"] == "text")
|
||||
return {"case": case.name, "kind": "SDK", "profile": report["profile"],
|
||||
"artifact_sha256": report["artifact_sha256"],
|
||||
"tool_count": len(catalog["tools"]), "calls": report["calls"],
|
||||
"parent_evidence_id": report["parent_evidence_id"],
|
||||
"parent_semantic_sha256": report["parent_semantic_sha256"],
|
||||
"token_estimates": {"input_catalog_once": count(compact(inputs)),
|
||||
"arguments": arguments, "text_replies": text,
|
||||
"whole_task": count(compact(inputs)) + arguments + text,
|
||||
"raw_catalog_including_output_schemas": count(compact(catalog))},
|
||||
"actual_model_usage": None, **resource(case),
|
||||
"receipt_sha256": {name: hashlib.sha256((case / name).read_bytes()).hexdigest()
|
||||
for name in ["report.json", "catalog.json", "transcript.json"]}}
|
||||
|
||||
|
||||
def model(case):
|
||||
summary = json.loads((case / "summary.json").read_text())
|
||||
assert summary["exit_code"] == 0 and not summary["timeout"]
|
||||
assert summary["selected_artifact_bytes_unchanged"]
|
||||
assert json.loads((case / "cleanup.json").read_text())["profile_removed"]
|
||||
return {"case": case.name, "kind": "model", "client": summary["codex_version"],
|
||||
"requested_model": summary["requested_model"], "reasoning": summary["reasoning"],
|
||||
"model_identity_scope": summary["model_identity_scope"],
|
||||
"actual_model_usage": summary["usage"],
|
||||
"artifact_sha256": summary["selected_artifact_sha256_before"],
|
||||
"calls": summary["completed_mcp_calls"],
|
||||
"factual_correctness": "requires independent oracle and answer review",
|
||||
**resource(case),
|
||||
"receipt_sha256": {name: hashlib.sha256((case / name).read_bytes()).hexdigest()
|
||||
for name in ["summary.json", "answer.txt", "events.jsonl",
|
||||
"trial-settings.json", "context-receipt.json"]}}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("cases", type=Path, nargs="+")
|
||||
args = parser.parse_args()
|
||||
encoding = tiktoken.get_encoding("cl100k_base")
|
||||
count = lambda value: len(encoding.encode(value, disallowed_special=()))
|
||||
result = {"tokenizer": f"tiktoken {tiktoken.__version__}", "encoding": encoding.name,
|
||||
"estimate_scope": "One complete name/description/input-schema catalog, every RPC argument and text reply; raw output-schema transport counted separately. Model usage is separate and is not inferred from estimates.",
|
||||
"records": [sdk(case, count) if (case / "report.json").exists() else model(case)
|
||||
for case in args.cases]}
|
||||
args.output.write_text(json.dumps(result, indent=2) + "\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,54 @@
|
||||
"""Independent ELF64 little-endian / zlib oracle for the pinned Alpine corpus."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import struct
|
||||
import zlib
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("artifact", type=Path)
|
||||
parser.add_argument("output", type=Path)
|
||||
args = parser.parse_args()
|
||||
assert args.artifact.stat().st_size <= 256 * 1024 ** 2
|
||||
binary = args.artifact.read_bytes()
|
||||
assert binary[:6] == b"\x7fELF\x02\x01"
|
||||
table = struct.unpack_from("<Q", binary, 40)[0]
|
||||
stride, count, strings_index = struct.unpack_from("<HHH", binary, 58)
|
||||
assert stride == 64 and 0 < count < 65535 and strings_index < count
|
||||
sections = [struct.unpack_from("<IIQQQQIIQQ", binary, table + index * stride)
|
||||
for index in range(count)]
|
||||
string_row = sections[strings_index]
|
||||
names = binary[string_row[4]:string_row[4] + string_row[5]]
|
||||
matches = [row for row in sections
|
||||
if names[row[0]:names.index(b"\0", row[0])] == b".dep-v0"]
|
||||
assert len(matches) == 1
|
||||
row = matches[0]
|
||||
assert row[5] <= 1024 ** 2
|
||||
compressed = binary[row[4]:row[4] + row[5]]
|
||||
decoder = zlib.decompressobj()
|
||||
decoded = decoder.decompress(compressed, 8 * 1024 ** 2 + 1)
|
||||
assert len(decoded) <= 8 * 1024 ** 2 and decoder.eof
|
||||
assert not decoder.unconsumed_tail and not decoder.unused_data
|
||||
raw = json.loads(decoded)
|
||||
packages = [{"name": item["name"], "version": item["version"],
|
||||
"source": item.get("source"), "kind": item.get("kind"),
|
||||
"dependencies": item.get("dependencies", []), "root": item.get("root", False)}
|
||||
for item in raw["packages"]]
|
||||
result = {
|
||||
"artifact_sha256": hashlib.sha256(binary).hexdigest(),
|
||||
"section_sha256": hashlib.sha256(compressed).hexdigest(),
|
||||
"json_sha256": hashlib.sha256(decoded).hexdigest(),
|
||||
"packages": packages,
|
||||
"edges": [{"from_index": index, "to_index": destination}
|
||||
for index, item in enumerate(packages) for destination in item["dependencies"]],
|
||||
"serde_rows": [{"index": index, **{key: item[key] for key in ["name", "version", "kind"]}}
|
||||
for index, item in enumerate(packages) if item["name"] == "serde"],
|
||||
}
|
||||
args.output.write_text(json.dumps(result, indent=2) + "\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
File diff suppressed because it is too large.
Load diff
Loaded 100 of 1336 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user