mirror of
https://github.com/morluto/rea.git
synced 2026-11-07 13:56:47 -10:00
Compare commits
371
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
800a3f24b7 | ||
|
|
6c895eeb8e | ||
|
|
8f97a45483 | ||
|
|
6fd5d347c7 | ||
|
|
b14b94f0f5 | ||
|
|
7b6d872a25 | ||
|
|
b9a8f8e9f2 | ||
|
|
23e7c4e8e2 | ||
|
|
ac545adae2 | ||
|
|
9593bc536b | ||
|
|
7c389cbefc | ||
|
|
8b74f30bf9 | ||
|
|
7aa943c14b | ||
|
|
33698e6b31 | ||
|
|
fea4f2e397 | ||
|
|
09225b08e1 | ||
|
|
c77735fa83 | ||
|
|
18a8e71c9f | ||
|
|
06d1247836 | ||
|
|
f483eab543 | ||
|
|
df7119aeed | ||
|
|
60bad9ed06 | ||
|
|
3b242491a4 | ||
|
|
e78ac1a55b | ||
|
|
6a226bd092 | ||
|
|
2b8fb387b6 | ||
|
|
0e4b806db1 | ||
|
|
a0a1962e06 | ||
|
|
b0fb51cb4c | ||
|
|
5ae77656e7 | ||
|
|
b594fbc3e7 | ||
|
|
8397a0c9eb | ||
|
|
fbb0e79354 | ||
|
|
c36971953c | ||
|
|
ad7d4c1f4d | ||
|
|
b69d8c5467 | ||
|
|
c01ed783ac | ||
|
|
d3b31a0e29 | ||
|
|
3d5c73f35c | ||
|
|
e556134302 | ||
|
|
aa6f6436c9 | ||
|
|
40b9c03f99 | ||
|
|
baec375c34 | ||
|
|
423d190026 | ||
|
|
6efb384261 | ||
|
|
5fcf0d2dcc | ||
|
|
7bc6c5bf61 | ||
|
|
aa210b7ccc | ||
|
|
ef11f77836 | ||
|
|
0cd7ef456b | ||
|
|
269630f4e1 | ||
|
|
65f1c44734 | ||
|
|
6eb37a7749 | ||
|
|
bcc6775dc1 | ||
|
|
313af7119c | ||
|
|
a95b83c2b0 | ||
|
|
7f90549916 | ||
|
|
b3fd0aa3ee | ||
|
|
b9d1a61dd5 | ||
|
|
79d2fc0540 | ||
|
|
097cd2c988 | ||
|
|
84f62f76e5 | ||
|
|
095a51cf38 | ||
|
|
d47efe1a54 | ||
|
|
cbeeeda97b | ||
|
|
b4118b9683 | ||
|
|
ec3f84b626 | ||
|
|
1201c25542 | ||
|
|
570abe95f2 | ||
|
|
740c0f5615 | ||
|
|
d6f88becd5 | ||
|
|
b8cdbdf0ef | ||
|
|
03f17cf41d | ||
|
|
98422997c0 | ||
|
|
2817d30ab2 | ||
|
|
0676ad254c | ||
|
|
dfe6aaf6da | ||
|
|
e99b6c2c3b | ||
|
|
365fb03e73 | ||
|
|
5b14823353 | ||
|
|
c602fe8828 | ||
|
|
d14f199736 | ||
|
|
1fe92bff8e | ||
|
|
50822e1eff | ||
|
|
59dc48db20 | ||
|
|
a2e2c29b59 | ||
|
|
abfc42cfb1 | ||
|
|
6941d5ab92 | ||
|
|
df0e2f7b3e | ||
|
|
cce244f037 | ||
|
|
4726b19f98 | ||
|
|
4055cc4df1 | ||
|
|
d3af70fa27 | ||
|
|
2733979b4d | ||
|
|
c9df40f810 | ||
|
|
7d6bccb86d | ||
|
|
f59fc19d21 | ||
|
|
4e67bc3999 | ||
|
|
6d14e25345 | ||
|
|
a37dbb953c | ||
|
|
6ed97a22ed | ||
|
|
1ea6903595 | ||
|
|
c29a93097a | ||
|
|
5b292b630e | ||
|
|
01a725ecfa | ||
|
|
235e8bc056 | ||
|
|
21483a1a47 | ||
|
|
98e47e37a2 | ||
|
|
5aa23c3d17 | ||
|
|
82f50f56db | ||
|
|
47f8669c1e | ||
|
|
ddb5337674 | ||
|
|
b61fe25068 | ||
|
|
65aeb80222 | ||
|
|
c7afedc3d2 | ||
|
|
df8c90df8f | ||
|
|
8a8331b082 | ||
|
|
8d747c2acd | ||
|
|
0a9d92a54b | ||
|
|
4b6fd03146 | ||
|
|
c66729eca9 | ||
|
|
4572f31589 | ||
|
|
8691e48e67 | ||
|
|
1dc33c0543 | ||
|
|
21b6ea7fbd | ||
|
|
8f894546c8 | ||
|
|
178ab26290 | ||
|
|
7968ceb450 | ||
|
|
160648cc60 | ||
|
|
3e590e5b2f | ||
|
|
921225d4b2 | ||
|
|
25375924f7 | ||
|
|
e152349c5d | ||
|
|
9e4cf28cef | ||
|
|
a49a3553f4 | ||
|
|
397a5599e3 | ||
|
|
39c7f7e359 | ||
|
|
44310bba32 | ||
|
|
279fc04095 | ||
|
|
7e8f7f6101 | ||
|
|
3d311d9eca | ||
|
|
b9e5a9f463 | ||
|
|
dd2cbbf1a2 | ||
|
|
7cbf375d01 | ||
|
|
dcfb61826d | ||
|
|
dd9f5cdc4d | ||
|
|
21f12b896e | ||
|
|
f5edef3c96 | ||
|
|
ad1a57b65d | ||
|
|
c4242cb85e | ||
|
|
2e7a206b20 | ||
|
|
ff6b3fb9a1 | ||
|
|
14dd07e740 | ||
|
|
1cd82597da | ||
|
|
e334a13c79 | ||
|
|
effb796027 | ||
|
|
5f9f13d77b | ||
|
|
6de60993b8 | ||
|
|
47a8000cce | ||
|
|
2f27d3ac92 | ||
|
|
3e8923c6eb | ||
|
|
0793b6c3ca | ||
|
|
f89b03e738 | ||
|
|
7557e39dcd | ||
|
|
0eff039d08 | ||
|
|
5d30f82417 | ||
|
|
7cc33fcf7e | ||
|
|
8aa6df2d86 | ||
|
|
a6a69ec63e | ||
|
|
cd7a0eefd8 | ||
|
|
c79bd41b5d | ||
|
|
4e33bd3e08 | ||
|
|
a486cfe518 | ||
|
|
a116f2a7ae | ||
|
|
d2da713859 | ||
|
|
f2277454b8 | ||
|
|
4de432d868 | ||
|
|
f812dc4135 | ||
|
|
319fee4691 | ||
|
|
5d5fef7391 | ||
|
|
86d4a21215 | ||
|
|
7b25049dee | ||
|
|
fe95b7611f | ||
|
|
76eecf7fa1 | ||
|
|
081f2e2559 | ||
|
|
a18297f7d1 | ||
|
|
76441ed31b | ||
|
|
52b3c63495 | ||
|
|
0d1d6e858d | ||
|
|
492860ed07 | ||
|
|
1635e559d2 | ||
|
|
92fb319b27 | ||
|
|
17da88f117 | ||
|
|
768b58c6db | ||
|
|
6207843814 | ||
|
|
e58feb48c3 | ||
|
|
3c0e021cb3 | ||
|
|
f8f7ac96de | ||
|
|
1fdd3df7b4 | ||
|
|
82d3ab7aa8 | ||
|
|
e4cdf65e2c | ||
|
|
37d6e8ca9a | ||
|
|
bae84d1b93 | ||
|
|
0e17aab451 | ||
|
|
b989e3c3a3 | ||
|
|
6fa8e2ee3d | ||
|
|
79b8219f29 | ||
|
|
f061989ad2 | ||
|
|
b7be0d90a9 | ||
|
|
92213a9155 | ||
|
|
ec40c10749 | ||
|
|
5093d51c05 | ||
|
|
413f24b532 | ||
|
|
3655dfd7d5 | ||
|
|
30216468cc | ||
|
|
4f2fc7ca28 | ||
|
|
b0c48e8b65 | ||
|
|
ded6542d93 | ||
|
|
b7cae1ad8c | ||
|
|
6749bd090d | ||
|
|
f53c256886 | ||
|
|
25fc08189e | ||
|
|
d1c88fab1a | ||
|
|
bfdde7ee4c | ||
|
|
8dc4421325 | ||
|
|
9aee546aba | ||
|
|
c81b7ecebc | ||
|
|
650873e772 | ||
|
|
2146caeb3d | ||
|
|
ed62f14be4 | ||
|
|
8e0b2a9765 | ||
|
|
c1e0f531e6 | ||
|
|
a905a71e31 | ||
|
|
f878266503 | ||
|
|
15a8f6847c | ||
|
|
f3a301eca5 | ||
|
|
27ac1b6781 | ||
|
|
443d0778be | ||
|
|
01d6a95fd7 | ||
|
|
7ba1d0161e | ||
|
|
6979c589b0 | ||
|
|
6734dee6a8 | ||
|
|
83bbad2b2f | ||
|
|
242a0f2880 | ||
|
|
9be640a8b4 | ||
|
|
9eb8ba2b29 | ||
|
|
55b4efcb88 | ||
|
|
fef83241b1 | ||
|
|
25b69bb803 | ||
|
|
a293738c66 | ||
|
|
f68b261db4 | ||
|
|
212479aa02 | ||
|
|
e2da92f5d2 | ||
|
|
01484bc95c | ||
|
|
a52914649a | ||
|
|
4266d32751 | ||
|
|
329325049c | ||
|
|
0e1500dc8d | ||
|
|
9cad06db10 | ||
|
|
9c9c64edfa | ||
|
|
5cf7133f82 | ||
|
|
39179db68d | ||
|
|
6d7e627783 | ||
|
|
bf7721080f | ||
|
|
5cd61aac8e | ||
|
|
72cc2d30a3 | ||
|
|
339b82e0c8 | ||
|
|
b2df588b4a | ||
|
|
aa253bd13f | ||
|
|
781eb1b28a | ||
|
|
4932e5615b | ||
|
|
d109a39105 | ||
|
|
06642a48fb | ||
|
|
e3044645c7 | ||
|
|
ad92e0f9c8 | ||
|
|
838f5f44d2 | ||
|
|
54fbfacfb1 | ||
|
|
0781c3e99c | ||
|
|
87d023dcc8 | ||
|
|
f347713e24 | ||
|
|
6b3a081f36 | ||
|
|
abc1351506 | ||
|
|
0ddde829b2 | ||
|
|
3431541073 | ||
|
|
e7f29f8b8f | ||
|
|
cb0c73246d | ||
|
|
3fcbabe593 | ||
|
|
60822e0702 | ||
|
|
ee654e98a6 | ||
|
|
5b8e415483 | ||
|
|
5d25aa4f52 | ||
|
|
69b328eec8 | ||
|
|
8c8a2752c0 | ||
|
|
9222526fe2 | ||
|
|
68533bc0a3 | ||
|
|
2ad599dace | ||
|
|
7fa54e2d62 | ||
|
|
8a47cbbcce | ||
|
|
b8f58fd7ca | ||
|
|
eb24da4481 | ||
|
|
25a08ed639 | ||
|
|
11b025ef97 | ||
|
|
d1202c539d | ||
|
|
5261340397 | ||
|
|
ecd22c42ac | ||
|
|
84a54b6183 | ||
|
|
046c4ce353 | ||
|
|
c74059d89f | ||
|
|
6a9911ea77 | ||
|
|
e80fb638be | ||
|
|
59a70adefd | ||
|
|
95d9d51f72 | ||
|
|
381004b664 | ||
|
|
af9bc3ab50 | ||
|
|
87e2cc26d8 | ||
|
|
29ebd67405 | ||
|
|
0e578d43c8 | ||
|
|
8706068b57 | ||
|
|
57d0ed45f7 | ||
|
|
0dea08fb07 | ||
|
|
087acf26e8 | ||
|
|
08f99dbaf2 | ||
|
|
dbe2c97af3 | ||
|
|
3052a067a3 | ||
|
|
db0908a732 | ||
|
|
077de92594 | ||
|
|
2dd2ffcd45 | ||
|
|
ace4dbf36e | ||
|
|
fc7f042c8c | ||
|
|
b529bd84d7 | ||
|
|
248133d784 | ||
|
|
030fa886f9 | ||
|
|
82fd223638 | ||
|
|
a6488a96a9 | ||
|
|
d0e695b42a | ||
|
|
90475ec9e5 | ||
|
|
d60b2cab65 | ||
|
|
ed6668b5bc | ||
|
|
50717c39b6 | ||
|
|
567ea4b1e8 | ||
|
|
7c8eb63fcc | ||
|
|
c27560e434 | ||
|
|
3515b26221 | ||
|
|
c4cdb7658b | ||
|
|
7f65617064 | ||
|
|
c6893d1ac6 | ||
|
|
779d548c4e | ||
|
|
e891926534 | ||
|
|
60834e391c | ||
|
|
83b2d16ee9 | ||
|
|
8694dc30d9 | ||
|
|
67b9181010 | ||
|
|
81adb8977a | ||
|
|
e1ec737d9b | ||
|
|
3a6e4f2cb1 | ||
|
|
19f9011511 | ||
|
|
52414282b9 | ||
|
|
4191974010 | ||
|
|
5f91616727 | ||
|
|
b6e58c22d4 | ||
|
|
4803c4f9c2 | ||
|
|
47fa4fbad6 | ||
|
|
06c8e14b34 | ||
|
|
ca3fd7baf9 | ||
|
|
8b7ee48a46 | ||
|
|
906f161dc6 | ||
|
|
63220edcc3 | ||
|
|
19b2972dfb | ||
|
|
3233992733 | ||
|
|
855eb703af | ||
|
|
d815367a11 |
No files matched your search
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "rea",
|
||||
"interface": {
|
||||
"displayName": "REA"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "rea",
|
||||
"source": {
|
||||
"source": "npm",
|
||||
"package": "rea-agents",
|
||||
"version": "6.8.0"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "Developer Tools"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
name: reverse-engineer-anything
|
||||
description: Reverse engineer native, managed, Electron/JavaScript, packaged, firmware, and browser targets with REA, and build agent environments (AgentEnv bundles) of web applications from a live instance or a capture. Use shipped-artifact or requested runtime evidence to explain features, compare versions, decompile code, or guide a reconstruction. Skip REA for ordinary source-repository architecture analysis.
|
||||
metadata:
|
||||
version: "49"
|
||||
version: "53"
|
||||
---
|
||||
|
||||
# REA
|
||||
@@ -17,6 +17,9 @@ readiness or provider commands.
|
||||
|
||||
Installing this skill supplies instructions; it does not register the REA MCP
|
||||
server, install analysis engines, or add tools to an already-running agent.
|
||||
The exception is a Claude Code or Codex plugin install: the plugin bundles
|
||||
this skill and registers its own `rea` server, outside the state that
|
||||
`rea setup` and `rea doctor` manage.
|
||||
|
||||
If REA tools are available and their registration is not known to be stale,
|
||||
proceed directly to the target. Do not run diagnostics or setup before every
|
||||
@@ -37,42 +40,23 @@ repeat or known not to have started. If it may already have changed the
|
||||
target, or it fails again, tell the user and ask them to restart the MCP
|
||||
client. If REA could not start its connection, retry once, then tell the user
|
||||
and ask them to restart the MCP client. Do not retry a startup failure that
|
||||
returns the same unchanged result. Run `rea doctor` when REA could not start
|
||||
returns the same unchanged result. For plugin installs, follow
|
||||
[plugin recovery](references/connection-and-recovery.md#rea-installed-as-a-client-plugin).
|
||||
For setup-owned registrations, run `rea doctor` when REA could not start
|
||||
or tools stay missing after that restart. For `cleanup_incomplete`, a retryable
|
||||
capacity limit, or `configuration_invalid`, follow the recovery guide's ladder
|
||||
before asking for a restart. Read that guide before a second repair attempt.
|
||||
|
||||
1. Diagnose without changing REA or client configuration. `npx` may download
|
||||
the package and write to npm's cache. For Codex, run
|
||||
`npx -y rea-agents@latest doctor --client codex --json`. Substitute the current
|
||||
supported client: `claude_code`, `claude_desktop`, `codex`, `cursor`,
|
||||
`gemini_cli`, `windsurf`, `devin`, `opencode`, `antigravity`, `copilot_cli`,
|
||||
`commandcode`, `vscode`, `grok_build`, `omp`, or `grok_bot`. `grok_bot` has no local
|
||||
file registration: doctor reports the Grok Bot chat step, and setup does not
|
||||
write `mcp.json`. If the client is unknown, use `doctor --json` and
|
||||
inspect its registration results before choosing a setup scope.
|
||||
2. Distinguish the reason. Missing, malformed, or stale registration needs a
|
||||
scoped configuration repair. An aligned registration with no tools in the
|
||||
active session needs a restart/reconnection; doctor cannot prove that the
|
||||
current agent has connected. A missing provider affects only tasks requiring
|
||||
that provider: static JavaScript inspection needs neither Hopper nor Ghidra,
|
||||
and Android inspection has separate bring-your-own JADX/Java prerequisites.
|
||||
3. For a configuration repair, prepare the read-only plan:
|
||||
`npx -y rea-agents@latest setup --client codex --dry-run --json`.
|
||||
Use the current client's ID, show its exact proposed paths, backups, and
|
||||
changes, and obtain approval before setup writes configuration or installs
|
||||
Hopper. Setup normally installs the matching bundled skill too; include that
|
||||
replacement in the reviewed plan. After approval, apply the same scope with
|
||||
`npx -y rea-agents@latest setup --client codex --yes`. Add `--install-hopper`
|
||||
only if that separate installation was needed and explicitly approved.
|
||||
4. Restart/reconnect the affected agent. Verify that REA tools actually appear
|
||||
in the session, then resume the original investigation. If they remain
|
||||
absent, inspect the client's MCP launch error rather than repeating setup.
|
||||
Choose the installation owner before repairing registration. Plugin installs use
|
||||
[plugin recovery](references/connection-and-recovery.md#rea-installed-as-a-client-plugin);
|
||||
only setup-owned registrations use the guide's
|
||||
[registration repair plan](references/connection-and-recovery.md#repair-registration-when-needed).
|
||||
A plugin-only doctor result of `missing` does not call for `rea setup`.
|
||||
|
||||
REA setup never installs or upgrades Node.js, npm, Homebrew, Java, Ghidra, IDA,
|
||||
JADX, Kuna, Binwalk, or Unblob. Use existing prerequisites; do not install unrelated
|
||||
software to repair MCP registration. For an unsupported client, use manual stdio
|
||||
registration with a version-pinned `rea-agents` package or continue through the CLI.
|
||||
registration with an existing installation’s absolute runtime and entry script, or continue through the CLI.
|
||||
|
||||
A concrete CLI fallback for an operator-supplied JavaScript tree or ASAR is:
|
||||
|
||||
@@ -85,8 +69,11 @@ graph, limitations, and unknowns with the same care as an MCP result; the CLI
|
||||
returns the Evidence record directly. This fallback does not establish that
|
||||
MCP is configured. Native CLI tasks still require their selected engine.
|
||||
Prefer an existing `rea` CLI. When none is installed and REA package acquisition
|
||||
is within the authorized scope, use `npx -y rea-agents@latest` in its place.
|
||||
Configuration repair starts with a read-only setup plan; show paths, backups and
|
||||
is within the authorized scope, use `npx -y rea-agents@latest` in its place from a
|
||||
trusted directory outside the target project, with absolute target paths. Managed
|
||||
setup binds the current installation directly; retain its runtime and package
|
||||
cache entry, or restore that installation before repairing its registration.
|
||||
For setup-owned registration, configuration repair starts with a read-only setup plan; show paths, backups and
|
||||
skill replacement before applying authorized changes. Preserve existing approval
|
||||
and target-execution boundaries.
|
||||
|
||||
@@ -344,6 +331,11 @@ leaves its database open. The modern headless profile creates and closes an
|
||||
owned private database without saving. Installation and registration reuse
|
||||
[mrexodia/ida-pro-mcp](https://github.com/mrexodia/ida-pro-mcp); see the
|
||||
[IDA provider guide](https://github.com/morluto/rea/blob/main/docs/ida-provider.md).
|
||||
For migration to the separate native IDA MCP plugin, follow the guide's
|
||||
[legacy attached migration](https://github.com/morluto/rea/blob/main/docs/ida-provider.md#migrate-a-legacy-attached-registration).
|
||||
Replace the upstream registration explicitly; modern mrexodia tools are not the
|
||||
native profile. Native attachment preserves the database but does not provide
|
||||
direct callers; check session availability and the guide's verification limits.
|
||||
Proceed directly to `analyze_function`, pseudocode, or function/string searches
|
||||
after opening; IDA does not supply `binary_overview`. Consult session availability
|
||||
when composing broader workflows. Modern direct callers and unsupported dossier
|
||||
|
||||
@@ -13,6 +13,27 @@ own APK path and explicit selectors; do not open a native session first.
|
||||
Choose an `overload_index` from the class inventory when methods are ambiguous
|
||||
instead of guessing.
|
||||
|
||||
For JNI implementations, discover `inspect_android_jni_bindings`. Select raw
|
||||
DEX class/method identities and optional descriptors, ABI or logical library
|
||||
paths. Prefer `detail: "summary"`; complete Evidence remains retained and
|
||||
`android-jni` views page declarations, libraries, candidates or binding rows
|
||||
with exact fields. Global native-pair ambiguity survives class selection.
|
||||
Preserve slot/relocation provenance and source coverage: matched means observed
|
||||
candidate presence; partial scans do not establish uniqueness or absence.
|
||||
This reads DEX/ELF bytes without loading the APK into the decompiler or executing
|
||||
target code. Runtime registration and loading remain unknown. See the
|
||||
[JNI guide](https://github.com/morluto/rea/blob/main/docs/android-analysis.md#link-native-declarations-to-jni-candidates).
|
||||
|
||||
For an R8/ProGuard release build with its `mapping.txt`, pass the absolute
|
||||
`mapping_path` to `inspect_android_class` or `inspect_android_method`. Prefer
|
||||
`detail: "summary"` to receive normalized symbols or the selected body without
|
||||
duplicate raw class metadata. Complete Evidence stays retained under the linked
|
||||
parent ID and can be exported; CLI summary delivery requires `--evidence_output`.
|
||||
Omitted or complete detail preserves the full inline response. Keep
|
||||
selecting by observed names; the separate `mapping` block reports each symbol
|
||||
as `mapped`, `ambiguous` or `unmapped` after checking DEX types and prototypes.
|
||||
REA does not verify that the mapping belongs to the APK build.
|
||||
|
||||
The provider requires a separately supplied headless JADX MCP JAR 0.7.1 and
|
||||
Java 17 or newer. `REA_JADX_MCP_JAR` selects the absolute JAR path; `JAVA_HOME`
|
||||
can select Java. Use `rea doctor --provider jadx --json` to check the JADX
|
||||
|
||||
@@ -17,7 +17,7 @@ does not establish which server an approval wildcard covers. See
|
||||
|
||||
| Observation | Meaning and next step |
|
||||
| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| No REA tools in the active session | Inspect registration with `rea doctor --client codex --json`. A skill installation alone does not register MCP. |
|
||||
| No REA tools in the active session | If REA was installed as a client plugin, follow the plugin section below. Otherwise inspect registration with `rea doctor --client codex --json`. A skill installation alone does not register MCP. |
|
||||
| Missing, malformed or stale registration | Prepare a scoped setup plan; apply only authorized changes with backups. |
|
||||
| Aligned registration, but no connected tools | Restart/reconnect the client. Doctor checks registration; it cannot establish the current agent's connection. Inspect the client's launch error if reconnection fails. |
|
||||
| MCP connection dropped or REA could not start | If the connection drops, retry that call once only when it is safe to repeat or known not to have started. If it may already have changed the target, or the same failure returns, tell the user REA's connection failed and ask them to restart the MCP client. If REA could not start its connection, retry once, then tell the user and ask them to restart the MCP client. Do not retry a startup failure that returns the same unchanged result. Run `rea doctor` when REA could not start or tools stay missing after restart. Doctor cannot restore a live connection by itself. |
|
||||
@@ -116,6 +116,32 @@ is not a recommendation to change it. Do not invent a setting. Host memory and
|
||||
- `invalid_request`: correct the reported fields from the current schema. Do
|
||||
not repeat the unchanged call.
|
||||
|
||||
## REA installed as a client plugin
|
||||
|
||||
A Claude Code or Codex plugin owns its `rea` server and this skill. Doctor's
|
||||
`--client` and `--skill` checks and `rea setup` read and write only
|
||||
setup-owned state, so for a plugin-only install they report `missing`, and
|
||||
applying setup would add a second `rea` server. If this skill was loaded from
|
||||
a plugin, or the client lists a `rea` plugin, do not prepare a setup plan for
|
||||
missing tools. Instead:
|
||||
|
||||
- Check that the plugin is installed and enabled with the client's own
|
||||
listing: `claude plugin list` and `/mcp` in Claude Code, `codex plugin list`
|
||||
in Codex.
|
||||
- Restart or reconnect the client, then read its launch error for the `rea`
|
||||
server if tools are still absent. The plugin starts its bundled runtime; a missing build or version mismatch
|
||||
requires a reinstall, or a fresh build when developing from source.
|
||||
- Check analysis engines through the connected server's
|
||||
`binary_session.result.tool_availability`. `rea doctor --provider <id> --json`
|
||||
from a shell reports that shell's environment, which can differ from the
|
||||
environment the client gave the plugin server. If you still run it through
|
||||
the package runner, use the version pinned in the plugin manifest's server
|
||||
entry (`rea-agents@<version>`), not `@latest`, so it matches the server the
|
||||
plugin starts.
|
||||
|
||||
Use the setup repair below only when the user wants a setup-owned registration
|
||||
instead of the plugin, and remove or disable the plugin first.
|
||||
|
||||
## Repair registration when needed
|
||||
|
||||
For Codex:
|
||||
@@ -130,7 +156,10 @@ Use the current supported client's ID: `claude_code`, `claude_desktop`, `codex`,
|
||||
`copilot_cli`, `commandcode`, `qwen_code`, `vscode`, `trae`, `grok_build`, `omp`, `pi`,
|
||||
`hermes`, `qoder`, `droid`, `zcode`, `dsh`, `freebuff`, or `grok_bot`. If unknown, inspect `doctor --json` before choosing a
|
||||
scope. `grok_bot` uses a chat registration step rather than local `mcp.json`.
|
||||
For unsupported clients, use version-pinned manual stdio registration or CLI.
|
||||
For unsupported clients, use manual stdio registration with the selected
|
||||
installation’s absolute runtime and entry script, or continue through the CLI.
|
||||
Acquire packages from a trusted directory outside the target project. Keep a
|
||||
package-runner installation and its runtime available while registrations use it.
|
||||
|
||||
Show the plan's exact paths, backups, changes and bundled-skill replacement.
|
||||
Obtain approval for writes when that concrete scope is not already authorized,
|
||||
|
||||
@@ -23,6 +23,14 @@ again if a hint names a gap, then writes the bundle with
|
||||
- Map the application first with `inspect_web_page` (and `capture_web_screenshot`
|
||||
when layout matters): the login form's locators, and the API calls behind the
|
||||
pages that list and edit the entities the user asked about.
|
||||
- `inspect_web_page` cannot sign in. To see pages behind sign-in, run a short
|
||||
`capture_browser_scenario` that signs in and opens them, with
|
||||
`"capture": {"after_each_step": ["accessibility"]}` (`"dom"` for markup).
|
||||
Read a step's tree with `inspect_analysis_view`, `view: {kind:
|
||||
"browser-scenario", collection: "text", step_index, artifact:
|
||||
"accessibility", offset: 0, limit: 2048}`, paging with `offset`. Capture
|
||||
options are only `after_each_step`, `at_end`, `events`, `network` and
|
||||
`limits`.
|
||||
|
||||
## Record a session an environment can learn writes from
|
||||
|
||||
@@ -80,20 +88,37 @@ shape, with the application's own locators, paths and headers:
|
||||
"path": "/api/folders",
|
||||
"expected_status": [200]
|
||||
},
|
||||
{
|
||||
"step_id": "new-folder-1",
|
||||
"action": "click",
|
||||
"timeout_ms": 15000,
|
||||
"locator": { "kind": "role", "role": "button", "name": "New folder" }
|
||||
},
|
||||
{
|
||||
"step_id": "folder-title-1",
|
||||
"action": "fill",
|
||||
"timeout_ms": 15000,
|
||||
"locator": { "kind": "css", "selector": "input[name=title]" },
|
||||
"value": { "source": "literal", "value": "Scratch folder 1" }
|
||||
},
|
||||
{
|
||||
"step_id": "create-folder-1",
|
||||
"action": "click",
|
||||
"timeout_ms": 15000,
|
||||
"locator": { "kind": "role", "role": "button", "name": "Create" },
|
||||
"save_response": {
|
||||
"method": "POST",
|
||||
"path": "/api/folders",
|
||||
"save": [{ "name": "folder_1", "json_pointer": "/id" }]
|
||||
}
|
||||
},
|
||||
{
|
||||
"step_id": "read-folder-1",
|
||||
"action": "request",
|
||||
"timeout_ms": 15000,
|
||||
"method": "POST",
|
||||
"path": "/api/folders",
|
||||
"json": { "title": "Scratch folder 1" },
|
||||
"headers": [
|
||||
{
|
||||
"name": "X-CSRFToken",
|
||||
"value": { "source": "cookie", "name": "csrftoken" }
|
||||
}
|
||||
],
|
||||
"expected_status": [200, 201]
|
||||
"method": "GET",
|
||||
"path": "/api/folders/{saved:folder_1}",
|
||||
"expected_status": [200]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -107,35 +132,73 @@ client with it. Match `wait_for` locators to exactly one element.
|
||||
as a secret reference), submit, then `wait_for` an element only a signed-in
|
||||
user sees.
|
||||
2. Read with `request` steps: each collection the environment needs, twice
|
||||
before any write, so fields that change on their own show up; one item of
|
||||
each.
|
||||
3. Use `request` steps only when the API lets the caller choose each scratch
|
||||
object's ID or a prior read already established it. Request paths are fixed
|
||||
strings; no action substitutes a value from an earlier response. For
|
||||
server-assigned IDs, create through the UI and open the new object's detail
|
||||
view to record its read, edit and delete through UI actions. If that journey
|
||||
cannot be scripted, leave the write unserved and report the limitation;
|
||||
never guess an ID or create objects with no supported cleanup path.
|
||||
before any write, so fields that change on their own show up; then each
|
||||
object a list shows by id, up to ten per collection. An object known only
|
||||
from a list that leaves out fields its own read shows cannot be read by id
|
||||
or updated in the environment.
|
||||
3. Write the way the application's UI does: fill its forms and click its
|
||||
buttons, so each request carries the fields the UI sends, including ones
|
||||
the server would otherwise derive. Give the click or key press that submits
|
||||
a create `save_response` to keep the new object's ID, then `goto` its page
|
||||
(`/items/{saved:item_1}`) or read it with a `request` step. Never guess an
|
||||
ID, and never create a probe object to learn the next one. Write with
|
||||
`request` steps instead only when the UI cannot reach the operation (an
|
||||
API-only resource, or a UI that does not call the JSON API), or when coverage
|
||||
withholds the UI-shaped write as `unexplained-change` or `contradicted`;
|
||||
that counts as one of the two re-recordings. A `request` step write that
|
||||
coverage withholds that way usually lacks fields the UI sends: record it
|
||||
through the UI instead. If a journey cannot be scripted, leave the write
|
||||
unserved and report the limitation.
|
||||
Record two numbered scratch objects per write type,
|
||||
with varied free text. After each write, and before the next one, read the
|
||||
object back by id and then its list: create 1, read 1, list, create 2,
|
||||
read 2, list; never several writes before their reads.
|
||||
4. Leave more than a second between a create and its first edit
|
||||
(`wait_for_timeout` with `duration_ms: 1100`).
|
||||
5. Update both objects and read each back; delete both and read each back
|
||||
(expect 404) and the list.
|
||||
5. Update both objects and read each back, changing the fields a person
|
||||
would change (a name, an email address, a status, a due date) rather than
|
||||
only a description: a served update accepts only the members a recorded
|
||||
update stored. Delete both and read each back (expect 404, or the object
|
||||
marked deleted) and the list.
|
||||
6. Vary what the two creates send, however you write them: the first every
|
||||
field the application takes, the second only what a person must give (its
|
||||
title or name), with the other fields left out or empty. A served create
|
||||
requires each member both creates filled in and lets a caller leave out one
|
||||
a create left out or sent empty, so an agent that names only a title is not
|
||||
refused for fields it had no reason to set.
|
||||
|
||||
About `request` steps:
|
||||
|
||||
- `path` is on the start URL's origin; the page must be on that origin.
|
||||
- Header values are literals, declared secrets, a cookie the browser holds
|
||||
(`{source: "cookie", name}`), or a local storage entry
|
||||
(`{source: "local_storage", key, json_pointer}`), with an optional
|
||||
`prefix` such as `"Bearer "`. Copy the headers the application's own
|
||||
requests send (a CSRF header, a bearer token). Values read from the page
|
||||
are redacted from records made after they are read, not from the login
|
||||
response that returned them, and values shorter than 8 characters are not
|
||||
redacted at all.
|
||||
(`{source: "cookie", name}`), a local storage entry
|
||||
(`{source: "local_storage", key, json_pointer}`), a saved value
|
||||
(`{source: "saved", name}`), or Basic credentials
|
||||
(`{source: "basic_credentials", parts: [username, password]}`, sent as the
|
||||
base64 of `username:password` and redacted), with an optional `prefix` such as
|
||||
`"Bearer "` or `"Basic "`. Each credential part is a literal, secret, saved
|
||||
value, cookie or local storage entry, so a header the frontend builds from a
|
||||
login token (the username and the token) can be copied too; the password is
|
||||
a secret or saved value, never a literal. Copy the
|
||||
headers the application's own requests send (a CSRF header such as
|
||||
`X-CSRFToken` from the `csrftoken` cookie, a bearer token). Values read from the page are redacted from records made after they
|
||||
are read, not from the login response that returned them, and values
|
||||
shorter than 8 characters are not redacted at all.
|
||||
- `save: [{name, json_pointer, secret}]` keeps a string or number from the
|
||||
step's JSON response, such as the created object's `/id`, for later steps;
|
||||
`secret: true` redacts it, as for a token the API returns, so mark every
|
||||
saved token, key or session value secret. This also protects the selected
|
||||
source response before its body or headers are retained. Compressed or
|
||||
unknown-size UI responses cannot supply saved values. On a `click` or `press`,
|
||||
`save_response: {method, path, save}` keeps values from the response to the
|
||||
new request observed while the step waits (`{*}` in `path` matches one segment).
|
||||
Matching does not prove UI causality: choose a path distinct from polling;
|
||||
multiple observed matches fail as ambiguous. The step
|
||||
fails unless a 2xx JSON response arrives before its `timeout_ms`. Later
|
||||
steps send a saved value as `{saved:name}` in a request `path` (and its
|
||||
query) or a `goto` URL; in the `json` body, where a string that is only
|
||||
`{saved:name}` keeps the saved JSON type; or as `{source: "saved", name}` in
|
||||
a header or credential part.
|
||||
- Reading a page value makes later bodies costlier to keep: after a CSRF
|
||||
token, bodies over about 47 KiB are kept as `unavailable`. When the API
|
||||
returns larger responses, raise `capture.limits`
|
||||
@@ -182,10 +245,12 @@ withheld with its hint:
|
||||
| `no-call` | Re-record once with a write that succeeds. |
|
||||
| `side-effect` | Stop: the application changes other entities. |
|
||||
| `contradicted` | Stop: a later read disagrees with the modelled effect. |
|
||||
| `body-unusable` | Stop: the body is not a JSON object. |
|
||||
| `body-unusable` | Re-record a UI write once with `request` steps (its body was not exposed); else stop. |
|
||||
|
||||
Use new scratch names on each attempt; the first attempt's objects may still
|
||||
exist.
|
||||
Use new scratch names on each attempt, and delete what an earlier attempt
|
||||
created before recording again (through the UI, or a `request` step with the
|
||||
id that capture shows): the environment starts from what the recording first
|
||||
reads, so a leftover object becomes seeded data that write tasks then find.
|
||||
New browser scenario captures include request times, so a fully timed capture
|
||||
can learn a write clock and serve updates that stamp modification times. Older
|
||||
captures or ones missing a request start keep record order and learn no clock.
|
||||
|
||||
@@ -652,3 +652,20 @@ page cannot prove absence in unknown coverage. Retained views are historical,
|
||||
not fresh filesystem checks. No decryption, Godot resource decoding, GDScript
|
||||
decompilation or target execution is provided. See
|
||||
[Godot PCK](https://github.com/morluto/rea/blob/main/docs/godot-pck.md).
|
||||
|
||||
UnityFS AssetBundle containers (`.bundle`, `.ab`, YooAsset packages and other
|
||||
byte-identified files) list `CAB-*` SerializedFiles and `.resS` members with
|
||||
header and node facts; none/LZ4/LZ4HC member blocks stream on demand. Bundles
|
||||
declaring asset-bundle encryption keep header facts with unknown directory
|
||||
coverage; LZMA member bytes retain named occurrences with unavailable hashes.
|
||||
Virtual member offsets are not physical carrier locations. Format 6–8 readers
|
||||
cache one decoded block and support retained filtered/paged views. No
|
||||
decryption or SerializedFile object decoding is provided. See
|
||||
[UnityFS](https://github.com/morluto/rea/blob/main/docs/unityfs.md).
|
||||
|
||||
U-Boot legacy uImages use the same inspection/extraction workflows. Prefer a
|
||||
retained summary and selected inventory views for header facts or component
|
||||
IDs. Header addresses/CPU/OS are declarations; payloads remain as stored.
|
||||
Multi-file components retain their aligned physical ranges; the full payload
|
||||
is also materialized. Unknown name text retains its original 32 bytes. See
|
||||
[U-Boot uImage](https://github.com/morluto/rea/blob/main/docs/uimage.md).
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
||||
"name": "rea",
|
||||
"description": "Reverse engineer anything with agents, from app behavior down to native binaries.",
|
||||
"owner": {
|
||||
"name": "morluto",
|
||||
"url": "https://github.com/morluto"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "rea",
|
||||
"description": "Reverse engineer anything with agents, from app behavior down to native binaries.",
|
||||
"source": {
|
||||
"source": "npm",
|
||||
"package": "rea-agents",
|
||||
"version": "6.8.0"
|
||||
},
|
||||
"category": "development"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "rea",
|
||||
"version": "6.8.0",
|
||||
"description": "Reverse engineer anything with agents, from app behavior down to native binaries.",
|
||||
"author": {
|
||||
"name": "morluto",
|
||||
"url": "https://github.com/morluto"
|
||||
},
|
||||
"homepage": "https://rea.tools/",
|
||||
"repository": "https://github.com/morluto/rea",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"reverse-engineering",
|
||||
"binary-analysis",
|
||||
"decompiler",
|
||||
"mcp-server"
|
||||
],
|
||||
"skills": "./skills",
|
||||
"mcpServers": {
|
||||
"rea": {
|
||||
"command": "node",
|
||||
"args": [
|
||||
"${CLAUDE_PLUGIN_ROOT}/scripts/plugin-mcp-launcher.mjs",
|
||||
"6.8.0"
|
||||
]
|
||||
}
|
||||
},
|
||||
"icon": "./assets/rea-plugin.png"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"rea": {
|
||||
"command": "node",
|
||||
"args": [
|
||||
"./scripts/plugin-mcp-launcher.mjs",
|
||||
"6.8.0"
|
||||
],
|
||||
"cwd": ".",
|
||||
"startup_timeout_sec": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "rea",
|
||||
"version": "6.8.0",
|
||||
"description": "Reverse engineer anything with agents, from app behavior down to native binaries.",
|
||||
"author": {
|
||||
"name": "morluto",
|
||||
"url": "https://github.com/morluto"
|
||||
},
|
||||
"homepage": "https://rea.tools/",
|
||||
"repository": "https://github.com/morluto/rea",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"reverse-engineering",
|
||||
"binary-analysis",
|
||||
"decompiler",
|
||||
"mcp-server"
|
||||
],
|
||||
"skills": "./skills",
|
||||
"mcpServers": "./.codex-plugin/mcp.json",
|
||||
"interface": {
|
||||
"displayName": "REA",
|
||||
"shortDescription": "Reverse engineer anything",
|
||||
"longDescription": "Reverse engineer anything with agents, from app behavior down to native binaries.",
|
||||
"developerName": "morluto",
|
||||
"category": "Developer Tools",
|
||||
"capabilities": [
|
||||
"Interactive",
|
||||
"Read",
|
||||
"Write"
|
||||
],
|
||||
"websiteURL": "https://rea.tools/",
|
||||
"defaultPrompt": [
|
||||
"Use REA to explain how this binary implements a feature.",
|
||||
"Use REA to compare two versions of this application.",
|
||||
"Use REA to recover the sources from this JavaScript bundle."
|
||||
],
|
||||
"composerIcon": "./assets/rea-plugin.png",
|
||||
"logo": "./assets/rea-plugin.png"
|
||||
}
|
||||
}
|
||||
+24
-16
@@ -753,6 +753,11 @@ jobs:
|
||||
- name: Run native Apple and process boundary regressions
|
||||
run: >-
|
||||
npm run test:focused --
|
||||
tests/boundary/providers/hopper/hopperMacLaunchArguments.test.ts
|
||||
tests/acceptance/providers/hopperStartupRecovery.test.ts
|
||||
tests/boundary/providers/hopper/hopperClient.helperFailure.test.ts
|
||||
tests/boundary/providers/hopper/bridgeBootstrapCleanup.test.ts
|
||||
tests/boundary/providers/hopper/bridgeTargetLease.integration.test.ts
|
||||
tests/acceptance/artifactDmgAttachmentRecoveryCli.test.ts
|
||||
tests/boundary/providers/native/nativeDmgArtifactReader.test.ts
|
||||
tests/process-global/dmgCancellationReason.test.ts
|
||||
@@ -855,6 +860,24 @@ jobs:
|
||||
# The matching native artifact establishes real Job Object and private
|
||||
# runtime boundaries for these fixtures. Ghidra and Java are not needed;
|
||||
# real engine claims remain in the separate controlled-provider workflow.
|
||||
# Run native proofs before the broad curated suite so an unrelated
|
||||
# fixture failure cannot hide the real control and recovery checks.
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: windows-process-boundary-fixture
|
||||
path: .cache/windows-process-boundary/
|
||||
# Passing the fixture adds the breakaway, caller/child token, environment
|
||||
# semantics and ancestor reparse observations, which the lane skips
|
||||
# entirely when it is absent.
|
||||
- run: >-
|
||||
npm run verify:windows-native -- .
|
||||
"${{ github.workspace }}\.cache\windows-process-boundary\process-boundary.exe"
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: windows-native-inspection-fixture
|
||||
path: .cache/windows-native-inspection-fixture/
|
||||
- name: Verify native inspection failure ownership and recovery
|
||||
run: node scripts/verify-windows-native-inspection.mjs
|
||||
- name: Run curated Windows capability tests
|
||||
run: >-
|
||||
npx vitest run --coverage.enabled=false
|
||||
@@ -883,6 +906,7 @@ jobs:
|
||||
tests/boundary/process/packageNpmInvocation.test.ts
|
||||
tests/boundary/process/packedBridgeVerification.test.ts
|
||||
tests/boundary/process/windowsOutputCapture.test.ts
|
||||
tests/boundary/process/windowsExecutableSelection.test.ts
|
||||
tests/acceptance/webModuleCli.test.ts
|
||||
tests/acceptance/webSourceLocationCli.test.ts
|
||||
tests/boundary/cli/referenceSourceImportStatus.test.ts
|
||||
@@ -907,22 +931,6 @@ jobs:
|
||||
tests/process-global/runnerCancellation.test.ts
|
||||
tests/process-global/windowsOwnedCommand.test.ts
|
||||
tests/conformance/providers/ghidra/realGhidraWindowsWorkflow.test.ts
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: windows-process-boundary-fixture
|
||||
path: .cache/windows-process-boundary/
|
||||
# Passing the fixture adds the breakaway, caller/child token, environment
|
||||
# semantics and ancestor reparse observations, which the lane skips
|
||||
# entirely when it is absent.
|
||||
- run: >-
|
||||
npm run verify:windows-native -- .
|
||||
"${{ github.workspace }}\.cache\windows-process-boundary\process-boundary.exe"
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: windows-native-inspection-fixture
|
||||
path: .cache/windows-native-inspection-fixture/
|
||||
- name: Verify native inspection failure ownership and recovery
|
||||
run: node scripts/verify-windows-native-inspection.mjs
|
||||
- name: Verify real Node Inspector discovery and observation
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ Thumbs.db
|
||||
|
||||
# Local reference sources and analysis artifacts
|
||||
/_reference/
|
||||
/experiments/analysis-efficiency/results/
|
||||
/experiments/analysis-efficiency/
|
||||
|
||||
# Generated website download
|
||||
/website/public/examples/notes-example.zip
|
||||
|
||||
+4
-1
@@ -10,7 +10,10 @@
|
||||
"node_modules/**",
|
||||
"CHANGELOG.md",
|
||||
"package-lock.json",
|
||||
".claude-plugin/plugin.json",
|
||||
".codex-plugin/plugin.json",
|
||||
"_reference/**",
|
||||
"third_party/**"
|
||||
"third_party/**",
|
||||
".codex-plugin/mcp.json"
|
||||
]
|
||||
}
|
||||
+2
-2
@@ -2683,7 +2683,7 @@ Read the [6.1 to 6.2 migration guide](docs/migration-6.2.md) before upgrading. R
|
||||
* enforce conventional pull request titles ([3a21f16](https://github.com/morluto/rea/commit/3a21f16c1832430765083636511a8c12dbccf2dd))
|
||||
* verify installed package with Linux Hopper ([4f97f69](https://github.com/morluto/rea/commit/4f97f699e4d5471557d1ce0ff91e144065d06a61))
|
||||
|
||||
## [0.3.0](https://github.com/morluto/rea/compare/rea-agents-0.2.1...rea-agents-0.3.0) (2026-07-12)
|
||||
## [0.3.0](https://github.com/morluto/rea/compare/rea-0.2.1...rea-agents-0.3.0) (2026-07-12)
|
||||
|
||||
|
||||
### Features
|
||||
@@ -2736,7 +2736,7 @@ Read the [6.1 to 6.2 migration guide](docs/migration-6.2.md) before upgrading. R
|
||||
* redesign and localize README ([051b6db](https://github.com/morluto/rea/commit/051b6db65687fd14826b6462cd623feb2504f123))
|
||||
* redesign and localize README ([910eda6](https://github.com/morluto/rea/commit/910eda6f323ba1151b0771fe5de6c60a91e3d46d))
|
||||
|
||||
## [0.2.0](https://github.com/morluto/rea/compare/rea-0.1.0...rea-0.2.0) (2026-07-12)
|
||||
## [0.2.0](https://github.com/morluto/rea/releases/tag/rea-0.2.0) (2026-07-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
@@ -83,12 +83,15 @@ npx rea-agents setup
|
||||
|
||||
Choose your agents, review the proposed changes, and approve them. Setup adds
|
||||
REA's MCP server and matching workflow instructions, with backups of existing
|
||||
configuration. Restart your agent afterward.
|
||||
configuration. Restart your agent afterward. Setup records the selected runtime and REA
|
||||
entry script directly. If acquired through a package runner, keep its cache entry
|
||||
available. Run package acquisition from a trusted directory outside the target
|
||||
project. Installation and recovery details are in the setup guide below.
|
||||
|
||||
Setup supports Claude Code, Codex, Cursor, Gemini CLI, Grok Build and
|
||||
[other agents](docs/installation.md#supported-agents). See
|
||||
[installation and setup](docs/installation.md) for provider configuration and
|
||||
manual MCP registration.
|
||||
manual MCP registration and Claude Code/Codex plugin installation.
|
||||
|
||||
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
|
||||
@@ -425,7 +428,7 @@ Report vulnerabilities through [SECURITY.md](SECURITY.md).
|
||||
|
||||
## Star history
|
||||
|
||||
🎉 **300,000 GitHub stars — thank you!**
|
||||
🎉 **400,000 GitHub stars — thank you!**
|
||||
|
||||
Thanks to everyone using REA, reporting bugs, requesting features, testing builds, and contributing fixes.
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Plugin icon
|
||||
|
||||
`rea-plugin.png` is a square adaptation of the left panel of REA's GitHub
|
||||
social preview, retrieved on 2026-10-28:
|
||||
|
||||
https://repository-images.githubusercontent.com/1209966933/1a3fef9a-be4b-41f4-8830-a94c0e8288cc
|
||||
|
||||
The image was adapted with imagegen, preserving the cyan REA lettering,
|
||||
pixel typography, orange rule, and taglines. Both plugin manifests reference
|
||||
this shared asset; only the PNG is included in the npm package.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
@@ -1,5 +1,9 @@
|
||||
import com.atxx.jhmcp.*;
|
||||
import com.google.gson.*;
|
||||
import com.android.tools.smali.dexlib2.Opcodes;
|
||||
import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import com.android.tools.smali.dexlib2.dexbacked.DexBackedClassDef;
|
||||
import com.android.tools.smali.dexlib2.dexbacked.DexBackedMethod;
|
||||
import io.modelcontextprotocol.kotlin.sdk.server.*;
|
||||
import io.modelcontextprotocol.kotlin.sdk.types.*;
|
||||
import jadx.api.*;
|
||||
@@ -9,14 +13,21 @@ import jadx.api.plugins.input.data.ICodeReader;
|
||||
import jadx.api.plugins.input.data.IMethodRef;
|
||||
import jadx.api.plugins.input.insns.InsnIndexType;
|
||||
import jadx.api.plugins.input.insns.Opcode;
|
||||
import jadx.core.codegen.TypeGen;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.nodes.*;
|
||||
import java.io.PrintStream;
|
||||
import java.io.StringReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import kotlin.Unit;
|
||||
import kotlin.ResultKt;
|
||||
import kotlin.coroutines.Continuation;
|
||||
@@ -178,6 +189,205 @@ class ReaJadxBridge {
|
||||
manifestSnapshot = null;
|
||||
}
|
||||
|
||||
// One bounded DEX at a time, beside the already admitted analysis JVM. The
|
||||
// response allowance accounts for worst-case JSON escaping before retention.
|
||||
private static final int NATIVE_DEX_BYTES = 64 * 1024 * 1024;
|
||||
private static final long NATIVE_TOTAL_DEX_BYTES = 256L * 1024 * 1024;
|
||||
// This JSON is escaped again inside an 8 MiB MCP frame.
|
||||
private static final long NATIVE_JSON_BYTES = 4L * 1024 * 1024;
|
||||
|
||||
/** The bundled decoder allocates its declared UTF-16 length before validating bytes. */
|
||||
private static final class NativeDex extends DexBackedDexFile {
|
||||
private OptionalIndexedSection<String> boundedStrings;
|
||||
NativeDex(byte[] bytes) { super(Opcodes.getDefault(), bytes); }
|
||||
|
||||
@Override public OptionalIndexedSection<String> getStringSection() {
|
||||
if (boundedStrings == null) {
|
||||
var source = super.getStringSection();
|
||||
boundedStrings = new OptionalIndexedSection<>() {
|
||||
@Override public int size() { return source.size(); }
|
||||
@Override public int getOffset(int index) { return source.getOffset(index); }
|
||||
@Override public String getOptional(int index) { return index == -1 ? null : get(index); }
|
||||
@Override public String get(int index) {
|
||||
int offset = getBuffer().readSmallUint(source.getOffset(index));
|
||||
int units = getDataBuffer().readerAt(offset).readSmallUleb128();
|
||||
if (units > NATIVE_JSON_BYTES / 6
|
||||
|| units > getDataBuffer().getBuf().length - offset)
|
||||
throw new IllegalArgumentException("DEX string exceeds the native decoding allowance");
|
||||
return source.get(index);
|
||||
}
|
||||
};
|
||||
}
|
||||
return boundedStrings;
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkNativeInterrupted() {
|
||||
if (Thread.currentThread().isInterrupted())
|
||||
throw new java.util.concurrent.CancellationException("Native declaration inventory interrupted");
|
||||
}
|
||||
|
||||
private static final class NativeInventory {
|
||||
final List<Map<String, Object>> methods = new ArrayList<>();
|
||||
final List<String> unknowns = new ArrayList<>();
|
||||
long retainedBytes = 1024;
|
||||
int dexEntries;
|
||||
int examinedDexEntries;
|
||||
int examinedClasses;
|
||||
int examinedMethods;
|
||||
boolean partial;
|
||||
boolean diagnosticLimit;
|
||||
|
||||
void unknown(String reason) {
|
||||
partial = true;
|
||||
long bytes = 64L + reason.length() * 6L;
|
||||
if (unknowns.size() < 16 && retainedBytes + bytes <= NATIVE_JSON_BYTES - 4096) {
|
||||
unknowns.add(reason);
|
||||
retainedBytes += bytes;
|
||||
} else if (!diagnosticLimit) {
|
||||
diagnosticLimit = true;
|
||||
unknowns.add("Additional native-inventory limitations exceed the retained diagnostic allowance.");
|
||||
}
|
||||
}
|
||||
|
||||
boolean retain(Map<String, Object> method, long bytes) {
|
||||
if (retainedBytes + bytes > NATIVE_JSON_BYTES - 4096) {
|
||||
unknown("Native declarations exceed the 4 MiB retained JSON allowance; remaining declarations are unknown.");
|
||||
return false;
|
||||
}
|
||||
retainedBytes += bytes;
|
||||
methods.add(method);
|
||||
return true;
|
||||
}
|
||||
|
||||
Map<String, Object> result() {
|
||||
return Map.of("scope", "apk-root-dex-declarations", "methods", List.copyOf(methods),
|
||||
"coverage", Map.of("status", partial ? "partial" : "complete",
|
||||
"dex_entries", dexEntries, "examined_dex_entries", examinedDexEntries,
|
||||
"examined_classes", examinedClasses, "examined_methods", examinedMethods),
|
||||
"unknowns", List.copyOf(unknowns));
|
||||
}
|
||||
}
|
||||
|
||||
/** Match Android's standard root multidex carriers, without a basename guess. */
|
||||
private static boolean nativeDexEntry(String name) {
|
||||
return name.equals("classes.dex") || name.matches("classes[0-9]+\\.dex");
|
||||
}
|
||||
|
||||
private static byte[] readNativeDex(ZipFile archive, ZipEntry entry) throws IOException {
|
||||
long size = entry.getSize();
|
||||
if (size < 0 || size > NATIVE_DEX_BYTES)
|
||||
throw new IllegalArgumentException("DEX exceeds the 64 MiB single-member read allowance");
|
||||
byte[] bytes = new byte[(int) size];
|
||||
CRC32 crc = new CRC32();
|
||||
try (InputStream input = archive.getInputStream(entry)) {
|
||||
int offset = 0;
|
||||
while (offset < bytes.length) {
|
||||
checkNativeInterrupted();
|
||||
int read = input.read(bytes, offset, Math.min(65536, bytes.length - offset));
|
||||
if (read < 0) throw new IOException("DEX is shorter than its ZIP declaration");
|
||||
if (read == 0) continue;
|
||||
crc.update(bytes, offset, read);
|
||||
offset += read;
|
||||
}
|
||||
if (input.read() != -1) throw new IOException("DEX exceeds its ZIP declaration");
|
||||
}
|
||||
if (entry.getCrc() < 0 || entry.getCrc() != crc.getValue())
|
||||
throw new IOException("DEX does not match its ZIP CRC32 declaration");
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/** Raw DEX ownership precedes JADX's duplicate-class selection and aliases. */
|
||||
static Map<String, Object> nativeDeclarations(Path apk) {
|
||||
NativeInventory inventory = new NativeInventory();
|
||||
try (ZipFile archive = new ZipFile(apk.toFile())) {
|
||||
Map<String, Integer> names = new HashMap<>();
|
||||
var directory = archive.entries();
|
||||
while (directory.hasMoreElements()) {
|
||||
checkNativeInterrupted();
|
||||
ZipEntry entry = directory.nextElement();
|
||||
if (!entry.isDirectory() && nativeDexEntry(entry.getName())) {
|
||||
inventory.dexEntries++;
|
||||
names.merge(entry.getName(), 1, Integer::sum);
|
||||
}
|
||||
}
|
||||
long totalBytes = 0;
|
||||
int entryIndex = -1;
|
||||
directory = archive.entries();
|
||||
while (directory.hasMoreElements()) {
|
||||
checkNativeInterrupted();
|
||||
ZipEntry entry = directory.nextElement();
|
||||
entryIndex++;
|
||||
String path = entry.getName();
|
||||
if (entry.isDirectory() || !nativeDexEntry(path)) continue;
|
||||
if (names.get(path) != 1) {
|
||||
inventory.unknown("Duplicate root DEX entry name cannot be selected uniquely by the ZIP reader: " + path);
|
||||
continue;
|
||||
}
|
||||
if (entry.getSize() < 0 || entry.getSize() > NATIVE_DEX_BYTES
|
||||
|| entry.getSize() > NATIVE_TOTAL_DEX_BYTES - totalBytes) {
|
||||
inventory.unknown("Root DEX member exceeds the 64 MiB member or 256 MiB total read allowance: " + path);
|
||||
continue;
|
||||
}
|
||||
totalBytes += entry.getSize();
|
||||
try {
|
||||
DexBackedDexFile dex = new NativeDex(readNativeDex(archive, entry));
|
||||
var classes = dex.getClassSection();
|
||||
for (int classIndex = 0; classIndex < classes.size(); classIndex++) {
|
||||
checkNativeInterrupted();
|
||||
DexBackedClassDef cls = classes.get(classIndex);
|
||||
String type = cls.getType();
|
||||
if (!type.startsWith("L") || !type.endsWith(";"))
|
||||
throw new IllegalArgumentException("Class definition has no reference type");
|
||||
String className = type.substring(1, type.length() - 1).replace('/', '.');
|
||||
// Passing false retains duplicate encoded method references too.
|
||||
for (Iterable<? extends DexBackedMethod> group : List.of(
|
||||
cls.getDirectMethods(false), cls.getVirtualMethods(false))) {
|
||||
for (DexBackedMethod method : group) {
|
||||
checkNativeInterrupted();
|
||||
inventory.examinedMethods++;
|
||||
if ((method.getAccessFlags() & 0x100) == 0) continue;
|
||||
String methodName = method.getName();
|
||||
String returnType = method.getReturnType();
|
||||
long characters = 2L + returnType.length();
|
||||
for (CharSequence parameter : method.getParameterTypes()) {
|
||||
characters += parameter.length();
|
||||
if (characters * 6L > NATIVE_JSON_BYTES) break;
|
||||
}
|
||||
long bytes = 512L + 6L * (className.length() + methodName.length()
|
||||
+ path.length() + characters);
|
||||
if (inventory.retainedBytes + bytes > NATIVE_JSON_BYTES - 4096) {
|
||||
inventory.unknown("Native declarations exceed the 4 MiB retained JSON allowance; remaining declarations are unknown.");
|
||||
return inventory.result();
|
||||
}
|
||||
StringBuilder descriptor = new StringBuilder((int) characters).append('(');
|
||||
for (CharSequence parameter : method.getParameterTypes()) descriptor.append(parameter);
|
||||
descriptor.append(')').append(returnType);
|
||||
Map<String, Object> row = Map.of("source_index", inventory.methods.size(),
|
||||
"class_name", className, "method_name", methodName, "descriptor", descriptor.toString(),
|
||||
"dex_entry", path, "dex_entry_index", entryIndex, "class_index", classIndex,
|
||||
"method_index", method.getMethodIndex());
|
||||
if (!inventory.retain(row, bytes)) return inventory.result();
|
||||
}
|
||||
}
|
||||
inventory.examinedClasses++;
|
||||
}
|
||||
inventory.examinedDexEntries++;
|
||||
} catch (IOException | RuntimeException failure) {
|
||||
if (failure instanceof java.util.concurrent.CancellationException) throw (RuntimeException) failure;
|
||||
inventory.unknown("Root DEX native declarations could not be fully read from " + path + ": "
|
||||
+ failure.getClass().getSimpleName()
|
||||
+ (failure.getMessage() == null ? "" : " (" + failure.getMessage() + ")"));
|
||||
}
|
||||
}
|
||||
} catch (IOException failure) {
|
||||
// A failed archive close must fail the operation so the provider retires
|
||||
// its owned JVM; do not cache a result with lost file-resource ownership.
|
||||
throw new IllegalArgumentException("APK ZIP native declaration inventory could not finish its reader", failure);
|
||||
}
|
||||
return inventory.result();
|
||||
}
|
||||
|
||||
/** Original archive identity, never a deobfuscated basename or name suffix. */
|
||||
private ManifestSnapshot manifest(JadxSession current) {
|
||||
if (manifestSession != current || manifestSnapshot == null) {
|
||||
@@ -270,7 +480,7 @@ class ReaJadxBridge {
|
||||
.map(Object::toString).collect(Collectors.joining(", "))
|
||||
+ "): " + method.getReturnType().toString();
|
||||
return new MethodSnapshot(name, rawName, shortId, List.copyOf(bodyAbsenceMarkers), Map.of(
|
||||
"name", name, "signature", signature,
|
||||
"name", name, "raw_name", rawName, "signature", signature,
|
||||
"dex_descriptor", descriptor,
|
||||
"is_constructor", method.isConstructor(), "def_pos", 0));
|
||||
}).toList();
|
||||
@@ -280,8 +490,11 @@ class ReaJadxBridge {
|
||||
List<Map<String, Object>> valuedFields = new ArrayList<>();
|
||||
boolean anyValue = false;
|
||||
for (FieldNode field : orderedFields) {
|
||||
// Raw DEX identity for mapping lookups; the display type can carry generics.
|
||||
Map<String, Object> entry = Map.of("name", field.getAlias(),
|
||||
"type", field.getType().toString(), "def_pos", 0);
|
||||
"raw_name", field.getFieldInfo().getName(),
|
||||
"type", field.getType().toString(),
|
||||
"dex_type", TypeGen.signature(field.getFieldInfo().getType()), "def_pos", 0);
|
||||
fields.add(entry);
|
||||
Map<String, Object> value = dexStaticValue(field);
|
||||
if (value == null) valuedFields.add(entry);
|
||||
@@ -293,10 +506,11 @@ class ReaJadxBridge {
|
||||
}
|
||||
}
|
||||
List<String> inner = node.getInnerClasses().stream().map(ClassNode::getFullName).toList();
|
||||
List<String> innerRaw = node.getInnerClasses().stream().map(ClassNode::getRawName).toList();
|
||||
Map<String, Object> summary = Map.of(
|
||||
"full_name", cls.getFullName(), "raw_name", cls.getRawName(), "name", cls.getName(),
|
||||
"method_count", methods.size(), "field_count", fields.size(),
|
||||
"inner_class_count", inner.size(), "inner_classes", inner,
|
||||
"inner_class_count", inner.size(), "inner_classes", inner, "inner_class_raw_names", innerRaw,
|
||||
"methods", methods.stream().map(MethodSnapshot::summary).toList(), "fields", List.copyOf(fields));
|
||||
// DEX static values are opt-in, so method and reference lookups keep the member-only reply.
|
||||
Map<String, Object> summaryWithValues = summary;
|
||||
@@ -470,6 +684,8 @@ class ReaJadxBridge {
|
||||
"available_processors", Runtime.getRuntime().availableProcessors(),
|
||||
"java_version", System.getProperty("java.version"),
|
||||
"metadata_scope", "parsed_members"));
|
||||
if (name.equals("rea_native_declarations"))
|
||||
return json(nativeDeclarations(Path.of(string(args, "path"))));
|
||||
JadxSession current = session();
|
||||
if (name.equals("get_app_info")) return json(manifest(current).summary());
|
||||
if (name.equals("get_android_manifest"))
|
||||
@@ -581,7 +797,7 @@ class ReaJadxBridge {
|
||||
SessionHolder holder = new SessionHolder(defaults);
|
||||
ServerCapabilities capabilities = new ServerCapabilities(
|
||||
new ServerCapabilities.Tools(null), null, null, null, null, null, null, Map.of());
|
||||
Server server = new Server(new Implementation("rea-jadx-bridge", "7", null, null, null),
|
||||
Server server = new Server(new Implementation("rea-jadx-bridge", "9", null, null, null),
|
||||
new ServerOptions(capabilities), "", ignored -> Unit.INSTANCE);
|
||||
SessionToolsKt.registerSessionTools(server, holder);
|
||||
ClassToolsKt.registerClassTools(server, holder);
|
||||
@@ -601,6 +817,11 @@ class ReaJadxBridge {
|
||||
new ToolSchema(null, new kotlinx.serialization.json.JsonObject(Map.of()), List.of(), null),
|
||||
"Observed worker JVM and metadata scope", null, null, null, null, null, null);
|
||||
server.addTool(diagnostics, (connection, request, continuation) -> bridge.handle("rea_jvm_status", request.getArguments()));
|
||||
registerBridgeTool(server, bridge, "rea_native_declarations",
|
||||
new ToolSchema(null, new kotlinx.serialization.json.JsonObject(Map.of("path",
|
||||
new kotlinx.serialization.json.JsonObject(Map.of("type",
|
||||
kotlinx.serialization.json.JsonElementKt.JsonPrimitive("string"))))), List.of("path"), null),
|
||||
"Original ACC_NATIVE declarations from the admitted APK's standard root DEX members, without loading or decompiling the APK.");
|
||||
for (String name : List.of("get_app_info", "get_android_manifest")) {
|
||||
String description = name.equals("get_app_info")
|
||||
? "Namespace-aware summary of the exact root AndroidManifest.xml resource."
|
||||
|
||||
@@ -2099,10 +2099,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
requireKeys(params, Set.of("document", "address"));
|
||||
requireDocument(params);
|
||||
Address query = requireAddress(params, "address");
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(query);
|
||||
if (function == null && query.isMemoryAddress()) {
|
||||
function = currentProgram.getFunctionManager().getFunctionContaining(query);
|
||||
}
|
||||
Function function = functionAtOrContaining(query);
|
||||
JsonObject result = new JsonObject();
|
||||
result.addProperty("query_address", canonicalAddress(query));
|
||||
if (function != null) {
|
||||
@@ -2118,10 +2115,9 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
}
|
||||
|
||||
private JsonArray search(JsonObject params, boolean procedureSearch) throws Exception {
|
||||
requireKeys(
|
||||
params,
|
||||
Set.of("pattern", "mode", "case_sensitive", "document")
|
||||
);
|
||||
Set<String> keys = new HashSet<>(Set.of("pattern", "mode", "case_sensitive", "document"));
|
||||
if (params.has("literal_ascii_candidate")) keys.add("literal_ascii_candidate");
|
||||
requireKeys(params, keys);
|
||||
requireDocument(params);
|
||||
String expression = requireString(params, "pattern");
|
||||
String mode = requireString(params, "mode");
|
||||
@@ -2132,9 +2128,18 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
List<InventoryItem> inventory = procedureSearch
|
||||
? procedures().stream().map(FunctionEntry::item).toList()
|
||||
: strings();
|
||||
ValueMatcher matcher = mode.equals("literal")
|
||||
? literalMatcher(expression, caseSensitive)
|
||||
: regexMatcher(expression, caseSensitive);
|
||||
ValueMatcher matcher;
|
||||
if (mode.equals("literal") && !caseSensitive) {
|
||||
if (!params.has("literal_ascii_candidate"))
|
||||
throw new RequestFailure("invalid_request", "Insensitive literal search requires an ASCII candidate");
|
||||
matcher = literalCandidateMatcher(optionalString(params, "literal_ascii_candidate"));
|
||||
} else {
|
||||
if (params.has("literal_ascii_candidate"))
|
||||
throw new RequestFailure("invalid_request", "ASCII candidate applies only to insensitive literals");
|
||||
matcher = mode.equals("literal")
|
||||
? literalMatcher(expression)
|
||||
: regexMatcher(expression, caseSensitive);
|
||||
}
|
||||
JsonArray items = new JsonArray();
|
||||
for (InventoryItem item : inventory) {
|
||||
monitor.checkCancelled();
|
||||
@@ -2291,6 +2296,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
return function;
|
||||
}
|
||||
|
||||
/** Exact entries include externals; containment applies only to memory addresses. */
|
||||
private Function functionAtOrContaining(Address address) {
|
||||
Function function = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
return function == null && address.isMemoryAddress()
|
||||
@@ -2995,7 +3001,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
if (!currentProgram.getLanguageID().getIdAsString().startsWith("AARCH64:")) {
|
||||
return null;
|
||||
}
|
||||
Function function = containingFunction(jumpTable.getSwitchAddress());
|
||||
Function function = functionAtOrContaining(jumpTable.getSwitchAddress());
|
||||
if (function == null) return null;
|
||||
|
||||
List<Instruction> instructions = new ArrayList<>();
|
||||
@@ -3495,7 +3501,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
|
||||
private boolean unrepresentedCaller(Reference reference, Set<Function> callers) {
|
||||
if (!reference.getReferenceType().isCall()) return false;
|
||||
Function caller = containingFunction(reference.getFromAddress());
|
||||
Function caller = functionAtOrContaining(reference.getFromAddress());
|
||||
return caller == null || !callers.contains(caller);
|
||||
}
|
||||
|
||||
@@ -3642,7 +3648,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
void observe(Reference reference) {
|
||||
if (!reference.getReferenceType().isCall()) return;
|
||||
// Reference identity follows the same containing-function owner as referenceEdge.
|
||||
Function target = containingFunction(reference.getToAddress());
|
||||
Function target = functionAtOrContaining(reference.getToAddress());
|
||||
if (returnedCallees != null && (target == null || !returnedCallees.contains(target)))
|
||||
unrepresented++;
|
||||
if (target == null) unresolved(reference.getFromAddress(),
|
||||
@@ -3812,8 +3818,8 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
JsonObject result = new JsonObject();
|
||||
result.addProperty("source_address", canonicalAddress(reference.getFromAddress()));
|
||||
result.addProperty("target_address", canonicalAddress(reference.getToAddress()));
|
||||
Function source = containingFunction(reference.getFromAddress());
|
||||
Function target = containingFunction(reference.getToAddress());
|
||||
Function source = functionAtOrContaining(reference.getFromAddress());
|
||||
Function target = functionAtOrContaining(reference.getToAddress());
|
||||
result.add(
|
||||
"source_procedure",
|
||||
source == null ? JsonNull.INSTANCE : procedureIdentity(source)
|
||||
@@ -3848,14 +3854,6 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Function containingFunction(Address address) {
|
||||
Function result = currentProgram.getFunctionManager().getFunctionAt(address);
|
||||
if (result == null && address.isMemoryAddress()) {
|
||||
result = currentProgram.getFunctionManager().getFunctionContaining(address);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String procedureName(Function function) {
|
||||
Symbol symbol = function.getSymbol();
|
||||
return symbol == null ? function.getName() : symbol.getName(true);
|
||||
@@ -4707,11 +4705,18 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
return source.name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
private static ValueMatcher literalMatcher(String pattern, boolean caseSensitive) {
|
||||
String needle = caseSensitive ? pattern : pattern.toLowerCase(Locale.ROOT);
|
||||
private static ValueMatcher literalMatcher(String pattern) {
|
||||
return value -> value.contains(pattern);
|
||||
}
|
||||
|
||||
// REA's host owns Unicode simple folding. Keep all non-ASCII source values
|
||||
// for its final predicate, and filter ASCII-only values without Java regexes.
|
||||
private static ValueMatcher literalCandidateMatcher(String asciiPattern) {
|
||||
if (asciiPattern != null && asciiPattern.chars().anyMatch(character -> character > 127))
|
||||
throw new RequestFailure("invalid_request", "ASCII candidate contains a non-ASCII character");
|
||||
return value -> {
|
||||
String candidate = caseSensitive ? value : value.toLowerCase(Locale.ROOT);
|
||||
return candidate.contains(needle);
|
||||
if (value.chars().anyMatch(character -> character > 127)) return true;
|
||||
return asciiPattern != null && value.toLowerCase(Locale.ROOT).contains(asciiPattern);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -183,6 +183,7 @@ what to record next; hints never change what is served:
|
||||
| `side-effect` | The write changed something besides its own entity, which the environment does not model. |
|
||||
| `unconfirmed` | No later read showed the effect. Read the entity and its list after the write. |
|
||||
| `incomplete-entities` | The write is confirmed, but the views that show its entity cannot render it in full. Read the written entity through every view that lists it. |
|
||||
| `unknown-clock` | The learned rules generate timestamps, but the capture establishes no global served clock start. Record usable start times and completed durations for every request. |
|
||||
|
||||
The bundle ships `evidence.json`, the whole capture Evidence, response bodies
|
||||
included. Inspection excludes the values of the standard authentication headers
|
||||
@@ -204,7 +205,10 @@ attached and a transaction no record represents, and each transaction URL's
|
||||
query once. Bodies larger than 4 MiB of UTF-8 text are not
|
||||
scanned; `credential-scan-incomplete` counts them and lists up to 20 record or
|
||||
event pointers, including base64 bodies whose decoded scan was cut. An empty name
|
||||
warning does not establish that these bodies were checked. Names do not establish sensitivity,
|
||||
warning does not establish that these bodies were checked. A browser scenario's
|
||||
saved values (`save` and `save_response`) named like credentials but not marked
|
||||
`secret: true` are recorded unredacted; `credential-named-saved-values` lists up
|
||||
to 20 of them by parameter pointer. Names do not establish sensitivity,
|
||||
so the build never refuses on them. Capture
|
||||
|
||||
Evidence also records the capture file's absolute path (`subject.local_path`,
|
||||
@@ -402,7 +406,8 @@ 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
|
||||
record with the most matches; ties keep manifest order. A query argument accepts
|
||||
one string or an array of strings for repeated values; the array is matched
|
||||
one string, a number or boolean sent as its JSON text, or an array of strings for
|
||||
repeated values; the array is matched
|
||||
against every occurrence in captured order. The raw recorded query remains the
|
||||
replay evidence. The result reports
|
||||
where the answer came from:
|
||||
@@ -609,8 +614,9 @@ 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 accept an optional string or array of strings (for
|
||||
repeated values in captured order); write methods accept an
|
||||
query parameter names accept an optional string, number or boolean (a number or
|
||||
boolean is sent as its JSON text) or array of strings (for repeated values in
|
||||
captured order); write methods accept an
|
||||
optional `body` object described by the recorded top-level key types. Each
|
||||
input keeps its own argument: a query name equal to a path parameter's name is
|
||||
advertised as `query_<name>`, a query name longer than 64 characters as
|
||||
@@ -764,11 +770,19 @@ sending a `derived` rule's member to an entity that does not hold the value the
|
||||
recorded call found, a nested clock on an entity holding no such object, and 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
|
||||
any. A served delete of a type whose item view has a `deleted_flag` (the
|
||||
member, `deleted`, `isDeleted` or `is_deleted`, its reads set `true` on a
|
||||
record the application soft-deleted, as EspoCRM does) keeps the entity until
|
||||
`data/reset` or `data/add`, within the size `data/add` loads, so a read of it by
|
||||
id answers its last fields with that flag `true`. 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
|
||||
id, tool, field and write count, skipping held values. If `write_clock` is null,
|
||||
plans needing `clock`, `held-clock`, or `nested-clock` retain their learned rules
|
||||
but are withheld with `unknown-clock`; other confirmed plans can still be served.
|
||||
`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"`; a bulk answer adds
|
||||
|
||||
+253
-2
@@ -30,8 +30,9 @@ code units; follow `coverage.next_offset`. The page preserves `source_status` an
|
||||
`reported_total_bytes`: exhausting retained text does not make a partial decoded
|
||||
manifest complete. Complete source Evidence remains exportable under the existing
|
||||
session lifetime. Servers without retention reject summary before starting JADX.
|
||||
One-shot CLI output remains complete. Older servers require the existing complete
|
||||
request after schema discovery. APK authenticity and runtime behavior remain
|
||||
One-shot CLI output remains complete by default. Select `--detail summary` with
|
||||
`--evidence_output /local/capture.json` to retain complete Evidence before returning
|
||||
a linked view. Older servers require the existing complete request after schema discovery. APK authenticity and runtime behavior remain
|
||||
unverified.
|
||||
|
||||
## Manifest component projection
|
||||
@@ -76,6 +77,61 @@ capacity limitation appears only when an actual collection limit was reached.
|
||||
The projection does not merge manifests, expand resource references, or
|
||||
observe runtime enabled/export state.
|
||||
|
||||
`enabled` and `grant_uri_permissions` report only literal component-level
|
||||
`android:enabled` and provider-level `android:grantUriPermissions` declarations.
|
||||
They are `null` when absent or not a literal boolean; missing attributes are not
|
||||
filled from application defaults. A nonliteral declaration gets a limitation.
|
||||
`process` preserves the exact component-level `android:process` spelling (including
|
||||
empty or symbolic values), or `null` when absent or omitted under the inventory-wide
|
||||
1 MiB copy budget. Neither field resolves resources, merges manifest values or
|
||||
establishes the effective runtime process or enabled state. The exact boolean
|
||||
attributes are retained in `enabled_declaration` and
|
||||
`grant_uri_permissions_declaration`, including resource references.
|
||||
|
||||
`intent_filters` preserves each filter's source ordinal, exact priority spelling,
|
||||
actions, categories and individual data declarations (scheme, host, port, path,
|
||||
path prefix/pattern/advanced pattern/suffix and MIME type). These are declarations,
|
||||
not computed Android matching rules. `meta_data` lists names; values remain in the
|
||||
complete decoded manifest. Component, filter, data and metadata `location` values
|
||||
use one-based lines/columns and UTF-16 offsets into that manifest. A component's
|
||||
`declaration_index` preserves its original declaration ordinal, including gaps.
|
||||
|
||||
`declaration_coverage` distinguishes complete, partial and unknown observations.
|
||||
Historical Evidence omits newly introduced fields and defaults coverage to
|
||||
`unknown`; omission never establishes absence. Current records contain the fields,
|
||||
with null for absent or unresolved scalar declarations. The inventory retains at
|
||||
most 32 filters and 64 nested action/category/data/metadata records per component,
|
||||
and shares a 1 MiB structured-value copy budget across components. Omitted values
|
||||
or unsupported filter constructs mark coverage partial and include a limitation;
|
||||
complete retained manifest text remains accessible.
|
||||
|
||||
For a small answer, select `detail: "summary"` with an explicit view:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "android",
|
||||
"facet": "components",
|
||||
"actions": ["android.provider.Telephony.SMS_RECEIVED"],
|
||||
"fields": ["name", "permission", "enabled", "process", "intent_filters"],
|
||||
"offset": 0,
|
||||
"limit": 16
|
||||
}
|
||||
```
|
||||
|
||||
The same JSON works with CLI `--view` or retained `inspect_analysis_view`.
|
||||
`kinds`, `names` and `actions` use exact matching; names accept either the recorded
|
||||
declared or resolved name, actions match any requested action, and different
|
||||
filters combine with AND. `exported` matches only explicit declarations, keeping
|
||||
`exported_default` separate. Empty selectors match nothing. Every selected row
|
||||
retains its parent-array `source_index` and `declaration_coverage`; source coverage,
|
||||
parent identity and limitations remain alongside the page. Follow
|
||||
`coverage.next_offset`. The 1 MiB projection budget can shorten a page; a single
|
||||
oversized row requires fewer selected fields. Exhausting a partial source does
|
||||
not establish complete manifest coverage. `facet: "component-summary"` applies
|
||||
the same filters and counts kinds, declaration coverage and explicit/default
|
||||
exported values separately. Both adapters use the same retained projection;
|
||||
repeated pages do not reload JADX.
|
||||
|
||||
The service `foreground_service_type` field preserves the declared attribute,
|
||||
including an empty value or surrounding spaces; `null` means the attribute is
|
||||
absent or the component is not a service. This field does not validate service
|
||||
@@ -230,6 +286,162 @@ instructions into field declarations, leaving an empty or incomplete method
|
||||
body. The selected method's disassembly preserves those instructions and retains
|
||||
the same source byte limit and explicit truncation reporting.
|
||||
|
||||
## Apply an R8/ProGuard mapping
|
||||
|
||||
Release builds shrunk by R8 or ProGuard rename classes and members. Select the
|
||||
build's `mapping.txt` with `mapping_path` on `inspect_android_class` or
|
||||
`inspect_android_method`, or `--mapping-path` on the matching CLI command:
|
||||
|
||||
```sh
|
||||
rea inspect-android-class /path/Example.apk a.b --mapping-path /path/mapping.txt \
|
||||
--detail summary --evidence_output /tmp/class-evidence.json
|
||||
```
|
||||
|
||||
For agent workflows, select `detail: "summary"` on class and method inspection.
|
||||
It preserves the complete normalized member inventory or selected method body,
|
||||
including mapping annotations, while retaining duplicate raw provider calls in
|
||||
the complete parent Evidence. The reply links that parent's identity and digest;
|
||||
export it with `export_evidence_bundle` or read its summary again through
|
||||
`inspect_analysis_view`. CLI summaries require `--evidence_output` and return
|
||||
the portable bundle path. Omitted or `complete` detail preserves complete inline
|
||||
Evidence. Search and reference operations retain their existing contracts.
|
||||
Symbol summary views admit at most **1 MiB**, including view context. An admitted
|
||||
method's source can already consume that amount; a larger combined summary
|
||||
fails explicitly instead of silently truncating facts. MCP refusal includes
|
||||
the retained parent ID. Select complete detail, or inspect one method rather
|
||||
than a whole class, when the requested summary does not fit.
|
||||
|
||||
The mapping path must be absolute. Selectors still take the observed names, such as
|
||||
`a.b`, and observed rows are unchanged. The result adds one `mapping` block with
|
||||
the file's path, SHA-256 and size, the header values the file reports
|
||||
(`compiler`, `compiler_version`, `min_api`, `map_version`, `pg_map_id`,
|
||||
`pg_map_hash`), valid record counts and up to 16 malformed line samples. Its
|
||||
`symbols` list has one entry per observed class, inner class, method and field;
|
||||
`inspect_android_method` lists the class and the selected method. `coverage`
|
||||
counts each resolution status. With summary delivery, these unchanged facts are
|
||||
under the view's `summary` field; the view separately reports source coverage.
|
||||
|
||||
Lookups use the bridge's raw DEX names, not JADX display aliases such as a
|
||||
renamed reserved word. Each symbol resolves as:
|
||||
|
||||
- `mapped`: exactly one record matches. A class needs one record for its raw
|
||||
name (`verified_by: "class"`). A method must also match its DEX prototype
|
||||
(`"descriptor"`) and a field its DEX type (`"type"`). R8 residual signature
|
||||
metadata is used when present; otherwise original types are translated
|
||||
through the file's class records.
|
||||
- `ambiguous`: `multiple-records`, `descriptor-mismatch`, `type-mismatch`,
|
||||
`ambiguous-class` or `residual-signature-conflict`, with `candidate_count` and
|
||||
up to 8 candidates. Conflicting residual metadata never selects a winner. A name match
|
||||
whose prototype or type does not verify is never reported as mapped.
|
||||
- `unmapped`: no valid record matched the raw identity.
|
||||
- `unknown` with reason `projection-budget`: this claim did not fit the combined
|
||||
reply budget. The observed raw symbol remains present; `coverage.unknown`
|
||||
counts these omissions. Inspect that specific class or method separately,
|
||||
or consult the selected local mapping file for complete source records.
|
||||
|
||||
A line continues an inline frame stack when it repeats the previous line's
|
||||
minified range and obfuscated name and gives a single call-site line, such as
|
||||
`:7`. Only the outermost original of a stack becomes a candidate. Original
|
||||
line numbers and source files are not projected. Malformed records are counted
|
||||
and skipped, so an `unmapped` symbol might be described by one of them. A file
|
||||
that is missing, not a regular file, not UTF-8, larger than the byte limit or
|
||||
without any class record, such as `usage.txt` or `seeds.txt`, is refused before
|
||||
JADX is used. Requests read their mappings one at a time, in the same queue as
|
||||
the JADX work and under the same operation deadline. A mapping failure therefore never starts or retires the JADX
|
||||
session, and a different mapping reuses the loaded APK.
|
||||
|
||||
## Link native declarations to JNI candidates
|
||||
|
||||
When advertised, `inspect_android_jni_bindings` links original `ACC_NATIVE`
|
||||
declarations from standard root `classes*.dex` members to bundled ELF libraries.
|
||||
The supplied JAR's DEX reader preserves duplicate declarations before decompiler
|
||||
deduplication. This operation does not load the APK into the decompiler.
|
||||
MCP defaults to retained summary delivery when `detail` is omitted; select
|
||||
`complete` explicitly to receive the full report inline.
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/absolute/Example.apk",
|
||||
"class_name": "org.conscrypt.NativeCrypto",
|
||||
"method_names": ["EVP_PKEY_new_RSA"],
|
||||
"abis": ["arm64-v8a"],
|
||||
"detail": "summary"
|
||||
}
|
||||
```
|
||||
|
||||
Class/method names and optional `descriptors` select raw DEX identities.
|
||||
`library_paths` selects exact logical APK paths such as
|
||||
`lib/arm64-v8a/libconscrypt_jni.so`; each library's `source_path` preserves its
|
||||
original ZIP spelling. Omitted filters include all scoped facts; `[]` matches
|
||||
none. Class selection never narrows the global inventory used for table-class
|
||||
attribution.
|
||||
|
||||
Independent `declarations`, `libraries`, `candidates` and `bindings` collections
|
||||
have stable IDs and source ordinals. Candidates retain APK/library digests,
|
||||
ABI, function addresses and file offsets. Table candidates also retain section,
|
||||
table and entry identity plus all three name/signature/function pointer slots
|
||||
and their relocation sources. JNI exports follow the
|
||||
[UTF-16 escaping and short-before-long rules](https://docs.oracle.com/en/java/javase/21/docs/specs/jni/design.html#resolving-native-method-names);
|
||||
failed escaping does not acquire an invented export match. Tables require
|
||||
NUL-terminated [Modified UTF-8 strings](https://docs.oracle.com/en/java/javase/21/docs/specs/jni/types.html#modified-utf-8-strings),
|
||||
valid descriptors and executable load mappings. REL, RELA and RELR retain
|
||||
separate provenance; unsupported packed relocations and unresolved pointer
|
||||
spans stay explicit unknowns.
|
||||
|
||||
A static `JNINativeMethod` entry names no class. Attribute it uniquely only
|
||||
when exactly one declaration in the complete recorded native inventory has
|
||||
that `(name, descriptor)` pair. Multiple classes remain ambiguous after a
|
||||
class filter; a partial inventory cannot establish unique attribution.
|
||||
|
||||
Each selected declaration has a row per selected/observed ABI. `matched` means
|
||||
candidate presence was observed; `ambiguous` means multiple observed targets
|
||||
or class associations remain. Binding `coverage` is separate: a matched
|
||||
partial row does not establish complete uniqueness, and an empty partial scan
|
||||
is `unknown`, never `unmatched`. ELF/ABI label mismatches preserve facts without
|
||||
asserting a binding. No result establishes library loading, runtime registration
|
||||
or method invocation.
|
||||
|
||||
Summary returns the first 64 selected binding rows, their declaration/candidate
|
||||
closure and every selected library's identity, coverage and failure reason;
|
||||
counts and page coverage describe the full selected binding set. Selected
|
||||
declaration IDs have separate preview coverage, so native declarations remain
|
||||
visible even when the APK has no bundled ABI libraries. Complete
|
||||
Evidence stays retained. Read exact fields or further pages without reopening
|
||||
files or rerunning analysis:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": { "kind": "retained-evidence", "evidence_id": "ev_<digest>" },
|
||||
"view": {
|
||||
"kind": "android-jni",
|
||||
"collection": "bindings",
|
||||
"offset": 64,
|
||||
"limit": 64,
|
||||
"fields": ["declaration_id", "abi", "status", "coverage", "candidate_ids"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Collections also include `declarations`, `candidates` and `libraries`, with
|
||||
exact filters and batch lookup by declaration/candidate/library IDs. `row_index`
|
||||
is the original parent collection index; DEX and
|
||||
ZIP source ordinals stay separate. Complete detail returns the full report.
|
||||
CLI uses the same selection and delivery contracts. Its common one-shot
|
||||
default remains complete; summary delivery requires an explicit Evidence path:
|
||||
|
||||
```sh
|
||||
rea inspect-android-jni-bindings /absolute/Example.apk \
|
||||
--query '{"class_name":"org.conscrypt.NativeCrypto","method_names":["EVP_PKEY_new_RSA"],"abis":["arm64-v8a"]}' \
|
||||
--detail summary --evidence_output /absolute/fresh-jni-evidence.json
|
||||
```
|
||||
|
||||
Optional `--view` accepts the same JSON page and requires summary delivery.
|
||||
Evidence bundles never overwrite files. Complete declarations and one library
|
||||
selection are cached within the immutable APK session. Changing ABI/library
|
||||
selection replaces the scan; class/method selection reuses it. Fresh analysis
|
||||
still validates current caller APK bytes. Idle/close releases the caches;
|
||||
retained Evidence remains historical and independently readable.
|
||||
|
||||
## Interpret the result
|
||||
|
||||
- Package inspection retains decoded manifest XML, summary declarations,
|
||||
@@ -266,6 +478,11 @@ the same source byte limit and explicit truncation reporting.
|
||||
`dex_descriptor`, for example `(I)V`. Display names can be JADX aliases;
|
||||
the descriptor alone is not a complete raw DEX method ID. Overload indices
|
||||
are tied to this artifact and engine, not stable identities across builds.
|
||||
- A `mapping` block appears only when the caller selected `mapping_path`. Its
|
||||
names are claims from that file, not observations of the APK. REA does not
|
||||
check that the mapping belongs to this build; `pg_map_id` is reported, not
|
||||
compared. Evidence keeps the selected path in its parameters and the file's
|
||||
SHA-256 in the result.
|
||||
- Method inspection reports Java or smali, fallback markers and complete/partial
|
||||
returned text. Decompiled source is a derived representation. A complete text
|
||||
result does not establish complete semantics or a byte-identical reconstruction.
|
||||
@@ -355,6 +572,19 @@ target/configuration changes, failure, timeout, cancellation, MCP disconnect or
|
||||
server shutdown. One-shot CLI commands always join cleanup before returning.
|
||||
REA never writes to the original APK or launches target code.
|
||||
|
||||
JNI scans reuse the analyzer process without loading the APK into the
|
||||
decompiler. They admit at most 64 MiB per DEX member and 256 MiB of DEX bytes,
|
||||
with a 4 MiB native-declaration JSON allowance before MCP string escaping.
|
||||
Native libraries are processed sequentially: one 64 MiB buffer, 256 MiB total
|
||||
selected read work, and a 16 MiB parsed-library-facts allowance. ZIP inventory
|
||||
and library counts also have explicit resource bounds. Unexamined occurrences
|
||||
remain unknown. A complete relationship report has a separate 16 MiB serialized
|
||||
allowance; summaries/pages allow 1 MiB including their provenance envelope.
|
||||
These are resource admissions, not claims about maximum valid Android formats.
|
||||
Select fewer ABI/library occurrences or smaller retained pages when needed.
|
||||
Completed parsed library facts survive failed reader finalization in typed
|
||||
partial observations; the exact reader owner remains available for cleanup retry.
|
||||
|
||||
On Windows, stdin writes preserve stream backpressure and run outside the Node
|
||||
event loop. Cancellation terminates the retained job, including descendants,
|
||||
before workspace cleanup. On Windows, a detached REA helper owns the private
|
||||
@@ -440,6 +670,27 @@ complete, case-sensitive search contract. A protocol frame above **8 MiB**, or c
|
||||
**32 MiB per operation**, fails with a diagnostic instead of returning an incomplete inventory
|
||||
as complete. These are memory-safety boundaries, not undocumented result caps.
|
||||
|
||||
A selected R8/ProGuard mapping is re-read and SHA-256 checked on every call, up
|
||||
to **64 MiB**. The serialized provider keeps one successful parsed index, keyed
|
||||
by byte length and digest with fixed parser options. Identical bytes reuse that
|
||||
index; changed bytes are reparsed, missing files still fail, and each response
|
||||
preserves the currently selected path. The index is released on provider idle
|
||||
retirement or close. Omitting `mapping_path` never applies the cached mapping.
|
||||
During replacement, the old index can coexist with the new parse until it
|
||||
succeeds; these transient allocations count toward process memory.
|
||||
|
||||
Before retaining records, the parser admits an estimated **128 MiB** index
|
||||
representation and **8 MiB** of expanded mapped claims per residual class,
|
||||
including shared header facts. The index allowance accounts for strings and
|
||||
containers; it is not a measured V8 heap cap. Parameter and metadata expansion
|
||||
is admitted before splitting or JSON decoding. These fixed resource bounds
|
||||
have no runtime override; refusal reports `resource_constraint`, the source
|
||||
line and mapping SHA-256. Ambiguous lookups count all candidates while keeping
|
||||
only the first eight in stable file order. A separate **8 MiB** combined claim
|
||||
budget applies to the actual query set, including outer and inner classes,
|
||||
before cloning the report. Claims that do not fit become explicit `unknown`
|
||||
entries; other admitted claims and all observed identities remain available.
|
||||
|
||||
## Real verification
|
||||
|
||||
Download the explicit public fixtures once; this installs no tools:
|
||||
|
||||
@@ -239,6 +239,13 @@ serialized size of the report together with its limitations (which repeat
|
||||
archive names) is then checked against an 8 MiB output budget (the exact check
|
||||
is authoritative); an over-budget report is refused, not truncated.
|
||||
|
||||
Signing blocks admit at most 4096 ID/value pairs; at most 4096 signing-relevant
|
||||
META-INF entries are retained. These fixed counts, signer/lineage counts and the
|
||||
report byte budget return nonretryable `resource_constraint` errors naming the
|
||||
effective allowance. This release has no runtime override for them. Waiting for
|
||||
an active scan cannot raise a fixed count, and complete CLI JSON cannot raise the
|
||||
report budget. Occupied scan-queue capacity remains retryable after a scan finishes.
|
||||
|
||||
The whole-file reader allocates the selected snapshot and bounded read scratch;
|
||||
total process memory exceeds the selected file's size. It also computes the complete
|
||||
file SHA-256, so inspection is not header-only. Content digests are recomputed
|
||||
|
||||
@@ -100,12 +100,13 @@ still suppresses all string projection, including in this mode.
|
||||
- **Metadata comes from apktool.yml as apktool printed it.** Version codes
|
||||
keep their own spelling (`'7'` versus `7`); `package_name` is read from
|
||||
the decoded manifest, not inferred.
|
||||
Apktool 3's emitted `version: 3.x.y` header selects its single-line string
|
||||
dialect: literal hashes, single quotes, empty strings, and the text `null`
|
||||
stay part of the value; producer backslashes and Unicode escapes decode
|
||||
once. Older/tagged documents retain YAML scalar semantics; double-quoted
|
||||
values also retain YAML string semantics.
|
||||
The `version: 2.9.0`-or-later header that Apktool 2.9+ and 3 emit selects
|
||||
their single-line string dialect: literal hashes, single quotes, empty
|
||||
strings, and the text `null` stay part of the value; producer backslashes
|
||||
and Unicode escapes decode once. Older/tagged documents retain YAML scalar
|
||||
semantics; double-quoted values also retain YAML string semantics.
|
||||
This distinction follows the released
|
||||
[2.9.0 metadata writer](https://github.com/iBotPeaches/Apktool/blob/b64e257c9b689eb9630ad0241f2fe4f4a749955b/brut.apktool/apktool-lib/src/main/java/brut/androlib/apk/VersionInfo.java#L38-L42),
|
||||
[3.0.3 metadata writer](https://github.com/iBotPeaches/Apktool/blob/18b5e99cb56ff9451e8aa55b065dcf5bbd616975/brut.apktool/apktool-lib/src/main/java/brut/androlib/meta/VersionInfo.java#L49-L55)
|
||||
and [string escape owner](https://github.com/iBotPeaches/Apktool/blob/18b5e99cb56ff9451e8aa55b065dcf5bbd616975/brut.j.yaml/src/main/java/brut/yaml/YamlStringEscapeUtils.java#L55-L116).
|
||||
- **The manifest is the decoded text**, bounded at 512 KiB and reported as
|
||||
|
||||
@@ -21,14 +21,14 @@ graph TD
|
||||
subgraph "Application Layer"
|
||||
APP["src/application/<br/>Shared CLI/MCP workflows<br/>enhanced analysis and investigations"]
|
||||
SESSION["SessionProviderRouter + BinarySession<br/>one immutable deep binding per target<br/>disjoint auxiliary routing"]
|
||||
REGISTRY["AnalysisProviderRegistry<br/>sorted deep candidates<br/>deterministic selection, no fallback"]
|
||||
REGISTRY["AnalysisProviderRegistry<br/>sorted deep candidates<br/>deterministic selection, no fallback<br/>ProviderInspectionScope: prerequisite observation lifetime"]
|
||||
RECORDS["src/application/investigation/<br/>composed InvestigationRecords + narrow ports<br/>EvidenceLedger and Unknown ownership"]
|
||||
SNAPSHOT["BinarySessionRecords + AnalysisSnapshotCache<br/>binary target/profile snapshots and session file ownership<br/>record coordination and post-commit notifications"]
|
||||
JS_RECON["src/application/javascript/ + src/artifacts/javascript/<br/>JavaScript artifact reconstruction<br/>directory/ASAR reads<br/>AST-only bundle projection"]
|
||||
end
|
||||
|
||||
subgraph "Provider Layers (selected adapters)"
|
||||
PROVIDER_OWNERS["src/providers/<br/>shared deferred client and inspection owners<br/>exact cleanup retry and attributed failures"]
|
||||
PROVIDER_OWNERS["src/providers/<br/>shared deferred client owners<br/>exact cleanup retry and attributed failures"]
|
||||
PWNTOOLS["src/native/pwntools/ + src/native/pwndbg/<br/>BYO offline ELF/core adapters<br/>owned snapshots/Python and optional core-only GDB<br/>unchanged upstream parsers, ABI structures and mapping API"]
|
||||
WASM["src/wasm/<br/>caller-supplied WABT; immutable artifact inspection<br/>owned process supervision and retryable workspace cleanup"]
|
||||
APKSIG["src/apkSignature/<br/>in-process APK Signing Block + v1 reader<br/>bounded single read, no device or execution"]
|
||||
@@ -75,7 +75,7 @@ graph TD
|
||||
end
|
||||
|
||||
subgraph "Domain Layer"
|
||||
DOMAIN["src/domain/<br/>Pure side-effect-free modules<br/>format declarations, Evidence, comparisons, application graphs"]
|
||||
DOMAIN["src/domain/<br/>Pure side-effect-free modules<br/>format declarations, provider selection, Evidence, comparisons, application graphs"]
|
||||
end
|
||||
|
||||
subgraph "Configuration"
|
||||
|
||||
@@ -415,7 +415,8 @@ allowance; exhaustion fails the observation explicitly instead of guessing scope
|
||||
Response metadata parses repeated CDP header field lines independently. The
|
||||
Link projection retains their declarations in order. `csp.directives` lists the
|
||||
directives of every CSP policy in order, across field lines and comma-separated
|
||||
policies, without recording policy boundaries, so a directive name can repeat.
|
||||
policies, without recording policy boundaries, so a directive name can repeat
|
||||
across policies. As in CSP3, a repeated name within one policy is ignored.
|
||||
Single-valued policy fields combine their lines as one comma-separated value,
|
||||
as RFC 9110 specifies. Each link keeps its target in `href` and
|
||||
its relationship context in `context_url` with a separate `context_scope`;
|
||||
|
||||
@@ -51,6 +51,30 @@ 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.
|
||||
|
||||
## Validate a scenario before running it
|
||||
|
||||
`validate-browser-scenario INPUT_JSON` checks one scenario against the same
|
||||
`browserScenarioSchema` refinement that `capture_browser_scenario` admits, and
|
||||
stops there. `INPUT_JSON` may be inline JSON, a JSON file path, or `-` for
|
||||
standard input.
|
||||
|
||||
```bash
|
||||
rea validate-browser-scenario ./browser-scenario.json --json
|
||||
```
|
||||
|
||||
A valid scenario reports `{"valid":true,"actions":<count>,"secrets":<count>}`
|
||||
and exits 0. An invalid one exits 1 and reports the same field paths capture
|
||||
would report, so a correction made here is the correction capture needs:
|
||||
duplicate or reserved step IDs, duplicate secret identities and
|
||||
environment-variable names, undeclared secret references, request-step
|
||||
violations, and unknown fields.
|
||||
|
||||
Validation performs no browser discovery, launch, attachment, or navigation and
|
||||
constructs no provider. It does not read secret environment variables, so a
|
||||
scenario whose declared variables are unset still validates; the missing-value
|
||||
failure belongs to capture. A schema-valid scenario does not prove that the
|
||||
executable or target is available on the host.
|
||||
|
||||
## Minimal launch example
|
||||
|
||||
Save this as `browser-scenario.json`, replacing the executable path with an
|
||||
@@ -173,6 +197,12 @@ distinction: it closes and deletes provider-owned profiles, but only disconnects
|
||||
from an external CDP browser. Real-browser verification checks both outcomes and
|
||||
confirms that an attached external browser remains alive.
|
||||
|
||||
CDP connections leave Playwright's default-context overrides disabled. The
|
||||
selected page receives the declared scenario environment and temporary focus
|
||||
emulation, so actions can complete while that page is in the background.
|
||||
Its environment owner clears these overrides before disconnecting; other pages
|
||||
keep their media settings. Connecting does not create a bootstrap page.
|
||||
|
||||
That cleanup requires REA to remain running. Abrupt termination, including
|
||||
Windows process-tree termination or POSIX `SIGKILL`, can leave the launch
|
||||
profile and Playwright artifacts behind. A profile can retain cookies, history,
|
||||
@@ -207,7 +237,8 @@ HTTP(S) URLs may include ordinary query values and fragments directly. Use
|
||||
ordered structured query entries when a value needs to reference a declared
|
||||
environment-backed secret. Form, storage, and cookie values are either literal
|
||||
strings or declared secret references; request step headers can also read a
|
||||
cookie or local storage value from the page. Raw URL userinfo credentials are rejected.
|
||||
cookie or local storage value from the page, and request steps and `goto`
|
||||
destinations can send [saved values](#saved-values). Raw URL userinfo credentials are rejected.
|
||||
Captured credential-header
|
||||
values are not retained, and declared secret values are redacted automatically.
|
||||
A secret may be declared solely to
|
||||
@@ -400,6 +431,17 @@ data you may change. This scenario creates one item:
|
||||
by default) get smaller: after a 32-character `X-CSRFToken` value, a body over
|
||||
about 47 KiB is kept as `unavailable`. Raise `capture.limits` when the
|
||||
application's responses are larger.
|
||||
- A header can send Basic credentials, `{"source": "basic_credentials", "parts":
|
||||
[username, password]}`: the base64 of `username:password`, after a `prefix`
|
||||
such as `"Basic "` or with none, as some APIs take encoded credentials in
|
||||
their own header. Each part is a literal, a declared secret, a saved value, a
|
||||
cookie or a local storage entry, so a header a frontend builds from a login
|
||||
token can be sent too; the password is never a literal other than empty, since
|
||||
Evidence records literals as written, and a username with a colon fails the
|
||||
step, since Basic authentication ends the username at its first colon. The
|
||||
encoded value is redacted however short, as
|
||||
`[REDACTED:page:<step_id>.<header>]`, and parts read from the page are
|
||||
redacted as page values are.
|
||||
- Validation refuses a header name given twice in a step, header names a
|
||||
page's `fetch` cannot set, such as `Cookie`, `Origin`, `Host` or `Sec-*`, and
|
||||
`User-Agent`, which Chrome drops; it refuses line breaks and other ASCII
|
||||
@@ -425,6 +467,143 @@ Captures with request steps state in `limitations` that the steps sent their
|
||||
declared requests through the page's fetch. A scenario without request steps
|
||||
is unchanged.
|
||||
|
||||
## Saved values
|
||||
|
||||
A step can keep a string or number from a JSON response, by name, and a later
|
||||
step can send it, so a scenario can read back, edit and delete an object whose
|
||||
id the application assigns:
|
||||
|
||||
```json
|
||||
{
|
||||
"browser": {
|
||||
"mode": "launch",
|
||||
"executable_path": "/absolute/path/to/chromium"
|
||||
},
|
||||
"start_url": { "url": "http://127.0.0.1:3000/items" },
|
||||
"actions": [
|
||||
{
|
||||
"step_id": "save-item-1",
|
||||
"action": "click",
|
||||
"timeout_ms": 10000,
|
||||
"locator": { "kind": "role", "role": "button", "name": "Save" },
|
||||
"save_response": {
|
||||
"method": "POST",
|
||||
"path": "/api/items",
|
||||
"save": [{ "name": "item_1", "json_pointer": "/id" }]
|
||||
}
|
||||
},
|
||||
{
|
||||
"step_id": "open-item-1",
|
||||
"action": "goto",
|
||||
"timeout_ms": 10000,
|
||||
"destination": { "url": "http://127.0.0.1:3000/items/{saved:item_1}" },
|
||||
"wait_until": "load"
|
||||
},
|
||||
{
|
||||
"step_id": "copy-item-1",
|
||||
"action": "request",
|
||||
"timeout_ms": 10000,
|
||||
"method": "POST",
|
||||
"path": "/api/items/{saved:item_1}/copies",
|
||||
"json": {
|
||||
"source_id": "{saved:item_1}",
|
||||
"title": "Copy of {saved:item_1}"
|
||||
},
|
||||
"expected_status": [201]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- A `request` step saves with `save: [{name, json_pointer, secret}]`, from its
|
||||
own response. A `click` or `press` step saves with `save_response: {method,
|
||||
path, save}`, from a newly observed matching response while the step waits.
|
||||
The recorder watches before the action and excludes requests already running,
|
||||
such as an earlier autosave. Method/path matching does not prove that the UI
|
||||
caused the request: use a path that distinguishes the intended operation from
|
||||
background polling. Multiple observed matches before binding fail as ambiguous;
|
||||
requests starting after this observation window cannot be ruled out. It matches the method and a path on the
|
||||
start origin as the browser spells it, so a path may name `My List` or
|
||||
`My%20List` (`{*}` matches one segment, and the query is ignored), and fails
|
||||
the step unless a 2xx JSON response arrives before its `timeout_ms`; one still
|
||||
being read when the step times out or is cancelled saves nothing. A pointer
|
||||
that names no string or number fails the step, so later steps never send a
|
||||
missing value, as does a response over 4,000,000 characters: a request step
|
||||
stops reading and aborts its fetch there. A UI step reads a body only when
|
||||
its decoded size is bounded at 12,000,000 bytes or less: its received size,
|
||||
or the declared Content-Length of one served from cache, times 1032 for each
|
||||
gzip or deflate coding, the most DEFLATE expands. Other codings and unknown
|
||||
or zero sizes are refused before materializing the body; decoded text over
|
||||
the character limit also fails. The UI action may already have applied.
|
||||
- `{saved:name}` sends a saved value in a request step's `path`, including its
|
||||
query, and in a `goto` destination's `url`, percent-encoded; a destination's
|
||||
structured `query` values are sent as declared. A saved value that makes a
|
||||
path segment `.` or `..`, alone or with the text beside it (including `%2e`),
|
||||
fails the step, since the URL would drop it. In a request step's `json` body,
|
||||
a string that is only `{saved:name}` becomes the saved value with the JSON
|
||||
type it was saved with, so a saved number id is sent as a number, and
|
||||
`{saved:name}` inside a longer string is filled as text. A header value or
|
||||
Basic credentials part sends one as `{"source": "saved", "name"}`. Other
|
||||
braces, such as `{id}`, are sent as written, and so is a percent-encoded
|
||||
`%7Bsaved:name%7D` anywhere but a `goto` URL, whose parsed form spells the
|
||||
braces that way.
|
||||
- Validation refuses a saved value that no earlier step saves. A later save of
|
||||
the same name replaces the value. An integer past 2^53, which JSON parsing
|
||||
would round to another number, and a number that is not finite, such as
|
||||
`1e400`, negative zero, or a value that underflows to zero, such as `1e-400`, fail the step
|
||||
that saves it.
|
||||
- A scenario keeps at most 4,000,000 characters of saved values at once,
|
||||
counting distinct retained redaction spellings, including trimmed variants,
|
||||
of values saved as secret. Replacing a binding releases its live value
|
||||
charge, while secret spellings remain protected for the scenario lifetime.
|
||||
A save past the budget fails before changing the binding.
|
||||
- A value saved with `secret: true` is redacted however short, as a declared
|
||||
secret is, as `[REDACTED:page:<step_id>.<name>]`. The selected source
|
||||
response is protected before retaining its body or header values, including
|
||||
when only headers were requested. If that body cannot be read safely, its
|
||||
body and header values remain unavailable. Before publishing the capture,
|
||||
the selected source transaction's earlier URL, request headers and request
|
||||
body are also protected using the admitted values. Unresolved source values
|
||||
withhold that transaction's affected metadata/content with an explicit
|
||||
limitation. Before publication, retained events are rechecked
|
||||
with the final marked-response values, including immediate follow-up requests
|
||||
and their response bodies, console/page errors, WebSocket text and event URL/name fields. Learned redaction facts are independent of source-identity readiness. Unknown source values withhold only the selected
|
||||
source transaction. Other saved values, such as ids, stay visible, since
|
||||
environments model them. The environment build warns about saved values
|
||||
named like credentials that are not marked secret
|
||||
(`credential-named-saved-values`).
|
||||
- Page-derived cookie/local-storage values and constructed Basic credentials
|
||||
remain redacted only from observations made after they were read/built.
|
||||
They do not retroactively rewrite earlier facts. The final event projection
|
||||
borrows only declared and response-marked patterns; promotion of an already
|
||||
held page value to an explicit response secret preserves its first marker.
|
||||
Projection state is session-local, references admitted pattern/byte owners,
|
||||
and is invalidated on admission or response classification changes.
|
||||
- Screenshots are withheld as `missing` from the start when the scenario plans
|
||||
any response save marked `secret: true`, page-derived or Basic authentication
|
||||
header values, or whenever nonempty sensitive values
|
||||
are already known. Raw pixels cannot be safely text-redacted, so the provider
|
||||
does not request pixels in those cases. This also protects earlier steps and
|
||||
partial failures without retaining an image to scrub later. Other requested
|
||||
artifacts remain available; affected screenshot/aggregate completeness is
|
||||
partial and is not eligible for equality.
|
||||
- Saved URLs and expanded request JSON are admitted before building their expanded strings or
|
||||
serializing. Its allowance is the smaller of Node's string limit and
|
||||
one sixteenth of current V8 available heap bytes, allowing for the expanded
|
||||
tree, serialization, Playwright transport and browser-side copies. Size
|
||||
accounting includes JSON escaping and repeated references; each distinct
|
||||
saved value's size is measured once per request. An oversized request fails
|
||||
before browser dispatch; the complete request envelope, including repeated
|
||||
header values, is checked as well. URL encoding uses a conservative
|
||||
nine-characters-per-UTF-16-unit allowance before encoding a saved value.
|
||||
Reduce the payload/repetitions, or raise the parent
|
||||
Node heap and restart; this is a conservative allocation estimate, not a
|
||||
measurement or guarantee of browser/process-family memory.
|
||||
- Evidence records a request step's empty `save` list as absent, so a scenario
|
||||
that saves nothing records the same parameters and `scenario_sha256` as
|
||||
before saved values existed, and REA versions without saved values read its
|
||||
captures.
|
||||
|
||||
## Network evidence
|
||||
|
||||
`capture.events: ["network"]` retains request, response, completion, failure,
|
||||
@@ -472,8 +651,9 @@ the browser's wall-clock start, and `elapsed_ms`, its time from that start to
|
||||
the end of the response, when the browser reports them. The environment views
|
||||
time scenario records from these, as HAR entries are timed: the browser's start
|
||||
where it reported one, else `observed_at`, which trails it by up to tens of
|
||||
milliseconds while REA reads other responses, and a duration of 0 where the
|
||||
browser reported none. Captures made before these fields existed lack them and
|
||||
milliseconds while REA reads other responses. A duration is retained only from a
|
||||
unique terminal event that reports it; missing or ambiguous durations stay
|
||||
omitted, while an explicitly reported zero remains zero. Captures made before these fields existed lack them and
|
||||
are read in record order. REA versions before them refuse captures that carry
|
||||
them. Scenario comparisons ignore all three (`ignore_network_request_timing`).
|
||||
Requests sharing a URL remain distinct. Redirects link to the preceding
|
||||
|
||||
+81
-4
@@ -51,6 +51,15 @@ module page. See
|
||||
[JavaScript application workflows](javascript-application-workflows.md) for
|
||||
views, feature traces and comparisons that take the same saved Evidence.
|
||||
|
||||
Add `--timings` to a command to write one JSON timing record to stderr. For
|
||||
example, `rea inspect-elf-notes program --json --timings > result.json` keeps
|
||||
stdout as a parseable result and writes
|
||||
`{"rea_timings":{"version":1,"command_ms":42}}` to stderr. `command_ms`
|
||||
measures CLI command dispatch and result delivery; it is not provider-only or
|
||||
analysis-only time. The flag is off by default, and the record omits stages
|
||||
that REA did not measure. Root version reporting does not dispatch a command
|
||||
and has no command timing record.
|
||||
|
||||
## JSON Lines record output
|
||||
|
||||
Use `--format jsonl` to consume row-oriented results one record per line:
|
||||
@@ -241,6 +250,17 @@ Formats 2, 3 and 4 retain header, directory and integrity facts. Compact deliver
|
||||
keeps complete Evidence in the requested bundle. See [Godot PCK](godot-pck.md)
|
||||
for embedded packs, batch queries and unknown encrypted coverage.
|
||||
|
||||
Inspect a UnityFS AssetBundle without running Unity:
|
||||
|
||||
```sh
|
||||
rea inspect-artifact content.bundle --detail summary --evidence_output evidence.json --json
|
||||
rea extract-artifact content.bundle --json
|
||||
```
|
||||
|
||||
Format versions 6 through 8 retain header, block and directory facts with
|
||||
none/LZ4/LZ4HC block decompression. See [UnityFS](unityfs.md) for encryption
|
||||
and LZMA coverage boundaries.
|
||||
|
||||
Inspect a Node.js SEA carrier without running it:
|
||||
|
||||
```sh
|
||||
@@ -251,6 +271,26 @@ rea extract-artifact ./application --json
|
||||
See [Node.js SEA](node-sea.md) for supported layouts, script and asset paths,
|
||||
fuse observations, and the real-fixture verification lane.
|
||||
|
||||
Inventory and extract Intel HEX or S-record regions:
|
||||
|
||||
```sh
|
||||
rea inspect-artifact ./firmware.hex --json
|
||||
rea extract-artifact ./firmware.hex --json
|
||||
```
|
||||
|
||||
See [Intel HEX and S-record images](hex-records.md) for recognition, region
|
||||
names, metadata and limits.
|
||||
|
||||
Inspect and extract stored U-Boot legacy uImage payloads and components:
|
||||
|
||||
```sh
|
||||
rea inspect-artifact ./firmware.bin --detail summary --evidence_output firmware.json --json
|
||||
rea extract-artifact ./firmware.bin --json
|
||||
```
|
||||
|
||||
See [U-Boot uImage](uimage.md) for verified CRCs, physical component ranges,
|
||||
unknown names, resource limits and retained views. Compressed bytes stay stored.
|
||||
|
||||
Inspect local model declarations without loading weights:
|
||||
|
||||
```bash
|
||||
@@ -491,6 +531,11 @@ Dispatching a provider metadata write invalidates the active session's snapshot
|
||||
even if its reply fails: the provider may already have applied the write.
|
||||
Close and reopen the target before importing or saving another snapshot.
|
||||
|
||||
Saved snapshots include only cache entries whose subject identifies the selected
|
||||
target. Unbound observations and observations of child artifacts remain available
|
||||
in the open session and its Evidence bundle; they are excluded from the target's
|
||||
saved replay entries without changing their subjects.
|
||||
|
||||
Snapshots retain eligible target-scoped question histories in full, including
|
||||
mutation Evidence recorded while another target was active. Observations and
|
||||
related questions must still belong to the saved target. If those dependencies
|
||||
@@ -546,6 +591,9 @@ rea compare /absolute/path/to/evidence/left.json /absolute/path/to/evidence/righ
|
||||
rea compare left.json right.json --record_pairs '[{"left_evidence_id":"ev_<left-sha256>","right_evidence_id":"ev_<right-sha256>"}]' --json
|
||||
```
|
||||
|
||||
Migration: replace `rea compare-bundles` with `rea compare`; the former command
|
||||
has been removed. The MCP tool remains `compare_bundles`.
|
||||
|
||||
`--record_pairs` supplies an explicit JSON array of observation pairs, matching
|
||||
MCP `compare_bundles.record_pairs`. Pair IDs must exist on their named sides and
|
||||
be one-to-one. Without pairs, one-sided membership remains unknown; REA does
|
||||
@@ -964,6 +1012,35 @@ values instead of replacing them with an object label. Table widths are measured
|
||||
iteratively, so an admitted row page is not limited by the JavaScript function
|
||||
argument count.
|
||||
|
||||
`--format csv` and `--format tsv` export one selected row collection. Select an
|
||||
exact array path with `--filter-output` and provide comma-separated direct
|
||||
scalar columns with `--columns`; column order is the output column order:
|
||||
|
||||
```bash
|
||||
rea inspect-analysis-view request.json --format csv \
|
||||
--filter-output normalized_result.rows --columns name,address
|
||||
```
|
||||
|
||||
The first line is a REA metadata record,
|
||||
`# rea-delimited-v1 <JSON>`. It carries the selected path, view request, limitations and unknowns,
|
||||
coverage, source coverage and completeness, command, and duration. A metadata
|
||||
value of `null` means that the selected row collection did not provide that
|
||||
fact; it does not mean complete coverage. The following line is the header.
|
||||
CSV records use CRLF line endings; TSV records use LF. Cells containing the
|
||||
delimiter, quotes, or line breaks are quoted and embedded quotes are doubled.
|
||||
Values are emitted as UTF-8 without Unicode normalization. Missing and `null`
|
||||
cells are empty; booleans and finite numbers use their ordinary text forms.
|
||||
String cells and headers that begin with spreadsheet formula syntax are refused
|
||||
with a structured error; JSON retains those values unchanged.
|
||||
|
||||
Delimited output does not flatten nested Evidence or nested field values.
|
||||
It returns a structured error and a nonzero status if the filter does not
|
||||
select exactly one row array, a row is not an object, or a selected cell is
|
||||
nested or formula-leading. JSON remains the complete canonical output; use it
|
||||
to retain fields outside the selected columns or preserve exact formula-leading
|
||||
text. Token counting and token windows are not
|
||||
available for CSV/TSV because slicing would corrupt records or metadata.
|
||||
|
||||
`--filter-output` selects fields from successful command data. Classified failures
|
||||
retain their complete typed diagnostic projection even when the selector matches
|
||||
a field such as `code` or `message`, or names a missing field. `--full-output`
|
||||
@@ -982,10 +1059,10 @@ Cutter when available. This is separate from `--format json`, which selects the
|
||||
CLI result representation; the global `--json` flag selects that same CLI
|
||||
representation.
|
||||
|
||||
Cutter still accepts deprecated `--json=true` and `--json=false` compatibility
|
||||
values. When both forms are present, `--json-output` takes precedence in either
|
||||
argument order. Bare `--json` retains its global meaning of selecting JSON CLI
|
||||
output formatting.
|
||||
Cutter no longer accepts command-local `--json=true` or `--json=false`.
|
||||
Replace these with `--json-output=true` or `--json-output=false`, respectively.
|
||||
Combine `--json-output` with bare `--json` when both Cutter command output and
|
||||
the CLI result should use JSON; either argument order is accepted.
|
||||
|
||||
| Status | Meaning |
|
||||
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -14,12 +14,17 @@ interpreter: the npm launcher's `#!/usr/bin/env node` still searches `PATH` for
|
||||
Node. Running that command successfully in a terminal does not establish that
|
||||
the client can launch it.
|
||||
|
||||
For direct JavaScript installations, setup registers the selected runtime
|
||||
For JavaScript installations, setup registers the selected runtime
|
||||
executable and REA script by absolute path. On POSIX, it prefers executable
|
||||
`node` or `bun` and REA aliases on setup's `PATH` only when they resolve to the
|
||||
same selected files. This preserves manager-owned aliases across version updates;
|
||||
otherwise setup uses the selected paths directly. Package-runner registrations keep
|
||||
their selected runner. Setup does not copy your ambient environment into client
|
||||
otherwise setup uses the selected paths directly. This also applies when setup
|
||||
runs through a package runner: retain the selected cache entry and runtime while
|
||||
the registration uses them. Clearing either makes startup fail without resolving
|
||||
another package from the client's project. Restore the same installation before
|
||||
repairing it; an unidentified registration remains untouched. See
|
||||
[installation and recovery](installation.md#package-runners-and-global-installation).
|
||||
Setup does not copy your ambient environment into client
|
||||
settings. To refresh an older registration, preview
|
||||
`rea setup --client <client-id> --skill=false --dry-run`, then run the same command
|
||||
without `--dry-run` and approve the displayed changes. Setup preserves unrelated
|
||||
@@ -74,6 +79,17 @@ Connect Fiddler Everywhere's MCP server separately for HTTP traffic debugging,
|
||||
preserving your REA client entry. See the
|
||||
[setup instructions and public skills](web-network-captures.md#fiddler-everywhere-mcp-and-public-skills).
|
||||
|
||||
## VS Code
|
||||
|
||||
`rea setup --client vscode` configures the default VS Code user profile's
|
||||
`mcp.json`. Setup honors `VSCODE_PORTABLE` and `VSCODE_APPDATA` when they are
|
||||
present in its environment. It cannot infer a running window's named profile
|
||||
or `--user-data-dir`; configure that profile separately when needed.
|
||||
|
||||
`rea setup --client copilot_cli` instead configures Copilot's user
|
||||
`mcp-config.json`. VS Code can forward eligible profile servers to Copilot
|
||||
sessions; see the [VS Code MCP configuration reference](https://code.visualstudio.com/docs/agents/reference/mcp-configuration).
|
||||
|
||||
## GitHub Copilot CLI
|
||||
|
||||
Setup preserves an existing `tools` selection in the REA registration, including
|
||||
@@ -486,17 +502,51 @@ comments and unrelated settings. It resolves that file from `HERMES_HOME`, else
|
||||
from the platform default Hermes itself uses — `%LOCALAPPDATA%\hermes` on
|
||||
Windows, `~/.hermes` elsewhere — including any `HERMES_DATA_DIR_SUFFIX`. Hermes
|
||||
connects an entry unless `enabled` is false, so setup states `enabled: true`.
|
||||
Aliases whose anchor is defined in the `rea` entry retain their original resolved
|
||||
values when setup refreshes or uninstall removes that entry. Setup does not
|
||||
redirect another server's alias to REA's new launcher or policy.
|
||||
This also covers an anchor on the removed registration key. References to
|
||||
definitions outside the entry keep sharing the original value, including when
|
||||
another definition later reuses the same anchor name.
|
||||
|
||||
Hermes personal skills install under the active Hermes home's `skills` directory.
|
||||
Setup, doctor and uninstall follow the root's `active_profile` selection, as
|
||||
plain Hermes CLI commands do. An explicit `HERMES_HOME` pointing to
|
||||
`profiles/<name>` selects that named profile directly. An invalid, missing or
|
||||
deleted sticky profile is reported instead of writing into the default home;
|
||||
it also remains an unresolved skill selection, so setup cannot report a
|
||||
successful empty installation. Overrides nested beneath the native Hermes home
|
||||
use that native home's sticky selection and profile root together, matching
|
||||
[Hermes's root rules](https://github.com/NousResearch/hermes-agent/blob/748c79a1c6873124d84071cdabb4062a75913e1f/hermes_constants.py#L83).
|
||||
Repair the profile or run `hermes profile use default` before retrying.
|
||||
Setup, doctor and uninstall share REA's sticky-profile resolver.
|
||||
A custom `HERMES_HOME` outside the platform default home
|
||||
reads its own `active_profile`. An override physically inside the default home
|
||||
uses that default home's sticky selection and profile root together, including
|
||||
when the final override directory does not yet exist.
|
||||
|
||||
For example, with `HERMES_HOME=~/.hermes/sub` and `~/.hermes/active_profile` set
|
||||
to `coder`, setup selects `~/.hermes/profiles/coder/config.yaml` and that
|
||||
profile's skills directory. It does not read `~/.hermes/sub/active_profile`.
|
||||
Without an outer named selection, this override uses `~/.hermes/sub/config.yaml`.
|
||||
Use a home outside the platform default tree for an independent sticky selection.
|
||||
|
||||
This describes REA's current routing, not full Hermes CLI equivalence.
|
||||
At Hermes commit `748c79a1`, the
|
||||
[sticky lookup](https://github.com/NousResearch/hermes-agent/blob/748c79a1c6873124d84071cdabb4062a75913e1f/hermes_cli/main.py#L612-L632)
|
||||
also reads the outer selection, but
|
||||
[`resolve_profile_env`](https://github.com/NousResearch/hermes-agent/blob/748c79a1c6873124d84071cdabb4062a75913e1f/hermes_cli/profiles.py#L2431-L2461)
|
||||
resolves it beneath the configured `HERMES_HOME`. For nested overrides, confirm
|
||||
the profile Hermes actually uses and point `HERMES_HOME` directly at that
|
||||
`profiles/<name>` directory before setup. Compatibility is tracked in
|
||||
[#3939](https://github.com/morluto/rea/issues/3939).
|
||||
|
||||
REA resolves existing ancestor directories before checking physical containment,
|
||||
including symlinks and junctions, even when the override directory does not exist.
|
||||
An override beneath a symlinked default home therefore uses the default home's
|
||||
sticky selection. If `~/.hermes/link` points outside the default home,
|
||||
`HERMES_HOME=~/.hermes/link/new` instead uses that override root, whether or not
|
||||
`new` exists. Previewed destinations retain the configured path spelling.
|
||||
An unreadable path or dangling alias leaves the home unresolved; repair that path
|
||||
before configuring Hermes. Inspect setup's previewed destinations before applying
|
||||
changes.
|
||||
|
||||
An explicit `HERMES_HOME` pointing to `profiles/<name>` selects that named
|
||||
profile directly, bypassing sticky selection. An invalid, missing or deleted
|
||||
sticky profile is reported instead of writing into the default home; repair the
|
||||
profile or run `hermes profile use default` before retrying. It also remains an
|
||||
unresolved skill selection, so setup cannot report a successful empty installation.
|
||||
REA follows `HERMES_HOME` whitespace trimming, environment-variable expansion,
|
||||
and home expansion before resolving that profile. Setup previews the resolved
|
||||
configuration and skill destinations; doctor and uninstall use those same paths.
|
||||
@@ -513,10 +563,12 @@ installs its skill copy there.
|
||||
## Factory Droid
|
||||
|
||||
For [Factory Droid](https://docs.factory.com/harness/mcp), setup writes
|
||||
`mcpServers.rea` into the user-level `~/.factory/mcp.json`. Entries carry
|
||||
`command`, `args`, and `env`. Droid discovers personal skills from
|
||||
`~/.factory/skills` ([skills](https://docs.factory.com/harness/skills)), so
|
||||
setup installs its skill copy there.
|
||||
`mcpServers.rea` into the user-level `~/.factory/mcp.json` (the
|
||||
`FACTORY_HOME_OVERRIDE` override replaces the home that contains `.factory`).
|
||||
Entries carry `command`, `args`, and `env`. Droid discovers personal skills
|
||||
from `~/.factory/skills` ([skills](https://docs.factory.com/harness/skills),
|
||||
following `FACTORY_HOME_OVERRIDE` when set), so setup installs its skill copy
|
||||
there.
|
||||
|
||||
## Trae
|
||||
|
||||
@@ -589,6 +641,12 @@ boundaries. FreeBuff MCP loading and skill discovery have not been verified
|
||||
with an installed native FreeBuff client/version; filesystem tests cover REA's
|
||||
editing, discovery, and ownership behavior only. Automatic applicability
|
||||
requires the FreeBuff profile directory even when the shared MCP file exists.
|
||||
When uninstall cannot establish FreeBuff or another shared-storage reader from
|
||||
product discovery, a malformed or unreadable shared MCP file is retained
|
||||
unchanged and does not stop other REA removals, including `--purge-data`. When
|
||||
FreeBuff or ZCode product applicability is established or unresolved, the same
|
||||
malformed shared file stops uninstall before removals. See
|
||||
[Diagnose, update, and remove](installation.md#diagnose-update-and-remove).
|
||||
|
||||
FreeBuff setup support requires `[email protected]` or later. Older versions
|
||||
reject `rea setup --client freebuff` as an unsupported client. See the
|
||||
@@ -692,10 +750,6 @@ can override an inherited disable. Lower files and other server entries remain
|
||||
unchanged; a legacy server named `servers` that conflicts with the native table
|
||||
requires manual repair before setup can write.
|
||||
|
||||
When Hermes aliases refer to an anchored REA entry, refreshing or removing REA
|
||||
retains the aliases' original resolved values. Setup does not redirect another
|
||||
server's alias to REA's new launcher or policy.
|
||||
|
||||
With no client selected, the interactive skill choice targets the shared
|
||||
`~/.agents/skills` copy. Selecting a client targets its personal destination
|
||||
when supported. Use `rea setup --skill-client shared --skill` for the shared
|
||||
|
||||
@@ -292,3 +292,25 @@ Use [`inspect_devicetree`](devicetree.md) / `rea inspect-devicetree` on an
|
||||
extracted DTB for its node/property tree, reservations, hardware summary and
|
||||
selected phandle relationships. FDT v16/v17 inspection is portable and requires
|
||||
no external tool or disassembler.
|
||||
|
||||
## Inspect Intel HEX and S-record images
|
||||
|
||||
Use `inspect-artifact` / `inspect_artifact` on an Intel HEX or Motorola S-record
|
||||
file for its address regions, declared start address and record facts, then
|
||||
`extract-artifact` / `extract_artifact` for one raw file per region. Decoding is
|
||||
portable and requires no external tool. See
|
||||
[Intel HEX and S-record images](hex-records.md).
|
||||
|
||||
## Inspect U-Boot legacy uImages
|
||||
|
||||
`inspect-artifact` / `extract-artifact` recognize a legacy uImage by its
|
||||
`0x27051956` magic and inventory it without running or decompressing it.
|
||||
The root facts record the 64-byte header (architecture, OS, type, and
|
||||
compression as raw values and names, load and entry addresses, image name,
|
||||
and timestamp) with the header and data CRC32 verified; the stored payload
|
||||
is extractable as `payload.bin`, and multi-file images additionally expose
|
||||
each sub-image as `image-<n>.bin` from the stored size table. Declared
|
||||
addresses are facts from the header, not proven entry points, and compressed
|
||||
payloads stay as stored. Intel HEX/S-record and FIT images are separate
|
||||
readers and are not covered here. See [U-Boot legacy uImage](uimage.md) for
|
||||
component padding, preserved names, resource policies and verification scope.
|
||||
+12
-3
@@ -1,9 +1,18 @@
|
||||
# Godot PCK archives
|
||||
|
||||
`inspect-artifact` and `extract-artifact` read ordinary Godot PCK formats 2, 3
|
||||
`inspect-artifact` and `extract-artifact` read ordinary Godot PCK formats 1, 2, 3
|
||||
and 4 without running the game or requiring Godot. Official Godot 4.4.1, 4.6.1
|
||||
and 4.7.1 produced these respective formats in verification; other engine
|
||||
releases have not been verified. Format 1 is unsupported.
|
||||
and 4.7.1 produced formats 2, 3 and 4 respectively in verification; other engine
|
||||
releases have not been verified. Format 1 compatibility follows the
|
||||
[Godot 3.5 loader](https://github.com/godotengine/godot/blob/3.5/core/io/file_access_pack.cpp#L201-L242)
|
||||
and [exporter](https://github.com/godotengine/godot/blob/3.5/editor/editor_export.cpp#L1094-L1164)
|
||||
layout and is covered by synthetic standalone and embedded fixtures; an actual
|
||||
Godot 3 export has not been exercised.
|
||||
|
||||
Format 1 uses an 84-byte header, no pack or member flags, and absolute member
|
||||
offsets in the complete source file, including an embedded executable carrier.
|
||||
Its reported flags and file base are zero because those fields are absent.
|
||||
Zero-offset removal records remain unsupported; REA does not apply patches.
|
||||
|
||||
Inspection retains the original header and directory facts, including engine
|
||||
version, flags, declared file count, source paths, offsets and declared MD5.
|
||||
|
||||
@@ -36,7 +36,7 @@ The MCP tool `project_harmony_application_graph` takes the same
|
||||
|
||||
- exact component paths, artifact IDs, and hashes (manifests, Ark bytecode,
|
||||
resources, native libraries, JavaScript, signing)
|
||||
- a packaging-model hint: Stage is claimed only from a `module.json` entry
|
||||
- a packaging-model hint: Stage is claimed only from an exactly cased `module.json` entry
|
||||
outside a classified resource path, FA only from `config.json` outside a
|
||||
classified resource path, otherwise `unknown`
|
||||
- FA resources under `assets/<module>/resources/` as well as Stage `resources/`
|
||||
@@ -46,6 +46,9 @@ The MCP tool `project_harmony_application_graph` takes the same
|
||||
- path-based N-API bridge hypotheses between bytecode and `libs/<abi>` native
|
||||
libraries
|
||||
|
||||
An unavailable manifest can still supply a path-based model hint; its content
|
||||
identity remains unknown. Manifest names follow case-sensitive ZIP member names.
|
||||
|
||||
File and slice occurrences supply component and child-package paths; directory
|
||||
trees and symlinks retain their identities in the source inventory without
|
||||
being classified as code files. Ark and JavaScript runtime hints summarize the
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
# Intel HEX and S-record images
|
||||
|
||||
REA inventories Intel HEX (I8HEX, I16HEX, I32HEX) and Motorola S-record (S19,
|
||||
S28, S37) programming files through `inspect-artifact` / `inspect_artifact`, and
|
||||
materializes their decoded bytes through `extract-artifact` /
|
||||
`extract_artifact`. Decoding is static and needs no external tool.
|
||||
|
||||
```sh
|
||||
rea inspect-artifact ./firmware.hex --json
|
||||
rea inspect-artifact ./firmware.s37 --detail summary --evidence_output evidence.json --json
|
||||
rea extract-artifact ./firmware.hex --json
|
||||
```
|
||||
|
||||
For MCP, open the file with `open_binary`, then call `inspect_artifact`. Summary
|
||||
delivery retains the complete Evidence; use `parent_evidence_id` with
|
||||
`inspect_analysis_view` to read selected regions and fields. `extract_artifact`
|
||||
returns a fresh `output_root` containing one raw file per region.
|
||||
|
||||
## Recognition
|
||||
|
||||
A file is recognized only when its first line, starting at byte 0, is a fully
|
||||
valid record: correct start character, hex digits, byte count, checksum, known
|
||||
record type and fixed length. The file name does not matter. A byte-order mark,
|
||||
a leading blank line or an invalid first record leaves the file unrecognized,
|
||||
so it falls through to plain `file` classification. Recognition never searches
|
||||
for a record later in the file. The container formats are `intel-hex` and
|
||||
`srec`.
|
||||
|
||||
## Regions and metadata
|
||||
|
||||
Each inventory entry is one address-contiguous region of decoded bytes, named
|
||||
`0x<start>-0x<end>.bin` with an inclusive end address of eight lowercase hex
|
||||
digits, for example `0x08000000-0x0800001f.bin`. Regions are listed in ascending
|
||||
address order. Out-of-order records are sorted into regions; gaps separate
|
||||
regions and are never filled.
|
||||
|
||||
Region `format_metadata` (`hex-record-region`) records `start_address`,
|
||||
`end_address`, `length`, `record_count`, and `first_line`/`last_line`: the
|
||||
1-based line span of the contributing data records.
|
||||
|
||||
Root `format_metadata` (`hex-records`) records:
|
||||
|
||||
| Field | Meaning |
|
||||
| ------------------------------------------------- | --------------------------------------------------------------------------------- |
|
||||
| `encoding`, `variant` | `intel-hex` or `srec`; the variant derived from the record types seen, or `mixed` |
|
||||
| `line_count`, `record_count`, `data_record_count` | Lines read, non-blank records, and data records |
|
||||
| `data_bytes`, `duplicate_bytes`, `region_count` | Unique decoded bytes, bytes rewritten with identical values, and regions |
|
||||
| `lowest_address`, `highest_address` | Address bounds of the decoded bytes, or `null` without data |
|
||||
| `termination` | Whether Intel `01` or S-record `S7`/`S8`/`S9` was present |
|
||||
| `start_address`, `start_address_record` | The Intel `05` EIP or the `S7`/`S8`/`S9` address, with its record type |
|
||||
| `start_segment_cs`, `start_segment_ip` | The Intel `03` CS:IP pair |
|
||||
| `header_hex`, `header_text` | S-record `S0` data as hex, and as text only when every byte is printable ASCII |
|
||||
| `declared_data_record_count` | The last `S5`/`S6` count, validated against the data records before it |
|
||||
|
||||
`variant` is `null` for an S-record file in which no data or termination
|
||||
record establishes an address width. Start addresses are declared facts, not
|
||||
proven entry points.
|
||||
|
||||
## Facts, limitations and failures
|
||||
|
||||
| Situation | Outcome |
|
||||
| ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
|
||||
| Gaps between regions | Separate regions; never zero-filled |
|
||||
| Out-of-order records | Sorted into regions |
|
||||
| An address written twice with the same value | Accepted and counted in `duplicate_bytes` |
|
||||
| An address written twice with different values | Fails, naming the address and the line spans of both writes |
|
||||
| Checksum mismatch, odd hex length, non-hex character, byte count disagreeing with the line | Fails with the line, declared and computed values, and record type |
|
||||
| Line longer than 521 (Intel) or 514 (S-record) characters, excluding the line ending | Fails before the line is decoded |
|
||||
| Intel type `06` or higher, `S4`, wrong fixed length for Intel `01`–`05` or `S5`–`S9` | Fails |
|
||||
| Missing Intel `01` or `S7`–`S9` | Regions are returned; coverage is unknown and the file may be truncated |
|
||||
| A non-blank record after termination, or a second `S0` | Fails; blank lines are allowed anywhere |
|
||||
| `S5`/`S6` count different from the data records before it | Fails |
|
||||
| Termination type not matching the data address width | Reported as a limitation; the declared fact is kept |
|
||||
| Conflicting repeated `03`/`05` start records | Fails; identical repeats are allowed |
|
||||
| An Intel data record whose 16-bit offset wraps past `0xFFFF` | Fails: producers disagree on whether the address wraps or continues linearly |
|
||||
| I16HEX data above `0xFFFFF`, or data crossing the S1/S2/S3 address width | Fails |
|
||||
|
||||
Lowercase hex, LF and CRLF line endings, and trailing spaces or tabs are
|
||||
accepted. A CR not followed by LF is an invalid character. Failures apply to
|
||||
the whole file and return no partial regions.
|
||||
|
||||
## Limits
|
||||
|
||||
The file must be at most 128 MiB. Every data byte needs two hex digits, so the
|
||||
decoder reserves at most half the file size for decoded bytes before reading,
|
||||
and stores only written addresses. The decoder retains at most 65,536
|
||||
address-discontiguous record runs before merging them into regions. A run is a
|
||||
sequence of consecutive records whose addresses continue each other. Both are
|
||||
fixed resource bounds, not format limits, and fail as limits (`file-size` and
|
||||
`capacity`) with no runtime override. Configurable ceilings are tracked in
|
||||
[#6176](https://github.com/morluto/rea/issues/6176). The line-length limits are
|
||||
the one-byte record count: Intel HEX allows 255 data bytes, while S-record
|
||||
counts include address and checksum bytes.
|
||||
|
||||
Decoded regions are cached only for the reader's lifetime. Each open checks
|
||||
its admitted carrier identity again. Region streams copy at most 64 KiB per
|
||||
chunk, so consumers cannot mutate cached bytes and opening a large region does
|
||||
not copy it in full. Caller cancellation keeps its exact reason, and closing
|
||||
the reader waits for active region streams to close.
|
||||
|
||||
## Analyzing a region
|
||||
|
||||
Inventory does not establish the CPU, byte order or memory map, or that a
|
||||
declared start address is executable. To disassemble a region, extract it and
|
||||
open the region file with `open_binary` using format `raw-binary`, an
|
||||
architecture you choose, and `entry_point` set to the region start address;
|
||||
raw-binary maps file offset 0 at `entry_point`. Each region is opened
|
||||
separately, so references between regions are not resolved. A caller-selected
|
||||
Ghidra language and base address for raw-binary imports is tracked in
|
||||
[#4246](https://github.com/morluto/rea/issues/4246); Thumb-only Cortex-M images
|
||||
may be refused or decoded in ARM state until
|
||||
[#5744](https://github.com/morluto/rea/issues/5744) is resolved.
|
||||
|
||||
## Verification
|
||||
|
||||
Fixtures with computed checksums cover supported record types, checksums,
|
||||
termination, address gaps and overlaps, resource refusals, inventory, extraction
|
||||
and reader lifecycle. CLI and stdio MCP tests exercise the same artifact
|
||||
provider and advertised schemas, including retained Evidence views.
|
||||
|
||||
GNU objcopy 2.40 output was also checked on Linux: the system `true` ELF was
|
||||
converted to Intel HEX and S-record, with additional address-rebased I32HEX
|
||||
and S37 cases. Each yielded 13 regions. A 19,124,817-byte Intel HEX conversion
|
||||
of the system Python 3.11 ELF yielded 11 regions containing 6,799,261 decoded
|
||||
bytes. Public CLI inspection and extraction matched GNU BFD address ranges
|
||||
and independently exported section bytes. Adjacent GNU sections were joined
|
||||
without filling address gaps. These are real producer outputs from system
|
||||
applications, not vendor-firmware or target-execution verification; srec_cat
|
||||
and other producers remain unverified. No general speedup is claimed.
|
||||
@@ -40,7 +40,12 @@ Record the image digest, REA source revision and these dependency versions:
|
||||
- OpenSSL and cURL advertising HTTP3 and HTTP2 in `curl --version`.
|
||||
|
||||
The verified guest used Python 3.14.7, cURL 8.22.0, ngtcp2 1.25.0 and nghttp3
|
||||
1.18.0. Other dependency profiles need verification. Back up the guest's
|
||||
1.18.0. The current requirements update certifi from 2026.7.22 to 2026.10.19
|
||||
to remove the compromised emSign trust root described in
|
||||
[GHSA-6q48-6c7w-9gw2](https://github.com/certifi/python-certifi/security/advisories/GHSA-6q48-6c7w-9gw2).
|
||||
The revised dependency graph has not been rerun in that sealed guest; the
|
||||
historical verification does not cover this update. Other dependency profiles
|
||||
need verification. Back up the guest's
|
||||
`/etc/hosts` before adding `127.0.0.1 lab.test`. Reserve guest TCP/UDP loopback
|
||||
ports 18443 and 19443. These changes belong only to the disposable guest.
|
||||
|
||||
|
||||
+66
-1
@@ -80,6 +80,71 @@ Native MCP 1.1.2 can navigate in the previously focused pseudocode tab when swit
|
||||
|
||||
Native tool observations retain actual tool names and complete JSON text. Upstream `structuredContent` can be a shortened preview even while text contains the full result. REA reads the full native representation and rejects missing/malformed text instead of treating previews as complete observations.
|
||||
|
||||
### Migrate a legacy attached registration
|
||||
|
||||
Both attached profiles remain supported. Migrating replaces the upstream server;
|
||||
adding `"protocol": "native"` to a legacy Python proxy registration is insufficient.
|
||||
The native plugin is separate from mrexodia/ida-pro-mcp, and upgrading mrexodia to
|
||||
its modern tool catalog does not select this profile.
|
||||
|
||||
1. Back up the working registration file. Install and start the native plugin
|
||||
using its [upstream instructions](https://github.com/0xshlomil/ida-free-mcp).
|
||||
IDA and the plugin are bring-your-own; REA does not install or build them.
|
||||
Use a build with the navigation correction described above, and restrict its
|
||||
listener to loopback or apply the documented host firewall restriction.
|
||||
Stop the legacy endpoint first if both servers would use the same port.
|
||||
2. Open the same original input binary in IDA and wait for analysis. Keep that
|
||||
file readable by REA. The native metadata resource must report its recorded
|
||||
input SHA-256; the resource's `path` identifies the database, not an input
|
||||
file to substitute. Universal Mach-O inputs still require a thin extraction.
|
||||
3. Replace the registration, using the native plugin's actual local endpoint.
|
||||
For example, this legacy registration:
|
||||
|
||||
```json
|
||||
{
|
||||
"mode": "attached",
|
||||
"command": "python",
|
||||
"args": [
|
||||
"/absolute/path/to/ida_pro_mcp/server.py",
|
||||
"--ida-rpc",
|
||||
"http://127.0.0.1:13337"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
becomes:
|
||||
|
||||
```json
|
||||
{
|
||||
"mode": "attached",
|
||||
"protocol": "native",
|
||||
"url": "http://127.0.0.1:13337/mcp"
|
||||
}
|
||||
```
|
||||
|
||||
Keep `REA_IDA_MCP_CONFIG` pointing at the replacement file and close/reopen
|
||||
the REA binary session to connect with it. If changing the environment's
|
||||
configuration path, restart the MCP server as described above. Do not reuse
|
||||
the legacy RPC URL as an MCP HTTP endpoint.
|
||||
|
||||
4. Check `binary_session` availability before resuming workflows. Direct
|
||||
`procedure_callers` becomes unavailable and dossier callers remain unknown;
|
||||
incoming address xrefs do not establish direct call edges. Native strings
|
||||
use C-string rendering. Assembly and instruction reads no longer navigate
|
||||
the GUI; native pseudocode still changes focus and closes existing
|
||||
pseudocode tabs. IDA Free decompilation may require cloud access and consent.
|
||||
5. Run the [real-provider verification](#verification) with two distinct
|
||||
functions and the required second-function marker. Supply independently
|
||||
known string and xref oracles for those checks. Existing Windows evidence
|
||||
covers IDA Pro 9.3 with the documented source build and listener change;
|
||||
it does not establish stock-plugin, Windows Free, or native macOS behavior.
|
||||
A valid registration or successful doctor check alone does not verify the
|
||||
connection, target identity, or function switching.
|
||||
|
||||
REA continues to verify identity and image base around requests and closes only
|
||||
its connection, preserving the attached database. Restore the backed-up legacy
|
||||
registration and its upstream endpoint to return to the legacy profile.
|
||||
|
||||
The legacy producer moves the active GUI as a side effect: assembly and raw function instructions jump to the function, and successful pseudocode opens or reuses a pseudocode view. A function dossier does both. Native GUI decompilation also changes the active view. `binary_session` reports these operations with `effects.may_show_ui: true`; headless operations and the other attached operations report `false`.
|
||||
|
||||
## Give REA a target for headless analysis
|
||||
@@ -175,7 +240,7 @@ The verifier requires the resolved procedure in both inventory and procedure sea
|
||||
|
||||
The initial real workflows use stdio registrations for the legacy Windows GUI profile and a Windows x64 headless supervisor with IDA 9.3. The headless workflow has also passed on macOS arm64 with IDA Professional 9.1 (build 9.1.250226) against the same upstream commit `c133c3853faa111a9b00ee615c013b720d0c4acd`, using a source-built arm64 Mach-O fixture; Mach-O C symbols carry a leading underscore, so the procedure name is `_rea_fixture_add`. Streamable HTTP is tested against a loopback MCP fixture with the pinned client SDK; a real IDA HTTP-supervisor workflow remains unverified. Linux headless engine operation, other IDA releases, architectures, and modern attached GUI tools require their corresponding real workflows before support is claimed.
|
||||
|
||||
Native Windows verification uses IDA Pro 9.3 with the public two-function fixture and Windows `whoami.exe`, using upstream `c9d15d98e8a143fc74f6e14037c48f63889b6d6c` with a loopback-listener change. It covers production CLI/MCP parity, distinct-function switching, identity and connection cleanup. See the [correctness and performance measurements](https://github.com/morluto/rea/blob/main/experiments/analysis-efficiency/ida-native-windows.md). This follow-up did not run Windows IDA Free or native macOS.
|
||||
Native Windows verification uses IDA Pro 9.3 with the public two-function fixture and Windows `whoami.exe`, using upstream `c9d15d98e8a143fc74f6e14037c48f63889b6d6c` with a loopback-listener change. It covers production CLI/MCP parity, distinct-function switching, identity and connection cleanup. See the [correctness and performance measurements](https://github.com/morluto/rea/blob/a2e2c29b59e8775b0e6aedb09a9eb16adf32646b/experiments/analysis-efficiency/ida-native-windows.md). This follow-up did not run Windows IDA Free or native macOS.
|
||||
|
||||
Headless readiness distinguishes an explicit `auto_analysis_ready: false` from
|
||||
unknown readiness (`null`). The former returns a retryable capability refusal
|
||||
|
||||
+14
-14
@@ -47,20 +47,20 @@ For runtime instrumentation, see the [Frida guide](./frida-instrumentation.md).
|
||||
|
||||
## Choose a guide
|
||||
|
||||
| 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), [CPython pyc files](python-pyc.md), [PE certificates](pe-certificates.md), [PE imports](pe-imports.md), [PE TLS/load config](pe-load-config.md), [ELF notes](elf-notes.md), [Linux kernel modules](kernel-modules.md), [Apple IPS](apple-ips.md), [Erlang BEAM](erlang-beam.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), [CPython pyc files](python-pyc.md), [PE certificates](pe-certificates.md), [PE imports](pe-imports.md), [PE TLS/load config](pe-load-config.md), [ELF notes](elf-notes.md), [Apple IPS](apple-ips.md), [Erlang BEAM](erlang-beam.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), [GameCube DOL](ghidra-dol.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) |
|
||||
| Inspect assemblies, packages, or firmware | [Godot PCK](godot-pck.md), [.NET](managed-code-analysis.md), [Python packages](python-packaged-applications.md), [Android](android-analysis.md), [APK signatures](apk-signature.md), [Apktool resources](apktool-resource-analysis.md), [ADB acquisition](adb-device-analysis.md), [Apple](apple-application-analysis.md), [Harmony](harmony-analysis.md), [firmware](firmware-analysis.md), [WASM](wasm-artifacts.md), [EVM](evm-bytecode.md) |
|
||||
| Observe or compare a browser scenario | [CDP observation](browser-observation.md), [scenarios](browser-scenario-contract.md), [runtime evidence](web-runtime.md), [historical captures](web-network-captures.md) |
|
||||
| Serve recorded behavior as an agent environment | [Agent environments](agent-environments.md) |
|
||||
| Trace captured website source | [Source locations](web-source-location.md), [module traces](website-module-trace.md), [script export](website-script-export.md) |
|
||||
| Capture and compare a command | [Process capture](process-capture.md) |
|
||||
| Use CLI/MCP and retain evidence | [CLI](cli.md), [MCP contracts](mcp-contracts.md), [agent prompts](mcp-prompts.md), [obligation ledgers](reconstruction-obligation-ledgers.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), [CPython pyc files](python-pyc.md), [PE certificates](pe-certificates.md), [PE imports](pe-imports.md), [PE TLS/load config](pe-load-config.md), [ELF notes](elf-notes.md), [Linux kernel modules](kernel-modules.md), [Apple IPS](apple-ips.md), [Erlang BEAM](erlang-beam.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), [CPython pyc files](python-pyc.md), [PE certificates](pe-certificates.md), [PE imports](pe-imports.md), [PE TLS/load config](pe-load-config.md), [ELF notes](elf-notes.md), [Apple IPS](apple-ips.md), [Erlang BEAM](erlang-beam.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), [GameCube DOL](ghidra-dol.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) |
|
||||
| Inspect assemblies, packages, or firmware | [Godot PCK](godot-pck.md), [UnityFS](unityfs.md), [U-Boot uImage](uimage.md), [.NET](managed-code-analysis.md), [Python packages](python-packaged-applications.md), [Android](android-analysis.md), [APK signatures](apk-signature.md), [Apktool resources](apktool-resource-analysis.md), [ADB acquisition](adb-device-analysis.md), [Apple](apple-application-analysis.md), [Harmony](harmony-analysis.md), [firmware](firmware-analysis.md), [WASM](wasm-artifacts.md), [EVM](evm-bytecode.md) |
|
||||
| Observe or compare a browser scenario | [CDP observation](browser-observation.md), [scenarios](browser-scenario-contract.md), [runtime evidence](web-runtime.md), [historical captures](web-network-captures.md) |
|
||||
| Serve recorded behavior as an agent environment | [Agent environments](agent-environments.md) |
|
||||
| Trace captured website source | [Source locations](web-source-location.md), [module traces](website-module-trace.md), [script export](website-script-export.md) |
|
||||
| Capture and compare a command | [Process capture](process-capture.md) |
|
||||
| Use CLI/MCP and retain evidence | [CLI](cli.md), [MCP contracts](mcp-contracts.md), [agent prompts](mcp-prompts.md), [obligation ledgers](reconstruction-obligation-ledgers.md) |
|
||||
|
||||
For development, use [testing](testing.md), [client verification](client-verification.md),
|
||||
[tool design](tool-design.md), [admission limits and recovery](design/limits-and-recovery.md),
|
||||
|
||||
+180
-61
@@ -3,13 +3,14 @@
|
||||
Run REA, connect your selected agents, and check the tools needed for your task.
|
||||
Setup previews configuration changes and asks for approval before applying them.
|
||||
|
||||
| Task | Section |
|
||||
| --------------------------------- | --------------------------------------------------------------------------------------------------- |
|
||||
| Connect an agent | [Start setup](#start-setup), then [review changes](#review-setup-changes) |
|
||||
| Diagnose one task | [Scoped readiness checks](#check-readiness-for-your-task) |
|
||||
| Configure an analysis engine | [Hopper](#hopper), [Ghidra](#ghidra), the [IDA guide](ida-provider.md), or [Kuna](kuna-provider.md) |
|
||||
| Update or remove REA | [Maintenance](#diagnose-update-and-remove) |
|
||||
| Resolve a client-specific problem | [Client configuration](client-configuration.md) |
|
||||
| Task | Section |
|
||||
| ---------------------------------- | --------------------------------------------------------------------------------------------------- |
|
||||
| Connect an agent | [Start setup](#start-setup), then [review changes](#review-setup-changes) |
|
||||
| Install a Claude Code/Codex plugin | [Agent plugins and marketplaces](#agent-plugins-and-marketplaces) |
|
||||
| Diagnose one task | [Scoped readiness checks](#check-readiness-for-your-task) |
|
||||
| Configure an analysis engine | [Hopper](#hopper), [Ghidra](#ghidra), the [IDA guide](ida-provider.md), or [Kuna](kuna-provider.md) |
|
||||
| Update or remove REA | [Maintenance](#diagnose-update-and-remove) |
|
||||
| Resolve a client-specific problem | [Client configuration](client-configuration.md) |
|
||||
|
||||
## Start setup
|
||||
|
||||
@@ -84,6 +85,13 @@ For an existing configuration, setup and uninstall recovery refuse a detected
|
||||
replacement or edit and name the recovery backup. Quit clients before editing their configuration;
|
||||
these checks do not lock out another writer modifying the same file in place,
|
||||
or exclude pathname changes between the final check and publication.
|
||||
Setup refreshes an existing `rea` registration only when its launcher proves REA
|
||||
ownership. Foreign or unresolved launcher identity blocks setup before any
|
||||
backup or write, including an OpenCode legacy entry that migration would remove.
|
||||
Review the existing launcher and manually rename or remove that registration to
|
||||
approve replacing it. A different existing installation path is foreign to the
|
||||
current entrypoint; a path that cannot be resolved remains unknown. Cordis uses
|
||||
its stable REA entry ID instead of launcher identity.
|
||||
Setup also retains valid environment overrides in REA's existing server entry,
|
||||
such as `REA_MCP_INPUT_SCHEMA_PROFILE`, `REA_MCP_OUTPUT_SCHEMA_PROFILE`, and
|
||||
`REA_MCP_MAX_RESPONSE_BYTES`, and `REA_MCP_TOOL_FAMILIES`.
|
||||
@@ -162,7 +170,9 @@ Setup leaves existing skill copies in other locations untouched.
|
||||
Setup refuses symbolic links at the selected skill directory or its managed
|
||||
`references` directory, matching uninstall and update's ownership rules. Use a
|
||||
regular skill directory, or select `--skill=false` to configure the client
|
||||
registration without installing the bundled skill.
|
||||
registration without installing the bundled skill. A non-directory ancestor is
|
||||
reported as `ENOTDIR`; preserve the blocking file and correct the directory path
|
||||
before rerunning setup.
|
||||
The final selected directories are checked before approval and again before
|
||||
setup changes any client or Hopper installation. Unselected client destinations
|
||||
do not block other setup choices. Doctor reports linked or non-directory skill
|
||||
@@ -265,7 +275,7 @@ After reviewing an update plan, rerun that same prefixed setup command without
|
||||
`--dry-run` and approve its exact changes. Profile removal likewise needs the
|
||||
prefix on `claude mcp remove --scope user rea` and any `rea uninstall` command;
|
||||
keep the broader client scope of uninstall in mind. Restart the selected
|
||||
profile after changing its pinned registration.
|
||||
profile after changing its registration.
|
||||
|
||||
`claude mcp remove` removes only the registration. To remove REA from this
|
||||
profile without running the broader uninstall flow, first back up the profile's
|
||||
@@ -315,30 +325,26 @@ commands. Record an existing selection first if you intend to restore it after
|
||||
finishing. The configuration path below is the default profile's
|
||||
`~/.claude.json`; a different active profile uses its own config root instead.
|
||||
|
||||
Register with the variable unset:
|
||||
|
||||
<!-- x-release-please-start-version -->
|
||||
Register with the variable unset, substituting the absolute runtime and entry
|
||||
script from your existing installation or setup dry-run:
|
||||
|
||||
```bash
|
||||
claude mcp add --scope local rea -- npx -y rea-agents@6.8.0 mcp
|
||||
claude mcp add --scope local rea -- "/absolute/path/to/node" "/absolute/path/to/rea/scripts/rea.mjs" mcp
|
||||
```
|
||||
|
||||
On native Windows, use the same project directory and wrap the package-runner
|
||||
shim so the stdio client can launch it:
|
||||
On native Windows, use the same project directory and absolute paths:
|
||||
|
||||
```powershell
|
||||
claude mcp add --scope local rea -- cmd.exe /d /c npx -y rea-agents@6.8.0 mcp
|
||||
claude mcp add --scope local rea -- "C:\Program Files\nodejs\node.exe" "C:\tools\rea\scripts\rea.mjs" mcp
|
||||
```
|
||||
|
||||
<!-- x-release-please-end -->
|
||||
|
||||
Local scope stores the entry under that directory's path in `~/.claude.json`,
|
||||
so other projects don't load it. This route doesn't install the bundled skill.
|
||||
Avoid `--scope project`, which writes `.mcp.json` into the repository where it
|
||||
can be committed or copied. `rea doctor` and `rea uninstall` read only the
|
||||
user-level entry, so they don't report or remove a local-scope registration;
|
||||
remove it with `claude mcp remove --scope local rea` from the same directory.
|
||||
`rea update` doesn't refresh it either, so it stays on the version it names.
|
||||
`rea update` doesn't refresh it either, so it continues using the selected installation.
|
||||
To move it to a newer release, first back up the project entry in
|
||||
`~/.claude.json` and record its environment and other metadata. In particular,
|
||||
preserve caller-selected overrides such as `REA_MCP_INPUT_SCHEMA_PROFILE` and
|
||||
@@ -437,11 +443,19 @@ and other MCP servers. Purging removes REA's legacy cache and state under
|
||||
archives under `${XDG_CACHE_HOME:-~/.cache}/rea/hopper-releases`. Other cache
|
||||
namespaces remain intact. A caller-selected `REA_KUNA_CACHE_DIR` is retained
|
||||
and reported because REA cannot establish ownership of its entire contents.
|
||||
Lexically equivalent spellings of that default directory, including a trailing
|
||||
separator, a `.` segment, or a repeated separator, share its purge result.
|
||||
The comparison preserves POSIX `..` traversal and literal backslashes.
|
||||
A client configuration that is malformed, unreadable, or at an unsafe
|
||||
path stops the operation before anything is removed, and a client that fails
|
||||
while being updated stops the remaining removals. Uninstall reports each
|
||||
candidate `configuration_path` with its outcome. A client with multiple files
|
||||
keeps their individual `actions` alongside its aggregate status and detail,
|
||||
path stops the operation before anything is removed when that client's
|
||||
product applicability is established or unresolved. Shared registration
|
||||
storage such as `~/.agents/mcp.json` whose product cannot be established
|
||||
(for example when FreeBuff and ZCode discovery directories are absent) is
|
||||
retained unchanged and does not block other REA removals, including cache
|
||||
and state deletion with `--purge-data`. A client that fails while being
|
||||
updated stops the remaining removals. Uninstall reports each candidate
|
||||
`configuration_path` with its outcome. A client with multiple files keeps
|
||||
their individual `actions` alongside its aggregate status and detail,
|
||||
including earlier removals when a later file fails. The paths name
|
||||
the discovered configuration candidates, not resolved physical file identities.
|
||||
For JSON clients, uninstall removes every repeated `rea` member in the effective
|
||||
@@ -537,8 +551,8 @@ non-TTY, and JSON modes without applying configuration changes.
|
||||
## Released package and main
|
||||
|
||||
Repository main documents its current code and generated catalog. `@latest`
|
||||
selects the npm release, and persistent MCP registrations are pinned to the
|
||||
version that performed setup. Installing newer instructions does not update a
|
||||
selects the npm release, and managed MCP registrations bind the installation
|
||||
that performed setup. Installing newer instructions does not update a
|
||||
running server or its registration.
|
||||
|
||||
The npm release checked on **2026-10-11** was **6.4.0**, published from
|
||||
@@ -841,9 +855,13 @@ stage `connection`.
|
||||
If macOS denies Apple Events, allow the application that starts REA under
|
||||
**System Settings → Privacy & Security → Automation**, then retry. REA releases
|
||||
the target reservation when the native helper reports its complete authorization
|
||||
rejection and its arguments cannot alter the helper's generated AppleScript.
|
||||
Arguments containing quotes, backslashes, or line breaks remain unchanged but
|
||||
cannot establish that a failed handoff opened no document. Other failed handoffs
|
||||
rejection after literal argument admission. Before application handoff, REA refuses
|
||||
double quotes, backslashes, or line breaks in the final launcher path or arguments,
|
||||
with `details.launch_rejection.boundary: "argument_encoding"` and the affected source/index.
|
||||
Select literal-safe launcher/runtime paths and loader arguments, or another
|
||||
compatible provider. REA preserves original file names and evidence: a quoted
|
||||
executable name can still work when its prepared image path is literal-safe;
|
||||
database paths must themselves be representable. Other failed handoffs
|
||||
retain ownership until document closure is confirmed. If a timed-out bridge
|
||||
becomes ready later, `close_binary` connects to that run, authenticates its
|
||||
identity, and requests document shutdown. Once its listener is ready, the bridge
|
||||
@@ -1081,14 +1099,15 @@ rea providers --json
|
||||
```
|
||||
|
||||
`rea setup` can configure supported Windows agents and install the bundled
|
||||
REA skill after approval. Direct registrations use Node to launch REA's entry
|
||||
script; package-runner registrations use the pinned `npx` or `bunx` command. Hopper
|
||||
REA skill after approval. Managed registrations use the absolute selected Node or
|
||||
Bun runtime and REA entry script, including when setup ran through a package runner. Hopper
|
||||
installation remains unavailable on Windows. Setup never installs Ghidra,
|
||||
Java, or Python. It preserves valid detected Ghidra/JDK settings in agent
|
||||
registrations. See [Windows Ghidra P0](windows-ghidra-p0.md) for provider diagnostics.
|
||||
|
||||
The separate `rea mcp add` builtin currently uses Incur's package-runner child
|
||||
launcher, which can fail on Windows with `MCP_ADD_FAILED: spawn npx ENOENT`
|
||||
The separate `rea mcp add` builtin delegates most clients to Incur's package-runner
|
||||
child launcher. Run that acquisition from a trusted directory; prefer managed
|
||||
`rea setup` when supported. That child launcher can fail on Windows with `MCP_ADD_FAILED: spawn npx ENOENT`
|
||||
before registering a client. REA's setup path is unaffected. For a client supported
|
||||
by setup, review `rea setup --client opencode --skill=false --dry-run --json`
|
||||
(substitute its client ID), then use the same scoped command without `--dry-run`
|
||||
@@ -1426,6 +1445,21 @@ current setting. For Windows PE resource analysis, the exact name is
|
||||
`WindowsResourceReference`. Disabling an analyzer skips the facts it would have
|
||||
produced.
|
||||
|
||||
Ghidra's Objective-C Message Analyzer can log
|
||||
`Required Objective-C data type not found in data type manager` /
|
||||
`Try adding libobjc.dylib` when a Mach-O links Objective-C runtime symbols but
|
||||
defines no class metadata (thin Cocoa glue in a C++ binary is a common case).
|
||||
That text is non-fatal Ghidra analyzer output: auto-analysis continues, and the
|
||||
analyzer simply skips `objc_msgSend` call-target recovery. REA's headless import
|
||||
does not accept a "add this library" option, and on modern macOS
|
||||
`/usr/lib/libobjc.A.dylib` exists only in the dyld shared cache, so there is no
|
||||
on-disk library to add. Treat the line as a coverage limitation, not an REA
|
||||
failure; check the session's `failure_kind` (and related provider errors) for
|
||||
any real abort. To silence that analyzer, set
|
||||
`REA_GHIDRA_DISABLED_ANALYZERS="Objective-C Message Analyzer"`. For large
|
||||
executables that miss the startup deadline instead, raise
|
||||
`REA_GHIDRA_STARTUP_TIMEOUT_MS` and the [Ghidra heap](#ghidra-heap-and-cpu-controls).
|
||||
|
||||
### Ghidra heap and CPU controls
|
||||
|
||||
Set resource controls in the environment that launches the CLI or MCP server,
|
||||
@@ -1527,6 +1561,87 @@ read-only operations, digest identity, and runtime cleanup. The separate
|
||||
ordinary user. It requires the built Windows native bundle and an existing
|
||||
Ghidra/JDK installation; neither is inferred from startup alone.
|
||||
|
||||
## Agent plugins and marketplaces
|
||||
|
||||
REA's npm package is the shared Claude Code and Codex plugin artifact. It
|
||||
contains `.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, and the
|
||||
canonical generated `skills/` tree. Both manifests select `./skills` and run a plain Node bootstrap pinned to
|
||||
that exact package version. The client must have a supported standalone `node`
|
||||
on its PATH. Claude expands its documented `CLAUDE_PLUGIN_ROOT` in the script
|
||||
argument; Codex resolves `cwd: "."` from the installed plugin root before
|
||||
launching the relative script. The bootstrap verifies the package version and runs its bundled runtime in
|
||||
the same process, preserving stdio and REA's provider/worker cleanup. It does
|
||||
not start another package runner or download a different runtime. The existing release skill
|
||||
generator also pins CLI recovery commands to the same version.
|
||||
|
||||
The repository's single-plugin marketplaces are declared in
|
||||
`.claude-plugin/marketplace.json` and `.agents/plugins/marketplace.json`.
|
||||
Both select an exact `rea-agents` npm version instead of mutable source-checkout
|
||||
contents. Release Please updates their selectors alongside the plugin manifests.
|
||||
No plugin-only publication or generated skill files committed to Git are needed.
|
||||
The qualified release archive contains a runtime-only manifest and
|
||||
`npm-shrinkwrap.json` plus bundled runtime dependencies, including PTY packages
|
||||
for each supported OS and CPU; development dependencies and development-only overrides
|
||||
stay in the source manifest and lockfile. Both clients receive this same archive.
|
||||
|
||||
This distribution becomes installable after the first qualified npm release
|
||||
containing these plugin manifests. Earlier published packages are not changed
|
||||
by this source proposal. For local source development, run `npm ci && npm run build:cached` to generate
|
||||
the runtime and packaged skill before loading the repository as a plugin.
|
||||
A source plugin uses the locally built runtime and generated skill; rebuild after
|
||||
source changes. Missing builds and mismatched version pins fail with an actionable
|
||||
error. The authored `.agents/skills/` tree is not the plugin's shipped skill layout.
|
||||
Windows source workflows that need native controls still require the
|
||||
[Windows source-checkout build](https://github.com/morluto/rea/blob/main/native/windows/README.md#build).
|
||||
|
||||
In Claude Code:
|
||||
|
||||
```text
|
||||
/plugin marketplace add morluto/rea
|
||||
/plugin install rea@rea
|
||||
```
|
||||
|
||||
In Codex CLI, add the marketplace and install REA:
|
||||
|
||||
```bash
|
||||
codex plugin marketplace add morluto/rea
|
||||
codex plugin add rea@rea
|
||||
```
|
||||
|
||||
Each release updates both manifest versions and their pinned server version
|
||||
together, which is when installed copies refresh the bundled skill and move to
|
||||
the new server. A plugin does not run `rea setup`, so provider
|
||||
configuration still follows the sections above. Use the plugin or a
|
||||
`rea setup` registration for a client, not both, to avoid two `rea` servers.
|
||||
|
||||
`rea doctor` does not see plugin-owned state. Its client and skill checks read
|
||||
only the registrations and skill locations that `rea setup` manages, so for a
|
||||
plugin-only install `rea doctor --client <id>` and `rea doctor --skill` report
|
||||
`missing` and recommend `rea setup`. Do not follow that remediation. Check the
|
||||
plugin with the client instead (`claude plugin list` and `/mcp` in Claude
|
||||
Code, `codex plugin list` in Codex).
|
||||
|
||||
For analysis engines, ask the connected server: have the agent call
|
||||
`binary_session` and read `result.tool_availability`, which reports what the
|
||||
server the plugin started can use, with reasons and remediation. See
|
||||
[MCP contracts](mcp-contracts.md).
|
||||
|
||||
A plugin does not put `rea` on your `PATH`. To check an engine from a
|
||||
terminal, use the package runner at the version the plugin pins:
|
||||
|
||||
<!-- x-release-please-start-version -->
|
||||
|
||||
```bash
|
||||
npx -y rea-agents@6.8.0 doctor --provider ghidra --json
|
||||
```
|
||||
|
||||
<!-- x-release-please-end -->
|
||||
|
||||
If your installed plugin is older, use the version in its manifest instead.
|
||||
That report describes the terminal's environment, not the plugin server's.
|
||||
The server inherits the client's environment, so a setting such as
|
||||
`GHIDRA_INSTALL_DIR` that exists only in your terminal does not reach it.
|
||||
|
||||
## MCP Registry
|
||||
|
||||
REA is published in the official MCP Registry as `io.github.morluto/rea`. Registry
|
||||
@@ -1537,40 +1652,45 @@ For a client that supports Registry discovery, search for `io.github.morluto/rea
|
||||
and select the npm package. The published metadata launches the existing stdio
|
||||
server through `npx` with the `mcp` command.
|
||||
|
||||
For a client that requires manual configuration, use:
|
||||
For supported clients, prefer `rea setup`: it records the absolute JavaScript
|
||||
runtime and entry script of the REA installation performing setup. Client starts
|
||||
then use that installation directly, keeping the client's working directory
|
||||
without running npm or Bun package resolution there. Registry clients control
|
||||
their own package acquisition; Registry metadata cannot name local absolute paths.
|
||||
|
||||
<!-- x-release-please-start-version -->
|
||||
For manual stdio configuration, substitute the absolute paths of an existing
|
||||
installation (use the command shown in a setup dry-run):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"rea": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "rea-agents@6.8.0", "mcp"]
|
||||
"command": "/absolute/path/to/node",
|
||||
"args": ["/absolute/path/to/rea/scripts/rea.mjs", "mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!-- x-release-please-end -->
|
||||
Run current setup to migrate recognized older `npx`/`bunx` registrations, with
|
||||
backups, then restart the client. Unrelated or unidentified registrations remain
|
||||
untouched. Setup does not prewarm a separate package-runner command.
|
||||
|
||||
Persistent registrations should use one exact package version. `rea setup`
|
||||
writes the same package-runner shape, or `bunx rea-agents@<version> mcp` when
|
||||
setup runs through `bunx`, and pins it to the exact version that performed
|
||||
setup. Run current setup to refresh an older registration, then restart the
|
||||
client.
|
||||
|
||||
Package runners key their package cache by the requested spec, so the entry
|
||||
installed for the `@latest` invocation that ran setup cannot serve the pinned
|
||||
registration. Setup therefore materializes the pinned entry once, best-effort
|
||||
with a bounded timeout, before finishing. When that step cannot run, for
|
||||
example offline, the first client start performs the one-time install inside
|
||||
the client's MCP startup deadline and may need one more restart.
|
||||
If setup itself runs from a package-runner cache, the registration depends on
|
||||
that cache entry and the selected runtime remaining installed. Removing either
|
||||
makes startup fail; it does not download or resolve another package. Restore the
|
||||
same installation and rerun setup. Changing package requests, cache roots, or
|
||||
runtimes can create a different installation identity. If the old entry cannot be
|
||||
identified, restore it first or manually remove the confirmed REA registration
|
||||
before running setup again. A global installation provides a more durable path.
|
||||
|
||||
## Package runners and global installation
|
||||
|
||||
A package-runner invocation can use a REA version installed in the current project. To
|
||||
request the latest release explicitly, use:
|
||||
Package runners can select project-local packages and read project configuration,
|
||||
even for explicit version requests. Acquire REA from a trusted working directory,
|
||||
outside the target project, and pass absolute target paths to analysis commands.
|
||||
REA cannot validate package acquisition that happens before its entrypoint starts.
|
||||
To request the latest release explicitly, use:
|
||||
|
||||
```bash
|
||||
npx rea-agents@latest setup
|
||||
@@ -1587,16 +1707,14 @@ For an intentional rollback, make the package request explicit:
|
||||
npm exec --yes --package=rea-agents@2.4.0 -- rea setup
|
||||
```
|
||||
|
||||
Setup continues to pin persistent MCP registrations to the exact version that
|
||||
performed setup. Running current setup later migrates unversioned or older
|
||||
managed registrations through the normal reviewed setup transaction.
|
||||
Setup binds persistent MCP registrations to the installation that performed setup.
|
||||
Running current setup later migrates recognized legacy package-runner registrations
|
||||
through the normal reviewed setup transaction.
|
||||
|
||||
With Bun, `bunx rea-agents setup` (or `bunx rea-agents@latest setup`) is the
|
||||
equivalent entry point. Setup run through `npx` registers
|
||||
`npx -y rea-agents@<version> mcp`; setup run through `bunx` or `bun x` registers
|
||||
`bunx rea-agents@<version> mcp`. On Windows, setup wraps either command in
|
||||
`cmd.exe /d /c` so clients can start the runner's command shim. Neither
|
||||
registration points into the runner's temporary package cache.
|
||||
equivalent acquisition entry point. Managed registrations use the selected Bun
|
||||
executable and REA entry script directly. Windows registrations likewise use
|
||||
absolute runtime and script paths, without a package-runner command shim.
|
||||
|
||||
REA supports Node.js 22.x (>=22.23.4), 24.x (>=24.22.1), and 26.12.1+. Node.js 23, 25, earlier 26.x releases, and prereleases are unsupported. It uses the npm already paired with that runtime and never upgrades Node.js, npm, or Homebrew.
|
||||
|
||||
@@ -1630,8 +1748,9 @@ Review the plan, approve the selected client changes, then restart those clients
|
||||
This registers the installed entrypoint directly; installing the global package
|
||||
alone does not replace existing `npx` registrations. Each client still has its own
|
||||
REA process and analysis state. Direct registrations follow the installed CLI;
|
||||
use `rea update` to update it. Running setup through `npx` again selects the pinned
|
||||
package-runner command. Do not register paths inside npm's temporary package cache.
|
||||
use `rea update` to update it. Running setup through `npx` again selects the
|
||||
installation that executes setup, potentially in npm's temporary package cache;
|
||||
retain that cache entry for as long as the registration uses it.
|
||||
|
||||
### npm workspace errors before REA starts
|
||||
|
||||
|
||||
@@ -156,6 +156,10 @@ Select one literal seed kind: node ID, route, string, API, IPC channel, module,
|
||||
or native export. Matching is exact or literal substring matching; regular
|
||||
expressions and executable predicates are not accepted. The trace includes all
|
||||
matching seeds and the complete graph reachable in the selected direction.
|
||||
`both` follows relationships in either direction, except that a container
|
||||
reached through `contains` from one of its children only leads further up its
|
||||
containment chain, so a shared asset or artifact root does not pull in its
|
||||
other children.
|
||||
|
||||
The result contains the matching basis, complete reachable subgraph, terminal
|
||||
paths, authority summaries, and native handoffs. A handoff binds
|
||||
|
||||
@@ -72,6 +72,18 @@ code-point order. Dependency manifests remain package observations but do not
|
||||
declare Electron main or renderer entries. If only dependency manifests are
|
||||
present, the inventory artifact remains the graph root.
|
||||
|
||||
Package observations use `renderer_declarations` to record the actual present
|
||||
fields: strings, including empty strings, remain exact; non-string values use `{ "status": "non-string" }`
|
||||
without copying nested browser mappings. An empty record means no such fields
|
||||
were present; `null` means package metadata was invalid or unavailable. Renderer
|
||||
role mechanisms and package load edges name the field that supplied the candidate,
|
||||
selected as the first nonempty string from `renderer`, `browser`, then `module`.
|
||||
The package load edge retains `declared_path`, `source_field`, and resolution
|
||||
facts for that selection. New analyses no longer emit the derived package
|
||||
`renderer` alias; consumers must read declarations for source metadata and load
|
||||
edges for the selected candidate. Previously retained Evidence keeps its original
|
||||
properties and remains readable without migration.
|
||||
|
||||
## Select sources before analysis
|
||||
|
||||
For a question about known entry sources, supply exact artifact-relative file
|
||||
@@ -239,10 +251,12 @@ An unpacked entry whose companion bytes were not supplied remains
|
||||
`unavailable`. REA continues analyzing embedded JavaScript and records the
|
||||
missing native/resource bytes as unknown. The occurrence keeps
|
||||
`hash_status: unavailable`; no content-addressed child artifact is created for
|
||||
those missing bytes. New inventories preserve an ASAR companion declaration as
|
||||
`unpacked: true`; an omitted flag in an older inventory does not establish that
|
||||
unavailable bytes belonged to a companion. See [MCP integrity handling](mcp-contracts.md#integrity-record-and-continue)
|
||||
for the tool-result contract.
|
||||
those missing bytes. New ASAR file occurrences record `unpacked: true` for
|
||||
companion files and `unpacked: false` for packed entries, including when the
|
||||
file bytes are unavailable. An omitted flag in an older inventory remains
|
||||
unknown; it does not establish either storage mode. See
|
||||
[MCP integrity handling](mcp-contracts.md#integrity-record-and-continue) for the
|
||||
tool-result contract.
|
||||
|
||||
JavaScript whose syntax cannot be parsed retains unavailable semantic coverage
|
||||
with `incomplete-module` unknowns for each semantic family and unknown omitted
|
||||
@@ -350,6 +364,13 @@ Selected bounded text is then parsed as inert data to recover:
|
||||
relative to the calling module; string worker and service-worker paths use
|
||||
the document base URL or Node's working directory, which static analysis
|
||||
does not establish, so they keep their expression and stay unresolved);
|
||||
- Vite preload dependency tables (`__vite__mapDeps`): `./` entries resolve
|
||||
relative to the importing chunk; base-relative entries such as
|
||||
`assets/chunk.js` carry a `vite-output:` specifier and resolve under the one
|
||||
ancestor directory of the importer that holds them, the build output
|
||||
directory. A file found there but not analyzed, such as a stylesheet, stays
|
||||
`unavailable` with its path. Selecting only the assets directory leaves them
|
||||
`not-found`;
|
||||
- route, network endpoint, storage, and vendor-marker observations;
|
||||
- local source-map declarations and original
|
||||
source names and content digests;
|
||||
|
||||
@@ -63,7 +63,7 @@ All four preserve target-file bytes. `open_jeb_project` selects or creates an en
|
||||
- The engine caps `list_units` pages at 100; a full page is reported as `coverage: "partial"` because more units may exist. An empty remainder is `complete` only when fewer units than requested were returned.
|
||||
- When `decompile_jeb_item` omits `unit_path`, the engine implicitly selects the project's first code unit; REA reports `unit_path: null` and a limitation instead of guessing the effective unit.
|
||||
- `item_address` is a JEB code-item reference, such as a value returned by the engine's `list_code_items`. Preserve that representation and select its code unit explicitly. For the audited CE SQLite unit, the exported method reference was `sqlite3_libversion_number`; using its raw ELF symbol address did not produce a successful decompilation. File offsets, ELF virtual addresses and engine item references have different semantics. REA currently exposes unit listing, while code-item discovery remains an upstream JEB operation.
|
||||
- Engine refusals (`success: false` envelopes) are preserved as unsupported-target errors carrying the engine's own message, for example a nonexistent item address.
|
||||
- Valid engine refusals (`success: false` envelopes) return `execution_failure` with the engine's message when available. Diagnostics preserve the original envelope, including any recovery advice, and the inputs of a refused primary request. If client metadata fails after a primary reply, that reply and the caller's inputs remain in partial Evidence. REA does not infer an unsupported target from a refusal, invoke a recovery tool, or retry the request.
|
||||
- Successfully parsed client information is reused for the lifetime of the MCP connection, including when the engine omits its version. Explicit client inspection and availability probes refresh it.
|
||||
- An unreachable endpoint is a provider-availability failure with recovery guidance; REA does not retry or spawn the engine.
|
||||
|
||||
|
||||
+11
-3
@@ -125,9 +125,17 @@ REA writes Kuna's exports only inside `REA_KUNA_CACHE_DIR`:
|
||||
- `trash/` holds retired builds and evicted exports awaiting removal.
|
||||
- `home/` is Kuna's HOME.
|
||||
|
||||
The cache key includes the selected launcher and resolved executable paths.
|
||||
Older exports without that identity are rebuilt automatically and retired through
|
||||
normal cache cleanup; no manual migration is needed.
|
||||
The cache key includes the selected launcher and resolved executable paths, plus
|
||||
the target's native basename: that name determines the export filenames and
|
||||
appears in generated source. REA accepts one current manifest layout. Older
|
||||
exports are rebuilt on demand and retired through normal owned-cache cleanup;
|
||||
no manual deletion or migration is needed. Manifests must name the producer's
|
||||
exact flat file layout, with matching basenames and producing inputs. Replaced
|
||||
entry, project or manifest symlinks are refused before their targets are read;
|
||||
an unverified `projects/` parent grants no removal authority. Warm reuse checks
|
||||
the manifest's file identity as well as the export files. These refusal and
|
||||
migration cases are verified with controlled Kuna-format exports; they do not
|
||||
establish behavior of an independently installed Kuna release.
|
||||
|
||||
Builds publish by one rename, so a reader sees a complete export or none. If later staging retirement fails, the typed cleanup error retains the completed export's key, directory and manifest in `published_export`. The session adopts that verified project; later queries reuse its immutable files while `project_export.cleanup_incomplete` reports the retained owner's live state. `close_binary` retries only the remaining cleanup, and a successful retry resolves prior cleanup errors. A failed export followed by failed staging cleanup retains both failures; it does not invent a publication receipt. A session keeps the export it uses from eviction only within its own REA process. If another REA process sharing the cache evicts it, the session rebuilds it; meanwhile pseudocode falls back to single-function runs. A damaged or edited export is removed and rebuilt. REA retains the file state verified with each digest, checks it before warm-cache reuse, and checks open descriptors before and after reading text. Assembly indexes are checked against the same state; a changed file makes the whole report retry rather than mixing facets from different exports. Staging moves to `trash/` for removal only after REA proves its Kuna process stopped. Staging of a process it cannot prove stopped is never swept; REA keeps it owned, retries the stop on `close_binary`, and reports it until the stop is proven. Failed file removal also stays bound to its export and is retried by `close_binary`; closing does not report success while that cleanup remains. `rea doctor --provider kuna` reports the cache directory without creating it.
|
||||
|
||||
|
||||
@@ -660,13 +660,15 @@ name and raw signature digest available while marking that signature malformed
|
||||
and coverage partial.
|
||||
A fat method header's nonzero LocalVarSigTok must name an existing StandAloneSig
|
||||
row whose blob is a structurally valid LocalVarSig. REA validates its local
|
||||
types and exact blob coverage but does not project their identities. An invalid
|
||||
types and exact blob coverage, retaining `local_var_signature` with the raw blob
|
||||
digest and whether named types, modifiers, or generic variables require metadata
|
||||
or declaring context. Historical Evidence defaults this field to null. An invalid
|
||||
token or malformed signature leaves decoded CIL anchors intact but marks the
|
||||
body malformed and coverage partial. Unsupported local type encodings retain
|
||||
the readable body with partial coverage. Zero continues to mean no locals
|
||||
signature. Comparison detects whether a locals declaration is present, but raw
|
||||
table tokens are not cross-build identities and local type contents are not
|
||||
compared.
|
||||
signature. Raw table tokens are not cross-build identities. Comparison uses
|
||||
validated context-free signature digests; signatures requiring metadata or
|
||||
declaring context remain unknown across artifacts.
|
||||
|
||||
## Decoded-CIL fingerprint
|
||||
|
||||
@@ -868,9 +870,14 @@ MethodDef flags or implementation flags value differs, including accessibility
|
||||
or synchronization changes. Observed method-body `init_locals` and `max_stack`
|
||||
differences also contribute to `metadata`, even when CIL decoding is incomplete.
|
||||
For complete bodies, presence or absence of a locals signature also contributes;
|
||||
the locals table token is build-local and is not compared. Local type contents
|
||||
are not currently compared, so this facet does not establish equivalent locals
|
||||
declarations.
|
||||
the locals table token is build-local and is not compared. Different validated
|
||||
context-free LocalVarSig digests report a metadata encoding difference without
|
||||
asserting a semantic type change. Equal digests establish unchanged bytes only
|
||||
when neither signature requires metadata or declaring context. Historical
|
||||
unrecorded signatures and context-dependent signatures keep local identity
|
||||
unknown, preserving any independently observed changes. The same method token
|
||||
in an artifact with the same authenticated SHA-256 identifies the same local
|
||||
signature bytes, including for retained historical Evidence.
|
||||
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.
|
||||
|
||||
+40
-3
@@ -26,6 +26,10 @@ can be passed directly to `compare_functions`, and `inspect_artifact` Evidence
|
||||
to `compare_artifacts`. Use `get_evidence_bundle` when the task needs broader
|
||||
retained session history or an explicit bundle for transfer.
|
||||
|
||||
`compare_artifacts` can also resolve an artifact summary to its exact retained
|
||||
parent in the session. Supported historical summaries keep their original
|
||||
Evidence identity and omissions; a missing or mismatched parent is rejected.
|
||||
|
||||
`analyze_function` does not deliver its complete record by default. Without
|
||||
`detail`, it retains the complete dossier in the session and returns
|
||||
`inspect_analysis_view` summary Evidence whose
|
||||
@@ -297,6 +301,15 @@ unknown metadata. Missing omission counts remain null. Summary output carries
|
||||
every matching record; actual transport admission still applies. Omitted
|
||||
`detail` preserves complete canonical bundle delivery; filters require summary.
|
||||
|
||||
Residual-unknown mutations reject missing Evidence or unknown references and
|
||||
unproven verified resolutions with nonretryable `invalid_request` diagnostics.
|
||||
`details.constraint` carries the validator's `kind`, owning `unknown_id`, and
|
||||
missing `evidence_id` or `related_unknown_id` where applicable. Correct the
|
||||
reported input or supply the required retained Evidence; unchanged retries do
|
||||
not repair these constraints. Rejected mutations leave retained state unchanged.
|
||||
Revision conflicts remain retryable `revision_conflict`; broken revision histories
|
||||
remain `evidence_integrity_mismatch`.
|
||||
|
||||
`list_unknowns` returns every matching current head by default. For a smaller
|
||||
inline response, supply `offset` and `limit`, then follow `next_offset` until it
|
||||
is null. `total` counts all matching heads; each page preserves complete records
|
||||
@@ -1206,7 +1219,18 @@ attachment. Native checksum verification failures still refuse traversal;
|
||||
Occurrences use normalized logical paths for identity and lookup. Optional
|
||||
`source_path` retains the original path within the owning reader when Unicode
|
||||
NFC or reader admission changes its spelling; it is source evidence, not an
|
||||
output destination. POSIX letter-colon names such as `a:b` remain valid logical
|
||||
output destination. New ASAR file occurrences explicitly record the boolean
|
||||
`unpacked`: `true` identifies a companion file and `false` identifies a packed
|
||||
entry. This field describes archive storage, independently of whether the bytes
|
||||
were available or passed integrity verification. Older occurrences may omit it;
|
||||
omission remains unknown and must not be defaulted to `false`. Consumers that
|
||||
previously accepted only literal `true` must also accept `false`, while retaining
|
||||
support for omitted historical values.
|
||||
`compare_artifacts` reports a metadata change when both storage values are
|
||||
known and differ. If only one value is known, storage comparison is unknown;
|
||||
when both are omitted, storage is not compared.
|
||||
|
||||
POSIX letter-colon names such as `a:b` remain valid logical
|
||||
names; Windows extraction refuses names its filesystem cannot materialize.
|
||||
|
||||
Extraction materializes regular files exposed by the active archive reader.
|
||||
@@ -1233,11 +1257,22 @@ failures for such entries name this cause and the operation to rerun with
|
||||
Advertised input and output schemas contain no reachable recursive references.
|
||||
Input schemas inline repeated definitions before applying the selected
|
||||
presentation profile. Both `full` and `compact` start from this self-contained
|
||||
projection; output schemas can share schema-local definitions. Full inputs
|
||||
retain nested fields, descriptions and valid literal examples. The compatibility
|
||||
projection; output schemas can share schema-local definitions. Analyst-authored
|
||||
full inputs retain nested fields, descriptions and valid literal examples. The compatibility
|
||||
projections below can relax advertised constraints; canonical runtime validation
|
||||
still enforces the complete input contract.
|
||||
|
||||
`compare_web_captures` declares its complete producer observations as object
|
||||
operands instead of repeating their full output schemas in the input catalog.
|
||||
Pass the original `inspect_web_page` normalized result in `before.inspection`
|
||||
and `after.inspection`, optional complete `discover_webmcp_tools` results in
|
||||
`webmcp`, or complete `capture_browser_scenario` results in the scenario fields.
|
||||
Do not construct partial observations from the abbreviated declaration: the
|
||||
server still validates every canonical field before comparison. Input groups
|
||||
and analyst-authored normalization rules remain explicit. This presentation
|
||||
changes no capture bytes, identity, completeness, or comparison semantics and
|
||||
does not reduce `inspect_analysis_view` selectors or other tools' declarations.
|
||||
|
||||
When a host forwards input schemas to the model, their examples consume context.
|
||||
REA's advertised examples therefore never copy complete producer Evidence.
|
||||
An embedded Evidence record is shown as its exact `{"kind":"retained-evidence","evidence_id":"ev_..."}`
|
||||
@@ -1476,6 +1511,8 @@ validates every result before delivery. On catalogs large enough that full
|
||||
input schemas alone approach the frame limit, keep the input profile at its
|
||||
`compact` default as well; with full input schemas the advertisement is
|
||||
dominated by the input side.
|
||||
The full input profile has no one-megabyte catalog-frame guarantee, including
|
||||
when output schemas are omitted.
|
||||
|
||||
Only client-side schema discovery and validation are reduced or omitted, so
|
||||
hosts using these profiles should rely on REA's validation and retain their
|
||||
|
||||
@@ -4,6 +4,20 @@ REA exposes six provider-neutral investigation workflows through the MCP
|
||||
`prompts` capability. They complement the generated tool catalog; they do not add, remove, or
|
||||
invoke tools by themselves.
|
||||
|
||||
Clients that expose tools but not prompts can use the target-free
|
||||
`guided_workflows` tool with `action: "list"` or `action: "render"`. CLI callers
|
||||
can use `rea guided-workflows` to list workflows, or pass `--action render`,
|
||||
`--workflow-id ID`, and `--arguments-json '{"feature":"offline search"}'` to
|
||||
render one. Both paths use the same contracts and renderer as native prompts;
|
||||
rendering returns guidance only and does not inspect a target, start analysis,
|
||||
or change session state.
|
||||
|
||||
The list contains workflow identifiers, descriptions, and argument requirements;
|
||||
render returns only the selected workflow's text. Unknown argument names and
|
||||
non-string values are rejected with field paths. `action: "list"` accepts no
|
||||
workflow identifier or arguments. The MCP adapter respects the same
|
||||
`REA_MCP_TOOL_FAMILIES` scope as native prompts, including render requests.
|
||||
|
||||
## Prompt inventory
|
||||
|
||||
| Prompt | Purpose |
|
||||
|
||||
@@ -332,7 +332,10 @@ 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.
|
||||
Literal mode retains Python Unicode full case folding, which can expand a
|
||||
character into a sequence: for example, `ss` matches `ß`. This differs from
|
||||
REA's Unicode simple case folding used by other native search providers and
|
||||
Hopper regex mode.
|
||||
|
||||
## Bounded static traces
|
||||
|
||||
@@ -700,10 +703,16 @@ complete observation.
|
||||
release their representation reservation for later documents.
|
||||
Repeated NIBArchive fields retain all serialized values in order. Array
|
||||
outlet connections resolve each serialized member and retain the collection
|
||||
object ID and member position on the outlet observation. AppKit object-parent
|
||||
registries use paired keys and parents; objects paired with `NSRoot` are
|
||||
top-level, while nested objects keep their recorded parent. Conflicting or
|
||||
unreadable registry pairs remain incomplete hierarchy evidence.
|
||||
object ID and member position on the outlet observation. NIB hierarchy uses
|
||||
recognized child fields, reverse `NSSuperview` links and window content links.
|
||||
AppKit registry pairs with a resolvable `NSRoot` owner establish top-level
|
||||
membership; other registry associations alone do not establish visual
|
||||
parentage and leave hierarchy coverage partial. Known non-view cell ownership
|
||||
and control-view backreferences remain raw facts. Conflicting explicit parents
|
||||
remain unknown rather than choosing an archive-order winner. Retained objects
|
||||
keep their decoded fields; uncertain registry diagnostics retain the source
|
||||
registry, child and value IDs. Missing, malformed or repeated registry
|
||||
declarations also qualify hierarchy coverage.
|
||||
`NSString` objects with the [recognized `NS.bytes` representation](https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/Foundation/NSString.swift#L201-L215) are decoded
|
||||
as UTF-8 without substituting malformed bytes. A failed conversion retains
|
||||
the source string object ID and `nibValues.NS.bytes` base64 data; dependent
|
||||
@@ -1068,8 +1077,17 @@ counted as known archive omissions. Recognized symlinked `.nib` entries are
|
||||
not followed; they retain their paths and reader limitations as counted archive
|
||||
omissions. Either gap makes `archive_decode` partial and the graph truncated
|
||||
while preserving decoded documents. Its `examined` count remains actual decode
|
||||
attempts, and asset-catalog UI joins retain their existing incomplete-graph
|
||||
qualification.
|
||||
attempts. `archive_object_decode` separately reports whether archive selection
|
||||
and decoding examined the object sources; hierarchy-only and connection-only
|
||||
unknowns do not make that facet partial. Asset-catalog resource-key joins use
|
||||
this source coverage together with document and object projection coverage.
|
||||
Incomplete hierarchy or synthetic hierarchy-node limits alone do not qualify
|
||||
otherwise complete resource-key joins; omitted archives or resource objects do.
|
||||
Archive omission reasons are counted independently of the bounded path samples.
|
||||
A UID outside the exact supported range reports `unsupported_uid_exact_range`,
|
||||
not budget exhaustion. Mixed source failures report `multiple_archive_decode_causes`;
|
||||
limitations retain omission counts by cause even when individual paths exceed
|
||||
the reporting allowance.
|
||||
|
||||
UI dispatch joins use the authored receiver's class independently of its
|
||||
presentation kind (controller, view, control or another object). An unresolved
|
||||
|
||||
@@ -53,6 +53,14 @@ An unset fuse with a present blob is reported as a limitation. These are static
|
||||
sentinel observations, not proof of runtime activation: sentinel-like text in
|
||||
script or asset bytes also participates in the scan.
|
||||
|
||||
Artifact comparison uses each member's runtime role and exact source key as
|
||||
semantic metadata. Unicode-normalized graph paths do not erase differences in
|
||||
runtime asset keys. For members paired at the same logical path, a directory
|
||||
index change alone does not change the member. Ordinal-based fallback paths can
|
||||
change when entries are reordered. When only one observation records member
|
||||
metadata, the complete runtime member declaration remains unavailable. Original
|
||||
source fields remain available in the retained Evidence.
|
||||
|
||||
## Supported layout and limits
|
||||
|
||||
The decoder follows the 64-bit little-endian layout in Node
|
||||
|
||||
@@ -81,9 +81,13 @@ Its separate inferred truncation lengths do not replace that limit; an unset
|
||||
file-header limit remains `null`.
|
||||
|
||||
Addresses count once per packet, including loopback and nested IP occurrences.
|
||||
DNS addresses are associated only with one question in the same response packet;
|
||||
additional records may be included, so this does not prove final resolution.
|
||||
Ambiguous addresses remain in a separate inventory. Protocol distribution counts
|
||||
DNS address attribution requires one question in one response and complete,
|
||||
consistent RR owner/type and section counts. Only answer-section A/AAAA records
|
||||
matching that question (or its unambiguous answer-section CNAME chain) are
|
||||
associated, with the requested address type respected. Authority, additional,
|
||||
unrelated, malformed, and ambiguous addresses remain in the unattributed
|
||||
inventory and make coverage partial. These packet-local relationships do not
|
||||
prove final resolution or destination authenticity. Protocol distribution counts
|
||||
exact nonempty `frame.protocols` stack strings. Frames for which TShark reports
|
||||
an empty stack, including zero-length packets, still contribute to the packet
|
||||
count without adding a protocol row. An all-empty stack inventory can have
|
||||
|
||||
+42
-3
@@ -224,7 +224,30 @@ child output. Child output remains in the capture Evidence on stdout.
|
||||
resource limits, and normalization settings have defaults; see
|
||||
`processScenarioSchema` for the exact contract. Event times are milliseconds
|
||||
from launch, must be ordered, and must fall within `timeout_ms`. Inputs marked
|
||||
`sensitive` are sent to the process but persisted as a byte-count placeholder.
|
||||
`sensitive` are sent to the process but persisted with empty `data`,
|
||||
`sensitive: true`, and `input_bytes`. Exact nonempty CR/LF-separated input
|
||||
literals are removed from retained terminal text, including cross-chunk and
|
||||
VT-styled echoes. Rendering uses that redacted stream, so intermediate terminal
|
||||
states and serialized state cannot restore removed bytes. Normalized text is
|
||||
checked again. Encoded, transformed, or arbitrarily edited values are not a
|
||||
secret-detection contract; their privacy remains unknown. Unmarked inputs and
|
||||
caller-selected environment values remain evidence.
|
||||
|
||||
The capture-local matcher admits at most 65,536 prefix states and 8,388,608
|
||||
construction work units. Projection uses at most 32 MiB of reusable position
|
||||
indexes and 67,108,864 work units across one capture. Capacity failures return a
|
||||
non-retryable resource error and withhold terminal text in partial observations.
|
||||
If output admission leaves gaps, the sensitive capture withholds retained
|
||||
terminal text rather than interpreting separated fragments as a complete stream.
|
||||
`raw_terminal.redacted_bytes` reports bytes removed from admitted original
|
||||
chunks; these bytes still consume `output_bytes` alongside retained safe bytes.
|
||||
Private display effects remain unknown, with frame order and provenance retained.
|
||||
|
||||
This changes the sensitive-input Evidence representation: consumers of the old
|
||||
`<redacted-input:N-bytes>` placeholder must read `input_bytes` instead. Existing
|
||||
saved captures remain readable and are not rewritten; old files may still
|
||||
contain previously echoed input. A private-input comparison policy version
|
||||
separates old and new captures; reacquire both sides for comparable observations.
|
||||
Environment overrides are recorded in the scenario commitment; inherited
|
||||
values are not copied into Evidence.
|
||||
|
||||
@@ -234,7 +257,9 @@ A bare executable name uses the scenario's `PATH` override, then the inherited
|
||||
An explicitly empty `PATH` searches only the working directory. Executable,
|
||||
working-directory, and observation paths preserve native `symlink/..` traversal.
|
||||
|
||||
Terminal dimensions must satisfy `columns × (rows + scrollback) ≤ 1,000,000`.
|
||||
Terminal width must be at least two columns: the pinned xterm renderer cannot
|
||||
represent a one-column screen. This applies to the initial size and every resize.
|
||||
Terminal dimensions must also satisfy `columns × (rows + scrollback) ≤ 1,000,000`.
|
||||
Every scheduled resize uses the same selected scrollback and must fit this
|
||||
working-buffer budget. REA rejects oversized scenarios before launching the
|
||||
command; it never clamps the requested dimensions. This limit is independent
|
||||
@@ -294,7 +319,8 @@ own classification until its exact resources are released.
|
||||
|
||||
Terminal frame `data` is the comparison text after the selected normalization.
|
||||
New captures also preserve `raw_data` when normalization changes a PTY chunk;
|
||||
otherwise `data` is already the original text. Older captures may lack the
|
||||
otherwise `data` is already that text. For sensitive captures, both fields
|
||||
contain only the safe projection; no unredacted backup is retained. Older captures may lack the
|
||||
original text for changed chunks. Both values participate in Evidence identity,
|
||||
while comparisons and trace assertions use the normalized text. Retaining the
|
||||
original adds at most `limits.output_bytes` of text, because it comes from the
|
||||
@@ -500,6 +526,11 @@ Every capture requires `truncation_details`, with separate accounting for:
|
||||
An unreadable directory is recorded in `enumeration_omissions` with its
|
||||
root-aliased path and operating-system error code. Entries observed before
|
||||
that directory remain available, while descendants beneath it stay unknown.
|
||||
A basename that is not valid UTF-8 is never looked up through replacement
|
||||
characters. It consumes entry capacity and records an `unrepresentable_name`
|
||||
omission at its containing directory, with exact basename bytes in
|
||||
`raw_name_hex` and a null `system_code`. That root's enumeration remains
|
||||
incomplete, so missing paths beneath it remain unknown.
|
||||
Each retained regular file without a digest has an aliased path, size,
|
||||
remaining budget and reason: `file_bytes_budget`,
|
||||
`file_changed_or_short_read`, or `file_unavailable`. Its `system_code` is
|
||||
@@ -663,3 +694,11 @@ REA then preserves ownership uncertainty and can report `cleanup_incomplete`;
|
||||
it does not disable verification to continue. A sandbox that explicitly allows
|
||||
this read-only process inspector is a separate prerequisite from the compiler
|
||||
and cache settings.
|
||||
|
||||
Symlink observations preserve their stored target bytes in `symlink_target_hex`
|
||||
(lowercase hexadecimal). `symlink_target` retains valid UTF-8 text and is `null`
|
||||
when the target bytes cannot be decoded as UTF-8. Filesystem effects compare
|
||||
these exact bytes without resolving the link. Older captures without the hex
|
||||
field still parse; a legacy target containing U+FFFD has ambiguous byte identity,
|
||||
so matching target text alone produces an `unknown` effect. Symlink descendants
|
||||
remain outside filesystem observation regardless of target encoding.
|
||||
@@ -350,7 +350,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## سجل النجوم
|
||||
|
||||
🎉 **300,000 نجمة على GitHub — شكرًا لكم!**
|
||||
🎉 **400,000 نجمة على GitHub — شكرًا لكم!**
|
||||
|
||||
شكرًا لكل من يستخدم REA، ويبلّغ عن الأخطاء، ويقترح ميزات، ويختبر إصدارات البناء، ويساهم بالإصلاحات.
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ Melde Sicherheitslücken gemäß [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Sternverlauf
|
||||
|
||||
🎉 **300.000 GitHub-Sterne – vielen Dank!**
|
||||
🎉 **400.000 GitHub-Sterne – vielen Dank!**
|
||||
|
||||
Danke an alle, die REA nutzen, Fehler melden, Funktionswünsche äußern, Builds testen und Fehlerbehebungen beitragen.
|
||||
|
||||
|
||||
@@ -352,7 +352,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## Ιστορικό αστεριών
|
||||
|
||||
🎉 **300.000 αστέρια στο GitHub — σας ευχαριστούμε!**
|
||||
🎉 **400.000 αστέρια στο GitHub — σας ευχαριστούμε!**
|
||||
|
||||
Ευχαριστούμε όλους όσοι χρησιμοποιούν το REA, αναφέρουν σφάλματα, ζητούν νέες λειτουργίες, δοκιμάζουν builds και συνεισφέρουν διορθώσεις.
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ Informa de vulnerabilidades siguiendo [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Historial de estrellas
|
||||
|
||||
🎉 **300.000 estrellas en GitHub: ¡gracias!**
|
||||
🎉 **400.000 estrellas en GitHub: ¡gracias!**
|
||||
|
||||
Gracias a quienes usan REA, informan de errores, solicitan funciones, prueban compilaciones y contribuyen con correcciones.
|
||||
|
||||
|
||||
@@ -333,7 +333,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## تاریخچهٔ ستارهها
|
||||
|
||||
🎉 **۳۰۰٬۰۰۰ ستارهٔ GitHub — سپاسگزاریم!**
|
||||
🎉 **۴۰۰٬۰۰۰ ستارهٔ GitHub — سپاسگزاریم!**
|
||||
|
||||
از همهٔ کسانی که از REA استفاده میکنند، خطاها را گزارش میدهند، قابلیتهای جدید پیشنهاد میکنند، buildها را آزمایش میکنند و در بهبود پروژه مشارکت دارند سپاسگزاریم.
|
||||
|
||||
|
||||
@@ -345,7 +345,7 @@ Signalez les vulnérabilités via [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Historique des étoiles
|
||||
|
||||
🎉 **300 000 étoiles GitHub — merci !**
|
||||
🎉 **400 000 étoiles GitHub — merci !**
|
||||
|
||||
Merci à toutes les personnes qui utilisent REA, signalent des bugs, proposent des fonctionnalités, testent les builds et contribuent des correctifs.
|
||||
|
||||
|
||||
@@ -366,7 +366,7 @@ Laporkan kerentanan melalui [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Riwayat Bintang
|
||||
|
||||
🎉 **300.000 bintang GitHub, terima kasih!**
|
||||
🎉 **400.000 bintang GitHub, terima kasih!**
|
||||
|
||||
Terima kasih kepada semua orang yang menggunakan REA, melaporkan bug, meminta fitur, menguji build, dan berkontribusi dalam perbaikan.
|
||||
|
||||
|
||||
@@ -345,7 +345,7 @@ Segnala vulnerabilità tramite [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Cronologia delle stelle
|
||||
|
||||
🎉 **300.000 stelle su GitHub — grazie!**
|
||||
🎉 **400.000 stelle su GitHub — grazie!**
|
||||
|
||||
Grazie a tutti coloro che usano REA, segnalano bug, propongono funzionalità, testano le build e contribuiscono con correzioni.
|
||||
|
||||
|
||||
@@ -350,7 +350,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## スター履歴
|
||||
|
||||
🎉 **GitHub スター 300,000 件、ありがとうございます!**
|
||||
🎉 **GitHub スター 400,000 件、ありがとうございます!**
|
||||
|
||||
REA の利用、バグ報告、機能の要望、ビルドのテスト、修正への貢献に感謝します。
|
||||
|
||||
|
||||
@@ -350,7 +350,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## 스타 기록
|
||||
|
||||
🎉 **GitHub 스타 300,000개, 감사합니다!**
|
||||
🎉 **GitHub 스타 400,000개, 감사합니다!**
|
||||
|
||||
REA를 사용하고, 버그를 보고하고, 기능을 요청하고, 빌드를 테스트하고, 수정에 기여해 주신 모든 분께 감사드립니다.
|
||||
|
||||
|
||||
@@ -355,7 +355,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## Star ചരിത്രം
|
||||
|
||||
🎉 **250,000 GitHub stars — നന്ദി!**
|
||||
🎉 **400,000 GitHub stars — നന്ദി!**
|
||||
|
||||
REA ഉപയോഗിക്കുന്നവർക്കും, bugs റിപ്പോർട്ട് ചെയ്യുന്നവർക്കും, features ആവശ്യപ്പെടുന്നവർക്കും, builds പരിശോധിക്കുന്നവർക്കും, fixes സംഭാവന ചെയ്യുന്നവർക്കും നന്ദി.
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ Zgłaszaj podatności zgodnie z [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Historia gwiazdek
|
||||
|
||||
🎉 **300 000 gwiazdek na GitHubie — dziękujemy!**
|
||||
🎉 **400 000 gwiazdek na GitHubie — dziękujemy!**
|
||||
|
||||
Dziękujemy wszystkim, którzy używają REA, zgłaszają błędy, proponują nowe funkcje, testują kompilacje i przesyłają poprawki.
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ Relate vulnerabilidades conforme [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Histórico de estrelas
|
||||
|
||||
🎉 **300.000 estrelas no GitHub — muito obrigado!**
|
||||
🎉 **400.000 estrelas no GitHub — muito obrigado!**
|
||||
|
||||
Obrigado a todos que usam o REA, relatam bugs, sugerem funcionalidades, testam builds e contribuem com correções.
|
||||
|
||||
|
||||
@@ -429,7 +429,7 @@ Raportează vulnerabilitățile conform [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Istoricul stelelor
|
||||
|
||||
🎉 **300.000 de stele pe GitHub — vă mulțumim!**
|
||||
🎉 **400.000 de stele pe GitHub — vă mulțumim!**
|
||||
|
||||
Mulțumim tuturor celor care folosesc REA, raportează erori, propun funcționalități,
|
||||
testează versiuni și contribuie cu remedieri.
|
||||
|
||||
@@ -348,7 +348,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## История звёзд
|
||||
|
||||
🎉 **300 000 звёзд на GitHub — спасибо!**
|
||||
🎉 **400 000 звёзд на GitHub — спасибо!**
|
||||
|
||||
Спасибо всем, кто использует REA, сообщает об ошибках, предлагает новые функции, тестирует сборки и помогает с исправлениями.
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## ประวัติดาว
|
||||
|
||||
🎉 **300,000 ดาวบน GitHub — ขอบคุณทุกคน!**
|
||||
🎉 **400,000 ดาวบน GitHub — ขอบคุณทุกคน!**
|
||||
|
||||
ขอบคุณทุกคนที่ใช้ REA รายงานบั๊ก เสนอฟีเจอร์ ทดสอบบิลด์ และช่วยแก้ไข
|
||||
|
||||
|
||||
@@ -344,7 +344,7 @@ Güvenlik açıklarını [SECURITY.md](../../SECURITY.md) üzerinden bildirin.
|
||||
|
||||
## Yıldız geçmişi
|
||||
|
||||
🎉 **GitHub'da 300.000 yıldız — teşekkürler!**
|
||||
🎉 **GitHub'da 400.000 yıldız — teşekkürler!**
|
||||
|
||||
REA'yı kullanan, hata bildiren, özellik talep eden, derlemeleri test eden ve düzeltmelere katkıda bulunan herkese teşekkürler.
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## Історія зірок
|
||||
|
||||
🎉 **300 000 зірок на GitHub — дякуємо!**
|
||||
🎉 **400 000 зірок на GitHub — дякуємо!**
|
||||
|
||||
Дякуємо всім, хто використовує REA, повідомляє про помилки, пропонує нові функції, тестує збірки й допомагає з виправленнями.
|
||||
|
||||
|
||||
@@ -432,7 +432,7 @@ Security vulnerabilities [SECURITY.md](../../SECURITY.md) ke zariye report karei
|
||||
|
||||
## Stars ki history
|
||||
|
||||
🎉 **300,000 GitHub stars — shukriya!**
|
||||
🎉 **400,000 GitHub stars — shukriya!**
|
||||
|
||||
REA use karne, bugs report karne, features suggest karne, builds test karne aur
|
||||
fixes contribute karne wale sab logon ka shukriya.
|
||||
|
||||
@@ -348,7 +348,7 @@ Báo cáo lỗ hổng theo [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Lịch sử sao
|
||||
|
||||
🎉 **300.000 sao trên GitHub — xin cảm ơn!**
|
||||
🎉 **400.000 sao trên GitHub — xin cảm ơn!**
|
||||
|
||||
Cảm ơn mọi người đã sử dụng REA, báo lỗi, đề xuất tính năng, kiểm thử bản dựng và đóng góp bản sửa lỗi.
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## Star 歷史
|
||||
|
||||
🎉 **GitHub Star 達到 300,000 個,感謝大家!**
|
||||
🎉 **GitHub Star 達到 400,000 個,感謝大家!**
|
||||
|
||||
感謝每一位使用 REA、報告錯誤、提出功能需求、測試建置和貢獻修復的朋友。
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## Star 历史
|
||||
|
||||
🎉 **GitHub Star 达到 300,000 个,感谢大家!**
|
||||
🎉 **GitHub Star 达到 400,000 个,感谢大家!**
|
||||
|
||||
感谢每一位使用 REA、报告错误、提出功能需求、测试构建和贡献修复的朋友。
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,112 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"repository": "morluto/rea",
|
||||
"version": "6.7.0",
|
||||
"base": "2c4338db1fdb7773e05376301c558cff2a0b4b80",
|
||||
"target": "b83b9caf4a5f0241a5fd370792f1aed1bffbb2cf",
|
||||
"commits": [
|
||||
{
|
||||
"sha": "8cbaf6c7021b97dd4de6b5771c35fbed06b240e9",
|
||||
"subject": "fix(tests): isolate command finalization module mocks",
|
||||
"body": "fix(tests): isolate command finalization module mocks\n\nMove the five registered WASM finalization cases into the existing per-file isolated project. Preserve all result, exit-code, observation and cleanup assertions. A preloaded shared CLI graph reproduces three failures before the move; the isolated covered packet passes.\n\nFixes #4959\n",
|
||||
"parents": ["2c4338db1fdb7773e05376301c558cff2a0b4b80"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "morluto",
|
||||
"email": "[email protected]",
|
||||
"user": {
|
||||
"login": "morluto",
|
||||
"__typename": "User"
|
||||
}
|
||||
}
|
||||
],
|
||||
"pullRequests": []
|
||||
},
|
||||
{
|
||||
"sha": "6b180783ed04ebc87548c8385c80e05725804c47",
|
||||
"subject": "fix(tests): budget CLI coverage from parsed options",
|
||||
"body": "fix(tests): budget CLI coverage from parsed options\n\nUse the pinned Vitest parser for coverage and shard flags. Keep ordinary CLI workers at 384 MiB and covered workers at the tested 512 MiB with unchanged concurrency. Retain complete coverage and add actual-config regressions for false, provider-only and spaced-shard options.\n\nValidation: 27 focused cases; 16 covered cases with CLI preloaded; 5 docs checks; typecheck/lint; exact discovery of 1578 files. Measured covered control: 22.18s elapsed, 46.52s CPU, about 2.33 GiB sampled summed process-family RSS on macOS arm64. Full Linux CI pending. No runtime/device verification claimed.\n\nFixes #4960\n",
|
||||
"parents": ["8cbaf6c7021b97dd4de6b5771c35fbed06b240e9"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "morluto",
|
||||
"email": "[email protected]",
|
||||
"user": {
|
||||
"login": "morluto",
|
||||
"__typename": "User"
|
||||
}
|
||||
}
|
||||
],
|
||||
"pullRequests": []
|
||||
},
|
||||
{
|
||||
"sha": "bb212ffecb47e129cc569b9867b2b6e7c9b65685",
|
||||
"subject": "fix(tests): inherit server identity deadline policy",
|
||||
"body": "fix(tests): inherit server identity deadline policy\n\nRemove per-case ten-second overrides from MCP catalog and identity checks. Keep the suite-owned bounded ordinary and coverage deadlines, all assertions, and session cleanup.\n\nFixes #4967\n",
|
||||
"parents": ["6b180783ed04ebc87548c8385c80e05725804c47"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "morluto",
|
||||
"email": "[email protected]",
|
||||
"user": {
|
||||
"login": "morluto",
|
||||
"__typename": "User"
|
||||
}
|
||||
}
|
||||
],
|
||||
"pullRequests": []
|
||||
},
|
||||
{
|
||||
"sha": "b83b9caf4a5f0241a5fd370792f1aed1bffbb2cf",
|
||||
"subject": "fix(setup): edit the duplicate JSON member that clients read (#4957)",
|
||||
"body": "fix(setup): edit the duplicate JSON member that clients read (#4957)\n\nJSON.parse, JSONC parse, and native Claude Code keep the last duplicate\nobject member, and parseClientConfiguration therefore validates the last\none. The shared setup/uninstall serializer instead edited text through\njsonc-parser's modify and findNodeAtLocation, which select the first\nmatching member, so setup and uninstall on configurations with repeated\nserver tables or rea members wrote into a shadowed member and failed\nreadback.\n\nLocate every JSON text edit by the effective (last) member in one place,\nreplacing the first-member modify path. Removing an effective member\nthat shadows an earlier duplicate would activate that duplicate, whatever\nits ownership, so the serializer now returns a tagged shadowed_member\nfailure and setup and uninstall refuse before writing a backup or the\nconfiguration.\n\nFixes #4952\n\nCo-authored-by: Claude Opus 5.5 <[email protected]>",
|
||||
"parents": ["bb212ffecb47e129cc569b9867b2b6e7c9b65685"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kaoru0822",
|
||||
"email": "[email protected]",
|
||||
"user": {
|
||||
"login": "kaoru0822-kitauji",
|
||||
"__typename": "User"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Claude Opus 5.5",
|
||||
"email": "[email protected]",
|
||||
"user": {
|
||||
"login": "claude",
|
||||
"__typename": "User"
|
||||
}
|
||||
}
|
||||
],
|
||||
"pullRequests": [4957]
|
||||
}
|
||||
],
|
||||
"pullRequests": [
|
||||
{
|
||||
"number": 4957,
|
||||
"title": "fix(setup): edit the duplicate JSON member that clients read",
|
||||
"url": "https://github.com/morluto/rea/pull/4957",
|
||||
"author": {
|
||||
"login": "kaoru0822-kitauji",
|
||||
"__typename": "User"
|
||||
},
|
||||
"mergeCommit": {
|
||||
"oid": "b83b9caf4a5f0241a5fd370792f1aed1bffbb2cf"
|
||||
},
|
||||
"issues": [
|
||||
{
|
||||
"number": 4952,
|
||||
"url": "https://github.com/morluto/rea/issues/4952",
|
||||
"author": {
|
||||
"login": "xu91102",
|
||||
"__typename": "User"
|
||||
},
|
||||
"repository": {
|
||||
"nameWithOwner": "morluto/rea"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+19
-1
@@ -349,7 +349,10 @@ tag remains in main's ancestry. Keep the released tag unchanged.
|
||||
|
||||
The synchronization must include `.release-please-manifest.json`,
|
||||
`package.json`, both root versions in `package-lock.json`, `CHANGELOG.md`,
|
||||
`server.json`, and the versioned documentation examples. Run
|
||||
`server.json`, both plugin manifests (`.claude-plugin/plugin.json` and
|
||||
`.codex-plugin/plugin.json`), the Codex server declaration (`.codex-plugin/mcp.json`), both
|
||||
marketplaces (`.claude-plugin/marketplace.json` and
|
||||
`.agents/plugins/marketplace.json`), and the versioned documentation examples. Run
|
||||
`npm run docs:generate`, `npm run docs:check`, and the release configuration
|
||||
tests against the combined tree. After the merge, verify that the released
|
||||
tag is an ancestor of main:
|
||||
@@ -383,3 +386,18 @@ tag. Do not dispatch a fresh publish phase to repair an already-created
|
||||
release: Release Please will not create the same release again. Do not move
|
||||
the tag, delete the release, or unpublish npm as a retry. A defective public
|
||||
package requires a reviewed correction and a new version.
|
||||
|
||||
### Plugin artifact metadata
|
||||
|
||||
Package verification selects files with npm, then packs an owned staging directory.
|
||||
The release manifest omits development dependencies and development-only overrides;
|
||||
its generated `npm-shrinkwrap.json` preserves the runtime dependency resolutions
|
||||
and integrity values from `package-lock.json`. Runtime or unresolved overrides
|
||||
fail packaging rather than being dropped. Source metadata is never rewritten.
|
||||
The archive bundles production dependencies because Codex fetches npm plugins
|
||||
without installing dependencies. The producer includes all locked PTY platform
|
||||
archives after checking their integrity, without re-resolving the runtime tree.
|
||||
Optional Frida stays outside the bundle so ordinary npm installation can retain
|
||||
its host-specific installer. This also lets Claude install locked dependencies under its plugin policy while
|
||||
retaining development security overrides. Both plugin marketplaces select the
|
||||
same qualified npm artifact, which the release workflow publishes unchanged.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Plan
|
||||
|
||||
1. Schema: `save` on request steps, `save_response` on click and press, the
|
||||
`saved` value source in headers and credential parts, `basic_credentials`
|
||||
with two parts, and the `{saved:name}` placeholder.
|
||||
2. Validation: every saved value a step sends was saved by an earlier step.
|
||||
3. Runtime: read the response body when a step saves, start waiting for a UI
|
||||
step's response before it acts, keep saved values with their JSON type,
|
||||
fill placeholders, build Basic credentials, and redact secret saves.
|
||||
4. Evidence: leave an empty `save` out of the recorded step.
|
||||
5. Environment build: warn about credential-named saved values not marked
|
||||
secret.
|
||||
6. Skill and docs: write through the UI first and save ids instead of guessing
|
||||
them; bump the skill version.
|
||||
7. Tests: schema, runtime with a fake page, Evidence parameters, the build
|
||||
warning, the catalog budget, and a real-Chrome recording.
|
||||
8. Write model: compose strings from generated ids and other fields, learn the
|
||||
`&` spelling of slugs, tell apart addresses whose parts are the same text,
|
||||
and check templates on later creates; census every recorded capture.
|
||||
9. End to end: agents build environments from prompts with main and with this
|
||||
branch on the same applications, and the branch's recordings are rebuilt
|
||||
before and after the write-model changes.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Saved values in browser scenarios
|
||||
|
||||
## Outcome
|
||||
|
||||
A browser scenario could not carry a value from one step to a later one. An
|
||||
agent recording an application from a prompt therefore guessed the id of the
|
||||
object it had just created, created probe objects to learn the next id, or
|
||||
read the object back by list only. An API that takes Basic auth, or a header a
|
||||
frontend builds from a login token, could not be sent at all, so the agent
|
||||
stopped and asked for an API key.
|
||||
|
||||
Steps now save strings and numbers from JSON responses, and later steps send
|
||||
them. A click or key press saves from a newly observed matching response,
|
||||
so a scenario can create an object the way the application's UI does and then
|
||||
open, read, edit or delete it by the id the application assigned. A request
|
||||
header can send Basic credentials built from literal, secret, saved or page
|
||||
values.
|
||||
|
||||
## Requirements
|
||||
|
||||
- A `request` step saves `[{name, json_pointer, secret}]` from its own JSON
|
||||
response. A `click` or `press` step's `save_response: {method, path, save}`
|
||||
saves from the first response that matches its method and a path on the start
|
||||
origin (`{*}` matches one segment; the query is ignored), which must be 2xx
|
||||
JSON. The wait starts before the step acts, and the step fails, saving
|
||||
nothing, unless such a response arrives and is read before its timeout or
|
||||
cancellation.
|
||||
- A pointer that names no string or number, a number that is not finite (such as
|
||||
`1e400`), a response that is not JSON or is larger than 4,000,000 characters
|
||||
(a UI step reads none received as more than 12,000,000 bytes, three per
|
||||
character), and a non-2xx `save_response` fail the step.
|
||||
- `{saved:name}` sends a saved value, percent-encoded, in a request path and its
|
||||
query and in a goto URL, and in a request's JSON body: a string that is only
|
||||
the placeholder becomes the saved value with its JSON type, and a placeholder
|
||||
inside a longer string is filled as text. Header values and Basic credential
|
||||
parts send `{source: "saved", name}`. Other braces are sent as written. A
|
||||
saved value that makes a path segment `.` or `..`, alone or with the text
|
||||
beside it, fails the step.
|
||||
- `basic_credentials` sends the base64 of `username:password` from `parts:
|
||||
[username, password]`, each a literal, declared secret, saved value, cookie or
|
||||
local storage entry. The encoded value and parts read from the page are
|
||||
redacted as page values are. A username with a colon fails the step.
|
||||
- Validation refuses a saved value no earlier step saves.
|
||||
- A scenario keeps at most 4,000,000 characters of saved values at once, counting
|
||||
the redaction spellings of values saved as secret; a save past that fails its
|
||||
step before the value is kept.
|
||||
- A value saved with `secret: true` is redacted from the selected source response
|
||||
before retention and from subsequent records. The environment build warns about saved values named like credentials
|
||||
that are not marked secret (`credential-named-saved-values`).
|
||||
- A scenario that saves nothing records the same Evidence parameters and
|
||||
`scenario_sha256` as before: an empty `save` is left out of the recorded
|
||||
step.
|
||||
- Earlier REA versions read captures that use saved values.
|
||||
- The compact MCP catalog stays under its measured one-megabyte frame.
|
||||
- The skill records writes the way the application's UI does and falls back to
|
||||
request steps when the UI cannot reach an operation or coverage withholds the
|
||||
UI-shaped write.
|
||||
- A UI-made create must be served as faithfully as one made through the API:
|
||||
- a string composed from a generated id and another field, such as Grafana's
|
||||
folder address, is learned as composed, not as a template around the id;
|
||||
- a slug learns how the application spells `&` from the call that shows it,
|
||||
and held entities that spell it both ways leave no slug rule;
|
||||
- an id that equals the title's slug is told apart by the entities the type
|
||||
holds, or by a later create;
|
||||
- a template a later create answers otherwise is withheld, as a composed
|
||||
string is.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- No general value transforms, string templates or script steps: the value
|
||||
kinds are fixed.
|
||||
- No saved values in `fill` or `select_option` values.
|
||||
- No retroactive redaction of earlier unrelated records.
|
||||
- No multi-factor sign-in.
|
||||
@@ -0,0 +1,15 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Record the outcome, requirements and non-goals.
|
||||
- [x] Add saved values, `save_response` and Basic credentials to the scenario schema.
|
||||
- [x] Validate that saved values are saved before use.
|
||||
- [x] Save and send values in the Playwright runtime.
|
||||
- [x] Keep scenarios that save nothing byte-identical in Evidence.
|
||||
- [x] Warn about credential-named saved values not marked secret.
|
||||
- [x] Update the skill and docs.
|
||||
- [x] Add unit, boundary and real-browser checks.
|
||||
- [x] Run the gates.
|
||||
- [x] Build prompt-recorded environments with main and with this branch.
|
||||
- [x] Make the skill's recording example write through the UI.
|
||||
- [x] Learn the addresses a UI-made create spells, and check templates on later creates.
|
||||
- [x] Rebuild the branch's recordings with the write-model changes and record every application again.
|
||||
@@ -0,0 +1,138 @@
|
||||
# Verification
|
||||
|
||||
This is Edgar Arakelyan's historical verification record from upstream PR #7162
|
||||
(head `d39f386d202fe8e98592fb2d9d26e43d8d0fb94f`), retained with attribution.
|
||||
These multi-application and model evaluations were not rerun during integration.
|
||||
The independent integration measurements and their limits are recorded in
|
||||
[saved-values integration verification](../../../verification/browser-saved-values-2026-10-26.md).
|
||||
|
||||
Executed on macOS with Node v24.22.1 at `feat/recorder-saved-values` e42362c9 (on main 2b84efe0), and on Ubuntu 24.04
|
||||
VMs with snap Chromium for the agent recordings.
|
||||
|
||||
## Gates
|
||||
|
||||
- `npm run typecheck`, `lint:built`, `format:check`, `metadata:check`, `verify:architecture-guards`, `knip:production`,
|
||||
`lint:typed`, `docs:check`, `mcp-catalog:check`, `verify:test-discovery`, `scan:todos` and `jscpd`: passed.
|
||||
`knip` reports one unused export, `isToolFamilyId` in `src/contracts/toolFamilies.ts`, which this branch does not
|
||||
touch and main 2b84efe0 reports too.
|
||||
- `npx vitest run --project domain --project services --project adapters`: 18,261 passed and 1 failed, "stops Inspector
|
||||
target authorization after the current stat settles", which fails the same way on main in this environment.
|
||||
- Browser scenario CLI and MCP boundaries, scenario input diagnostics, cancellation and cleanup, the analysis-view CLI
|
||||
and MCP boundaries, the environment build, export and serve CLI boundaries, the environment serve, served-writes and
|
||||
bundle MCP boundaries, tool schema validity, MCP schema validation, and output schema constraints and profile: 17
|
||||
files, 128 passed.
|
||||
- The compact MCP catalog must stay under the one-megabyte frame `outputSchemaProfile.test.ts` measures. A first
|
||||
design with `path_params` on request and goto steps, `json_values`, and separate `username` and `password` unions
|
||||
added 9,391 bytes on main ff6d96bc and failed the test, which then had 5,731 bytes to spare. Saved values now travel
|
||||
as `{saved:name}` placeholders, Basic credentials repeat their part union once, and repeated inner descriptions were
|
||||
dropped: on main 2b84efe0 the catalog takes 1,038,975 bytes and this branch 1,042,639.
|
||||
|
||||
## Compatibility
|
||||
|
||||
- Scenarios that save nothing record the same Evidence parameters and `scenario_sha256` on main and on this branch: a
|
||||
UI-only scenario with a goto to a URL holding literal braces, and a request step with a secret query value, a cookie
|
||||
header, and literal braces in its path and JSON body.
|
||||
- Main reads a capture that uses saved values: `environment-build --dry-run` of the real-Chrome capture below gives the
|
||||
same manifest, state, coverage and file plan on main and on this branch. This branch adds the
|
||||
`credential-named-saved-values` warning.
|
||||
- Write plans for 109 captures (the 50 published captures, 29 earlier agent recordings and the 30 recorded in the
|
||||
comparison below), built by main and by this branch: 524 plans and 247 served on each. Three plans differ, all
|
||||
Grafana folder creates recorded below, whose `url` the branch composes from the uid and the title's slug where main
|
||||
learned a template or nothing.
|
||||
|
||||
## Real Chrome
|
||||
|
||||
A local application with a cookie-session UI and an API that takes only Basic auth, recorded with Google Chrome:
|
||||
|
||||
- fill a name and click Save with `save_response` on `POST /ui/items`, saving the new id;
|
||||
- `goto` `/items/{saved:item1}` and wait for the item's page;
|
||||
- `GET /api/items/{saved:item1}` with Basic credentials whose username comes from local storage and password from a
|
||||
declared secret;
|
||||
- `POST /api/tokens`, saving the token both as a secret and, unmarked, as `session_token`;
|
||||
- `POST /api/items` with the saved token in a header and `{"name": "Child of {saved:item1}", "ref": "{saved:item1}"}`;
|
||||
- `PATCH /api/items/{saved:child}` and `GET /api/items?parent={saved:item1}`.
|
||||
|
||||
All 11 steps completed. The requests went to `/items/101`, `/api/items/101`, `/api/items/108` and `?parent=101`, and the
|
||||
body sent was `{"name":"Child of 101","ref":101}`. The Evidence parameters keep the placeholders, the password appears
|
||||
nowhere in the capture, and the token header is recorded as `[REDACTED:page:token.api_token]`. The token's own response
|
||||
was redacted too in this run; the docs say it may not be, since the recorder reads bodies on their own schedule.
|
||||
`environment-build` warned about `/parameters/actions/7/save/1`.
|
||||
|
||||
## Agent-built environments, main and this branch
|
||||
|
||||
Claude Code (`claude-sonnet-5-5`) built an environment of each application from the same prompt, with REA main
|
||||
ff6d96bc (skill 49) and with this branch (skill 50), on freshly seeded instances. Each bundle was rebuilt by the REA it
|
||||
was recorded with, and its write tasks run with `fireworks_ai/gpt-oss-120b` and `fireworks_ai/glm-5p3-flash`. Each task
|
||||
checks its result from the environment's state, including that nothing else changed.
|
||||
|
||||
The branch was recorded three times as it changed:
|
||||
|
||||
1. With the skill as first written, EspoCRM's agent wrote through request steps with Basic credentials instead of the
|
||||
UI, and EspoCRM's API answers in a shape the write model withholds (0/3). The skill's recording example created its
|
||||
object with a request step, which agents copy; it now creates through the UI with `save_response`.
|
||||
2. With that example, Grafana's agent created folders through the UI, where Grafana generates the uid. REA then learned
|
||||
the folder's `url` as a template around the uid that kept the first folder's slug, and coverage did not check the
|
||||
template against the second folder, so served creates answered with wrong addresses (0/2). The write-model fixes
|
||||
in this PR compose the address from the uid and the title's slug, learn Grafana's `&` spelling, and check templates
|
||||
on later creates.
|
||||
3. With both, every application was recorded again.
|
||||
|
||||
**The same recordings, before and after the write-model fixes.** Run 2's captures, rebuilt by this branch before and
|
||||
after the fixes (gpt-oss, GLM):
|
||||
|
||||
| Application | Before | After |
|
||||
| ----------- | ------------- | ------------- |
|
||||
| Miniflux | 3/3 3/3 | 3/3 3/3 |
|
||||
| Paperless | 1/3 2/3 | 1/3 1/3 |
|
||||
| Vikunja | 1/3 1/3 + 0/2 | 1/3 1/3 + 0/2 |
|
||||
| Linkding | 0/2 0/2 | 0/2 0/2 |
|
||||
| Homebox | 0/2 0/2 | 0/2 0/2 |
|
||||
| Grafana | 0/2 0/2 | 2/2 2/2 |
|
||||
| EspoCRM | 1/3 1/3 | 1/3 1/3 |
|
||||
|
||||
Only Grafana's plans change, and its tasks pass. Paperless's plans are identical in both builds; its GLM difference is
|
||||
the eval model's.
|
||||
|
||||
**Fresh recordings, main and the final branch:**
|
||||
|
||||
| Application | Write tasks | Main: served, tasks | Branch: served, tasks |
|
||||
| ----------- | ----------- | ---------------------- | --------------------- |
|
||||
| Miniflux | 3 | no bundle | 4, 3/3 3/3 |
|
||||
| Paperless | 3 | 3, 1/3 1/3; 6, 2/3 2/3 | 6, 1/3 2/3 |
|
||||
| Vikunja | 3 + 2 | 1, 0/3 0/3 + 0/2 0/2 | 3, 1/3 1/3 + 2/2 2/2 |
|
||||
| Linkding | 2 | 0, 0/2 0/2 | 3, 0/2 0/2 |
|
||||
| Homebox | 2 | 1, 0/2 0/2 | 5, 0/2 0/2 |
|
||||
| Grafana | 2 | 2, 2/2 2/2; 3, 2/2 2/2 | 1, 1/2 1/2 |
|
||||
| EspoCRM | 3 | 2, 1/3 1/3 | 2, 0/3 0/3 |
|
||||
| Total | 20 | 9, 4/20 4/20 | 24, 8/20 9/20 |
|
||||
|
||||
"Served" counts the write tools the final capture serves; tasks are gpt-oss then GLM, and Miniflux's count as failed
|
||||
without a bundle. Paperless and Grafana were recorded twice on main; totals use the first run.
|
||||
|
||||
- **Miniflux:** main's agent stopped and asked for an API key, since the API takes Basic auth. With Basic credentials
|
||||
the branch served category create, rename and delete in all three runs, and every category task passed with both
|
||||
models.
|
||||
- **Vikunja:** label edits and deletes are served and pass in two of the three branch runs, and task deletes in the
|
||||
last two.
|
||||
- **Saved ids:** every branch agent saved ids, with `save_response` on UI writes, and read objects back by them. On main
|
||||
no step can carry a value to a later one, so agents chose their own ids or read lists back instead.
|
||||
- **Paperless:** the two main runs differ as much as main and the branch do.
|
||||
- **Linkding and Homebox** serve more writes, but their create tasks still fail. Linkding's served create requires every
|
||||
member its recorded calls sent (`description`, `notes`, `unread`, `shared`, `tag_names`), so a task that sends a URL
|
||||
and a title is refused.
|
||||
- **Grafana:** the folder create is served with the right address and its task passes. The rename is withheld:
|
||||
Grafana lists folders sorted by title, the recording renamed a folder to a title that sorts first, and REA keeps an
|
||||
updated entity where it was in a list. Main's REA reads this recording the same way, and serves its create with the
|
||||
template that keeps the first folder's slug, so the create task would fail too. Main's two recordings passed because
|
||||
their titles kept their order.
|
||||
- **EspoCRM:** the recording started with a contact an earlier attempt in the same session created and left, so the
|
||||
environment holds it as seeded data and every task's "nothing else changed" check fails. The skill now asks agents to
|
||||
delete what an earlier attempt created before recording again; that change was not measured.
|
||||
- Agents spent $9.98 and 3,149 seconds in total on the fresh branch run, against $7.45 and 2,235 on main, a third of it
|
||||
Homebox's.
|
||||
|
||||
## Not verified
|
||||
|
||||
- One fresh recording per application and version, two for Paperless and Grafana on main; agent runs vary.
|
||||
- Lists sorted by a field that an update changes, and the skill's cleanup of earlier attempts.
|
||||
- Multi-factor sign-in, and saved values in `fill` or `select_option` steps, which this change does not add.
|
||||
@@ -17,6 +17,7 @@
|
||||
6. Tests: the collector stamps both fields, records take them, the state learns
|
||||
the HAR's clock and verdicts from a timed scenario and none from an untimed
|
||||
or partly untimed one, a request that never ended or ended twice falls back
|
||||
to its observation, comparisons ignore the times (also against an untimed
|
||||
to its observation with unknown duration omitted, an explicit zero remains
|
||||
observed, comparisons ignore the times (also against an untimed
|
||||
capture), and the real-Chrome network lane checks every request is observed
|
||||
and every finished request carries the browser's start and duration.
|
||||
@@ -27,9 +27,9 @@ scenario capture learns the clock a HAR does.
|
||||
Evidence that carries them.
|
||||
- Scenario records take `startedDateTime` from the transaction's single
|
||||
finished or failed event's `started_at`, else from `observed_at`, and `time`
|
||||
from its `elapsed_ms` (0 without one), and say so in a limitation; a capture
|
||||
whose requests are all timed gets the recorded-start-time timeline and a
|
||||
write clock.
|
||||
from its `elapsed_ms`, omitted without a unique reported duration, and say so
|
||||
in a limitation. An explicit zero remains zero. Complete starts establish the
|
||||
recorded-start-time timeline; a write clock also requires known completions.
|
||||
- Scenario comparisons ignore both fields, as a committed built-in rule
|
||||
(`ignore_network_request_timing`).
|
||||
- The added metadata is charged to the event budgets as other metadata is.
|
||||
|
||||
@@ -543,7 +543,11 @@ contradicts it. Otherwise the reason, in this precedence, is:
|
||||
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.
|
||||
a held value;
|
||||
6. `unknown-clock`: an otherwise servable plan needs `clock`, `held-clock`, or
|
||||
`nested-clock`, but the capture establishes no global served clock start.
|
||||
Its learned rules and confirming reads remain retained, and plans without
|
||||
this clock dependency remain eligible for serving.
|
||||
|
||||
`checked_record_ordinals` lists the confirming reads.
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Implementation plan
|
||||
|
||||
1. **Query values.** Widen the query property schema and spell numbers and booleans as JSON text where a call enters
|
||||
serving.
|
||||
2. **Sequence start.** `start` on sequence rules and their schema; the exemplar records integer fields above every held
|
||||
value; serving and replay floor the next value at `start`.
|
||||
3. **Later rules.** Merging a later create adopts its `composed`, `template` or started `sequence` rule when it spells
|
||||
the exemplar's value.
|
||||
4. **Made objects.** The `made-object` rule and schema; its explanation, merge, later-call check, counts taken, serving
|
||||
and own members.
|
||||
5. **Bulk link.** `respondedIds` reads the object of a one-element array member; `anyLinkedSource` lets a linked
|
||||
create take any path values its plan stores in fields, in replay and serving.
|
||||
6. **Skill, tests and docs.**
|
||||
@@ -0,0 +1,46 @@
|
||||
# Serve the calls agents make and the values applications count
|
||||
|
||||
Issue: https://github.com/morluto/rea/issues/4933
|
||||
|
||||
## Outcome
|
||||
|
||||
Eval agents' trajectories on rebuilt environments, and the write plans of the recordings they ran on, showed three
|
||||
gaps REA could close:
|
||||
|
||||
- **Query values.** Served tools typed each query parameter as a string or an array of strings, while agents send page
|
||||
sizes and flags as JSON numbers and booleans (`maxSize: 50`, `withItems: true`). The MCP server refused those calls
|
||||
before REA saw them: 63 of 418 stored eval runs hit it, in EspoCRM, Homebox and PhotoPrism, and 18 never got the tool
|
||||
to answer.
|
||||
- **Counted and made values.** Vikunja numbers a project's tasks past those deleted earlier, so a created task's
|
||||
`index` is not one past what the state holds; its `identifier` spells that index; and each created task gets a
|
||||
`subscription` object the application makes with it. A second create disagreed with the first on all three, so
|
||||
task creates were withheld.
|
||||
- **Bulk creates.** Vikunja's UI creates a task through `POST /projects/{id}/tasks/bulk`, sending and answering the
|
||||
task wrapped in `tasks: [ … ]`. The answer's id sat inside the array, so REA linked the call to no type.
|
||||
|
||||
The diagnosis also found that a recorded update stores only what it sent (EspoCRM's updates never changed an email
|
||||
address), and that an object known only from a list that leaves out fields its own read shows can be neither read by
|
||||
id nor updated. Both are recording gaps the skill now addresses.
|
||||
|
||||
## Behaviour
|
||||
|
||||
- **Query values.** A query parameter accepts a number or boolean besides a string or an array of strings, and serving
|
||||
sends it as its JSON text.
|
||||
- **Sequences from a start.** A field the first create showed above every value its type held, which a later create
|
||||
shows one past the first's, is a `sequence` with that `start`: serving never goes below it.
|
||||
- **Rules that spell the first create.** A field the plan kept as shown takes a later create's rule when that rule also
|
||||
spells the first create's value: a `composed` or `template` string, or the `sequence` above.
|
||||
- **Made objects.** A created object no other entity of the type holds otherwise, with a member the request stamped, is
|
||||
a `made-object`: stamped members take the write's clock, members holding the entity's identity take its id, counts
|
||||
go one past the largest value held objects show from a `start`, and other members stay as recorded.
|
||||
- **Linked bulk creates.** A create's answer names the id of the one object a one-element array member holds. A linked
|
||||
create accepts any path values when it creates into its type's own collection, whose path has no parameters, and
|
||||
stores each path value in a field, as a Vikunja task stores its project: no path value changes where it creates.
|
||||
- **Skill.** Recordings read each listed object by id, up to ten per collection, before writing.
|
||||
|
||||
Plans and views that need none of this are unchanged.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- No write tool of the 130 recorded captures goes from served to withheld.
|
||||
- Rebuilt from the same recordings, the branch passes at least the write tasks #7274 passes.
|
||||
@@ -0,0 +1,13 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Accept numbers and booleans for query parameters.
|
||||
- [x] Start a sequence from the value its first create took.
|
||||
- [x] Adopt a later create's rule that spells the first create's value.
|
||||
- [x] Learn, check and serve objects made with an entity.
|
||||
- [x] Link creates whose answer wraps the entity in a one-element array, and let a linked create take path values
|
||||
it stores.
|
||||
- [x] Ask recordings to read each listed object by id.
|
||||
- [x] Add view, serving, MCP boundary and unit tests.
|
||||
- [x] Document the rules and the query argument types.
|
||||
- [x] Measure the recorded captures and served write tasks.
|
||||
- [x] Run static, formatting, documentation and test gates.
|
||||
@@ -0,0 +1,88 @@
|
||||
# Verification
|
||||
|
||||
Executed on macOS with Node v24.22.1 on this branch merged with #7274 at `45832406` (main `8706068b`), and on Ubuntu
|
||||
24.04 VMs for the task runs.
|
||||
|
||||
## Diagnosis
|
||||
|
||||
The 418 eval runs stored on the comparison VMs, with their agent trajectories:
|
||||
|
||||
- 63 runs had a call refused before REA saw it because a query value came as a JSON number or boolean (`maxSize`,
|
||||
`pageSize`, `withItems`, `isLocation`, PhotoPrism's `count`, `offset`, `merged`, `public`), and in 18 the agent never
|
||||
got that tool to answer.
|
||||
- EspoCRM's contact update fails in every run: the served update accepts only the members recorded updates stored
|
||||
(`description`, `name`, `lastName`), and a seeded contact known only from lists can be neither read by id nor
|
||||
answered for. On #7274, gpt-oss passes the task by creating a replacement contact and deleting the original.
|
||||
- Vikunja's task creates were withheld by an unexplained `index`, `identifier` and `subscription` (main's recording),
|
||||
or had no state target, being bulk creates (four recordings).
|
||||
|
||||
## Gates
|
||||
|
||||
- `npm run -s check:fast`, `format:check`, `scan:todos`, `docs:check`, `verify:test-discovery`, `mcp-catalog:check` and
|
||||
`jscpd`: passed. `npx knip` reports `staticFileUrlPath` and `ObjcClassImportBindingCoverage`, which main `8706068b`
|
||||
added and this branch does not touch.
|
||||
- `npx vitest run --project domain --project services`: 11,430 passed, 6 skipped. `--project adapters`: 7,437 passed, 19
|
||||
skipped, 3 failed: the Inspector cancellation test and two AppKit asset-catalog tests, which fail the same way on
|
||||
#7274 at `e29e9c74`.
|
||||
- `npm run -s test:focused --` the environment build, export and serve CLI boundaries, the analysis-view CLI and MCP
|
||||
boundaries and the environment serve MCP boundary: passed. `outputSchemaProfile`, `toolSchemaValidity`,
|
||||
`mcpSchemaValidation` and `outputSchemaSemanticConstraints`: passed; the compact catalog stays under its frame.
|
||||
|
||||
## Tests
|
||||
|
||||
- View: two task creates at a project path learn `index` as a `sequence` from 15, `identifier` as a `template` around
|
||||
it and `subscription` as a `made-object` whose `id` counts from 21 and whose `entity_id` holds the task's own id; one
|
||||
create alone keeps `index` as recorded; a bulk create whose body and answer wrap the task in `tasks` links to the
|
||||
tasks type and is served; an object with no member the request stamped makes no rule.
|
||||
- Serving: created tasks take index 15 then 16, `#15` then `#16`, and a subscription numbered 22 holding the second
|
||||
task's id; a bulk create answers in its envelope, and one into another project stores that project.
|
||||
- Query values: a number or boolean query value is spelled as its JSON text, and a list paged by a number answers as
|
||||
with the same text; through the MCP server, `maxSize: 2` and `withItems: true` replay their recording exactly. The
|
||||
served card of the `renamed` fixture grows 637 bytes, 91 for each of its seven query parameters.
|
||||
- The seven behaviour tests fail on #7274 at `4ede1305`.
|
||||
|
||||
## Write plans and views over recorded captures
|
||||
|
||||
The 130 captures #7274 measured, built by #7274 at `45832406` and by this branch: 615 plans, 332 served and 333.
|
||||
|
||||
- No write goes from served to withheld. Newly served: Vikunja's bulk task create in #7260's final recording.
|
||||
- Vikunja's task create in main's recording is now explained, by its counter, template and made subscription, but
|
||||
main's `unknown-clock` withholds it in both builds, as that capture has no clock anchor. Measured on #7274 at
|
||||
`4ede1305`, before that rule, it was served too (339 to 341).
|
||||
- Six plans that stay withheld explain more: Homebox entity creates learn `assetId` as a counter from 5 in four
|
||||
recordings, and Vikunja task creates in two.
|
||||
- In #7260's two Vikunja recordings whose UI writes lost their bodies, the bulk create now counts as a task write, so
|
||||
the scratch task it made is no longer held as seeded (35 to 34 and 36 to 35 initial entities), a read tool that read
|
||||
only that task replays its recordings, and later reads check fewer lines. Every other view is unchanged.
|
||||
|
||||
## The same recordings, built by #7274 and by this branch
|
||||
|
||||
Claude Code (`claude-sonnet-5-5`) recordings from earlier rounds, rebuilt by #7274 at `e839af3f` (its last two merges
|
||||
change no census) and by this branch, their write tasks run with `fireworks_ai/gpt-oss-120b` then
|
||||
`fireworks_ai/glm-5p3-flash`, each checked from the environment's state:
|
||||
|
||||
| Recording | Write tasks | #7274 | This branch |
|
||||
| ---------------------------------------------------------- | ----------- | ----------- | ----------- |
|
||||
| Vikunja: #7260 final (bulk creates) | 3 + 2 | 1/5 1/5 | 2/5 2/5 |
|
||||
| Vikunja: main (two), saved-values (two), #7260 (first two) | 6 × (3 + 2) | 6/30 6/30 | 6/30 6/30 |
|
||||
| EspoCRM: main, #7260 (three), saved-values | 5 × 3 | 15/15 10/15 | 15/15 10/15 |
|
||||
| Homebox: main, #7260 final, saved-values (two) | 4 × 2 | 6/8 6/8 | 6/8 6/8 |
|
||||
| Total | 58 | 28/58 23/58 | 29/58 24/58 |
|
||||
|
||||
No recording passes fewer tasks with this branch.
|
||||
|
||||
- **Vikunja, bulk creates:** the create task passes with both models. The served bulk create numbers the task and makes
|
||||
its subscription, and creates into Lighthouse Rota though the recording created into the inbox.
|
||||
- **Refused calls:** agents' calls were refused at input validation 34 times with #7274 (30 in Vikunja) and once with
|
||||
this branch, and agents made 286 tool calls against 317.
|
||||
- **Main's `unknown-clock`** withholds Vikunja's task create and Homebox's tag create in main's recordings in both
|
||||
builds, so those tasks fail in both. Rebuilt by #7274 at `4ede1305`, before that rule, this branch without the
|
||||
linked-path change made main's Vikunja create task pass with both models (1/3 to 2/3) and changed no other result
|
||||
among the recordings that finished.
|
||||
|
||||
## Not verified
|
||||
|
||||
- A fresh recording with skill 52, which reads each listed object by id.
|
||||
- Path parameters given as numbers stay refused: they are required properties, which REA keeps free of combinators.
|
||||
- A counter one create alone shows, and linked creates into a collection whose path has parameters, which still take
|
||||
only their recorded path values.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Implementation plan
|
||||
|
||||
1. **Blank members.** `WriteBody.blank` and its schema; creates explain empty members as blank; merges join them;
|
||||
created fields apply a left-out blank member as sent.
|
||||
2. **Listed ids.** `listed_ids` on list views and its schema; the gate learns them; list rendering sets them.
|
||||
3. **Sorted collections.** The replayed state moves an entity whose sorted field changed; update plans carry the
|
||||
type's sort; serving moves updated entities; a failed whole-collection read after an update can teach the sort.
|
||||
4. **Observations.** A create's item read-back accepts unloaded answer values; updates treat empty-container
|
||||
respellings as unchanged; later creates check unruled fields.
|
||||
5. **Skill, schema, tests and docs.**
|
||||
@@ -0,0 +1,56 @@
|
||||
# Serve the writes callers make without recorded form fields
|
||||
|
||||
Issue: https://github.com/morluto/rea/issues/4933
|
||||
|
||||
## Outcome
|
||||
|
||||
Agents now record writes through an application's UI, and environments built that way refused most of the creates
|
||||
natural-language tasks ask for, or withheld them:
|
||||
|
||||
- A form sends every field it shows, the ones left alone as `""`, `null`, `false`, `[]` or `{}`. Every member a
|
||||
recorded create sent was required, so a call naming only a title was refused (Homebox tags required `color` and
|
||||
`icon`, Linkding bookmarks `notes`, `unread` and `shared`, EspoCRM contacts about twenty members).
|
||||
- Paperless-ngx answers lists with `all`, the ids of the listed entities in list order. The state did not render it,
|
||||
so the first list read after every Paperless create contradicted the create.
|
||||
- Grafana lists folders by title and Paperless lists tags by name. An update kept its entity where it was, so a rename
|
||||
that sorted elsewhere contradicted the update, and a served rename listed in the wrong order.
|
||||
- A Vikunja create answers before it loads what it stored: the owner with empty fields and Go's zero time, and empty
|
||||
lists as `[]` where reads show `null`. The later item read was not taken as the observation, so it contradicted the
|
||||
create; an update whose answer spelled an empty list `[]` was unexplained.
|
||||
|
||||
## Behaviour
|
||||
|
||||
- **Blank members.** A create member a recorded call sent empty is not required. A call that leaves it out is applied
|
||||
as sending that value (`body.blank`), so the entity, the answer and every rule reading the member come out as for
|
||||
the recorded call. A member a later call left out takes the default it showed instead. A call may send a member as
|
||||
any recorded call sent it empty, such as `null` where another stored a string, even once a default is learned, and
|
||||
one leaving it out without a default is applied as the earliest did. Updates are unchanged.
|
||||
- **Listed ids.** A list view names top-level envelope members that list two or more listed entities' identity values
|
||||
in list order (`listed_ids`). A rendered list sets them to its own entities' values, unless it is a page of more
|
||||
matches, which keeps the recorded value as a partial page's total does.
|
||||
- **Sorted collections.** An update that writes the field its type's creates are sorted by moves its entity to where
|
||||
the new value sorts, in replay and serving (a bulk update moving each entity in turn), and its plan carries that
|
||||
`insert`. When a read listing the whole collection in collection order (not sorted by its query) fails after an
|
||||
update and the type's creates are not sorted by a
|
||||
field the update writes, replay tries the collection sorted by such a field when the entities no exercised write
|
||||
changed already follow it, as serving moves only written entities, and unless a create was placed by a sort
|
||||
that excludes it or a whole-collection read in collection order (not sorted by its query) that placed a create did
|
||||
not follow it; on a match, the type's creates and updates take that order.
|
||||
- **Unloaded answers.** A create's later item read is taken as its observation when it differs from the answer only in
|
||||
values the answer had not loaded: empty, zero, `false` or Go's zero time, or objects whose members are each the same
|
||||
or loaded so; the plan points to those values (`observation.read.unloaded`), which a served create's answer keeps as
|
||||
the recorded answer showed them, unless the call sent one the plan stores as sent, while the state holds the read's. An unsent update field that changes only between
|
||||
`null`, `[]` and `{}` is unchanged. Write answers, bulk answers and replay's checks of them included, spell empty
|
||||
lists and maps the call did not send as their recorded answers did, and a sent one as sent.
|
||||
- **Unruled fields.** A later create that stored a field no rule writes otherwise than the plan keeps it is
|
||||
`unexplained-change` at the create, so its recorded entity is held and later reads check other writes as before.
|
||||
- **Skill.** The two scratch creates differ in what they send, the second only what a person must give, however they
|
||||
are made; the skill shows how to read signed-in pages' accessibility trees from a scenario, and re-records once with
|
||||
request steps a UI write whose body the browser did not expose.
|
||||
|
||||
Plans and views that need none of this are unchanged.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- No write tool of the 109 recorded captures goes from served to withheld.
|
||||
- Rebuilt from the same recordings, the branch passes at least the write tasks main passes.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Learn blank create members and apply them when a call leaves them out.
|
||||
- [x] Learn and render list envelope members listing the listed ids.
|
||||
- [x] Move updated entities in sorted collections, in replay and serving, and learn a sort from a rename.
|
||||
- [x] Take item read-backs over unloaded create answers and empty-container respellings.
|
||||
- [x] Withhold later creates that store an unruled field otherwise.
|
||||
- [x] Add view, serving and unit tests.
|
||||
- [x] Document the rules and view member, and update the skill.
|
||||
- [x] Measure the recorded captures and served write tasks.
|
||||
- [x] Run static, formatting, documentation and test gates.
|
||||
@@ -0,0 +1,124 @@
|
||||
# Verification
|
||||
|
||||
Executed on macOS with Node v24.22.1 at `5a3c6762` (main `99062fea`), and on Ubuntu 24.04 VMs with snap Chromium for
|
||||
the agent recordings.
|
||||
|
||||
## Gates
|
||||
|
||||
- `npm run -s check:fast`, `format:check`, `scan:todos`, `docs:check`, `verify:test-discovery`, `mcp-catalog:check` and
|
||||
`jscpd`: passed. `npx knip` reports one unused export, `isToolFamilyId` in `src/contracts/toolFamilies.ts`, which this
|
||||
branch does not touch and main reports too.
|
||||
- `npx vitest run --project domain --project services --project adapters`: 18,281 passed, 25 skipped, 1 failed ("stops
|
||||
Inspector target authorization after the current stat settles"), which fails the same way on main in this environment.
|
||||
- `npm run -s test:focused --` the environment build, export and serve CLI boundaries, the analysis-view CLI and MCP
|
||||
boundaries and the environment serve MCP boundary: 7 files, 75 passed. `outputSchemaProfile.test.ts`: 4 passed; the
|
||||
full catalog grows 648 bytes and the compact catalog, 554,640 bytes, does not change.
|
||||
|
||||
## Tests
|
||||
|
||||
- View: form creates whose empty members differ require only the member both filled and apply the others as sent; a
|
||||
create with only a last name, sending `null` for strings and for a flag another create sent `false`, merges and is
|
||||
served; a rename moves a label in a collection its
|
||||
creates sort by name; a rename that sorts first teaches a folder collection's title order to its creates and updates;
|
||||
a list envelope's `all` is learned and creates there are confirmed; a create answer with an unloaded owner and `[]`
|
||||
for `null` takes its item read; an update answer spelling an empty list `[]` is unchanged; a later create storing a
|
||||
derived field otherwise is withheld at the create and later deletes stay confirmed.
|
||||
- Serving: a label created from its name alone stores the empty members as sent and is inserted by name, and one
|
||||
without the required name is refused; renamed labels and folders move to where their new names sort, and a bulk
|
||||
rename of two labels moves each; a created tag's id appears in the list envelope's `all` in list order; a note sent
|
||||
`null` as one recording did is accepted after a later call taught `""` as its default, which a note left out takes;
|
||||
a created and an updated task answer `assignees: []` as their recordings did while reads show `null`.
|
||||
- Review cases: a member's recorded empty value stays accepted once a default is learned; a rename teaches title order
|
||||
where the creates fit both id and title order; moving written entities in turn sorts `[a, b, c, d]` with `b→h` and
|
||||
`c→i` as `[a, d, h, i]`. The plan and serving tests for these fail on the branch's first head `0ceff6fa`.
|
||||
|
||||
## Write plans over recorded captures
|
||||
|
||||
The 109 captures the saved-values branch measured: 50 published captures and 59 Claude Code recorded from a prompt,
|
||||
built by main and by this branch.
|
||||
|
||||
| Captures | Write plans | Served on main | This branch |
|
||||
| ------------------------- | ----------- | -------------- | ----------- |
|
||||
| 50 published | 187 | 70 | 70 |
|
||||
| 59 recorded from a prompt | 337 | 177 | 209 |
|
||||
|
||||
No write goes from served to withheld. The 32 newly served are 23 Paperless creates (tags, correspondents and document
|
||||
types, every recording), 3 Vikunja label creates, a Vikunja task update, Grafana's folder rename and delete, a Homebox
|
||||
tag delete, and a Linkding bundle update and delete. 65 plans require fewer members and 66 carry `body.blank`; 30 plans
|
||||
change `insert`, mostly updates that now move their entity by the field their type's creates sort by.
|
||||
|
||||
## Agent-built environments
|
||||
|
||||
Claude Code (`claude-sonnet-5-5`) built an environment of each of seven applications from the same prompt, as the
|
||||
saved-values branch measured, and each bundle's write tasks ran with `fireworks_ai/gpt-oss-120b` and
|
||||
`fireworks_ai/glm-5p3-flash`. Each task checks its result from the environment's state, including that nothing else
|
||||
changed.
|
||||
|
||||
The Homebox and Linkding task specs used until now checked for seed objects an earlier round's recordings left behind
|
||||
("Rec Fragile", `scratch-two.example.test`), which no current recording holds, so their "nothing else changed" check
|
||||
could not pass. They now check the current seed. With the corrected specs, main passes both Homebox and both Linkding
|
||||
tasks on the saved-values branch's recordings, so earlier rounds' 0/2 for those applications measured the specs, not
|
||||
the required members.
|
||||
|
||||
**The same recordings, built by main and by this branch** (gpt-oss, GLM):
|
||||
|
||||
| Recording | Write tasks | Main | This branch |
|
||||
| ----------------------------- | ----------- | --------- | ----------- |
|
||||
| Paperless, saved-values | 3 | 1/3 2/3 | 3/3 3/3 |
|
||||
| Paperless, main (two) | 3 + 3 | 3/6 3/6 | 5/6 5/6 |
|
||||
| Grafana, saved-values | 2 | 0/2 0/2 | 1/2 1/2 |
|
||||
| Grafana, main (two) | 2 + 2 | 3/4 3/4 | 4/4 3/4 |
|
||||
| Vikunja, saved-values + main | 5 + 5 | 3/10 3/10 | 3/10 3/10 |
|
||||
| EspoCRM, saved-values + main | 3 + 3 | 1/6 1/6 | 1/6 1/6 |
|
||||
| Homebox, saved-values + main | 2 + 2 | 2/4 2/4 | 2/4 2/4 |
|
||||
| Linkding, saved-values + main | 2 + 2 | 2/4 2/4 | 2/4 2/4 |
|
||||
| Miniflux, saved-values | 3 | 3/3 3/3 | 3/3 3/3 |
|
||||
| Total | 42 | 18 19 | 24 23 |
|
||||
|
||||
No recording passes fewer tasks with this branch. Paperless creates pass once served. The saved-values Grafana
|
||||
recording's rename is served and passes; its create still needs the saved-values branch's composed address.
|
||||
Vikunja's task create, EspoCRM's leftover contact (held as seeded data, so every "nothing else changed" check fails)
|
||||
and the main Homebox recording, which wrote no tags, are unchanged.
|
||||
|
||||
**Fresh recordings.** Each application was recorded afresh with main (skill 49) and with this branch. The branch was
|
||||
recorded again for the four applications whose first branch recording passed fewer tasks, and a third time after the
|
||||
skill's sixth step was reworded; the final skill's recordings are the last column (served writes, then tasks):
|
||||
|
||||
| Application | Write tasks | Main | Branch, first two recordings | Branch, final skill |
|
||||
| ----------- | ----------- | -------------------- | ---------------------------- | -------------------- |
|
||||
| Paperless | 3 | 2, 1/3 2/3 | 8, 1/3 2/3 | |
|
||||
| Linkding | 2 | 0, 0/2 0/2 | 5, 2/2 2/2 | |
|
||||
| Miniflux | 3 | no bundle | 4, 3/3 3/3 | |
|
||||
| Grafana | 2 | 3, 2/2 2/2 | 1, 0/2 1/2; 3, 1/2 2/2 | 0, 0/2 0/2 |
|
||||
| Vikunja | 3 + 2 | 3, 1/3 1/3 + 2/2 2/2 | 0, 0/5 0/5; 0, 0/5 0/5 | 1, 1/3 1/3 + 0/2 0/2 |
|
||||
| EspoCRM | 3 | 2, 1/3 1/3 | 2, 1/3 1/3; 2, 1/3 1/3 | 2, 1/3 1/3 |
|
||||
| Homebox | 2 | 4, 2/2 2/2 | 1, 0/2 0/2; 1, 0/2 0/2 | 3, 2/2 2/2 |
|
||||
|
||||
Every fresh recording builds the same plans with main and with this branch, except Paperless (main serves 0 of the
|
||||
branch recording's writes and 2 of 3 of its own), Vikunja's main recording (3 to 4) and the EspoCRM recordings below;
|
||||
the per-application differences are what each agent recorded:
|
||||
|
||||
- **Paperless:** the branch recording serves creates, renames and deletes of tags, correspondents and document types.
|
||||
Its two tag creates used a light and a dark color, whose derived `text_color` differs, so the tag create stays
|
||||
withheld and the tasks, which create a tag, score as on main.
|
||||
- **Linkding:** main's agent recorded no writes. The branch's second bookmark create sent only `url` and `title`, so
|
||||
the served create requires only those.
|
||||
- **Miniflux:** main's agent stopped and asked for an API key. The branch's agent created a token in the UI and sent it
|
||||
as a literal header value, which REA recorded as written; the instance and its token were destroyed afterwards.
|
||||
- **EspoCRM:** following the sixth step, the branch's second contact sent only a last name, with `null` for strings the
|
||||
first stored and for flags it sent `false`. That merge was refused until the empty-spelling fix in this PR; with it,
|
||||
the create requires only `lastName` and `name` and its task passes, as on main.
|
||||
- **Vikunja:** the first two branch agents wrote through the UI, whose request bodies Chromium did not expose, so every
|
||||
write was `body-unusable`. The sixth step then read "fill every field the form offers"; reworded to say how the
|
||||
creates differ, not where they are made, the third agent wrote with request steps. It recorded no label writes.
|
||||
- **Homebox:** the first two branch agents recorded item writes only, the third tags as main's did.
|
||||
- **Grafana:** the branch agents created folders with request steps and their own uids. The second create's address
|
||||
needs the saved-values branch's composed-address fixes to be explained, so the create is withheld here.
|
||||
|
||||
## Not verified
|
||||
|
||||
- One to three fresh recordings per application and version; agent runs vary more than the builds do.
|
||||
- Request bodies Chromium does not expose for some UI writes (Vikunja's); the skill now re-records such a write once
|
||||
with request steps.
|
||||
- Paperless derives `text_color` from `color`, so a create whose two recorded colors differ in brightness stays
|
||||
withheld; EspoCRM's create still requires `name` and `emailAddressData`, which it derives from other members.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Implementation plan
|
||||
|
||||
1. **Soft deletes.** `markedDeleted` reads the deleted flags; item-read checks, adoption and replay's resync treat a
|
||||
marked object as absent.
|
||||
2. **Page sizes.** Add the names to the paging and query `limit` sets.
|
||||
3. **Later fields.** Extraction collects the members later plain item reads show; the gate adds those no merged entity
|
||||
holds to the item view without requiring them.
|
||||
4. **Answers.** `laterItemFields` names the item view's fields no initial entity holds; write answers and the verdict's
|
||||
`incomplete-entities` check skip them for entities without them.
|
||||
5. **Skill, tests and docs.**
|
||||
@@ -0,0 +1,42 @@
|
||||
# Serve the writes that later reads explain
|
||||
|
||||
Issue: https://github.com/morluto/rea/issues/4933
|
||||
|
||||
## Outcome
|
||||
|
||||
Environments built from a prompt withheld some writes in every recording of an application, though the recordings read
|
||||
each write back:
|
||||
|
||||
- EspoCRM keeps a deleted record. A read of it answers `200` with the record and `deleted: true`, which replay took
|
||||
as the record still being there, so contact and task deletes were contradicted or left unconfirmed.
|
||||
- EspoCRM pages its lists with `maxSize`, which REA did not know as a page size, so a list read after a delete was not
|
||||
taken as listing the whole collection and confirmed nothing.
|
||||
- Vikunja shows `subscription` only on tasks created after the recording started. The tasks' item view did not show
|
||||
it, so reads of created tasks disagreed with the state and contradicted the task update before them; and an update
|
||||
whose recorded answer shows it could not answer for a seeded task, which lacks it.
|
||||
|
||||
## Behaviour
|
||||
|
||||
- **Soft deletes.** An item read whose object is marked deleted (`deleted`, `isDeleted` or `is_deleted` set to `true`)
|
||||
agrees with an entity the state does not hold, as a `404` does. Replay drops the entity such a read names, and such
|
||||
an object never seeds or adopts an entity. The item view records the flag its reads set as `deleted_flag`, and
|
||||
serving keeps an entity a served delete removed from such a type until a reset or load, so a read of it by id answers
|
||||
its last fields with the flag `true`, as the application does.
|
||||
- **Page sizes.** `maxSize`, `max_results` and `maxResults` are page sizes, for a list read's whole-collection
|
||||
membership and for a list query's `limit` role.
|
||||
- **Fields only later reads show.** An item view also shows the members that reads after its type's first write show
|
||||
of the entities they name, when no initial entity holds them. They are never required. An update or delete that
|
||||
answers with the entity, a bulk update's answer included, leaves such a field out when the entity does not hold it,
|
||||
and the field no longer makes the write `incomplete-entities`. A field some initial entity holds keeps the existing rule: an answer showing it is
|
||||
refused for an entity without it.
|
||||
- **Skill.** Updates change the fields a person would change (a name, an email address, a status, a due date) rather
|
||||
than only a description, since a served update accepts only the members a recorded update stored, and a deleted
|
||||
object may read back marked deleted instead of `404`.
|
||||
|
||||
Plans and views that need none of this are unchanged.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- No write tool of the 130 recorded captures goes from served to withheld, and no plan's rules, body or `insert`
|
||||
changes.
|
||||
- Rebuilt from the same recordings, the branch passes at least the write tasks #7260 passes.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Treat item reads of objects marked deleted as absent in checks, adoption and replay.
|
||||
- [x] Answer a read of a served-deleted entity of such a type marked deleted, until a reset or load.
|
||||
- [x] Learn `maxSize`, `max_results` and `maxResults` as page sizes.
|
||||
- [x] Add fields only later item reads show to item views, unrequired.
|
||||
- [x] Leave those fields out of write answers for entities without them, and stop them withholding updates.
|
||||
- [x] Add view, serving and unit tests.
|
||||
- [x] Document the rules and update the skill.
|
||||
- [x] Measure the recorded captures and served write tasks.
|
||||
- [x] Run static, formatting, documentation and test gates.
|
||||
@@ -0,0 +1,84 @@
|
||||
# Verification
|
||||
|
||||
Executed on macOS with Node v24.22.1 on this branch, built on #7260's head `053264bd` (main `662ec2e4`), and on
|
||||
Ubuntu 24.04 VMs for the task runs.
|
||||
|
||||
## Gates
|
||||
|
||||
- `npm run -s check:fast`, `scan:todos`, `docs:check`, `verify:test-discovery`, `mcp-catalog:check` and `jscpd`:
|
||||
passed.
|
||||
- `npx oxfmt --check .` reports `scripts/verify-apk-signature.mjs` only, which this branch does not touch and
|
||||
`053264bd` reports too. `npx knip` reports `isToolFamilyId` in `src/contracts/toolFamilies.ts` only, as main does.
|
||||
- `npx vitest run --project domain --project services --project adapters`: 18,420 passed, 25 skipped, 1 failed ("stops
|
||||
Inspector target authorization after the current stat settles"), which fails the same way on main in this
|
||||
environment.
|
||||
- `npm run -s test:focused --` the environment build, export and serve CLI boundaries, the analysis-view CLI and MCP
|
||||
boundaries and the environment serve MCP boundary: 7 files, 75 passed.
|
||||
|
||||
## Tests
|
||||
|
||||
- View: a contact delete whose item read answers the record with `deleted: true` is served, confirmed by that read and
|
||||
the list; only a `true` `deleted`, `isDeleted` or `is_deleted` marks an object deleted; a delete is confirmed by a
|
||||
list read paged with `maxSize`; a field only created tasks show joins the task item view without being required; a
|
||||
task update whose answers show it is served.
|
||||
- Serving: a deleted contact leaves the served list; an update of a seeded task, single or bulk, answers without the
|
||||
field only created tasks show (the bulk case fails on `4515a000`, before the review fix).
|
||||
- The six behaviour tests fail on `053264bd`.
|
||||
- The existing serving test that refuses to give chapter rows to a book the state holds without them still passes. A
|
||||
first version of the answer rule left out every field the item view does not require, which served that update; the
|
||||
rule now covers only fields no initial entity holds.
|
||||
|
||||
## Write plans and views over recorded captures
|
||||
|
||||
The 109 captures #7260 measured and #7260's 21 fresh recordings, built by `053264bd` and by this branch:
|
||||
|
||||
| Captures | Write plans | Served on #7260 | This branch |
|
||||
| ------------------------- | ----------- | --------------- | ----------- |
|
||||
| 50 published | 187 | 70 | 71 |
|
||||
| 80 recorded from a prompt | 428 | 258 | 268 |
|
||||
|
||||
- No write goes from served to withheld, and no plan's rules, body or `insert` changes. The 11 newly served are
|
||||
EspoCRM contact deletes in seven recordings, the published EspoCRM capture's task delete, and Vikunja task updates
|
||||
in three recordings.
|
||||
- With main `c6893d1a` merged, whose `unknown-clock` withholds clock writes without an anchor on both builds, #7260
|
||||
serves 322 and this branch 332. One of the Vikunja task updates is among the writes it withholds, so this branch
|
||||
gains 10, and none goes from served to withheld.
|
||||
- 73 list views learn a page size they held as `inert`, valid only for its recorded values, as `limit`: 72 EspoCRM
|
||||
lists (`maxSize`) and one Umami list (`maxResults`). One EspoCRM stream list now counts a line paged only by
|
||||
`maxSize` as listing the whole collection and explains its other line's query; no view explains fewer lines.
|
||||
- Six item views gain a field only later reads show, never required: Vikunja's tasks `subscription` in four recordings,
|
||||
a Homebox entity's `children` and Mattermost's posts `has_reactions`. Every other view is unchanged.
|
||||
|
||||
## The same recordings, built by #7260 and by this branch
|
||||
|
||||
Claude Code (`claude-sonnet-5-5`) recordings from earlier rounds, rebuilt by each version, their write tasks run with
|
||||
`fireworks_ai/gpt-oss-120b` then `fireworks_ai/glm-5p3-flash`, each checked from the environment's state:
|
||||
|
||||
| Recording | Write tasks | #7260 | This branch |
|
||||
| ---------------------------------------------- | ----------- | ----------- | ----------- |
|
||||
| EspoCRM: main, #7260 (three), saved-values | 5 × 3 | 5/15 5/15 | 15/15 10/15 |
|
||||
| EspoCRM: saved-values, leftover contact | 3 | 0/3 0/3 | 0/3 0/3 |
|
||||
| Vikunja: main, #7260 final, saved-values (two) | 4 × (3 + 2) | 8/20 8/20 | 8/20 8/20 |
|
||||
| Homebox: main | 2 | 2/2 2/2 | 2/2 2/2 |
|
||||
| Total | 40 | 15/40 15/40 | 25/40 20/40 |
|
||||
|
||||
No recording passes fewer tasks with this branch.
|
||||
|
||||
- **EspoCRM:** the contact delete passes with both models on all five recordings. The contact update passes with
|
||||
gpt-oss on all five only by replacing the contact: the served update refuses `emailAddress`, which no recorded update
|
||||
stored, so the agent created a contact with the new address and deleted the old one, which the task's check, by name
|
||||
and address, accepts. The update itself is refused in both builds, as is a read of a seeded contact by id, since the
|
||||
state knows seeded contacts only from list reads, which lack fields the item reads show. GLM's update fails in both
|
||||
builds the same way, and it often ends a turn at the eval agent's 1,024-token completion limit.
|
||||
- **EspoCRM, leftover contact:** the recording started with a contact an earlier attempt left, held as seeded data, so
|
||||
every "nothing else changed" check fails in both builds.
|
||||
- **Vikunja:** the newly served task update accepts the members the recorded update stored (`title`, `description`,
|
||||
`priority`), so the task asking to mark a task done is refused in both builds. The skill now asks for updates that
|
||||
change a status, an email address or a due date. Task creates are unchanged.
|
||||
- **Homebox:** the entity view's new `children` field changes no task.
|
||||
|
||||
## Not verified
|
||||
|
||||
- An application answering `deleted: true` for a record it still lists, as a trash view might: such a read counts as
|
||||
absent. No recorded capture does this.
|
||||
- The skill's update wording, which no fresh recording has used yet.
|
||||
+20
-5
@@ -5,6 +5,12 @@ lane. Start with the commands below; use [real-toolchain lanes](#real-toolchain-
|
||||
for engine prerequisites and [client verification](client-verification.md) for
|
||||
installed-client and agent runs.
|
||||
|
||||
Historical verification records may refer to `experiments/analysis-efficiency`.
|
||||
Those experiment scripts are available in the [archived source tree](https://github.com/morluto/rea/tree/a2e2c29b59e8775b0e6aedb09a9eb16adf32646b/experiments/analysis-efficiency);
|
||||
they are not included in current checkouts. The retained [test support](https://github.com/morluto/rea/blob/main/tests/support/analysis-efficiency/README.md)
|
||||
contains deterministic checkers and fixtures. The [allocation report](verification/analysis-efficiency/mcp-integer-allocation.md)
|
||||
and its original receipt JSON remain documentation, checked by the report producer.
|
||||
|
||||
## Developer commands
|
||||
|
||||
Use source feedback while editing, explicit boundary checks for the changed
|
||||
@@ -204,7 +210,11 @@ changing a callback solely to satisfy its declared `void` return type.
|
||||
Ordinary Knip remains. `check`, `check:pr`, and `check:ci:deep` run reachability
|
||||
then typed lint sequentially after cached work. Typed lint builds the project
|
||||
type graph and stays separate from fast feedback. Its default Go settings are
|
||||
`GOMAXPROCS=2` and `GOMEMLIMIT=1024MiB`; caller-selected settings take precedence.
|
||||
`GOMAXPROCS=1` and `GOMEMLIMIT=1024MiB`; caller-selected settings take precedence.
|
||||
One Go worker reuses checker caches across the file queue without changing the
|
||||
file inventory or TypeScript project scope. The Go memory target is soft and
|
||||
does not cap the complete process family's memory; measure the full invocation
|
||||
when enforcing a host budget.
|
||||
|
||||
Routine iterations and rebases need focused regressions and relevant checks.
|
||||
Before handing off a PR, run `npm run check` and generated-document checks when
|
||||
@@ -1164,8 +1174,8 @@ its metadata regressions against the same checksum-pinned engine and public APK.
|
||||
It runs on branch pushes affecting its bridge, fixture or engine inputs, and can
|
||||
also be dispatched manually or called by another workflow. It uses the runner's
|
||||
JDK with two active processors and a 512 MiB heap; it needs no npm dependency
|
||||
installation. This lane checks exact raw/display class selectors and the existing
|
||||
cold-metadata regressions. It does not establish CLI/MCP parity or application
|
||||
installation. This lane checks exact raw/display class selectors, raw member names and field
|
||||
DEX types used by mapping lookups, and the existing cold-metadata regressions. It does not establish CLI/MCP parity or application
|
||||
execution behavior. The broader `verify:android` lane checks CLI/MCP parity;
|
||||
neither lane runs the APK.
|
||||
|
||||
@@ -1211,7 +1221,7 @@ HarmonyOS `.har` libraries are deliberately not suffix-classified because
|
||||
Synthetic producer regressions run independently:
|
||||
|
||||
```sh
|
||||
npm run test:focused -- tests/boundary/process/jadxIntegration.test.ts tests/boundary/process/androidAnalysisMcp.test.ts
|
||||
npm run test:focused -- tests/boundary/process/jadxIntegration.test.ts tests/boundary/process/androidAnalysisMcp.test.ts tests/boundary/process/androidMappingMcp.test.ts
|
||||
```
|
||||
|
||||
## Apktool resource decoding
|
||||
@@ -1374,7 +1384,7 @@ other engine versions and architectures remain unverified; see the
|
||||
|
||||
Native IDA MCP verification uses `"protocol": "native"` with an already-running native plugin and requires `--second-procedure other_function --second-marker unique_second_body_text` to exercise GUI function switching and a return to the first function. These options remain optional for other profiles. The literal marker must appear in the second function's pseudocode and be absent from the first. Native cloud/widget failures are reported without hidden retries.
|
||||
|
||||
The initial Linux x64 IDA Free 9.4 run used native MCP 1.1.2 with a local navigation correction. Windows x64 verification uses **IDA Pro 9.3**, the two-function public fixture, and the shipped Windows `whoami.exe` application. The native plugin was built from upstream `c9d15d98e8a143fc74f6e14037c48f63889b6d6c`, including the merged navigation fix, with a local loopback-listener change. Production CLI/MCP parity, switching, identity and cleanup passed. Correctness and performance measurements are recorded in the [Windows native verification notes](https://github.com/morluto/rea/blob/main/experiments/analysis-efficiency/ida-native-windows.md). Stock 1.1.2 switching, native macOS, and Windows IDA Free remain unverified. See the [native bridge prerequisites](ida-provider.md#optional-native-ida-mcp-bridge).
|
||||
The initial Linux x64 IDA Free 9.4 run used native MCP 1.1.2 with a local navigation correction. Windows x64 verification uses **IDA Pro 9.3**, the two-function public fixture, and the shipped Windows `whoami.exe` application. The native plugin was built from upstream `c9d15d98e8a143fc74f6e14037c48f63889b6d6c`, including the merged navigation fix, with a local loopback-listener change. Production CLI/MCP parity, switching, identity and cleanup passed. Correctness and performance measurements are recorded in the [Windows native verification notes](https://github.com/morluto/rea/blob/a2e2c29b59e8775b0e6aedb09a9eb16adf32646b/experiments/analysis-efficiency/ida-native-windows.md). Stock 1.1.2 switching, native macOS, and Windows IDA Free remain unverified. See the [native bridge prerequisites](ida-provider.md#optional-native-ida-mcp-bridge).
|
||||
|
||||
## Kuna lane
|
||||
|
||||
@@ -1624,6 +1634,11 @@ results after a failure. Available failed-shard reports remain diagnostic only:
|
||||
failed, cancelled, skipped, or missing selected shards cannot pass the gate or
|
||||
publish successful timing history. This deliberately avoids relying on an
|
||||
import graph for generated files, filesystem inputs, subprocesses, or bridges.
|
||||
The portable report rejects an entirely skipped module inventory and lists
|
||||
fully skipped modules in its summary. A mixed passed/skipped inventory is
|
||||
allowed: Vitest's skip state does not establish whether a skipped module was
|
||||
required on that runner. Review the listed skips against platform and provider
|
||||
prerequisites; the inventory alone does not prove every required case ran.
|
||||
|
||||
Scheduled qualification is admitted hourly at minute 23. A forced full run at
|
||||
03:23 UTC refreshes runner and dependency drift every day. Other hourly runs
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# U-Boot legacy uImage containers
|
||||
|
||||
`inspect-artifact` and `extract-artifact` recognize the big-endian
|
||||
`0x27051956` legacy uImage signature regardless of filename. They read local
|
||||
stored bytes without booting, executing, decompressing or modifying the image.
|
||||
FIT is a different format; its analysis is outside this reader.
|
||||
|
||||
The same domain header/table facts and artifact reader serve CLI and MCP.
|
||||
The root is an archive with unknown executable architecture. The header's CPU,
|
||||
OS, type, compression, load address and entry address are declarations, not proof of
|
||||
compatible or executable payloads. Raw numeric identifiers remain available
|
||||
alongside names; unrecognized identifiers have the name `unknown`.
|
||||
|
||||
The header's CRC32 and the declared payload's CRC32 must verify before a
|
||||
successful inventory. `payload.bin` contains the complete stored payload.
|
||||
Multi-file images also expose `image-0.bin`, `image-1.bin`, and so on. These
|
||||
component names are generated from table order. Components follow the zero-terminated big-endian size table, with four-byte
|
||||
padding after every nonfinal component. Their physical source ranges and
|
||||
content hashes retain precise provenance. Extraction writes the complete
|
||||
payload and every component, so multi-file output can approach twice the input
|
||||
size. Compressed payloads remain compressed.
|
||||
|
||||
The fixed 32-byte name field is retained as `name_bytes_hex`. `name` contains
|
||||
the UTF-8 bytes before the first NUL, or null when those bytes cannot be decoded
|
||||
exactly. For example, a producer can truncate a multibyte character at the
|
||||
32-byte boundary; replacement characters do not establish a source name.
|
||||
|
||||
## Bounded work and retained facts
|
||||
|
||||
The reader admits at most 4,096 components, a resource policy rather than a
|
||||
format maximum. It reads at most 16,388 bytes for the size table and refuses an
|
||||
excess count as a capacity limit before its remaining payload CRC scan.
|
||||
Shared artifact identity hashing has separate cost. The
|
||||
same prefix participates in the native incremental CRC32 calculation; no
|
||||
custom bytewise CRC table or full-payload buffer is retained. Remaining CRC
|
||||
reads and member streams use 64 KiB chunks. Parsed facts are cached for one reader. Carrier state is checked during
|
||||
directory preparation, at member open and after stream completion; metadata
|
||||
getters return the retained facts. Close joins active member
|
||||
pipelines and final validation before releasing the descriptor; failed cleanup
|
||||
remains owned for retry.
|
||||
|
||||
Prefer a retained summary when only a few facts are needed:
|
||||
|
||||
```sh
|
||||
rea inspect-artifact firmware.bin --detail summary \
|
||||
--evidence_output firmware.evidence.json --json
|
||||
rea extract-artifact firmware.bin --json
|
||||
```
|
||||
|
||||
With MCP, `inspect_artifact` with `detail: "summary"` retains the complete
|
||||
Evidence. Use `inspect_analysis_view` and its `parent_evidence_id` for exact
|
||||
logical paths, batches of occurrence/content IDs, selected fields and pages.
|
||||
Coverage and limitations remain attached. Retained views are historical
|
||||
observations tied to the saved Evidence. Complete Evidence remains available;
|
||||
these views do not narrow the examined inventory.
|
||||
|
||||
## Verification scope
|
||||
|
||||
The public OpenWrt 24.10.0 GL-AR150 initramfs kernel is checked against its
|
||||
[published digest](https://downloads.openwrt.org/releases/24.10.0/targets/ath79/generic/sha256sums):
|
||||
`027c60a7061462d8145b11efa23ab02b334acb9a23a215f9095860b632ace4ff`.
|
||||
Independent `mkimage`/`dumpimage` 2023.01 provide producer and extraction
|
||||
oracles. Generated containers use real host ELF files, system metadata and
|
||||
stored gzip bytes; their declared ARM64, VxWorks or RISC-V labels do not prove
|
||||
boot/runtime compatibility. U-Boot's identifier and alignment definitions are
|
||||
pinned to commit `ece349ade2973e220f524ce59e59711cc919263f`.
|
||||
|
||||
Source and compiled CLI/full/compact MCP tests cover aligned component ranges,
|
||||
unknown identifiers/text, malformed/truncated inputs, CRC failures, capacity,
|
||||
source changes, cancellation, pending reads, final validation and cleanup
|
||||
retry. Real producer results, complete-task cost measurements and limitations
|
||||
are reported in the PR. No target runtime or decompressor behavior is verified.
|
||||
@@ -0,0 +1,86 @@
|
||||
# UnityFS AssetBundle archives
|
||||
|
||||
`inspect-artifact` and `extract-artifact` read standalone UnityFS AssetBundle
|
||||
containers without running Unity or the producer application. Header format
|
||||
versions 6 through 8 are supported. Version 9 adds a different block-table
|
||||
layout and is unsupported until independently verified.
|
||||
|
||||
Inspection retains the header facts: format version, player and engine version
|
||||
strings, declared size, dataflags, blocks-and-directory table bounds, the
|
||||
producer's 16-byte data hash as declared, and the resolved data-area offset.
|
||||
Members (`CAB-*` SerializedFiles, `.resS` resource streams, shared assets)
|
||||
retain declared source paths, virtual stream offsets, sizes and raw node flags.
|
||||
The directory flag identifies directories. Virtual offsets are not physical
|
||||
carrier locations: member `source_location` is null. Member reads only examine
|
||||
their covering blocks. Uncompressed ranges stream directly; compressed ranges
|
||||
reuse at most one completed decoded block. Independent 64 KiB output chunks
|
||||
preserve cache ownership. Carrier freshness is checked when a member is opened,
|
||||
including when a cached block suffices, and after its stream completes. Reader close cancels and
|
||||
joins outstanding streams before releasing its descriptor.
|
||||
|
||||
Data blocks compressed with none, LZ4 or LZ4HC are supported. LZMA-compressed
|
||||
blocks and blocks-info tables are reported as unsupported coverage or an
|
||||
`unavailable` member read; the directory and any readable members are still
|
||||
retained. Bundles declaring asset-bundle encryption keep their header facts
|
||||
but report unknown directory coverage; no decryption is attempted. The reused
|
||||
0x200 encryption/padding flag is interpreted by producer revision. Ambiguous
|
||||
revisions retain unknown layout coverage. Unread block counts and data offsets
|
||||
are null, never invented zeroes. A declared
|
||||
size that exceeds the input file, node paths outside the block stream, and
|
||||
counts that cannot fit their table are malformed-input errors.
|
||||
|
||||
## Resource bounds
|
||||
|
||||
These are resource policies, not format maxima. Encoded and decoded directory
|
||||
buffers are each limited to 16 MiB. Buffers, parsed rows, retained entries and
|
||||
path projections share a conservative 64 MiB admission budget, reserved before
|
||||
allocation. Each LZ4 decode allows at most 64 MiB of output and its bounded
|
||||
encoded representation; plain blocks stream without this allocation. A reader
|
||||
admits four active member streams. The shared archive plaintext-work ceiling
|
||||
is the larger of 256 MiB and 500 times carrier size: declared stream bytes,
|
||||
readable logical occurrences (including aliases), and cumulative block-decode
|
||||
attempts are each charged against that ceiling. Empty-output blocks retain
|
||||
their source count and offsets but are removed from member read plans. A separate
|
||||
member-I/O budget allows four times the larger of 1,024 and the sum of nonempty
|
||||
blocks, directory nodes, and readable 64 KiB plaintext chunks. It admits ordinary
|
||||
passes while bounding repeated tiny-block reads independently of output bytes. Unavailable content is retained
|
||||
as named occurrences with unknown coverage and no invented content hash.
|
||||
|
||||
Use existing summary delivery and retained inventory views for selected fields,
|
||||
filters and paging; full Evidence remains available without repeating the graph.
|
||||
|
||||
## CLI
|
||||
|
||||
```sh
|
||||
rea inspect-artifact assets/hotfix.bundle --detail summary \
|
||||
--evidence_output evidence/hotfix.json --json
|
||||
rea extract-artifact assets/hotfix.bundle --json
|
||||
```
|
||||
|
||||
Detection is byte-based on the `UnityFS\0` signature, so `.bundle`, `.ab`,
|
||||
`assets_*` YooAsset bundles and extensionless files all classify as `unityfs`
|
||||
containers. Compact delivery keeps complete Evidence in the requested bundle.
|
||||
|
||||
## Verification scope
|
||||
|
||||
Synthetic fixtures cover format 6–8 layouts, padding independent of header
|
||||
alignment, directories, malformed tables, allocation admission, overlapping
|
||||
members, unsupported LZMA, cancellation inside decoding, paused iteration,
|
||||
close during I/O, cleanup retry, empty blocks with unsupported codecs, cache
|
||||
freshness and independent output buffers.
|
||||
Compiled CLI and full/compact MCP tests cover inventory and extraction.
|
||||
|
||||
A public UnityPy `atlas_test` bundle (Unity 2018.4.11f1, format 6) is verified
|
||||
against independent UnityPy 1.24.2 raw member bytes. Source SHA-256:
|
||||
`61ee5afb5f5c64f0a4f65f039d09b2509198363e713423289c895067ac215177`.
|
||||
The source is pinned to UnityPy commit
|
||||
`417d59522a998fdee9a9c2b29fe35f3063222457`. The same public corpus supplies
|
||||
`banner_1` (2018.4.4f1) and `char_118_yuki.ab` (5.6.7f1), whose raw members
|
||||
also match the independent oracle. `xinzexi_2_n_tex` (2017.4.37f1) uses LZMA
|
||||
data: its member names and sizes are retained with unavailable hashes and
|
||||
unknown coverage. UnityPy-produced repacks additionally verify format 7/8,
|
||||
padded and unpadded front tables, end tables, and unsupported LZMA directories.
|
||||
These repacks are library-produced tests, not Unity engine executions. The PR
|
||||
records producer parameters, source digests and measured task costs; synthetic
|
||||
fixtures alone do not establish real Unity version coverage. SerializedFile objects, textures and runtime
|
||||
behavior are outside this container reader's verification scope.
|
||||
@@ -15,7 +15,7 @@ harm_rank,location,trigger,current_copy,user_risk,proposed_replacement,implement
|
||||
11,src/domain/errors.ts:ArtifactOperationError,Artifact inventory or extraction fails,"Artifact {operation} failed: {reason} at {logicalPath} (declared_sha256=...)",Exposes paths hashes and internal reason,"Reason-specific plain message with safe recovery step.",implemented,focused assertions passed; full `npm run check` passed
|
||||
12,src/domain/errors.ts:EvidenceFileError,Evidence file operation fails,"Evidence bundle {operation} failed: {reason}",Internal reason token gives weak recovery,"Reason-specific plain message with safe recovery step.",implemented,focused assertions passed; full `npm run check` passed
|
||||
13,src/domain/errors.ts:EvidenceIntegrityError,Evidence validation fails,Raw constructor message,May expose validation internals and lacks recovery,"Evidence is invalid or has changed. Recreate or re-import it, then try again.",implemented,focused assertions passed; full `npm run check` passed
|
||||
14,src/domain/errors.ts:UnknownRegistryError,Evidence-state mutation fails,"Residual unknown registry mutation failed: {reason}",Exposes internal subsystem and state token,"Missing IDs identify the session and retry; concurrent revision conflicts refresh current state.",implemented,focused assertions passed; full `npm run check` passed
|
||||
14,src/domain/analysisErrorPresentation.ts:UnknownRegistryError,Residual-unknown reference or graph constraint fails,Specific graph constraint and missing reference ID,Unchanged retries cannot repair missing references or insufficient proof,Correct the named reference or proof constraint; revision conflicts retain refresh recovery.,implemented,96 focused tests passed; real stdio correction and atomic-rejection controls passed
|
||||
15,src/domain/errors.ts:ProcessCaptureError,Process capture fails,Raw constructor message,May expose process and cleanup internals,"Process capture could not complete. Check command access and limits, then try again.",implemented,focused assertions passed; full `npm run check` passed
|
||||
16,src/domain/errors.ts:AnalysisTimeoutError,Analysis deadline expires,"REA's {operation} operation reached its {timeoutMs}ms server/provider deadline; extending only the client deadline does not change this budget",Returned server deadline is distinct from a host timeout that discards the response,"Inspect partial Evidence, provider diagnostics, and reported cleanup, then follow the returned remediation. Change a request field or REA_* setting only when the returned remediation explicitly recommends that change. Restart REA when that text says the value is read at startup. A mention that a control does not raise the deadline is not a recommendation to change it. When it names no setting, reduce supported work; do not invent one. JavaScript names analysis_timeout_ms and exact source_paths; omit an unneeded filter rather than passing an empty array.",implemented,generic projection does not invent a setting; producer remediation names analysis_timeout_ms or the applicable REA_* value; initialization and the shipped skill teach the same split
|
||||
17,src/domain/errors.ts:HopperTimeoutError,Provider deadline expires,"Hopper did not respond within {timeoutMs}ms",Exposes provider and internal deadline,"Analysis took too long. Try a smaller request, then run `rea doctor` if it continues.",implemented,focused assertions passed; full `npm run check` passed
|
||||
@@ -44,13 +44,15 @@ harm_rank,location,trigger,current_copy,user_risk,proposed_replacement,implement
|
||||
32,src/application/Setup.ts:configureDetectedClients(backup),Agent configuration backup fails,"{clientName} configuration backup verification failed; no successful configuration was reported.",Exposes machine client key and obscures no-write guarantee,"Agent configuration could not be backed up, so no change was made. Check file permissions, then rerun setup.",implemented,focused assertions passed
|
||||
33,src/application/Setup.ts:configureDetectedClients(write),Agent configuration write fails,"{clientName} configuration write verification failed; no successful configuration was reported.",Exposes machine client key and gives no recovery,"Agent configuration could not be updated. Check file permissions, then rerun setup.",implemented,focused assertions passed
|
||||
34,src/application/Setup.ts:configureDetectedClients(readback),Written agent configuration cannot be verified,"{clientName} configuration readback verification failed; no successful configuration was reported.",Exposes machine client key and omits backup recovery,"Agent configuration could not be verified after writing. The original was restored and its backup at {backupPath} was retained. Repair the configuration file or restore that backup, then rerun setup. Without a backup: Agent configuration could not be verified. Repair the configuration file, then rerun setup.",implemented,focused assertions passed
|
||||
35,src/application/Setup.ts:installSkill,Skill install or semantic readback fails,Agent skill installation or readback failed.,No useful recovery action,"REA analysis skill could not be installed or verified. Check permissions for `~/.agents/skills`, then rerun setup.",implemented,focused assertions passed
|
||||
36,src/main.ts:serveStdio.onerror,Established MCP client connection reports an error,MCP stdio transport error,Exposes transport implementation and gives no recovery,"Retry the tool call once only when it is safe to repeat or known not to have started. If it may already have changed the target, or it fails again, tell the user REA lost its MCP client connection and ask them to restart the MCP client.",implemented,verified by injected transport onerror runtime test
|
||||
35,src/application/SetupSkill.ts:SetupSkillInstallError,Skill install or semantic readback fails,Stage and selected path; separate failure reason and recovery action,A non-directory path is not a demonstrated permission failure,Correct the reported failure; directory blockers retain regular-directory and --skill=false guidance.,implemented,"Public CLI ancestor/root refusal, preserved caller file, complete install and idempotent rerun; focused recovery tests"
|
||||
36,src/main/reportMcpTransportError.ts:reportMcpTransportError,MCP pipe breaks or connection resets,"Retry the tool call once only when it is safe to repeat or known not to have started. If it may already have changed the target, or it fails again, tell the user REA lost its MCP client connection and ask them to restart the MCP client.",Retry safety and restart guidance for known disconnection,Keep current copy,implemented,injected EPIPE recovery regression
|
||||
36,src/main/reportMcpTransportError.ts:reportMcpTransportError,MCP message fails schema validation,MCP message validation failed. Check the protocol fields before retrying a message that is safe to repeat. Continue using the connection while it remains responsive.,Validation failure does not establish connection loss,Keep current copy,implemented,public stdio invalid-ID controls followed by successful ping and file analysis
|
||||
36,src/main/reportMcpTransportError.ts:reportMcpTransportError,MCP error has no known validation or disconnection identity,MCP reported an error with unknown connection state. Check whether the client is still connected before following connection-loss recovery.,Connection state remains unknown,Keep current copy,implemented,injected unknown-error recovery regression
|
||||
37,src/main.ts:serveStdio throw,MCP connection cannot be created,Failed to start MCP stdio transport,Exposes transport implementation and gives no recovery,"Retry once. If it fails again, tell the user REA could not start its MCP connection and ask them to restart the MCP client, then run `rea doctor`.",implemented,verified by injected transport startup-throw runtime test
|
||||
38,src/main.ts:requestShutdown catch,Connection or analysis session close rejects,Failed to shut down cleanly,Does not explain duplicate-process risk or recovery,REA could not close cleanly. End the REA process before starting it again.,implemented,verified by injected handle-close rejection runtime test
|
||||
39,src/main.ts:entrypoint catch,Unhandled rejection escapes run(),Unexpected server startup failure,Vague and lacks diagnostic recovery,"Do not repeat this startup. Tell the user REA could not start and ask them to restart the MCP client, then run `rea doctor`.",implemented,verified by injected entrypoint rejection test
|
||||
40,src/application/Upgrade.ts:unknown-install-method,Running package is not owned by detectable global npm installation,Update manually with: npm install --global rea-agents@latest,Already gives exact safe recovery,Keep current copy,unchanged,existing focused assertion passed
|
||||
41,src/application/Upgrade.ts:install,npm global install subprocess exits unsuccessfully,npm install --global rea-agents@latest failed.,Does not identify bounded likely checks before retry,"REA could not update through npm. Check npm registry access and global install permissions, then run: npm install --global rea-agents@latest",implemented,focused assertion passed
|
||||
40,src/application/Update.ts:unknown-install-method,Running package is not owned by detectable global npm installation,Update manually with: npm install --global rea-agents@latest,Old global-npm advice does not identify the owning installation,"Update this installation with the package manager or source checkout that owns it. For a one-off latest invocation, use npx rea-agents@latest.",implemented,36 Update tests passed; public CLI unowned-installation refusal verified with isolated package-manager fixtures
|
||||
41,src/application/Update.ts:install,npm global install subprocess exits unsuccessfully,npm install --global rea-agents@latest failed.,Old registry/global-install advice omits the actual version prefix and installer failure,"REA could not install {version} in {prefix}: {failure}. Repair this npm installation, then rerun rea update.",implemented,36 Update tests passed; public CLI owned npm fixture failure preserved version prefix and installer reason
|
||||
42,src/application/Uninstall.ts:removeClient read,Existing agent configuration cannot be read,Configuration could not be read.,No recovery step,"Configuration could not be read. Check file permissions, then rerun uninstall.",implemented,verified by injected filesystem read failure test
|
||||
43,src/application/Uninstall.ts:removeClient parse,Agent configuration is malformed,Malformed configuration was preserved without mutation.,Does not name required repair format or retry,"Configuration is not valid JSON/TOML and was not changed. Repair it, then rerun uninstall.",implemented,focused JSON assertion passed; TOML path uses same branch
|
||||
44,src/application/Uninstall.ts:removeClient backup,Configuration backup copy fails,Configuration backup failed; no mutation was attempted.,No recovery step,"Configuration could not be backed up, so no change was made. Check file permissions, then rerun uninstall.",implemented,verified by injected filesystem backup failure test
|
||||
@@ -114,7 +116,7 @@ Then rerun this installer.",implemented,verified by shell branch inspection
|
||||
88,install.sh:binary absent,npm exits successfully without executable,the rea command was not installed at local path,Leaks local path and no recovery,"npm completed without installing the rea command. Check the npm global bin directory and PATH, then retry.",implemented,verified by exact absent-installed-command test
|
||||
89,install.sh:version read,Installed rea executable cannot report its version,could not read the installed REA version.,No recovery instruction,"The installed REA version could not be read. Reinstall the requested version, then retry.",implemented,verified by exact unreadable-installed-version test
|
||||
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.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,implemented,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
|
||||
90.7,src/ghidra/GhidraProviderClient.ts:projectPrimarySessionError,One procedure's decompile reaches REA_GHIDRA_DECOMPILE_TIMEOUT_SECONDS,"Ghidra decompilation of {entry} exceeded the {N}-second limit set by REA_GHIDRA_DECOMPILE_TIMEOUT_SECONDS. Only this procedure's decompilation was stopped; the Ghidra session remains usable.",Low risk; names the setting and keeps the session,Keep current copy,implemented,provider projection test and real-provider lane
|
||||
91,src/application/binaryDiagnostics/ByteEntropyService.ts,Invalid file or window,"Expected a regular file.; Selected file could not be found.; Selected byte window starts beyond the end of the file.; 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
|
||||
|
||||
|
File renamed without changes.
+11
-4
@@ -22,7 +22,7 @@ Seven dependency-boundary variants match parsed values and complete error issues
|
||||
|
||||
## Tasks, artifacts and bounds
|
||||
|
||||
Reuse the shared SDK task driver and independent ELF/section/zlib/JSON oracles from [the catalog study](mcp-input-catalog.md): official Alpine v3.21 x86_64 ripgrep 14.1.1-r0 and Zellij 0.40.0-r0. All 42/422 packages and 88/1,063 edges match the independent oracles. Select serde name/version/kind, repeat exact retained-parent reads twice, verify a canonical negative-offset refusal, export/check complete Evidence and confirm the unchanged directory. `kind: null` stays unknown. Targets are not executed; dependency presence does not establish runtime use. Acquisition URLs, archive/executable/oracle hashes and complete answers are in [the receipts](mcp-integer-allocation.json). Previously acquired public bytes are rehashed, not redownloaded.
|
||||
Reuse the shared SDK task driver and independent ELF/section/zlib/JSON oracles from [the archived catalog study](https://github.com/morluto/rea/blob/a2e2c29b59e8775b0e6aedb09a9eb16adf32646b/experiments/analysis-efficiency/mcp-input-catalog.md): official Alpine v3.21 x86_64 ripgrep 14.1.1-r0 and Zellij 0.40.0-r0. All 42/422 packages and 88/1,063 edges match the independent oracles. Select serde name/version/kind, repeat exact retained-parent reads twice, verify a canonical negative-offset refusal, export/check complete Evidence and confirm the unchanged directory. `kind: null` stays unknown. Targets are not executed; dependency presence does not establish runtime use. Acquisition URLs, archive/executable/oracle hashes and complete answers are in [the receipts](https://github.com/morluto/rea/blob/main/docs/verification/analysis-efficiency/mcp-integer-allocation.json). Previously acquired public bytes are rehashed, not redownloaded.
|
||||
|
||||
Normal cohort: three alternating baseline/candidate pairs for each task × cold/warm server compile cache × default compact/full inputs: 72 trials, plus four excluded full-task warm priming runs. Separate diagnostic cohort: three alternating pairs per profile, cold Zellij tasks, 12 trials. All pass, with identical complete parent IDs/hashes and answers.
|
||||
|
||||
@@ -115,6 +115,12 @@ Question, explicit recipe, server instructions, one complete name/description/in
|
||||
- Both runtime builds and all six static checks plus architecture guards pass. Before the final main synchronization, 5,972 source/contract/public CLI/MCP tests pass across 323 files; four skip for unavailable/guarded coverage. After synchronization, both builds/static checks repeat successfully, 77 affected producer and CLI/MCP tests pass, and all 974 registered numeric-parameter parser cases match again. Includes real SQLite CLI/MCP record/column selection and JavaScript heap/deadline preservation. A first direct schema-validity invocation lacked generated catalog metadata; the supported focused entry generates it and all 15 cases pass. A later affected-test invocation selected two nonexistent paths; the corrected three-file producer/consumer run is the 77-case result above. Neither setup failure was counted as a passing test, and no production or timeout change was needed.
|
||||
- All 84 measured tasks and four warm priming tasks pass independent oracles, canonical refusal, parent/directory identity and owned cleanup checks. This does not verify external Hopper/Ghidra/IDA, Android devices, all providers or foreign OS behavior. The earlier macOS numbers in #4360 describe a different revision/platform and are not combined with these results.
|
||||
|
||||
The historical cohort commands below use the retired experiment layout. Run them
|
||||
from the matching recorded producer checkout; the [archived source tree](https://github.com/morluto/rea/tree/a2e2c29b59e8775b0e6aedb09a9eb16adf32646b/experiments/analysis-efficiency)
|
||||
provides the former files for reference. Current checkouts retain the report and
|
||||
its conformance producer, rather than the full measurement suite. Moving these
|
||||
files does not requalify the historical measurements against current REA.
|
||||
|
||||
Build the pinned baseline/candidate in separate clean worktrees with the locked toolchain. Use the candidate’s producer scripts for both roles. `measurement_inputs` in the JSON records the complete matrix, questions/recipes, runtime bindings and producer hashes; extract it unchanged as the bindings file. Historical receipts require their matching producer revision. One normal task:
|
||||
|
||||
```bash
|
||||
@@ -133,11 +139,12 @@ python experiments/analysis-efficiency/mcp-startup-costs.py "$RECEIPT_ROOT" \
|
||||
|
||||
The aggregator requires the recorded tiktoken version, exact catalog/parent/runtime/producer/guard identities, clean source, successful payload cleanup and matching matrix coverage. Default driver behavior continues without an inspector; the heap flag is confined to the experiment.
|
||||
|
||||
Regenerate or verify every numerical section directly from the committed JSON:
|
||||
In a current checkout, regenerate or verify every numerical section directly
|
||||
from the committed JSON:
|
||||
|
||||
```bash
|
||||
node experiments/analysis-efficiency/mcp-integer-report.mjs
|
||||
node experiments/analysis-efficiency/mcp-integer-report.mjs --check
|
||||
node tests/support/analysis-efficiency/mcp-integer-report.mjs
|
||||
node tests/support/analysis-efficiency/mcp-integer-report.mjs --check
|
||||
```
|
||||
|
||||
The documentation conformance gate checks current receipts, rejects stale normal/heap tables, and refuses missing producer markers without writing.
|
||||
@@ -0,0 +1,320 @@
|
||||
# Static Android JNI verification, 2026-10-27
|
||||
|
||||
Issue #6403 asks which bundled native functions could implement original DEX
|
||||
native declarations. The implementation reads immutable APK bytes, preserving
|
||||
declarations, library occurrences, exported/table candidates and selected
|
||||
per-ABI bindings as independently queryable facts. No target, library,
|
||||
`JNI_OnLoad` or `RegisterNatives` code was executed.
|
||||
|
||||
## Revisions and independent oracles
|
||||
|
||||
The full qualification and alternating delivery measurements below use
|
||||
implementation `4a1839de6f091ade19e82557874c358ed34b8e36`, based on main
|
||||
`03f17cf41d3c844f9383d7792d9b1a14330d0bb2`. Subsequent merge
|
||||
`e8a8a50725cd384ae38ce66a94bafdaba1138108` incorporates main
|
||||
`d6f88becd531cabafca1d968b89cf7fc77a80041`; its browser input-presentation and
|
||||
SQLite test changes are separate from JNI analysis. Post-merge confirmation is
|
||||
recorded below. The native parser's built SHA-256 is
|
||||
`3bf0a2c342f1c404f5861b7c913f7f1b931f740a8c808b518474fc8de20821d5`.
|
||||
|
||||
Linux x86-64, Node 24.22.1/npm 11.16.0 and JDK 21.0.12.1 qualified the workflows.
|
||||
JADX MCP 0.7.1 remains the supplied unmodified JAR, SHA-256
|
||||
`6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75`.
|
||||
The REA metadata bridge is version 9. JNI declarations use the JAR's existing
|
||||
dexlib2 reader before decompiler deduplication, with no `load_apk` call.
|
||||
|
||||
The genuine Android NDK r27d package is revision 27.3.13750724, clang/LLD 18.0.4.
|
||||
Its official Linux ZIP is 663,956,036 bytes, publisher SHA-1
|
||||
`22105e410cf29afcf163760cc95522b9fb981121`; observed SHA-256 is
|
||||
`601246087a682d1944e1e16dd85bc6e49560fe8b6d61255be2829178c8ed15d9`.
|
||||
Pins come from the [official repository manifest](https://dl.google.com/android/repository/repository2-3.xml).
|
||||
The package was streamed, hashed and selectively extracted into a private task
|
||||
cache, without installing or changing global tools. The selected compiler,
|
||||
sysroot and four additional official libunwind archives total 319,933,537 bytes.
|
||||
An initial link failure exposed those omitted archives; the corrected fixture
|
||||
build passed in 4.606 seconds, CPU 6.026 seconds, peak family RSS 110.4 MiB.
|
||||
|
||||
[Committed source fixtures and reproduction](https://github.com/morluto/rea/blob/main/tests/fixtures/android/jni-bindings/README.md)
|
||||
build native declarations, javac headers and two libraries for arm64-v8a,
|
||||
armeabi-v7a, x86 and x86_64. Ordinary REL/RELA, RELR and Android packed APS2
|
||||
variants include overloads, BMP/supplementary names, explicit Modified UTF-8,
|
||||
`.data` and `.data.rel.ro` tables, repeated exports in two libraries, an
|
||||
unmatched declaration and two classes sharing one registered pair. Source,
|
||||
`javac -h`, independent DEX flag/index reads, readelf and a separate byte/relocation
|
||||
oracle establish expected facts. Oracle SHA-256 is
|
||||
`fa634493bc8559a80eda3b70f01d44550c2f06e176cfc2a7cc7e10794b1eb793`.
|
||||
|
||||
| Static APK | SHA-256 |
|
||||
| -------------------- | ------------------------------------------------------------------ |
|
||||
| Ordinary | `c4eb50ef8bdecc6f56c454294c0c8f198fa51a4174d101dc720a849976546649` |
|
||||
| RELR | `5a2ce56191f633575e87bd239702f988d0d1ad82795a203e13a4f907f8624658` |
|
||||
| APS2 | `d2f0d613bc8f22ed1a6435f13b5ae1f088e904216aa8a04dd70c27c5cb606778` |
|
||||
| Conscrypt derivative | `5985c40d5a6b14b64c202c80335d851adb7e8a987e6154a1488a194253856385` |
|
||||
|
||||
The Conscrypt derivative packages the public Android 2.8.0 AAR's original
|
||||
library bytes with its class files transformed by D8 8.0.40. It is a static
|
||||
test container, not a vendor APK or a claimed launchable application. The AAR
|
||||
SHA-256 is `752044c289bc98e2dcabc00a1f88ca158b3aa3f505b38f124552bf4b2a0902b1`.
|
||||
The original-name DEX is used, not an R8-renamed DEX paired with unchanged JNI
|
||||
strings. D8's missing platform-adapter dependency warning remains a qualification
|
||||
limit; no full application linkage or signature verification is claimed.
|
||||
|
||||
## Executed correctness and Evidence checks
|
||||
|
||||
The built pure parser passed independent checks over 25 real libraries:
|
||||
24 genuine NDK outputs plus Conscrypt arm64. All 33 golden table entries match
|
||||
their strings, slot addresses/file offsets, relocated values, encodings,
|
||||
function addresses and code offsets. Conscrypt yields 367 structural entries;
|
||||
the requested `EVP_PKEY_new_RSA ([B[B[B[B[B[B[B[B)J` candidate is `0xfa11c`.
|
||||
Its name/signature/function slots are `0x2ada68`, `0x2ada70`, `0x2ada78`,
|
||||
with relocated values `0x749a8`, `0x7affa`, `0xfa11c`. This built-artifact
|
||||
qualification took 0.684 seconds, CPU 0.736 seconds, peak family RSS 99.5 MiB.
|
||||
|
||||
Real SDK/stdio MCP and CLI checks independently validate:
|
||||
|
||||
- All 12 source native declarations across four ABIs, exact library digests,
|
||||
overloads, UTF-16 names and per-library alternatives. Ordinary/RELR return
|
||||
32 matched, 12 ambiguous and four unknown rows. The source-known unmatched
|
||||
method remains unknown because symbolic writes/NOBITS leave scanning partial.
|
||||
- APS2 preserves 20 observed export matches, four ambiguous export rows and
|
||||
24 unknown rows. It explicitly reports unsupported table relocation encoding,
|
||||
retaining each selected library's reason even without a positive candidate.
|
||||
- Class selection never hides the other class sharing a registered pair.
|
||||
All selected native declarations survive independently of available ABI rows;
|
||||
the no-library selection case is covered by a domain regression, not claimed
|
||||
as a separate real SDK artifact qualification.
|
||||
- All four retained collections support exact fields, empty filters and batch
|
||||
ID retrieval. Parent-array `row_index` remains separate from raw DEX/ZIP
|
||||
source ordinals. Advertised converted schemas validate with the real SDK/Ajv.
|
||||
- Complete portable parents preserve the same normalized facts through summary
|
||||
and CLI delivery. Ordinary and each Conscrypt cohort copy the source to an
|
||||
exclusively created owned file, inspect it, remove only that copy, then read
|
||||
retained summary, exact table slots, binding fields and a full export.
|
||||
Original fixture bytes remain unchanged. Post-removal success is observed;
|
||||
hidden internal engine activity is not directly instrumented by this harness.
|
||||
|
||||
The first three four-ABI cohorts execute 107 SDK calls and three cold CLI parity
|
||||
checks. Each Conscrypt cohort adds 28 investigation calls, five separately
|
||||
accounted retained-removal calls and one CLI parity check. Four alternating
|
||||
Conscrypt cohorts preserve the same normalized fact digest:
|
||||
`7e4738d2dd9e518277d5268ce5c334d9d25728198f66b2102cdc3411865f2d46`.
|
||||
|
||||
Raw parent transcripts show one native inventory RPC on the first investigation,
|
||||
then only JVM-status RPCs on later main queries; normalized native facts remain
|
||||
present. No JNI parent contains `load_apk`. Library reuse is owned by the same
|
||||
immutable APK session; ABI/library selection replaces one scan, while class
|
||||
and method selection reuses it. Fresh analysis admission still hashes current
|
||||
caller APK bytes. Historical views never reopen them.
|
||||
|
||||
Type/lint/build and 396 tests across ten exact files pass together: native/domain
|
||||
projection, producer parsing, real ZIP occurrence/cleanup boundaries, unchanged
|
||||
JADX session/idle/cancellation behavior, public contracts and existing IL2CPP
|
||||
decoding/ownership. The gate took 215.198 seconds, CPU 257.470 seconds, peak
|
||||
family RSS 4396.1 MiB. A full real JDK/JADX metadata run additionally passed
|
||||
native reads before any APK load, malformed/duplicate DEX and CRC negatives,
|
||||
raw aliases, constants, absence facts, manifest identity and downstream CLI/MCP
|
||||
bodies/direct-invoke parity from both DEX entries: 154.890 seconds, CPU 233.275
|
||||
seconds, peak family RSS 984.8 MiB.
|
||||
|
||||
Finalization regressions retain already parsed library facts/digests in typed
|
||||
partial observations before ZIP close. Caller/deadline-first cancellation,
|
||||
failed close, blocked admission and retry preserve their first cause and exact
|
||||
resource lease. Interrupted later libraries preserve earlier completed facts.
|
||||
Stable table candidate identity uses physical pointer-slot address/file offset,
|
||||
not inferred run grouping. Known ZIP size claims stay separate from verified
|
||||
read size/hash.
|
||||
|
||||
## Completed-task costs
|
||||
|
||||
Earlier main cannot decode/register JNI tables with equivalent coverage, so
|
||||
manual export lookup is not an equivalent before workflow. The controlled
|
||||
comparison is complete versus summary delivery of the same new investigation,
|
||||
same bytes, query, selected pages and proof export. Conscrypt trials alternate
|
||||
summary/complete/summary/complete, each with one cold and one warm task.
|
||||
|
||||
Each fixture task has four investigations, 12 selected collection pages and a
|
||||
proof export (17 calls). Each Conscrypt task has one investigation, the same
|
||||
12 page checks and proof export (14 calls). Task time includes public calls and
|
||||
local oracle checks; one-time startup/catalog, separate retained-removal
|
||||
qualification, final cleanup and a cold CLI parity run are included in the
|
||||
whole-process columns, not hidden in task timings. Ordinary includes removal
|
||||
qualification; RELR/APS2 do not, so their whole-process costs are not a paired
|
||||
performance comparison. All four Conscrypt cohorts use the same phase flags.
|
||||
|
||||
| Cohort | Cold task s | Warm task s | Whole s | CPU s | Peak family MiB | Warm text tokens | Warm SDK tokens |
|
||||
| -------------------- | ----------: | ----------: | ------: | -----: | --------------: | ---------------: | --------------: |
|
||||
| Ordinary | 11.058 | 0.606 | 32.658 | 45.124 | 1215.7 | 58,319 | 401,681 |
|
||||
| RELR | 12.140 | 0.797 | 29.122 | 38.375 | 1266.2 | 58,231 | 401,502 |
|
||||
| APS2 | 12.578 | 0.917 | 30.892 | 41.071 | 1268.0 | 50,900 | 386,634 |
|
||||
| Conscrypt summary | 11.237 | 0.444 | 33.999 | 46.953 | 1282.0 | 32,265 | 349,128 |
|
||||
| Conscrypt complete | 10.846 | 0.456 | 32.907 | 45.948 | 1398.3 | 224,954 | 737,723 |
|
||||
| Conscrypt summary 2 | 19.205 | 1.200 | 57.545 | 77.644 | 1456.2 | 32,223 | 349,055 |
|
||||
| Conscrypt complete 2 | 20.978 | 0.925 | 64.513 | 81.218 | 1502.0 | 224,526 | 736,950 |
|
||||
|
||||
Warm text estimates are about 85.7% lower for summary delivery. Cold text
|
||||
estimates are 32,087/32,202 versus 247,593/247,912. SDK-inclusive warm estimates
|
||||
are about 52.6% lower. Latency/CPU/peak-memory samples vary substantially and do
|
||||
not establish a general improvement. Cold costs include the first generic
|
||||
view-schema compilation in the client; subsequent tasks reuse it. Startup/
|
||||
catalog alone ranges 2.692–4.955 seconds across these Conscrypt cohorts.
|
||||
|
||||
Token estimates use tiktoken 0.14.0/o200k_base. Every task counts its analyst
|
||||
question, discovered input catalog once, arguments and all text replies,
|
||||
including pages and export receipts. SDK totals additionally count output
|
||||
schemas and structured-content duplication. Qualifications and CLI response
|
||||
costs are reported separately by the cost script. Exported file contents are
|
||||
verified locally and are not counted as model context unless actually returned
|
||||
inline. Actual billing, hidden prompts, client rendering/pruning and OS cache
|
||||
state are unmeasured.
|
||||
|
||||
### Latest-main confirmation
|
||||
|
||||
After merging main `d6f88becd` into `e8a8a5072`, type/lint/build and the eight
|
||||
input-presentation/public-contract cases pass. The first direct schema-suite
|
||||
invocation could not load its generated test catalog; `test:focused` supplied
|
||||
the required artifacts and all 16 schema tests then passed (63.310 seconds,
|
||||
CPU 72.830 seconds, peak family RSS 1943.5 MiB). No schema assertion was relaxed.
|
||||
|
||||
Fresh full Conscrypt SDK/CLI cohorts use the same proof, 12 pages and owned-copy
|
||||
removal flags. Both retain the identical fact digest above:
|
||||
|
||||
| Delivery | Cold task s | Warm task s | Whole s | CPU s | Peak family MiB | Warm text tokens | Warm SDK tokens |
|
||||
| -------- | ----------: | ----------: | ------: | -----: | --------------: | ---------------: | --------------: |
|
||||
| Summary | 11.739 | 0.680 | 36.712 | 51.209 | 1395.1 | 31,932 | 348,522 |
|
||||
| Complete | 11.161 | 0.459 | 34.692 | 48.319 | 1385.2 | 224,954 | 737,723 |
|
||||
|
||||
Summary text estimates remain about 85.8% lower. This pair does not show a
|
||||
latency or peak-memory improvement. Each adds 33 SDK calls and one cold CLI
|
||||
parity check, bringing the executed public qualification to 305 SDK calls and
|
||||
nine CLI checks across the pinned cohorts.
|
||||
|
||||
`docs:check`, `format:check` and `docs:build` pass together: 44.365 seconds,
|
||||
CPU 56.935 seconds, peak sampled family RSS 1300.6 MiB. Generated catalogs,
|
||||
schemas, packaged skills and provider binaries remain uncommitted outputs.
|
||||
|
||||
All expensive checks use CPU affinity 0,1, bounded heaps and one active process
|
||||
family, with an 8 GiB RSS guard and 4 GiB host-availability guard. Peak memory is
|
||||
the sum of family RSS sampled every 100 ms: shared pages can be double-counted
|
||||
and short peaks can be missed. No guard stop or OOM occurred.
|
||||
|
||||
### Default-summary delivery confirmation
|
||||
|
||||
The new MCP operation now defaults to retained `summary` when `detail` is omitted.
|
||||
Explicit `complete` remains supported; the CLI retains its common explicit-detail
|
||||
policy. The actual SDK regression verifies both modes, caller selectors and
|
||||
reading an unselected declaration from the complete parent after source removal.
|
||||
Type/lint/build and all five cases in that MCP boundary file pass: 80.012 seconds,
|
||||
CPU 110.240 seconds, peak sampled family RSS 4747.6 MiB. An earlier attempt stopped
|
||||
at the test-function length lint rule; the fixture helper was extracted before
|
||||
this successful gate.
|
||||
|
||||
A fresh genuine Conscrypt workflow omits `detail` on JNI investigation calls and
|
||||
passes 33 SDK calls, all 12 retained pages, proof export, one cold CLI parity
|
||||
check and the separate owned-copy removal qualification. The same investigation
|
||||
fact digest above is retained. Cold/warm task times are 15.608/0.481 seconds;
|
||||
whole process-family time is 45.239 seconds, CPU 61.038 seconds, peak sampled RSS
|
||||
1431.2 MiB. Warm text/SDK token estimates are 31,928/348,516 using the same cost
|
||||
method. This adds a tenth CLI check and brings the successful public qualification
|
||||
total to 338 SDK calls. Explicit-complete removal qualification remains separate
|
||||
from the investigation task; default summaries do not discard the full parent.
|
||||
|
||||
Final `docs:check`, `format:check` and `docs:build` also pass: 77.269 seconds,
|
||||
CPU 70.506 seconds, peak sampled family RSS 1191.1 MiB.
|
||||
|
||||
The updated harness adds `--omit-detail` (with `--detail summary`), SHA-256
|
||||
`c2a5d090f32429c852e3c974083bb9c21a0dc6a608407687031f155a722b53d7`.
|
||||
The earlier cohort tables use the original frozen harness below. Default-run
|
||||
summary/catalog/call receipt SHA-256 values are respectively
|
||||
`c10e4d702b9694b0ccc69926a4e1f688fa8dea33a3de2e2837ea15190a706b37`,
|
||||
`0c36244f5ff788fabd5491144b0711e99ad211ce3c09e1812d1d4da5753624ac`, and
|
||||
`e1f021f0a7a92f101a037a1467a3428b4c620482eb556d81501a5ea64226ab82`.
|
||||
|
||||
### Review corrections and final qualification
|
||||
|
||||
Four review findings were reproduced or confirmed at their producing boundaries:
|
||||
|
||||
- The shared relocation reader had charged every file-backed write against a
|
||||
sparse retention limit. Its single immutable decoder now streams writes;
|
||||
IL2CPP applies them to its existing private copy and retains only bounded
|
||||
unresolved/zero-fill state and a file-offset bitmap. JNI keeps its bounded
|
||||
sparse provenance index. The two actual IL2CPP registration-read regressions
|
||||
each include 65,537 extra file-backed relative writes (AArch64 and x86-64)
|
||||
and verify the original bytes remain unchanged.
|
||||
- GNU version headers could replay shared auxiliary chains and names. The shared
|
||||
export owner now bounds total record visits from section bytes and the existing
|
||||
export-row allowance, caches decoded/failed string offsets within 16 MiB, and
|
||||
yields checkpoints through the same generator used by synchronous callers.
|
||||
Refusal retains exports with partial coverage and unknown version names.
|
||||
Both GNU table variants exercise 10,000 headers replaying 65,535 auxiliary
|
||||
records and a 65,535-byte name, verifying one decode and cooperative yields.
|
||||
- A named mapped-string read-limit failure now distinguishes budget exhaustion
|
||||
from invalid text. JNI preserves later candidates, marks tables partial and
|
||||
projects absent candidates as unknown. Both long names and descriptors are
|
||||
covered. An additional actual JNI-consumer regression queues cancellation
|
||||
after GNU name decoding begins and stops before export-symbol decoding.
|
||||
- The static verifier now requires the Conscrypt oracle only when expectations
|
||||
advertise it. Executed controls pass with 25 libraries/33 entries when present,
|
||||
and 24 libraries/32 entries for NDK-only expectations; an advertised missing
|
||||
oracle rejects with ENOENT and writes no success receipt.
|
||||
|
||||
Type/lint/build and 330 cases in 13 related domain, parser, archive, IL2CPP and
|
||||
actual CLI/stdio MCP files pass together: 192.437 seconds, CPU 224.376 seconds,
|
||||
peak sampled family RSS 4190.2 MiB. After adding the during-version cancellation
|
||||
case, type/lint and all 38 JNI parser cases pass: 39.842 seconds, CPU 67.581
|
||||
seconds, peak RSS 3928.0 MiB. These overlap earlier gates; counts are not summed
|
||||
as unique tests.
|
||||
|
||||
The final built parser again passes the independent 25-library/33-entry oracle:
|
||||
0.975 seconds, CPU 1.009 seconds, peak RSS 103.9 MiB. Built parser SHA-256 is
|
||||
`7c0638751427b2b282b8e55bb21c95f6c3f05c246b0ea66a31d0280694f9ffeb`;
|
||||
its receipt also fingerprints every shared parsing dependency. The fixed oracle
|
||||
SHA-256 above is unchanged. Large-capacity IL2CPP verification uses valid producer
|
||||
fixtures, not a newly qualified real IL2CPP application.
|
||||
|
||||
A fresh Conscrypt investigation qualification again passes 33 SDK calls,
|
||||
12 pages, proof, a cold CLI check and owned-copy removal. Investigation facts
|
||||
retain the same digest above. Cold/warm task times are 23.529/1.015 seconds;
|
||||
whole time 66.284 seconds, CPU 77.940 seconds, peak RSS 1402.6 MiB. Warm text/SDK
|
||||
estimates are 31,955/348,569. Host/time variation does not establish a general
|
||||
latency improvement. Cumulative successful public qualification is now 371 SDK
|
||||
calls and eleven CLI parity checks, across the explicitly separated revisions.
|
||||
The final cohort summary/calls SHA-256 values are
|
||||
`84df4f4ed97f6d1a931010db8e16420e5f06df371940ed9225eb99a7a7c01094` and
|
||||
`2c22b89e5ec4b26f15f0e9c5f8fdfd4af8583ad0926ad32edb359ecd991cd7fd`;
|
||||
its catalog hash matches the default-summary cohort. No resource guard or OOM
|
||||
occurred. Final `docs:check`, `format:check` and `docs:build` pass in
|
||||
38.602 seconds, CPU 49.448 seconds, peak sampled family RSS 1286.2 MiB.
|
||||
|
||||
## Reproduction and limitations
|
||||
|
||||
Build the runtime, generate the source fixtures using selected existing JDK,
|
||||
NDK and D8 paths, then run the maintained
|
||||
[pure parser verifier](https://github.com/morluto/rea/blob/main/tests/support/analysis-efficiency/android-jni-library.mjs)
|
||||
against the built parser. The
|
||||
[public workflow harness](https://github.com/morluto/rea/blob/main/tests/support/analysis-efficiency/android-jni.mjs)
|
||||
accepts `--variant ordinary|relr|aps2|conscrypt`, `--detail complete|summary`,
|
||||
`--proof --pages --cli` and optional `--retained-removal`, explicit selected
|
||||
repository/artifact/JDK/JAR/oracle paths and a fresh output directory. Frozen
|
||||
harness SHA-256:
|
||||
`14836895659de0f161c479b2b013ec39d754d172fd9935898872ab9cb5937035`.
|
||||
The [cost script](https://github.com/morluto/rea/blob/main/tests/support/analysis-efficiency/android-jni-costs.py)
|
||||
consumes every case's catalog, calls and summary receipts, fingerprints them
|
||||
and keeps qualification costs separate.
|
||||
|
||||
Initial source integration type/lint errors were corrected before qualification.
|
||||
A first CLI verifier attempt incorrectly treated its summary wrapper as flat
|
||||
Evidence; the CLI had written its valid bundle. The corrected harness saves raw
|
||||
stdout/stderr before assertions and validates the unwrapped named contract.
|
||||
One driver used the wrong Conscrypt derivative filename and failed before
|
||||
analysis; corrected cohorts use the pinned file above. A direct schema-suite
|
||||
invocation lacked generated test catalog metadata; artifact-aware verification
|
||||
is recorded separately. These attempts are not counted as successful runs.
|
||||
|
||||
Only Linux/JDK21/JADX0.7.1 and the fixed genuine NDK variants/public Conscrypt
|
||||
arm64 sample are qualified. Cross-ABI ELF fixtures do not establish real
|
||||
Windows/macOS provider lifecycle, device/emulator operation or runtime JNI
|
||||
registration. Existing IL2CPP regressions cover the shared relocation refactor;
|
||||
no new real IL2CPP application qualification is claimed. Runtime-built tables,
|
||||
obfuscated strings, unsupported encodings and missing split/runtime-loaded code
|
||||
remain unknown. Byte digests identify artifacts, not authenticity or build
|
||||
ownership.
|
||||
Loaded 100 of 1770 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user