Compare commits
107
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65f2f9a22b | ||
|
|
2dc3820b69 | ||
|
|
90fee8aee5 | ||
|
|
dd6c1db523 | ||
|
|
6bc4ea2839 | ||
|
|
c8469c844c | ||
|
|
ededbd7f24 | ||
|
|
b88c75df82 | ||
|
|
35d93e21f2 | ||
|
|
0c8b7c29a4 | ||
|
|
8488f82366 | ||
|
|
5d4c2638ae | ||
|
|
185bf90c41 | ||
|
|
b2a2ab29cf | ||
|
|
985dcc4156 | ||
|
|
04e0959de4 | ||
|
|
ba0ded9a7b | ||
|
|
f161952ffd | ||
|
|
4158e8a050 | ||
|
|
391be63177 | ||
|
|
bde56bc2bc | ||
|
|
c8d8319367 | ||
|
|
ef60791750 | ||
|
|
bf9d3a6e47 | ||
|
|
cda262bfc4 | ||
|
|
d3443521d4 | ||
|
|
e4153bc268 | ||
|
|
5eede35c97 | ||
|
|
4aee0afc21 | ||
|
|
d4b615e2b9 | ||
|
|
577ca5a0ae | ||
|
|
bfe439d990 | ||
|
|
8416f4d3e3 | ||
|
|
e70f2df61e | ||
|
|
5ca00675b7 | ||
|
|
9a769cbefe | ||
|
|
1565461809 | ||
|
|
e990feeb7c | ||
|
|
e23f540445 | ||
|
|
7259ea1dee | ||
|
|
65b701df54 | ||
|
|
3e4c0d8b59 | ||
|
|
8d13c67e7e | ||
|
|
d7d95c7dcc | ||
|
|
7a76e0b9ba | ||
|
|
8e0aa73db2 | ||
|
|
bd27ab7422 | ||
|
|
1aaa21296f | ||
|
|
3e08a6aeaf | ||
|
|
09677946cb | ||
|
|
4a067b335b | ||
|
|
9f576495a0 | ||
|
|
499fe56a62 | ||
|
|
782132cb58 | ||
|
|
f521ec72f5 | ||
|
|
b5259d82a4 | ||
|
|
3348688579 | ||
|
|
f44dca9c37 | ||
|
|
29e0472812 | ||
|
|
4882f6b5dc | ||
|
|
7a7c4a6d7a | ||
|
|
e2205313a5 | ||
|
|
7d0da075e7 | ||
|
|
4986b8644f | ||
|
|
a440049026 | ||
|
|
e678be3f9d | ||
|
|
e38a4c4394 | ||
|
|
a225d7c552 | ||
|
|
14bc2bca21 | ||
|
|
71be07de42 | ||
|
|
8114bd675e | ||
|
|
4d7fccbce6 | ||
|
|
af53e0fbe5 | ||
|
|
f08c191ed3 | ||
|
|
da6f5470be | ||
|
|
fb9adbf384 | ||
|
|
f9f9dc209d | ||
|
|
04c081fc61 | ||
|
|
3aa685db39 | ||
|
|
56182b2217 | ||
|
|
e9348df0c3 | ||
|
|
01e5c59551 | ||
|
|
33c4282b8a | ||
|
|
f34425dc24 | ||
|
|
dad0228df8 | ||
|
|
73db4fad54 | ||
|
|
c53c2a9b90 | ||
|
|
9e1b39358a | ||
|
|
1346e97dca | ||
|
|
dc022bcd0f | ||
|
|
5aa78c873e | ||
|
|
15d75ea1ea | ||
|
|
e9b9a8dd0e | ||
|
|
f3f209d03f | ||
|
|
4f13bd6733 | ||
|
|
f2f029c5dd | ||
|
|
a7e9f8843b | ||
|
|
fcfc87b2b4 | ||
|
|
c5cefd622b | ||
|
|
5aa1c5c64f | ||
|
|
2e11fc23fd | ||
|
|
fd79a273f3 | ||
|
|
d711c55aed | ||
|
|
72b24433ea | ||
|
|
2e19ece025 | ||
|
|
27f981352d | ||
|
|
0d99e8c5c5 |
No files matched your search
@@ -1,113 +0,0 @@
|
||||
---
|
||||
name: rea-analysis-optimization
|
||||
description: Optimize REA providers and shared analysis workflows for agent context, latency, CPU, and memory while preserving correctness and Evidence. Use for analysis bottlenecks and cache or query design; CI/test-suite optimization belongs to rea-ci-tests-audit.
|
||||
---
|
||||
|
||||
# REA analysis optimization
|
||||
|
||||
Find a concrete source of unnecessary work, change it at its owner, and verify
|
||||
equivalent completed investigations. A useful outcome can also be a measured
|
||||
decision to leave an implementation alone.
|
||||
|
||||
Follow the checkout's [performance priorities](../../../AGENTS.md#performance),
|
||||
[tool design](../../../docs/tool-design.md), and
|
||||
[testing guide](../../../docs/testing.md). This skill supplies an optimization
|
||||
workflow, not additional permission to execute targets, publish, or merge.
|
||||
Use the current contracts, provider prerequisites, and user authorization.
|
||||
|
||||
Read [the Kuna case study](references/kuna-case-study.md) when selecting a
|
||||
reuse strategy or interpreting a benchmark. Its pinned observations illustrate
|
||||
tradeoffs; they are not current-provider guarantees or universal speedups.
|
||||
|
||||
## Pin the question and the correctness oracle
|
||||
|
||||
Describe the analyst's completed task, including the facts and relationships
|
||||
needed to answer it, requested detail, source access, and meaningful unknowns.
|
||||
Choose a representative real artifact and a small or empty case. Record the
|
||||
baseline revision, target digest, engine identity, options, host, and entrypoint.
|
||||
Use a separate checkout for changes without disturbing other work.
|
||||
|
||||
Establish an oracle independent of the changed implementation: source-built
|
||||
fixture expectations, independently mapped file bytes, or a native producer
|
||||
paired with checks of its interpretation. Comparing two wrappers around the
|
||||
same faulty decoder does not establish correctness. Preserve address widths,
|
||||
same-address alternatives, unresolved endpoints, coverage, and source linkage.
|
||||
An empty result proves absence only within the actually examined scope.
|
||||
|
||||
## Locate the earliest unnecessary work
|
||||
|
||||
Trace one public CLI or MCP task through shared application code to its producer.
|
||||
Measure relevant phases: admission and identity checks, native analysis,
|
||||
decoding, lookup, projection, serialization, Evidence retention, and cleanup.
|
||||
Include catalog discovery and extra calls when they affect the completed task.
|
||||
|
||||
Use the evidence to choose the smallest structural correction:
|
||||
|
||||
| Observed cost | Candidate correction | Condition to establish |
|
||||
| --------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
||||
| Repeated scans of validated facts | Reuse existing order or lookup structure | The owner establishes ordering and identity; every matching alternative survives |
|
||||
| Repeated equivalent engine work | Share a validated result or in-flight producer | Inputs, freshness, lifetime, and per-caller outcomes remain explicit |
|
||||
| Full reports for selected facts | Push selection or projection to the earliest capable owner | Required facts and evidence remain reachable; examined coverage is reported |
|
||||
| Large temporary transport buffers | Decode incrementally or use bounded source reads | Validate the whole admitted document; retained facts and copies still consume memory |
|
||||
| Many repeated homogeneous reads | Share admission, decoding, or batch work | Preserve item identity, order where required, and individual failures |
|
||||
|
||||
Do not introduce an index, generic cache, batch endpoint, or orchestration layer
|
||||
without identifying the work it removes and its maintenance/resource cost.
|
||||
Projection after materializing a full report may reduce output while leaving
|
||||
analysis time and peak memory unchanged. Fix missing or incorrect facts before
|
||||
benchmarking an alternative composition against a better-covered workflow.
|
||||
|
||||
## Keep one interpretation and a defined reuse lifetime
|
||||
|
||||
Let the producer boundary validate and normalize facts once. Consumers query
|
||||
that representation through the shared CLI/MCP implementation; adapters should
|
||||
not rebuild relationships or independently reinterpret raw reports. Keep lookup
|
||||
identity separate from display formatting. Reuse contracts when their intent
|
||||
matches, honoring requested detail and complete Evidence access.
|
||||
|
||||
For every cache or shared producer, state its key, owner, invalidation, retained
|
||||
size, and lifetime. Account for result-affecting target bytes, engine contents,
|
||||
analysis options, architecture/load mapping, and parser/schema versions where
|
||||
they affect reuse. Validate live state before calling a cached observation
|
||||
current. Cache a refusal only when it is deterministic for that validated key;
|
||||
malformed, partial, transient, or cancelled attempts need explicit retry policy.
|
||||
|
||||
One cancelled waiter must not invalidate a successful peer. Preserve producer
|
||||
failure context and each caller's cancellation reason. Retain ownership and
|
||||
capacity charges until shared work and cleanup settle; preserve completed
|
||||
observations when cleanup fails. Exercise invalidation, concurrent consumers,
|
||||
last-waiter cancellation, close, and cleanup retry when those paths change.
|
||||
|
||||
Bound the process family and retained state, not just a parent heap or worker
|
||||
count. Account for decoding and serialization expansion before allocation.
|
||||
Choose CPU, memory, concurrency, and disk limits from the host and workload;
|
||||
stop before OOM and verify owned cleanup. A guard-stopped task is incomplete.
|
||||
Do not replace a transport buffer cap with an unbounded retained inventory or
|
||||
hide partial results behind a success status.
|
||||
|
||||
## Compare completed tasks and limit the claim
|
||||
|
||||
Run the affected real public workflow before and after with equivalent inputs,
|
||||
results, coverage, and Evidence semantics. Include small inputs so setup costs
|
||||
and regressions are visible. Distinguish fresh sessions, warm runtime caches,
|
||||
and OS file caches. Alternate or repeat runs when variance affects the decision.
|
||||
Choose meaningful boundary regressions for cases the actual engine cannot
|
||||
reliably reproduce; a fake engine does not qualify a real provider.
|
||||
|
||||
Report task outcome, relevant phase timings, total elapsed and CPU time, peak
|
||||
process-family memory and its accounting method, resource stops, and cleanup.
|
||||
Check the payload exit status as well as the profiler's. Keep failed attempts
|
||||
and identify unmeasured costs; a passing retry does not explain a failure.
|
||||
|
||||
For token claims, count schemas/discovery, arguments, replies, retries, and
|
||||
continuations needed to finish the task. Label tokenizer estimates separately
|
||||
from actual model usage and record the client/catalog behavior. Smaller JSON
|
||||
alone establishes neither fewer model tokens nor better investigation quality.
|
||||
Do not claim a complex-software advantage without completed representative
|
||||
investigations and comparable correctness/coverage.
|
||||
|
||||
Finish with the bottleneck, owning change, preserved semantics, executed
|
||||
checks, before/after measurements, and remaining limits. Keep any integration
|
||||
record current with its tested revision and distinguish merged production work
|
||||
from experiment-only code. Stop when the demonstrated bottleneck is resolved
|
||||
or further benefit remains speculative.
|
||||
@@ -1,4 +0,0 @@
|
||||
interface:
|
||||
display_name: "REA analysis optimization"
|
||||
short_description: "Optimize analysis with preserved Evidence and measured costs"
|
||||
default_prompt: "Use $rea-analysis-optimization to find and verify a concrete analysis bottleneck while preserving correctness and Evidence."
|
||||
@@ -1,112 +0,0 @@
|
||||
# Kuna: reuse before adding machinery
|
||||
|
||||
Read this reference for concrete examples of the skill's decisions. The records
|
||||
below concern static Linux analysis with caller-supplied Kuna. They do not
|
||||
establish parity with another provider or a general advantage for Code Mode,
|
||||
atomic tools, or any particular orchestration design.
|
||||
|
||||
## Exact-address lookup: a measured, narrow improvement
|
||||
|
||||
[PR #4695](https://github.com/morluto/rea/pull/4695) reused the validated string
|
||||
inventory's numeric address order. Previously, each `list_strings(address)`
|
||||
filtered all cached facts. The owner now performs a binary lower-bound lookup
|
||||
and returns every encoding at that address: O(log n + matches), without a
|
||||
second retained lookup index.
|
||||
|
||||
The owning implementation is
|
||||
[`KunaStringInventory.ts`](../../../../src/kuna/KunaStringInventory.ts), consumed
|
||||
by [`KunaStringQueries.ts`](../../../../src/kuna/KunaStringQueries.ts). Inspect
|
||||
their current versions before adapting the example. Numeric u64 addresses,
|
||||
same-address encodings, duplicate rejection, source digests, caller selection,
|
||||
and the existing session lifetime were part of the contract. Full listings and
|
||||
literal/regex searches kept their semantics. An attempted removal of the
|
||||
duplicate-detection set was dropped: no stable memory benefit was established,
|
||||
and it delayed malformed-input rejection.
|
||||
|
||||
### Recorded workload and results
|
||||
|
||||
The benchmark used unmodified Kuna 1.833 and LLVM 16 on Linux x86-64, with
|
||||
602,544 string facts. Baseline was `be0b2d138`; the final feature was
|
||||
`5f564962da0e1b17f00a68a74a312539f0209a01`, subsequently integrated in
|
||||
`c6b62754b095a134d6d67877508fa34311a2eda2`. These are historical observations,
|
||||
not a benchmark of every subsequent main revision.
|
||||
|
||||
The same production stdio MCP task discovered the catalog, opened the binary,
|
||||
made one cold selected read and 28 warm exact reads, checked retained Evidence,
|
||||
and closed the session. Five selected addresses and two absent selectors were
|
||||
read four times. A native filtered scan selected the strings; an independent
|
||||
ELF load-header mapping checked the source bytes and terminators. Returned
|
||||
facts, source linkage, target digests, and cleanup were checked.
|
||||
|
||||
Three alternating fresh sessions per implementation used one CPU, a 4 GiB
|
||||
process-family hard limit, a 3 GiB early stop, and no swap. OS file caches were
|
||||
warm. Whole-harness costs include the independent native oracle, hashing,
|
||||
catalog/client work, and correctness checks.
|
||||
|
||||
| Median | Before | After |
|
||||
| ---------------------------------------- | ---------: | ---------: |
|
||||
| 28 warm exact MCP reads | 495.2 ms | 90.8 ms |
|
||||
| Cold selected MCP read | 11.30 s | 11.01 s |
|
||||
| Whole harness elapsed | 28.24 s | 27.43 s |
|
||||
| Whole process-family CPU | 27.71 s | 26.89 s |
|
||||
| Kernel family peak, including file cache | 2237.6 MiB | 2240.6 MiB |
|
||||
|
||||
Warm totals ranged from 491.7–544.3 ms before to 84.8–99.5 ms after: about
|
||||
5.5 times faster at this phase. Cold/whole-task timing and memory overlapped;
|
||||
no stable improvement in those costs was established. One small SQLite pair
|
||||
(7,985 facts) measured 20 warm reads at 88.6 → 80.5 ms and the whole harness at
|
||||
13.68 → 13.94 s. The large-inventory lookup benefit does not generalize to a
|
||||
whole-task speedup on small inputs.
|
||||
|
||||
Catalog hashes, call counts, and normalized facts were unchanged. A
|
||||
`cl100k_base` estimate over one pass of raw catalog JSON, arguments, and replies
|
||||
was about 846,000 tokens in both lanes, with about 802,562 from the catalog.
|
||||
This was transport serialization, not rendered model context or actual usage;
|
||||
client discovery, prompts, replay, and protocol framing were unmeasured.
|
||||
**No token reduction or improved agent investigation outcome was established.**
|
||||
|
||||
Pinned target SHA-256:
|
||||
`f62d254b7f2bf42df8c8b07d46ee3bb4c2cafeca436b2e6bc6ccbe4581f58f40`.
|
||||
Pinned engine SHA-256:
|
||||
`d858918b0766435cd96b999a77f2d5a31a0cc4f07256421c883b5b9dc4dd58e4`.
|
||||
All six normalized-result sequence digests were
|
||||
`4d2f90269da8568984090b20274163c4a7c2a0538aab63530bd2fe44840a0bba`.
|
||||
Selected byte agreement does not prove native discovery completeness; missing
|
||||
strings and relationships can remain unknown.
|
||||
|
||||
## Other transferable changes and their limits
|
||||
|
||||
- [Cached string inventory and search, #4095](https://github.com/morluto/rea/pull/4095):
|
||||
share validated facts across queries in a defined session. Audit key inputs
|
||||
and lifetime before extending reuse across targets or engine revisions.
|
||||
- [Shared single-function work, #4045](https://github.com/morluto/rea/pull/4045)
|
||||
and [repeat-request reuse, #4169](https://github.com/morluto/rea/pull/4169):
|
||||
avoid duplicate native work while retaining per-caller cancellation and
|
||||
cleanup ownership. A query count alone cannot reveal duplicate subprocesses.
|
||||
- [Streamed strings, #4318](https://github.com/morluto/rea/pull/4318)
|
||||
and [streamed call graph, #4329](https://github.com/morluto/rea/pull/4329):
|
||||
remove fixed aggregate transport-buffer failures through incremental parsing.
|
||||
Streaming transport does not bound every retained object or final reply.
|
||||
These links establish changes; no numerical speedup is asserted here.
|
||||
|
||||
Typed reference facts, native string-query projection, and shared native byte
|
||||
reads remained experimental at the 2026-10-17 checkpoint
|
||||
`65f2f9a22bc892f61d2b00f9a4611124f57d4bff` on
|
||||
`experiment/atomic-codemode-20261016`. Some experiments used a patched native
|
||||
engine. Check current integration and bring-your-own engine capabilities before
|
||||
proposing them; a working experiment is not a stock-provider guarantee.
|
||||
|
||||
## Applying the reasoning elsewhere
|
||||
|
||||
For another provider or format, inspect its actual representation and native
|
||||
capabilities before borrowing the implementation. Existing numeric ordering
|
||||
may support range reads; an on-disk native query may avoid materializing an
|
||||
inventory; an immutable parse may support several views. Measure the relevant
|
||||
alternative rather than requiring every provider to use Kuna's cached array.
|
||||
|
||||
For live observations, immutable artifact caching rules are insufficient:
|
||||
validate the process/session identity and freshness required by the caller.
|
||||
For compact replies, preserve access to source Evidence and report examined
|
||||
coverage; projection must not silently turn an unresolved edge into no edge.
|
||||
For batching, test mixed successes and failures and measure the entire task,
|
||||
including discovery, extra calls, native work, and serialization.
|
||||
@@ -124,26 +124,6 @@ operation's full ordered list. Candidate capabilities describe possible
|
||||
providers. Top-level session capabilities describe the current route, and
|
||||
`analysis_provider_binding` identifies the selected provider.
|
||||
|
||||
## Static memory and original file bytes
|
||||
|
||||
For Ghidra, `read_bytes` reads initialized analysis memory, including loader
|
||||
fixups; it does not read a running process. Check `returned_bytes` and `complete`
|
||||
before decoding a table. An incomplete read is missing coverage, not a zero-filled
|
||||
tail. Use `list_segments` to inspect the selected block's initialization and address-space
|
||||
facts, and retain unavailable facts as unknown.
|
||||
|
||||
Use `address_to_file_offset` to anchor one observed address to original file
|
||||
bytes. A mapping for the first address does not establish a contiguous mapping
|
||||
for an entire table, and loader fixups can make analysis bytes differ from source
|
||||
bytes. Keep source ranges and analysis-memory observations separate.
|
||||
|
||||
A pointer table can refer to writable slots populated by a constructor rather
|
||||
than directly to immutable resources. An uninitialized block or an observed zero
|
||||
does not establish the slot's later runtime value. Follow `xrefs` and the relevant
|
||||
writer's assembly or pseudocode; distinguish recorded assignments from inferred
|
||||
execution order. Do not replace unreadable bytes with zeros or conclude that a
|
||||
resource is absent without the necessary initialization evidence.
|
||||
|
||||
## DOS MZ with Ghidra
|
||||
|
||||
For an admitted DOS MZ target, use `inspect_native_load_image` to check measured
|
||||
@@ -153,8 +133,10 @@ reported static image, not runtime DOS or PC-98 hardware behavior.
|
||||
|
||||
For Ghidra decompilation, `procedure_pseudo_code` also accepts `procedure: "file-offset:0x..."`; CLI `rea decompile <path> --file-offset=0x... --provider ghidra` resolves the source byte offset internally. An unresolved 0x-prefixed numeric procedure selector also falls back to a unique file mapping. Existing symbols and analysis addresses win; multiple mappings fail as ambiguous. Preserve the returned file-offset and address locations and raw selection observations. ELF virtual addresses are distinct from file offsets; never assume an arbitrary offset plus image base is an analysis address.
|
||||
|
||||
Complete function body ranges use inclusive ends and can contain gaps. Do not
|
||||
treat the enclosing span as code.
|
||||
Use `read_bytes` for initialized analysis memory and `address_to_file_offset` to
|
||||
anchor one observed address to original file bytes. Loader fixups can change a
|
||||
word; a source offset does not imply byte equality. Complete function body ranges
|
||||
use inclusive ends and can contain gaps. Do not treat the enclosing span as code.
|
||||
For packed targets, retain the original and separately derived artifact identities;
|
||||
decompiling an unpacking stub does not recover the unpacked program.
|
||||
|
||||
|
||||
@@ -24,7 +24,19 @@ runs:
|
||||
BUILD_CACHE_PREFIX: rea-portable-build-v2-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.npmrc', '.nvmrc', 'package-lock.json') }}
|
||||
run: |
|
||||
npm run --silent test:prepare -- --dry=json |
|
||||
node scripts/ci/portable-build-cache.mjs key >> "$GITHUB_OUTPUT"
|
||||
node --input-type=module -e '
|
||||
import { createHash } from "node:crypto";
|
||||
import { readFileSync } from "node:fs";
|
||||
const { tasks } = JSON.parse(readFileSync(0, "utf8"));
|
||||
const hashes = tasks.map(({ taskId, hash }) => {
|
||||
if (typeof hash !== "string")
|
||||
throw new Error(`Build task ${taskId} must have an eager Turbo hash`);
|
||||
return `${taskId}:${hash}`;
|
||||
}).sort();
|
||||
const hash = createHash("sha256").update(hashes.join("\n")).digest("hex");
|
||||
console.log(`key=${process.env.BUILD_CACHE_PREFIX}-${hash}`);
|
||||
console.log(`prefix=${process.env.BUILD_CACHE_PREFIX}-`);
|
||||
' >> "$GITHUB_OUTPUT"
|
||||
- name: Restore portable build outputs
|
||||
if: inputs.build_cache_artifact == '' && inputs.save != 'true'
|
||||
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
|
||||
@@ -357,15 +357,10 @@ jobs:
|
||||
# test:prepare caches only portable JS, skill, and catalog outputs.
|
||||
# Native package jobs still run their build and prepack checks; Turbo
|
||||
# restores matching outputs or rebuilds when their inputs differ.
|
||||
- name: Stage current portable build task cache
|
||||
shell: bash
|
||||
run: |
|
||||
# A new Turbo dry run can evict the entries this build just used.
|
||||
node scripts/ci/portable-build-cache.mjs snapshot < .cache/ci-build-plan.json
|
||||
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: rea-build-cache
|
||||
path: .cache/ci-build-cache/
|
||||
path: .turbo/cache/
|
||||
include-hidden-files: true
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
@@ -653,7 +648,6 @@ jobs:
|
||||
tests/boundary/cli/nativePlistPrototypeKeyCli.test.ts
|
||||
tests/boundary/cli/nativePlistSelectionFailureCli.test.ts
|
||||
tests/boundary/cli/nativeDemangleCli.test.ts
|
||||
tests/boundary/cli/nativeDispatchPropertyAttributes.test.ts
|
||||
tests/boundary/mcp/nativeDemangleMcp.test.ts
|
||||
tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts
|
||||
tests/boundary/cli/nativeSignatureCli.test.ts
|
||||
@@ -754,7 +748,6 @@ jobs:
|
||||
tests/boundary/filesystem/webScriptManifestPaths.test.ts
|
||||
tests/boundary/process/ProcessEvidence.host.test.ts
|
||||
tests/boundary/process/packageNpmInvocation.test.ts
|
||||
tests/boundary/process/packedBridgeVerification.test.ts
|
||||
tests/boundary/process/windowsOutputCapture.test.ts
|
||||
tests/acceptance/webModuleCli.test.ts
|
||||
tests/acceptance/webSourceLocationCli.test.ts
|
||||
|
||||
@@ -24,19 +24,7 @@ jobs:
|
||||
real-recorded-crash:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: ["ubuntu:24.04", "debian:trixie-slim"]
|
||||
container: ${{ matrix.image }}
|
||||
steps:
|
||||
- name: Install fixture and debugger prerequisites in the disposable container
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get install --yes --no-install-recommends \
|
||||
ca-certificates git python3-venv gcc libc6-dev strace gdb
|
||||
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
@@ -48,6 +36,11 @@ jobs:
|
||||
- uses: ./.github/actions/portable-build-cache
|
||||
with:
|
||||
build_cache_artifact: ${{ inputs.build_cache_artifact }}
|
||||
- name: Install GDB on the disposable CI runner
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install --yes --no-install-recommends gdb
|
||||
- name: Acquire exact unchanged upstreams in isolated runner storage
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
".": "6.7.0"
|
||||
".": "6.5.0"
|
||||
}
|
||||
@@ -1,93 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [6.7.0](https://github.com/morluto/rea/compare/rea-agents-6.6.0...rea-agents-6.7.0) (2026-10-18)
|
||||
|
||||
### Highlights
|
||||
|
||||
- Client configuration edits follow the duplicate-member semantics used by MCP clients.
|
||||
|
||||
### Changes
|
||||
|
||||
- Includes the [6.6.0 changes and migration notes](https://github.com/morluto/rea/releases/tag/rea-agents-6.6.0). That version was tagged but was not published to npm.
|
||||
|
||||
### Fixes
|
||||
|
||||
- **Client configuration:** Setup edits the last repeated JSON/JSONC member, matching the value clients actually read. Setup and uninstall refuse a removal that would reactivate a shadowed duplicate, preserving the original configuration. ([#4957](https://github.com/morluto/rea/pull/4957), [morluto/rea#4952](https://github.com/morluto/rea/issues/4952)). Thanks @kaoru0822-kitauji, @xu91102.
|
||||
|
||||
Full contribution record: [4 commits and 1 merged PR](https://github.com/morluto/rea/blob/rea-agents-6.7.0/docs/releases/6.7.0.contributions.json).
|
||||
|
||||
## [6.6.0](https://github.com/morluto/rea/compare/rea-agents-6.5.0...rea-agents-6.6.0) (2026-10-18)
|
||||
|
||||
### Highlights
|
||||
|
||||
- Add Kuna as a caller-supplied static-analysis provider.
|
||||
- Query selected JavaScript facts and multiple APK locale tables without repeating the underlying analysis.
|
||||
- Extend Ghidra analysis to Windows ARM PE targets and explicit raw m68k images.
|
||||
- Preserve completed Evidence, cancellation reasons and retryable cleanup across provider and CLI finalization.
|
||||
|
||||
### Changes
|
||||
|
||||
- **Kuna analysis:** Use a caller-installed Kuna for procedure listings, pseudocode, assembly, call relationships, exact-address xrefs and cached string searches. Project exports retain source spans and digests; repeated requests reuse completed work. Recorded real-provider coverage uses Kuna 1.833 on Linux; Windows, PE and universal Mach-O are unsupported. See [the provider guide](docs/kuna-provider.md). ([#3832](https://github.com/morluto/rea/pull/3832), [#3854](https://github.com/morluto/rea/pull/3854), [#4071](https://github.com/morluto/rea/pull/4071), [#4095](https://github.com/morluto/rea/pull/4095)). Thanks @gensokyo-dev, @kaoru0822-kitauji, @N0zoM1z0.
|
||||
- **Retained JavaScript facts:** Query exact application paths, selected properties and filtered module references through `inspect_analysis_view`, with paging and complete row Evidence. These views reuse completed analysis and preserve source selection and unknown coverage. ([#4265](https://github.com/morluto/rea/pull/4265), [morluto/rea#4190](https://github.com/morluto/rea/issues/4190), [#4097](https://github.com/morluto/rea/pull/4097), [morluto/rea#4092](https://github.com/morluto/rea/issues/4092)). Thanks @kaoru0822-kitauji, @N0zoM1z0.
|
||||
- **APK locale tables:** Request several resource locales in one decode with repeatable CLI `--locales` or MCP `locales`. Each table reports its status and coverage; existing single-locale fields remain available. ([#4804](https://github.com/morluto/rea/pull/4804), [morluto/rea#4777](https://github.com/morluto/rea/issues/4777)). Thanks @abhay-2108, @N0zoM1z0.
|
||||
- **Windows ARM binaries:** Ghidra admits ARMNT/Thumb-2 and ARM64 PE applications and DLLs on the Windows x64 host lane. Recorded Ghidra 12.1.4 verification uses `WindowsResourceReference` disabled and raised startup budgets; default-analyzer completion, ARM64EC/ARM64X and Windows-on-Arm hosts remain unverified or unsupported. See [the exact scope](docs/windows-ghidra-p0.md#native-authority-and-target-identity). ([#3965](https://github.com/morluto/rea/pull/3965), [morluto/rea#2186](https://github.com/morluto/rea/issues/2186)). Thanks @N0zoM1z0, @WestLabsAI.
|
||||
- **Raw m68k images:** Analyze explicitly selected big-endian m68k raw binaries using Ghidra’s fixed 68000 profile and a caller-supplied aligned entry. Real CLI/MCP verification used Ghidra 12.1.4 on macOS arm64; Linux is unverified and Windows P0 does not admit m68k. See [mapping requirements](docs/raw-binary.md). ([#4018](https://github.com/morluto/rea/pull/4018)). Thanks @icedac.
|
||||
- **JADX deadlines:** Set `REA_JADX_OPERATION_TIMEOUT_MS` to extend APK loading and upstream operation deadlines together. Doctor reports the effective value and setup forwards an explicit selection. ([#4466](https://github.com/morluto/rea/pull/4466), [morluto/rea#3918](https://github.com/morluto/rea/issues/3918)). Thanks @jaychou813, @SandstromPL.
|
||||
- **Electron window options:** Resolve stable local constant `BrowserWindow` options while retaining source provenance. Relevant writes and escapes keep the result unknown. ([#4400](https://github.com/morluto/rea/pull/4400), [morluto/rea#4366](https://github.com/morluto/rea/issues/4366)). Thanks @kaoru0822-kitauji, @N0zoM1z0.
|
||||
- **Language editions:** Add the Greek website edition and Malayalam documentation, with Korean typography and translation corrections across the site. ([#3520](https://github.com/morluto/rea/pull/3520), [#4792](https://github.com/morluto/rea/pull/4792), [#3821](https://github.com/morluto/rea/pull/3821), [morluto/rea#3820](https://github.com/morluto/rea/issues/3820), [#3799](https://github.com/morluto/rea/pull/3799), [morluto/rea#3798](https://github.com/morluto/rea/issues/3798), [#4344](https://github.com/morluto/rea/pull/4344), [#3856](https://github.com/morluto/rea/pull/3856), [#4166](https://github.com/morluto/rea/pull/4166)). Thanks @gensokyo-dev, @hi2242, @kalayciburak, @kaoru0822-kitauji, @kraken-503, @kukinghan, @N0zoM1z0, @yeseong0412.
|
||||
|
||||
### Fixes
|
||||
|
||||
- **Cancellation and cleanup:** Keep completed observations, exact cancellation reasons and the original physical failure through finalization. Failed cleanup retains its process or file owner for retry; recovered resources disappear from pending-cleanup reports without replacing the original error. ([#4238](https://github.com/morluto/rea/pull/4238), [morluto/rea#4232](https://github.com/morluto/rea/issues/4232), [#4274](https://github.com/morluto/rea/pull/4274), [morluto/rea#3923](https://github.com/morluto/rea/issues/3923), [3e82366](https://github.com/morluto/rea/commit/3e8236639abffa39deb5d5e939ec8baf6aaf3ca3), [16924e2](https://github.com/morluto/rea/commit/16924e275e939d0543ba01493324959a9e1d731c), [bbfe6ed](https://github.com/morluto/rea/commit/bbfe6edd60290f9bfbec68c8a0bcf605d8bbf5b3), [1f23e97](https://github.com/morluto/rea/commit/1f23e977b50301e91f02a4a17c9f8d48bb7b60f3), [08fbeb8](https://github.com/morluto/rea/commit/08fbeb8bdab27118b6c57039aef7c0fa8b6463bc)). Thanks @coygeek.
|
||||
- **Provider startup:** Join prerequisite probes and in-flight readiness work before shutdown, preserve typed timeout and JVM-memory failures, and retain startup diagnostics through cleanup. Ghidra recognizes keg-only Homebrew JDKs and names the setting responsible for a startup timeout. ([376eeca](https://github.com/morluto/rea/commit/376eeca770820b31f7f8d4c5fcc397315621643e), [ceeff5a](https://github.com/morluto/rea/commit/ceeff5a41788e47e5aee96a4baf191a6ce7fde4b), [3ad1032](https://github.com/morluto/rea/commit/3ad1032b11edea2dcb054e78f951cc43159ae83d), [964decd](https://github.com/morluto/rea/commit/964decd989acfa84c4bfc3295362c4c46877fc20), [3fa972a](https://github.com/morluto/rea/commit/3fa972af7c7cb6cf014ffc426bdf7130dc6f2fd2), [#4557](https://github.com/morluto/rea/pull/4557), [morluto/rea#4556](https://github.com/morluto/rea/issues/4556), [#4590](https://github.com/morluto/rea/pull/4590), [morluto/rea#4241](https://github.com/morluto/rea/issues/4241)). Thanks @DanielCvz1, @J0UH, @Rinkia, @RishTheFish21, @vadlachary2002.
|
||||
- **Client configuration:** Preserve the selected launcher, destination file, caller timeout choices and unresolved configuration evidence. Setup/uninstall recovery stays bound to the exact published file, keeps current verified backups, and transfers failed cleanup ownership for retry. ([d0253c9](https://github.com/morluto/rea/commit/d0253c99d65afbbd12732a2fdaf711640574e17f), [7e4eed9](https://github.com/morluto/rea/commit/7e4eed9dd48485b6a7100300aa98401811c2deb9), [2fb5e20](https://github.com/morluto/rea/commit/2fb5e204a35723f6f843d56ca47b0db94d8fcc44), [8235210](https://github.com/morluto/rea/commit/823521085a28f825e7fee1929d852d420042d1f7), [d818c3d](https://github.com/morluto/rea/commit/d818c3d2639d3115edb8a5269a754101aea6c3bd), [19329e4](https://github.com/morluto/rea/commit/19329e43bb38ca9d64512d801b25abcb188d2512), [dadf909](https://github.com/morluto/rea/commit/dadf909dce2e8b3d055541de69b4118d21276316), [333e0ab](https://github.com/morluto/rea/commit/333e0ab0dfc126a9915907d5079ed6195190e38e), [c15c206](https://github.com/morluto/rea/commit/c15c2062ad815cc9a3222ccfaeb7ef53cacd8b72)). Thanks @Adolanium.
|
||||
- **Configuration formats:** Read signed 64-bit TOML integers without rounding, handle large TOML documents without argument-spread failures, preserve JSONC trivia and Hermes YAML scalar text, and reject NUL bytes in registration environment values. ([#4937](https://github.com/morluto/rea/pull/4937), [morluto/rea#4917](https://github.com/morluto/rea/issues/4917), [c43bc0b](https://github.com/morluto/rea/commit/c43bc0bf66a4e245a0cafa40def0d0207bcbd73c), [4fd28fc](https://github.com/morluto/rea/commit/4fd28fc9e0c4f8358147af38c72ab9e814f52d61), [#3568](https://github.com/morluto/rea/pull/3568), [#4335](https://github.com/morluto/rea/pull/4335)). Thanks @alfredo1491, @gensokyo-dev, @kaoru0822-kitauji, @N0zoM1z0, @ShuaixinHuang, @xu91102.
|
||||
- **Claude Code configuration:** Setup, doctor and uninstall now accept only the strict JSON format Claude Code reads, including a leading UTF-8 BOM. Comments and trailing commas are refused before backup or writing; clients that support JSONC retain their existing behavior. ([#4944](https://github.com/morluto/rea/pull/4944), [morluto/rea#4940](https://github.com/morluto/rea/issues/4940)). Thanks @kaoru0822-kitauji, @xu91102.
|
||||
- **CLI output and dispatch:** Accept `--flag=value` and spaced global output values, keep array positions in filtered JSON, validate integer tokens before coercion, and exit quietly when the output reader closes. Cancellation remains effective through command finalization; app bundles and static native inspections select the intended workflow. ([#3811](https://github.com/morluto/rea/pull/3811), [#4823](https://github.com/morluto/rea/pull/4823), [2ae4e16](https://github.com/morluto/rea/commit/2ae4e1608f290c95ff7cff28c4d16a79b301d03d), [8d82579](https://github.com/morluto/rea/commit/8d8257928bbe8d43fedffc4db5fca26c8108820f), [#3781](https://github.com/morluto/rea/pull/3781), [279c590](https://github.com/morluto/rea/commit/279c590ef6bb737d4a48ea696a0ae5eb30010b3d), [#3511](https://github.com/morluto/rea/pull/3511), [morluto/rea#3321](https://github.com/morluto/rea/issues/3321), [f31b231](https://github.com/morluto/rea/commit/f31b231a92a61be6bd1800b16be0b3210ae82944)). Thanks @arjunprabhulal, @coygeek, @kaoru0822-kitauji, @ShuaixinHuang, @Sriram-PR, @Tapraj-Pathak.
|
||||
- **Updates:** Route `--update` through the verified updater and bound retained package-manager diagnostics. ([4f7b5fb](https://github.com/morluto/rea/commit/4f7b5fb6023ce2ec449561782d09e3c7e5ac7c7b), [01cdbbd](https://github.com/morluto/rea/commit/01cdbbdc556262c47d04a5b3391dd9c17946d3fc)).
|
||||
- **MCP contracts:** Advertise self-contained tool inputs while preserving tuple, array, Boolean and nested-JSON constraints across schema profiles. Schema-reference handling no longer rewrites literal metadata; catalog identity includes the output-schema profile. ([5e30969](https://github.com/morluto/rea/commit/5e30969cc5f1255d44ec7a1f1ca8dbac0af5e7c4), [10aa74d](https://github.com/morluto/rea/commit/10aa74dfedc3ae776f50d1fa1eb83b64ae82d3d6), [204b9f3](https://github.com/morluto/rea/commit/204b9f3ac140a993c3e458bb0e117de31818ab29), [b3389a5](https://github.com/morluto/rea/commit/b3389a5b0834265fe7a40391be315d810a53a97e), [a2e3016](https://github.com/morluto/rea/commit/a2e30168a046f3b79319eb7fbaf807b802104199), [ba98130](https://github.com/morluto/rea/commit/ba98130049fa40ade66b03611ff70c7ddc011a1d), [c5fb86d](https://github.com/morluto/rea/commit/c5fb86d1948af0a287a581b29b2b1d554743c607)). Thanks @akushonkamen, @HarsH-1877, @kaoru0822-kitauji, @xingzihai.
|
||||
- **Session ordering:** Keep snapshot admission ahead of later calls on the same connection, retain shutdown signals until cleanup succeeds, and preserve inspection authority through investigation publication. ([#3661](https://github.com/morluto/rea/pull/3661), [morluto/rea#3334](https://github.com/morluto/rea/issues/3334), [8873b39](https://github.com/morluto/rea/commit/8873b39770e89eae22b7693bc492d7e423b22bea), [663d07f](https://github.com/morluto/rea/commit/663d07f02cd62c99d81c59391d2c6d745c875335)). Thanks @coygeek, @rudycelekli, @Swatantra-66.
|
||||
- **JavaScript exports and resolution:** Retain CommonJS exports created with `Object.defineProperty` and track export receiver lifetimes. Resolve scoped packages, package `main`, JSON requires and `.mts`/`.cts` imports using the owning loader; overwritten `require` bindings and erased type-only imports no longer create false runtime links. ([#4725](https://github.com/morluto/rea/pull/4725), [morluto/rea#4724](https://github.com/morluto/rea/issues/4724), [#3567](https://github.com/morluto/rea/pull/3567), [morluto/rea#3541](https://github.com/morluto/rea/issues/3541), [#4838](https://github.com/morluto/rea/pull/4838), [morluto/rea#4632](https://github.com/morluto/rea/issues/4632), [#3844](https://github.com/morluto/rea/pull/3844), [morluto/rea#3383](https://github.com/morluto/rea/issues/3383), [#4164](https://github.com/morluto/rea/pull/4164), [morluto/rea#3915](https://github.com/morluto/rea/issues/3915), [#4223](https://github.com/morluto/rea/pull/4223), [#3801](https://github.com/morluto/rea/pull/3801), [morluto/rea#3393](https://github.com/morluto/rea/issues/3393), [#4165](https://github.com/morluto/rea/pull/4165), [morluto/rea#3932](https://github.com/morluto/rea/issues/3932)). Thanks @Abishek0070, @coygeek, @JNTMTMTM, @kaoru0822-kitauji, @prasad2512, @rodricksz4h5, @xu91102.
|
||||
- **JavaScript value flow:** Preserve values captured before later assignments, guarded factory fallthrough and nested destructuring. Track exact property keys and setter writes; direct `eval`, compound assignments and incoming callbacks preserve unresolved effects instead of inventing certainty. ([#4196](https://github.com/morluto/rea/pull/4196), [morluto/rea#3881](https://github.com/morluto/rea/issues/3881), [#4341](https://github.com/morluto/rea/pull/4341), [morluto/rea#3963](https://github.com/morluto/rea/issues/3963), [bfb7ed0](https://github.com/morluto/rea/commit/bfb7ed0bd43edc605e00fc52c6e21e735b285904), [#3480](https://github.com/morluto/rea/pull/3480), [#3831](https://github.com/morluto/rea/pull/3831), [morluto/rea#3312](https://github.com/morluto/rea/issues/3312), [9ac76d3](https://github.com/morluto/rea/commit/9ac76d3d9486856d25395b413d7ac5ffa744cad0), [#4342](https://github.com/morluto/rea/pull/4342), [morluto/rea#4206](https://github.com/morluto/rea/issues/4206), [#4243](https://github.com/morluto/rea/pull/4243), [morluto/rea#3880](https://github.com/morluto/rea/issues/3880)). Thanks @coygeek, @kaoru0822-kitauji, @maxazure, @N0zoM1z0, @ShuaixinHuang.
|
||||
- **JavaScript relationships:** Distinguish `Map` reads from network endpoints, associate response endpoints only with writes that reach the read, and preserve child-process receiver ownership and effective stdio choices. Version comparisons keep relocation and unknown relationships distinct from application changes. ([fbfdb6a](https://github.com/morluto/rea/commit/fbfdb6abe9d663be0be146a15a489e33ccba0f68), [#4759](https://github.com/morluto/rea/pull/4759), [morluto/rea#4606](https://github.com/morluto/rea/issues/4606), [#3819](https://github.com/morluto/rea/pull/3819), [morluto/rea#3362](https://github.com/morluto/rea/issues/3362), [#4336](https://github.com/morluto/rea/pull/4336), [morluto/rea#3355](https://github.com/morluto/rea/issues/3355), [556504e](https://github.com/morluto/rea/commit/556504edcbb0f8cd9eaf81a91b18ff891b8f5457), [4d980d0](https://github.com/morluto/rea/commit/4d980d017622d3175d86aaf3b0dcfbdf4ca3d091)). Thanks @Abdooo2235, @coygeek, @kaoru0822-kitauji, @Xinglan233.
|
||||
- **JavaScript source admission:** Parse JavaScript with its own grammar, refuse FIFO recovery inputs without blocking, and report oversized or resource-skipped files with their actual capacity and coverage state. Malformed runtime events stay excluded rather than becoming policy-filtered facts. ([#3782](https://github.com/morluto/rea/pull/3782), [morluto/rea#3780](https://github.com/morluto/rea/issues/3780), [#3788](https://github.com/morluto/rea/pull/3788), [morluto/rea#3332](https://github.com/morluto/rea/issues/3332), [#4757](https://github.com/morluto/rea/pull/4757), [morluto/rea#4629](https://github.com/morluto/rea/issues/4629), [#3852](https://github.com/morluto/rea/pull/3852), [morluto/rea#3670](https://github.com/morluto/rea/issues/3670), [#4755](https://github.com/morluto/rea/pull/4755), [morluto/rea#4685](https://github.com/morluto/rea/issues/4685)). Thanks @andresaragon, @coygeek, @kaoru0822-kitauji, @sx4im.
|
||||
- **Browser capture:** Bound CDP handshakes and command responses, preserve malformed inventory uncertainty and partial cleanup diagnostics, and report cancellation after content reads and final cleanup. Accessibility comparisons require observed coverage; attached emulation teardown limits remain explicit. ([#3555](https://github.com/morluto/rea/pull/3555), [morluto/rea#3553](https://github.com/morluto/rea/issues/3553), [#3901](https://github.com/morluto/rea/pull/3901), [morluto/rea#3379](https://github.com/morluto/rea/issues/3379), [4cc044b](https://github.com/morluto/rea/commit/4cc044be68f813e96907e6cedcf422d0a3170de3), [#4406](https://github.com/morluto/rea/pull/4406), [morluto/rea#4403](https://github.com/morluto/rea/issues/4403), [#2893](https://github.com/morluto/rea/pull/2893), [0123d59](https://github.com/morluto/rea/commit/0123d5976828bfe621bd51daa4cf39fee48a1349), [2ff0867](https://github.com/morluto/rea/commit/2ff086796ad7b8f60397956750584e170dbe2910)). Thanks @coygeek, @dakjdakd, @kaoru0822-kitauji, @maxazure, @N0zoM1z0, @YunzhouLi-hub.
|
||||
- **Browser page facts:** Preserve URL path bytes when removing credentials, repeated document `Link` headers and complete COOP/COEP structured items. WebMCP discovery reads the actual schema properties and exact receiver path. ([#4731](https://github.com/morluto/rea/pull/4731), [df2fc25](https://github.com/morluto/rea/commit/df2fc251e318a1255309dba232f9f73c700777b6), [c360cfc](https://github.com/morluto/rea/commit/c360cfcd6d7901514b16dd6113eba2e0b0fdf422), [ebd5a82](https://github.com/morluto/rea/commit/ebd5a82c439f6deb3a06062225ce009eb03257cf), [38f92d1](https://github.com/morluto/rea/commit/38f92d108e3148cdf47e4ffbfe3de8a76e795d51)). Thanks @Abdooo2235, @geekwolf, @ShuaixinHuang.
|
||||
- **Electron runtime capture:** Keep native IPC listener and one-shot dispatch behavior, block synchronous shell effects during capture, refuse active scenarios when the inspect fuse is disabled, and preserve fuse/transport cleanup ownership. ([#4389](https://github.com/morluto/rea/pull/4389), [morluto/rea#4390](https://github.com/morluto/rea/issues/4390), [#4605](https://github.com/morluto/rea/pull/4605), [morluto/rea#4593](https://github.com/morluto/rea/issues/4593), [#4562](https://github.com/morluto/rea/pull/4562), [morluto/rea#4393](https://github.com/morluto/rea/issues/4393), [#3605](https://github.com/morluto/rea/pull/3605), [morluto/rea#3453](https://github.com/morluto/rea/issues/3453), [f9de413](https://github.com/morluto/rea/commit/f9de41371f7536e2e22ce6e43c9314fa2f238a30), [e7df00e](https://github.com/morluto/rea/commit/e7df00e80777757b329bbe8aba6d421d8892b9d5)). Thanks @Adolanium, @gensokyo-dev, @gkobayashi0, @HarsH-1877, @kaoru0822-kitauji, @keeponlight, @N0zoM1z0, @Nitin13-git, @xu91102.
|
||||
- **APK resource accuracy:** Retain completed tables and decode facts after interrupted or failed reads. Derive locale limits from resource configuration fields, disclose unselectable qualified tables, distinguish document failures from omitted entries, and bind Evidence to the decoded snapshot. ([34a88d6](https://github.com/morluto/rea/commit/34a88d6c1674710953e2c94bd0a17332cd69ca6f), [f5fcf52](https://github.com/morluto/rea/commit/f5fcf5216ffb3a266b8c00f6d9a0943051084ab5), [6385ef4](https://github.com/morluto/rea/commit/6385ef4355d7a794b3154ee38529cbddee583336), [98886ad](https://github.com/morluto/rea/commit/98886adddfcbd7b4f4236b3a9825f91878c3cb11), [dc2e811](https://github.com/morluto/rea/commit/dc2e8117b60c4481372ed89b077e6c1cf81ee653), [#4771](https://github.com/morluto/rea/pull/4771), [morluto/rea#4768](https://github.com/morluto/rea/issues/4768)). Thanks @abhay-2108, @gensokyo-dev, @Iyanuoluwa007, @kaoru0822-kitauji, @N0zoM1z0.
|
||||
- **Apktool guidance:** Retain the observed version and disclose the matching platform/release advisory windows without treating a version string as proof of decoder safety. Missing prerequisites and decode refusals identify the selected APK or launcher. ([d38f099](https://github.com/morluto/rea/commit/d38f099692394ec90c582f9f0a14b036b421b160), [63696d2](https://github.com/morluto/rea/commit/63696d277328f556c971d1fc9f81ae83128d468b), [cc038da](https://github.com/morluto/rea/commit/cc038da218cada68c87700477aba3db4739791ff)). Thanks @GovinduSasanka, @peter-research.
|
||||
- **Android method bodies:** Recover original bytecode bodies when Java source is omitted while preserving genuine native/abstract body absence and primary failures during retryable cleanup. ([63c65a2](https://github.com/morluto/rea/commit/63c65a22430a4bbc0c1807a0298edb867775001f), [742b6f5](https://github.com/morluto/rea/commit/742b6f587f3c4ef1b8212e7376d6f3a305b194dc), [9fa6d2b](https://github.com/morluto/rea/commit/9fa6d2b254cc390665974efb52463386a029e9fc)). Thanks @balkan16, @Chessing234.
|
||||
- **ADB observations and transfers:** Preserve display-scoped focus, distinguish missing declarations from absent focus, retain numeric physical density and mark unknown permission coverage partial. Transfers use consumed snapshot identity and refuse unknown destination existence; uninstall requests explicitly select user zero. ([7086768](https://github.com/morluto/rea/commit/7086768a27242a15daa93486aefbaacc3c891e78), [3d028db](https://github.com/morluto/rea/commit/3d028dbc74a465f6f8df1813a931fbb5362e7dc3), [#4074](https://github.com/morluto/rea/pull/4074), [morluto/rea#3942](https://github.com/morluto/rea/issues/3942), [#4663](https://github.com/morluto/rea/pull/4663), [#4665](https://github.com/morluto/rea/pull/4665), [1342127](https://github.com/morluto/rea/commit/1342127e91d4db8b4113a7a4e85be909bc96e1db), [61e6880](https://github.com/morluto/rea/commit/61e688070f48016b6d178cd04c02fcc2f33e19ad), [be0b2d1](https://github.com/morluto/rea/commit/be0b2d138c46bb951fc3c8ee57ef7b0d57fed312)). Thanks @Copilot, @coygeek, @gongfpp, @Tapraj-Pathak, @yankikucuk.
|
||||
- **Apple metadata:** Preserve exact plist/keyed-archive integers, negative zero, non-finite real identity and dictionary keys. Reject malformed XML before value decoding, retain undecodable dates as unknown and report unsupported OpenStep entries explicitly. ([#4324](https://github.com/morluto/rea/pull/4324), [morluto/rea#4292](https://github.com/morluto/rea/issues/4292), [2cf9c28](https://github.com/morluto/rea/commit/2cf9c28f27261b7e64af2ba7ecb4e23ea7714aee), [#4839](https://github.com/morluto/rea/pull/4839), [morluto/rea#4834](https://github.com/morluto/rea/issues/4834), [f2b7bbb](https://github.com/morluto/rea/commit/f2b7bbb31279a820f4cf32d439570f8e5381d010), [6c98708](https://github.com/morluto/rea/commit/6c98708793c23615de8053b2cd14d9f164b960c5), [78cf610](https://github.com/morluto/rea/commit/78cf6100f33ad2412c0a3d60b83f8a44a43fbbb5), [c7e9e09](https://github.com/morluto/rea/commit/c7e9e096d3e2444e4c251123b8e914e9c0941f4e), [#3793](https://github.com/morluto/rea/pull/3793), [#4105](https://github.com/morluto/rea/pull/4105), [morluto/rea#3892](https://github.com/morluto/rea/issues/3892)). Thanks @coygeek, @kaoru0822-kitauji, @mertkayacs, @pablodiazjorge, @pollychen-lab, @xu91102.
|
||||
- **Apple application structure:** Derive bundle components and launchd domains from their owning directories, retain unavailable components, and select only exact `Assets.car` names as asset catalogs. Interface Builder keeps unresolved classes and counts hierarchy records beyond the returned object page. ([149a0fc](https://github.com/morluto/rea/commit/149a0fc06c3c67ee45624e6da14dfb0754473758), [5d6029e](https://github.com/morluto/rea/commit/5d6029ea62a65ec34fd739ee40223c77c6fdb63b), [c192c58](https://github.com/morluto/rea/commit/c192c58815ddeaf5cf30159e7082c742c0bc36b7), [#4094](https://github.com/morluto/rea/pull/4094), [morluto/rea#3914](https://github.com/morluto/rea/issues/3914), [#4118](https://github.com/morluto/rea/pull/4118), [morluto/rea#3958](https://github.com/morluto/rea/issues/3958), [#4162](https://github.com/morluto/rea/pull/4162), [morluto/rea#3950](https://github.com/morluto/rea/issues/3950)). Thanks @coygeek, @kaoru0822-kitauji.
|
||||
- **Native names and layout:** Keep valid Objective-C records beside malformed neighbors, preserve leading U+FEFF and repeated load-command fields, and select exact arm64e.x1 slices. PE resource ownership and NativeAOT reads stay within declared image/header ranges. ([#3833](https://github.com/morluto/rea/pull/3833), [morluto/rea#3336](https://github.com/morluto/rea/issues/3336), [#4549](https://github.com/morluto/rea/pull/4549), [morluto/rea#4540](https://github.com/morluto/rea/issues/4540), [morluto/rea#4541](https://github.com/morluto/rea/issues/4541), [#4730](https://github.com/morluto/rea/pull/4730), [#4048](https://github.com/morluto/rea/pull/4048), [morluto/rea#4008](https://github.com/morluto/rea/issues/4008), [#3500](https://github.com/morluto/rea/pull/3500), [morluto/rea#3389](https://github.com/morluto/rea/issues/3389), [#4463](https://github.com/morluto/rea/pull/4463), [morluto/rea#4373](https://github.com/morluto/rea/issues/4373), [morluto/rea#4455](https://github.com/morluto/rea/issues/4455), [3fc0075](https://github.com/morluto/rea/commit/3fc007534bb2104d662b43cc712281f9d1d6a7d3), [4a076f3](https://github.com/morluto/rea/commit/4a076f368c62bdfb19415accad342e03a38d1005)). Thanks @coygeek, @Iyanuoluwa007, @jayinvers, @kaoru0822-kitauji, @kevinjosh10, @maxazure, @ShuaixinHuang.
|
||||
- **Native analysis providers:** Keep Ghidra byte matches within examined coverage, retain PE PDB/function-boundary limitations and preserve configured MIPS choices. Attached IDA refuses universal Mach-O rather than silently choosing a slice; request timeout identity and captured output survive adapter handling. ([#4531](https://github.com/morluto/rea/pull/4531), [#2933](https://github.com/morluto/rea/pull/2933), [morluto/rea#2259](https://github.com/morluto/rea/issues/2259), [01a1b3f](https://github.com/morluto/rea/commit/01a1b3fda6a7dacd24a0b10619d41d12153080d4), [50dd9fc](https://github.com/morluto/rea/commit/50dd9fcad1efb47cb404192c30bdf190dcdaca58), [#4765](https://github.com/morluto/rea/pull/4765), [morluto/rea#3871](https://github.com/morluto/rea/issues/3871), [c0cfccb](https://github.com/morluto/rea/commit/c0cfccb45fe43e7eeff18e56c64caa5b121988f9)). Thanks @BeLit-Development-2, @coygeek, @kaoru0822-kitauji, @N0zoM1z0, @ShuaixinHuang.
|
||||
- **Recorded crashes:** Prevent GDB from discovering an executable named by an untrusted core, reject core mapping paths that escape the isolated sysroot, and preserve pwntools worker ownership across launcher exec. Completed decode facts and cancellation reasons remain available through failed final cleanup. ([5bf4fff](https://github.com/morluto/rea/commit/5bf4fffc1b835130ddb16f96db9ce13b639591db), [b33c0df](https://github.com/morluto/rea/commit/b33c0df02e93fabca00a44f2de625b1a63637ee9), [#4435](https://github.com/morluto/rea/pull/4435), [morluto/rea#4011](https://github.com/morluto/rea/issues/4011)). Thanks @coygeek, @N0zoM1z0.
|
||||
- **Cutter and Rizin:** Read Cutter’s active document from core configuration and attribute its host version correctly. Keep interrupted Rizin frames and output whitespace before completion markers, with exact command and cleanup failure attribution. ([#4507](https://github.com/morluto/rea/pull/4507), [morluto/rea#4497](https://github.com/morluto/rea/issues/4497), [#4514](https://github.com/morluto/rea/pull/4514), [morluto/rea#4498](https://github.com/morluto/rea/issues/4498), [#4459](https://github.com/morluto/rea/pull/4459), [morluto/rea#4015](https://github.com/morluto/rea/issues/4015), [d5fc7e6](https://github.com/morluto/rea/commit/d5fc7e6ebf9af050081fc4c6e18b9079cfaa5cdc), [199396f](https://github.com/morluto/rea/commit/199396f61c8f61da326d059606a992304a760147)). Thanks @coygeek, @N0zoM1z0, @Xander-AJ.
|
||||
- **Windows cleanup:** Retain unpublished runtimes after failed removal, handle read-only attributes and sharing conflicts, preserve primary snapshot failures and honor caller environment overrides. ([f78d137](https://github.com/morluto/rea/commit/f78d137b42741a0ed5fb8ac161286f9a50220c4d), [d69acc3](https://github.com/morluto/rea/commit/d69acc3455c33f90a2fc4381db43d38b6af50622), [0679a79](https://github.com/morluto/rea/commit/0679a7972b4f2b02eee6a86a44f50f4c2967d3cb), [5f9ac2c](https://github.com/morluto/rea/commit/5f9ac2c98a6fe11988c41afb737df9b6d5c3a1b3), [1bbf4bd](https://github.com/morluto/rea/commit/1bbf4bd16ca134cdb2187eaf29291cae90d14a57)). Thanks @DeryFerd.
|
||||
- **Managed metadata:** Compare nominal signatures and declaring identities across builds, preserve empty names without display substitutions, verify ABI-prefixed Mach-O exports exactly, and charge cached metadata once. Metadata errors report artifact file offsets; mixed-mode assemblies retain their actual boundary classification. ([#3059](https://github.com/morluto/rea/pull/3059), [#3079](https://github.com/morluto/rea/pull/3079), [#3853](https://github.com/morluto/rea/pull/3853), [morluto/rea#3352](https://github.com/morluto/rea/issues/3352), [#3974](https://github.com/morluto/rea/pull/3974), [morluto/rea#3961](https://github.com/morluto/rea/issues/3961), [#3491](https://github.com/morluto/rea/pull/3491), [morluto/rea#3449](https://github.com/morluto/rea/issues/3449), [#4418](https://github.com/morluto/rea/pull/4418), [morluto/rea#4372](https://github.com/morluto/rea/issues/4372), [#3516](https://github.com/morluto/rea/pull/3516), [morluto/rea#3366](https://github.com/morluto/rea/issues/3366)). Thanks @8rulerstar, @coygeek, @duckhunt113, @Hahaa909, @JayOfTheKeyboard, @kaoru0822-kitauji, @keeponlight, @N0zoM1z0, @tomyrms.
|
||||
- **Archive and filesystem identity:** Reject colliding extraction paths before writing, classify ZIP offsets beyond EOF as malformed, normalize ZIP current-directory prefixes once, and preserve symlink and unreadable-path provenance. A directory named `*.map` is no longer mistaken for a source-map file. ([862a0b2](https://github.com/morluto/rea/commit/862a0b2631785492f8dc20c8acd396646c545fd1), [c209dcb](https://github.com/morluto/rea/commit/c209dcb209118069f123e789949eeba1ef78853e), [6b1c36e](https://github.com/morluto/rea/commit/6b1c36e336eeacbb7159b211e687b4b84f99b9f5), [25c2222](https://github.com/morluto/rea/commit/25c22222abe7a681491bdb4d7316250fdcf32973), [d6e4fe4](https://github.com/morluto/rea/commit/d6e4fe4a4dd8914ec3db50d2a7fc3d0802649262), [#4131](https://github.com/morluto/rea/pull/4131), [morluto/rea#3909](https://github.com/morluto/rea/issues/3909)). Thanks @Adkid-Zephyr, @coygeek, @jackie-cqz, @kaoru0822-kitauji, @maxazure, @XY-code1.
|
||||
- **Evidence and reconstruction:** Authenticate all retained inventory substeps, preserve source-attributed caveats in composed workflows, and require comparable cited Evidence before declaring reconstruction coverage or readiness. Missing Evidence and residual replay uncertainty stay explicit. ([9ac91e0](https://github.com/morluto/rea/commit/9ac91e0c1e13e91cd21341635ad5be89b0e8642d), [c4608a2](https://github.com/morluto/rea/commit/c4608a29620ea3e7bb8259b47357b942fe4e4709), [#4075](https://github.com/morluto/rea/pull/4075), [morluto/rea#3357](https://github.com/morluto/rea/issues/3357), [#3526](https://github.com/morluto/rea/pull/3526), [morluto/rea#3363](https://github.com/morluto/rea/issues/3363), [153017d](https://github.com/morluto/rea/commit/153017d750322188c1a112b2284c1b8065c67320)). Thanks @coygeek, @gensokyo-dev, @kaoru0822-kitauji, @N0zoM1z0, @rudycelekli.
|
||||
- **Offline data:** Preserve exact UTC packet-capture instants, SQLite column identity and snapshot admission failures, and cooked WASM directive literals. Cleanup cancellation retains completed EVM/WASM observations rather than losing them. ([796faa0](https://github.com/morluto/rea/commit/796faa0e4e6bf745bcdc33acef65af8ccfc3622d), [748ac7f](https://github.com/morluto/rea/commit/748ac7f0df340f0d0569eca2e803a59cd51ffdbd), [bc51d0e](https://github.com/morluto/rea/commit/bc51d0ea5df7dcee1fcc42dfae3ab0c62c9cca5e), [4f87f02](https://github.com/morluto/rea/commit/4f87f02bb19bf77349a683a5bcb2da2d1da427d0), [d694aef](https://github.com/morluto/rea/commit/d694aef227e90164e6654ea9e5ce6a854d099404), [321cacb](https://github.com/morluto/rea/commit/321cacb84a020f447e1110df5c58fa71d99b7bf1)). Thanks @himamaheswarreddy, @mertkayacs, @rollroyces, @viniciusdsandrade.
|
||||
- **Kuna recovery:** Share concurrent single-function requests and cache repeats, validate warm exports once, stream string inventories beyond the former fixed buffer ceiling, and keep unproven processes in their run slots until close confirms release. Failure messages distinguish final buffer refusals from configurable deadlines. ([#4045](https://github.com/morluto/rea/pull/4045), [#4169](https://github.com/morluto/rea/pull/4169), [#4049](https://github.com/morluto/rea/pull/4049), [#4318](https://github.com/morluto/rea/pull/4318), [#4052](https://github.com/morluto/rea/pull/4052), [#4098](https://github.com/morluto/rea/pull/4098), [#4343](https://github.com/morluto/rea/pull/4343)). Thanks @kaoru0822-kitauji.
|
||||
- **Flutter snapshots:** Check symbol-table ranges against loadable segments and retain completed inspection facts when cancellation occurs during snapshot cleanup. ([#3859](https://github.com/morluto/rea/pull/3859), [morluto/rea#3346](https://github.com/morluto/rea/issues/3346), [#4766](https://github.com/morluto/rea/pull/4766), [morluto/rea#4717](https://github.com/morluto/rea/issues/4717), [#4762](https://github.com/morluto/rea/pull/4762), [morluto/rea#4640](https://github.com/morluto/rea/issues/4640)). Thanks @coygeek, @kaoru0822-kitauji.
|
||||
- **Native metadata recovery:** Keep unknown Objective-C category classes, empty protocol names, undecoded Swift aliases and unfinished property types explicit instead of discarding neighboring valid records. Preserve unnamed segment identity and exclude a dylib’s own install name from dependencies. ([#4093](https://github.com/morluto/rea/pull/4093), [morluto/rea#4012](https://github.com/morluto/rea/issues/4012), [#4078](https://github.com/morluto/rea/pull/4078), [morluto/rea#3873](https://github.com/morluto/rea/issues/3873), [#4085](https://github.com/morluto/rea/pull/4085), [morluto/rea#3934](https://github.com/morluto/rea/issues/3934), [#3825](https://github.com/morluto/rea/pull/3825), [morluto/rea#3345](https://github.com/morluto/rea/issues/3345), [#4051](https://github.com/morluto/rea/pull/4051), [morluto/rea#3875](https://github.com/morluto/rea/issues/3875), [#4050](https://github.com/morluto/rea/pull/4050), [morluto/rea#3872](https://github.com/morluto/rea/issues/3872)). Thanks @coygeek, @kaoru0822-kitauji.
|
||||
- **Document selection:** Preserve explicitly selected plist paths and bundle defaults, and only use document fallback after confirming its applicability. Finalization keeps completed selection facts and cancellation outcomes. ([e6c4877](https://github.com/morluto/rea/commit/e6c487799bb64f559e66b69be1863e6ec5187548), [#3774](https://github.com/morluto/rea/pull/3774), [9df559b](https://github.com/morluto/rea/commit/9df559b7e712298a761ff26e9caae8d659b7e54b)). Thanks @kaoru0822-kitauji.
|
||||
- **Capture and comparison accuracy:** Admit schema-valid HAR numeric values while retaining exact-publication limits, preserve empty URL path segments, and keep unrelated process traces and unnamed reference endpoints distinct or unknown. ([#3159](https://github.com/morluto/rea/pull/3159), [morluto/rea#3145](https://github.com/morluto/rea/issues/3145), [#3792](https://github.com/morluto/rea/pull/3792), [morluto/rea#3307](https://github.com/morluto/rea/issues/3307), [#4178](https://github.com/morluto/rea/pull/4178), [morluto/rea#3931](https://github.com/morluto/rea/issues/3931), [#3809](https://github.com/morluto/rea/pull/3809), [morluto/rea#3388](https://github.com/morluto/rea/issues/3388)). Thanks @coygeek, @gensokyo-dev, @kaoru0822-kitauji, @N0zoM1z0, @pablodiazjorge, @xu91102.
|
||||
- **Evidence publication:** Recheck staged output identity after its final write, classify missing review Evidence and duplicate ledger entries as caller input, and preserve the selected freshness requirement in comparison parameters. ([#4764](https://github.com/morluto/rea/pull/4764), [morluto/rea#4613](https://github.com/morluto/rea/issues/4613), [#4452](https://github.com/morluto/rea/pull/4452), [morluto/rea#4444](https://github.com/morluto/rea/issues/4444), [#4065](https://github.com/morluto/rea/pull/4065), [morluto/rea#4000](https://github.com/morluto/rea/issues/4000)). Thanks @amyanger, @coygeek, @kaoru0822-kitauji, @Rinkia, @Swatantra-66.
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
- **Saved Evidence:** Evidence and analysis snapshots now require explicit nullable `relationship_coverage` in their identity commitments. Artifact inventories require scoped coverage and explicit `integrity_contradictions`; obsolete `coverage_status` and prose-based coverage inference are removed. Regenerate old Evidence/snapshots and inventory observations with this release: saved files are not migrated and omitted facts are not filled with guessed defaults. ([db8128d](https://github.com/morluto/rea/commit/db8128dc0d1c4f731f3d19877fa00d25cf17f657), [0405c9d](https://github.com/morluto/rea/commit/0405c9d361de6d904dfa16cc0b6d8350407f2c9b), [a9588be](https://github.com/morluto/rea/commit/a9588be4ebdd20eeda975cb63ffcdb1cd868b340)).
|
||||
- **Browser capture results:** Consumers must retain resolved capture limits, event families and omission facts. Set desired budgets through the supported capture options; omitted caller inputs still select defaults, but stored observations must report the resolved values. Admitted content reads queue behind bounded concurrency. ([57a23f0](https://github.com/morluto/rea/commit/57a23f0a2da0fdc3835e203718ded8acea5a34e6)).
|
||||
- **Android version codes:** `inspect_adb_package.version_code` is a decimal string rather than a JSON number. Read it as a string, or use `BigInt` for numeric comparison. ([#3485](https://github.com/morluto/rea/pull/3485), [morluto/rea#3368](https://github.com/morluto/rea/issues/3368), [7666a48](https://github.com/morluto/rea/commit/7666a482b69dc7cabdbac3bbaf89a43e32300192)). Thanks @coygeek, @kaoru0822-kitauji.
|
||||
- **Native UI failures:** Failed or cancelled native UI scenarios now return typed errors with the collected report in `partial_observation`. Handle the error path and read that report instead of expecting a successful result containing failed steps. ([d909919](https://github.com/morluto/rea/commit/d9099190ab3a819bd3a9fd62a8714cef398016d5)).
|
||||
- **Provider status:** `binary_session` candidate availability can be unknown during owner finalization. Preserve that state rather than treating it as unavailable; internal consumers must await the asynchronous session status API. ([150e996](https://github.com/morluto/rea/commit/150e996a86f2bec4982ba87f37bf502a8d5e8214)).
|
||||
- **Swift symbol locations:** `swift_symbols` entries may have a null `address` when the provider supplies no location. Handle unknown addresses; optional `evidence.reported_address` retains the original provider value. ([8116dc0](https://github.com/morluto/rea/commit/8116dc06512b4609d8db63cebc9f2ff8cb964151)).
|
||||
- **Linux Hopper admission:** Older builds previously admitted by a fixed allowlist need retained publisher-signed package evidence or an approved update to the current public demo. Update explicit `HOPPER_LAUNCHER_PATH` selections when migrating; the live feed offers only its current release. The official RPM metadata mismatch remains unresolved and is refused. ([#3590](https://github.com/morluto/rea/pull/3590), [morluto/rea#3577](https://github.com/morluto/rea/issues/3577), [70cd4cb](https://github.com/morluto/rea/commit/70cd4cbfb849b61f05d97d2690372a9782831426)). Thanks @gensokyo-dev, @kaoru0822-kitauji, @N0zoM1z0.
|
||||
|
||||
Full contribution record: [571 commits and 236 merged PRs](https://github.com/morluto/rea/blob/rea-agents-6.6.0/docs/releases/6.6.0.contributions.json).
|
||||
|
||||
## [6.5.0](https://github.com/morluto/rea/compare/rea-agents-6.4.0...rea-agents-6.5.0) (2026-10-13)
|
||||
|
||||
Provider prerequisites and recorded verification scope are listed in [the testing guide](docs/testing.md).
|
||||
|
||||
@@ -21,9 +21,6 @@ For analysis workflows and agent interfaces, follow the
|
||||
[performance priorities](AGENTS.md#performance). Explain the selected output
|
||||
scope, reuse/cache decisions, and relevant before/after measurements when these
|
||||
costs change.
|
||||
Use the [analysis optimization skill](.agents/skills/rea-analysis-optimization/SKILL.md)
|
||||
to locate provider and shared-workflow bottlenecks, preserve Evidence, and
|
||||
compare equivalent real tasks before claiming an improvement.
|
||||
|
||||
When adding or changing an MCP tool, follow the [tool design guide](docs/tool-design.md) and preserve the canonical contracts and generated catalog.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
**English** · [简体中文](docs/readme/README_zh.md) · [繁體中文](docs/readme/README_zh-TW.md) · [日本語](docs/readme/README_ja.md) · [한국어](docs/readme/README_ko.md) · [Türkçe](docs/readme/README_tr.md) · [Русский](docs/readme/README_ru.md) · [Tiếng Việt](docs/readme/README_vi.md) · [ไทย](docs/readme/README_th.md) · [Deutsch](docs/readme/README_de.md) · [Español](docs/readme/README_es.md) · [Français](docs/readme/README_fr.md) · [Українська](docs/readme/README_uk.md) · [Polski](docs/readme/README_pl.md) · [Português (Brasil)](docs/readme/README_pt-BR.md) · [العربية](docs/readme/README_ar.md) · [فارسی](docs/readme/README_fa.md) · [Bahasa Indonesia](docs/readme/README_id.md) · [Italiano](docs/readme/README_it.md)
|
||||
· [Ελληνικά](docs/readme/README_el.md) · [മലയാളം](docs/readme/README_ml.md)
|
||||
· [Ελληνικά](docs/readme/README_el.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -132,14 +132,6 @@ For a CLI installed with `npm install --global` or `bun add --global`:
|
||||
rea update
|
||||
```
|
||||
|
||||
`rea --update` is an alias for this verified workflow and accepts the same global
|
||||
output flags. Use `rea update` when combining it with other command controls.
|
||||
|
||||
Updater commands retain at most 4 MiB of stdout and stderr combined. Oversized
|
||||
metadata replies are rejected after the command exits; verbose installs continue
|
||||
with bounded diagnostics. Human progress output respects terminal backpressure
|
||||
and waits for submitted writes to finish.
|
||||
|
||||
Bun global updates require Bun 1.2.17 or later. With an older Bun release,
|
||||
upgrade Bun manually before running `rea update`.
|
||||
|
||||
@@ -353,7 +345,7 @@ Report vulnerabilities through [SECURITY.md](SECURITY.md).
|
||||
|
||||
## Star history
|
||||
|
||||
🎉 **300,000 GitHub stars — thank you!**
|
||||
🎉 **250,000 GitHub stars — thank you!**
|
||||
|
||||
Thanks to everyone using REA, reporting bugs, requesting features, testing builds, and contributing fixes.
|
||||
|
||||
|
||||
@@ -15,14 +15,11 @@ import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.stream.Collectors;
|
||||
import kotlin.Unit;
|
||||
import kotlin.ResultKt;
|
||||
import kotlin.coroutines.Continuation;
|
||||
import kotlin.coroutines.CoroutineContext;
|
||||
import kotlin.coroutines.EmptyCoroutineContext;
|
||||
import kotlin.coroutines.intrinsics.IntrinsicsKt;
|
||||
import kotlinx.coroutines.BuildersKt;
|
||||
import kotlinx.io.CoreKt;
|
||||
import kotlinx.io.JvmCoreKt;
|
||||
import kotlinx.serialization.json.JsonObject;
|
||||
|
||||
/** REA-owned metadata boundary for the unmodified jadx-headless-mcp 0.7.1 JAR. */
|
||||
class ReaJadxBridge {
|
||||
@@ -31,8 +28,7 @@ class ReaJadxBridge {
|
||||
private JadxSession indexedSession;
|
||||
private Map<String, List<ClassSnapshot>> classes = Map.of();
|
||||
|
||||
private record MethodSnapshot(String name, String rawName, String shortId, List<String> bodyAbsenceMarkers,
|
||||
Map<String, Object> summary) {}
|
||||
private record MethodSnapshot(String name, String shortId, Map<String, Object> summary) {}
|
||||
private record ClassSnapshot(JavaClass node, List<MethodSnapshot> methods, Map<String, Object> summary) {}
|
||||
|
||||
private static final class InputFailure extends IllegalArgumentException {
|
||||
@@ -48,93 +44,15 @@ class ReaJadxBridge {
|
||||
|
||||
private static CallToolResult json(Object value) { return text(JSON.toJson(value), false); }
|
||||
|
||||
/** Translate the typed load outcome before upstream drops its exception identity. */
|
||||
static Object loadResult(Object result) {
|
||||
try { ResultKt.throwOnFailure(result); }
|
||||
catch (Throwable failure) {
|
||||
if (failure instanceof java.util.concurrent.CancellationException
|
||||
|| failure instanceof Error && !(failure instanceof OutOfMemoryError)) return result;
|
||||
if (failure instanceof OutOfMemoryError) {
|
||||
String reason = failure.getMessage();
|
||||
boolean heap = "Java heap space".equals(reason) || "GC overhead limit exceeded".equals(reason);
|
||||
Map<String, Object> reply = new LinkedHashMap<>();
|
||||
reply.put("kind", "jvm-memory-failure");
|
||||
reply.put("memory_area", heap ? "heap" : "unknown");
|
||||
reply.put("exception_type", "java.lang.OutOfMemoryError");
|
||||
if (reason != null) reply.put("message", reason);
|
||||
reply.put("max_heap_bytes", Runtime.getRuntime().maxMemory());
|
||||
return text(JSON.toJson(reply), true);
|
||||
}
|
||||
return text("load failed: " + failure.getMessage(), true);
|
||||
}
|
||||
SessionHolder.LoadResult loaded = (SessionHolder.LoadResult) result;
|
||||
Map<String, Object> reply = new LinkedHashMap<>();
|
||||
reply.put("state", "LOADED");
|
||||
reply.put("apk_path", loaded.getApkPath());
|
||||
reply.put("class_count", loaded.getClassCount());
|
||||
reply.put("raw_class_count", loaded.getRawClassCount());
|
||||
reply.put("resource_count", loaded.getResourceCount());
|
||||
reply.put("load_duration_ms", loaded.getLoadDurationMs());
|
||||
reply.put("decompile_timeout_ms", loaded.getDecompileTimeoutMs());
|
||||
reply.put("threads", loaded.getThreads());
|
||||
reply.put("code_cache_size", loaded.getCodeCacheSize());
|
||||
reply.put("resources", loaded.getResourceMode());
|
||||
if (!loaded.getIncludePackages().isEmpty()) reply.put("include_packages", loaded.getIncludePackages());
|
||||
if (!loaded.getExcludePackages().isEmpty()) reply.put("exclude_packages", loaded.getExcludePackages());
|
||||
return json(reply);
|
||||
}
|
||||
|
||||
private Object load(kotlinx.serialization.json.JsonObject arguments, SessionConfig defaults,
|
||||
Continuation<? super CallToolResult> continuation) {
|
||||
JsonObject args = JsonParser.parseString(arguments.toString()).getAsJsonObject();
|
||||
String path = string(args, "path");
|
||||
SessionConfig options = defaults.withLoadOverrides(
|
||||
optionalString(args, "include_packages"), optionalString(args, "exclude_packages"),
|
||||
args.has("threads") ? integer(args, "threads", 1) : null,
|
||||
args.has("code_cache_size") ? integer(args, "code_cache_size", 64) : null,
|
||||
optionalString(args, "resources"));
|
||||
return loadCall(next -> holder.load(path, options, next), continuation);
|
||||
}
|
||||
|
||||
static Object loadCall(kotlin.jvm.functions.Function1<Continuation<SessionHolder.LoadResult>, Object> load,
|
||||
Continuation<? super CallToolResult> continuation) {
|
||||
var forwarded = new java.util.concurrent.atomic.AtomicBoolean();
|
||||
Continuation<SessionHolder.LoadResult> resumed = new Continuation<>() {
|
||||
public CoroutineContext getContext() { return continuation.getContext(); }
|
||||
public void resumeWith(Object result) {
|
||||
if (!forwarded.compareAndSet(false, true)) throw new IllegalStateException("Load resumed twice");
|
||||
Object translated;
|
||||
try { translated = loadResult(result); }
|
||||
catch (Throwable failure) { translated = ResultKt.createFailure(failure); }
|
||||
// Keep the consumer outside the translation catch, including inline completion.
|
||||
continuation.resumeWith(translated);
|
||||
}
|
||||
};
|
||||
Object result;
|
||||
try { result = load.invoke(resumed); }
|
||||
catch (Throwable failure) {
|
||||
if (forwarded.get()) ResultKt.throwOnFailure(ResultKt.createFailure(failure));
|
||||
result = ResultKt.createFailure(failure);
|
||||
}
|
||||
if (result == IntrinsicsKt.getCOROUTINE_SUSPENDED()) return result;
|
||||
Object translated = loadResult(result);
|
||||
ResultKt.throwOnFailure(translated);
|
||||
return translated;
|
||||
}
|
||||
|
||||
private static String optionalString(JsonObject args, String name) {
|
||||
return args.has(name) ? string(args, name) : null;
|
||||
}
|
||||
|
||||
private static String string(JsonObject args, String name) {
|
||||
JsonElement value = args.get(name);
|
||||
JsonElement value = JsonParser.parseString(args.toString()).getAsJsonObject().get(name);
|
||||
if (value == null || !value.isJsonPrimitive() || !value.getAsJsonPrimitive().isString())
|
||||
throw new IllegalArgumentException(name + " must be a string");
|
||||
return value.getAsString();
|
||||
}
|
||||
|
||||
private static int integer(JsonObject args, String name, int fallback) {
|
||||
JsonElement value = args.get(name);
|
||||
JsonElement value = JsonParser.parseString(args.toString()).getAsJsonObject().get(name);
|
||||
if (value == null) return fallback;
|
||||
if (!value.isJsonPrimitive() || !value.getAsJsonPrimitive().isNumber())
|
||||
throw new IllegalArgumentException(name + " must be a nonnegative integer");
|
||||
@@ -172,13 +90,10 @@ class ReaJadxBridge {
|
||||
if (!shortId.startsWith(rawName + "("))
|
||||
throw new IllegalStateException("JADX method ID has no raw-name prefix: " + shortId);
|
||||
String descriptor = shortId.substring(rawName.length());
|
||||
List<String> bodyAbsenceMarkers = new ArrayList<>();
|
||||
if (method.getAccessFlags().isNative()) bodyAbsenceMarkers.add("native_method");
|
||||
if (method.getAccessFlags().isAbstract()) bodyAbsenceMarkers.add("abstract_method");
|
||||
String signature = name + "(" + method.getArgTypes().stream()
|
||||
.map(Object::toString).collect(Collectors.joining(", "))
|
||||
+ "): " + method.getReturnType().toString();
|
||||
return new MethodSnapshot(name, rawName, shortId, List.copyOf(bodyAbsenceMarkers), Map.of(
|
||||
return new MethodSnapshot(name, shortId, Map.of(
|
||||
"name", name, "signature", signature,
|
||||
"dex_descriptor", descriptor,
|
||||
"is_constructor", method.isConstructor(), "def_pos", 0));
|
||||
@@ -225,52 +140,16 @@ class ReaJadxBridge {
|
||||
|
||||
private JadxSession.SmartCode methodBody(JadxSession current, ClassSnapshot cls,
|
||||
MethodSnapshot selected, JavaMethod method) {
|
||||
// Access flags belong to the parsed member, before code generation rewrites it.
|
||||
// These methods have no Java body; source slicing can include unrelated members.
|
||||
if (!selected.bodyAbsenceMarkers().isEmpty())
|
||||
return new JadxSession.SmartCode("", "java", false, selected.bodyAbsenceMarkers());
|
||||
if (!selected.shortId().equals("<clinit>()V"))
|
||||
return current.getMethodBodySmart(method, current.getMaxSourceBytes(), true);
|
||||
// Java code generation can fold all or part of <clinit> into field declarations.
|
||||
// Its method text cannot establish coverage, even when a static block remains.
|
||||
if (selected.shortId().equals("<clinit>()V"))
|
||||
return exactMethodSmali(current, cls, selected, List.of("static_initializer_disassembly"));
|
||||
String java = current.getMethodSource(method);
|
||||
if (java.startsWith("// ERROR:")) throw new IllegalArgumentException(java);
|
||||
// The upstream placeholder means only that Java code was omitted, including
|
||||
// methods merged into synthetic bridges. Access flags established absence above.
|
||||
if (java.isEmpty() || java.equals(
|
||||
"// method exists but has no decompiled body (native/abstract)"))
|
||||
return exactMethodSmali(current, cls, selected, List.of("java_body_unavailable"));
|
||||
List<String> markers = DecompileFailureKt.detectDecompileFailure(java);
|
||||
if (markers.stream().anyMatch(DecompileFailureKt.getSTRONG_FAILURE_MARKERS()::contains))
|
||||
return exactMethodSmali(current, cls, selected, markers);
|
||||
JadxSession.MethodSmali smali = current.getMethodSmali(cls.node(), method.getName());
|
||||
if (!smali.getFound() || smali.getBlocks().size() != 1)
|
||||
throw new IllegalArgumentException("Static initializer disassembly requires one exact method: " + selected.shortId());
|
||||
return new JadxSession.SmartCode(
|
||||
TextUtilKt.truncateToBytes(java, current.getMaxSourceBytes()), "java", false, markers);
|
||||
}
|
||||
|
||||
private JadxSession.SmartCode exactMethodSmali(JadxSession current, ClassSnapshot cls,
|
||||
MethodSnapshot selected, List<String> markers) {
|
||||
JadxSession.MethodSmali smali = current.getMethodSmali(cls.node(), selected.rawName());
|
||||
String block = selectMethodSmali(smali, selected.shortId());
|
||||
return new JadxSession.SmartCode(
|
||||
TextUtilKt.truncateToBytes(block, current.getMaxSourceBytes()), "smali", true, markers);
|
||||
}
|
||||
|
||||
private static String selectMethodSmali(JadxSession.MethodSmali smali, String shortId) {
|
||||
if (!smali.getFound())
|
||||
throw new IllegalArgumentException("JADX could not disassemble " + shortId
|
||||
+ (smali.getNote() == null ? "" : ": " + smali.getNote()));
|
||||
// Upstream returns every same-name overload, and can return an unterminated
|
||||
// trailing block. Match the full original identity before applying output limits.
|
||||
List<String> matches = smali.getBlocks().stream().filter(block -> {
|
||||
String header = block.lines().findFirst().orElse("").strip();
|
||||
return header.startsWith(".method ") && header.endsWith(" " + shortId);
|
||||
}).toList();
|
||||
if (matches.size() != 1)
|
||||
throw new IllegalArgumentException("Disassembly could not establish one selected method: " + shortId);
|
||||
String block = matches.get(0);
|
||||
if (!block.stripTrailing().endsWith("\n.end method"))
|
||||
throw new IllegalArgumentException("Selected method disassembly is incomplete: " + shortId);
|
||||
return block;
|
||||
TextUtilKt.truncateToBytes(smali.getBlocks().get(0), current.getMaxSourceBytes()),
|
||||
"smali", true, List.of("static_initializer_disassembly"));
|
||||
}
|
||||
|
||||
// The local transport admits 8 MiB frames. Reserve 1 KiB for the fixed
|
||||
@@ -324,8 +203,7 @@ class ReaJadxBridge {
|
||||
return new DirectInvokes(sites, exhaustive[0]);
|
||||
}
|
||||
|
||||
private CallToolResult handle(String name, kotlinx.serialization.json.JsonObject input) {
|
||||
JsonObject args = JsonParser.parseString(input.toString()).getAsJsonObject();
|
||||
private CallToolResult handle(String name, JsonObject args) {
|
||||
if (name.equals("rea_jvm_status")) return json(Map.of(
|
||||
"engine_reported_version", BuildInfo.VERSION,
|
||||
"max_heap_bytes", Runtime.getRuntime().maxMemory(),
|
||||
@@ -335,25 +213,12 @@ class ReaJadxBridge {
|
||||
JadxSession current = session();
|
||||
if (name.equals("list_classes")) {
|
||||
List<String> names = current.getClassFqns();
|
||||
String query = args.has("query") ? string(args, "query") : "";
|
||||
int offset = integer(args, "offset", 0);
|
||||
int limit = integer(args, "limit", 200);
|
||||
int start = Math.min(offset, names.size());
|
||||
int end = start;
|
||||
List<String> items;
|
||||
if (query.isEmpty()) {
|
||||
end = (int) Math.min((long) start + limit, names.size());
|
||||
items = names.subList(start, end);
|
||||
} else {
|
||||
items = new ArrayList<>();
|
||||
while (end < names.size() && items.size() < limit) {
|
||||
String nameInInventory = names.get(end++);
|
||||
if (nameInInventory.contains(query)) items.add(nameInInventory);
|
||||
}
|
||||
}
|
||||
return json(Map.of("total_classes", names.size(), "next_offset", end,
|
||||
"scope", "top_level", "offset", offset, "limit", limit,
|
||||
"items", items));
|
||||
int end = (int) Math.min((long) start + limit, names.size());
|
||||
return json(Map.of("total", names.size(), "offset", offset, "limit", limit,
|
||||
"items", names.subList(start, end)));
|
||||
}
|
||||
ClassSnapshot cls = selected(args);
|
||||
if (name.equals("get_class_summary")) return json(cls.summary());
|
||||
@@ -365,7 +230,6 @@ class ReaJadxBridge {
|
||||
JadxSession.SmartCode code = methodBody(current, cls, overloads.get(index), method);
|
||||
return json(Map.of("class_name", cls.summary().get("full_name"),
|
||||
"method_name", overloads.get(index).name(), "full_name", method.getFullName(),
|
||||
"dex_descriptor", overloads.get(index).summary().get("dex_descriptor"),
|
||||
"overload_index", index, "overload_count", overloads.size(),
|
||||
"mode", code.getKind(), "fell_back", code.getFellBack(),
|
||||
"markers", code.getMarkers(), "body", code.getText()));
|
||||
@@ -377,7 +241,7 @@ class ReaJadxBridge {
|
||||
if (name.equals("get_xrefs_to_class")) uses = cls.node().getUseIn();
|
||||
else {
|
||||
List<MethodSnapshot> overloads = methods(cls, args);
|
||||
if (overloads.size() != 1 && !args.has("overload_index"))
|
||||
if (overloads.size() != 1 && !args.containsKey("overload_index"))
|
||||
throw new InputFailure("overload_index", "Select one of " + overloads.size() + " method overloads");
|
||||
overloadIndex = integer(args, "overload_index", 0);
|
||||
if (overloadIndex >= overloads.size())
|
||||
@@ -423,12 +287,11 @@ class ReaJadxBridge {
|
||||
public static void main(String[] args) throws Exception {
|
||||
PrintStream protocolOut = System.out;
|
||||
System.setOut(System.err);
|
||||
SessionConfig defaults = new SessionConfig(
|
||||
1048576, 0, 90000L, 1, List.of(), List.of(), 64, ResourceMode.FULL);
|
||||
SessionHolder holder = new SessionHolder(defaults);
|
||||
SessionHolder holder = new SessionHolder(new SessionConfig(
|
||||
1048576, 0, 90000L, 1, List.of(), List.of(), 64, ResourceMode.FULL));
|
||||
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", "4", null, null, null),
|
||||
Server server = new Server(new Implementation("rea-jadx-bridge", "1", null, null, null),
|
||||
new ServerOptions(capabilities), "", ignored -> Unit.INSTANCE);
|
||||
SessionToolsKt.registerSessionTools(server, holder);
|
||||
ManifestToolsKt.registerManifestTools(server, holder);
|
||||
@@ -436,17 +299,13 @@ class ReaJadxBridge {
|
||||
MethodToolsKt.registerMethodTools(server, holder);
|
||||
XrefToolsKt.registerXrefTools(server, holder);
|
||||
ReaJadxBridge bridge = new ReaJadxBridge(holder);
|
||||
Tool loadTool = server.getTools().get("load_apk").getTool();
|
||||
server.removeTool("load_apk");
|
||||
server.addTool(loadTool, (connection, request, continuation) ->
|
||||
bridge.load(request.getArguments(), defaults, continuation));
|
||||
Set<String> consumed = Set.of("load_apk", "get_app_info", "get_android_manifest",
|
||||
"list_classes", "get_class_summary", "get_method_body",
|
||||
"get_xrefs_to_class", "get_xrefs_to_method");
|
||||
for (String name : new ArrayList<>(server.getTools().keySet()))
|
||||
if (!consumed.contains(name)) server.removeTool(name);
|
||||
Tool diagnostics = new Tool("rea_jvm_status",
|
||||
new ToolSchema(null, new kotlinx.serialization.json.JsonObject(Map.of()), List.of(), null),
|
||||
new ToolSchema(null, new 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()));
|
||||
for (String name : List.of("list_classes", "get_class_summary",
|
||||
@@ -461,16 +320,13 @@ class ReaJadxBridge {
|
||||
};
|
||||
Map<String, kotlinx.serialization.json.JsonElement> properties = new LinkedHashMap<>();
|
||||
for (String field : fields) properties.put(field, tool.getInputSchema().getProperties().get(field));
|
||||
if (name.equals("list_classes")) properties.put("query",
|
||||
new kotlinx.serialization.json.JsonObject(Map.of(
|
||||
"type", kotlinx.serialization.json.JsonElementKt.JsonPrimitive("string"))));
|
||||
String description = switch (name) {
|
||||
case "list_classes" -> "Pages of case-sensitive matching top-level class names; offset and next_offset are inventory positions, limit bounds matching rows. Omitted or empty query inventories all names.";
|
||||
case "list_classes" -> "Indexed pages of all top-level class names, with offset and limit.";
|
||||
case "get_class_summary" -> "Parsed member metadata for one exact class name; no source generation.";
|
||||
case "get_method_body" -> "Source for an exact class and stable same-name overload index; static initializers use smali to preserve folded field initialization.";
|
||||
default -> "Complete static using-node inventory for an exact class or selected method overload; one node may contain multiple invoke instructions, and source lines are unresolved.";
|
||||
};
|
||||
Tool narrowed = new Tool(name, new ToolSchema(null, new kotlinx.serialization.json.JsonObject(properties),
|
||||
Tool narrowed = new Tool(name, new ToolSchema(null, new JsonObject(properties),
|
||||
tool.getInputSchema().getRequired(), null), description, null, null, null, null, null, null);
|
||||
server.addTool(narrowed, (connection, request, continuation) -> {
|
||||
try { return bridge.handle(name, request.getArguments()); }
|
||||
|
||||
@@ -783,22 +783,14 @@ def _within_response_limit(value: Any) -> bool:
|
||||
current = pending.pop()
|
||||
if isinstance(current, str):
|
||||
size += 2
|
||||
if len(current) > MAX_FRAME_BYTES - size:
|
||||
return False
|
||||
if current.isascii():
|
||||
size += len(current)
|
||||
size += current.count('"') + current.count("\\")
|
||||
size += sum(5 for character in current if ord(character) < 0x20)
|
||||
else:
|
||||
# Count UTF-8 bytes without allocating a copy of the whole output.
|
||||
try:
|
||||
size += sum(
|
||||
len(current[start:start + 65536].encode("utf-8"))
|
||||
for start in range(0, len(current), 65536)
|
||||
)
|
||||
except UnicodeEncodeError:
|
||||
# Unencodable output also needs the signed omission fallback.
|
||||
return False
|
||||
size += current.count('"') + current.count("\\")
|
||||
size += sum(5 for character in current if ord(character) < 0x20)
|
||||
size += 4 * len(current)
|
||||
size += current.count('"') + current.count("\\")
|
||||
size += sum(5 for character in current if ord(character) < 0x20)
|
||||
elif isinstance(current, dict):
|
||||
identity = id(current)
|
||||
if identity in seen:
|
||||
|
||||
@@ -140,7 +140,6 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
"params"
|
||||
);
|
||||
private static final String[] CAPABILITIES = {
|
||||
"read_binary_inventory_summary",
|
||||
"annotate_native_function",
|
||||
"set_address_name",
|
||||
"set_addresses_names",
|
||||
@@ -428,7 +427,6 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
);
|
||||
}
|
||||
return switch (request.method) {
|
||||
case "read_binary_inventory_summary" -> binaryInventorySummary(request.params);
|
||||
case "inspect_native_load_image" -> inspectNativeLoadImage(request.params);
|
||||
case "read_bytes" -> readMemoryBytes(request.params);
|
||||
case "search_bytes" -> searchMemoryBytes(request.params, descriptor);
|
||||
@@ -1976,18 +1974,6 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
return result;
|
||||
}
|
||||
|
||||
private JsonObject binaryInventorySummary(JsonObject params) throws Exception {
|
||||
requireKeys(params, Set.of());
|
||||
JsonObject result = new JsonObject();
|
||||
result.addProperty("document", currentProgram.getName());
|
||||
result.add("segments", segments());
|
||||
// Count the owning inventories, preserving their exact discovery rules
|
||||
// without serializing function identities or string values for counts.
|
||||
result.addProperty("procedure_count", procedures().size());
|
||||
result.addProperty("string_count", strings().size());
|
||||
return result;
|
||||
}
|
||||
|
||||
private JsonArray listNames(JsonObject params) throws Exception {
|
||||
requireKeys(params, Set.of("document", "address"));
|
||||
requireDocument(params);
|
||||
@@ -2014,10 +2000,6 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
private JsonArray listSegments(JsonObject params) {
|
||||
requireKeys(params, Set.of("document"));
|
||||
requireDocument(params);
|
||||
return segments();
|
||||
}
|
||||
|
||||
private JsonArray segments() {
|
||||
JsonArray result = new JsonArray();
|
||||
String imageBase = canonicalAddress(currentProgram.getImageBase());
|
||||
MemoryBlock[] blocks = currentProgram.getMemory().getBlocks();
|
||||
|
||||
@@ -20,9 +20,8 @@ def inspect(request):
|
||||
root = Path(os.environ["REA_CORE_CONTEXT_REQUEST"]).parent
|
||||
empty = root / "no-libraries"
|
||||
empty.mkdir(mode=0o700)
|
||||
for command in ["set auto-load off", "set debuginfod enabled off", "set auto-solib-add off", "set history save off", "set pagination off", "set target-file-system-kind unix",
|
||||
"set sysroot ./no-libraries", "set solib-search-path ./no-libraries",
|
||||
"set debug-file-directory ./no-libraries"]:
|
||||
for command in ["set auto-load off", "set debuginfod enabled off", "set auto-solib-add off", "set history save off", "set pagination off",
|
||||
"set sysroot ./no-libraries", "set solib-search-path ./no-libraries"]:
|
||||
gdb.execute(command, to_string=True)
|
||||
entry = request["gdbinit"]
|
||||
try:
|
||||
@@ -39,19 +38,7 @@ def inspect(request):
|
||||
# relative filename in the owned cwd so no selected path becomes GDB syntax.
|
||||
if Path(request["snapshot_path"]) != root.parent / "object.snapshot":
|
||||
raise ContextFailure("decoder", "Core context request did not select the shared owned snapshot.")
|
||||
# GDB 16 searches AT_EXECFN/NT_FILE outside sysroot when no executable BFD
|
||||
# is selected. Occupy that slot with the already running, owned debugger;
|
||||
# exec-file loads no symbols and never runs it. Clear it before any query.
|
||||
# /proc/self/exe identifies this process, not the core's historical PID.
|
||||
architecture = {"x86_64-little-endian": "i386:x86-64", "aarch64-little-endian": "aarch64"}.get(request["architecture"])
|
||||
if architecture is None:
|
||||
raise ContextFailure("unsupported", "Unsupported recorded core architecture.")
|
||||
gdb.execute("exec-file /proc/self/exe", to_string=True)
|
||||
# The placeholder must not select the core's architecture. Reuse the
|
||||
# decoder's validated profile, including for cross-architecture GDB builds.
|
||||
gdb.execute("set architecture " + architecture, to_string=True)
|
||||
gdb.execute("core-file ../object.snapshot", to_string=True)
|
||||
gdb.execute("file", to_string=True)
|
||||
inferior = gdb.selected_inferior()
|
||||
if inferior.connection is None or inferior.connection.type != "core" or gdb.current_progspace().filename is not None:
|
||||
raise ContextFailure("decoder", "Requested core-only boundary was not established; no mapping query performed.")
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
"""Producer regressions with controlled GDB state, not native debugger qualification."""
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import runpy
|
||||
import sys
|
||||
import tempfile
|
||||
import types
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
BRIDGE = Path(__file__).with_name("core_context.py")
|
||||
|
||||
|
||||
class CoreContextTests(unittest.TestCase):
|
||||
def inspect(self, failure=None, connection="core", symbols=None, architecture="x86_64-little-endian"):
|
||||
commands, reads, queries = [], [], []
|
||||
state = {"executable": None, "symbols": None, "connection": None}
|
||||
gdb = types.ModuleType("gdb")
|
||||
gdb.VERSION = "16.3"
|
||||
gdb.selected_inferior = lambda: types.SimpleNamespace(
|
||||
connection=state["connection"], pid=123)
|
||||
gdb.current_progspace = lambda: types.SimpleNamespace(filename=state["symbols"])
|
||||
|
||||
def execute(command, to_string):
|
||||
self.assertTrue(to_string)
|
||||
commands.append(command)
|
||||
if command == failure:
|
||||
raise RuntimeError("controlled command failure")
|
||||
if command == "exec-file /proc/self/exe":
|
||||
state["executable"] = "/proc/self/exe"
|
||||
elif command == "core-file ../object.snapshot":
|
||||
if state["executable"] is None:
|
||||
reads.append("recorded-executable")
|
||||
state["executable"] = state["symbols"] = "recorded-executable"
|
||||
state["connection"] = types.SimpleNamespace(type=connection)
|
||||
elif command == "file":
|
||||
state["executable"] = None
|
||||
state["symbols"] = symbols
|
||||
|
||||
gdb.execute = execute
|
||||
pwndbg = types.ModuleType("pwndbg")
|
||||
pwndbg.aglib = types.ModuleType("pwndbg.aglib")
|
||||
pwndbg.aglib.vmmap = types.ModuleType("pwndbg.aglib.vmmap")
|
||||
pwndbg.lib = types.ModuleType("pwndbg.lib")
|
||||
pwndbg.lib.version = types.ModuleType("pwndbg.lib.version")
|
||||
pwndbg.lib.version.__version__ = "2026.09.15"
|
||||
|
||||
def maps():
|
||||
self.assertIsNone(state["executable"], "Helper executable must be discarded before mapping queries")
|
||||
queries.append("maps")
|
||||
return [types.SimpleNamespace(start=4096, end=8192, offset=0, flags=5, objfile="recorded-executable")]
|
||||
|
||||
pwndbg.aglib.vmmap.get = maps
|
||||
modules = {module.__name__: module for module in [
|
||||
gdb, pwndbg, pwndbg.aglib, pwndbg.aglib.vmmap, pwndbg.lib, pwndbg.lib.version]}
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
stage = root / "debugger"
|
||||
stage.mkdir()
|
||||
plugin = root / "gdbinit.py"
|
||||
plugin.write_text("")
|
||||
request = stage / "request.json"
|
||||
reply = stage / "reply.json"
|
||||
request.write_text(json.dumps({"gdbinit": str(plugin), "architecture": architecture, "snapshot_path": str(root / "object.snapshot"), "reply_path": str(reply)}))
|
||||
with patch.dict(sys.modules, modules), patch.dict(os.environ, REA_CORE_CONTEXT_REQUEST=str(request)):
|
||||
runpy.run_path(str(BRIDGE))
|
||||
result = json.loads(reply.read_text())
|
||||
return result, commands, reads, queries
|
||||
|
||||
def test_core_load_never_opens_recorded_executable_and_queries_only_after_discard(self):
|
||||
result, commands, reads, queries = self.inspect()
|
||||
self.assertTrue(result["ok"], result)
|
||||
self.assertEqual(reads, [])
|
||||
self.assertEqual(queries, ["maps"])
|
||||
self.assertEqual(commands[-4:], ["exec-file /proc/self/exe", "set architecture i386:x86-64", "core-file ../object.snapshot", "file"])
|
||||
self.assertLess(commands.index("set debug-file-directory ./no-libraries"), commands.index("core-file ../object.snapshot"))
|
||||
self.assertIsNone(result["value"]["executable"])
|
||||
self.assertEqual(result["value"]["maps"][0]["current_file_identity"], "unknown")
|
||||
|
||||
def test_failed_guard_core_load_or_discard_never_queries_mappings(self):
|
||||
for command in ["exec-file /proc/self/exe", "set architecture i386:x86-64", "core-file ../object.snapshot", "file"]:
|
||||
with self.subTest(command=command):
|
||||
result, commands, reads, queries = self.inspect(failure=command)
|
||||
self.assertFalse(result["ok"])
|
||||
self.assertEqual(reads, [])
|
||||
self.assertEqual(queries, [])
|
||||
if command in ["exec-file /proc/self/exe", "set architecture i386:x86-64"]:
|
||||
self.assertNotIn("core-file ../object.snapshot", commands)
|
||||
|
||||
def test_cross_architecture_uses_the_validated_decoder_profile(self):
|
||||
result, commands, reads, queries = self.inspect(architecture="aarch64-little-endian")
|
||||
self.assertTrue(result["ok"], result)
|
||||
self.assertEqual(reads, [])
|
||||
self.assertEqual(queries, ["maps"])
|
||||
self.assertLess(commands.index("set architecture aarch64"), commands.index("core-file ../object.snapshot"))
|
||||
|
||||
def test_unknown_architecture_refuses_before_loading_core(self):
|
||||
result, commands, reads, queries = self.inspect(architecture="unknown")
|
||||
self.assertFalse(result["ok"])
|
||||
self.assertEqual(result["reason"], "unsupported")
|
||||
self.assertNotIn("core-file ../object.snapshot", commands)
|
||||
self.assertEqual(reads, [])
|
||||
self.assertEqual(queries, [])
|
||||
|
||||
def test_wrong_connection_or_remaining_symbols_never_queries_mappings(self):
|
||||
for options in [{"connection": "native"}, {"symbols": "unexpected-symbols"}]:
|
||||
with self.subTest(options=options):
|
||||
result, _, reads, queries = self.inspect(**options)
|
||||
self.assertFalse(result["ok"])
|
||||
self.assertEqual(reads, [])
|
||||
self.assertEqual(queries, [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -98,24 +98,16 @@ existing analysis families directly, for example
|
||||
| `collect_adb_bugreport` | read | Device-generated bugreport zip, digested |
|
||||
| `push_adb_file` | **mutates device** | One local file to a device path (e.g. pushing tools into `/data/local/tmp`); checks for existing targets and refuses them without explicit overwrite (the check is not atomic); compares digests when device `sha256sum` is available |
|
||||
| `install_adb_package` | **mutates device** | Local APK via `adb install [-r]`; preserves its Success/Failure verdict, records `replace_requested`, and leaves actual replacement `null` because prior package state is not observed |
|
||||
| `uninstall_adb_package` | **mutates device** | Requests package removal for user 0 via `adb shell pm uninstall --user 0`, without data retention |
|
||||
| `uninstall_adb_package` | **mutates device** | Removes a package and its data for user 0 |
|
||||
| `start_adb_app` | **mutates device** | Resolves the package's launcher activity (`cmd package resolve-activity --brief`) and starts it (`am start -n`) |
|
||||
| `start_adb_activity` | **mutates device** | Starts an intent (`am start -a` with optional URI, component, and up to 16 typed extras); preserves the activity manager's verdict |
|
||||
| `stop_adb_app` | **mutates device** | Force-stops every process of a package, ending a dynamic-analysis run |
|
||||
|
||||
For `inspect_adb_window`, `focus_contexts` retains each display header, its exact
|
||||
display ID when recognized, and every focus declaration with its original line.
|
||||
Declarations without a display header are explicitly `unscoped`. A missing
|
||||
declaration differs from a declaration whose `value` is JSON `null`.
|
||||
`source_section` identifies the selected dumpsys section; `observed_lines`
|
||||
preserves its focus declarations and display headers in source order.
|
||||
|
||||
`focus_summary` is `single_context` only for one context with no repeated focus
|
||||
field. The singular `focused_window` and `focused_app` summarize that context;
|
||||
they do not establish device-wide focus. Multiple contexts or repeated fields
|
||||
produce `ambiguous` with null singular fields and all declarations retained.
|
||||
When no focus field was declared, the status is `unavailable`. REA reads the
|
||||
displays section only when the windows section declares neither focus field.
|
||||
For `inspect_adb_window`, an explicitly printed null focus reference becomes
|
||||
JSON `null`. `observed_lines` retains the original focus declarations, including
|
||||
their field names, so explicit absence can be distinguished from omitted
|
||||
declarations. REA reads the displays section only when the windows section
|
||||
declares neither focus field. If both sections omit them, focus remains unknown.
|
||||
|
||||
For `install_adb_package`, `replace_requested` records whether `-r` was sent.
|
||||
The `replaced` result is `null`: the successful install response does not say
|
||||
|
||||
+11
-37
@@ -103,10 +103,9 @@ that every class or engine operation will load successfully. Discovery limits
|
||||
each ZIP metadata read to 8 MiB before allocation; a larger directory reports
|
||||
the exhausted read budget and the selected JAR path.
|
||||
|
||||
The filtered class-page bridge (protocol 2) is verified on Linux x86-64 with
|
||||
Temurin 21, public Appium ApiDemos 6.0.18 and NewPipe 0.29.1 APKs. Earlier
|
||||
metadata-bridge records covered macOS arm64/OpenJDK 21 and Windows x64/JDK 21;
|
||||
this protocol revision has not been rerun on those hosts or Linux/JDK 25.
|
||||
The current metadata bridge is verified on macOS arm64 with OpenJDK 21 and the
|
||||
public Appium ApiDemos fixture. The POSIX adapter also supports Linux; the new
|
||||
bridge has not yet undergone real verification on Linux/JDK 25.
|
||||
Windows x64 uses an owned Job Object with bidirectional stdio, atomic job
|
||||
assignment and kill-on-owner-close. Real Windows verification uses JDK 21 and
|
||||
the pinned JADX 0.7.1 JAR; see the real verification lane below.
|
||||
@@ -147,20 +146,10 @@ queries accept the same `overload_index`; the bridge resolves the selected
|
||||
method node and the result reports its index and displayed signature. These
|
||||
indices are tied to the current artifact and engine, not stable across builds.
|
||||
|
||||
Smali fallbacks select one complete block using the original method name and DEX
|
||||
descriptor, before applying the source byte limit. This preserves the selected
|
||||
overload even when Java code generation renames a method. If the selected Java
|
||||
body was omitted, including a method merged into a synthetic bridge, REA returns
|
||||
its original smali with the `java_body_unavailable` marker. The marker describes
|
||||
missing Java; it does not infer why the method was omitted or name a replacement.
|
||||
Unresolved or duplicate disassembly identities fail instead of attributing another
|
||||
method's instructions to the selection.
|
||||
|
||||
Native and abstract methods are identified from access flags
|
||||
captured before code generation. They report `body_status: "not_available"`, an
|
||||
empty source, and the `native_method` or `abstract_method` marker; their declarations
|
||||
are not passed through the engine's source slicer. Other missing decompiled bodies
|
||||
do not establish either access flag.
|
||||
The engine's smali fallback also joins same-name overloads; REA rejects that
|
||||
fallback for an overloaded method instead of attributing all bodies to one
|
||||
selected overload. Native/abstract methods with no decompiled body report
|
||||
`body_status: "not_available"` without inferring which implementation flag caused it.
|
||||
|
||||
Static initializers (`<clinit>`) return smali with the
|
||||
`static_initializer_disassembly` marker. Java decompilation can move their
|
||||
@@ -174,10 +163,7 @@ the same source byte limit and explicit truncation reporting.
|
||||
permissions and class/resource counts. Summary fields are extracted by the
|
||||
upstream engine and should be checked against the retained XML when needed.
|
||||
Signature verification is explicitly `not_performed`.
|
||||
- Class search filters the engine's cached top-level names before transferring
|
||||
pages, then follows contiguous inventory positions without rescanning earlier
|
||||
rows. It checks selection, scope, examined ranges and counts before reporting
|
||||
complete coverage. Complete producer replies stay in Evidence; an empty `query`
|
||||
- Class search consumes all pages and checks their counts. An empty `query`
|
||||
inventories all class-name rows; class names are decompiler representations.
|
||||
Repeated names remain repeated in `matches` so the inventory row count and
|
||||
producer evidence stay visible. `duplicate_names` identifies matching names
|
||||
@@ -247,12 +233,8 @@ rea project-android-application-graph '{"inventory_evidence":[<inventory_artifac
|
||||
```
|
||||
|
||||
The projection reports exact component paths and hashes, runtime-family hints,
|
||||
and path-based bridge hypotheses. File and slice occurrences supply component
|
||||
endpoints; directory trees and symlinks retain their identities in the source
|
||||
inventory without being classified as code files. It does not decode DEX or
|
||||
claim observed runtime calls. DEX/JVM runtime hints summarize the classified
|
||||
bytecode component lists. Framework hints match complete native library names,
|
||||
such as
|
||||
and path-based bridge hypotheses. It does not decode DEX or claim observed
|
||||
runtime calls. Framework hints match complete native library names, such as
|
||||
`libreactnativejni.so`, `libreactnative.so`, `libhermes.so`,
|
||||
`libhermes_executor.so`, `libflutter.so`, and `libunity.so`; unrelated names
|
||||
such as `libcommunity.so` and `libreactivity.so` do not identify those families.
|
||||
@@ -317,15 +299,7 @@ settings. Evidence reports the worker's observed `Runtime.maxMemory()` rounded
|
||||
down to MiB and retains exact bytes, Java version and visible processors in its
|
||||
raw runtime response. The observed allocatable heap can differ from configured
|
||||
`-Xmx`, especially with Serial GC. Heap is not a total RSS cap: the JVM also
|
||||
uses native memory. A typed JVM memory allocation failure during APK loading
|
||||
reports `resource_constraint` with the observed maximum heap in bytes. Known
|
||||
heap failures name `REA_JADX_HEAP_MIB` in remediation; other memory regions
|
||||
remain unknown. A healthy doctor configuration check does not establish that
|
||||
any particular APK fits. Failures before the bridge can report a typed result
|
||||
and upstream errors from other operations retain their existing diagnostics;
|
||||
error text alone does not establish memory exhaustion.
|
||||
|
||||
Independent REA instances have independent queues. Whole
|
||||
uses native memory. Independent REA instances have independent queues. Whole
|
||||
operations have a **120-second** execution deadline by default, starting after
|
||||
they reach the queue's front. For a known slow cold load, such as a large
|
||||
multidex APK, select another finite deadline:
|
||||
|
||||
@@ -24,30 +24,6 @@ missing launcher reports `capability_unavailable` with the
|
||||
`binary_session` uses the same host probe for tool availability; it does not
|
||||
validate a particular APK or guarantee that the selected input can be decoded.
|
||||
|
||||
Client inspection and decode results disclose the following reported-version
|
||||
advisory windows without refusing otherwise compatible launchers:
|
||||
|
||||
| Advisory | Reported version window | Host scope |
|
||||
| ----------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ---------- |
|
||||
| [CVE-2024-21633](https://github.com/iBotPeaches/Apktool/security/advisories/GHSA-2hqv-2xv4-5h5w) | Before 2.9.2 | All |
|
||||
| [GHSA-vgwr-4w3p-xmjv](https://github.com/iBotPeaches/Apktool/security/advisories/GHSA-vgwr-4w3p-xmjv) | Before 2.9.3 | Windows |
|
||||
| [CVE-2026-39973](https://github.com/iBotPeaches/Apktool/security/advisories/GHSA-m8mh-x359-vm8m) | 3.0.0 release line through versions before 3.0.2 | All |
|
||||
|
||||
The 2026 advisory names 3.0.1 and its 3.0.2 fix. Inclusion of 3.0.0 is
|
||||
source-derived: [tagged 3.0.0](https://github.com/iBotPeaches/Apktool/blob/f770b39e425af4fa6ac4ca1e9ea6c4824339c6d3/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/table/ResTypeSpec.java)
|
||||
passes type names through unchanged; the [3.0.2 patch](https://github.com/iBotPeaches/Apktool/commit/65dd8480dfcb63068562ffaa527f71bb0a9f772c)
|
||||
validates those names at their owner before they reach the output-path producer.
|
||||
Prereleases before the fixed release are conservatively disclosed; the exact
|
||||
`-dirty` downstream marker is compared as a release while preserving its spelling.
|
||||
This is version guidance, not verification of a particular prerelease or decoder.
|
||||
|
||||
A launcher version does not prove the decoder's contents, execution platform,
|
||||
downstream backports, or overall safety. Windows applicability uses the selected
|
||||
local host; an opaque wrapper may run another engine. A missing warning means
|
||||
only that none of these version/host windows matched. Verify the selected
|
||||
decoder's patches before decoding untrusted APKs; the compatibility floor above
|
||||
is not a security recommendation. REA does not fetch advisories at runtime.
|
||||
|
||||
On Windows, a `.bat` or `.cmd` launcher (such as Chocolatey's `apktool.bat`)
|
||||
runs through an explicit `cmd.exe /d /s /c` call. That call has no AutoRun,
|
||||
no delayed expansion, and quotes every argument. A launcher path that
|
||||
@@ -62,15 +38,13 @@ reports `capability_unavailable`.
|
||||
rea inspect-apktool-client
|
||||
rea decode-android-resources /targets/Example.apk
|
||||
rea decode-android-resources /targets/Example.apk --locale de
|
||||
rea decode-android-resources /targets/Example.apk --locales de --locales pt-BR
|
||||
rea decode-android-resources /targets/Example.apk --no-strings
|
||||
```
|
||||
|
||||
Equivalent MCP methods are `inspect_apktool_client` and
|
||||
`decode_android_resources`. The decode request takes `path`, an optional
|
||||
primary `locale` (project `res/values-<locale>/strings.xml` instead of the default
|
||||
table), `locales` (repeatable array of additional localized string tables to project
|
||||
from the same single decode pass), and `include_strings` (default true). Regional locales such as `pt-BR`
|
||||
`locale` (project `res/values-<locale>/strings.xml` instead of the default
|
||||
table), and `include_strings` (default true). Regional locales such as `pt-BR`
|
||||
select Android's `values-pt-rBR`; Android qualifiers such as `pt-rBR` and
|
||||
`b+zh+Hans+CN` may also be supplied directly.
|
||||
|
||||
@@ -78,8 +52,6 @@ select Android's `values-pt-rBR`; Android qualifiers such as `pt-rBR` and
|
||||
|
||||
- **An owned APK snapshot is digested and decoded.** `target.sha256` and
|
||||
`target.bytes` bind the observation to the exact APK that was decoded.
|
||||
The Evidence subject carries the same snapshot digest and caller-selected
|
||||
path, including when the original file changes during decoding.
|
||||
- **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.
|
||||
@@ -87,28 +59,9 @@ select Android's `values-pt-rBR`; Android qualifiers such as `pt-rBR` and
|
||||
truncated when larger.
|
||||
- **Strings are projected verbatim.** Escaped entities stay escaped, and
|
||||
entries containing nested markup (`<b>`, `<xliff:g>`) are counted as
|
||||
unparsed rather than flattened — the limitation names the examined count.
|
||||
Malformed XML and a wrong document root are whole-document projection
|
||||
failures: the result is partial, the failure reason is disclosed, and entry
|
||||
counts remain unknown. They are not counted as one unsupported string.
|
||||
The default table is bounded to 2000 entries with partial coverage when more
|
||||
exist. `locales` lists observed regular `strings.xml` tables whose exact
|
||||
`values-<locale>` directory is selectable by the request's locale grammar.
|
||||
Locale suffixes allow up to 23 ASCII characters, derived from Apktool's
|
||||
language, script, region, and variant fields; for example,
|
||||
`b+sr+Latn+RS+REVISED` selects that exact table.
|
||||
Other table directories, including combined qualifiers such as
|
||||
`values-en-rUS-v21` and `values-mcc310-fr`, are named in limitations with
|
||||
their source spelling. They are not advertised as selectable locales;
|
||||
REA does not infer Android's runtime resource matching. Non-regular
|
||||
strings-table paths are disclosed with partial coverage. Discovery uses
|
||||
the same bounded traversal as the file count; filesystem failures remain
|
||||
failures rather than being interpreted as missing tables.
|
||||
When multiple tables are requested with `locales`, `string_tables` records
|
||||
each projected table with its locale, status (`present`, `missing`,
|
||||
`oversized`, `malformed`, or `skipped`), entry counts, and coverage,
|
||||
bounded at an aggregate budget of 10,000 strings and 32 MiB XML. When `locales`
|
||||
is omitted, legacy single-table payloads are preserved without adding `string_tables`.
|
||||
unparsed rather than flattened — the limitation names the count. The
|
||||
default table is bounded to 2000 entries with partial coverage when more
|
||||
exist; `locales` lists every `values-<locale>` that has a strings table.
|
||||
- **Smali is skipped by design** (`apktool d --no-src`): Java-source
|
||||
recovery belongs to the JADX family. Resource smali edits and rebuild are
|
||||
a follow-up lane with mutation authority.
|
||||
@@ -128,11 +81,9 @@ select Android's `values-pt-rBR`; Android qualifiers such as `pt-rBR` and
|
||||
coverage and an explicit limit, rather than reported as missing.
|
||||
- `decoded_file_count` is capped at 100,000 files; the cap is reported in
|
||||
the limitations when hit.
|
||||
- An ordinary nonzero decode exit surfaces as `unsupported_target` naming
|
||||
the caller-selected APK, with Apktool's diagnostic and captured output.
|
||||
Launcher startup, ownership preparation, signal termination and incomplete
|
||||
output collection remain provider failures; they do not establish that the
|
||||
selected APK is unsupported.
|
||||
- Apktool's own decode failures (`AndrolibException`, directory traversal
|
||||
refusals) surface as `unsupported_target` with apktool's reason preserved
|
||||
verbatim.
|
||||
|
||||
## Real verification
|
||||
|
||||
|
||||
@@ -60,15 +60,6 @@ states that absence is unknown. Component arrays remain complete when candidate
|
||||
hypotheses are omitted; component arrays still include every component from
|
||||
the supplied inventory pages, and overall coverage is `partial` in that case.
|
||||
|
||||
Inventoried files whose bytes were not read, such as encrypted archive members,
|
||||
are listed in `unavailable_components` with their original path, format,
|
||||
encryption flag, limitations, and null content identity. The same application-root
|
||||
and AppleDouble attribution rules apply. These files make overall coverage
|
||||
`partial`; component absence is unknown even when `inventory_complete` is true.
|
||||
Directories have no file bytes and symlinks remain in `symlinks`, so neither is
|
||||
an unavailable file component. The additive field participates in `projection_id`,
|
||||
including when empty, so Apple projection identifiers change.
|
||||
|
||||
## Application roots
|
||||
|
||||
| Inventory root | Application root |
|
||||
@@ -77,15 +68,6 @@ including when empty, so Apple projection identifiers change.
|
||||
| `.app` directory | `.`, the inventoried bundle itself |
|
||||
| Directory, ZIP, or DMG containing apps | Each outermost `<Name>.app` followed by `Contents/` |
|
||||
|
||||
File and slice occurrences supply component endpoints. Directory tree identities
|
||||
remain in source inventory and bundle anatomy, and links remain in `symlinks`.
|
||||
|
||||
Root and layout discovery use known directories and ancestors implied by deeper
|
||||
inventory paths. A leaf file or symlink named `*.app`, `Contents`, or `Versions`
|
||||
does not establish that directory. Directory and authenticated-file identity are
|
||||
selected before applying anatomy case preferences, so a file cannot shadow a
|
||||
folded directory name or a directory shadow a metadata/signature file.
|
||||
|
||||
ZIP archives made with `ditto -c -k --keepParent` report `<Name>.app`. A DMG
|
||||
reports `<image>.dmg/<Volume>/<Name>.app`; DMG child inventory needs the native
|
||||
macOS mounting adapter. When a DMG has only its root identity, the projection is
|
||||
|
||||
@@ -285,14 +285,6 @@ REA establishes a main-frame origin boundary before enabling Runtime, Debugger,
|
||||
|
||||
## Data minimization
|
||||
|
||||
The Link projection parses repeated CDP header field lines independently and
|
||||
retains their declarations in order, including derived untrusted agent hints.
|
||||
Commas inside URI targets or quoted parameters remain part of those values.
|
||||
COOP and COEP projections retain the exact declared token after validating the
|
||||
complete Structured Field Item, including parameters such as `report-to`.
|
||||
These are declarations, not an assessment of the document's effective policy;
|
||||
absent, malformed or non-token items project as `null`.
|
||||
|
||||
REA retains local observation data and removes only URL userinfo credentials, explicitly declared scenario secrets, and values from structured credential/storage fields:
|
||||
|
||||
- URL observations preserve the complete local URL, including query values, fragments, duplicate parameters, and their order. Only username/password userinfo is removed; malformed original URL strings remain available with `origin: null`.
|
||||
|
||||
@@ -144,18 +144,6 @@ 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.
|
||||
|
||||
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,
|
||||
cache and origin storage. Later REA runs currently do not reclaim these paths.
|
||||
Playwright 1.58.2 can also leave an artifacts directory when launch preparation
|
||||
fails before a browser process exists, such as for a missing executable.
|
||||
POSIX wrappers can request awaited cancellation with `SIGINT` or `SIGTERM`;
|
||||
Windows process termination is not an equivalent graceful-cancellation channel.
|
||||
Do not identify owned artifacts by directory prefix or creation time alone.
|
||||
See [#4659](https://github.com/morluto/rea/issues/4659) for the remaining recovery
|
||||
and wrapper-cancellation work.
|
||||
|
||||
Keeping that browser alive does not guarantee its emulation state survives.
|
||||
Chromium can clear caller-owned `navigator.platform` emulation when a page CDP
|
||||
session disconnects, including sessions that sent no emulation commands. REA
|
||||
|
||||
@@ -56,15 +56,8 @@ rea inspect-electron-page http://127.0.0.1:9223 TARGET_ID \
|
||||
|
||||
The normalized result contains canonical local paths, frame and DOM
|
||||
structure, resource metadata, stable script/resource identities, explicit
|
||||
completeness, and content-addressed script artifacts. Resource sizes are unknown
|
||||
when omitted or invalid; supplied invalid sizes also produce an explicit
|
||||
completeness diagnostic.
|
||||
|
||||
DOM node indices retain their snapshot positions. Invalid rows are omitted with
|
||||
completeness diagnostics, so `total_nodes` can exceed the retained node count
|
||||
and a parent index can refer to an omitted source node.
|
||||
|
||||
Script metadata retains its execution-context frame ID when CDP supplies one. The capture also
|
||||
completeness, and content-addressed script artifacts. Script metadata
|
||||
retains its execution-context frame ID when CDP supplies one. The capture also
|
||||
inventories worker, service-worker, and shared-worker targets with
|
||||
validated opener-target and parent-frame IDs. Worker discovery uses passive
|
||||
target metadata; REA does not attach to or execute code in those targets.
|
||||
|
||||
@@ -124,10 +124,6 @@ FileBytes digests, every source mapping and its memory digest, relocation record
|
||||
module partitions, relocation fixups and linear coordinates rather than relying
|
||||
on the imported executable SHA alone.
|
||||
|
||||
Expected DOS relocation records retain each fixup's pre-application bytes and
|
||||
applied value. Their memory-byte windows come from the final relocated image,
|
||||
including changes made by later overlapping fixups.
|
||||
|
||||
The result is `verified`, `mismatch`, or `unsupported`. Every check retains its
|
||||
expected and observed values. A memory-digest mismatch identifies the source
|
||||
range's file offset and analysis address; it does not locate the first differing
|
||||
@@ -138,10 +134,6 @@ their contents and DOS runtime semantics are not verified. Independent verificat
|
||||
also covers explicit [raw-binary imports](raw-binary.md); other formats return
|
||||
`unsupported` with measured observations.
|
||||
|
||||
MZ verification retains the initialized image described by the header's page
|
||||
count and streams appended overlay bytes into the complete original and modified
|
||||
source digests. Overlay size does not increase the retained image allocation.
|
||||
|
||||
`read_bytes` returns initialized provider memory, including loader fixups; an
|
||||
unmapped or uninitialized byte ends the read with an explicit returned length and
|
||||
`complete: false`. `address_to_file_offset` uses the provider's source mapping;
|
||||
|
||||
@@ -65,14 +65,6 @@ PDB, or change analyzer settings.
|
||||
|
||||
## Loaded addresses and file offsets
|
||||
|
||||
Ghidra computes overview procedure and string counts from the same inventories
|
||||
used by `list_procedures` and `list_strings`, without transporting those rows
|
||||
solely to count them. Counts include external functions and only Ghidra-defined
|
||||
strings; they do not establish discovery of unidentified functions or undefined
|
||||
string bytes. Complete inventories remain available through the list tools.
|
||||
Overview reuse follows the target/profile snapshot lifetime and is invalidated
|
||||
by session metadata edits.
|
||||
|
||||
`rea analyze <path> --provider ghidra --json` and MCP `binary_overview` report
|
||||
the observed loaded `image_base` in `normalized_result`. They retain each
|
||||
segment's reported `image_base` and `address_space`. A provider that does not
|
||||
|
||||
@@ -45,12 +45,6 @@ The MCP tool `project_harmony_application_graph` takes the same
|
||||
- path-based N-API bridge hypotheses between bytecode and `libs/<abi>` native
|
||||
libraries
|
||||
|
||||
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
|
||||
classified bytecode and JavaScript lists; supported source extensions share the
|
||||
same classification rule as their component rows.
|
||||
|
||||
Every claim is path-presence only. Manifest semantics (module identity,
|
||||
abilities, entry points, permissions, dependencies), Ark bytecode contents and
|
||||
versions, resource resolution, signing verification, and observed native
|
||||
|
||||
@@ -41,7 +41,7 @@ rea function /absolute/path/to/program main --json
|
||||
rea decompile /absolute/path/to/program main --json
|
||||
```
|
||||
|
||||
Open the **original input binary** in REA, not an `.idb` or `.i64` database. Its SHA-256 must match IDA's recorded input hash. REA checks the attached identity and image base around each analysis request. A mismatch or target switch fails with recovery guidance. The original input must remain readable by REA; WSL can use its mounted alias while the GUI runs on Windows. Attached profiles, including native mode, refuse universal Mach-O inputs at admission: every slice shares the recorded whole-file hash, so REA cannot verify which slice the GUI loaded. Open a thin file extracted with `lipo -thin` in both IDA and REA, or use headless mode, which analyzes the selected slice.
|
||||
Open the **original input binary** in REA, not an `.idb` or `.i64` database. Its SHA-256 must match IDA's recorded input hash. REA checks the attached identity and image base around each analysis request. A mismatch or target switch fails with recovery guidance. The original input must remain readable by REA; WSL can use its mounted alias while the GUI runs on Windows.
|
||||
|
||||
REA's close operation releases its MCP connection or proxy. It never saves or closes the existing GUI database. External edits remain visible because results are live and are not replayed from snapshots. These checks do not lock the GUI or prove that the database is unpatched.
|
||||
|
||||
|
||||
+5
-48
@@ -57,26 +57,14 @@ Before applying changes, REA checks your current configuration. The plan lists:
|
||||
Malformed or unsafe existing configuration blocks the whole transaction before
|
||||
Hopper installation or any file write. Declining or pressing Ctrl-C makes no
|
||||
changes. Agent configuration writes preserve unrelated entries and comments,
|
||||
create backups, stage changes in a private directory, and verify their result.
|
||||
Before publication, they refuse detected changes to the selected configuration.
|
||||
Replacement uses an explicit destination under the selected canonical parent;
|
||||
it does not follow a newly inserted destination symlink. First-run setup uses
|
||||
an exclusive hard link and fails without overwriting a newly created destination;
|
||||
filesystems without hard-link support cannot publish a first-run configuration.
|
||||
Setup and uninstall retain an existing `.rea.backup` rather than replacing the
|
||||
first snapshot.
|
||||
create backups, use atomic replacement, and verify their result. Setup and
|
||||
uninstall retain an existing `.rea.backup` rather than replacing the first snapshot.
|
||||
If that snapshot differs from the current configuration, setup and uninstall
|
||||
preserve a verified `.rea.backup.<sha256>.recovery` copy of the current bytes
|
||||
before editing; setup also previews it. Both snapshots remain available.
|
||||
When an edit made a backup, a failed uninstall update or restore, and a failed
|
||||
setup readback or rollback, name the backup path that holds the bytes from just
|
||||
before that edit.
|
||||
If setup cannot verify a newly created configuration, it retains the file and
|
||||
reports manual recovery instead of deleting a pathname that may have changed.
|
||||
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 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`.
|
||||
@@ -276,14 +264,14 @@ Register with the variable unset:
|
||||
<!-- x-release-please-start-version -->
|
||||
|
||||
```bash
|
||||
claude mcp add --scope local rea -- npx -y rea-agents@6.7.0 mcp
|
||||
claude mcp add --scope local rea -- npx -y rea-agents@6.5.0 mcp
|
||||
```
|
||||
|
||||
On native Windows, use the same project directory and wrap the package-runner
|
||||
shim so the stdio client can launch it:
|
||||
|
||||
```powershell
|
||||
claude mcp add --scope local rea -- cmd.exe /d /c npx -y rea-agents@6.7.0 mcp
|
||||
claude mcp add --scope local rea -- cmd.exe /d /c npx -y rea-agents@6.5.0 mcp
|
||||
```
|
||||
|
||||
<!-- x-release-please-end -->
|
||||
@@ -913,12 +901,6 @@ Properties format limit. Reads preserve Ghidra's Latin-1 byte mapping and check
|
||||
the descriptor and selected name for changes. Permission failures and resource
|
||||
refusals remain explicit; failed descriptor cleanup must succeed before that
|
||||
owner admits another inspection.
|
||||
Native decompiler compatibility inspection follows the selected executable symlink
|
||||
and reads at most the first 4096 bytes through the same descriptor owner. It
|
||||
checks the full extent and selected name for changes without reading the remainder.
|
||||
An unreadable or unrecognized header leaves compatibility unknown; diagnostics
|
||||
retain read failures. Cancellation and incomplete cleanup propagate as failures,
|
||||
and failed cleanup retains the exact descriptor for retry.
|
||||
This coordinate selects only REA's session-private configuration directory, not
|
||||
the installation or an existing user configuration directory.
|
||||
|
||||
@@ -937,10 +919,6 @@ ownership inspection, so retaining those wrappers would prevent verified
|
||||
process-group cancellation during startup.
|
||||
If ownership remains unverifiable, it reports the reason and retains the process
|
||||
supervisor and private runtime instead of removing files beneath a live provider.
|
||||
Startup preserves an observed launch failure when cancellation arrives during
|
||||
rollback. Producer cancellation retains the caller's exact reason separately
|
||||
from LaunchSupport warnings and cleanup failures. Failed rollback keeps the
|
||||
original process owner for a later cleanup retry.
|
||||
The experimental Windows transport uses authenticated IPv4 loopback with a
|
||||
private native-owned bearer descriptor and Job Object process ownership.
|
||||
|
||||
@@ -1036,8 +1014,6 @@ export REA_GHIDRA_COMPILER_SPEC_ID="borlandcpp" # optional; requires a languag
|
||||
|
||||
REA passes `-processor`/`-cspec`, checks both against the installation's `.ldefs`, and records them in the analysis profile. DOS imports reject an override.
|
||||
|
||||
Language definitions must be well-formed XML encoded as UTF-8 or BOM-marked UTF-16, with any encoding declaration matching the bytes. Literal Unicode replacement characters (U+FFFD) are accepted; malformed source bytes are rejected.
|
||||
|
||||
To seed code that auto-analysis cannot reach (computed jumps, pointers in data):
|
||||
|
||||
```bash
|
||||
@@ -1137,10 +1113,6 @@ compiler remains distinguishable from a compiler that exited with an error.
|
||||
The helper compile deadline defaults to 120,000 ms; set
|
||||
`REA_SWIFTC_COMPILE_TIMEOUT_MS` to an integer between 1 and 2,147,483,647 when
|
||||
a busy host needs longer.
|
||||
On macOS, the Java prerequisite probe waits for this independently bounded
|
||||
preparation before starting its five-second command deadline. Caller cancellation
|
||||
still interrupts preparation, and failed helper cleanup remains owned for retry.
|
||||
Linux process-table preparation remains inside the command deadline.
|
||||
Other rejection values retain their primitive value or an explicit type.
|
||||
Shutdown warnings include the failure
|
||||
kind, message, and diagnostics, while process and temporary-project cleanup
|
||||
@@ -1187,7 +1159,7 @@ For a client that requires manual configuration, use:
|
||||
"mcpServers": {
|
||||
"rea": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "rea-agents@6.7.0", "mcp"]
|
||||
"args": ["-y", "rea-agents@6.5.0", "mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1252,21 +1224,6 @@ on the shell `PATH`. Use the setup command above for the guided setup
|
||||
journey, `npx -y rea-agents@latest` for unattended one-off commands, or install globally
|
||||
with `npm install --global rea-agents` for a shell-visible `rea` command.
|
||||
|
||||
For many concurrent agent sessions, run setup directly from a global installation
|
||||
to avoid keeping a separate npm launcher process for each MCP connection:
|
||||
|
||||
```bash
|
||||
npm install --global rea-agents
|
||||
rea setup
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
The optional curl wrapper installs only the global npm package:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -288,27 +288,6 @@ and the result includes its basis, candidates, changed dimensions, Evidence
|
||||
links, limitations, and a `changed_from` graph containing all compared nodes,
|
||||
their observations, and relationships.
|
||||
|
||||
A matched pair whose only differing dimension is `location` counts as
|
||||
`unchanged` when both input graphs have complete coverage and its neighboring
|
||||
relationship identities are resolved. This includes an
|
||||
identical module shifted by an earlier bundle edit and a named IPC channel
|
||||
observed at a new offset. The item still reports `dimensions: ["location"]`
|
||||
and both node IDs; the graph retains both original observations and coordinates.
|
||||
Content, property, and complete relationship differences still count as
|
||||
`changed`. With incomplete coverage, relocation alone remains `unknown` and
|
||||
retains the location and coverage dimensions. Matching confidence is unchanged:
|
||||
an inferred pair is not promoted to exact identity by this classification.
|
||||
|
||||
Complete inventory does not resolve ambiguous or unmatched relationship targets.
|
||||
A matched module with identical bytes can therefore remain `unknown` when a
|
||||
neighbor, including its containing chunk, has no cross-version match. The item
|
||||
retains its exact content match, coordinates, candidate inventory, and an explicit
|
||||
relationship-identity limitation. `coverage` is added to its dimensions only for
|
||||
incomplete inventory. Definite content, property, or complete topology differences
|
||||
remain `changed` while retaining any separate relationship uncertainty.
|
||||
An unknown item with no observed content, property, or relationship difference
|
||||
does not emit a `changed_from` edge; its pairing and uncertainty remain in the item.
|
||||
|
||||
One-sided absence is `added` or `removed` only when the opposite input graph has
|
||||
complete coverage. With partial, unavailable, or truncated input, the same
|
||||
condition is `unknown`. The comparison retains every classified item and
|
||||
|
||||
@@ -586,21 +586,6 @@ not bypass worker heap, execution deadline or parent result admission. Truncated
|
||||
coverage reports both effective node ceilings; omitted relationships remain
|
||||
unknown.
|
||||
|
||||
Unknown records have independent defaults of 100000 across the application and
|
||||
20000 per source. Select `max_semantic_unknowns` and
|
||||
`max_semantic_unknowns_per_file` (CLI: `--max-semantic-unknowns` and
|
||||
`--max-semantic-unknowns-per-file`), each from 1 to 1000000. The parent offers the
|
||||
remaining capacity to the worker, and rejects excess records before adoption.
|
||||
Unknown admission happens before canonical identity and provenance construction.
|
||||
When capacity is exhausted, coverage is partial and truncated and names both
|
||||
effective unknown ceilings. `coverage.omitted_unknown_occurrences` counts examined
|
||||
emission occurrences by family and reason, including repeated emissions. It does
|
||||
not claim distinct discarded identities or count frontiers in unexamined source.
|
||||
Omitted unknown provenance and IDs are not retained. Existing source, node,
|
||||
execution and memory limits continue to determine examined coverage. Raising only
|
||||
a node capacity does not raise the unknown capacity. Graphs without unknown
|
||||
omissions omit this optional coverage field, preserving their existing identities.
|
||||
|
||||
While sources remain, the sequential worker reserves one next compact static
|
||||
checkpoint at its 8 MiB bound with the same 6x retention expansion used at
|
||||
admission. Earlier checkpoints are already charged to retained bytes; the
|
||||
|
||||
@@ -133,11 +133,8 @@ Each operation uses one worker, a 1 GiB address-space ceiling and a 120-second
|
||||
deadline; it accepts up to 64 MiB of total input across all selected files and
|
||||
128 MiB/10000 entries of staged
|
||||
output, with 8 MiB per diagnostic/report stream. Exceeding a limit is an explicit
|
||||
failure with rollback. Selected inputs beyond the total input allowance return a
|
||||
non-retryable `resource_constraint` with `resource: "file-size"` and
|
||||
`reported_limits.maximum_input_bytes`/`remaining_input_bytes`; input that is not
|
||||
valid UTF-8 is an `invalid_format` request issue. These limits apply per
|
||||
operation and do not claim aggregate host containment across concurrent callers.
|
||||
failure with rollback. These limits apply per operation and do not claim aggregate
|
||||
host containment across concurrent callers.
|
||||
|
||||
See [testing.md](testing.md#javascript-source-recovery) for the focused real
|
||||
Wakaru CLI/MCP lane and its source-owned compiler fixtures. Other host platforms
|
||||
|
||||
@@ -109,9 +109,7 @@ The direct observations are:
|
||||
- `Runtime.executionContextCreated`,
|
||||
`Runtime.executionContextDestroyed`, and
|
||||
`Runtime.executionContextsCleared`, establishing context lifecycle within
|
||||
the capture window. A created or destroyed event whose context ID is
|
||||
missing or not a safe integer adds no context record; it is retained only
|
||||
as a count reported in `unknowns`.
|
||||
the capture window.
|
||||
|
||||
The Inspector protocol does not directly expose require/import caller edges,
|
||||
EventEmitter emissions or listener invocation, Electron IPC messages or
|
||||
|
||||
+1
-21
@@ -22,8 +22,6 @@ Select it explicitly with `--provider kuna`, MCP's `open_binary.provider_id: "ku
|
||||
| `REA_KUNA_TIMEOUT_MS` | 120 s | Deadline for one single-function decompile, and for the inventory run REA makes when the export ends without one. |
|
||||
| `REA_KUNA_JOBS` | 1 | `decompile-project --jobs`. 1 is Kuna's reference answer; more jobs finish sooner but lose callee-first prototypes, and change about 40–60% of function bodies on the measured binaries. |
|
||||
|
||||
A single-function decompile, inventory, string, graph or xref run that exceeds its deadline fails as `provider_timeout`, naming the setting that owns the deadline and that raising it takes a restart. A project export that exceeds `REA_KUNA_PROJECT_TIMEOUT_MS` is an export failure instead: requests that need the export report `capability_unavailable` with the export's own retry guidance.
|
||||
|
||||
Windows is not supported yet. Supported targets are ELF and thin Mach-O executables for x86-64, AArch64 and ARM; PE and universal Mach-O are rejected with a typed reason.
|
||||
|
||||
## What Kuna answers
|
||||
@@ -70,7 +68,7 @@ Single-function subprocess output and each cached source facet share a 16 MiB bu
|
||||
|
||||
Results keep exact u64 virtual addresses, decoded text, native encoding, terminator status and byte length including any terminator. Kuna scans mapped sections or segments for runs of at least five characters; unterminated fragments can include instruction bytes. `all` includes ASCII, UTF-8 and the engine's Latin-range UTF-16LE reading. Other text, including short strings, non-Latin wide text and UTF-16BE, can remain undiscovered. An empty result does not prove absence.
|
||||
|
||||
Use `search_strings` for the matching rows or `list_strings` with an exact address for that location. The validated inventory is sorted by numeric address and encoding. Once cached, exact-address reads use binary search and return every encoding at that address without scanning the full inventory or retaining another lookup index. Literal and regex matching run in REA, preserving the existing case and ECMAScript Unicode semantics instead of substituting Kuna's different regex dialect. Procedure and string regex queries share one worker slot per session. Input projections are materialized only after admission, so queued queries retain no per-query inventory arrays. Close cancels and drains matching. Native metadata queries also share one admission slot, including references; a failed stop retains admission until cleanup is proven.
|
||||
Use `search_strings` for the matching rows or `list_strings` with an exact address for that location. Literal and regex matching run in REA, preserving the existing case and ECMAScript Unicode semantics instead of substituting Kuna's different regex dialect. Procedure and string regex queries share one worker slot per session. Input projections are materialized only after admission, so queued queries retain no per-query inventory arrays. Close cancels and drains matching. Native metadata queries also share one admission slot, including references; a failed stop retains admission until cleanup is proven.
|
||||
|
||||
`raw_result.strings` reports the source JSON digest/size, scanned scope, extraction policy, complete inventory count and selected count without copying unrequested text into the answer. Omit the address from `list_strings` to retrieve the complete inventory as Evidence; normal session retention and bundle export apply, including transport-capacity errors for oversized inline replies. These operations preserve their complete-result contracts and do not add paging. Function-referenced string facets in `analyze_function` remain unavailable; call `xrefs` explicitly when references to one returned string are needed.
|
||||
|
||||
@@ -84,24 +82,6 @@ REA parses the graph as Kuna writes it, like the string scan, so the graph has n
|
||||
|
||||
Evidence includes only selected addresses or dossier neighbors, the producing JSON's SHA-256/byte count, coverage and relevant function facts; unrequested program-wide JSON and instruction text are omitted. Reference caches are in memory and expire on close: a fresh CLI process or MCP server rebuilds them. A first call query therefore costs a whole-program reference walk even when a C export is warm. These operations do not establish full Ghidra/IDA feature parity.
|
||||
|
||||
Failures from shared installation or inventory work identify the operation the
|
||||
caller requested. `diagnostics.producer_operation` retains the internal producer
|
||||
name when it differs. Caller-specific failures keep the producer's typed outcome,
|
||||
captured output, partial facts and live cleanup dependencies; cleanup retry
|
||||
updates every projection rather than preserving an independent stale marker.
|
||||
Installation acquisition is shared, with independently cancellable caller waits.
|
||||
The final departing caller stops the probe and joins its cleanup; session close
|
||||
also stops and joins acquisition. A cleanly cancelled acquisition can be retried,
|
||||
while a retained cleanup failure blocks replacement until its owner is closed.
|
||||
Shared string and reference queries preserve caller cancellation reasons and
|
||||
join the final departing caller's command cleanup. A command cleanup error keeps
|
||||
its typed primary failure and captured output. Its live resource list follows
|
||||
both process and workspace ownership: proving process exit does not prove that
|
||||
the private workspace was removed, and retry updates earlier caller errors.
|
||||
If workspace setup fails, an unsuccessful rollback retains the original target
|
||||
or read failure together with its cleanup owner. Replacement stays blocked until
|
||||
that rollback is resolved; a clean rollback permits another setup attempt.
|
||||
|
||||
## Provenance and limitations
|
||||
|
||||
- Addresses and bytes are Kuna's observations of the image. Procedure entries and extents are its derivations: extents are upper bounds clipped at the next entry, and Kuna can split one function at an entry its own analysis infers. Pseudocode is its reconstruction, never original source.
|
||||
|
||||
@@ -524,12 +524,6 @@ analysis runtime. These failures are reported at the operation that needs
|
||||
them. A configured provider or an endpoint alone does not establish that a
|
||||
target is supported.
|
||||
|
||||
Composite Hopper regex searches report failures against the accepted
|
||||
`search_strings` or `search_procedures` operation. The underlying inventory
|
||||
method and request ID remain in `details.diagnostics.provider_request`, with
|
||||
the bridge error code and diagnostic type when available. Reattribution
|
||||
preserves the failure class, captured output, and live cleanup ownership.
|
||||
|
||||
Evidence bundles, snapshots, and extraction use the paths and output behavior
|
||||
declared by their tools. Artifact extraction materializes the selected regular
|
||||
files into a fresh REA-chosen temporary directory and reports its path.
|
||||
@@ -540,25 +534,6 @@ temporary source files are declared as `launchesProcess` and `writesFilesystem`,
|
||||
including for a single JavaScript source. This internal analysis does not execute
|
||||
the supplied application code.
|
||||
|
||||
## Static Ghidra bytes and source mappings
|
||||
|
||||
`read_bytes` returns initialized analysis memory, including loader fixups, rather
|
||||
than live process memory. Check `returned_bytes` and `complete` before decoding:
|
||||
reads stop at unmapped or uninitialized bytes. Missing bytes are unknown; do not
|
||||
pad an incomplete read with zeros and treat the result as an observation.
|
||||
|
||||
`list_segments` reports memory-block initialization and address-space facts.
|
||||
`address_to_file_offset` maps one address through the provider's source-byte
|
||||
mapping. A successful start-address mapping does not establish that an entire
|
||||
range is contiguous in the original file, or that its bytes equal analysis
|
||||
memory after loader fixups. Uninitialized, missing, and ambiguous mappings fail
|
||||
explicitly; preserve the reported failure rather than guessing an offset.
|
||||
|
||||
For constructor-populated pointer or resource slots, a static zero is not proof
|
||||
of a later null value. Inspect the slot's `xrefs` and the writer's assembly or
|
||||
pseudocode, retaining uncertainty about execution order and runtime values.
|
||||
These operations inspect static evidence and do not execute the target.
|
||||
|
||||
## Ghidra first-query deadlines and recovery
|
||||
|
||||
A successful MCP initialize handshake establishes the REA connection.
|
||||
|
||||
@@ -261,23 +261,6 @@ Mach-O fixtures check each case against source-owned return values.
|
||||
|
||||
## Static inspection
|
||||
|
||||
`inspect_plist.format` describes the selected source, not plutil's conversion
|
||||
format. Sources explicitly identified as XML, binary or JSON retain those
|
||||
labels. For generic text, a bounded source-prefix probe recognizes leading XML
|
||||
markup, including UTF-8 and BOM-marked UTF-16 sources. Unidentified text and
|
||||
OpenStep plists, including a data-only value such as `<deadbeef>`, report
|
||||
`unknown` even when plutil decodes their values through an XML conversion.
|
||||
|
||||
A plist explicitly selected through the path input or as the active plist target
|
||||
reports an unreadable or malformed selection as `invalid_request`. A missing or
|
||||
unreadable default plist of another target reports `capability_unavailable`.
|
||||
Permission failures remain `access_denied`; output and cleanup failures retain
|
||||
their own error categories.
|
||||
|
||||
A plist decode refusal includes plutil's diagnostic from either output stream.
|
||||
`details.captured_output` retains bounded stdout/stderr excerpts, observed byte
|
||||
totals and exit status. `truncated: true` means those excerpts are incomplete.
|
||||
|
||||
`inspect_macho.selected_architecture` identifies the exact selected lipo slice
|
||||
and its `container_file_offset` in the input file. A thin Mach-O has a known
|
||||
offset of zero; an unknown universal-slice offset stays null. The Evidence
|
||||
@@ -334,16 +317,12 @@ complete observation.
|
||||
shared/cyclic references, class descriptors, raw serialized fields and
|
||||
malformed/unresolved/nil references. Missing fields stay absent; unknown
|
||||
classes are preserved. Select `root`, `offset` and `limit` explicitly.
|
||||
Object `kind` describes the decoded archive value: data, dates and numbers
|
||||
remain `scalar` when their JSON value uses a `$plist_type` wrapper. An actual
|
||||
dictionary with the same fields remains `dictionary`.
|
||||
UID 0 cannot distinguish conditional nil from ordinary nil. Limits are
|
||||
64 MiB of input, 200,000 objects/references and 128 nesting levels.
|
||||
XML dictionary entries decoded as `__proto__` are omitted with an explicit
|
||||
count because REA results cannot represent that key. XML tag whitespace and
|
||||
comments do not change that handling. XML key names combine their text and
|
||||
CDATA segments without trimming or expanding literal CDATA entities. Other
|
||||
values and the original archive digest are preserved.
|
||||
comments do not change that handling. Other values and the original archive
|
||||
digest are preserved; key interpretation follows the pinned plist decoder.
|
||||
- `decode_interface_builder` / `rea decode-interface-builder <app>` reads
|
||||
compiled storyboard and nib resources into objects, outlets, actions,
|
||||
connections and controller/class names. A full app graph is often several
|
||||
@@ -439,11 +418,7 @@ decrement scrolling and text-value entry, or bounded waits. No global event
|
||||
injection is used. Unsupported AX actions fail explicitly. The result preserves
|
||||
ordered before/after captures and gaps; an action may have occurred before a
|
||||
post-action capture fails. Application state is left as-is; REA does not attempt
|
||||
to restore it. Failed or cancelled scenarios return a typed error with the
|
||||
collected report in `partial_observation`, including ordered step outcomes.
|
||||
Cancellation preserves the caller's reason and remains observable through helper
|
||||
cleanup. A later abort does not replace an earlier helper or output failure.
|
||||
Cleanup failures retain their runtime owner until a confirmed cleanup retry.
|
||||
to restore it.
|
||||
|
||||
Scenarios accept caller-selected action lists and accessibility node counts.
|
||||
Individual waits cannot exceed the operation's 180-second deadline, and the
|
||||
@@ -597,10 +572,6 @@ digests identify the original serialized bytes.
|
||||
## Keyed archive integer precision
|
||||
|
||||
The archive reader observes XML number element types and binary number markers.
|
||||
XML values and their number facts are interpreted together from the validated
|
||||
DOM. Hexadecimal `<integer>` text, including an optional sign, retains its value;
|
||||
`<real>` text and CDATA segments are combined without inferring text from nested
|
||||
elements. The XML path does not serialize or reparse character references.
|
||||
Integers beyond the exact range of a JSON number are reported with the original
|
||||
decimal text as `{ "$plist_type": "integer", "decimal": "<exact digits>" }` when
|
||||
that source value can be associated unambiguously. Integral real values remain
|
||||
@@ -638,30 +609,6 @@ or a negative year, is reported as `{ "$plist_type": "date", "iso8601": null }`
|
||||
with a counted limitation; the rest of the plist or archive is still decoded.
|
||||
`inspect_plist` and Interface Builder decoding use the same projection.
|
||||
|
||||
A negative-zero real is reported as `{ "$plist_type": "real", "value": "-0" }`
|
||||
because a JSON number cannot carry the sign of zero. `inspect_plist` and
|
||||
`inspect_keyed_archive` count these values in a limitation, and Interface
|
||||
Builder node attributes use the same value. Positive zero and integer zero,
|
||||
including an `<integer>-0</integer>` literal, remain the number `0`.
|
||||
|
||||
Known non-finite reals are reported as
|
||||
`{ "$plist_type": "real", "value": "nan" | "+infinity" | "-infinity" }`.
|
||||
These are canonical numeric labels, not a claim about original source spelling.
|
||||
Binary IEEE reals retain NaN versus signed infinity; NaN payload bits and sign
|
||||
are not represented in the JSON value, and the original bytes remain the source
|
||||
for those details. XML CFPropertyList literals (`nan`, `+infinity`, `-infinity`,
|
||||
`infinity`, `inf`, `+inf`, `-inf`, case-insensitively) decode to the same known
|
||||
values. Case and aliases normalize; original archive bytes retain source text.
|
||||
|
||||
XML numeric text whose identity the decoder cannot establish, including
|
||||
unrecognized non-finite text and finite literals that overflow the numeric
|
||||
representation, remains `{ "$plist_type": "real", "value": null }` with a
|
||||
counted limitation. The XML decoder marks these values explicitly before shared
|
||||
projection, so they cannot be confused with known binary IEEE values.
|
||||
Incomplete numeric markup retains its existing compatibility behavior described
|
||||
above. Known non-finite and unresolved numeric values have separate counts.
|
||||
Native `inspect_plist` uses these same labels for plutil's XML conversion.
|
||||
|
||||
## Locate a byte signature
|
||||
|
||||
Use `search_bytes` after opening a target with Ghidra to locate a known constant
|
||||
|
||||
@@ -58,11 +58,6 @@ tools read that copy, which is hashed again after analysis. Capture metadata and
|
||||
literal field values are producer observations; address/protocol counts and DNS
|
||||
associations are derivations. Capture Evidence has historical-reference authority.
|
||||
|
||||
`capture_start` and `capture_end` are RFC 3339 UTC instants derived from
|
||||
`capinfos -S` epoch seconds, retaining all producer fractional digits (up to
|
||||
nanoseconds). Empty captures, malformed timestamps and instants outside years
|
||||
0000–9999 remain `null`; host-local timestamps without a zone are not inferred.
|
||||
|
||||
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.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · **العربية** · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: هندسة عكسية لأي شيء
|
||||
|
||||
@@ -274,7 +274,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## سجل النجوم
|
||||
|
||||
🎉 **300,000 نجمة على GitHub — شكرًا لكم!**
|
||||
🎉 **250,000 نجمة على GitHub — شكرًا لكم!**
|
||||
|
||||
شكرًا لكل من يستخدم REA، ويبلّغ عن الأخطاء، ويقترح ميزات، ويختبر إصدارات البناء، ويساهم بالإصلاحات.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · **Deutsch** · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: Alles reverse-engineeren
|
||||
|
||||
@@ -272,7 +272,7 @@ Melde Sicherheitslücken gemäß [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Sternverlauf
|
||||
|
||||
🎉 **300.000 GitHub-Sterne – vielen Dank!**
|
||||
🎉 **250.000 GitHub-Sterne – vielen Dank!**
|
||||
|
||||
Danke an alle, die REA nutzen, Fehler melden, Funktionswünsche äußern, Builds testen und Fehlerbehebungen beitragen.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md) · **Ελληνικά** · [മലയാളം](README_ml.md)
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md) · **Ελληνικά**
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -285,7 +285,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## Ιστορικό αστεριών
|
||||
|
||||
🎉 **300.000 αστέρια στο GitHub — σας ευχαριστούμε!**
|
||||
🎉 **250.000 αστέρια στο GitHub — σας ευχαριστούμε!**
|
||||
|
||||
Ευχαριστούμε όλους όσοι χρησιμοποιούν το REA, αναφέρουν σφάλματα, ζητούν νέες λειτουργίες, δοκιμάζουν builds και συνεισφέρουν διορθώσεις.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · **Español** · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: Ingeniería inversa de cualquier cosa
|
||||
|
||||
@@ -272,7 +272,7 @@ Informa de vulnerabilidades siguiendo [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Historial de estrellas
|
||||
|
||||
🎉 **300.000 estrellas en GitHub: ¡gracias!**
|
||||
🎉 **250.000 estrellas en GitHub: ¡gracias!**
|
||||
|
||||
Gracias a quienes usan REA, informan de errores, solicitan funciones, prueban compilaciones y contribuyen con correcciones.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center" dir="rtl">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · **فارسی** · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: مهندسی معکوس هر چیزی
|
||||
|
||||
@@ -257,7 +257,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## تاریخچهٔ ستارهها
|
||||
|
||||
🎉 **۳۰۰٬۰۰۰ ستارهٔ GitHub — سپاسگزاریم!**
|
||||
🎉 **۲۵۰٬۰۰۰ ستارهٔ GitHub — سپاسگزاریم!**
|
||||
|
||||
از همهٔ کسانی که از REA استفاده میکنند، خطاها را گزارش میدهند، قابلیتهای جدید پیشنهاد میکنند، buildها را آزمایش میکنند و در بهبود پروژه مشارکت دارند سپاسگزاریم.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · **Français** · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA : rétro-ingénierie de tout
|
||||
|
||||
@@ -276,7 +276,7 @@ Signalez les vulnérabilités via [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Historique des étoiles
|
||||
|
||||
🎉 **300 000 étoiles GitHub — merci !**
|
||||
🎉 **250 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.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · **Bahasa Indonesia** · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: Rekayasa Balik Apa Pun
|
||||
|
||||
@@ -297,7 +297,7 @@ Laporkan kerentanan melalui [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Riwayat Bintang
|
||||
|
||||
🎉 **300.000 bintang GitHub, terima kasih!**
|
||||
🎉 **250.000 bintang GitHub, terima kasih!**
|
||||
|
||||
Terima kasih kepada semua orang yang menggunakan REA, melaporkan bug, meminta fitur, menguji build, dan berkontribusi dalam perbaikan.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · **Italiano**
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -276,7 +276,7 @@ Segnala vulnerabilità tramite [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Cronologia delle stelle
|
||||
|
||||
🎉 **300.000 stelle su GitHub — grazie!**
|
||||
🎉 **250.000 stelle su GitHub — grazie!**
|
||||
|
||||
Grazie a tutti coloro che usano REA, segnalano bug, propongono funzionalità, testano le build e contribuiscono con correzioni.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · **日本語** · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA:あらゆるものをリバースエンジニアリング
|
||||
|
||||
@@ -274,7 +274,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## スター履歴
|
||||
|
||||
🎉 **GitHub スター 300,000 件、ありがとうございます!**
|
||||
🎉 **GitHub スター 250,000 件、ありがとうございます!**
|
||||
|
||||
REA の利用、バグ報告、機能の要望、ビルドのテスト、修正への貢献に感謝します。
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · **한국어** · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: 무엇이든 리버스 엔지니어링
|
||||
|
||||
@@ -283,7 +283,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## 스타 기록
|
||||
|
||||
🎉 **GitHub 스타 300,000개, 감사합니다!**
|
||||
🎉 **GitHub 스타 250,000개, 감사합니다!**
|
||||
|
||||
REA를 사용하고, 버그를 보고하고, 기능을 요청하고, 빌드를 테스트하고, 수정에 기여해 주신 모든 분께 감사드립니다.
|
||||
|
||||
|
||||
@@ -1,325 +0,0 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · **മലയാളം**
|
||||
|
||||
# REA: എന്തും Reverse Engineer ചെയ്യുക
|
||||
|
||||
### Binaries, applications, runtime behavior എന്നിവയുടെ Reverse Engineering-നായി ഒരൊറ്റ MCP.
|
||||
|
||||
**നിങ്ങൾക്ക് ഇഷ്ടപ്പെട്ട ഒരു feature കണ്ടോ? അത് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് binary തലത്തിലേക്ക് വരെ മനസ്സിലാക്കൂ.**
|
||||
|
||||
[](https://www.npmjs.com/package/rea-agents)
|
||||
[](../mcp-contracts.md#generated-catalog)
|
||||
[](#what-you-can-analyze)
|
||||
[](https://skills.sh/morluto/rea/reverse-engineer-anything)
|
||||
[](../../LICENSE)
|
||||
[](https://discord.gg/GkcryMnJDM)
|
||||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[വെബ്സൈറ്റ്](https://rea.tools/) · [ഗൈഡുകൾ](https://rea.tools/guides/) · [ഉദാഹരണങ്ങൾ](https://rea.tools/showcase/)**
|
||||
|
||||
[ദ്രുതാരംഭം](#ദ്രുതാരംഭം) · [REA എങ്ങനെ പ്രവർത്തിക്കുന്നു](#rea-എങ്ങനെ-പ്രവർത്തിക്കുന്നു) · [എന്തൊക്കെ വിശകലനം ചെയ്യാം](#എന്തൊക്കെ-വിശകലനം-ചെയ്യാം) · [ഉദാഹരണങ്ങൾ](#ഉദാഹരണങ്ങൾ) · [പതിവുചോദ്യങ്ങൾ](#പതിവുചോദ്യങ്ങൾ) · [ഡോക്യുമെന്റേഷൻ](#ഡോക്യുമെന്റേഷൻ)
|
||||
|
||||
<code>npx rea-agents setup</code>
|
||||
|
||||
</div>
|
||||
|
||||
> [!IMPORTANT]
|
||||
> REA ലഭ്യമാക്കേണ്ടത് [morluto/rea](https://github.com/morluto/rea),
|
||||
> [rea.tools](https://rea.tools/), അല്ലെങ്കിൽ [rea-agents npm package](https://www.npmjs.com/package/rea-agents) എന്നിവയിൽ നിന്നാണ്.
|
||||
> ഈ ഔദ്യോഗിക ഉറവിടങ്ങളിലെ ഇൻസ്റ്റലേഷൻ, റിലീസ് ലിങ്കുകൾ പിന്തുടരുക. സമാനമായ
|
||||
> repository പേരോ പകർത്തിയ README-യോ മാത്രം ഒരു download ഔദ്യോഗികമാണെന്ന് ഉറപ്പാക്കുന്നില്ല.
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../assets/rea-hopper-analysis.png" alt="ഒരു native binary പരിശോധിക്കുന്നതിനിടെ Hopper-ൽ REA അതിന്റെ analysis bridge ആരംഭിക്കുന്നു" width="1200" />
|
||||
|
||||
<br /><br />
|
||||
|
||||
<table aria-label="REA community">
|
||||
<tr>
|
||||
<td align="center" width="360">
|
||||
<a href="https://discord.gg/GkcryMnJDM">
|
||||
<img src="../assets/discord.svg" height="42" alt="Discord" /><br />
|
||||
<strong>Reverse Engineering കമ്മ്യൂണിറ്റിയിൽ ചേരുക</strong>
|
||||
</a><br />
|
||||
<sub>Discord · ചോദ്യോത്തരങ്ങൾ · അനുഭവങ്ങളും കണ്ടെത്തലുകളും പങ്കിടുക</sub>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
നിങ്ങളുടെ സ്വന്തം product-ൽ ഉൾപ്പെടുത്താൻ ആഗ്രഹിക്കുന്ന ഒരു feature ഏതെങ്കിലും app-ൽ കണ്ടോ? REA ഉപയോഗിച്ച് അത് പരിശോധിക്കാൻ നിങ്ങളുടെ agent-നോട് ആവശ്യപ്പെടുക. source code ഇല്ലാതെയും അതിന് app പരിശോധിക്കാനും feature എങ്ങനെ പ്രവർത്തിക്കുന്നുവെന്ന് വിശദീകരിക്കാനും അതിനുള്ള തെളിവുകൾ കാണിക്കാനും നിങ്ങളുടെ project-നായി അതിന് സമാനമായൊരു പതിപ്പ് നിർമ്മിക്കാനും കഴിയും.
|
||||
|
||||
Native binaries, JavaScript, Electron apps, .NET assemblies, websites എന്നിവ പരിശോധിക്കുന്നതിനുള്ള tools-ലേക്ക് REA നിങ്ങളുടെ agent-നെ ബന്ധിപ്പിക്കുന്നു. ഇതേ tools നിങ്ങളുടെ terminal-ൽ നിന്നും ഉപയോഗിക്കാം. വിശകലനം local ആയി നടക്കുന്നു; ഓരോ നിഗമനത്തിനും പിന്നിലെ തെളിവുകളും പരിമിതികളും ഫലങ്ങളിൽ ഉൾപ്പെടുന്നു.
|
||||
|
||||
Setup നിങ്ങളുടെ agent-ിൽ REA രജിസ്റ്റർ ചെയ്യുകയും അനുയോജ്യമായ workflow നിർദ്ദേശങ്ങൾ ഇൻസ്റ്റാൾ ചെയ്യുകയും ചെയ്യുന്നു. Native analysis-നായി നിലവിലുള്ള Hopper, Ghidra, അല്ലെങ്കിൽ IDA installation ഉപയോഗിക്കാം; അനുമതി നൽകിയാൽ setup-ന് Hopper ഇൻസ്റ്റാൾ ചെയ്യാനും കഴിയും. Static JavaScript analysis-ന് native analysis engine ആവശ്യമില്ല.
|
||||
|
||||
> **[REA വെബ്സൈറ്റ് സന്ദർശിക്കുക](https://rea.tools/)** — setup നിർദ്ദേശങ്ങൾക്കും ചിത്രങ്ങളോടുകൂടിയ ഗൈഡുകൾക്കും യഥാർത്ഥ case study-കൾക്കും.
|
||||
|
||||
## ദ്രുതാരംഭം
|
||||
|
||||
Linux-ൽ Ghidra, JADX, firmware tool launches, static JavaScript/Electron analysis എന്നിവയ്ക്ക് process ownership പരിശോധിക്കാൻ REA-യുടെ `PATH`-ൽ procps-compatible `ps` ആവശ്യമാണ്. പരിഹാര നടപടികൾ `docs/installation.md`-യിലെ "Linux owned-process prerequisite" എന്ന വിഭാഗത്തിൽ ലഭ്യമാണ്.
|
||||
|
||||
### നിങ്ങളുടെ agent സജ്ജമാക്കുക
|
||||
|
||||
Node.js-ഉം npm-ഉം ഇൻസ്റ്റാൾ ചെയ്തശേഷം ഈ command പ്രവർത്തിപ്പിക്കുക:
|
||||
|
||||
```bash
|
||||
npx rea-agents setup
|
||||
```
|
||||
|
||||
നിങ്ങൾ ഉപയോഗിക്കുന്ന agents തിരഞ്ഞെടുക്കുക, നിർദ്ദേശിച്ച മാറ്റങ്ങൾ പരിശോധിക്കുക, തുടർന്ന് അവയ്ക്ക് അനുമതി നൽകുക. നിലവിലുള്ള configuration-ന്റെ backup-ുകൾ സൂക്ഷിച്ചുകൊണ്ട് setup, REA-യുടെ MCP server-ഉം അനുയോജ്യമായ workflow നിർദ്ദേശങ്ങളും ചേർക്കും. അതിനുശേഷം നിങ്ങളുടെ agent വീണ്ടും ആരംഭിക്കുക.
|
||||
|
||||
Claude Code, Codex, Cursor, Gemini CLI, Grok Build, കൂടാതെ [മറ്റ് agents](../installation.md#supported-agents) എന്നിവയെ setup പിന്തുണയ്ക്കുന്നു. provider configuration-നും manual MCP registration-നും [installation and setup](../installation.md) കാണുക.
|
||||
|
||||
### നിങ്ങളുടെ agent-നോട് ആവശ്യപ്പെടുക
|
||||
|
||||
```text
|
||||
Notes app-ൽ search എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് മനസ്സിലാക്കി, അതിനുള്ള തെളിവുകൾ കാണിച്ചുതരികയും എന്റെ project-നായി സമാനമായൊരു feature നിർമ്മിക്കുകയും ചെയ്യുക.
|
||||
```
|
||||
|
||||
`Notes` എന്നതിന് പകരം നിങ്ങൾ പരിശോധിക്കാൻ ആഗ്രഹിക്കുന്ന app-ിന്റെയും മനസ്സിലാക്കേണ്ട feature-ിന്റെയും പേരുകൾ നൽകുക.
|
||||
|
||||
### Terminal ഉപയോഗിക്കുക
|
||||
|
||||
Extract ചെയ്ത JavaScript/Electron app directory അല്ലെങ്കിൽ ASAR പരിശോധിക്കുക:
|
||||
|
||||
```bash
|
||||
npx -y rea-agents@latest analyze-javascript-application /absolute/path/to/app --json
|
||||
```
|
||||
|
||||
ഫലത്തിൽ modules, imports, Electron boundaries, അവയ്ക്കുള്ള തെളിവുകൾ എന്നിവ ഉൾപ്പെടും. `/absolute/path/to/app` എന്നതിന് പകരം നിങ്ങളുടെ target-ന്റെ path നൽകുക; Windows-ൽ ഉദാഹരണത്തിന് `"D:/apps/example"` ഉപയോഗിക്കാം.
|
||||
|
||||
സാധാരണ ഉപയോഗത്തിനായി `rea` command ഇൻസ്റ്റാൾ ചെയ്യാൻ:
|
||||
|
||||
```bash
|
||||
npm install --global rea-agents
|
||||
rea --help
|
||||
```
|
||||
|
||||
Native analysis നടത്തുന്നതിന് മുമ്പ് ഒരു provider ക്രമീകരിക്കുക. Native commands, provider തിരഞ്ഞെടുക്കൽ, snapshots, scripting എന്നിവയ്ക്കായി [CLI and Evidence guide](../cli.md) കാണുക.
|
||||
|
||||
### REA അപ്ഡേറ്റ് ചെയ്യുക
|
||||
|
||||
REA-യിൽ പതിവായി മാറ്റങ്ങൾ വരുന്നു; പുതിയ releases-ൽ പല bug fixes-ഉം ഉൾപ്പെടുന്നു. നിങ്ങളുടെ installation ഏറ്റവും പുതിയ പതിപ്പിലേക്ക് അപ്ഡേറ്റ് ചെയ്യുക.
|
||||
|
||||
`npm install --global` അല്ലെങ്കിൽ `bun add --global` ഉപയോഗിച്ച് ഇൻസ്റ്റാൾ ചെയ്ത CLI-ക്കായി:
|
||||
|
||||
```bash
|
||||
rea update
|
||||
```
|
||||
|
||||
Bun-ന്റെ global updates-ന് Bun 1.2.17 അല്ലെങ്കിൽ അതിനുശേഷമുള്ള പതിപ്പ് ആവശ്യമാണ്. പഴയ Bun പതിപ്പാണെങ്കിൽ `rea update` പ്രവർത്തിപ്പിക്കുന്നതിന് മുമ്പ് Bun സ്വമേധയാ അപ്ഗ്രേഡ് ചെയ്യുക.
|
||||
|
||||
Agent registrations-ഉം skill-ഉം പുതുക്കാൻ, update കാണിക്കുന്ന setup command പ്രവർത്തിപ്പിക്കുക.
|
||||
|
||||
`npx` ഉപയോഗിക്കുന്നുവെങ്കിൽ, agent setup പുതുക്കാൻ:
|
||||
|
||||
```bash
|
||||
npx rea-agents@latest setup
|
||||
```
|
||||
|
||||
Setup-ൽ വരുത്തുന്ന മാറ്റങ്ങൾ പരിശോധിച്ച് നിങ്ങളുടെ agent വീണ്ടും ആരംഭിക്കുക. ഒറ്റത്തവണ മാത്രം ഉപയോഗിക്കുന്ന CLI commands-നായി command-ന് മുമ്പ് `npx rea-agents@latest` ഉപയോഗിക്കുക. Bun ഉപയോഗിക്കുമ്പോൾ `npx rea-agents@latest`-ന് പകരം `bunx rea-agents@latest` ഉപയോഗിക്കുക.
|
||||
|
||||
## REA എങ്ങനെ പ്രവർത്തിക്കുന്നു
|
||||
|
||||
Target പരിശോധിക്കാനും പ്രസക്തമായ code-ന്റെ പാത പിന്തുടരാനും നിങ്ങളുടെ agent MCP വഴി REA-യെ വിളിക്കുന്നു. REA കണ്ടെത്തലുകളും അവയ്ക്കുള്ള തെളിവുകളും തിരികെ നൽകുന്നു. തുടർന്ന് agent കൂടുതൽ ചോദ്യങ്ങൾ ചോദിക്കാനും പെരുമാറ്റം വിശദീകരിക്കാനും implementation എഴുതുകയും പരിശോധിക്കുകയും ചെയ്യാനും അവ ഉപയോഗിക്കുന്നു. CLI commands-ഉം ഇതേ workflows ഉപയോഗിക്കുന്നു.
|
||||
|
||||

|
||||
|
||||
[പൂർണ്ണ വലുപ്പത്തിലുള്ള ചിത്രം തുറക്കുക](../../website/public/assets/figures/rea-investigation-flow.svg).
|
||||
|
||||
<a id="current-status"></a>
|
||||
|
||||
## എന്തൊക്കെ വിശകലനം ചെയ്യാം
|
||||
|
||||
REA-യ്ക്ക് Node.js 22.x (>=22.19), 24.x (>=24.11), അല്ലെങ്കിൽ 26+ പതിപ്പും npm-ഉം ആവശ്യമാണ്. Target അനുസരിച്ച് അധിക tools-ഉം host support-ഉം വ്യത്യാസപ്പെടും:
|
||||
|
||||
| Target | REA നൽകുന്ന ഫലങ്ങൾ | ആവശ്യകതകളും ഗൈഡും |
|
||||
| ---------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Native binaries | Pseudocode, assembly, strings, symbols, calls, references | Hopper, Ghidra അല്ലെങ്കിൽ IDA; [native analysis](../native-investigation.md) |
|
||||
| Offline ELF layout | Sections, segments, യഥാർത്ഥ symbols/relocations, static mitigation candidates | Linux x64-ൽ caller നൽകുന്ന pwntools; [binary diagnostics](../binary-diagnostics.md) |
|
||||
| Go binaries | ഉൾച്ചേർത്ത compiler version, modules, replacements, build settings | Built-in static ELF/PE/thin Mach-O പരിശോധന; Go installation ആവശ്യമില്ല |
|
||||
| Rust binaries | ഉൾച്ചേർത്ത cargo-auditable crate പേരുകൾ, versions, sources, dependency edges | Built-in static ELF/PE/thin Mach-O പരിശോധന; [Rust binaries](../rust-binaries.md) |
|
||||
| WASM artifact | Validation, sections, കൃത്യമായ import/export WAT രൂപങ്ങൾ, decoded WAT | Caller നൽകുന്ന WABT 1.0.42; `inspect_wasm_artifact` |
|
||||
| EVM bytecode | Dispatch selectors, byte offsets, അനുമാനിച്ച arguments, mutability | Linux x64-ൽ local raw/hex carrier; [offline EVM guide](../evm-bytecode.md) |
|
||||
| SQLite databases | Tables, columns, indexes, views, triggers, തിരഞ്ഞെടുത്ത സാധാരണ table rows | Local database/WAL snapshot; native SQLite പരിമിതികളോടെ Node.js 24.x >=24.15 അല്ലെങ്കിൽ 26+ |
|
||||
| Recorded Linux crashes | Raw notes, രേഖപ്പെടുത്തിയ ഓരോ thread-ന്റെയും registers/signals, ഐച്ഛിക mapping candidates | Linux x64-ൽ caller നൽകുന്ന pwntools; ഐച്ഛിക GDB/pwndbg; [recorded crashes](../recorded-crashes.md) |
|
||||
| JavaScript / Electron | Modules, imports, source maps, routes, IPC, native add-on ബന്ധങ്ങൾ | Node.js, npm; Linux: procps-compatible `ps`; [application analysis](../javascript-application-workflows.md) |
|
||||
| Websites | Page structure, scripts, network observations, ആവശ്യപ്പെട്ട screenshots | Chrome-family browser; [browser analysis](../browser-observation.md) |
|
||||
| Saved network captures | Requests, responses, പുറത്തുകാണുന്ന payload-ുകൾ, source locations | HAR അല്ലെങ്കിൽ Fiddler Everywhere SAZ; native mitmproxy-നായി Linux-ൽ mitmdump; [capture guide](../web-network-captures.md) |
|
||||
| .NET assemblies | Metadata, CIL instructions, പ്രഖ്യാപിച്ച native dependencies, build comparisons | ഒന്നും ആവശ്യമില്ല (static മാത്രം); [managed-code guide](../managed-code-analysis.md) |
|
||||
| Android APKs | Manifest declarations, classes, decompiled methods, references | Linux/macOS/Windows x64-ൽ Headless JADX-ഉം full JDK-ഉം; [Android guide](../android-analysis.md) |
|
||||
| Android devices | Devices, packages, processes, logs, dumps, screen captures, APK/file transfers | Caller നൽകുന്ന adb (emulator അല്ലെങ്കിൽ hardware); [ADB guide](../adb-device-analysis.md) |
|
||||
| JEB projects | Engine-backed project units, artifact digests, type/method pseudo-code | MCP സേവനം നൽകുന്ന caller ആരംഭിച്ച JEB client; REA_JEB_MCP_URL ഉപയോഗിച്ച് തിരഞ്ഞെടുക്കുക; [JEB guide](../jeb-analysis.md) |
|
||||
| Android resources | Decoded manifest, string tables, locales, version വിവരങ്ങൾ | Caller നൽകുന്ന Apktool launcher; [resource guide](../apktool-resource-analysis.md) |
|
||||
| Flutter apps | Dart snapshot hash, ഓരോ ABI-യിലെയും library digests, engine build provenance | ഒന്നും ആവശ്യമില്ല (static APK parsing); [Flutter guide](../flutter-analysis.md) |
|
||||
| Firmware | Regions, extraction results, native-analysis handoffs | Linux-ൽ Binwalk / Unblob; [firmware guide](../firmware-analysis.md) |
|
||||
| Recorded packets | തിരഞ്ഞെടുത്ത fields, ആവർത്തിക്കുന്ന values, filters, decode-as rules | Linux: TShark 4.x + prlimit; [capture guide](../packet-captures.md) |
|
||||
| Packet summaries | Endpoints, DNS, TLS SNI, protocol distribution, HTTP requests | Caller നൽകുന്ന tshark, capinfos (Linux-ൽ പരിശോധിച്ചത്); [pcap guide](../pcap-analysis.md) |
|
||||
| Recorded logic signals | Decoder annotations, sample ranges, diagnostics | Linux: sigrok-cli 0.7.2 + prlimit; [signal recordings](../signal-recordings.md) |
|
||||
| Packages and resources | File inventories, digests, plists, Apple bundle ഘടന, extracted resources | [Artifact and JavaScript guide](../javascript-artifact-reconstruction.md), [Apple applications](../apple-application-analysis.md) |
|
||||
| Process behavior | Terminal output, interactions, exit, filesystem observations, run comparisons | Native PTY ഉള്ള Linux/macOS; [process capture](../process-capture.md) |
|
||||
|
||||
Static JavaScript, .NET പരിശോധനകൾ application പ്രവർത്തിപ്പിക്കാതെ നൽകിയ files വായിച്ചാണ് നടത്തുന്നത്. Runtime capture, നിങ്ങളുടെ user permissions ഉപയോഗിച്ച് തിരഞ്ഞെടുത്ത target പ്രവർത്തിപ്പിക്കുകയോ അതുമായി ഇടപെടുകയോ ചെയ്യുന്നു; ഓരോ runtime guide-ലും അതിന്റെ പ്രത്യാഘാതങ്ങൾ വിശദീകരിച്ചിട്ടുണ്ട്.
|
||||
|
||||
Offline native-binary പരിശോധനയ്ക്കായി REA, caller നൽകുന്ന GNU objdump, Rizin എന്നിവയും പിന്തുണയ്ക്കുന്നു. Provider setup, CLI commands, Evidence-ന്റെ പരിമിതികൾ എന്നിവയ്ക്കായി [reverse-engineering tools guide](../reverse-engineering-tools.md) കാണുക. ഈ providers ഒന്നും REA ഇൻസ്റ്റാൾ ചെയ്യുകയോ അപ്ഡേറ്റ് ചെയ്യുകയോ ചെയ്യുന്നില്ല.
|
||||
|
||||
<a id="choosing-a-deep-analysis-provider"></a>
|
||||
|
||||
Native formats-ഉം host support-ഉം provider അനുസരിച്ച് വ്യത്യാസപ്പെടും. [Hopper and Ghidra setup](../installation.md#hopper), [IDA guide](../ida-provider.md) (ഐച്ഛിക native MCP bridge ഉൾപ്പെടെ), [Kuna decompiler guide](../kuna-provider.md), [പരീക്ഷണഘട്ടത്തിലുള്ള Windows Ghidra support](../windows-ghidra-p0.md) എന്നിവ കാണുക.
|
||||
Ghidra, [16-bit DOS analysis](../ghidra-dos.md)-ഉം പിന്തുണയ്ക്കുന്നു.
|
||||
വലിയ binaries-നായി `REA_GHIDRA_STARTUP_TIMEOUT_MS` അല്ലെങ്കിൽ `REA_HOPPER_STARTUP_TIMEOUT_MS` ഉപയോഗിച്ച് provider-ന്റെ startup deadline വർധിപ്പിക്കുക.
|
||||
Provider തിരഞ്ഞെടുക്കാൻ [CLI guide](../cli.md#choose-a-provider) കാണുക.
|
||||
ഏറ്റവും പുതിയ npm release-നുശേഷം ചേർത്ത features അറിയാൻ [release availability](../installation.md#released-package-and-main) പരിശോധിക്കുക.
|
||||
|
||||
## ഉദാഹരണങ്ങൾ
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
|
||||
### DX-Ball: sound-pan കണക്കുകൂട്ടൽ പുനർനിർമ്മിക്കുക
|
||||
|
||||
ഒരു sound call-നെ അതിന്റെ position-to-pan helper വരെ പിന്തുടരുക, instructions പരിശോധിക്കുക, അപൂർണ്ണമായ pseudocode-നെ C-യാക്കി മാറ്റുക. ഈ പുനർനിർമ്മാണം യഥാർത്ഥ x86-ലെ 3,205 test cases വിജയിക്കുകയും compile ചെയ്ത function-ന്റെ 63 bytes-ഉം അതേപടി പുനരുത്പാദിപ്പിക്കുകയും ചെയ്യുന്നു.
|
||||
|
||||
[Case study വായിക്കുക](https://rea.tools/showcase/dx-ball/) ·
|
||||
[പുനർനിർമ്മാണ repository](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: Electron clipboard bridge പിന്തുടരുക
|
||||
|
||||
Renderer-ന്റെ clipboard API കണ്ടെത്തി, അതിനെ preload-ഉം IPC-ഉം വഴി main process വരെ പിന്തുടർന്ന് rich clipboard format പരിശോധിക്കുക.
|
||||
|
||||
[Case study വായിക്കുക](https://rea.tools/showcase/notion/)
|
||||
|
||||
### TH04: DOS bullet-ring കണക്കുകൂട്ടൽ വീണ്ടെടുക്കുക
|
||||
|
||||
യഥാർത്ഥ PC-98 game-ന്റെ 16-bit instructions പരിശോധിക്കുക, fixed, aimed angle കണക്കുകൂട്ടലുകൾ വീണ്ടെടുക്കുക, പുനർനിർമ്മിച്ച C++-നെ ചരിത്രപരമായ compiler output-ുമായി താരതമ്യം ചെയ്യുക.
|
||||
|
||||
[Case study വായിക്കുക](https://rea.tools/showcase/th04/) ·
|
||||
[പുനർനിർമ്മാണ repository](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
REA ഉപയോഗിച്ച് നിങ്ങൾ രസകരമായ എന്തെങ്കിലും പരിശോധിച്ചിട്ടുണ്ടെങ്കിൽ അത് കാണാൻ ഞങ്ങൾ ആഗ്രഹിക്കുന്നു. പരിശോധിച്ച target, നിങ്ങളുടെ ചോദ്യം, REA എങ്ങനെ സഹായിച്ചു, നിങ്ങൾ കണ്ടെത്തിയത് എന്നിവ ഉൾപ്പെടുത്തി [issue](https://github.com/morluto/rea/issues) അല്ലെങ്കിൽ [pull request](https://github.com/morluto/rea/pulls) വഴി നിങ്ങളുടെ case പങ്കിടുക.
|
||||
|
||||
## പതിവുചോദ്യങ്ങൾ
|
||||
|
||||
<details>
|
||||
<summary><strong>ഏതൊക്കെ agents-ന് REA ഉപയോഗിക്കാം?</strong></summary>
|
||||
|
||||
Local MCP servers പിന്തുണയ്ക്കുന്ന ഏത് agent-നും REA ഉപയോഗിക്കാം. Setup, [പിന്തുണയ്ക്കുന്ന agents](../installation.md#supported-agents) ക്രമീകരിക്കുന്നു; മറ്റ് clients-ന് [manual MCP registration](../installation.md#mcp-registry) ഉപയോഗിക്കാം.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Hopper, Ghidra അല്ലെങ്കിൽ IDA ആവശ്യമാണോ?</strong></summary>
|
||||
|
||||
ആഴത്തിലുള്ള native analysis-ന് ഇവയിൽ ഒന്ന് ആവശ്യമാണ്. Static JavaScript, .NET പരിശോധനകൾ native analysis engine ഇല്ലാതെയും പ്രവർത്തിക്കും. അനുമതി ലഭിച്ചാൽ setup-ന് Hopper ഇൻസ്റ്റാൾ ചെയ്യാം; Ghidra, IDA എന്നിവയ്ക്കായി നിങ്ങളുടെ നിലവിലുള്ള installations ഉപയോഗിക്കുന്നു. [Provider setup](../installation.md#hopper) കാണുക.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Hopper ആദ്യം ആരംഭിക്കേണ്ടതുണ്ടോ?</strong></summary>
|
||||
|
||||
ഒരു operation-ന് ആവശ്യമാകുമ്പോൾ REA Hopper ആരംഭിക്കും. macOS-ൽ ആദ്യമായി പ്രവർത്തിപ്പിക്കുമ്പോൾ demo mode തിരഞ്ഞെടുക്കാനോ license activate ചെയ്യാനോ ആവശ്യപ്പെടുന്ന dialog പ്രത്യക്ഷപ്പെടാം. ആദ്യ CLI/MCP operation അല്ലെങ്കിൽ unattended job നടത്തുന്നതിന് മുമ്പ് അതേ user session-ൽ ആ prompt പൂർത്തിയാക്കുക. ആവശ്യമെങ്കിൽ Hopper സ്വമേധയാ തുറക്കുക. [Hopper startup and troubleshooting](../installation.md#launcher-paths-and-troubleshooting) കാണുക.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>skills.sh-ൽ നിന്ന് skill ഇൻസ്റ്റാൾ ചെയ്യുന്നത് എന്താണ് ചെയ്യുന്നത്?</strong></summary>
|
||||
|
||||
ഈ skill നിങ്ങളുടെ agent-ന് അന്വേഷണ നിർദ്ദേശങ്ങൾ നൽകുന്നു. REA-യുടെ MCP server രജിസ്റ്റർ ചെയ്യാനും അനുയോജ്യമായ നിർദ്ദേശങ്ങൾ ഇൻസ്റ്റാൾ ചെയ്യാനും `npx rea-agents setup` ഉപയോഗിക്കുക; തുടർന്ന് നിങ്ങളുടെ agent വീണ്ടും ആരംഭിക്കുക. [Skill-only installation](../installation.md#skill-only-installation) കാണുക.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>REA ഏത് തരത്തിലുള്ള code ആണ് നൽകുന്നത്?</strong></summary>
|
||||
|
||||
Native analysis pseudocode-ഉം assembly-ഉം നൽകുന്നു. JavaScript/Electron analysis modules-ഉം അവയുടെ ബന്ധങ്ങളും വീണ്ടെടുക്കുന്നു. ഈ കണ്ടെത്തലുകൾ ഉപയോഗിച്ച് നിങ്ങളുടെ agent implementation എഴുതുകയും പരിശോധിക്കുകയും ചെയ്യും; പ്രായോഗിക ഉദാഹരണങ്ങൾക്കായി [ഉദാഹരണങ്ങൾ](#showcases) കാണുക.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>REA എന്റെ app upload ചെയ്യുമോ?</strong></summary>
|
||||
|
||||
REA targets local ആയി വിശകലനം ചെയ്യുന്നു. Tool-ൽ നിന്നുള്ള ഫലങ്ങൾ നിങ്ങളുടെ agent-ന് ലഭിക്കും; അതിന്റെ model provider-ന് സ്വന്തമായ data policy ഉണ്ടായിരിക്കും.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>ഒരു bug നേരിട്ടാൽ എന്തുചെയ്യണം?</strong></summary>
|
||||
|
||||
ആദ്യം അപ്ഡേറ്റ് ചെയ്യുക; പുതിയ release-ൽ ആ പ്രശ്നത്തിനുള്ള പരിഹാരം ഇതിനകം ഉണ്ടായേക്കാം.
|
||||
|
||||
`npm install --global` അല്ലെങ്കിൽ `bun add --global` ഉപയോഗിച്ച് ഇൻസ്റ്റാൾ ചെയ്ത CLI-ക്കായി:
|
||||
|
||||
```bash
|
||||
rea update
|
||||
```
|
||||
|
||||
`npx` വഴി agent setup നടത്തുന്നതിനായി:
|
||||
|
||||
```bash
|
||||
npx rea-agents@latest setup
|
||||
```
|
||||
|
||||
നിങ്ങൾ agent ഉപയോഗിക്കുന്നുണ്ടെങ്കിൽ, [setup പുതുക്കൽ](#update-rea) പൂർത്തിയാക്കി അത് വീണ്ടും ആരംഭിക്കുക. അതേ task വീണ്ടും ശ്രമിക്കുക. പ്രശ്നം തുടരുകയാണെങ്കിൽ, നിങ്ങളുടെ REA version, target type, പ്രശ്നം ആവർത്തിക്കാൻ ആവശ്യമായ ഘട്ടങ്ങൾ, error output എന്നിവ ഉൾപ്പെടുത്തി [issue തുറക്കുക](https://github.com/morluto/rea/issues).
|
||||
|
||||
</details>
|
||||
|
||||
## ഡോക്യുമെന്റേഷൻ
|
||||
|
||||
വെബ്സൈറ്റിലെ [പ്രായോഗിക ഗൈഡുകൾ](https://rea.tools/guides/) ഉപയോഗിച്ച് തുടങ്ങുക.
|
||||
കൃത്യമായ options, prerequisites, result contracts എന്നിവയ്ക്കായി:
|
||||
|
||||
- [Installation and setup](../installation.md): agent registration, provider configuration, updates, uninstall.
|
||||
- [Readiness and troubleshooting](../installation.md#check-readiness-for-your-task): ഒരു agent-ന്റെയോ analysis engine-ന്റെയോ പ്രശ്നങ്ങൾ കണ്ടെത്തുക.
|
||||
- [CLI and Evidence](../cli.md): commands, provider തിരഞ്ഞെടുക്കൽ, snapshots, import/export, exit statuses.
|
||||
- [MCP contracts](../mcp-contracts.md), [agent prompts](../mcp-prompts.md): tool results, sessions, guided investigations.
|
||||
- [Tool catalog](../mcp-contracts.md#generated-catalog): tools, providers, CLI commands എന്നിവയുടെ സ്വയമേവ സൃഷ്ടിച്ച പട്ടിക.
|
||||
- [Roadmap](../roadmap.md): ആസൂത്രണം ചെയ്ത പ്രവർത്തനങ്ങളും capability trackers-ഉം.
|
||||
|
||||
സുരക്ഷാ ദുർബലതകൾ [SECURITY.md](../../SECURITY.md) വഴി റിപ്പോർട്ട് ചെയ്യുക.
|
||||
|
||||
## Star ചരിത്രം
|
||||
|
||||
🎉 **250,000 GitHub stars — നന്ദി!**
|
||||
|
||||
REA ഉപയോഗിക്കുന്നവർക്കും, bugs റിപ്പോർട്ട് ചെയ്യുന്നവർക്കും, features ആവശ്യപ്പെടുന്നവർക്കും, builds പരിശോധിക്കുന്നവർക്കും, fixes സംഭാവന ചെയ്യുന്നവർക്കും നന്ദി.
|
||||
|
||||
<a href="https://www.star-history.com/?repos=morluto%2Frea&type=date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=morluto/rea&type=date&theme=dark&legend=top-left" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=morluto/rea&type=date" />
|
||||
<img alt="REA GitHub star ചരിത്രം" src="https://api.star-history.com/chart?repos=morluto/rea&type=date" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## നിരാകരണം
|
||||
|
||||
ഉത്തരവാദിത്തത്തോടെ ഉപയോഗിക്കുന്നതിനുള്ള മാർഗനിർദ്ദേശങ്ങൾക്ക് [DISCLAIMER.md](../../DISCLAIMER.md) കാണുക.
|
||||
|
||||
നിയമവിരുദ്ധമോ അനുമതിയില്ലാത്തതോ ആയ ഉപയോഗത്തെക്കുറിച്ചുള്ള project-ന്റെ നിലപാട് എല്ലാ REA versions-നും distribution channels-നും platforms-നും ബാധകമാണ്; ഓരോ copy-യും അതിന് ബാധകമായ licenses നിലനിർത്തുന്നു.
|
||||
|
||||
നിയമാനുസൃതമായ research, education, interoperability, software preservation, കൂടാതെ നിങ്ങൾക്ക് സ്വന്തമായതോ പരിശോധിക്കാൻ അനുമതിയുള്ളതോ ആയ software-ന്റെ analysis എന്നിവയ്ക്കാണ് REA ഉദ്ദേശിച്ചിരിക്കുന്നത്.
|
||||
|
||||
## സംഭാവനകൾ
|
||||
|
||||
REA-യ്ക്കായി നിങ്ങളുടെ സഹായം ഞങ്ങൾ സ്വാഗതം ചെയ്യുന്നു! bug റിപ്പോർട്ട് ചെയ്യാനോ feature നിർദ്ദേശിക്കാനോ [issue തുറക്കുക](https://github.com/morluto/rea/issues), code അല്ലെങ്കിൽ docs മെച്ചപ്പെടുത്താൻ [pull request അയയ്ക്കുക](https://github.com/morluto/rea/pulls).
|
||||
|
||||
Development setup-നും checks-നും [CONTRIBUTING.md](../../CONTRIBUTING.md), verification lanes-നായി [testing](../testing.md), project ഘടനയ്ക്കായി [architecture map](../architecture.mermaid) എന്നിവ കാണുക.
|
||||
|
||||
## ലൈസൻസ്
|
||||
|
||||
[MIT](../../LICENSE)
|
||||
|
||||
REA-യുടെ രചയിതാക്കൾ സൃഷ്ടിച്ച code MIT license പ്രകാരമാണ് ലൈസൻസ് ചെയ്തിരിക്കുന്നത്. Third-party material അതിന്റെ സ്വന്തം licenses-ഉം copyright notices-ഉം നിലനിർത്തുന്നു; dependencies-ന്റെ പട്ടിക, നിലനിർത്തിയ license text-ുകൾ, external tool നിബന്ധനകൾ എന്നിവയ്ക്കായി [Third-party notices](../../THIRD_PARTY_NOTICES.md) കാണുക.
|
||||
|
||||
**IDA Pro / Hex-Rays decompilers, Hopper, JEB എന്നിവ ഉൾപ്പെടെയുള്ള commercial tools നിയമാനുസൃതമായി സ്വന്തമാക്കുകയും അവയുടെ ബാധകമായ licenses പ്രകാരം ഉപയോഗിക്കാൻ അനുമതിയുണ്ടെന്ന് ഉറപ്പാക്കുകയും വേണം.** REA ഒരു tool license-ഓ key-യോ activation entitlement-ഓ നൽകുന്നില്ല. Trials-ഉം demos-ഉം ഉൾപ്പെടെ vendor നിബന്ധനകൾക്ക് വിധേയമാണ്; ഇതിൽ user, feature, automation, output sharing നിയന്ത്രണങ്ങളും ഉൾപ്പെടാം. Cracked copies, മോഷ്ടിച്ച keys, അനുമതിയില്ലാത്ത key sharing, license നിയന്ത്രണങ്ങൾ മറികടക്കൽ എന്നിവയ്ക്ക് അനുമതിയില്ല. ഈ മാർഗനിർദ്ദേശം MIT അല്ലെങ്കിൽ third-party licenses-ൽ മാറ്റം വരുത്തുന്നില്ല.
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · **Polski** · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -272,7 +272,7 @@ Zgłaszaj podatności zgodnie z [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Historia gwiazdek
|
||||
|
||||
🎉 **300 000 gwiazdek na GitHubie — dziękujemy!**
|
||||
🎉 **250 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.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · **Português (Brasil)** · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: Faça engenharia reversa de qualquer coisa
|
||||
|
||||
@@ -272,7 +272,7 @@ Relate vulnerabilidades conforme [SECURITY.md](../../SECURITY.md).
|
||||
|
||||
## Histórico de estrelas
|
||||
|
||||
🎉 **300.000 estrelas no GitHub — muito obrigado!**
|
||||
🎉 **250.000 estrelas no GitHub — muito obrigado!**
|
||||
|
||||
Obrigado a todos que usam o REA, relatam bugs, sugerem funcionalidades, testam builds e contribuem com correções.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · **Русский** · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: Реверс-инжиниринг чего угодно
|
||||
|
||||
@@ -272,7 +272,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## История звёзд
|
||||
|
||||
🎉 **300 000 звёзд на GitHub — спасибо!**
|
||||
🎉 **250 000 звёзд на GitHub — спасибо!**
|
||||
|
||||
Спасибо всем, кто использует REA, сообщает об ошибках, предлагает новые функции, тестирует сборки и помогает с исправлениями.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · **ไทย** · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -272,7 +272,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## ประวัติดาว
|
||||
|
||||
🎉 **300,000 ดาวบน GitHub — ขอบคุณทุกคน!**
|
||||
🎉 **250,000 ดาวบน GitHub — ขอบคุณทุกคน!**
|
||||
|
||||
ขอบคุณทุกคนที่ใช้ REA รายงานบั๊ก เสนอฟีเจอร์ ทดสอบบิลด์ และช่วยแก้ไข
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · **Türkçe** · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: Her şeyi tersine mühendislikle inceleyin
|
||||
|
||||
@@ -277,7 +277,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 250.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.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · **Українська** · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: Реверс-інжиніринг будь-чого
|
||||
|
||||
@@ -272,7 +272,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## Історія зірок
|
||||
|
||||
🎉 **300 000 зірок на GitHub — дякуємо!**
|
||||
🎉 **250 000 зірок на GitHub — дякуємо!**
|
||||
|
||||
Дякуємо всім, хто використовує REA, повідомляє про помилки, пропонує нові функції, тестує збірки й допомагає з виправленнями.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · **Tiếng Việt** · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA: Kỹ thuật dịch ngược cho mọi thứ
|
||||
|
||||
@@ -272,7 +272,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!**
|
||||
🎉 **250.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.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · **繁體中文** · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA:逆向一切
|
||||
|
||||
@@ -278,7 +278,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## Star 歷史
|
||||
|
||||
🎉 **GitHub Star 達到 300,000 個,感謝大家!**
|
||||
🎉 **GitHub Star 達到 250,000 個,感謝大家!**
|
||||
|
||||
感謝每一位使用 REA、報告錯誤、提出功能需求、測試建置和貢獻修復的朋友。
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · **简体中文** · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md)
|
||||
|
||||
# REA:逆向一切
|
||||
|
||||
@@ -278,7 +278,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## Star 历史
|
||||
|
||||
🎉 **GitHub Star 达到 300,000 个,感谢大家!**
|
||||
🎉 **GitHub Star 达到 250,000 个,感谢大家!**
|
||||
|
||||
感谢每一位使用 REA、报告错误、提出功能需求、测试构建和贡献修复的朋友。
|
||||
|
||||
|
||||
@@ -61,21 +61,9 @@ The outer provider owns both processes and one stable core snapshot. An owned
|
||||
Python launcher lowers inherited soft limits before replacing itself with GDB.
|
||||
GDB starts without initfiles, auto-load, debuginfod or automatic shared-library
|
||||
loading. Owned empty library search paths and caches are used, with plugin
|
||||
updates disabled. Debug-file lookup is also restricted to the owned empty
|
||||
search directory. GDB 16 can otherwise locate the recorded executable independently
|
||||
of these settings. While opening the core, fixed package code temporarily selects
|
||||
`/proc/self/exe` (the already running debugger) with `exec-file`, without loading
|
||||
symbols or running an inferior. This occupies GDB's executable slot and prevents
|
||||
its automatic executable discovery. The validated decoder profile selects the
|
||||
core architecture explicitly, so the placeholder cannot select it instead. The
|
||||
bridge discards that selection with `file` before querying mapping candidates,
|
||||
and verifies the core connection and absence of a main symbol file. Before launching GDB, the provider also checks
|
||||
source-bound `NT_FILE` descriptors: mapping names must be absolute Unix paths
|
||||
without dot segments. Relative names bypass GDB's sysroot, and traversal can
|
||||
escape it. Unresolved or unsafe mapping coverage refuses debugger enrichment
|
||||
while retaining the basic decoded observation and original bytes. No caller GDB
|
||||
command language is exposed. The exact observed GDB/plugin version strings are
|
||||
retained.
|
||||
updates disabled. Fixed package code verifies a core connection and no paired
|
||||
executable before querying mapping candidates. No caller GDB command language is
|
||||
exposed. The exact observed GDB/plugin version strings are retained.
|
||||
|
||||
Mapping names are producer display metadata, with unknown current file identity.
|
||||
Map permissions are derived from reported flags; zero/unfamiliar flags leave
|
||||
@@ -105,6 +93,4 @@ GDB/Python/pwndbg/strace. Fixture generation explicitly launches its owned test
|
||||
program; subsequent inspection only reads the resulting core. Real acceptance
|
||||
checks recorded threads, high registers, missing/malformed notes, opaque owners,
|
||||
CLI/MCP parity, optional debugger context and historical PID collision with an
|
||||
owned live sentinel. The syscall trace also rejects access to the still-present
|
||||
source executable. The CI workflow defines Ubuntu 24.04 and Debian 13 (GDB 16)
|
||||
container lanes. Original inputs and host configuration remain unchanged.
|
||||
owned live sentinel. Original inputs and host configuration remain unchanged.
|
||||
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": "76467478+morluto@users.noreply.github.com",
|
||||
"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": "76467478+morluto@users.noreply.github.com",
|
||||
"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": "76467478+morluto@users.noreply.github.com",
|
||||
"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 <noreply@anthropic.com>",
|
||||
"parents": ["bb212ffecb47e129cc569b9867b2b6e7c9b65685"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kaoru0822",
|
||||
"email": "kanadekitauji@proton.me",
|
||||
"user": {
|
||||
"login": "kaoru0822-kitauji",
|
||||
"__typename": "User"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Claude Opus 5.5",
|
||||
"email": "noreply@anthropic.com",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -57,10 +57,7 @@ triggers or arbitrary SQL.
|
||||
Rows are optional. `table` selects one exact ordinary-table name. `columns`
|
||||
(CLI repeated `--column`) selects exact visible column names in the requested
|
||||
order; omission selects all visible columns, including generated columns.
|
||||
Unselected cells are not evaluated or projected. Malformed column-name bytes
|
||||
cause a format refusal when all columns are requested. In inventory scope, an explicit valid subset can
|
||||
still be sampled without decoding unrelated malformed column names.
|
||||
Column selection requires a
|
||||
Unselected cells are not evaluated or projected. Column selection requires a
|
||||
table and at least one name; empty-string identifiers are valid. `row_limit`
|
||||
requires `table`, defaults to 20 and accepts positive safe integers. Samples
|
||||
remain subject to the byte and worker resource limits below, regardless of row count. The result reports
|
||||
|
||||
+6
-45
@@ -110,14 +110,9 @@ rendered declarations. Keep canonical rejection checks separate from the
|
||||
intentionally reduced compact advertisement, and probe actual client renderers
|
||||
when changing schema representations.
|
||||
|
||||
The reused CLI boundary workers cap V8 old space at 384 MiB for ordinary runs
|
||||
and 512 MiB with coverage enabled. Covered ADB fixtures exhaust the ordinary
|
||||
384 MiB budget; those fixtures also complete with the shared CLI graph preloaded
|
||||
at 512 MiB. This is a measured capacity control, not a suite-wide speedup claim.
|
||||
Both profiles keep the
|
||||
same bounded worker count, and spawned REA processes retain their own heap
|
||||
settings. Explicitly disabling coverage retains the ordinary profile; coverage
|
||||
provider options alone do not enable instrumentation.
|
||||
The reused CLI boundary workers cap V8 old space at 384 MiB, based on their
|
||||
profiled allocation and cleanup behavior. This encourages collection between
|
||||
files; spawned REA processes retain their own heap settings.
|
||||
|
||||
Vitest worker limits do not bound subprocesses launched within a test. Bound
|
||||
those batches separately so repeated CLI validation cannot oversubscribe the
|
||||
@@ -221,12 +216,6 @@ controlled production seam for interleavings that cannot be reproduced reliably.
|
||||
| Cleanup fails after success or primary failure | Public output retains the completed observation or primary diagnostic, remaining resources, and owner recovery action. Restore the denied resource and verify the owning cleanup retry. |
|
||||
| Target exits without an acknowledgement, or transport disappears while it stays alive | Positive owned exit proof resolves target lifetime; other resources still need cleanup. Lost transport alone does not prove exit. Verify unrelated/attached targets survive and same-connection recovery works when supported. |
|
||||
|
||||
Shared process-supervision controls separate leader exit from output closure.
|
||||
Cover output during held or failed cleanup, bounded retention and drain timeout,
|
||||
retry, and borrowed stream authority. The POSIX inherited-stderr control uses a
|
||||
separate pipe as a release barrier after leader exit; it does not establish
|
||||
native Windows Job Object behavior.
|
||||
|
||||
Synchronize cancellation with the finalization boundary being tested; a fixed
|
||||
delay after dispatch does not establish that phase. Use markers, barriers, or
|
||||
owned cleanup seams while preserving real cleanup where feasible. Check server
|
||||
@@ -236,21 +225,6 @@ cover cancellation during final cleanup.
|
||||
Use explicit abort reasons and assert their identity at admission and after
|
||||
provider completion, alongside retained observations and cleanup state.
|
||||
|
||||
Electron fuse regressions cover actual descriptor close denial and retry through
|
||||
the built CLI, same-connection MCP recovery, mixed descriptor outcomes, and
|
||||
server shutdown. Controlled seams cover cancellation during final close and
|
||||
after reader finalization, plus active-provider shutdown during preflight.
|
||||
They preserve real filesystem cleanup where possible; mocked launch boundaries
|
||||
do not establish real Electron teardown or naturally occurring OS failures.
|
||||
|
||||
Active Electron cleanup controls retain independent transport and process-family
|
||||
owners, block replacement captures until recovery, and retry only unresolved
|
||||
owners. Cover late close acknowledgement and rejection after a wait deadline,
|
||||
opaque rejection reasons, cancellation during failed finalization, and missing
|
||||
lineage followed by a confirmed passive family census. Windows controls require
|
||||
a fresh lineage observation and do not signal cached descendant PIDs after root
|
||||
termination. Simulated Windows controls do not establish native Windows behavior.
|
||||
|
||||
For atomic writes, exercise cancellation on both sides of the documented commit
|
||||
point and preserve any publication receipt. A late interruption does not prove
|
||||
that no output was published.
|
||||
@@ -529,7 +503,7 @@ costs. Its queue, execution, and failures are independent of the required gate
|
||||
and publication. CPU time and peak process-family memory are not measured by this API.
|
||||
|
||||
The build job saves portable Turbo outputs across runs. Eight Linux real-system
|
||||
lanes reuse its current-run artifact; standalone dispatches restore the cross-run cache. The shared action
|
||||
lanes restore this cache without waiting for the build job. The shared action
|
||||
derives its key from `test:prepare --dry=json` task hashes, runner OS and
|
||||
architecture, `.npmrc`, `.nvmrc`, and the lockfile; test-only changes can reuse compiled outputs. Every
|
||||
build and verification command still runs, so Turbo checks task inputs and
|
||||
@@ -539,15 +513,7 @@ that generator's entry. Native outputs are not stored in this cache.
|
||||
|
||||
Native package jobs, the Windows curated lane, and the Apple artifact lane reuse
|
||||
the same workflow's Turbo cache for portable compiled JavaScript, skills, and
|
||||
catalogs. The key parser retains the validated `test:prepare` task identities in
|
||||
`.cache/ci-build-plan.json`; staging reads this plan without starting another
|
||||
Turbo run that could evict cache entries. The producer stages matching archives,
|
||||
metadata, and available manifests into `.cache/ci-build-cache/`.
|
||||
`portable-build-cache.json` records availability per task. Evicted or partially
|
||||
missing entries are omitted as whole entries, and consumers rebuild cache misses,
|
||||
including when every entry is unavailable. Malformed plans, non-file entries,
|
||||
and I/O errors other than disappearance still fail publication. Older cross-run entries stay in the
|
||||
original cache. The Windows lane relies on the Linux static job for typechecking. They retain the normal build and prepack
|
||||
catalogs. The Windows lane relies on the Linux static job for typechecking. They retain the normal build and prepack
|
||||
commands, which restore matching outputs or rebuild on a cache miss. Native
|
||||
artifacts, dependency installs, package archives, and runtime verification remain
|
||||
host-local. Keep platform-dependent outputs out of this shared cache.
|
||||
@@ -1570,12 +1536,7 @@ NUL-containing names. It compares exact WAT,
|
||||
section output and selected/tool digests through the compiled CLI and real MCP
|
||||
SDK, validates advertised schemas, checks identical CLI/MCP Evidence IDs and
|
||||
session bundle readback, retains invalid/truncated module diagnostics, preserves
|
||||
all inputs and checks workspace cleanup.
|
||||
The lane also injects one cleanup denial for exact private runtime roots and
|
||||
input descriptors, checks recovered CLI errors, and verifies retry on the same
|
||||
MCP connection after repeated runtime-removal denial. These are controlled
|
||||
faults, not naturally occurring permission failures; no WASM target is executed.
|
||||
Pass an installed package's
|
||||
all inputs and checks workspace cleanup. Pass an installed package's
|
||||
`scripts/rea.mjs` as the first argument to run the same lane against the package.
|
||||
`npm run verify:wasm:package` packs and installs REA into an isolated temporary
|
||||
prefix with lifecycle scripts disabled and runs the same required real-tool lane.
|
||||
|
||||
@@ -79,13 +79,6 @@ providers need not expose identical state machines.
|
||||
and resource release separate. A valid process handle, successful launcher,
|
||||
or selected target establishes only its own fact. Publish available identity
|
||||
and exit observations even when launch fails; retain unknown ownership.
|
||||
- Process exit does not establish output closure. The shared process supervisor
|
||||
retains at most 64 KiB of additional diagnostics from owned stop entry,
|
||||
including pending cleanup and retries, and drains for up to one second after
|
||||
verified stop. It marks output incomplete when closure cannot be
|
||||
observed and releases owned event-loop references without changing the proven
|
||||
process-cleanup outcome. Failed process cleanup retains capture for retry;
|
||||
borrowed processes and streams retain their own lifetime and reference state.
|
||||
- Authenticate and capture identity through the same boundary on initial and
|
||||
recovery handshakes. Bound abandoned unauthenticated listeners where the
|
||||
protocol permits it; that deadline must not expire authenticated idle sessions
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
# Analysis efficiency measurements
|
||||
|
||||
For authentic old Evidence and mixed investigations, see the
|
||||
[retained-query checkpoint](retained-investigation-workflows.md).
|
||||
`retained-investigation.mjs` compares existing complete delivery with selected
|
||||
pages, including capacity-refusal recovery and original-record round trips.
|
||||
It records negative model results and separates imported-format validation work
|
||||
from the query contract.
|
||||
|
||||
For genuine Fiddler captures, see the [SAZ selection checkpoint](saz-selection-workflows.md).
|
||||
`measure.mjs --saz-selection baseline|focused|retained` compares default complete
|
||||
delivery (including retained-reference recovery), caller-selected ordinals, and
|
||||
|
||||
@@ -4,6 +4,7 @@ import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import signal
|
||||
@@ -22,7 +23,31 @@ def file_digest(path):
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def runtime_fingerprint(root):
|
||||
def pinned_experimental_engine(settings):
|
||||
expected = settings.get('REA_ATOMIC_NATIVE_IR_ENGINE_SHA256')
|
||||
if expected is None:
|
||||
return None
|
||||
if not re.fullmatch(r'[0-9a-f]{64}', expected):
|
||||
raise ValueError('Experimental native engine pin must be a SHA-256')
|
||||
path = Path(settings.get('REA_KUNA_COMMAND', ''))
|
||||
if not path.is_absolute() or not path.is_file() or not os.access(path, os.X_OK):
|
||||
raise ValueError('Pinned experimental engine requires an absolute executable file')
|
||||
actual = file_digest(path)
|
||||
if actual != expected:
|
||||
raise ValueError('Experimental engine digest differs from its pin; use a preserved build artifact')
|
||||
return {'path': str(path), 'sha256': actual}
|
||||
|
||||
|
||||
def experimental_engine_unchanged(receipt):
|
||||
if receipt is None:
|
||||
return None
|
||||
try:
|
||||
return file_digest(Path(receipt['path'])) == receipt['sha256']
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
def runtime_fingerprint(root, entrypoint=None):
|
||||
files = []
|
||||
for name in ['dist', 'bridge']:
|
||||
for path in sorted((root / name).rglob('*')):
|
||||
@@ -30,6 +55,18 @@ def runtime_fingerprint(root):
|
||||
raise ValueError('Runtime fingerprint does not follow symlinks')
|
||||
if path.is_file():
|
||||
files.append({'path': path.relative_to(root).as_posix(), 'sha256': file_digest(path)})
|
||||
if entrypoint is not None:
|
||||
# Include the experimental modules and their installed QuickJS JS/WASM,
|
||||
# plus the shared fact owner; the entrypoint alone does not pin them.
|
||||
for directory in [entrypoint.parent, root / 'experiments/atomic-re-tools']:
|
||||
for path in sorted(directory.rglob('*')):
|
||||
if path.suffix not in {'.mjs', '.cjs', '.js', '.wasm'} and path.name not in {'package.json', 'package-lock.json'}:
|
||||
continue
|
||||
if path.is_symlink():
|
||||
raise ValueError('Experimental runtime fingerprint does not follow symlinks')
|
||||
if path.is_file():
|
||||
label = path.relative_to(root).as_posix() if path.is_relative_to(root) else path.as_posix()
|
||||
files.append({'path': label, 'sha256': file_digest(path)})
|
||||
files.sort(key=lambda row: row['path'])
|
||||
text = json.dumps(files, separators=(',', ':'), ensure_ascii=False)
|
||||
return files, hashlib.sha256(text.encode()).hexdigest()
|
||||
@@ -39,6 +76,12 @@ def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--mode', choices=['direct', 'client-code'], default='direct')
|
||||
parser.add_argument('--runtime-root', type=Path, required=True)
|
||||
parser.add_argument('--mcp-entrypoint', type=Path,
|
||||
help='Caller-selected experimental stdio MCP entrypoint; leaves production dispatcher unchanged')
|
||||
parser.add_argument('--server-name', default='rea')
|
||||
parser.add_argument('--protocol-profile', choices=['canonical', 'atomic', 'atomic-direct'], default='canonical')
|
||||
parser.add_argument('--profile-parent', type=Path,
|
||||
help='Absolute parent outside the repository for the isolated model workspace')
|
||||
parser.add_argument('--revision', required=True)
|
||||
parser.add_argument('--prompt', type=Path, required=True)
|
||||
parser.add_argument('--artifact-path', help='Replace {{artifact_path}} in a question template')
|
||||
@@ -54,6 +97,10 @@ def main():
|
||||
help='Retain owned tool/usage items; excludes account/ambient state')
|
||||
parser.add_argument('--guide-enabled-tools', action='store_true',
|
||||
help='Opt-in exact-name discovery guidance for selected REA tools')
|
||||
parser.add_argument('--normalize-mcp-guidance', action='store_true',
|
||||
help='Opt-in common envelope/stopping guidance, identical across protocol lanes')
|
||||
parser.add_argument('--guide-long-waits', action='store_true',
|
||||
help='Opt-in common client wait guidance; does not change analysis contracts or deadlines')
|
||||
args = parser.parse_args()
|
||||
if args.guide_enabled_tools and args.enabled_tools is None:
|
||||
parser.error('--guide-enabled-tools requires --enabled-tools')
|
||||
@@ -94,13 +141,19 @@ def main():
|
||||
if undeclared:
|
||||
raise ValueError('Declare inherited provider settings explicitly in --providers: '
|
||||
+ ', '.join(undeclared) + '. Values are not logged.')
|
||||
# Fail before copying credentials or spending model tokens. Cargo test/build
|
||||
# can replace a mutable target/release path with a different feature build.
|
||||
experimental_engine = pinned_experimental_engine(provider_env)
|
||||
source_auth_home = (Path(os.environ['CODEX_HOME']) if 'CODEX_HOME' in os.environ
|
||||
else Path.home() / '.codex')
|
||||
source_auth = source_auth_home / 'auth.json'
|
||||
args.output.mkdir(parents=True, exist_ok=False, mode=0o700)
|
||||
runtime_files, runtime_digest = runtime_fingerprint(repository)
|
||||
runtime_files, runtime_digest = runtime_fingerprint(repository, args.mcp_entrypoint)
|
||||
(args.output / 'runtime-files.json').write_text(json.dumps(runtime_files))
|
||||
profile = Path(tempfile.mkdtemp(prefix='profile-', dir=args.output))
|
||||
if args.profile_parent and (not args.profile_parent.is_absolute()
|
||||
or args.profile_parent.resolve().is_relative_to(repository.resolve())):
|
||||
raise ValueError('profile-parent must be an absolute directory outside runtime-root')
|
||||
profile = Path(tempfile.mkdtemp(prefix='rea-model-profile-', dir=args.profile_parent or args.output))
|
||||
trial_codex_home = profile / 'codex'
|
||||
account = profile / 'account'
|
||||
workspace = profile / 'workspace'
|
||||
@@ -119,7 +172,12 @@ def main():
|
||||
'NODE_OPTIONS': '--max-old-space-size=512',
|
||||
})
|
||||
target_digest = file_digest(Path(args.artifact_path)) if args.artifact_path else None
|
||||
command_args = [str(repository / 'scripts/rea.mjs'), 'mcp']
|
||||
if not args.server_name.replace('-', '').replace('_', '').isalnum():
|
||||
raise ValueError('server-name must contain only letters, digits, hyphens or underscores')
|
||||
if args.mcp_entrypoint and not args.mcp_entrypoint.is_absolute():
|
||||
raise ValueError('mcp-entrypoint must be absolute')
|
||||
command_args = ([str(args.mcp_entrypoint)] if args.mcp_entrypoint
|
||||
else [str(repository / 'scripts/rea.mjs'), 'mcp'])
|
||||
instruction = (
|
||||
'Use the registered REA MCP server for this investigation. Static analysis '
|
||||
'only: do not execute target code, fetch URLs, launch a GUI, or modify targets. '
|
||||
@@ -132,6 +190,23 @@ def main():
|
||||
'Prefer summary/focused views where appropriate. Do not invent successful facts '
|
||||
'after a tool error. No other agents. Stop once the requested facts are supported.'
|
||||
)
|
||||
if args.protocol_profile in {'atomic', 'atomic-direct'}:
|
||||
instruction = (
|
||||
'Use the registered ' + args.server_name + ' MCP server for this static binary investigation. '
|
||||
'Call reference to inspect API contracts, then compose the supported analysis calls. '
|
||||
'Do not execute target code, fetch URLs, launch a GUI, modify targets, use shell/file tools, '
|
||||
'or use other agents. API methods return {ok,context,data} or {ok:false,error}; '
|
||||
'execute_javascript returns the script value, with script-derived authority. '
|
||||
'Preserve real evidence_id values, artifact digest, uncertainty and traversal boundaries. '
|
||||
'Check failures before reading data. Do not infer absence from partial coverage. '
|
||||
'Do not return complete inventories or source reports when a focused answer suffices. '
|
||||
'Close the binary when finished. No precomputed answer is available to you.'
|
||||
)
|
||||
if args.protocol_profile == 'atomic-direct':
|
||||
instruction = instruction.replace(
|
||||
'execute_javascript returns the script value, with script-derived authority. ',
|
||||
'Call the registered facts_* tools directly; no JavaScript execution tool is registered. '
|
||||
)
|
||||
if args.authority == 'browser':
|
||||
instruction = (
|
||||
'Use the registered REA tools for the explicitly selected public browser scenario. '
|
||||
@@ -147,14 +222,31 @@ def main():
|
||||
'possible and select the requested normalized_result fields before returning '
|
||||
'intermediate output to model context. Keep real Evidence IDs and limitations.'
|
||||
)
|
||||
if args.normalize_mcp_guidance:
|
||||
instruction += (
|
||||
' MCP calls return transport envelopes: prefer structuredContent when present; '
|
||||
'otherwise parse the text content JSON. Do not print both duplicate encodings. '
|
||||
'Apply the same rule to every tool. Stop once the requested facts are supported, '
|
||||
'state missing coverage explicitly, and close the binary when finished.'
|
||||
)
|
||||
if args.guide_enabled_tools:
|
||||
instruction += (
|
||||
' Configured REA tool function names for this trial: '
|
||||
+ json.dumps(['mcp__rea__' + name for name in enabled_tools])
|
||||
+ '. For discovery select only these exact names from ALL_TOOLS and '
|
||||
'return only their metadata. Preserve the original analyst question, '
|
||||
' Configured REA server label: ' + json.dumps(args.server_name)
|
||||
+ '. Enabled tool base names for this trial: ' + json.dumps(enabled_tools)
|
||||
+ '. Discover their actual registered callable names from ALL_TOOLS metadata; '
|
||||
'do not construct a namespace from the server label. Select only matching '
|
||||
'enabled base names and return only their metadata. Preserve the original analyst question, '
|
||||
'dependency order and source Evidence.'
|
||||
)
|
||||
if args.guide_long_waits:
|
||||
instruction += (
|
||||
' When the client executor reports a running cell during a long analysis, '
|
||||
'resume that same cell with wait and yield_time_ms:30000, within the '
|
||||
'advertised tool schema, rather than repeated one-second polls. '
|
||||
'The wait may return early when the result is ready. Do not sleep or '
|
||||
'start duplicate analysis calls just to check completion. Keep the '
|
||||
'original analysis dependencies, evidence and stopping requirements.'
|
||||
)
|
||||
quote = json.dumps
|
||||
config = '\n'.join([
|
||||
'approval_policy = "never"', 'sandbox_mode = "read-only"',
|
||||
@@ -166,16 +258,16 @@ def main():
|
||||
'code_mode = ' + ('true' if args.mode == 'client-code' else 'false'),
|
||||
'code_mode_only = ' + ('true' if args.mode == 'client-code' else 'false'),
|
||||
'[history]', 'persistence = "none"',
|
||||
'[mcp_servers.rea]', 'command = ' + quote(node),
|
||||
'[mcp_servers.' + args.server_name + ']', 'command = ' + quote(node),
|
||||
'args = ' + quote(command_args), 'startup_timeout_sec = 60',
|
||||
'tool_timeout_sec = 600',
|
||||
*([] if enabled_tools is None else ['enabled_tools = ' + quote(enabled_tools)]),
|
||||
'[mcp_servers.rea.env]',
|
||||
'[mcp_servers.' + args.server_name + '.env]',
|
||||
*[key + ' = ' + quote(value) for key, value in provider_env.items()],
|
||||
]) + '\n'
|
||||
# MCP read-only hints cover normal static tools. Explicitly authorize only
|
||||
# the session-opening primitive needed by the requested native tasks.
|
||||
config += '[mcp_servers.rea.tools.open_binary]\napproval_mode = "approve"\n'
|
||||
config += '[mcp_servers.' + args.server_name + '.tools.open_binary]\napproval_mode = "approve"\n'
|
||||
for tool in ['analyze_javascript_application', 'inspect_analysis_view',
|
||||
'inspect_android_package', 'search_android_classes',
|
||||
'inspect_android_class', 'inspect_android_method',
|
||||
@@ -187,10 +279,9 @@ def main():
|
||||
'inspect_managed_members', 'inspect_managed_native_boundaries',
|
||||
'inspect_artifact', 'inspect_wasm_artifact',
|
||||
'inspect_evm_interface', 'get_evidence_bundle', 'export_evidence_bundle',
|
||||
'import_evidence_bundle', 'list_unknowns', 'verify_unknown_resolution',
|
||||
'capture_browser_scenario',
|
||||
'resolve_containing_procedure', 'analyze_function', 'close_binary']:
|
||||
config += '[mcp_servers.rea.tools.' + tool + ']\napproval_mode = "approve"\n'
|
||||
config += '[mcp_servers.' + args.server_name + '.tools.' + tool + ']\napproval_mode = "approve"\n'
|
||||
try:
|
||||
if source_auth.exists():
|
||||
shutil.copyfile(source_auth, auth)
|
||||
@@ -210,10 +301,17 @@ def main():
|
||||
'mode': args.mode, 'model': args.model, 'reasoning': args.reasoning,
|
||||
'capture_tool_context': args.capture_tool_context,
|
||||
'guide_enabled_tools': args.guide_enabled_tools,
|
||||
'normalize_mcp_guidance': args.normalize_mcp_guidance,
|
||||
'guide_long_waits': args.guide_long_waits,
|
||||
'driver_commit': subprocess.check_output(
|
||||
['git', 'rev-parse', 'HEAD'], cwd=driver_repository, text=True).strip(),
|
||||
'runtime_revision': args.revision,
|
||||
'runtime_root': str(repository),
|
||||
'mcp_server_name': args.server_name,
|
||||
'protocol_profile': args.protocol_profile,
|
||||
'isolated_profile_parent': str(args.profile_parent) if args.profile_parent else str(args.output),
|
||||
'mcp_entrypoint': str(args.mcp_entrypoint) if args.mcp_entrypoint else None,
|
||||
'mcp_entrypoint_sha256': file_digest(args.mcp_entrypoint) if args.mcp_entrypoint else None,
|
||||
'selected_artifact_path': args.artifact_path,
|
||||
'selected_artifact_sha256_before': target_digest,
|
||||
'enabled_tools': enabled_tools,
|
||||
@@ -231,6 +329,7 @@ def main():
|
||||
'question_template_sha256': template_digest,
|
||||
'provider_settings_sha256': hashlib.sha256(
|
||||
json.dumps(provider_env, sort_keys=True).encode()).hexdigest(),
|
||||
'experimental_engine': experimental_engine,
|
||||
'provider_search_path_sha256': hashlib.sha256(
|
||||
provider_env.get('PATH', os.environ.get('PATH', '')).encode()).hexdigest(),
|
||||
'provider_environment_policy_sha256': hashlib.sha256(
|
||||
@@ -283,6 +382,9 @@ def main():
|
||||
summary = {
|
||||
'mode': args.mode, 'requested_model': args.model, 'reasoning': args.reasoning,
|
||||
'runtime_revision': args.revision,
|
||||
'runtime_inputs_unchanged': runtime_fingerprint(repository, args.mcp_entrypoint)[1] == runtime_digest,
|
||||
'experimental_engine': experimental_engine,
|
||||
'experimental_engine_unchanged': experimental_engine_unchanged(experimental_engine),
|
||||
'capture_tool_context_requested': args.capture_tool_context,
|
||||
'selected_artifact_sha256_before': target_digest,
|
||||
'selected_artifact_sha256_after': final_target_digest,
|
||||
@@ -297,6 +399,10 @@ def main():
|
||||
}
|
||||
(args.output / 'summary.json').write_text(json.dumps(summary, indent=2) + '\n')
|
||||
print(json.dumps(summary))
|
||||
if not summary['runtime_inputs_unchanged']:
|
||||
raise RuntimeError('Runtime inputs changed during the trial; retain costs but reject the comparison')
|
||||
if summary['experimental_engine_unchanged'] is False:
|
||||
raise RuntimeError('Experimental engine changed during the trial; retain costs but reject the comparison')
|
||||
finally:
|
||||
try:
|
||||
if args.capture_tool_context:
|
||||
|
||||
@@ -68,10 +68,15 @@ def stop_owned_scope(unit, process, group):
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--task-ceiling', type=int, default=192)
|
||||
parser.add_argument('--early-stop-mib', type=int, default=3072,
|
||||
help='Memory pre-stop threshold; hard cap remains 4 GiB (default 3072 MiB)')
|
||||
parser.add_argument('--observe-payload-exit', action='store_true',
|
||||
help='Observe payload-exit counters before the cgroup observer exits')
|
||||
parser.add_argument('command', nargs=argparse.REMAINDER)
|
||||
options = parser.parse_args()
|
||||
if not 1 <= options.early_stop_mib <= 3584:
|
||||
parser.error('--early-stop-mib must leave at least 512 MiB below the 4 GiB hard cap')
|
||||
early_stop_bytes = options.early_stop_mib * 1024 * 1024
|
||||
if options.task_ceiling <= 0:
|
||||
parser.error('--task-ceiling must be positive')
|
||||
if options.observe_payload_exit and options.task_ceiling < 2:
|
||||
@@ -95,7 +100,7 @@ def main():
|
||||
]
|
||||
command = [
|
||||
'systemd-run', '--user', '--scope', '--unit=' + unit,
|
||||
'-p', 'MemoryMax=4G', '-p', 'MemoryHigh=3G', '-p', 'MemorySwapMax=0',
|
||||
'-p', 'MemoryMax=4G', '-p', f'MemoryHigh={early_stop_bytes}', '-p', 'MemorySwapMax=0',
|
||||
'-p', 'CPUQuota=100%', '-p', 'TasksMax=' + str(options.task_ceiling),
|
||||
'taskset', '-c', str(cpu), *payload,
|
||||
]
|
||||
@@ -158,7 +163,7 @@ def main():
|
||||
except FileNotFoundError:
|
||||
# A completed transient scope can disappear between reads.
|
||||
pass
|
||||
if peak > 3 * gib:
|
||||
if peak > early_stop_bytes:
|
||||
abort = 'scope_memory_early_stop'
|
||||
elif available_bytes() < 4 * gib:
|
||||
abort = 'host_available_memory_early_stop'
|
||||
@@ -184,7 +189,7 @@ def main():
|
||||
'resource_scope': unit, 'peak_cgroup_bytes_sampled': peak,
|
||||
'elapsed_seconds': round(time.monotonic() - started, 3),
|
||||
'abort': abort, 'hard_memory_bytes': 4 * gib,
|
||||
'early_stop_bytes': 3 * gib, 'cpu_quota_percent': 100,
|
||||
'early_stop_bytes': early_stop_bytes, 'cpu_quota_percent': 100,
|
||||
'cpu_affinity': [cpu],
|
||||
'task_ceiling': options.task_ceiling, 'peak_tasks_sampled': peak_tasks,
|
||||
'resource_events_last_observed': events,
|
||||
|
||||
@@ -1,635 +0,0 @@
|
||||
{
|
||||
"runtime_revision": "f4322b15ed1423d736bd2572cf7a8eadf2b466e1",
|
||||
"host": "Linux x86-64",
|
||||
"node": "24.18.0",
|
||||
"npm": "11.16.0",
|
||||
"codex_cli": "0.161.0",
|
||||
"requested_model": "gpt-6.1-sol",
|
||||
"reasoning": "high",
|
||||
"resolved_model_identity": "unknown",
|
||||
"code_mode": false,
|
||||
"client_enabled_tools": [
|
||||
"import_evidence_bundle",
|
||||
"get_evidence_bundle",
|
||||
"inspect_analysis_view",
|
||||
"list_unknowns"
|
||||
],
|
||||
"catalog": {
|
||||
"tools": 207,
|
||||
"serialized_bytes": 3152125,
|
||||
"sha256": "4f31d9d56c400bc48f5639a9dc4b4cdad7faf862e4be81641d94fa70552438e4"
|
||||
},
|
||||
"bounds": {
|
||||
"cpu_quota_percent": 100,
|
||||
"family_hard_mib": 8192,
|
||||
"early_stop_mib": 7168,
|
||||
"swap": false,
|
||||
"tasks": 192
|
||||
},
|
||||
"counter_scope": "Payload-exit counters with observer alive; kernel family peaks include file cache; terminal whole-scope counters and remote model compute unknown",
|
||||
"sources": {
|
||||
"native": {
|
||||
"target_sha256": "2e6eef9a727f081f0d453b4e5e6cbd8b9ef8b6f86cbf7681cbad444d3b0b55c8",
|
||||
"sections": 26,
|
||||
"symbols": 1479,
|
||||
"relocations": 2963,
|
||||
"all_symbol_locations_names_values_agree_with_independent_ELF_parser": true
|
||||
},
|
||||
"javascript": {
|
||||
"package": "npm",
|
||||
"version": "11.16.0",
|
||||
"source_files": [
|
||||
{
|
||||
"path": "package.json",
|
||||
"sha256": "60ff022e32b5d8291d3e09849fd0cee6bbbff4e4d8352ad258214b1adf070714"
|
||||
},
|
||||
{
|
||||
"path": "bin/npm-cli.js",
|
||||
"sha256": "8e5f6f3429f8cdbe693cdc29904e9d5a7b127a494bd15c804bd54c7403bfcbe7"
|
||||
},
|
||||
{
|
||||
"path": "lib/cli.js",
|
||||
"sha256": "67666f06479f9b0bbc01412c198caadd4287d34d5ed74a02871ea78f186451e7"
|
||||
},
|
||||
{
|
||||
"path": "lib/cli/entry.js",
|
||||
"sha256": "667a44c1fa8795fdbba8ad843736ca7f8f24e64511985e9a7060b002123560c6"
|
||||
},
|
||||
{
|
||||
"path": "lib/commands/install.js",
|
||||
"sha256": "f7a60e8b40ab1bece76a2441b8b15378d199f05c6050eebe455cd9961f67b816"
|
||||
}
|
||||
],
|
||||
"lib_cli_module": {
|
||||
"node_id": "jag_node_131257ad52f3333971c2a5ed325c64357e52604489e42ccc67a8849770cb5b10",
|
||||
"kind": "javascript-module",
|
||||
"path": "lib/cli.js"
|
||||
},
|
||||
"source_bytes_checked": true,
|
||||
"inventory_completeness": "producer-relative, not independently established",
|
||||
"unselected_sources": 1416
|
||||
}
|
||||
},
|
||||
"sdk": [
|
||||
{
|
||||
"name": "sdk-native-complete-1",
|
||||
"status": "passed",
|
||||
"answer_sha256": "4e28c2c2a25620576d27abe846a05835ec49386b889779e33410c31971523b54",
|
||||
"query_ms": 1328.7,
|
||||
"query_reply_bytes": 11224227,
|
||||
"rpc_count": 7,
|
||||
"elapsed_seconds": 14.117,
|
||||
"cpu_seconds": 13.915,
|
||||
"peak_family_mib": 1160.8,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
},
|
||||
"payload_cleanup_verified": true,
|
||||
"response_capacity_refused": false,
|
||||
"warm_page_ms": []
|
||||
},
|
||||
{
|
||||
"name": "sdk-native-complete-2",
|
||||
"status": "passed",
|
||||
"answer_sha256": "4e28c2c2a25620576d27abe846a05835ec49386b889779e33410c31971523b54",
|
||||
"query_ms": 1385.4,
|
||||
"query_reply_bytes": 11224227,
|
||||
"rpc_count": 7,
|
||||
"elapsed_seconds": 14.722,
|
||||
"cpu_seconds": 14.485,
|
||||
"peak_family_mib": 1109.9,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
},
|
||||
"payload_cleanup_verified": true,
|
||||
"response_capacity_refused": false,
|
||||
"warm_page_ms": []
|
||||
},
|
||||
{
|
||||
"name": "sdk-native-focused-1",
|
||||
"status": "passed",
|
||||
"answer_sha256": "4e28c2c2a25620576d27abe846a05835ec49386b889779e33410c31971523b54",
|
||||
"query_ms": 529.7,
|
||||
"query_reply_bytes": 167985,
|
||||
"rpc_count": 25,
|
||||
"elapsed_seconds": 12.907,
|
||||
"cpu_seconds": 12.679,
|
||||
"peak_family_mib": 934.8,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
},
|
||||
"payload_cleanup_verified": true,
|
||||
"response_capacity_refused": false,
|
||||
"warm_page_ms": [44.1, 59.6, 24.0, 30.8, 26.7, 47.4]
|
||||
},
|
||||
{
|
||||
"name": "sdk-native-focused-2",
|
||||
"status": "passed",
|
||||
"answer_sha256": "4e28c2c2a25620576d27abe846a05835ec49386b889779e33410c31971523b54",
|
||||
"query_ms": 572.2,
|
||||
"query_reply_bytes": 167985,
|
||||
"rpc_count": 25,
|
||||
"elapsed_seconds": 13.316,
|
||||
"cpu_seconds": 13.116,
|
||||
"peak_family_mib": 1000.0,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
},
|
||||
"payload_cleanup_verified": true,
|
||||
"response_capacity_refused": false,
|
||||
"warm_page_ms": [44.0, 64.6, 26.8, 33.2, 29.8, 50.4]
|
||||
},
|
||||
{
|
||||
"name": "sdk-javascript-complete-1",
|
||||
"status": "passed",
|
||||
"answer_sha256": "0fe3ad249eb1a7233a4966a56652c173667c48fdaf395b6c08fc6901ef3b46f7",
|
||||
"query_ms": 11241.5,
|
||||
"query_reply_bytes": 212856,
|
||||
"rpc_count": 31,
|
||||
"elapsed_seconds": 26.3,
|
||||
"cpu_seconds": 26.1,
|
||||
"peak_family_mib": 1333.5,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
},
|
||||
"payload_cleanup_verified": true,
|
||||
"response_capacity_refused": true,
|
||||
"warm_page_ms": [1124.6, 1073.8, 1474.7, 1074.7, 1081.6, 1109.5]
|
||||
},
|
||||
{
|
||||
"name": "sdk-javascript-complete-2",
|
||||
"status": "passed",
|
||||
"answer_sha256": "0fe3ad249eb1a7233a4966a56652c173667c48fdaf395b6c08fc6901ef3b46f7",
|
||||
"query_ms": 11938.1,
|
||||
"query_reply_bytes": 212856,
|
||||
"rpc_count": 31,
|
||||
"elapsed_seconds": 27.105,
|
||||
"cpu_seconds": 26.87,
|
||||
"peak_family_mib": 1320.9,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
},
|
||||
"payload_cleanup_verified": true,
|
||||
"response_capacity_refused": true,
|
||||
"warm_page_ms": [1155.4, 1096.2, 1489.3, 1121.3, 1088.3, 1484.6]
|
||||
},
|
||||
{
|
||||
"name": "sdk-javascript-focused-2",
|
||||
"status": "passed",
|
||||
"answer_sha256": "0fe3ad249eb1a7233a4966a56652c173667c48fdaf395b6c08fc6901ef3b46f7",
|
||||
"query_ms": 10967.3,
|
||||
"query_reply_bytes": 208350,
|
||||
"rpc_count": 28,
|
||||
"elapsed_seconds": 25.708,
|
||||
"cpu_seconds": 25.505,
|
||||
"peak_family_mib": 1344.0,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
},
|
||||
"payload_cleanup_verified": true,
|
||||
"response_capacity_refused": false,
|
||||
"warm_page_ms": [1342.7, 1085.1, 1055.0, 1034.6, 1082.7, 1440.7]
|
||||
},
|
||||
{
|
||||
"name": "sdk-javascript-focused-3",
|
||||
"status": "passed",
|
||||
"answer_sha256": "0fe3ad249eb1a7233a4966a56652c173667c48fdaf395b6c08fc6901ef3b46f7",
|
||||
"query_ms": 10990.4,
|
||||
"query_reply_bytes": 208350,
|
||||
"rpc_count": 28,
|
||||
"elapsed_seconds": 26.197,
|
||||
"cpu_seconds": 25.98,
|
||||
"peak_family_mib": 1336.0,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
},
|
||||
"payload_cleanup_verified": true,
|
||||
"response_capacity_refused": false,
|
||||
"warm_page_ms": [1338.1, 1088.5, 1069.1, 1038.3, 1087.5, 1483.0]
|
||||
},
|
||||
{
|
||||
"name": "sdk-mixed-native",
|
||||
"status": "passed",
|
||||
"answer_sha256": "4e28c2c2a25620576d27abe846a05835ec49386b889779e33410c31971523b54",
|
||||
"query_ms": 560.0,
|
||||
"query_reply_bytes": 167991,
|
||||
"rpc_count": 25,
|
||||
"elapsed_seconds": 16.933,
|
||||
"cpu_seconds": 16.714,
|
||||
"peak_family_mib": 1261.4,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
},
|
||||
"payload_cleanup_verified": true,
|
||||
"response_capacity_refused": false,
|
||||
"warm_page_ms": [46.9, 51.0, 36.3, 24.4, 38.6, 43.8]
|
||||
},
|
||||
{
|
||||
"name": "sdk-mixed-javascript",
|
||||
"status": "passed",
|
||||
"answer_sha256": "0fe3ad249eb1a7233a4966a56652c173667c48fdaf395b6c08fc6901ef3b46f7",
|
||||
"query_ms": 10904.5,
|
||||
"query_reply_bytes": 208356,
|
||||
"rpc_count": 28,
|
||||
"elapsed_seconds": 26.5,
|
||||
"cpu_seconds": 26.297,
|
||||
"peak_family_mib": 1346.5,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
},
|
||||
"payload_cleanup_verified": true,
|
||||
"response_capacity_refused": false,
|
||||
"warm_page_ms": [1321.9, 1063.3, 1070.8, 1309.9, 1041.7, 1074.2]
|
||||
}
|
||||
],
|
||||
"model_trials": [
|
||||
{
|
||||
"name": "model-javascript-complete-1",
|
||||
"facts_pass": true,
|
||||
"elapsed_seconds": 76.49,
|
||||
"cpu_seconds": 24.687,
|
||||
"peak_family_mib": 818.7,
|
||||
"input_tokens": 454491,
|
||||
"cached_input_tokens": 396288,
|
||||
"uncached_input_tokens": 58203,
|
||||
"output_tokens": 2033,
|
||||
"reported_reasoning_output_tokens": 207,
|
||||
"mcp_calls_including_discovery": 9,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model-javascript-complete-2",
|
||||
"facts_pass": true,
|
||||
"elapsed_seconds": 58.335,
|
||||
"cpu_seconds": 14.993,
|
||||
"peak_family_mib": 971.4,
|
||||
"input_tokens": 328066,
|
||||
"cached_input_tokens": 280704,
|
||||
"uncached_input_tokens": 47362,
|
||||
"output_tokens": 1676,
|
||||
"reported_reasoning_output_tokens": 129,
|
||||
"mcp_calls_including_discovery": 9,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model-javascript-focused-1",
|
||||
"facts_pass": false,
|
||||
"elapsed_seconds": 34.206,
|
||||
"cpu_seconds": 16.31,
|
||||
"peak_family_mib": 811.9,
|
||||
"input_tokens": 167470,
|
||||
"cached_input_tokens": 136320,
|
||||
"uncached_input_tokens": 31150,
|
||||
"output_tokens": 633,
|
||||
"reported_reasoning_output_tokens": 172,
|
||||
"mcp_calls_including_discovery": 4,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model-javascript-focused-2",
|
||||
"facts_pass": true,
|
||||
"elapsed_seconds": 66.455,
|
||||
"cpu_seconds": 14.337,
|
||||
"peak_family_mib": 955.3,
|
||||
"input_tokens": 339528,
|
||||
"cached_input_tokens": 307456,
|
||||
"uncached_input_tokens": 32072,
|
||||
"output_tokens": 2051,
|
||||
"reported_reasoning_output_tokens": 169,
|
||||
"mcp_calls_including_discovery": 10,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model-javascript-guided-complete-1",
|
||||
"facts_pass": true,
|
||||
"elapsed_seconds": 69.206,
|
||||
"cpu_seconds": 13.65,
|
||||
"peak_family_mib": 888.8,
|
||||
"input_tokens": 168862,
|
||||
"cached_input_tokens": 121728,
|
||||
"uncached_input_tokens": 47134,
|
||||
"output_tokens": 2385,
|
||||
"reported_reasoning_output_tokens": 737,
|
||||
"mcp_calls_including_discovery": 6,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model-javascript-guided-complete-2",
|
||||
"facts_pass": false,
|
||||
"elapsed_seconds": 29.187,
|
||||
"cpu_seconds": 15.105,
|
||||
"peak_family_mib": 697.4,
|
||||
"input_tokens": 28696,
|
||||
"cached_input_tokens": 23296,
|
||||
"uncached_input_tokens": 5400,
|
||||
"output_tokens": 610,
|
||||
"reported_reasoning_output_tokens": 379,
|
||||
"mcp_calls_including_discovery": 0,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model-javascript-guided-focused-1",
|
||||
"facts_pass": true,
|
||||
"elapsed_seconds": 53.464,
|
||||
"cpu_seconds": 12.059,
|
||||
"peak_family_mib": 944.5,
|
||||
"input_tokens": 124218,
|
||||
"cached_input_tokens": 92416,
|
||||
"uncached_input_tokens": 31802,
|
||||
"output_tokens": 1746,
|
||||
"reported_reasoning_output_tokens": 330,
|
||||
"mcp_calls_including_discovery": 5,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model-javascript-guided-focused-2",
|
||||
"facts_pass": true,
|
||||
"elapsed_seconds": 58.526,
|
||||
"cpu_seconds": 22.852,
|
||||
"peak_family_mib": 924.2,
|
||||
"input_tokens": 129134,
|
||||
"cached_input_tokens": 97536,
|
||||
"uncached_input_tokens": 31598,
|
||||
"output_tokens": 1478,
|
||||
"reported_reasoning_output_tokens": 69,
|
||||
"mcp_calls_including_discovery": 5,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model-native-complete-1",
|
||||
"facts_pass": true,
|
||||
"elapsed_seconds": 52.103,
|
||||
"cpu_seconds": 8.686,
|
||||
"peak_family_mib": 1028.5,
|
||||
"input_tokens": 287913,
|
||||
"cached_input_tokens": 249984,
|
||||
"uncached_input_tokens": 37929,
|
||||
"output_tokens": 1724,
|
||||
"reported_reasoning_output_tokens": 121,
|
||||
"mcp_calls_including_discovery": 4,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model-native-complete-2",
|
||||
"facts_pass": true,
|
||||
"elapsed_seconds": 58.261,
|
||||
"cpu_seconds": 9.102,
|
||||
"peak_family_mib": 837.4,
|
||||
"input_tokens": 348976,
|
||||
"cached_input_tokens": 286976,
|
||||
"uncached_input_tokens": 62000,
|
||||
"output_tokens": 2009,
|
||||
"reported_reasoning_output_tokens": 246,
|
||||
"mcp_calls_including_discovery": 5,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model-native-focused-1",
|
||||
"facts_pass": true,
|
||||
"elapsed_seconds": 62.078,
|
||||
"cpu_seconds": 10.198,
|
||||
"peak_family_mib": 823.9,
|
||||
"input_tokens": 335445,
|
||||
"cached_input_tokens": 293120,
|
||||
"uncached_input_tokens": 42325,
|
||||
"output_tokens": 1924,
|
||||
"reported_reasoning_output_tokens": 87,
|
||||
"mcp_calls_including_discovery": 8,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model-native-focused-2",
|
||||
"facts_pass": true,
|
||||
"elapsed_seconds": 57.933,
|
||||
"cpu_seconds": 8.058,
|
||||
"peak_family_mib": 821.3,
|
||||
"input_tokens": 286938,
|
||||
"cached_input_tokens": 256384,
|
||||
"uncached_input_tokens": 30554,
|
||||
"output_tokens": 1831,
|
||||
"reported_reasoning_output_tokens": 106,
|
||||
"mcp_calls_including_discovery": 8,
|
||||
"payload_cleanup_verified": true,
|
||||
"memory_events": {
|
||||
"low": 0,
|
||||
"high": 0,
|
||||
"max": 0,
|
||||
"oom": 0,
|
||||
"oom_kill": 0,
|
||||
"oom_group_kill": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"failed_trials": {
|
||||
"model-javascript-focused-1": "Wrong connector discovery; approval-policy refusal; no source facts established.",
|
||||
"model-javascript-guided-complete-2": "Premature agent refusal with no REA RPC; asserted tool unavailability not established by a connection/discovery observation."
|
||||
},
|
||||
"pilot_failures": [
|
||||
"Private pilot oracle read view.item instead of view.items; corrected before the committed SDK cohorts. No product failure inferred."
|
||||
],
|
||||
"decision": "Existing query APIs suffice for these bounded questions; no general token/time advantage established. Separate imported immutable-format validation optimization is tracked in #4810.",
|
||||
"review_followup_verification": {
|
||||
"review-mixed-native": {
|
||||
"status": "passed",
|
||||
"checks": {
|
||||
"heads_checked": 64,
|
||||
"pages": 32,
|
||||
"revised_unknown_id": "unk_057c8f2dbf30ec98851a66ee054366bc6e2e168874581e6f99cb80673d0ff9b8",
|
||||
"revision_checked": 2,
|
||||
"stale_update_rejected": true,
|
||||
"tampered_import_rejected_atomically": true,
|
||||
"unknowns_after_close": 0,
|
||||
"old_reference_refused": true
|
||||
},
|
||||
"original_records_preserved": true,
|
||||
"elapsed_seconds": 18.444,
|
||||
"cpu_seconds": 18.16515,
|
||||
"peak_family_mib": 1401.6328125,
|
||||
"oom_events_at_payload_exit": 0,
|
||||
"payload_cleanup_verified": true
|
||||
},
|
||||
"review-mixed-javascript": {
|
||||
"status": "passed",
|
||||
"checks": {
|
||||
"heads_checked": 64,
|
||||
"pages": 32,
|
||||
"revised_unknown_id": "unk_057c8f2dbf30ec98851a66ee054366bc6e2e168874581e6f99cb80673d0ff9b8",
|
||||
"revision_checked": 2,
|
||||
"stale_update_rejected": true,
|
||||
"tampered_import_rejected_atomically": true,
|
||||
"unknowns_after_close": 0,
|
||||
"old_reference_refused": true
|
||||
},
|
||||
"original_records_preserved": true,
|
||||
"elapsed_seconds": 27.617,
|
||||
"cpu_seconds": 27.275299,
|
||||
"peak_family_mib": 1444.30859375,
|
||||
"oom_events_at_payload_exit": 0,
|
||||
"payload_cleanup_verified": true
|
||||
},
|
||||
"deterministic_receipt_tests": {
|
||||
"passed": 4,
|
||||
"scope": "Rejected SDK call, protocol error, receipt-write failure, simultaneous call/write failure; not real-provider evidence"
|
||||
},
|
||||
"cleanup_receipt_regressions": {
|
||||
"passed": 6,
|
||||
"scope": "Real stream/file refusals, independent peer close, and injected partial publication at the filesystem boundary. Original failure and call costs survive; failed cleanup retains workspace ownership. Harness failure checks, not real-provider evidence.",
|
||||
"baseline_reproduction": {
|
||||
"revision": "b025a919b36ec091ca888339df6b24e78e89b79b",
|
||||
"method": "Execute the prior committed finalization block with deterministic workspace or log rejection; not a production-provider reproduction.",
|
||||
"workspace_error": {
|
||||
"file_receipt_attempts": 0,
|
||||
"stdout_receipt_attempts": 0
|
||||
},
|
||||
"log_error": {
|
||||
"file_receipt_attempts": 0,
|
||||
"stdout_receipt_attempts": 0
|
||||
}
|
||||
},
|
||||
"partial_retry_baseline": {
|
||||
"revision": "5d6259e658ee54fc9829b9143a8721a2ab426e80",
|
||||
"regression_exit_code": 1,
|
||||
"observed_saved_report": "partial",
|
||||
"method": "Run the unchanged partial-write regression against the prior committed finalizer with deterministic filesystem-boundary failure injection."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
# Retained investigation query checkpoint
|
||||
|
||||
[#3134](https://github.com/morluto/rea/issues/3134) measured existing retained
|
||||
queries on Linux. Selected reads preserved the requested facts, original
|
||||
Evidence and Unknown revisions, including a mixed investigation. Existing
|
||||
contracts suffice for these questions; this checkpoint adds no production API,
|
||||
cache, persistence or default change.
|
||||
|
||||
Imported JavaScript pages repeatedly validated their entire source graph. That
|
||||
separate, observed bottleneck is owned by
|
||||
[#4810](https://github.com/morluto/rea/issues/4810). Smaller replies did not
|
||||
establish a general model-token or whole-task latency improvement.
|
||||
|
||||
The [curated measurements](retained-investigation-results.json) retain individual
|
||||
SDK/model costs and unsuccessful attempts. Raw bundles, transcripts, profiles
|
||||
and detailed receipts stay private and are not build inputs.
|
||||
|
||||
## Sources and questions
|
||||
|
||||
Runtime: `f4322b15ed1423d736bd2572cf7a8eadf2b466e1`, Linux x86-64,
|
||||
Node 24.18.0/npm 11.16.0. The SDK discovered all 207 advertised tools
|
||||
(3,152,125 serialized catalog bytes). Model trials used Codex CLI 0.161.0,
|
||||
requested `gpt-6.1-sol`/high, direct MCP, and the same four enabled tool names:
|
||||
`import_evidence_bundle`, `get_evidence_bundle`, `inspect_analysis_view`, and
|
||||
`list_unknowns`. The resolved service-side model identity is unknown. These are
|
||||
selected-client-tool trials, not an evaluation of full-catalog agent discovery.
|
||||
|
||||
Two public source workflows produced authentic bundles through production MCP:
|
||||
|
||||
- Native: `inspect_binary_layout` on Debian's `libsqlite3.so.0.8.6`, SHA-256
|
||||
`2e6eef9a727f081f0d453b4e5e6cbd8b9ef8b6f86cbf7681cbad444d3b0b55c8`.
|
||||
Pwntools 4.15.0/pyelftools 0.33/Unicorn 2.1.2 observed 26 sections, 1,479
|
||||
symbols and 2,963 relocations. An independent ELF64 decoder checked section
|
||||
and relocation counts and every symbol's table/entry index, value, raw name
|
||||
bytes and source entry range against the original file.
|
||||
- JavaScript: shipped npm 11.16.0, directory inventory digest
|
||||
`f8e576a7d162542c616168b25a95a5f62b9accf29467cc37e149905ad4b8e603`.
|
||||
`analyze_javascript_application` selected exactly `package.json`,
|
||||
`bin/npm-cli.js`, `lib/cli.js`, `lib/cli/entry.js`, and
|
||||
`lib/commands/install.js`. It parsed four JavaScript files; 1,416 other
|
||||
relevant files remained unselected. The complete retained result contained
|
||||
2,822 application nodes, 1,796 semantic nodes and 13,682 semantic unknowns.
|
||||
Source-file digests and the `lib/cli.js` source-module identity were checked
|
||||
against shipped bytes. Inventory/discovery completeness remains producer-relative.
|
||||
|
||||
Analyst-recorded Unknowns came from the actual source limitations: five native
|
||||
and seven JavaScript questions. These registry heads are distinct from the
|
||||
13,682 semantic-graph unknowns. The exported histories contained 15 and 17
|
||||
records, respectively, and approximately 1.75 and 21.06 MB of canonical JSON.
|
||||
No synthetic payload arrays were used.
|
||||
|
||||
The SDK task read the first six original symbol/module rows and the relevant
|
||||
current Unknown heads. Complete delivery and selected delivery answered the
|
||||
same question; selected delivery intentionally exercised two-row pages. Each
|
||||
fresh server performed three traversals, exported again and closed. The model
|
||||
task additionally requested native identity/counts, or the five JavaScript source
|
||||
choices and exact `lib/cli.js` source module, with explicit runtime uncertainty.
|
||||
Compare arms within each declared task, not SDK costs against model costs.
|
||||
|
||||
## Correctness, capacity and lifetime
|
||||
|
||||
Both fresh-server SDK repetitions passed in both delivery arms. Selected rows,
|
||||
ordering and counts agreed with original records; all original records and
|
||||
Unknown revisions survived export/import, including links, omitted fields,
|
||||
nulls and scalar types. Query calls did not rerun either producer. The resumed
|
||||
servers had no native producer configuration.
|
||||
|
||||
The JavaScript complete bundle exceeded the default 10 MiB receive-buffer
|
||||
boundary. Its typed capacity refusal preserved the complete retained data and a
|
||||
usable connection. Complete-arm costs include that refusal and subsequent
|
||||
selected-view recovery; they are not timings for a successful complete transfer.
|
||||
|
||||
A mixed history combined both authentic investigations and promoted 64 actual
|
||||
semantic unknowns to separately identified analyst follow-ups. One follow-up
|
||||
was updated to investigating. It contained 97 records, 76 heads and 77 revisions.
|
||||
Both source queries preserved all original records/revisions. Thirty-two
|
||||
two-head pages verified every semantic-follow-up head, including revision two.
|
||||
A stale update and a tampered bundle import were rejected without changing the
|
||||
ledger. Export reproduced the complete original mixed bundle. Closing cleared
|
||||
records/Unknowns and made the old reference unavailable; no implicit persistence
|
||||
or producer restart was introduced.
|
||||
|
||||
Public CLI `inspect-evidence-bundle` summary and inline `inspect-analysis-view`
|
||||
summary also passed on both authentic sources. Portable CLI input still requires
|
||||
complete input admission/validation; small output does not remove that cost.
|
||||
|
||||
## SDK costs
|
||||
|
||||
Each row spans two fresh MCP servers. Query time is the sum of SDK RPC elapsed
|
||||
times over three traversals. Local post-call contract validation, oracle checks
|
||||
and transcript writes are included only in the whole harness, along with startup,
|
||||
full discovery, file reads, import, export and close. OS caches were uncontrolled/warm. A fresh imported
|
||||
session is not a cold native-analysis measurement.
|
||||
|
||||
| Source / arm | Three traversals | Query reply bytes | Whole elapsed | Local family CPU | Family peak |
|
||||
| ------------------------------ | ---------------: | ----------------: | --------------: | ---------------: | --------------: |
|
||||
| Native complete | 1.329–1.385 s | 11,224,227 | 14.117–14.722 s | 13.915–14.485 s | 1,110–1,161 MiB |
|
||||
| Native selected | 0.530–0.572 s | 167,985 | 12.907–13.316 s | 12.679–13.116 s | 935–1,000 MiB |
|
||||
| JavaScript complete + recovery | 11.242–11.938 s | 212,856 | 26.300–27.105 s | 26.100–26.870 s | 1,321–1,334 MiB |
|
||||
| JavaScript selected | 10.967–10.990 s | 208,350 | 25.708–26.197 s | 25.505–25.980 s | 1,336–1,344 MiB |
|
||||
|
||||
Mixed-history selected tasks took 16.933 s native and 26.500 s JavaScript,
|
||||
including the larger import and complete round-trip checks. Their family peaks
|
||||
were 1,261 and 1,347 MiB. This does not establish scaling to thousands of
|
||||
registry heads or every provider.
|
||||
|
||||
Original-session npm warm pages measured 8–31 ms; after import, repeated pages
|
||||
cost about 1.1–1.4 s. Source inspection shows that imported immutable Evidence
|
||||
does not carry the format owner's private graph proofs, so each view repeats
|
||||
full validation. Native layout views also parse the complete layout on each
|
||||
page. #4810 owns equivalent before/after verification of a correction; this
|
||||
checkpoint claims no speedup from an unimplemented cache.
|
||||
|
||||
## Actual model tasks
|
||||
|
||||
All twelve attempts retained their costs. Ten supplied every checked fact and
|
||||
current Unknown identity/status; runtime and unselected-source coverage stayed
|
||||
unknown. One initial JavaScript selected attempt searched the wrong connector
|
||||
and received an approval-policy refusal. One guided complete attempt stopped
|
||||
without an REA RPC and asserted tool unavailability without a supporting
|
||||
connection/discovery observation. Both are failed tasks, despite CLI exit zero.
|
||||
|
||||
| Cohort / arm | Successful tasks | Total input tokens | Elapsed |
|
||||
| ------------------------------------- | ---------------: | -----------------------: | -----------------------: |
|
||||
| Native complete | 2/2 | 287,913 / 348,976 | 52.103 / 58.261 s |
|
||||
| Native selected, two-head pages | 2/2 | 335,445 / 286,938 | 62.078 / 57.933 s |
|
||||
| JavaScript complete + recovery | 2/2 | 454,491 / 328,066 | 76.490 / 58.335 s |
|
||||
| JavaScript selected, two-head pages | 1/2 | 167,470 failed / 339,528 | 34.206 failed / 66.455 s |
|
||||
| JavaScript guided complete + recovery | 1/2 | 168,862 / 28,696 failed | 69.206 / 29.187 failed s |
|
||||
| JavaScript guided selected | 2/2 | 124,218 / 129,134 | 53.464 / 58.526 s |
|
||||
|
||||
The separate guided JavaScript cohort named the exact configured tools and
|
||||
allowed one sufficiently large Unknown page for this bounded question. Both
|
||||
arms received the same discovery guidance. Its single completed complete-arm
|
||||
sample is insufficient for a stable repeated-pair benefit claim. Native total
|
||||
input/time overlapped; extra pages and model turns can consume the reply saving.
|
||||
Do not pool failed tasks as fast answers or attribute guidance changes to REA.
|
||||
|
||||
The JSON report records total/cached/uncached input, output, local CPU and peak
|
||||
memory per attempt. These are client-reported usage counters, not tokenizer
|
||||
estimates; output includes the client's reported reasoning accounting without
|
||||
adding it again. Schema/discovery, errors, retries and continuations remain in
|
||||
the task. Remote model compute, full-catalog model behavior and other hosts were
|
||||
not measured.
|
||||
|
||||
Heavy runs were serial, one CPU, 8 GiB family hard limit, 7 GiB early stop,
|
||||
no swap. Kernel peaks include charged file cache. Counter observations were
|
||||
taken at payload exit while the owned observer remained alive; terminal
|
||||
whole-scope counters remain unknown. Observed payload OOM/capacity events were
|
||||
zero, all payloads exited and cleanup was verified. The expected MCP response
|
||||
refusal is a separate transport-capacity outcome.
|
||||
|
||||
## Reproduce
|
||||
|
||||
Build the pinned runtime, acquire the matching real artifacts and produce the
|
||||
two authentic histories with the public operations above. Export before close.
|
||||
Keep bundles, transcripts and model profiles private. For a known source ID:
|
||||
|
||||
```sh
|
||||
node experiments/analysis-efficiency/retained-investigation.mjs \
|
||||
--runtime-root /absolute/built-rea \
|
||||
--revision f4322b15ed1423d736bd2572cf7a8eadf2b466e1 \
|
||||
--bundle /absolute/authentic-history.json \
|
||||
--evidence-id ev_ORIGINAL_SHA256 \
|
||||
--scenario native --delivery focused \
|
||||
--output /absolute/new-receipt-directory
|
||||
```
|
||||
|
||||
Run under the existing process-family resource wrapper, with sufficient bounds
|
||||
for the selected source. Repeat with `--delivery complete`; use
|
||||
`--scenario javascript` for module rows. The task's Unknown domain is
|
||||
`retained-native` or `retained-javascript`. Output is never overwritten.
|
||||
`agent-trial.py --mode direct` supports the same four enabled names; its success
|
||||
exit only establishes client completion. Grade original IDs/digests, exact
|
||||
facts, coverage and Unknowns from the retained transcript and final answer.
|
||||
|
||||
For a privately supplied authentic mixed bundle, add `--verify-mixed`. Besides
|
||||
the normal source query and original-record round trip, this pages every current
|
||||
head in `javascript-semantic-followup`, checks the current updated revision,
|
||||
submits a deliberately stale update and a tampered copy of the bundle, verifies
|
||||
atomic refusal, then checks Unknown/reference lifetime after close. The bundle
|
||||
must contain genuine follow-ups and at least one updated head. The checkpoint's
|
||||
64-head bundle passed this mode for both source scenarios. Its extra verification
|
||||
costs are separate from the original SDK comparison rows above.
|
||||
|
||||
Rejected SDK calls are recorded before propagating the original failure, with
|
||||
request, phase and elapsed time. Reply bytes stay null when no usable reply was
|
||||
received. Receipt-write failures remain distinct; simultaneous call/write
|
||||
failures retain both causes. Deterministic failure tests run with
|
||||
`python3 -m unittest discover -s experiments/analysis-efficiency -p test_retained_queries.py`.
|
||||
|
||||
Finalization independently attempts client/transport close, log completion and
|
||||
both receipt outputs. Cleanup failures preserve the original task failure and
|
||||
call costs, record the failing phase and retain the workspace for retry. A file
|
||||
receipt refusal still permits stdout; a broken stdout write is recorded in a
|
||||
file retry. Files publish through a sibling temporary file and rename; an
|
||||
interrupted retry preserves the previous receipt. Failed publication files stay
|
||||
in the owned output directory. Cleanup or receipt-output failures make the
|
||||
command fail. Six additional regressions exercise stream/file errors, partial
|
||||
publication and peer cleanup; these are harness failure checks, not real-provider
|
||||
evidence.
|
||||
@@ -1,310 +0,0 @@
|
||||
/** Measure public retained queries against an authentic, previously exported bundle. */
|
||||
import assert from "node:assert/strict";
|
||||
import { createHash } from "node:crypto";
|
||||
import { createWriteStream } from "node:fs";
|
||||
import {
|
||||
appendFile,
|
||||
mkdir,
|
||||
mkdtemp,
|
||||
readFile,
|
||||
writeFile,
|
||||
} from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, isAbsolute, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { parseArgs } from "node:util";
|
||||
import { finished } from "node:stream/promises";
|
||||
import canonicalize from "canonicalize";
|
||||
import { Client } from "@modelcontextprotocol/client";
|
||||
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
||||
import {
|
||||
requireMcpOperationResult,
|
||||
requireMcpToolError,
|
||||
} from "../../scripts/lib/mcp-verifier-results.mjs";
|
||||
import { createRetainedQueryCaller } from "./retained-query-calls.mjs";
|
||||
import { finalizeRetainedQueryReceipt } from "./retained-query-finalization.mjs";
|
||||
import {
|
||||
verifyMixedRetainedHistory,
|
||||
verifyMixedRetainedClosure,
|
||||
retainedUnknownHeads,
|
||||
} from "./retained-mixed-verification.mjs";
|
||||
|
||||
const { values } = parseArgs({
|
||||
options: {
|
||||
"runtime-root": {
|
||||
type: "string",
|
||||
default: resolve(dirname(fileURLToPath(import.meta.url)), "../.."),
|
||||
},
|
||||
revision: { type: "string" },
|
||||
bundle: { type: "string" },
|
||||
"evidence-id": { type: "string" },
|
||||
scenario: { type: "string" },
|
||||
delivery: { type: "string" },
|
||||
output: { type: "string" },
|
||||
"verify-mixed": { type: "boolean", default: false },
|
||||
},
|
||||
});
|
||||
for (const key of ["runtime-root", "bundle", "output"])
|
||||
assert.ok(values[key] && isAbsolute(values[key]), `${key} must be absolute`);
|
||||
assert.ok(values.revision && values["evidence-id"]);
|
||||
assert.ok(["native", "javascript"].includes(values.scenario));
|
||||
assert.ok(["complete", "focused"].includes(values.delivery));
|
||||
const root = values["runtime-root"];
|
||||
const output = values.output;
|
||||
await mkdir(output, { recursive: false, mode: 0o700 });
|
||||
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
||||
const sourceBytes = await readFile(values.bundle);
|
||||
const original = JSON.parse(sourceBytes);
|
||||
const source = original.records.find(
|
||||
(record) => record.evidence_id === values["evidence-id"],
|
||||
);
|
||||
const operation =
|
||||
values.scenario === "native"
|
||||
? "inspect_binary_layout"
|
||||
: "analyze_javascript_application";
|
||||
assert.equal(source?.operation, operation);
|
||||
const unknownDomain = `retained-${values.scenario}`;
|
||||
const expectedUnknowns = retainedUnknownHeads(original.unknowns, unknownDomain);
|
||||
// These oracles check selected original facts, not producer discovery completeness.
|
||||
const expectedRows =
|
||||
values.scenario === "native"
|
||||
? source.normalized_result.symbols
|
||||
: source.normalized_result.graph.nodes
|
||||
.filter((node) =>
|
||||
["javascript-asset", "javascript-module", "source-module"].includes(
|
||||
node.kind,
|
||||
),
|
||||
)
|
||||
.map((node) => {
|
||||
const candidates = node.observations.flatMap((observation) => {
|
||||
const property = observation.properties.path;
|
||||
const where = observation.evidence.location;
|
||||
return [
|
||||
...(typeof property === "string" ? [property] : []),
|
||||
...(where.available && where.value.kind === "artifact-path"
|
||||
? [where.value.path]
|
||||
: where.available && where.value.kind === "source-range"
|
||||
? [where.value.source]
|
||||
: []),
|
||||
];
|
||||
});
|
||||
return {
|
||||
node_id: node.node_id,
|
||||
kind: node.kind,
|
||||
path:
|
||||
node.identity.strategy === "canonical-path"
|
||||
? node.identity.path
|
||||
: node.identity.strategy === "source-map-original"
|
||||
? node.identity.original_source
|
||||
: (candidates[0] ?? null),
|
||||
};
|
||||
});
|
||||
assert.ok(expectedRows.length >= 6, "This task needs six original rows");
|
||||
const runtimeEntrySha256 = digest(
|
||||
await readFile(join(root, "dist/mcp/main.js")),
|
||||
);
|
||||
const account = await mkdtemp(join(tmpdir(), "rea-retained-query-"));
|
||||
const transport = new StdioClientTransport({
|
||||
command: process.execPath,
|
||||
args: [join(root, "scripts/rea.mjs"), "mcp"],
|
||||
env: {
|
||||
PATH: process.env.PATH,
|
||||
HOME: account,
|
||||
NODE_OPTIONS: "--max-old-space-size=2048",
|
||||
REA_LOG_LEVEL: "silent",
|
||||
},
|
||||
stderr: "pipe",
|
||||
});
|
||||
const serverLog = createWriteStream(join(output, "server.log"));
|
||||
const serverLogFinished = finished(serverLog);
|
||||
serverLogFinished.catch(() => {});
|
||||
transport.stderr?.pipe(serverLog);
|
||||
const client = new Client({
|
||||
name: "retained-investigation-measurement",
|
||||
version: "1",
|
||||
});
|
||||
const report = {
|
||||
revision: values.revision,
|
||||
runtime_entry_sha256: runtimeEntrySha256,
|
||||
bundle_sha256: digest(sourceBytes),
|
||||
bundle_bytes: sourceBytes.length,
|
||||
source_evidence_id: source.evidence_id,
|
||||
scenario: values.scenario,
|
||||
delivery: values.delivery,
|
||||
verify_mixed: values["verify-mixed"],
|
||||
calls: [],
|
||||
status: "running",
|
||||
};
|
||||
const call = createRetainedQueryCaller(client, async (receipt, event) => {
|
||||
report.calls.push(receipt);
|
||||
await appendFile(
|
||||
join(output, "transcript.jsonl"),
|
||||
JSON.stringify(event) + "\n",
|
||||
);
|
||||
});
|
||||
const result = (reply, name) => requireMcpOperationResult(reply, name);
|
||||
try {
|
||||
await client.connect(transport);
|
||||
const started = performance.now();
|
||||
const catalog = await client.listTools();
|
||||
report.catalog = {
|
||||
elapsed_ms: performance.now() - started,
|
||||
tools: catalog.tools.length,
|
||||
bytes: Buffer.byteLength(JSON.stringify(catalog)),
|
||||
sha256: digest(JSON.stringify(catalog)),
|
||||
};
|
||||
assert.equal(catalog.nextCursor, undefined);
|
||||
await writeFile(join(output, "catalog.json"), JSON.stringify(catalog));
|
||||
result(
|
||||
await call("import_evidence_bundle", { path: values.bundle }, "import"),
|
||||
"import_evidence_bundle",
|
||||
);
|
||||
const answers = [];
|
||||
for (let repeat = 0; repeat < 3; repeat += 1) {
|
||||
let answer;
|
||||
if (values.delivery === "complete") {
|
||||
const reply = await call("get_evidence_bundle", {}, `complete-${repeat}`);
|
||||
if (reply.isError !== true) {
|
||||
const bundle = result(reply, "get_evidence_bundle");
|
||||
assert.deepEqual(
|
||||
bundle.records.find(
|
||||
(record) => record.evidence_id === source.evidence_id,
|
||||
),
|
||||
source,
|
||||
);
|
||||
assert.deepEqual(bundle.unknowns, original.unknowns);
|
||||
answer = [expectedRows.slice(0, 6), expectedUnknowns];
|
||||
} else {
|
||||
// Keep capacity refusals and every recovery RPC in the completed task.
|
||||
const failure = requireMcpToolError(reply);
|
||||
assert.equal(failure.code, "resource_constraint");
|
||||
assert.equal(failure.details?.resource, "transport");
|
||||
report.complete_delivery_refused = true;
|
||||
}
|
||||
}
|
||||
if (answer === undefined) {
|
||||
const metadata = result(
|
||||
await call(
|
||||
"get_evidence_bundle",
|
||||
{
|
||||
detail: "summary",
|
||||
filters: { evidence_id: source.evidence_id },
|
||||
},
|
||||
`discovery-${repeat}`,
|
||||
),
|
||||
"get_evidence_bundle",
|
||||
);
|
||||
assert.equal(metadata.matching_records, 1);
|
||||
assert.equal(metadata.records[0].evidence_id, source.evidence_id);
|
||||
const rows = [];
|
||||
for (const offset of [0, 2, 4]) {
|
||||
const view = result(
|
||||
await call(
|
||||
"inspect_analysis_view",
|
||||
{
|
||||
source: {
|
||||
kind: "retained-evidence",
|
||||
evidence_id: source.evidence_id,
|
||||
},
|
||||
view: {
|
||||
kind: "page",
|
||||
collection:
|
||||
values.scenario === "native" ? "symbols" : "modules",
|
||||
offset,
|
||||
limit: 2,
|
||||
},
|
||||
},
|
||||
`page-${repeat}-${offset}`,
|
||||
),
|
||||
"inspect_analysis_view",
|
||||
);
|
||||
assert.equal(view.parent_evidence_id, source.evidence_id);
|
||||
assert.equal(view.coverage.total, expectedRows.length);
|
||||
assert.equal(view.coverage.examined, 2);
|
||||
assert.equal(
|
||||
view.coverage.next_offset,
|
||||
offset + 2 < expectedRows.length ? offset + 2 : null,
|
||||
);
|
||||
assert.deepEqual(view.items, expectedRows.slice(offset, offset + 2));
|
||||
rows.push(...view.items);
|
||||
}
|
||||
const unknowns = [];
|
||||
let offset = 0;
|
||||
do {
|
||||
const page = result(
|
||||
await call(
|
||||
"list_unknowns",
|
||||
{ domain: unknownDomain, offset, limit: 2 },
|
||||
`unknowns-${repeat}-${offset}`,
|
||||
),
|
||||
"list_unknowns",
|
||||
);
|
||||
assert.equal(page.total, expectedUnknowns.length);
|
||||
assert.equal(page.offset, offset);
|
||||
assert.deepEqual(
|
||||
page.items,
|
||||
expectedUnknowns.slice(offset, offset + 2),
|
||||
);
|
||||
assert.equal(
|
||||
page.next_offset,
|
||||
offset + 2 < expectedUnknowns.length ? offset + 2 : null,
|
||||
);
|
||||
unknowns.push(...page.items);
|
||||
offset = page.next_offset;
|
||||
} while (offset !== null);
|
||||
assert.deepEqual(unknowns, expectedUnknowns);
|
||||
answer = [rows, unknowns];
|
||||
}
|
||||
answers.push(digest(canonicalize(answer)));
|
||||
}
|
||||
assert.equal(new Set(answers).size, 1);
|
||||
report.answer_sha256 = answers[0];
|
||||
if (values["verify-mixed"])
|
||||
report.mixed_verification = await verifyMixedRetainedHistory({
|
||||
call,
|
||||
original,
|
||||
sourceId: source.evidence_id,
|
||||
output,
|
||||
});
|
||||
const roundtrip = join(output, "roundtrip.json");
|
||||
result(
|
||||
await call("export_evidence_bundle", { path: roundtrip }, "export"),
|
||||
"export_evidence_bundle",
|
||||
);
|
||||
const exported = JSON.parse(await readFile(roundtrip, "utf8"));
|
||||
const exportedRecords = new Map(
|
||||
exported.records.map((record) => [record.evidence_id, record]),
|
||||
);
|
||||
for (const record of original.records)
|
||||
assert.deepEqual(exportedRecords.get(record.evidence_id), record);
|
||||
assert.deepEqual(exported.unknowns, original.unknowns);
|
||||
report.original_records_preserved = true;
|
||||
result(await call("close_binary", {}, "close"), "close_binary");
|
||||
const closed = result(
|
||||
await call("get_evidence_bundle", { detail: "summary" }, "after-close"),
|
||||
"get_evidence_bundle",
|
||||
);
|
||||
assert.equal(closed.total_retained_records, 0);
|
||||
report.close_cleared_records = true;
|
||||
if (values["verify-mixed"])
|
||||
Object.assign(
|
||||
report.mixed_verification,
|
||||
await verifyMixedRetainedClosure(call, source.evidence_id),
|
||||
);
|
||||
assert.equal(digest(await readFile(values.bundle)), report.bundle_sha256);
|
||||
report.status = "passed";
|
||||
} catch (cause) {
|
||||
report.status = "failed";
|
||||
report.failure = { name: cause.name, message: cause.message };
|
||||
} finally {
|
||||
const finalized = await finalizeRetainedQueryReceipt({
|
||||
report,
|
||||
client,
|
||||
transport,
|
||||
account,
|
||||
serverLog,
|
||||
serverLogFinished,
|
||||
output,
|
||||
});
|
||||
if (report.status !== "passed" || !finalized) process.exitCode = 1;
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import {
|
||||
requireMcpOperationResult as result,
|
||||
requireMcpToolError,
|
||||
} from "../../scripts/lib/mcp-verifier-results.mjs";
|
||||
|
||||
/** Expected current heads from the original exported revisions, not displayed pages. */
|
||||
export const retainedUnknownHeads = (unknowns, domain) => {
|
||||
const heads = new Map();
|
||||
for (const unknown of unknowns) {
|
||||
const previous = heads.get(unknown.unknown_id);
|
||||
if (previous === undefined || previous.revision < unknown.revision)
|
||||
heads.set(unknown.unknown_id, unknown);
|
||||
}
|
||||
return [...heads.values()]
|
||||
.filter((unknown) => unknown.domain === domain)
|
||||
.sort((a, b) =>
|
||||
a.unknown_id < b.unknown_id ? -1 : a.unknown_id > b.unknown_id ? 1 : 0,
|
||||
);
|
||||
};
|
||||
|
||||
const verifyFollowupPages = async (call, original) => {
|
||||
const expected = retainedUnknownHeads(
|
||||
original.unknowns,
|
||||
"javascript-semantic-followup",
|
||||
);
|
||||
assert.ok(
|
||||
expected.length > 0,
|
||||
"Supply an authentic mixed history with semantic follow-ups",
|
||||
);
|
||||
const revised = expected.find((unknown) => unknown.revision > 1);
|
||||
assert.ok(revised, "Mixed verification requires a retained updated Unknown");
|
||||
let offset = 0;
|
||||
let pages = 0;
|
||||
const observed = [];
|
||||
do {
|
||||
const page = result(
|
||||
await call(
|
||||
"list_unknowns",
|
||||
{
|
||||
domain: "javascript-semantic-followup",
|
||||
offset,
|
||||
limit: 2,
|
||||
},
|
||||
`mixed-heads-${offset}`,
|
||||
),
|
||||
"list_unknowns",
|
||||
);
|
||||
assert.equal(page.total, expected.length);
|
||||
assert.equal(page.offset, offset);
|
||||
assert.deepEqual(page.items, expected.slice(offset, offset + 2));
|
||||
assert.equal(
|
||||
page.next_offset,
|
||||
offset + 2 < expected.length ? offset + 2 : null,
|
||||
);
|
||||
observed.push(...page.items);
|
||||
offset = page.next_offset;
|
||||
pages += 1;
|
||||
} while (offset !== null);
|
||||
assert.deepEqual(observed, expected);
|
||||
return { revised, headsChecked: expected.length, pages };
|
||||
};
|
||||
|
||||
const verifyMutationRefusals = async ({
|
||||
call,
|
||||
original,
|
||||
sourceId,
|
||||
output,
|
||||
revised,
|
||||
}) => {
|
||||
const before = result(
|
||||
await call(
|
||||
"get_evidence_bundle",
|
||||
{ detail: "summary" },
|
||||
"mixed-before-refusals",
|
||||
),
|
||||
"get_evidence_bundle",
|
||||
);
|
||||
const stale = await call(
|
||||
"update_unknown",
|
||||
{
|
||||
unknown_id: revised.unknown_id,
|
||||
expected_revision: revised.revision - 1,
|
||||
status: revised.status,
|
||||
severity: revised.severity,
|
||||
supporting_evidence_ids: revised.supporting_evidence_ids,
|
||||
contradicting_evidence_ids: revised.contradicting_evidence_ids,
|
||||
required_authority: revised.required_authority,
|
||||
required_confidence: revised.required_confidence,
|
||||
required_environment: revised.required_environment,
|
||||
recommended_probes: revised.recommended_probes,
|
||||
relationships: revised.relationships,
|
||||
resolution: revised.resolution,
|
||||
},
|
||||
"mixed-stale-update",
|
||||
);
|
||||
assert.equal(requireMcpToolError(stale).code, "revision_conflict");
|
||||
const tampered = structuredClone(original);
|
||||
const target = tampered.records.find(
|
||||
(record) => record.evidence_id === sourceId,
|
||||
);
|
||||
assert.ok(target);
|
||||
target.normalized_result = { checkpoint_tampered: true };
|
||||
const path = join(output, "tampered-import.json");
|
||||
await writeFile(path, JSON.stringify(tampered), { flag: "wx" });
|
||||
const rejected = await call(
|
||||
"import_evidence_bundle",
|
||||
{ path },
|
||||
"mixed-tampered-import",
|
||||
);
|
||||
assert.equal(
|
||||
requireMcpToolError(rejected).code,
|
||||
"evidence_integrity_mismatch",
|
||||
);
|
||||
const after = result(
|
||||
await call(
|
||||
"get_evidence_bundle",
|
||||
{ detail: "summary" },
|
||||
"mixed-after-refusals",
|
||||
),
|
||||
"get_evidence_bundle",
|
||||
);
|
||||
assert.deepEqual(after, before);
|
||||
};
|
||||
|
||||
/** Verify original mixed-history heads, CAS rejection and atomic import failure. */
|
||||
export const verifyMixedRetainedHistory = async (options) => {
|
||||
const { revised, headsChecked, pages } = await verifyFollowupPages(
|
||||
options.call,
|
||||
options.original,
|
||||
);
|
||||
await verifyMutationRefusals({ ...options, revised });
|
||||
return {
|
||||
heads_checked: headsChecked,
|
||||
pages,
|
||||
revised_unknown_id: revised.unknown_id,
|
||||
revision_checked: revised.revision,
|
||||
stale_update_rejected: true,
|
||||
tampered_import_rejected_atomically: true,
|
||||
};
|
||||
};
|
||||
|
||||
/** Closing must neither retain old Unknowns nor rehydrate a closed source. */
|
||||
export const verifyMixedRetainedClosure = async (call, sourceId) => {
|
||||
const unknowns = result(
|
||||
await call("list_unknowns", {}, "mixed-after-close-heads"),
|
||||
"list_unknowns",
|
||||
);
|
||||
assert.equal(unknowns.total, 0);
|
||||
const missing = await call(
|
||||
"inspect_analysis_view",
|
||||
{
|
||||
source: { kind: "retained-evidence", evidence_id: sourceId },
|
||||
view: { kind: "summary" },
|
||||
},
|
||||
"mixed-after-close-reference",
|
||||
);
|
||||
const failure = requireMcpToolError(missing);
|
||||
assert.equal(failure.details?.reason, "missing");
|
||||
return { unknowns_after_close: 0, old_reference_refused: true };
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
/** Keep settled and rejected RPCs in the same receipt before returning control. */
|
||||
export const createRetainedQueryCaller =
|
||||
(client, record) => async (name, input, phase) => {
|
||||
const start = performance.now();
|
||||
let reply;
|
||||
try {
|
||||
reply = await client.callTool(
|
||||
{ name, arguments: input },
|
||||
{ timeout: 300000 },
|
||||
);
|
||||
} catch (cause) {
|
||||
const failure =
|
||||
cause instanceof Error
|
||||
? { name: cause.name, message: cause.message }
|
||||
: { name: typeof cause, message: String(cause) };
|
||||
const receipt = {
|
||||
name,
|
||||
input,
|
||||
phase,
|
||||
elapsed_ms: performance.now() - start,
|
||||
reply_bytes: null,
|
||||
is_error: true,
|
||||
failure,
|
||||
};
|
||||
try {
|
||||
await record(receipt, { name, input, phase, failure });
|
||||
} catch (recordingFailure) {
|
||||
throw new AggregateError(
|
||||
[cause, recordingFailure],
|
||||
"MCP call and receipt recording both failed",
|
||||
);
|
||||
}
|
||||
throw cause;
|
||||
}
|
||||
const receipt = {
|
||||
name,
|
||||
input,
|
||||
phase,
|
||||
elapsed_ms: performance.now() - start,
|
||||
reply_bytes: Buffer.byteLength(JSON.stringify(reply)),
|
||||
is_error: reply.isError === true,
|
||||
};
|
||||
// A receipt-write failure is distinct from a rejected MCP call.
|
||||
await record(receipt, { name, input, phase, reply });
|
||||
return reply;
|
||||
};
|
||||
@@ -1,81 +0,0 @@
|
||||
import { rename, rm, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
const attempt = async (failures, phase, action) => {
|
||||
try {
|
||||
await action();
|
||||
return true;
|
||||
} catch (cause) {
|
||||
failures.push(`${phase}: ${String(cause)}`);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const writeReceipt = (stream, text) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const onError = (cause) => reject(cause);
|
||||
stream.once("error", onError);
|
||||
try {
|
||||
stream.write(text, (cause) => {
|
||||
if (cause !== null && cause !== undefined) {
|
||||
// A Writable emits its error after notifying the write callback.
|
||||
reject(cause);
|
||||
} else {
|
||||
stream.off("error", onError);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
} catch (cause) {
|
||||
stream.off("error", onError);
|
||||
reject(cause);
|
||||
}
|
||||
});
|
||||
|
||||
/** Preserve task costs through independent cleanup and receipt-output failures. */
|
||||
export const finalizeRetainedQueryReceipt = async ({
|
||||
report,
|
||||
client,
|
||||
transport,
|
||||
account,
|
||||
serverLog,
|
||||
serverLogFinished,
|
||||
output,
|
||||
stdout = process.stdout,
|
||||
}) => {
|
||||
report.cleanup_failures = [];
|
||||
await Promise.all([
|
||||
attempt(report.cleanup_failures, "client", () => client.close()),
|
||||
attempt(report.cleanup_failures, "transport", () => transport.close()),
|
||||
]);
|
||||
await attempt(report.cleanup_failures, "server-log", async () => {
|
||||
if (!serverLog.writableEnded) serverLog.end();
|
||||
await serverLogFinished;
|
||||
});
|
||||
if (report.cleanup_failures.length === 0)
|
||||
await attempt(report.cleanup_failures, "workspace", () =>
|
||||
rm(account, { recursive: true }),
|
||||
);
|
||||
if (report.cleanup_failures.length > 0) report.retained_workspace = account;
|
||||
|
||||
report.receipt_failures = [];
|
||||
let publication = 0;
|
||||
const saveReport = async () => {
|
||||
// Keep failed publications in the owned output directory for inspection.
|
||||
// A partial retry must never truncate an already published cost receipt.
|
||||
const pending = join(output, `.report-${++publication}.json.pending`);
|
||||
await writeFile(pending, JSON.stringify(report, null, 2) + "\n", {
|
||||
flag: "wx",
|
||||
});
|
||||
await rename(pending, join(output, "report.json"));
|
||||
};
|
||||
await attempt(report.receipt_failures, "report-file", saveReport);
|
||||
const stdoutWritten = await attempt(report.receipt_failures, "stdout", () =>
|
||||
writeReceipt(stdout, JSON.stringify(report) + "\n"),
|
||||
);
|
||||
// Preserve a broken stdout diagnostic in the file that may already exist.
|
||||
if (!stdoutWritten)
|
||||
await attempt(report.receipt_failures, "report-file-retry", saveReport);
|
||||
return (
|
||||
report.cleanup_failures.length === 0 && report.receipt_failures.length === 0
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
// Generate a complete declared-native baseline; do not infer tools from ordering.
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { resolve } from "node:path";
|
||||
import { Client } from "@modelcontextprotocol/client";
|
||||
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
||||
import { KUNA_OPERATIONS } from "../../dist/kuna/KunaProviderCapabilities.js";
|
||||
import {
|
||||
createVerifierRun,
|
||||
completeVerifierRun,
|
||||
assertVerifierCleanupComplete,
|
||||
} from "../../scripts/lib/verifier-run.mjs";
|
||||
|
||||
const [output] = process.argv.slice(2);
|
||||
assert.ok(output, "Usage: node select-kuna-tools.mjs NEW_OUTPUT_JSON");
|
||||
assert.equal(process.versions.node, (await readFile(".nvmrc", "utf8")).trim());
|
||||
const desired = new Set([
|
||||
...KUNA_OPERATIONS,
|
||||
"open_binary",
|
||||
"close_binary",
|
||||
"inspect_analysis_view",
|
||||
]);
|
||||
const run = createVerifierRun(),
|
||||
failures = [];
|
||||
const client = new Client({
|
||||
name: "rea-kuna-baseline-catalog",
|
||||
version: "0.1.0",
|
||||
});
|
||||
const transport = new StdioClientTransport({
|
||||
command: process.execPath,
|
||||
args: [resolve("scripts/rea.mjs"), "mcp"],
|
||||
env: {
|
||||
...process.env,
|
||||
// This pass needs tool identities, not large result schemas. Keep any
|
||||
// explicit caller profile; the measured runner already selects off.
|
||||
REA_MCP_OUTPUT_SCHEMA_PROFILE:
|
||||
process.env.REA_MCP_OUTPUT_SCHEMA_PROFILE ?? "off",
|
||||
},
|
||||
stderr: "pipe",
|
||||
});
|
||||
let names;
|
||||
try {
|
||||
await client.connect(transport);
|
||||
names = [];
|
||||
const cursors = new Set();
|
||||
let cursor;
|
||||
do {
|
||||
assert.ok(!cursors.has(cursor), "Catalog pagination did not advance");
|
||||
cursors.add(cursor);
|
||||
const page = await client.listTools(cursor === undefined ? {} : { cursor });
|
||||
names.push(
|
||||
...page.tools
|
||||
.filter((tool) => desired.has(tool.name))
|
||||
.map((tool) => tool.name),
|
||||
);
|
||||
cursor = page.nextCursor;
|
||||
} while (cursor !== undefined);
|
||||
assert.equal(
|
||||
new Set(names).size,
|
||||
names.length,
|
||||
"Ambiguous duplicate catalog names",
|
||||
);
|
||||
assert.deepEqual(
|
||||
[...desired].filter((name) => !names.includes(name)),
|
||||
[],
|
||||
"Declared native operation lacks a named MCP tool",
|
||||
);
|
||||
} catch (error) {
|
||||
failures.push(error.stack ?? String(error));
|
||||
} finally {
|
||||
await client.close();
|
||||
await transport.close();
|
||||
}
|
||||
const lifecycle = await completeVerifierRun(run);
|
||||
assertVerifierCleanupComplete(lifecycle.process_lineage);
|
||||
assert.deepEqual(failures, []);
|
||||
// Caller-selected artifact only; never replace an existing configuration/record.
|
||||
await writeFile(output, JSON.stringify(names, null, 2) + "\n", { flag: "wx" });
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
provider: "kuna",
|
||||
selection: "complete declared native operations plus session/views",
|
||||
names,
|
||||
lifecycle,
|
||||
scope:
|
||||
"Actual registered catalog matched by name to the compiled provider capability owner. No target opened; declared coverage does not prove live provider availability.",
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,46 @@
|
||||
import hashlib
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
|
||||
spec = importlib.util.spec_from_file_location('agent_trial', Path(__file__).with_name('agent-trial.py'))
|
||||
trial = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(trial)
|
||||
|
||||
|
||||
class ExperimentalEnginePinTests(unittest.TestCase):
|
||||
def test_missing_pin_preserves_other_provider_trials(self):
|
||||
self.assertIsNone(trial.pinned_experimental_engine({}))
|
||||
self.assertIsNone(trial.experimental_engine_unchanged(None))
|
||||
|
||||
def test_feature_build_replacement_and_removal_invalidate_pinned_engine(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
engine = Path(directory) / 'kuna'
|
||||
engine.write_bytes(b'embedded-spec-build')
|
||||
engine.chmod(0o755)
|
||||
settings = {'REA_KUNA_COMMAND': str(engine),
|
||||
'REA_ATOMIC_NATIVE_IR_ENGINE_SHA256': hashlib.sha256(engine.read_bytes()).hexdigest()}
|
||||
receipt = trial.pinned_experimental_engine(settings)
|
||||
self.assertTrue(trial.experimental_engine_unchanged(receipt))
|
||||
engine.write_bytes(b'non-embedded-test-build')
|
||||
with self.assertRaisesRegex(ValueError, 'differs from its pin'):
|
||||
trial.pinned_experimental_engine(settings)
|
||||
self.assertFalse(trial.experimental_engine_unchanged(receipt))
|
||||
engine.unlink()
|
||||
self.assertFalse(trial.experimental_engine_unchanged(receipt))
|
||||
with self.assertRaisesRegex(ValueError, 'absolute executable'):
|
||||
trial.pinned_experimental_engine(settings)
|
||||
|
||||
def test_malformed_pin_and_relative_command_are_rejected(self):
|
||||
for settings in [
|
||||
{'REA_ATOMIC_NATIVE_IR_ENGINE_SHA256': 'bad'},
|
||||
{'REA_ATOMIC_NATIVE_IR_ENGINE_SHA256': '0' * 64, 'REA_KUNA_COMMAND': './kuna'},
|
||||
]:
|
||||
with self.assertRaises(ValueError):
|
||||
trial.pinned_experimental_engine(settings)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -29,13 +29,16 @@ class PayloadObservationTests(unittest.TestCase):
|
||||
spec = importlib.util.spec_from_file_location('resource_run', Path(__file__).with_name('resource-run.py'))
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
arguments = ['resource-run.py', '--observe-payload-exit', '--task-ceiling', '1', '--', 'payload']
|
||||
with patch.object(sys, 'argv', arguments), patch.object(sys, 'stderr', io.StringIO()), \
|
||||
patch.object(module.subprocess, 'Popen') as spawn:
|
||||
with self.assertRaises(SystemExit) as failure:
|
||||
module.main()
|
||||
self.assertEqual(failure.exception.code, 2)
|
||||
spawn.assert_not_called()
|
||||
for flags in [['--observe-payload-exit', '--task-ceiling', '1'],
|
||||
['--early-stop-mib', '0'], ['--early-stop-mib', '3585']]:
|
||||
with self.subTest(flags=flags), \
|
||||
patch.object(sys, 'argv', ['resource-run.py', *flags, '--', 'payload']), \
|
||||
patch.object(sys, 'stderr', io.StringIO()), \
|
||||
patch.object(module.subprocess, 'Popen') as spawn:
|
||||
with self.assertRaises(SystemExit) as failure:
|
||||
module.main()
|
||||
self.assertEqual(failure.exception.code, 2)
|
||||
spawn.assert_not_called()
|
||||
|
||||
def test_preserves_nonzero_status_kernel_peak_and_nonzero_events(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
"""Deterministic RPC receipt failures; not real-provider or model evidence."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import unittest
|
||||
|
||||
|
||||
class RetainedQueryReceipts(unittest.TestCase):
|
||||
def run_node(self, body):
|
||||
module = Path(__file__).with_name('retained-query-calls.mjs').resolve().as_uri()
|
||||
finalizer = Path(__file__).with_name('retained-query-finalization.mjs').resolve().as_uri()
|
||||
source = ('import assert from "node:assert/strict";\n'
|
||||
'const {createRetainedQueryCaller} = await import(' + json.dumps(module) + ');\n'
|
||||
'const {finalizeRetainedQueryReceipt} = await import(' + json.dumps(finalizer) + ');\n' + body)
|
||||
result = subprocess.run(['node', '--input-type=module', '-'], input=source,
|
||||
text=True, capture_output=True, timeout=15)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
|
||||
def run_finalization(self, body):
|
||||
self.run_node('''
|
||||
import {mkdtemp,mkdir,readFile,writeFile,rm,stat} from 'node:fs/promises';
|
||||
import {join} from 'node:path';
|
||||
import {tmpdir} from 'node:os';
|
||||
import {Writable} from 'node:stream';
|
||||
import {finished} from 'node:stream/promises';
|
||||
const root=await mkdtemp(join(tmpdir(),'rea-receipt-test-'));
|
||||
const account=join(root,'account');const output=join(root,'output');
|
||||
await mkdir(account);await mkdir(output);
|
||||
const chunks=[];
|
||||
const stdout=new Writable({write(chunk,encoding,done){chunks.push(chunk.toString());done();}});
|
||||
const serverLog=new Writable({write(chunk,encoding,done){done();}});
|
||||
const serverLogFinished=finished(serverLog);serverLogFinished.catch(()=>{});
|
||||
const originalFailure={name:'Error',message:'original request failed'};
|
||||
const report={status:'failed',failure:originalFailure,calls:[{phase:'page',elapsed_ms:17}]};
|
||||
const input={report,client:{close:async()=>{}},transport:{close:async()=>{}},
|
||||
account,output,stdout,serverLog,serverLogFinished};
|
||||
const saved=async()=>JSON.parse(await readFile(join(output,'report.json'),'utf8'));
|
||||
try {
|
||||
''' + body + '''
|
||||
} finally {
|
||||
serverLog.destroy();await serverLogFinished.catch(()=>{});stdout.destroy();
|
||||
await rm(root,{recursive:true,force:true});
|
||||
}
|
||||
''')
|
||||
|
||||
def test_rejected_call_preserves_request_phase_cost_and_original_failure(self):
|
||||
self.run_node('''
|
||||
const failure = new Error('owned server closed');
|
||||
const input = {offset:0, limit:2}; const rows=[]; const events=[];
|
||||
const call = createRetainedQueryCaller({callTool:async request=>{
|
||||
assert.strictEqual(request.arguments,input);throw failure;
|
||||
}}, async(row,event)=>{rows.push(row);events.push(event);});
|
||||
await assert.rejects(call('list_unknowns',input,'resume-2'), e=>e===failure);
|
||||
assert.equal(rows.length,1);assert.equal(events.length,1);
|
||||
assert.strictEqual(rows[0].input,input);assert.equal(rows[0].name,'list_unknowns');
|
||||
assert.equal(rows[0].phase,'resume-2');assert.ok(rows[0].elapsed_ms>=0);
|
||||
assert.equal(rows[0].reply_bytes,null);assert.equal(rows[0].is_error,true);
|
||||
assert.deepEqual(events[0].failure,{name:'Error',message:'owned server closed'});
|
||||
''')
|
||||
|
||||
def test_protocol_error_is_a_received_reply_with_known_bytes(self):
|
||||
self.run_node('''
|
||||
const reply={isError:true,content:[{type:'text',text:'capacity refusal'}]};const rows=[];
|
||||
const call=createRetainedQueryCaller({callTool:async()=>reply},async row=>rows.push(row));
|
||||
assert.strictEqual(await call('get_evidence_bundle',{},'complete'),reply);
|
||||
assert.equal(rows.length,1);assert.equal(rows[0].is_error,true);
|
||||
assert.equal(rows[0].reply_bytes,Buffer.byteLength(JSON.stringify(reply)));
|
||||
assert.equal(Object.hasOwn(rows[0],'failure'),false);
|
||||
''')
|
||||
|
||||
def test_receipt_write_error_does_not_reclassify_a_completed_rpc(self):
|
||||
self.run_node('''
|
||||
const failure=new Error('receipt disk unavailable');const rows=[];
|
||||
const call=createRetainedQueryCaller({callTool:async()=>({content:[]})},async row=>{
|
||||
rows.push(row);throw failure;
|
||||
});
|
||||
await assert.rejects(call('list_unknowns',{},'read'),e=>e===failure);
|
||||
assert.equal(rows.length,1);assert.equal(rows[0].is_error,false);
|
||||
assert.equal(Object.hasOwn(rows[0],'failure'),false);
|
||||
''')
|
||||
|
||||
def test_failed_recording_preserves_the_prior_rpc_failure(self):
|
||||
self.run_node('''
|
||||
const rpc=new Error('request timeout');const disk=new Error('receipt close failed');
|
||||
const call=createRetainedQueryCaller({callTool:async()=>{throw rpc;}},async()=>{throw disk;});
|
||||
await assert.rejects(call('inspect_analysis_view',{},'selected'),e=>
|
||||
e instanceof AggregateError && e.errors[0]===rpc && e.errors[1]===disk);
|
||||
''')
|
||||
|
||||
def test_log_stream_failure_keeps_costs_both_receipts_and_workspace(self):
|
||||
self.run_finalization('''
|
||||
const log=new Writable({write(chunk,encoding,done){done(new Error('log disk failed'));}});
|
||||
const logFinished=finished(log);logFinished.catch(()=>{});log.write('diagnostic');
|
||||
assert.equal(await finalizeRetainedQueryReceipt({...input,serverLog:log,
|
||||
serverLogFinished:logFinished}),false);
|
||||
assert.match(report.cleanup_failures[0],/server-log:.*log disk failed/);
|
||||
assert.strictEqual(report.failure,originalFailure);
|
||||
assert.equal(report.calls[0].elapsed_ms,17);assert.equal(report.retained_workspace,account);
|
||||
assert.equal((await stat(account)).isDirectory(),true);
|
||||
assert.deepEqual(await saved(),report);assert.deepEqual(JSON.parse(chunks.join('')),report);
|
||||
''')
|
||||
|
||||
def test_workspace_removal_error_still_writes_the_original_failure(self):
|
||||
self.run_finalization('''
|
||||
const blocked=join(root,'owned-file');await writeFile(blocked,'owned');
|
||||
const malformedAccount=join(blocked,'child');
|
||||
assert.equal(await finalizeRetainedQueryReceipt({...input,account:malformedAccount}),false);
|
||||
assert.match(report.cleanup_failures[0],/^workspace:/);
|
||||
assert.equal(report.retained_workspace,malformedAccount);
|
||||
assert.deepEqual((await saved()).failure,originalFailure);
|
||||
assert.deepEqual(JSON.parse(chunks.join('')),report);
|
||||
''')
|
||||
|
||||
def test_report_file_refusal_preserves_the_stdout_receipt(self):
|
||||
self.run_finalization('''
|
||||
await mkdir(join(output,'report.json'));
|
||||
assert.equal(await finalizeRetainedQueryReceipt(input),false);
|
||||
assert.deepEqual(report.cleanup_failures,[]);
|
||||
assert.match(report.receipt_failures[0],/^report-file:/);
|
||||
assert.deepEqual(JSON.parse(chunks.join('')),report);
|
||||
assert.deepEqual(report.failure,originalFailure);
|
||||
''')
|
||||
|
||||
def test_stdout_write_error_is_handled_and_saved_in_the_file(self):
|
||||
self.run_finalization('''
|
||||
const failedStdout=new Writable({write(chunk,encoding,done){done(new Error('broken pipe'));}});
|
||||
assert.equal(await finalizeRetainedQueryReceipt({...input,stdout:failedStdout}),false);
|
||||
assert.match(report.receipt_failures[0],/stdout:.*broken pipe/);
|
||||
assert.deepEqual(await saved(),report);assert.deepEqual(report.failure,originalFailure);
|
||||
''')
|
||||
|
||||
def test_partial_retry_after_stdout_failure_preserves_the_prior_receipt(self):
|
||||
self.run_finalization('''
|
||||
const fs=await import('node:fs/promises');
|
||||
const {syncBuiltinESMExports}=await import('node:module');
|
||||
const originalWrite=fs.default.writeFile;let writes=0;let before;
|
||||
fs.default.writeFile=async(...args)=>{
|
||||
if(++writes===2){await originalWrite(args[0],'partial',args[2]);throw new Error('disk quota');}
|
||||
return originalWrite(...args);
|
||||
};
|
||||
syncBuiltinESMExports();
|
||||
try {
|
||||
const failedStdout=new Writable({async write(chunk,encoding,done){
|
||||
before=await readFile(join(output,'report.json'),'utf8');done(new Error('broken pipe'));
|
||||
}});
|
||||
assert.equal(await finalizeRetainedQueryReceipt({...input,stdout:failedStdout}),false);
|
||||
assert.equal(writes,2);assert.equal(report.receipt_failures.length,2);
|
||||
assert.match(report.receipt_failures[1],/report-file-retry:.*disk quota/);
|
||||
assert.equal(await readFile(join(output,'report.json'),'utf8'),before);
|
||||
assert.deepEqual((await saved()).failure,originalFailure);
|
||||
assert.equal((await saved()).calls[0].elapsed_ms,17);
|
||||
} finally {fs.default.writeFile=originalWrite;syncBuiltinESMExports();}
|
||||
''')
|
||||
|
||||
def test_failed_client_close_keeps_ownership_and_attempts_peer_cleanup(self):
|
||||
self.run_finalization('''
|
||||
const closed=[];
|
||||
assert.equal(await finalizeRetainedQueryReceipt({...input,
|
||||
client:{close(){closed.push('client');throw new Error('close failed');}},
|
||||
transport:{close:async()=>{closed.push('transport');}}}),false);
|
||||
assert.deepEqual(closed,['client','transport']);
|
||||
assert.match(report.cleanup_failures[0],/client:.*close failed/);
|
||||
assert.equal(report.retained_workspace,account);assert.equal(serverLog.writableEnded,true);
|
||||
assert.equal((await stat(account)).isDirectory(),true);
|
||||
assert.deepEqual(await saved(),report);assert.deepEqual(JSON.parse(chunks.join('')),report);
|
||||
''')
|
||||
@@ -0,0 +1,451 @@
|
||||
# Atomic RE through Code Mode
|
||||
|
||||
This is an **in-progress experiment**, not an integrated provider release. Branch
|
||||
`experiment/atomic-codemode-20261016` starts at main
|
||||
`42fc6c53ae188978deb3bedfe88287b6b316ba22` and carries the previous atomic-facts
|
||||
prototype. Historical measurements in `../atomic-re-tools/` retain their original
|
||||
baselines. No PR or merge is intended.
|
||||
|
||||
The branch was subsequently [refreshed from main `60bf10245`](main-refresh-study.md).
|
||||
Shared installation/file cleanup and string parsing now follow that main's
|
||||
owners. Historical model measurements retain their original frozen runtimes;
|
||||
the refresh has separate real-provider verification and resource receipts.
|
||||
|
||||
The goal is a real model completing reverse-engineering questions through
|
||||
composable facts, with Code Mode as the calling adapter. A configured feature flag,
|
||||
a scripted verifier or a small response does not prove that goal.
|
||||
|
||||
The [capability map](capability-map.md) distinguishes verified task coverage,
|
||||
experimental exporter requirements and remaining unknowns before interpreting
|
||||
adapter comparisons.
|
||||
|
||||
The [string-span study](string-span-study.md) adds paged incoming occurrence
|
||||
queries for encoded object spans and independently verifies pooled suffix
|
||||
references on real SQLite. The same native sparse range index serves Kuna's
|
||||
existing string aggregates. Equivalent cold occurrence retrieval falls from
|
||||
48.1 to 1.8 seconds; this is shared analysis reuse, not a Code Mode result.
|
||||
The subsequent frozen real-model runs all answer the selected task correctly:
|
||||
traditional takes 315.6 seconds, Direct 102.3 and Code Mode 93.6. Code Mode uses
|
||||
less cumulative input but more uncached input and peak memory than Direct.
|
||||
Traditional's full inventory is truncated by the client; one original cited
|
||||
payload remains only partially auditable. The study preserves that limitation.
|
||||
|
||||
The [string-fact precision study](string-facts-study.md) preserves native NUL
|
||||
termination as true/false/unknown through the shared domain and public output
|
||||
contract. Real canonical MCP, SDK, Direct, Code Mode and CLI checks retain both
|
||||
NUL-terminated strings and a nonterminated printable run without length-based
|
||||
agent inference. The old coarse descriptor remains compatible.
|
||||
Both fresh real models complete the same frozen task after this repair: Direct
|
||||
takes 95.2 seconds, Code Mode 90.9. Code Mode lowers cumulative input and peak
|
||||
memory but increases uncached input and CPU. The results do not isolate the
|
||||
metadata change's performance effect; all source and usage checks are recorded.
|
||||
|
||||
The [large-result study](large-result-study.md) verifies that paging alone does
|
||||
not bound a large field. String metadata can now be selected without text, while
|
||||
SDK full reads remain available. Shared pre-allocation JSON checks preserve
|
||||
context and Evidence on transport refusal, including in-program Code Mode
|
||||
recovery. The synthetic fixture tests capacity; it does not establish real-app
|
||||
analysis quality. Real SQLite/SSH regressions are reported separately.
|
||||
The subsequent real Code Mode model passes the frozen capacity task. Direct
|
||||
retrieves correct data but labels two 17-byte prefixes as 16, failing the exact
|
||||
reporting criterion. Both use metadata selection without sending full blobs.
|
||||
Code Mode uses less input but more wall time; the differing correctness and byte
|
||||
window choices prevent a matched-quality efficiency ranking. All runs remain.
|
||||
The [streamed inventory study](streamed-inventory-study.md) then restores real
|
||||
FFmpeg queries whose complete native source exceeds 8 MiB, using the production
|
||||
streaming parser and bounded retained files. Real SDK/MCP lanes pass; LLVM and
|
||||
Node still exceed the existing 64 MiB budget. Those failures remain explicit.
|
||||
Both real models now complete the FFmpeg task with all cited raw captures
|
||||
verified. Code Mode uses less cumulative input but more uncached input and time.
|
||||
The study also retains two evaluator namespace failures and their full costs;
|
||||
the corrected pair uses actual registered tool discovery.
|
||||
The [refusal-cache study](capacity-refusal-study.md) then avoids repeated native
|
||||
work for proven immutable source-budget failures. Real SDK and both MCP adapters
|
||||
verify reuse and readable partial Evidence; cancellation/cleanup uncertainty
|
||||
remain uncached. The first Code Mode precondition failure and its cost remain in
|
||||
the record. Larger-target inventory coverage is still unresolved.
|
||||
|
||||
The later [native query study](native-string-query-study.md) makes selected LLVM
|
||||
and Node string queries answerable without retaining a whole oversized inventory.
|
||||
Both frozen LLVM model answers pass; Code Mode uses fewer input tokens in that
|
||||
pair, with only a modest wall-time difference. The [shared byte checkpoint](byte-batch-study.md)
|
||||
then batches missing byte windows through one native program while retaining
|
||||
per-window facts and Evidence. A same-engine SDK toggle reduces ten-window cold
|
||||
retrieval from about 94.3 to 8.5 seconds. Real provider preflight passes; new model
|
||||
trials for this byte change were not run because the user cleared the goal.
|
||||
|
||||
The [AArch64 reference study](aarch64-xref-study.md) finds and fixes missing
|
||||
ADRP-based string and memory references before the next model comparison.
|
||||
Real SDK and traditional MCP preflights now agree with independent machine
|
||||
evidence; the shared bounded producer preserves space/width and uncertainty.
|
||||
All three real models now complete the behavior-level task. Code Mode takes
|
||||
151.3 seconds / 388,365 cumulative input tokens, Direct 164.9 / 515,929 and
|
||||
traditional 345.7 / 681,613. Code has more uncached input than traditional and
|
||||
more memory than Direct. These are the earlier pinned measurements.
|
||||
|
||||
The [return-coverage study](aarch64-return-study.md) subsequently fixes two
|
||||
independent producer defects: BTI import-entry identity and false no-return
|
||||
promotion that erased the post-warning path. All three fresh model answers pass
|
||||
the same selected task. Direct uses 351,157 cumulative input tokens / 139.0
|
||||
seconds, Code Mode 371,571 / 166.8, and traditional 662,683 / 263.1. Code Mode
|
||||
reduces MCP requests but adds model responses in this sample; correct primitives
|
||||
and fewer RPCs do not establish a stable adapter advantage.
|
||||
|
||||
The [architecture storage study](storage-study.md) adds exact native register-name
|
||||
and address-space queries, sharing one bounded immutable capture per lease.
|
||||
It separates coordinates, widths and native map misses from hardware absence,
|
||||
SSA equality or alias claims. Both real SSH models complete the extended task;
|
||||
Code Mode uses 307,888 versus 415,450 cumulative input tokens and 142.2 versus
|
||||
158.1 seconds, but more local CPU. This single pair does not establish a stable
|
||||
advantage; the full typecheck gate remains resource-limited.
|
||||
|
||||
The [function-boundary study](function-boundary-study.md) adds independent native
|
||||
prototype entries and return descriptors, separated from raw input varnodes.
|
||||
Both real SSH models correctly distinguish these inventories and compose the
|
||||
selected caller/parameter/helper transfer. Direct uses 331,674 cumulative input
|
||||
tokens / 118.4 seconds; Code Mode uses 359,789 / 125.7, with lower uncached input
|
||||
but mixed overall costs. Native and real-provider checks are recorded there.
|
||||
|
||||
The [path-query study](path-query-study.md) adds a shared, bounded recovered-CFG
|
||||
witness query with exclusions and paging. Both actual MCP adapters verify the
|
||||
same four real SQLite witnesses without requiring the model to fetch the entire
|
||||
graph. This establishes graph-relative facts; predicate feasibility stays unknown.
|
||||
Both real models now use the query and answer correctly on the same frozen
|
||||
controller task: direct takes 200.8 seconds / 495,895 cumulative input tokens;
|
||||
Code Mode takes 203.3 seconds / 554,477. Code Mode has lower uncached input,
|
||||
but no stable overall advantage is established. All prior pairs stay reported.
|
||||
|
||||
The [control-query study](control-query-study.md) verifies every derived control
|
||||
triple on the real SQLite VM, fixes unknown CFG seeds and reuses a lazy
|
||||
postdominator index. Its [two-level investigation](controller-oracle.md) is
|
||||
frozen before model runs and separates alternative path predicates, SSA identity
|
||||
and finite recovered-edge witnesses from runtime claims. Both real-model answers
|
||||
now pass: Code Mode reduces cumulative input but increases uncached input, time,
|
||||
CPU and memory in this pair. Correct facts support both calling strategies;
|
||||
the query-cache improvement is separate from those mixed whole-task costs.
|
||||
|
||||
The [discovery-summary study](discovery-summary-study.md) addresses repeated
|
||||
metadata from that pair. The complete method index now uses owned intent
|
||||
summaries; all full contracts and advertised tools remain available. Contracts
|
||||
and session admission have separate owners, with native loading deferred to open.
|
||||
Its repeat uses the same frozen control question and retains the earlier results.
|
||||
|
||||
That completed repeat again answers correctly in both lanes. The smaller index
|
||||
does not establish an overall task improvement: actual help use adds a Code Mode
|
||||
call, and cumulative/uncached tokens, local resources and end-to-end time have
|
||||
mixed changes. A large observed inter-call gap remains charged and unexplained.
|
||||
|
||||
The [exact-value query study](value-query-study.md) adds location-to-value and
|
||||
value-to-operand-use queries, including inputs/constants without defining operations.
|
||||
Real stripped OpenSSH checks preserve all 250 SSA versions / 369 occurrences at
|
||||
one selected policy location while reducing an equivalent core read task from
|
||||
244 queries to six. A subsequent [real-agent OpenSSH comparison](ssh-warning-study.md)
|
||||
completes the same machine-supported task through all three interfaces, after
|
||||
correcting an incomplete traditional evaluator toolset. Atomic direct has the
|
||||
lowest measured costs in this sample, using machine facts without decompilation;
|
||||
Code Mode uses the new queries but takes extra analysis steps. General efficiency
|
||||
claims still require broader evidence.
|
||||
|
||||
The reference is [Hex-Rays IDA MCP](https://github.com/HexRaysSA/ida-mcp/blob/df6de7985b534a964c125d5a86e41b26b17b14f6/ida_mcp/mcp.py):
|
||||
an on-demand `reference` lookup and an execution entrypoint over a richer analysis
|
||||
API. This experiment uses JavaScript and a QuickJS WASM environment rather than
|
||||
Python in the host process. It exposes only declared static analysis capabilities.
|
||||
It does not add target execution, patching or GUI control.
|
||||
|
||||
Three boundaries own the implementation:
|
||||
|
||||
- `provider.mjs`, `native-ir.mjs`: existing REA native target/process owners and parsed Kuna
|
||||
string/reference/SSA facts, retained sources, freshness and cleanup.
|
||||
- `api.mjs`: named, validated fact/relationship contracts and their intent summaries.
|
||||
`session.mjs` owns shared admission and lease/file cleanup, loading the native
|
||||
provider only on open. SDK callers, CLI scripts and both MCP adapters use these
|
||||
same contracts and application owner.
|
||||
- `executor.mjs`, `server.mjs`, `cli.mjs`: bounded JavaScript composition and
|
||||
presentation. No analysis is reimplemented in the execution environment.
|
||||
|
||||
The complete Code Mode MCP catalog is `open_binary`, `reference`,
|
||||
`execute_javascript`, `close_binary`. Setting `REA_ATOMIC_ADAPTER=direct` exposes
|
||||
the same fact API as `facts_*` MCP operations for comparison. This is a distinct
|
||||
experimental server; the production REA catalog is not filtered or replaced.
|
||||
|
||||
Use the pinned Node, an existing REA build and a caller-supplied Kuna 1.833:
|
||||
|
||||
```sh
|
||||
npm ci --prefix experiments/atomic-codemode --ignore-scripts
|
||||
node --test experiments/atomic-codemode/*.test.mjs
|
||||
REA_KUNA_COMMAND=/absolute/path/to/kuna node experiments/atomic-codemode/server.mjs
|
||||
```
|
||||
|
||||
The local MCP registration for real model trials is named `rea-codemode`.
|
||||
`agent-trial.py --mcp-entrypoint /absolute/path/to/server.mjs
|
||||
--server-name rea-codemode --protocol-profile atomic --profile-parent /tmp` creates an isolated
|
||||
configuration, home and empty working directory for the model. Shell/file tools,
|
||||
web search and delegation are disabled. No repository or oracle is placed in that
|
||||
workspace. The copied authentication file is removed with the isolated profile.
|
||||
Model output, actual MCP calls, original errors and usage remain in the trial
|
||||
directory. `REA_ATOMIC_TRACE` and `REA_ATOMIC_EVIDENCE_DIR` retain actual API calls
|
||||
and complete sources outside the model workspace when explicitly selected by the
|
||||
evaluator. The ambient environment and credentials are not logged.
|
||||
|
||||
Current bounds: 64 MiB guest heap, 32 KiB code and script value/error payloads, 64 host calls per execution,
|
||||
120 seconds wall deadline and 2 seconds of guest synchronous execution. Native
|
||||
requests use existing supervision and a 1 GiB function-memory limit. Buffered
|
||||
formats and diagnostics keep an 8 MiB bound; string inventories stream through
|
||||
the production reader into the existing 64 MiB per-target source budget, without
|
||||
an aggregate stdout string. Two resident function indexes each derive from at
|
||||
most 2 MiB diagnostic or 8 MiB native wire source. Compressed native graphs admit at most 32 MiB decoded
|
||||
JSON plus independent row/text/relationship bounds. One decoded Evidence text view
|
||||
up to 32 MiB is also retained per lease; these source bounds are not parsed-heap
|
||||
size guarantees. Sources are
|
||||
content-digested and retained until close; explicit evaluator copies survive
|
||||
close. Capacity failures are explicit, not clipped facts. Leases and snapshot
|
||||
handles prevent cross-session joins.
|
||||
|
||||
The current experimental MCP profile also caps encoded tool-result bodies at
|
||||
1 MiB, including text escaping and metadata; JSON-RPC/client framing is separate.
|
||||
`reference.transport_limits` advertises this policy in both modes. The QuickJS
|
||||
bridge remains 2 MiB. CLI/SDK transports have their own bounds; SDK full selected
|
||||
string values remain available. Prefer `strings({query,fields:[]})` for metadata.
|
||||
|
||||
Invocation context and observed source IDs are additional bounded receipt
|
||||
metadata; the script payload bound is not a 32 KiB whole-MCP-wire limit. A real
|
||||
MCP probe found that a 40,000-byte guest exception bypassed that payload policy
|
||||
and produced a 40,183-byte response. Oversized errors now return explicit
|
||||
`output_budget` with omission metadata. Escaping expansion is checked too;
|
||||
ordinary smaller errors remain intact. `verify-executor.mjs` confirms real MCP
|
||||
delivery and continued access to source Evidence collected before the exception.
|
||||
It measures response bytes, not model tokens or an analysis speedup. Targeted JS
|
||||
tests at this stage totaled 42, alongside the separate real-provider and native-writer checks.
|
||||
|
||||
The diagnostic SSA format still has incomplete CFG and phi predecessor coverage.
|
||||
The opt-in [native recovered IR experiment](native-engine.md) adds full recovered
|
||||
CFG edges, exact value/operand identities, phi incoming-edge bindings, selected
|
||||
`values`/`blocks` reads and derived control dependence. It requires an explicitly
|
||||
pinned patched engine; stock Kuna does not gain those capabilities from a wrapper.
|
||||
Runtime successors, memory aliases and machine-semantic equivalence remain
|
||||
unknown. Other providers are not yet wired to this experimental service.
|
||||
|
||||
The initial [actual model comparison](trials.md) favors the focused traditional
|
||||
workflow. The seeded value-origin task has lower cumulative input and wall time
|
||||
through Code Mode, but initially exposes an IR-to-machine-path error. The revised
|
||||
trial correctly explains that machine path with lower observed task costs;
|
||||
broader claims still require more than this single seeded task.
|
||||
|
||||
The large SQLite VM diagnostic task also completes when its native graph exceeds
|
||||
capacity. Atomic direct beats Code Mode on cumulative input and wall time in
|
||||
that sample, and a traditional reused-project run is fastest. The actual CLI
|
||||
client already exposes JavaScript dispatch in every lane, regardless of requested
|
||||
feature flags. MCP request counts therefore do not establish fewer model rounds;
|
||||
the ledger now records actual model responses and client dispatch/wait calls.
|
||||
|
||||
`instructions` reads selected machine byte/decode windows through the same
|
||||
owner. Recovered operations use `origin_address` and blocks `origin_start`;
|
||||
these locations cannot be substituted for machine branch destinations. The
|
||||
value-origin trial demonstrates why this boundary matters. The experiment
|
||||
now has nineteen fact methods, still behind the same four-tool Code Mode
|
||||
catalog.
|
||||
|
||||
`calls` connects recovered call operations to native target specifications and
|
||||
separates argument SSA values from passing storage. `values(is_input:true)`
|
||||
selects retained callee inputs for exact storage comparisons. These candidate
|
||||
links preserve snapshot identities, missing specifications, unknown storage and
|
||||
runtime-binding limits. The [cross-function task and oracle](call-oracle.md)
|
||||
are fixed before its real-model trials; the graph wire format is version 3, with independent version-1 call facts.
|
||||
|
||||
`references` now selects incoming exact-address references or outgoing
|
||||
instruction/function references, with native kind filtering, field selection and
|
||||
paging. Source Evidence plus `source_row` identifies an occurrence. Function
|
||||
applicability, excluded/unattributed rows, indirect targets and discovery stay
|
||||
explicit. `fields:[]` requests only the always-retained identity columns across
|
||||
projection contracts. The [reference question and independent oracle](reference-oracle.md)
|
||||
cover real SQLite VM aggregates and a machine call omitted from optimized IR.
|
||||
|
||||
`bytes` reads explicit virtual-address ranges as native loaded-image hex without
|
||||
decoding them as instructions. Batched reads preserve short reads and individual
|
||||
failures, with 64 KiB aggregate selected-byte capacity to bound hex/bridge growth.
|
||||
Complete hexdumps remain in Evidence. The original-file-offset mapping and live
|
||||
runtime memory remain unknown. This closes a direct byte-reading contract gap
|
||||
for data tables; it does not establish arbitrary memory-alias analysis.
|
||||
|
||||
`functions` provides selected name/alias/entry reads. Native snapshots report
|
||||
code and recovered-IR facets separately, preserving readable code when graph
|
||||
extraction is unavailable. Real capacity and cold/warm MCP checks are documented
|
||||
in [native-engine.md](native-engine.md). Whole-model costs and unequal-depth
|
||||
comparisons remain separate in the trial report.
|
||||
|
||||
The corrected SQLite comparison reaches the formatter implementation in all
|
||||
three interfaces. Code Mode uses fewer calls than atomic direct in that sample;
|
||||
a traditional run reusing its persistent whole-project cache is faster than
|
||||
Code Mode's fresh lease. Cache state, completed-answer coverage and actual
|
||||
uncached tokens must therefore accompany any cost comparison.
|
||||
|
||||
SDK views share immutable parsed inventories with their owner. A real SDK probe
|
||||
initially changed a returned string and made the next query disappear under the
|
||||
same Evidence ID. Freezing at the cache boundary fixes that producing rule,
|
||||
without copying or parsing the entire inventory for each read. `verify-sdk.mjs`
|
||||
checks the real provider's string/metadata/function views and complete retained
|
||||
source digest. The fixed probe passes under the bounded runner (1.328 seconds,
|
||||
1.144 family CPU seconds, 110.6 MiB kernel family peak, zero OOM kills and verified
|
||||
payload cleanup); it is a correctness check, not a model-cost measurement.
|
||||
|
||||
Encoded size is another real coverage boundary: two SQLite functions initially
|
||||
lose even their C because pretty JSON exceeds transport capacity. The native
|
||||
patch now uses bounded compact serialization and a graph-only failure when
|
||||
needed. Parser's full graph fits; Pragma retains identical C with an explicit
|
||||
missing graph. The 8 MiB bound remains. See the exact sizes, rebuilt engine digest
|
||||
and verification scope in [native-engine.md](native-engine.md).
|
||||
|
||||
Completion requires actual model Code Mode use, independently checked task
|
||||
answers, shared atomic/direct/Code Mode semantics, needed relation coverage,
|
||||
failure/cancellation/identity tests, and equivalent completed-task measurements
|
||||
including discovery/retries, actual model usage, cold/warm analysis, CPU and
|
||||
process-family peak memory. Negative cases such as the small SQLite function
|
||||
must remain in the comparison.
|
||||
|
||||
The outgoing-reference real-model pair now completes with identical required
|
||||
facts and explicit coverage limits. In its single sample, Code Mode uses 264,680
|
||||
cumulative input / 93.837 seconds versus direct's 285,086 / 106.183. The shared
|
||||
CLI/API also verifies the VM aggregates on unpatched stock Kuna 1.833. These are
|
||||
scoped positive results alongside the earlier mixed adapter comparisons, not
|
||||
proof of general superiority. Details and retained failed/partial attempts are
|
||||
in [trials.md](trials.md).
|
||||
|
||||
Recovered calls and their boundary values now survive full-graph capacity
|
||||
failure. The real VM capture preserves 416 call operations and 1,294 boundary
|
||||
values while its graph remains unavailable. Values clearly state their partial
|
||||
scope; definition IDs do not imply readable defining operations. See the
|
||||
[boundary question and oracle](boundary-oracle.md) and its completed real-model
|
||||
pair in [trials.md](trials.md). Both answers pass, using one VM capture each.
|
||||
Code Mode's single-sample latency is lower, with mixed context costs; broader
|
||||
efficiency remains unproven. The focused JS suite at that stage passes 49 tests.
|
||||
|
||||
Available snapshot call facets now include `by_opcode` known/unknown-target
|
||||
counts and their own coverage. The owner derives them once from the same
|
||||
validated immutable calls used by selected reads, including dead operations;
|
||||
target knowledge is independent of opcode. Empty available facets report zeros,
|
||||
while unavailable facets omit counts. This small aggregate addresses an observed
|
||||
cost in the real boundary pair: paging the entire call set just to count it.
|
||||
Both subsequent real-model answers satisfy the unchanged question/oracle without
|
||||
that paging. In the new sample direct is faster and lower on cumulative/uncached
|
||||
input than Code Mode, reversing the preceding latency ordering. Whole-task
|
||||
effects remain mixed; see [the complete results](trials.md). This aggregate is a
|
||||
shared fact-layer improvement, available to either adapter.
|
||||
|
||||
The shared owner also checks the native cleanup `Result` before releasing its
|
||||
lease or clearing retained state. A tagged cleanup failure now stays retryable;
|
||||
MCP errors retain the lease context and reported resources. The real SDK
|
||||
failure-injection verifier first reproduces the old false success, then verifies
|
||||
both close and target replacement retain the staged file/owner until a successful
|
||||
retry. Both public MCP adapters preserve that error and retry successfully.
|
||||
These use an injected tagged failure, not an observed engine cleanup incident;
|
||||
native reads and subsequent cleanup use the real provider. See the recorded
|
||||
scope and resource receipts in [native-engine.md](native-engine.md).
|
||||
|
||||
A [subsequent diagnostic probe](projection-experiment.md) measures the VM's full
|
||||
17 MB recovered graph and much smaller selected definition neighborhoods. It
|
||||
supports trying a bounded operation/value facet, while preserving unresolved
|
||||
definitions and unavailable CFG. The following implementation now makes that
|
||||
facet callable; the original diagnostic remains separate from public results.
|
||||
|
||||
`snapshot.facets.operations` distinguishes a complete recovered graph from a
|
||||
bounded call-rooted definition projection. `operations`, `values`, selected
|
||||
definition/use `relations` and `slice` share the same parsed operation owner in
|
||||
either case. Projection coverage preserves unexpanded definition counts and
|
||||
selected slice frontier reasons; CFG/controller reads remain unavailable.
|
||||
Native operation reads retain `is_dead` and literal operand/value identities.
|
||||
Coverage returns compact counts and bounded issue text, with complete native
|
||||
details retained in Evidence. [The new question/oracle](projection-oracle.md)
|
||||
are fixed before real-model trials of the PHI format alternatives.
|
||||
|
||||
Both first PHI-format model answers pass the full oracle using one VM analysis
|
||||
and a six-operation selected trace, with the global graph/use limits intact.
|
||||
The trace reveals two format sources at each shared call, verified against byte
|
||||
and machine evidence. [Costs and source review](trials.md) also record a direct
|
||||
documentation-lookup miss; named discovery needs fixing before rerunning the
|
||||
same task. No general adapter speedup follows from that first pair.
|
||||
|
||||
Named reference lookup now accepts canonical IDs or exact displayed names,
|
||||
including space/comma-separated lists. One presentation map supplies direct
|
||||
registration and documentation names; unmatched terms remain explicit. Selected
|
||||
schemas come from named contracts, use input semantics (defaulted fields stay
|
||||
optional), and are cached immutably by Zod schema identity for the process.
|
||||
Validation stays in the API registry; documentation has its own module. Both
|
||||
actual MCP catalogs and all fourteen reference schemas validate. The unchanged
|
||||
PHI question/oracle were rerun: both answers pass again, but direct has a native
|
||||
timeout followed by a successful retry. Complete costs and the unknown timeout
|
||||
cause remain in [trials.md](trials.md); this does not isolate an adapter speedup.
|
||||
|
||||
The next observed atom boundary is a wide PHI. One real VM operation has 156
|
||||
inputs; its old default single-node slice is about 44 KB and exceeds the guest's
|
||||
32 KiB result budget. Native operation/slice defaults now return opcode, output
|
||||
and exact input/definition/constant counts. Explicit detailed fields still work.
|
||||
`relations({kind:"operands",seeds:[id],input_indices:[0,105,155]})` reads selected
|
||||
slots; omitting the selector pages all slots. Each slot retains value/definition
|
||||
and phi predecessor/edge identity, including null values and definition-free
|
||||
constants/inputs. Counts concern recovered facts, not source function arity.
|
||||
|
||||
Full and projected native operations use the same owner. Relationship paging
|
||||
counts existing groups before materializing only the requested page; identity
|
||||
reads deduplicate requested IDs in caller order. Diagnostic SSA explicitly lacks
|
||||
native operand relations. The discriminated relation schema advertises the same
|
||||
seed types and selector applicability enforced at runtime. The fourteen-method
|
||||
API and both adapters remain shared; no new engine or output-budget increase is
|
||||
needed. The [seeded wide-operand task/oracle](operands-oracle.md) is separate from
|
||||
the earlier PHI-format question and is pinned before model trials.
|
||||
|
||||
Both actual wide-operand model answers now pass that fixed oracle, including
|
||||
distinct edges sharing a value and absent-slot versus unretained-seed semantics.
|
||||
Each performs one native analysis and reads only selected slots, distinct values
|
||||
and their immediate definitions. Code Mode takes 95.699 seconds versus direct's
|
||||
91.817, with nearly equal cumulative input and lower uncached input. Its four
|
||||
discovery lookups prevent fewer MCP requests from becoming fewer model responses.
|
||||
These [mixed costs](trials.md#selected-wide-phi-input-relationships) validate the
|
||||
fact boundary while leaving broad efficiency unproven. The current shared JS
|
||||
suite passes 57 tests; the Python cost-ledger suite passes three.
|
||||
|
||||
Discovery now also offers `reference({view:"index"})`: the complete fourteen
|
||||
method names and descriptions, without schemas or return contracts. Follow with
|
||||
`view:"contracts"` and exact names for only the needed inputs. The default
|
||||
contract view and named/topic lookup stay compatible. Both views use the same
|
||||
registry and presentation map; index access never constructs unrequested schemas.
|
||||
The index describes declared methods, while `snapshot` remains the live coverage
|
||||
authority. This addresses observed blind discovery without inventing aliases or
|
||||
changing analysis facts; its whole-task effect must be measured on the unchanged
|
||||
wide-operand question.
|
||||
|
||||
The identical question now completes correctly through both indexed adapters.
|
||||
Code Mode uses the intended index plus one named lookup; discovery drops from
|
||||
four calls to two, without changing the seven fact reads. The new pair takes
|
||||
about 98.8 seconds each; cumulative input favors direct, uncached input favors
|
||||
Code Mode. All four wide-operand answers pass, with no retry or OOM. Costs remain
|
||||
mixed. A selected-slot read still incurs whole-function native decompilation on
|
||||
a fresh lease; phase profiling is the next computation question, separate from
|
||||
the now finer fact/query boundary.
|
||||
|
||||
The [native phase study](native-compute-study.md) now measures the VM drive at
|
||||
about 34 seconds, C rendering at 0.22 seconds and projection at 0.03 seconds.
|
||||
Repeated new native processes do not gain the API owner's warm result reuse.
|
||||
Its subsequent [bounded codec implementation](native-graph-transport-study.md)
|
||||
now returns the complete 21,349-operation VM graph in about 3.79 MB, inside the
|
||||
unchanged 8 MiB wire budget. Selected definitions/CFG reads and decoded Evidence
|
||||
work through both real MCP adapters; all graph fields and ordinary C/calls match
|
||||
the prior complete golden. Same-lease reuse is about 67 ms after a 39.7-second
|
||||
fresh capture, with resource limits and no OOM. The [next question/oracle](savepoint-control-oracle.md)
|
||||
start from names/error messages and exercise the new condition/CFG coverage.
|
||||
Two [real-model pairs](savepoint-control-study.md), including a discovery-guided
|
||||
repeat, answer both local guards correctly without a whole-report fetch. Code
|
||||
Mode uses fewer MCP requests, but whole-task costs are mixed and a large capture
|
||||
time variation remains unexplained. Both clients already provide JavaScript
|
||||
orchestration. Source fidelity is not machine equivalence, provider parity or a
|
||||
general speedup. The [native switch experiment](switch-study.md) now exports and independently checks
|
||||
182 labels over those 149 targets, exposes selected case-to-edge relations and
|
||||
keeps them readable when a 2 MiB native output budget omits the full graph.
|
||||
Both real models now answer the selected-case/default question correctly using
|
||||
one retained capture and focused case/byte reads. Code Mode uses fewer tokens
|
||||
in this pair, but unequal native capture time and extra client polling confound
|
||||
the comparison. Whole-task costs and limits are in the same study; a general
|
||||
efficiency advantage remains unproved. A common
|
||||
[long-wait repeat](client-wait-study.md) reduces polling to one wait per lane;
|
||||
both answers remain correct, but direct wins cumulative input and wall time
|
||||
while Code Mode uses less uncached input. Runtime correctness, discovery,
|
||||
composition choices and waiting all matter to the completed task.
|
||||
@@ -0,0 +1,251 @@
|
||||
# AArch64 import entries and return coverage
|
||||
|
||||
Two independent producer defects are corrected: BTI import-entry identity and
|
||||
false no-return promotion that erased a post-warning path. A fresh three-way
|
||||
model run passes the selected task oracle with all interfaces. Direct atomic
|
||||
reads use less cumulative and uncached input and finish sooner than Code Mode
|
||||
in this sample, despite more MCP requests. Correct primitive facts are useful;
|
||||
the extra Code Mode layer does not automatically improve a completed task.
|
||||
|
||||
This continues the [three-way warning investigation](aarch64-xref-study.md),
|
||||
where all three interfaces encountered the same dropped post-warning path.
|
||||
|
||||
## PLT entry checkpoint
|
||||
|
||||
The actual Debian arm64 SSH fixture remains SHA-256
|
||||
`de352e4ace7028d9816fd0ee9d22936bc1b5622c400d5b0b7df660df3426b068`,
|
||||
1,051,744 bytes, extracted and never executed. The independent
|
||||
[machine verifier](verify-aarch64-machine.py) checks the warning epilogue's
|
||||
restored LR/SP, tail branch `0x25858 → 0xbad0`, BTI at that entry, ADRP at
|
||||
`0xbad4`, loaded GOT slot `0x10f390`, and its `free@GLIBC_2.17` JUMP_SLOT
|
||||
relocation. GNU objdump's neighbouring synthetic PLT label is not authoritative
|
||||
symbol identity. Actual runtime binding, pointer authentication and path
|
||||
feasibility remain unknown.
|
||||
|
||||
The old loader recognizes an ADRP/LDR pair and names the ADRP address. The
|
||||
resulting inventory splits `sub_bad0` (4 bytes) from `free` at `0xbad4` (20).
|
||||
The corrected owner recognizes the complete standard veneer, optional immediate
|
||||
BTI c prefix and optional AUTIA1716. It uses the ADRP's own PC and exact
|
||||
relocation slot, without assuming a PLT stride. Complete load/add/branch
|
||||
agreement is required before consuming a relocation. Truncated/corrupt sequences,
|
||||
ordinary preceding instructions, missing slots, misalignment and overflowing
|
||||
instruction ranges cannot manufacture an entry.
|
||||
|
||||
The AArch64 decoder and its tests move into `loader/elf_plt/aarch64.rs`;
|
||||
section and PT_DYNAMIC paths call that single owner. The parent still owns GOT
|
||||
name correlation and deduplication. These supported sequences follow Arm's
|
||||
[System V ABI examples](https://github.com/ARM-software/abi-aa/blob/main/sysvabi64/sysvabi64.rst#sample-plt-sequences).
|
||||
Other veneer forms stay unrecognized. This experiment does not establish full
|
||||
Ghidra loader/analyzer parity.
|
||||
|
||||
REA refreshed main through `d5be402fb3dbfc56ac9854c27b5538df20cc2437`
|
||||
(merge `d3443521d`); native upstream stays
|
||||
`fe01d6294eb0d1053ce343c8943646df88e143fc`. The PLT-only overlay hash is
|
||||
`ec660ee463d46e95bc76a9c80e0889ee65443748f1196ad61c4464352dfc8c19`.
|
||||
Copied immutable embed-specs/opt1 engine SHA-256:
|
||||
`646c49341f9f55147ce9363d8f3e33b69860a830dbd1b88beea339db88ff2fe9`.
|
||||
The previous engine is `e43185ff11e74c18753e8755c7757ef6ede415c87a1dac9f04bb39856de87f43`.
|
||||
|
||||
Six new test groups first ran against the old decoder: five failed, one passed.
|
||||
All 13 PLT decoder tests then passed, including seven AArch64 groups and the
|
||||
other architectures' retained cases. The real public SDK inventory now places
|
||||
`free` at `0xbad0` and `_exit` at `0xbdd0`; their former ADRP-body entries disappear.
|
||||
The warning's recovered tail call names `free`. The real native CLI
|
||||
[loader verifier](verify-aarch64-plt.py) checks both the original ELF section
|
||||
path and PT_DYNAMIC fallback using a separately hashed derived copy with only
|
||||
ELF section-header coordinates zeroed. Both produce the corrected entries.
|
||||
Neither input is executed. Both patch application directions pass.
|
||||
The original and sectionless inventories contain 1713 and 518 entries; this
|
||||
check compares selected imports, not whole-inventory completeness. PAC coverage
|
||||
uses synthetic byte fixtures; the real SSH checks exercise the BTI form.
|
||||
|
||||
| Executed check | Family wall s | Family CPU s | Kernel family peak MiB |
|
||||
| ------------------------------------------------------------------------- | ------------- | ------------ | ---------------------- |
|
||||
| Refreshed REA runtime build | 34.141 | 32.976667 | 3039.0 |
|
||||
| Six new groups against old decoder, expected failure | 123.335 | 122.063494 | 1031.2 |
|
||||
| All 13 PLT tests after correction, including compile | 68.475 | 68.217534 | 887.9 |
|
||||
| Corrected native CLI build | 102.486 | 102.098492 | 625.3 |
|
||||
| Old-engine SDK inventory/references/two captures/full source verification | 14.314 | 14.060418 | 389.6 |
|
||||
| PLT-only engine, equivalent SDK workflow | 14.312 | 14.080485 | 388.5 |
|
||||
| Real CLI, both loader paths | 4.045 | 3.744119 | 101.9 |
|
||||
|
||||
All listed scopes verify payload cleanup, observed OOM 0, one CPU and the existing
|
||||
4 GiB hard/3 GiB early-stop memory guard. Peaks include charged file cache and
|
||||
are not RSS; verified payload-exit counters are not final whole-scope counters.
|
||||
SDK sessions use fresh retained-evidence stores; OS cache state is uncontrolled.
|
||||
The single equivalent SDK pair does not establish a performance improvement.
|
||||
No new model/token measurement or broad repository typecheck is claimed here.
|
||||
|
||||
The PLT-only correction **does not** restore the caller's strict diagnostic:
|
||||
its recovered call facet still omits `0x2854c`, and C still marks the warning
|
||||
call at `0x2841c` no-return. This controlled result separates the import-entry
|
||||
defect from the no-return defect. The discovered-no-return pass has a weaker
|
||||
terminal-call promotion than the existing propagation walk: it observes a
|
||||
terminal call somewhere and absence of RET, without rejecting an escaping tail
|
||||
transfer to possibly returning code. Causality and the structural correction
|
||||
require their own checks; the entry fix alone is not claimed to solve it.
|
||||
|
||||
## No-return ownership checkpoint
|
||||
|
||||
With the PLT-only engine unchanged, disabling only `noreturn_disc` restores the
|
||||
caller call at `0x2854c` and removes the false no-return annotation from the
|
||||
warning call at `0x2841c`. That native CLI counterfactual takes 5.052 s wall,
|
||||
4.813974 s local family CPU, 175.6 MiB kernel family peak, with verified cleanup
|
||||
and observed OOM 0. It isolates the discovered pass; it is not the final fix or
|
||||
the configuration supplied to model evaluators.
|
||||
|
||||
The discovered pass's duplicate promotion scanned a whole function span for
|
||||
any terminal call and no RET. An alternative tail transfer to a returning
|
||||
import therefore failed to protect the caller's continuation. The correction
|
||||
removes that interpretation and shares the propagation pass's conservative
|
||||
reachable-path walk. Known terminal transfers stop a path; returning tails,
|
||||
missing successors, unresolved indirect jumps and escaping branches cannot
|
||||
prove the whole function no-return. A dead, unreachable RET no longer prevents
|
||||
legitimate promotion. Existing call-site threshold and strict-successor options
|
||||
remain, but an absent local successor contributes no new vote: it is compatible
|
||||
with a returning tail call. The inspected
|
||||
[Ghidra analyzer](https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/FindNoReturnFunctionsAnalyzer.java)
|
||||
also skips calls without fall-through when looking for new indicators; this is
|
||||
source comparison, not a real-Ghidra runtime verification.
|
||||
|
||||
The shared entry first checks for any terminal-transfer candidate before
|
||||
allocating a body map or visiting its CFG. That necessary-condition check also
|
||||
applies to the existing propagation consumer. Terminal sets still grow during
|
||||
the bounded fixpoint, so false results are not cached across changing sets.
|
||||
There is no added long-lived graph cache or duplicate adapter interpretation.
|
||||
|
||||
Five new semantic test groups cover the fatal/returning-tail alternative,
|
||||
four different unknown exits, genuine terminal paths with a dead RET, a
|
||||
transitive wrapper fixpoint, and missing versus positively identified
|
||||
successors. Against the old rule, four groups fail and the wrapper group passes
|
||||
(the two pre-existing smoke tests also pass). After the correction, all 39
|
||||
no-return-related tests pass, including those groups. Expected-failure run:
|
||||
68.371 s wall / 68.147478 s CPU / 889.2 MiB peak. Passing run including compile:
|
||||
73.808 s / 72.914925 s / 892.6 MiB. Both have verified cleanup and observed OOM 0.
|
||||
An earlier syntax-error attempt is not counted as a semantic regression run.
|
||||
|
||||
The final overlay SHA-256 is
|
||||
`597b5236c42b214b88da39afe0f2b2b1cd7c5ff82e512e91d6a3249bfef565f1`;
|
||||
the immutable engine SHA-256 is
|
||||
`0969be0c9c3ace9357acce1f802f12e8595bc57445da32937933de543ca77672`.
|
||||
Forward-index and reverse-worktree application checks pass. The public
|
||||
[SDK verifier](verify-aarch64-returns.mjs) now finds the strict call at
|
||||
`0x2854c`, removes the false warning-call annotation, retains the genuine fatal
|
||||
call annotation, verifies canonical import ownership and byte identity, hashes
|
||||
all retained sources, and checks complete C/source fidelity and warm reuse.
|
||||
Warm captures retain identical handles/facts: warning 0.770 ms / 0.000797 CPU s;
|
||||
caller 0.702 ms / 0.000761 CPU s. Cold captures take 2033.6 / 5857.3 ms and
|
||||
2.023671 / 5.835244 CPU s respectively. These are lease cache observations, not
|
||||
OS-cold or model-task measurements.
|
||||
|
||||
| Executed check after no-return correction | Family wall s | Family CPU s | Kernel family peak MiB |
|
||||
| --------------------------------------------------------------------- | ------------- | ------------ | ---------------------- |
|
||||
| Native CLI build | 212.756 | 166.409933 | 629.8 |
|
||||
| New SDK return/source verifier | 13.606 | 13.381336 | 421.9 |
|
||||
| Equivalent earlier SDK inventory/references/two captures/full sources | 15.632 | 15.370816 | 415.7 |
|
||||
| Existing AArch64 xrefs/GOT reads/source regression | 13.309 | 13.018756 | 206.9 |
|
||||
| Complete old x86 function/prototype fidelity through MCP | 9.080 | 8.790274 | 308.5 |
|
||||
| All 87 experimental JS tests | 5.355 | 5.055786 | 83.8 |
|
||||
| Both actual catalogs and converted schemas | 1.936 | 1.712823 | 136.3 |
|
||||
| Both real native ELF loader paths | 4.047 | 3.799690 | 101.1 |
|
||||
|
||||
All these successful scopes verify cleanup and observed OOM 0 under the same
|
||||
resource bounds. Wall/CPU divergence occurred during compilation; attribution
|
||||
between host contention and changed compilation is unmeasured. The equivalent
|
||||
SDK task is slower than the PLT-only 14.312 s / 14.080485 CPU s / 388.5 MiB
|
||||
sample, while retaining the previously missing path. This single sequential
|
||||
pair does not establish a general performance delta. Changed-file JS lint,
|
||||
format and Python compilation checks pass. Broad repository type checking
|
||||
retains the previously disclosed resource-limited gap.
|
||||
|
||||
## Fresh real-model comparison after both corrections
|
||||
|
||||
All three trials freeze REA runtime
|
||||
`bf9d3a6e47de1e16a7eefb58bf385dfbe093fdb9`, the final engine above, the same
|
||||
target and the unchanged [question](aarch64-warning-question.txt). Trial prefixes
|
||||
are `arm-return-{direct,codemode,traditional}-v1` under the ignored local cache.
|
||||
Execution order is Direct, Code Mode, traditional. Each uses a fresh isolated
|
||||
Codex profile; traditional gets a new project-cache directory and the atomic
|
||||
modes get new evidence stores. Each requests `gpt-6.1-sol` with high
|
||||
reasoning through Codex 0.161.0, and receives its actual advertised tools:
|
||||
22 Direct, 4 Code Mode, or all 16 Kuna-supported traditional tools. Discovery
|
||||
and SDK-converted schema verification precede these runs. No runtime or engine
|
||||
mutation occurs during the three trials.
|
||||
|
||||
| Whole-task observation | Traditional | Code Mode | Direct atomic |
|
||||
| -------------------------------------------- | ----------: | --------: | ------------: |
|
||||
| Cumulative input tokens | 662,683 | 371,571 | 351,157 |
|
||||
| Cached input, included above | 570,368 | 323,968 | 310,912 |
|
||||
| Uncached input | 92,315 | 47,603 | 40,245 |
|
||||
| Output tokens | 5,304 | 6,069 | 5,402 |
|
||||
| Reasoning tokens, included in output | 1,181 | 1,586 | 1,379 |
|
||||
| Model responses | 20 | 14 | 12 |
|
||||
| Client executor calls / waits | 15 / 4 | 13 / 0 | 11 / 0 |
|
||||
| MCP attempts | 20 | 13 | 25 |
|
||||
| Rejected MCP attempts | 2 | 0 | 0 |
|
||||
| Reference-document requests, included in MCP | — | 3 | 1 |
|
||||
| Shared fact API calls | — | 23 | 22 |
|
||||
| Model wall seconds | 263.085 | 166.756 | 139.033 |
|
||||
| Family wall seconds | 263.580 | 167.258 | 139.587 |
|
||||
| Local family CPU seconds | 166.299552 | 41.040445 | 34.362879 |
|
||||
| Kernel family peak MiB | 1279.4 | 617.0 | 625.2 |
|
||||
|
||||
The unique per-response usage sums match each runner total. Cache writes are
|
||||
zero. All three runs preserve runtime/engine/target fingerprints, close the
|
||||
target, remove their isolated profiles, verify payload cleanup and observe OOM 0. Whole-scope final counters remain unavailable; family CPU/memory use verified
|
||||
payload-exit observations. Memory includes charged file cache, not just RSS.
|
||||
Remote compute, resolved service model build, OS cache state and host contention
|
||||
are unmeasured. Fresh local profiles do not imply cold OS or remote model caches.
|
||||
|
||||
Code Mode executes its 23 fact calls inside eight `execute_javascript` requests;
|
||||
Direct issues 22 `facts_*` requests. Each mode retains the same two complete
|
||||
native function documents, verified equal, including restored strict call
|
||||
`0x2854c`, the selected pointer bindings, and the warning's named `free` tail.
|
||||
Code Mode requests three snapshots but captures only two distinct sources; a
|
||||
repeat uses the existing lease cache. Different queries/field selections and
|
||||
model response counts are part of the measured workflows, not equal instruction
|
||||
traces. Both modes, and traditional, also have the same client-side JavaScript
|
||||
executor available. This compares MCP/API surfaces, not JavaScript versus its
|
||||
absence.
|
||||
|
||||
The traditional run first passes xref instruction addresses `0x25750` and
|
||||
`0x2853c` to an exact-entry analysis operation; both are correctly rejected. It
|
||||
recovers with `list_procedures`. Traditional `xrefs` normalizes these results to
|
||||
address strings; the atomic response also supplies native owning-function
|
||||
facts. Those navigation differences and retries are counted. Its two successful
|
||||
function dossiers share the same ready project-export key
|
||||
`dbfd828b95d9c1a2981707728a9e31b4c38688162e851a904c3808fd911c79eb`.
|
||||
Higher CPU is not evidence of a broken project cache. Traditional project export
|
||||
and per-function atomic export remain different native analysis profiles; the
|
||||
comparison does not isolate transport or schema cost from analysis scope.
|
||||
|
||||
All complete answers were read and passed agent review against the frozen
|
||||
question, independent file/GNU oracle, selected additional GNU checks and their
|
||||
actual delivered Evidence. Each identifies both functions, proves the selected
|
||||
pointer transfer and first helper target, verifies format formation/passing,
|
||||
the four-byte test and actual zero/nonzero successors, conditional cleanup
|
||||
return, and the necessary runtime/logging/alias limitations. This is selected
|
||||
task correctness, not human readiness or general analysis completeness.
|
||||
|
||||
Every cited source is verified: 11 traditional, 14 Code Mode and 14 Direct IDs.
|
||||
Traditional projected views correctly have their own provider and null engine
|
||||
profile; their explicit parent-Evidence links trace to the pinned engine. An
|
||||
initial audit incorrectly required a native engine profile on each projection;
|
||||
the corrected audit follows that provenance chain and passes. Atomic retained
|
||||
source byte counts/digests, target/engine contexts, selected native call/value
|
||||
bindings, restored strict call and complete selected-function equality pass.
|
||||
Answer SHA-256 values are:
|
||||
|
||||
- Traditional: `655877f07ce8819e7f086c584b49fb6d63dd2a7319c792deb09a721092eb7c5b`
|
||||
- Code Mode: `35d96912940a3a51704093d08ab228aea3e40fbdc80085d8137385f0d9199f61`
|
||||
- Direct: `24b1f3954397c3c30686a199189d0a37b61bc6ce74dfc49cfc061e79fe5c7fa9`
|
||||
|
||||
The local `return-model-costs.json`, `return-answer-checks.json` and
|
||||
`return-answer-review.json` retain the detailed receipts/review; raw model and
|
||||
native captures remain ignored. The earlier Code Mode advantage does not repeat:
|
||||
this sample uses 5.8% more cumulative input, 18.3% more uncached input and 19.9%
|
||||
more model wall time than Direct. Its memory peak is slightly lower. One
|
||||
sequential sample with different model choices cannot establish a stable winner
|
||||
or attribute the change solely to the fixes. It supplies a concrete counterexample
|
||||
to treating fewer RPCs as proof of fewer tokens or faster completed analysis.
|
||||
Broader complex-software effectiveness remains unproved.
|
||||
@@ -0,0 +1,92 @@
|
||||
# AArch64 OpenSSH warning oracle
|
||||
|
||||
Freeze the question, oracle, source runtime, immutable engine and complete
|
||||
catalogs before real models. This is a behavior/machine question, without
|
||||
native-only SSA or prototype-count requirements. The traditional native
|
||||
Kuna workflow is a valid comparison when its complete tools and evidence
|
||||
can answer the same question. No question addresses or answers are supplied
|
||||
to the isolated model workspaces.
|
||||
|
||||
Target: extracted Debian `openssh-client_10.0p1-7+deb13u4_arm64.deb`, never
|
||||
installed or executed. ELF size 1,051,744, SHA-256
|
||||
`de352e4ace7028d9816fd0ee9d22936bc1b5622c400d5b0b7df660df3426b068`.
|
||||
Package/provenance and signature-verification limits are in [the storage study](storage-study.md).
|
||||
All lanes use immutable embed-specs/opt1 engine SHA-256
|
||||
`e43185ff11e74c18753e8755c7757ef6ede415c87a1dac9f04bb39856de87f43`.
|
||||
The backend xref correction benefits every lane; old engines with missing
|
||||
AArch64 facts are not used as a scored traditional baseline.
|
||||
|
||||
Independent GNU AArch64 disassembly and FDEs identify banner function
|
||||
`0x256c0..0x25888`, selected caller `0x27848..0x297d4`. The public
|
||||
[file/machine verifier](verify-aarch64-machine.py) checks selected ELF words,
|
||||
ADRP/ADD math, direct/conditional branch targets, the GOT slot/relocation and
|
||||
GNU unwind ranges without consuming Kuna output. Native SDK/source fidelity
|
||||
is checked separately. GNU nearest-export labels are not original function names.
|
||||
|
||||
Required facts and interpretations:
|
||||
|
||||
- Banner format is `0xb0468`: `ADRP X6,0xb0000` at `0x2574c`, then
|
||||
`ADD X6,X6,0x468` at `0x25750`, then `BL 0x5ae04` at `0x25754`.
|
||||
The incoming data-reference site is the completing ADD, owned by `0x256c0`.
|
||||
X6 holds the format pointer at the call. No banner-format stack slot or
|
||||
original source argument ordinal should be invented from the x86 study.
|
||||
- Strict format is `0xb1330`: `ADRP X6,0xb1000` at `0x28534`, unrelated
|
||||
`MOV X5,0` at `0x28538`, completing `ADD X6,X6,0x330` at `0x2853c`,
|
||||
and `BL 0x5ae04` at `0x2854c`. Reference owner is `0x27848`.
|
||||
- Banner function has selected incoming calls `0x2841c` from `0x27848` and
|
||||
`0x29ccc` from `0x297e0`. Select the caller by the strict diagnostic and
|
||||
corroboration, not by address/name ordering or an original source-name guess.
|
||||
- Selected pointer setup is `MOV X0,X27` at `0x28414`, then
|
||||
`BL 0x256c0` at `0x2841c`. In the callee `MOV X23,X0` at `0x256e8`
|
||||
preserves the incoming pointer; X0 is not rewritten before the first helper
|
||||
`BL 0x3d108` at `0x256f0`. Matching native passing/input tuples, if used,
|
||||
remain snapshot-scoped correlations and not global SSA/alias equality.
|
||||
- Local decision loads **four bytes**: `LDR W0,[X25,0x88]` at `0x2851c`.
|
||||
`CBZ W0,0x28554` at `0x28524` takes the zero successor `0x28554`;
|
||||
nonzero falls through to `0x28528`, which prepares the strict diagnostic.
|
||||
The normalized static model names the tested global `dat_1104f8`.
|
||||
- The address recovery is corroborated by `ADRP X25,0x10f000` at `0x27904`
|
||||
and `LDR X25,[X25,0xf20]` at `0x27908`: slot `0x10ff20`, initial/model
|
||||
bytes `7004110000000000` = `0x110470`, plus field offset `0x88` gives
|
||||
static image coordinate `0x1104f8`. Independent ELF relocation is
|
||||
`R_AARCH64_RELATIVE` with addend `0x110470`. An ABI-conforming initial
|
||||
relocation uses load bias plus addend; this is not a captured live pointer
|
||||
or a read of the tested runtime value. Across calls, interpreting X25 as
|
||||
preserved relies on the ordinary callee-save model, not a proved runtime path.
|
||||
See [Arm ELF relocation semantics](https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst#dynamic-relocations)
|
||||
and [AAPCS64 registers](https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#general-purpose-registers).
|
||||
- After the strict logging call, `B 0x281c0` at `0x28550` enters cleanup.
|
||||
Its selected returning route sets `W0=0xffffffff` at `0x281f4` and reaches
|
||||
`RET X30` at `0x28264`; intervening calls, the stack-check branch at
|
||||
`0x28214` and pointer authentication can prevent runtime return. Report low
|
||||
32 bits `0xffffffff` (signed 32-bit -1), without inventing the original return type.
|
||||
- The banner call precedes this policy test. It alone is not proof of rejection.
|
||||
Zero enters more checks at `0x28554`, not proof of acceptance/login. The
|
||||
static initial global/pointer is not a runtime value, alias or binding proof.
|
||||
|
||||
Score complete final answers against owner/caller, both address formations,
|
||||
selected pointer/helper transfer, tested storage/width and zero/nonzero machine
|
||||
successors, cleanup/low return bits, Evidence/target identities, necessary
|
||||
unknowns and close. Accept native C/model recovery corroborated by machine
|
||||
addressing for the static global, or selected loaded-image bytes plus instruction
|
||||
arithmetic; do not require an unavailable native-only representation. Explicitly
|
||||
label weaker/missing coverage rather than treating missing facts as completion.
|
||||
|
||||
Preflight confirms both strings/xrefs, both selected C/assembly dossiers and
|
||||
the correct artifact through the real traditional MCP. It resolves the same
|
||||
static `dat_1104f8`. Its 95.291-second first dossier waits for whole-program
|
||||
export; later reads reuse that cache. This preflight is not a model trial.
|
||||
|
||||
Both atomic catalogs are complete (twenty-two direct / four Code tools), and
|
||||
the baseline includes all thirteen declared Kuna native operations plus
|
||||
open/close/retained views (sixteen tools), generated from the capability owner
|
||||
and actual catalog. Use the same question, requested gpt-6.1-sol/high, fresh
|
||||
isolated profiles/private caches, common envelope/discovery/stopping/wait
|
||||
guidance and one-CPU / 4 GiB hard / 3 GiB early-stop bounds. Planned order is
|
||||
traditional → Code Mode → direct, pinned before launch. Charge every attempt,
|
||||
whole-task cumulative/cached/uncached input, output/reasoning, responses,
|
||||
calls/retries/waits, elapsed/CPU and kernel family peak memory. Existing client
|
||||
JavaScript dispatch is present in every lane. Native profiles differ: selected
|
||||
atomic windows/functions versus traditional whole-program export. This is a
|
||||
workflow comparison, not an isolated dispatch-only or same-native-work ablation.
|
||||
Remote build/compute, OS/model caches and host contention remain unknown.
|
||||
@@ -0,0 +1,30 @@
|
||||
Analyze {{artifact_path}} statically, starting from these observed formats:
|
||||
- REMOTE HOST IDENTIFICATION HAS CHANGED
|
||||
- Host key for %.200s has changed and you have requested strict checking.
|
||||
|
||||
Find the function that supplies the banner format to a formatting/logging call,
|
||||
and the caller that owns the second diagnostic. Establish both from references
|
||||
and corroborating function facts; do not guess original source names. Show the
|
||||
selected direct call from that caller into the warning function. Trace its
|
||||
passed pointer into the warning function's first helper-call use, including
|
||||
machine passing locations and call targets. If using SSA, keep the snapshots'
|
||||
value identities separate; matching storage is not a general alias proof.
|
||||
|
||||
Show how the banner format pointer is formed and passed to its formatting/
|
||||
logging call. Verify the essential address formation, register or stack passing
|
||||
location and transfer against selected machine instructions. Recovered origins
|
||||
or operand slots alone do not establish machine addresses or source ordinals.
|
||||
|
||||
In the selected caller, after the warning call returns, identify the local test
|
||||
that chooses the strict-checking diagnostic versus continuation. Report the
|
||||
tested storage and width, both actual machine successors with zero/nonzero
|
||||
behavior, and the selected failure-cleanup path's low 32-bit return value.
|
||||
Distinguish machine addressing from any static model's global-address recovery;
|
||||
do not present an initial/model pointer as observed live memory. Does selecting
|
||||
the banner alone prove rejection? Does zero prove a connection will be accepted?
|
||||
|
||||
Give a focused answer with function/instruction addresses, real Evidence IDs,
|
||||
target digest and necessary coverage. Prefer selected facts/windows; do not
|
||||
return full reports or inventories to model context. Preserve unknown runtime
|
||||
values, relocation/binding state, aliases, logging behavior, other paths and
|
||||
runtime feasibility. Do not execute the target. Close the target lease.
|
||||
@@ -0,0 +1,230 @@
|
||||
# Composable AArch64 address references
|
||||
|
||||
The AArch64 OpenSSH check exposed a real completeness gap before another model
|
||||
comparison: both warning strings were present, but Kuna returned zero incoming
|
||||
references for either. Native observations had unknown discovery coverage;
|
||||
zero was not proof that the strings were unused. Independent GNU decoding
|
||||
showed ADRP plus ADD at `0x2574c/0x25750` and `0x28534/0x2853c`.
|
||||
|
||||
The query scanner read one instruction's p-code at a time. The existing ARM
|
||||
pool-displacement tracker supplied the relevant bounded value-flow owner, but
|
||||
did not carry AArch64 page bases. The experiment extends that owner rather than
|
||||
introducing another interpreter or postprocessing disassembly text. SLEIGH's
|
||||
mnemonic licenses ADRP, and its exact constant COPY supplies the coordinate;
|
||||
COPY/ADD/SUB then propagate the value. Machine operand text and hardcoded
|
||||
register-offset tables are not reparsed. Possible page copies alone, such as
|
||||
ordinary MOV-immediate instructions, do not establish PC provenance.
|
||||
|
||||
The same calculation produces Data for materialized register addresses, or
|
||||
Read/Write for a LOAD/STORE through a composed default-data-space byte address.
|
||||
The accessed cell is identified; its mutable/GOT contents are not propagated
|
||||
as a live value. This also covers the selected GOT slot, which an intermediate
|
||||
address-only fix still missed. Space-selector constants and stored values are
|
||||
not mistaken for access pointers.
|
||||
|
||||
The directly related refactor renames the former private pool-only module to
|
||||
`kuna_pc_relative`, moves its tests out of the implementation and retains one
|
||||
value lookup for arithmetic and memory accesses. Keys preserve native space
|
||||
identity, offset and width. Partial overwrites invalidate overlaps; copies can
|
||||
carry a known value into a different register. Calls/jumps/returns stop carry,
|
||||
instruction-local predicates do not execute both arms sequentially, a pool
|
||||
load overwritten later in the same instruction cannot seed a stale value,
|
||||
unsupported widths remain unknown and interval checks include the final u64
|
||||
byte without overflow. Empty/failed assembly rendering cannot license ADRP.
|
||||
|
||||
State remains function-local, follows fall-through addresses and keeps the
|
||||
existing eight-hop/eight-value bounds. It is not a complete fixed-point,
|
||||
cross-call, alias, runtime-value or feasible-path analysis. Unknown discovery
|
||||
and indirect-target coverage remain explicit through the shared parser and
|
||||
SDK/CLI/MCP views. Both experimental adapters and the traditional Kuna provider
|
||||
consume the corrected native producer; no special advantage is injected into
|
||||
one evaluator lane. Stock Kuna is not silently upgraded.
|
||||
|
||||
## Pins and real artifacts
|
||||
|
||||
REA refreshed main through `0d2247428` before this work. The native upstream is
|
||||
`fe01d6294eb0d1053ce343c8943646df88e143fc`, overlay SHA-256
|
||||
`62cb9d9386d110ca1301d4f7d541d0d1ee676f17ca888163cf7d69d8a9d07c53`.
|
||||
The copied immutable embed-specs/opt1 engine SHA-256 is
|
||||
`e43185ff11e74c18753e8755c7757ef6ede415c87a1dac9f04bb39856de87f43`.
|
||||
Default forward-index and reverse-worktree patch checks pass. New analysis
|
||||
patch sections use Git-supported unprefixed empty context lines, preserving
|
||||
line counts/source bytes without whitespace-only lines in the patch artifact.
|
||||
|
||||
The target is extracted Debian arm64 OpenSSH, SHA-256
|
||||
`de352e4ace7028d9816fd0ee9d22936bc1b5622c400d5b0b7df660df3426b068`.
|
||||
The [storage study](storage-study.md) records its package URL, digest and
|
||||
unverified package-signature scope. It was neither installed nor executed.
|
||||
The [independent machine oracle](verify-aarch64-machine.py) reads checked
|
||||
file-backed ELF ranges, validates selected instruction/branch math and GNU FDEs,
|
||||
and confirms the selected RELATIVE relocation. It does not read Kuna output.
|
||||
The oracle refuses optimized Python rather than silently disabling assertions.
|
||||
|
||||
The real SDK verifier returns one reference for `0xb0468`, from `0x25750`,
|
||||
owned by `0x256c0`; and one for `0xb1330`, from `0x2853c`, owned by `0x27848`.
|
||||
It also verifies both direct caller sites and 77 reads of GOT slot `0x10ff20`,
|
||||
including `0x256d0`, `0x27908`, `0x27dcc` and `0x28eb8`. The slot's selected
|
||||
loaded-image bytes agree with the independent file read, while runtime memory
|
||||
remains not-observed. Full retained source digests are verified. A warm repeat
|
||||
uses the same Evidence IDs and identical facts.
|
||||
|
||||
## Executed checks and costs before model trials
|
||||
|
||||
| Check | Family wall s | Family CPU s | Kernel family peak MiB |
|
||||
| ------------------------------------------------------------- | ------------- | ------------ | ---------------------- |
|
||||
| Refreshed REA runtime build | 36.660 | 35.931222 | 2989.1 |
|
||||
| 17 final PC-relative tests, including compile | 69.090 | 68.844945 | 885.1 |
|
||||
| All 125 Listing tests, including those 17 | 0.524 | 0.349058 | 59.2 |
|
||||
| Final native CLI build | 104.525 | 104.240617 | 630.2 |
|
||||
| Real AArch64 SDK/source verifier | 13.109 | 12.857963 | 203.1 |
|
||||
| Old x86 complete-function/prototype fidelity through real MCP | 8.779 | 8.516305 | 302.0 |
|
||||
| Both actual atomic catalogs and converted schemas | 1.932 | 1.689159 | 139.3 |
|
||||
| All 87 experimental JS tests | 5.060 | 4.890171 | 78.8 |
|
||||
| Complete traditional capability/catalog selection | 4.148 | 3.761593 | 443.2 |
|
||||
| Actual traditional MCP target/C/assembly preflight | 103.002 | 102.596202 | 872.3 |
|
||||
|
||||
The independent machine verifier, changed-file lint/format checks and patch
|
||||
application checks also pass; their CPU/memory costs were not separately measured.
|
||||
All measured successful runs have observed OOM 0 and verified payload cleanup.
|
||||
Resource scopes use one CPU, 4 GiB hard/3 GiB early-stop memory, TasksMax192 and
|
||||
swap disabled. Peaks include charged file cache and are not RSS. Final
|
||||
whole-scope counters are unavailable; table values use verified payload-exit
|
||||
observations. Broad repository type checking retains the previously reported
|
||||
resource-limited gap; no passing full typecheck/native corpus gate is claimed.
|
||||
|
||||
The 17 PC-relative tests include the retained pool-displacement cases and new
|
||||
page/copy/space/width/clobber/predicate/access cases; they are included in the
|
||||
125 Listing tests, not additional independent executions. An intermediate run
|
||||
passed 16/17: its obsolete assertion expected no reference when a composed
|
||||
temporary was dereferenced. The intended extension now identifies that actual
|
||||
cell Read while retaining the negative assertion against a register address-taken
|
||||
claim. The test was updated to require exactly that stronger typed outcome.
|
||||
All failed/intermediate receipts remain local; they are not model attempts.
|
||||
|
||||
The AArch64 two-address reference batch takes 3,548.3 ms wall / 3.535213 CPU s
|
||||
on a fresh lease, versus 1.54 ms / 0.001539 s for the same-lease repeat. This
|
||||
shows retained-source reuse, not faster native discovery. Old engine c48ad957
|
||||
returned incorrect zero results; its costs are not an equivalent completed-task
|
||||
performance baseline for those new facts.
|
||||
|
||||
A separate equivalent x86 task requests the same three exact-address reference
|
||||
sets before/after. Every normalized fact and coverage field agrees (counts
|
||||
1/1/2), using fresh leases/private caches. Its old/new cold phase is
|
||||
4,028.3/4,082.2 ms wall and 3.993216/4.031850 CPU s; warm is 3.30/2.38 ms.
|
||||
Whole-run wall is 4.852/4.852 s, CPU 4.554857/4.580338 s, peak 155.3/157.4 MiB.
|
||||
This single lookup repeat shows no material observed regression for that case;
|
||||
it is not a model-token measurement or a general speed guarantee. OS/cache and
|
||||
host variation remain uncontrolled.
|
||||
|
||||
## Frozen model task
|
||||
|
||||
The [question](aarch64-warning-question.txt) and [oracle](aarch64-warning-oracle.md)
|
||||
ask the same behavior-level warning/pointer/guard/cleanup question through
|
||||
three complete interfaces. Native SSA identities are optional. Traditional
|
||||
preflight supplies the same strings, actual references, both C/assembly dossiers,
|
||||
and recovered static `dat_1104f8`, with target/engine digests verified. Its first
|
||||
dossier costs 95.291 s waiting for whole-program export; later assembly/dossier
|
||||
reads reuse that cache. Atomic selected-native profiles differ, so the planned
|
||||
comparison is a full workflow comparison, not a dispatch-only ablation.
|
||||
|
||||
The runtime/question/oracle are frozen at
|
||||
`5eede35c978c76ff9215443ed0a0d5980bfbdfe1`. Execution order is traditional →
|
||||
Code Mode → direct. All request gpt-6.1-sol/high via Codex 0.161.0, with fresh
|
||||
isolated profiles/private caches and the same task. Both atomic catalogs are
|
||||
complete (22/4 tools); the traditional set contains every declared Kuna native
|
||||
operation and session/views (16 tools). Each client actually has JavaScript
|
||||
dispatch. This compares MCP workflows inside that common client surface.
|
||||
|
||||
All three complete answers pass agent review against the frozen oracle. They
|
||||
identify both owners, the X27→X0 pointer/helper transfer, banner ADRP/ADD into
|
||||
X6, four-byte field/CBZ successors, static versus live pointer knowledge,
|
||||
cleanup/low return bits, Evidence/target identities, unknowns and close. The
|
||||
traditional answer uses native C recovery plus machine addressing for the static
|
||||
global; both atomic answers also read the selected loaded-image pointer bytes.
|
||||
No native-only representation is required to pass.
|
||||
|
||||
Separate scripted checks verify all seven traditional, fifteen Code and fourteen
|
||||
Direct cited sources against delivered responses/traces and target/engine
|
||||
identities. Atomic retained source hashes/lengths agree; complete selected native
|
||||
function documents are identical between the two atomic lanes. Selected native
|
||||
argument/value/passing tuples and the PHI/input distinction match the delivered
|
||||
graphs/call facets. The independent ELF/GNU oracle checks the machine facts.
|
||||
Supplementary GNU checks corroborate the traditional answer's added logging
|
||||
wrapper call at `0x5ae6c → 0x5abb0`, with X6 unchanged. Source/fidelity checks
|
||||
are separate from agent review of the entire natural-language answers; neither
|
||||
constitutes human readiness or global machine-equivalence verification.
|
||||
|
||||
| Whole completed task | Traditional | Code Mode | Direct atomic |
|
||||
| ----------------------------------------------------- | ----------- | ----------------------------- | --------------- |
|
||||
| Required answer | pass | pass | pass |
|
||||
| Cumulative input tokens | 681,613 | 388,365 | 515,929 |
|
||||
| Cached input, included above | 639,360 | 336,000 | 436,224 |
|
||||
| Uncached input | 42,253 | 52,365 | 79,705 |
|
||||
| Output tokens | 5,423 | 5,755 | 6,529 |
|
||||
| Reasoning, included in output | 1,324 | 1,137 | 1,934 |
|
||||
| Unique model responses | 23 | 13 | 15 |
|
||||
| Client executor / wait calls | 16 / 6 | 12 / 0 | 14 / 0 |
|
||||
| MCP attempts, including failures/discovery/open/close | 13 | 12 | 31 |
|
||||
| Rejected MCP attempts | 2 | 0 | 0 |
|
||||
| Atomic fact reads | n/a | 25 inner reads | 25 direct reads |
|
||||
| Native function dossiers / snapshot requests | 4 dossiers | 3 requests, 2 unique captures | 2 captures |
|
||||
| Model wall seconds | 345.676 | 151.264 | 164.942 |
|
||||
| Family wall seconds | 346.217 | 151.834 | 165.421 |
|
||||
| Local family CPU seconds | 186.786767 | 41.152525 | 43.116751 |
|
||||
| Kernel family peak MiB | 973.1 | 695.7 | 600.4 |
|
||||
|
||||
Both traditional rejections are instruction-interior addresses passed to exact
|
||||
procedure lookup. The inventory was available, the model used it and completed;
|
||||
this is not the earlier under-equipped baseline. All four traditional dossiers
|
||||
report the same ready project-export key, so the observation does not establish
|
||||
a broken project cache. Its extra logging-wrapper investigations and native
|
||||
profile add work beyond the two selected atomic captures. All attempts remain
|
||||
charged; failed/intermediate development checks are separate from model trials.
|
||||
|
||||
Code uses 24.7% less cumulative input and less wall/CPU time than Direct in
|
||||
this pair, but more peak memory. Compared with traditional it uses 43.0% less
|
||||
cumulative input and less wall/CPU/memory, but **23.9% more uncached input** and
|
||||
more output. There are only two fewer model responses than Direct, despite
|
||||
nineteen fewer MCP requests. Same fact-read counts do not mean identical native
|
||||
work. This is one new architecture/version sample with uncontrolled OS/model
|
||||
caches, host contention, service build and remote compute, not a stable Code
|
||||
Mode advantage, a price claim or broad complex-software superiority.
|
||||
|
||||
Unique per-response usage sums match the task totals. All target, engine and
|
||||
runtime fingerprints remain unchanged. All three profiles are removed; verified
|
||||
payload-exit observations show OOM 0 and descendant cleanup. The same resource
|
||||
bounds and kernel-memory interpretation as above apply.
|
||||
|
||||
Raw model records are `arm-warning-{traditional,codemode,direct}-v1/` with sibling
|
||||
resource logs/configs; atomic traces and explicitly retained sources have matching
|
||||
prefixes. Derived records are `arm-model-costs.json`, `arm-answer-checks.json`,
|
||||
`arm-answer-review.json` and `arm-traditional-delivered-evidence.json`. Reviewed
|
||||
answer SHA-256 values are:
|
||||
|
||||
- Traditional: `5312aa0757b35b8a28b8d1c60af652760e445b0463117eb41def1e2eeb5031eb`
|
||||
- Code: `e331df37f53e58a85bea61f37b5e3b7c6a6848af78a0225383df0d9a481121a7`
|
||||
- Direct: `792b613d25e9c5dfec4e4dd03c13d265f24937e0eafc817931bd5a563e496408`
|
||||
|
||||
## Remaining native identity/control-flow question
|
||||
|
||||
All answers detect the recovered caller's no-return treatment of the warning
|
||||
call and use machine instructions for the requested conditional post-call path.
|
||||
The recovered call facet omits the strict call. Complete recovered-graph coverage
|
||||
therefore does not establish a complete machine graph or a correct no-return
|
||||
inference. This is a concrete remaining backend/identity investigation.
|
||||
|
||||
Supplementary static observations identify a suspicious boundary: the warning
|
||||
epilogue restores LR/SP and branches at `0x25858` to `0xbad0`. That address
|
||||
starts with BTI, followed by ADRP at `0xbad4` and a slot load at `0xbad8` from
|
||||
`0x10f390`. ELF `R_AARCH64_JUMP_SLOT` names that slot `free@GLIBC_2.17`.
|
||||
The native inventory instead exposes `sub_bad0` with size bound 4 and `free`
|
||||
at `0xbad4` with bound 20. GNU's synthetic PLT label at `0xbad0` says closedir,
|
||||
which the actual slot relocation contradicts; it must not be used as symbol
|
||||
identity. Whether the native BTI/veneer split causes the no-return propagation
|
||||
still needs a producing-boundary investigation and regression proof. No such
|
||||
fix or rerun is attributed to the frozen comparison above.
|
||||
|
||||
Raw receipts live under `.cache/atomic-codemode/` as `arm-*`: initial missing
|
||||
xrefs, intermediate/final native test/build logs, SDK/source records, x86 fidelity
|
||||
and equivalent-query costs, actual catalogs and traditional preflight. Binaries,
|
||||
native projects and raw captures remain uncommitted.
|
||||
@@ -0,0 +1,24 @@
|
||||
// Shared named contract and selection vocabulary; no engine or adapter code.
|
||||
import { z } from "zod";
|
||||
export const hex = z.string().regex(/^0x(?:0|[1-9a-f][0-9a-f]{0,15})$/u);
|
||||
export const valueLocation = z.strictObject({
|
||||
space: z.string(),
|
||||
offset: hex,
|
||||
size_bytes: z.number().int().positive(),
|
||||
});
|
||||
export const page = {
|
||||
offset: z.number().int().nonnegative().default(0),
|
||||
limit: z.number().int().min(1).max(128).default(20),
|
||||
};
|
||||
export const definition = (
|
||||
{ summary, description },
|
||||
input,
|
||||
method,
|
||||
example,
|
||||
) => ({
|
||||
summary,
|
||||
description,
|
||||
input: z.strictObject(input),
|
||||
method,
|
||||
example,
|
||||
});
|
||||
@@ -0,0 +1,424 @@
|
||||
// One named contract registry shared by SDK, CLI, direct MCP and Code Mode.
|
||||
import { z } from "zod";
|
||||
import { MAX_BYTE_BATCH_BYTES, MAX_BYTE_WINDOWS } from "./limits.mjs";
|
||||
import { MAX_GRAPH_BLOCKS } from "./graph-limits.mjs";
|
||||
import { createReference } from "./reference.mjs";
|
||||
import { definition, hex, page, valueLocation } from "./api-contracts.mjs";
|
||||
import { storageMethods } from "./storage-contracts.mjs";
|
||||
import { referencesMethod } from "./reference-contracts.mjs";
|
||||
|
||||
const snapshot = z.string().startsWith("snap_");
|
||||
const byteWindow = z.strictObject({
|
||||
address: hex,
|
||||
length: z.number().int().min(1).max(MAX_BYTE_BATCH_BYTES).default(256),
|
||||
});
|
||||
const kinds = z.enum([
|
||||
"value",
|
||||
"load",
|
||||
"store",
|
||||
"phi",
|
||||
"call",
|
||||
"branch",
|
||||
"switch",
|
||||
"return",
|
||||
]);
|
||||
const fields = z
|
||||
.array(
|
||||
z.enum([
|
||||
"kind",
|
||||
"statement",
|
||||
"definitions",
|
||||
"constants",
|
||||
"opcode",
|
||||
"inputs",
|
||||
"output",
|
||||
"is_dead",
|
||||
"input_count",
|
||||
"definition_count",
|
||||
"constant_count",
|
||||
]),
|
||||
)
|
||||
.optional();
|
||||
const identitySeeds = z.array(z.string()).min(1).max(128);
|
||||
const relationInput = z.discriminatedUnion("kind", [
|
||||
z.strictObject({
|
||||
snapshot,
|
||||
kind: z.literal("cases"),
|
||||
seeds: identitySeeds,
|
||||
case_values: z.array(hex).max(128).optional(),
|
||||
case_indices: z.array(z.number().int().nonnegative()).max(128).optional(),
|
||||
...page,
|
||||
}),
|
||||
z.strictObject({
|
||||
snapshot,
|
||||
kind: z.literal("operands"),
|
||||
seeds: identitySeeds,
|
||||
input_indices: z.array(z.number().int().nonnegative()).max(128).optional(),
|
||||
...page,
|
||||
}),
|
||||
z.strictObject({
|
||||
snapshot,
|
||||
kind: z.enum(["definitions", "uses", "value_uses"]),
|
||||
seeds: identitySeeds,
|
||||
...page,
|
||||
}),
|
||||
z.strictObject({
|
||||
snapshot,
|
||||
kind: z.enum(["incoming", "outgoing", "controllers"]),
|
||||
seeds: z.array(z.number().int().nonnegative()).min(1).max(128),
|
||||
...page,
|
||||
}),
|
||||
]);
|
||||
export const methods = {
|
||||
...storageMethods,
|
||||
switches: definition(
|
||||
{
|
||||
summary:
|
||||
"Select recovered switches/table metadata; fetch cases separately. Native defaults may differ from machine guards.",
|
||||
description:
|
||||
"Inspect recovered indirect branches and their independent native jump-table metadata, without returning all case rows. Selector is the current recovered BRANCHIND input, which may be normalized rather than the machine jump address. Native consumed mask and signed rendering hint are not complete runtime/signedness proofs. Null tables/defaults stay unknown. The native model default out-edge is separate from any machine out-of-range guard destination. Use relations kind:cases for selected raw table rows, labels and their native mapping to recovered edges; row/edge ordinals are not case values. Available even when the full graph is unavailable if this independent facet was captured.",
|
||||
},
|
||||
{
|
||||
snapshot,
|
||||
ids: z.array(z.string()).max(128).optional(),
|
||||
origin_addresses: z.array(hex).max(128).optional(),
|
||||
fields: z.array(z.enum(["selector", "table"])).optional(),
|
||||
...page,
|
||||
},
|
||||
"switches",
|
||||
'await rea.switches({snapshot:s,origin_addresses:["0x1000"]})',
|
||||
),
|
||||
functions: definition(
|
||||
{
|
||||
summary:
|
||||
"Select callable entries and aliases, preserving ambiguous names; reported sizes are bounds, not assured extents.",
|
||||
description:
|
||||
"Search retained native callable entries by literal name/alias, exact name, or entry addresses. Names can match several entries, including PLT/import stubs and implementations; preserve all matches and select by address. A name does not establish runtime symbol binding.",
|
||||
},
|
||||
{
|
||||
query: z.string().default(""),
|
||||
exact: z.boolean().default(false),
|
||||
case_sensitive: z.boolean().default(true),
|
||||
addresses: z.array(hex).max(128).optional(),
|
||||
fields: z.array(z.enum(["name", "aliases", "size"])).optional(),
|
||||
...page,
|
||||
},
|
||||
"functions",
|
||||
'await rea.functions({query:"format_error",exact:true})',
|
||||
),
|
||||
strings: definition(
|
||||
{
|
||||
summary:
|
||||
"Search native string candidates by literal text; discovery and reference attribution remain unknown.",
|
||||
description:
|
||||
"Search native string candidates by literal text (JavaScript UTF16 includes semantics, no regex). Address and encoding identify an object within the artifact; fields:[] omits display text. Select value, provider_value or decoding only when needed. Encoded byte lengths and provider-reported NUL termination are preserved when known; omitted NUL status is unknown. A false NUL status makes no claim about bytes outside that span. Coverage.source_scope distinguishes a retained whole inventory from a selected query report; source IDs need not be shared between queries/pages/detail views. source_row, when present, is the canonical candidate ordinal under the declared native scan settings. Paging and native selection completeness do not establish artifact discovery completeness. Complete captured source remains readable through evidence.",
|
||||
},
|
||||
{
|
||||
query: z.string(),
|
||||
fields: z
|
||||
.array(z.enum(["value", "provider_value", "decoding"]))
|
||||
.optional(),
|
||||
...page,
|
||||
},
|
||||
"strings",
|
||||
'await rea.strings({query:"incorrect header check",fields:[]})',
|
||||
),
|
||||
references: referencesMethod,
|
||||
snapshot: definition(
|
||||
{
|
||||
summary:
|
||||
"Capture one function's analysis; return a snapshot, retained Evidence, facet availability and scoped counts.",
|
||||
description:
|
||||
"Analyze an explicit function entry once; return a retained capture handle, facets and coverage. Reuses the source within this target lease. Code, recovered calls and values remain independently available when full recovered IR exceeds capacity. A bounded call-rooted operation/definition projection may also be available; inspect facets.operations and coverage before reads. CFG queries still require the complete recovered graph. Available calls include compact by_opcode counts of known/unknown targets over the whole retained call facet; no paging is needed for these counts. Selected calls and complete Evidence remain readable.",
|
||||
},
|
||||
{ entry: hex },
|
||||
"snapshot",
|
||||
'await rea.snapshot({entry:"0x1000"})',
|
||||
),
|
||||
bytes: definition(
|
||||
{
|
||||
summary:
|
||||
"Read batched static loaded-image byte ranges with source identity and per-window partial outcomes.",
|
||||
description:
|
||||
"Read selected native loaded-image bytes without instruction decoding. Batch up to 16 exact virtual-address windows and 64 KiB total selected bytes; hex uses twice that space before provenance. Short reads remain partial. A shared source can contain several windows; source_row, when present, identifies its zero-based native window row. Repeated exact ranges can reuse that source. These are not live process memory or an original-file-offset mapping. Global code discovery is not performed.",
|
||||
},
|
||||
{
|
||||
windows: z.array(byteWindow).min(1).max(MAX_BYTE_WINDOWS),
|
||||
},
|
||||
"bytes",
|
||||
'await rea.bytes({windows:[{address:"0x2000",length:32}]})',
|
||||
),
|
||||
instructions: definition(
|
||||
{
|
||||
summary:
|
||||
"Decode selected static machine-byte windows, distinct from optimized IR edges and runtime execution.",
|
||||
description:
|
||||
"Batch selected machine instruction windows. Read exact bytes and native disassembly to verify actual control transfers; optimized recovered CFG edges can bypass machine blocks. Address+size with the artifact context identifies the byte range. A caller-selected decode start does not prove execution/alignment.",
|
||||
},
|
||||
{
|
||||
windows: z
|
||||
.array(
|
||||
z.strictObject({
|
||||
address: hex,
|
||||
count: z.number().int().min(1).max(4096).default(16),
|
||||
}),
|
||||
)
|
||||
.min(1)
|
||||
.max(16),
|
||||
fields: z
|
||||
.array(z.enum(["bytes", "text", "mnemonic", "operands"]))
|
||||
.optional(),
|
||||
},
|
||||
"instructions",
|
||||
'await rea.instructions({windows:[{address:"0x1000",count:8}],fields:["bytes","text"]})',
|
||||
),
|
||||
operations: definition(
|
||||
{
|
||||
summary:
|
||||
"Select snapshot-local IR operations by identity, origin, constant or kind, with native/projection scope.",
|
||||
description:
|
||||
"Select SSA operations by IDs, source instruction origins, block IDs, constant literal or kind. Native default rows are compact summaries: opcode/kind/output and input/definition/constant counts; request detailed fields explicitly or page input slots via relations kind:operands. Filters intersect; identities and native is_dead are retained. Availability may be a complete recovered graph or a bounded call-rooted projection; inspect coverage before inferring absence. A literal match is not object identity. origin_addresses selects optimized recovered IR origins; use instructions for actual machine control transfers.",
|
||||
},
|
||||
{
|
||||
snapshot,
|
||||
ids: z.array(z.string()).max(128).optional(),
|
||||
origin_addresses: z.array(hex).max(128).optional(),
|
||||
block_ids: z.array(z.number().int().nonnegative()).max(128).optional(),
|
||||
constant: hex.optional(),
|
||||
kind: kinds.optional(),
|
||||
fields,
|
||||
...page,
|
||||
},
|
||||
"operations",
|
||||
'await rea.operations({snapshot:s,constant:"0x2000",fields:["statement"]})',
|
||||
),
|
||||
relations: {
|
||||
summary:
|
||||
"Read typed SSA operands/def-use, CFG/controllers or switch cases by identities; preserve unknown/partial scope.",
|
||||
description:
|
||||
"Read native operand occurrences, operation definitions/uses, value_uses or case rows. value_uses takes value-ID seeds and returns exact operation/input-slot occurrences, including function inputs and constants without defining operations; null definition stays explicit, not a missing use. Uses cover retained operations, not runtime or memory aliases. Other data-flow/case seeds are operation IDs; incoming/outgoing CFG edges or derived controllers for block IDs. Native CFG/controller reads deduplicate seeds and report unretained_seeds; an unknown block is not a retained block with no relations. Incoming/outgoing rows keep caller seed then native edge order; controllers keep native controller/edge then postdominator order. cases pages one relation per case/out-edge, with a stable case_id; an unmapped case has one explicit unknown-edge row. total counts relations, not table rows. cases filters optional case_values (native labels tagged value) and case_indices (original row ordinals); both filters intersect and paging spans deduplicated seeds in caller order. Rows preserve missing/no-label status, original recovered target, and separate recovered edges. Partial/unavailable tables and unmapped rows are explicit; no runtime feasibility claim. operands pages every selected input slot, including constants, function inputs and null slots; input_indices optionally selects slots in caller order. Identity is snapshot + operation + input_index; value_id/definition and exact phi predecessor/edge bindings remain separate. Out-of-range slots of retained operations are absent; unretained_seeds remain unknown. A bounded call-rooted projection supports operands/definitions/uses but no CFG; uses cover retained selected operations only. Diagnostic SSA lacks native operands and has partial CFG/printed occurrences. controllers requires a complete recovered graph and concerns finite paths to recovered exits, not runtime feasibility.",
|
||||
input: relationInput,
|
||||
method: "relations",
|
||||
example:
|
||||
'await rea.relations({snapshot:s,kind:"operands",seeds:[op.id],input_indices:[0,2]})',
|
||||
},
|
||||
values: definition(
|
||||
{
|
||||
summary:
|
||||
"Select SSA values by ID or exact space/offset/width; keep versions, inputs and constants distinct, without alias inference.",
|
||||
description:
|
||||
"Read native SSA values by IDs or exact locations [{space,offset,size_bytes}], with width required. Locations match retained metadata, including const/unique spaces, not pointee contents, aliases or live memory. Filters intersect; IDs retain caller order, otherwise locations retain caller order and values retain native order per location. Empty IDs/locations select none. Null-space values cannot resolve a location and stay explicit in location_coverage; unretained_locations means no known retained coordinate match, not absent machine storage. Scope may be a full graph, bounded call-rooted definition projection, or call-boundary values only; is_input filters the raw native input flag, which can also mark globals or stack values; it is not formal-parameter membership. Use parameters for the separate native recovered prototype, which also does not prove an original source signature. Offset is an address-space offset, not a computed arbitrary-width value. Width, constants, function inputs, annotation status and defining operation are separate facts. Requires the pinned native exporter.",
|
||||
},
|
||||
{
|
||||
snapshot,
|
||||
ids: z.array(z.string()).max(128).optional(),
|
||||
is_input: z.boolean().optional(),
|
||||
locations: z.array(valueLocation).max(128).optional(),
|
||||
fields: z
|
||||
.array(
|
||||
z.enum([
|
||||
"space",
|
||||
"offset",
|
||||
"size_bytes",
|
||||
"is_constant",
|
||||
"is_input",
|
||||
"is_annotation",
|
||||
"definition",
|
||||
"type_name",
|
||||
]),
|
||||
)
|
||||
.optional(),
|
||||
...page,
|
||||
},
|
||||
"values",
|
||||
"await rea.values({snapshot:s,ids:op.inputs.map(i=>i.value_id).filter(Boolean)})",
|
||||
),
|
||||
calls: definition(
|
||||
{
|
||||
summary:
|
||||
"Read recovered calls, target knowledge, arguments and passing storage; signatures and runtime binding remain uncertain.",
|
||||
description:
|
||||
"Select structured recovered call sites and argument bindings. Target comes from native call specifications, never the fspec annotation offset or display text. Each argument separates its SSA value from its passing storage. Calls and their boundary values survive full graph capacity failure. target_value_id retains input zero independently of target resolution; it may be an fspec annotation or an unresolved indirect target value. A null output describes this recovered operation, not proof of a void source signature. Input slots are not original source parameter ordinals; missing storage and indirect/runtime targets remain unknown. To investigate across functions, snapshot the selected callee and select values with is_input:true, comparing exact space/offset/width. Requires the pinned native exporter.",
|
||||
},
|
||||
{
|
||||
snapshot,
|
||||
ids: z.array(z.string()).max(128).optional(),
|
||||
origin_addresses: z.array(hex).max(128).optional(),
|
||||
fields: z
|
||||
.array(
|
||||
z.enum([
|
||||
"target",
|
||||
"target_name",
|
||||
"arguments",
|
||||
"output",
|
||||
"prototype",
|
||||
"stack_offset",
|
||||
"target_value_id",
|
||||
"is_dead",
|
||||
]),
|
||||
)
|
||||
.optional(),
|
||||
...page,
|
||||
},
|
||||
"calls",
|
||||
'await rea.calls({snapshot:s,origin_addresses:["0x1100"]})',
|
||||
),
|
||||
blocks: definition(
|
||||
{
|
||||
summary:
|
||||
"Select recovered CFG blocks and edges; origin addresses are provenance, not machine block extents.",
|
||||
description:
|
||||
"Read native recovered blocks by stable snapshot-local ID, with ordered predecessors, successor edges and member operation IDs. origin_start describes optimized IR provenance, not a machine block extent. Requires an available native recovered IR graph. Runtime successors remain unknown.",
|
||||
},
|
||||
{
|
||||
snapshot,
|
||||
ids: z.array(z.number().int().nonnegative()).max(128).optional(),
|
||||
fields: z
|
||||
.array(
|
||||
z.enum(["origin_start", "operations", "predecessors", "successors"]),
|
||||
)
|
||||
.optional(),
|
||||
...page,
|
||||
},
|
||||
"blocks",
|
||||
"await rea.blocks({snapshot:s,ids:[op.block]})",
|
||||
),
|
||||
parameters: definition(
|
||||
{
|
||||
summary:
|
||||
"Select native recovered formal parameter and return storage, convention and recovery flags; raw input varnodes are not formals.",
|
||||
description:
|
||||
"Read the captured native function prototype: paged parameter entries, return descriptor, native convention label, locks, variadic and recovery-error flags. IDs/indices belong to this snapshot's recovered prototype, not proven source parameter ordinals or original signature. Native is_input also marks stack/global input varnodes; it is not formal membership. Select indices in caller order and optional fields; defaults omit display names/type strings. Output uses the same field selection. Null storage/type stays unknown; explicit is_void is independent of storage absence. Storage matches across snapshots require exact artifact/callee identity and ABI reasoning; stack rebasing, aliases, split/join storage, runtime binding and source signatures remain unproved. Requires a captured parameters facet, independently of full CFG/calls. Older experimental captures explicitly report not-captured; no synthetic empty signature.",
|
||||
},
|
||||
{
|
||||
snapshot,
|
||||
indices: z.array(z.number().int().nonnegative()).max(128).optional(),
|
||||
fields: z
|
||||
.array(
|
||||
z.enum([
|
||||
"name",
|
||||
"type_name",
|
||||
"size_bytes",
|
||||
"is_void",
|
||||
"storage",
|
||||
"type_locked",
|
||||
"name_locked",
|
||||
"size_locked",
|
||||
"this_pointer",
|
||||
"indirect_storage",
|
||||
"hidden_return",
|
||||
]),
|
||||
)
|
||||
.optional(),
|
||||
...page,
|
||||
},
|
||||
"parameters",
|
||||
'await rea.parameters({snapshot:s,indices:[0],fields:["storage","size_bytes","is_void","type_name"]})',
|
||||
),
|
||||
path: definition(
|
||||
{
|
||||
summary:
|
||||
"Find one shortest recovered CFG path to a block or exit, with exclusions and paged native edges; feasibility stays unknown.",
|
||||
description:
|
||||
"Find one shortest edge-count witness in the complete recovered CFG from a numeric block ID to a block or any zero-successor recovered exit, excluding avoid IDs. Ties follow native successor order. Return paged native edges with a separate step_index; index remains the original successor ordinal. A found zero-edge path is distinct from not-found. Unknown start/target/avoid identities produce status unknown and unretained_blocks, never absence. Not-found applies only to this recovered graph under the requested exclusions; exits, termination, machine flow and branch-predicate feasibility remain unproved. Requires the full recovered_ir facet, not a call-rooted projection. Search state is bounded by the admitted graph; one last-query cache per resident immutable graph expires with eviction/lease close. The avoid selection is bounded by the maximum admitted graph block count.",
|
||||
},
|
||||
{
|
||||
snapshot,
|
||||
from: z.number().int().nonnegative(),
|
||||
target: z.discriminatedUnion("kind", [
|
||||
z.strictObject({
|
||||
kind: z.literal("block"),
|
||||
id: z.number().int().nonnegative(),
|
||||
}),
|
||||
z.strictObject({ kind: z.literal("exit") }),
|
||||
]),
|
||||
avoid: z
|
||||
.array(z.number().int().nonnegative())
|
||||
.max(MAX_GRAPH_BLOCKS)
|
||||
.default([]),
|
||||
...page,
|
||||
},
|
||||
"path",
|
||||
'await rea.path({snapshot:s,from:block,target:{kind:"exit"},avoid:[join]})',
|
||||
),
|
||||
slice: definition(
|
||||
{
|
||||
summary:
|
||||
"Trace bounded backward definitions with explicit LOAD/PHI/frontier cutoffs; memory aliases remain unknown.",
|
||||
description:
|
||||
"Compose a bounded backward definition traversal from explicit operation IDs. Native default operation rows are compact summaries; request detailed fields or use paged operand relations for wide nodes. Available over a complete recovered graph or bounded call-rooted projection. Missing defining bodies retain frontier reasons; complete use sets and CFG are unavailable for a projection. Default load/phi cutoffs keep boundaries visible; choose stop_kinds:[] to traverse beyond them. Complete reachability and memory aliases remain unknown.",
|
||||
},
|
||||
{
|
||||
snapshot,
|
||||
seeds: z.array(z.string()).min(1).max(64),
|
||||
max_operations: z.number().int().min(1).max(256).default(48),
|
||||
stop_at: z.array(z.string()).max(128).default([]),
|
||||
stop_kinds: z.array(kinds).default(["phi", "load"]),
|
||||
fields,
|
||||
},
|
||||
"slice",
|
||||
'await rea.slice({snapshot:s,seeds:callIds,stop_kinds:["load"],fields:["opcode","inputs","output","constants"]})',
|
||||
),
|
||||
code: definition(
|
||||
{
|
||||
summary:
|
||||
"Read selected lines of retained reconstructed code, including when graph capture is unavailable.",
|
||||
description:
|
||||
"Read reconstructed code from the same retained function capture, even when its graph facet is unavailable. offset is zero-based. A large limit reads the complete code inside Code Mode for local filtering. The bridge byte budget bounds the result. No additional decompilation.",
|
||||
},
|
||||
{
|
||||
snapshot,
|
||||
offset: page.offset,
|
||||
limit: z.number().int().positive().default(64),
|
||||
},
|
||||
"code",
|
||||
"await rea.code({snapshot:s,offset:100,limit:64})",
|
||||
),
|
||||
evidence: definition(
|
||||
{
|
||||
summary:
|
||||
"Page complete retained source or decoded graph Evidence with source/view identities and freshness checks.",
|
||||
description:
|
||||
"Read complete retained native source in UTF-16-code-unit pages by evidence_id; no reanalysis. component:source preserves exact original wire JSON. component:recovered_ir reads the decoded graph source, including lossless compressed graphs; source hash remains the original capture and view has its own hash/byte count. This is source inspection, not a claim that malformed graph facts are valid. Available until close_binary.",
|
||||
},
|
||||
{
|
||||
evidence_id: z.string().startsWith("ev_"),
|
||||
component: z.enum(["source", "recovered_ir"]).default("source"),
|
||||
offset: page.offset,
|
||||
limit: z.number().int().min(1).max(16384).default(4096),
|
||||
},
|
||||
"evidence",
|
||||
"await rea.evidence({evidence_id:id,offset:0,limit:4096})",
|
||||
),
|
||||
};
|
||||
|
||||
methods.bytes.input = methods.bytes.input.superRefine((value, context) => {
|
||||
// Pattern failures need not prevent object refinements from running in Zod.
|
||||
// Only the named window contract may admit values to exact u64 arithmetic.
|
||||
const windows = value.windows.flatMap((window) => {
|
||||
const parsed = byteWindow.safeParse(window);
|
||||
return parsed.success ? [parsed.data] : [];
|
||||
});
|
||||
if (
|
||||
windows.reduce((sum, window) => sum + window.length, 0) >
|
||||
MAX_BYTE_BATCH_BYTES
|
||||
)
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: ["windows"],
|
||||
message:
|
||||
"Select at most 64 KiB of bytes per batch; use additional windows/pages in later calls",
|
||||
});
|
||||
if (
|
||||
windows.some(
|
||||
(window) =>
|
||||
BigInt(window.address) + BigInt(window.length) > 0xffffffffffffffffn,
|
||||
)
|
||||
)
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: ["windows"],
|
||||
message: "Byte range end exceeds the native u64 address format",
|
||||
});
|
||||
});
|
||||
export const reference = createReference(methods);
|
||||
@@ -0,0 +1,231 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import Ajv2020 from "ajv/dist/2020.js";
|
||||
import { methods, reference } from "./api.mjs";
|
||||
import { AtomicSession } from "./session.mjs";
|
||||
|
||||
const factory = () => {
|
||||
let sequence = 0;
|
||||
const calls = [];
|
||||
const create = async (path) => ({
|
||||
context: { lease: `lease-${++sequence}`, selected_path: path },
|
||||
close: async () => {
|
||||
calls.push("close");
|
||||
},
|
||||
cancel: () => {
|
||||
calls.push("cancel");
|
||||
},
|
||||
strings: async (input) => {
|
||||
calls.push(input);
|
||||
return { items: [], source: { evidence_id: "ev_real-owner" } };
|
||||
},
|
||||
});
|
||||
return { create, calls };
|
||||
};
|
||||
test("path selectors agree in runtime and JSON Schema, without inferred target or string identities", () => {
|
||||
const validate = new Ajv2020({ strict: false }).compile(
|
||||
reference("path").methods[0].input_schema,
|
||||
);
|
||||
for (const [request, valid] of [
|
||||
[{ from: 0, target: { kind: "exit" } }, true],
|
||||
[
|
||||
{
|
||||
from: 0,
|
||||
target: { kind: "block", id: 1 },
|
||||
avoid: [2, 2],
|
||||
offset: 1,
|
||||
limit: 1,
|
||||
},
|
||||
true,
|
||||
],
|
||||
[{ from: "0", target: { kind: "exit" } }, false],
|
||||
[{ from: 0, target: { kind: "block" } }, false],
|
||||
[{ from: 0, target: { kind: "exit", id: 1 } }, false],
|
||||
[{ from: 0, target: { kind: "exit" }, avoid: [-1] }, false],
|
||||
[{ from: 0, target: { kind: "exit" }, limit: 129 }, false],
|
||||
]) {
|
||||
const input = { snapshot: "snap_test", ...request };
|
||||
assert.equal(methods.path.input.safeParse(input).success, valid);
|
||||
assert.equal(validate(input), valid, JSON.stringify(validate.errors));
|
||||
}
|
||||
});
|
||||
test("relation identity and operand-only selectors agree in runtime and advertised schemas", () => {
|
||||
const validate = new Ajv2020({ strict: false }).compile(
|
||||
reference("relations").methods[0].input_schema,
|
||||
);
|
||||
for (const [request, valid] of [
|
||||
[{ kind: "operands", seeds: ["0x1:0"], input_indices: [0, 155] }, true],
|
||||
[{ kind: "operands", seeds: ["0x1:0"], input_indices: [] }, true],
|
||||
[{ kind: "uses", seeds: ["0x1:0"] }, true],
|
||||
[
|
||||
{
|
||||
kind: "cases",
|
||||
seeds: ["0x1:0"],
|
||||
case_values: ["0xffffffffffffffff"],
|
||||
case_indices: [0, 155],
|
||||
},
|
||||
true,
|
||||
],
|
||||
[{ kind: "cases", seeds: [0] }, false],
|
||||
[{ kind: "cases", seeds: ["0x1:0"], case_values: ["0X1"] }, false],
|
||||
[{ kind: "incoming", seeds: [0] }, true],
|
||||
[{ kind: "incoming", seeds: ["0"] }, false],
|
||||
[{ kind: "operands", seeds: [0] }, false],
|
||||
[{ kind: "uses", seeds: ["0x1:0"], input_indices: [0] }, false],
|
||||
[{ kind: "operands", seeds: ["0x1:0"], input_indices: [-1] }, false],
|
||||
]) {
|
||||
const input = { snapshot: "snap_test", ...request };
|
||||
assert.equal(methods.relations.input.safeParse(input).success, valid);
|
||||
assert.equal(validate(input), valid, JSON.stringify(validate.errors));
|
||||
}
|
||||
});
|
||||
test("named contracts reject extra keys and stale leases before provider admission", async () => {
|
||||
const provider = factory();
|
||||
const session = new AtomicSession(provider.create);
|
||||
await session.open("first");
|
||||
const lease = session.context.lease;
|
||||
const invalid = await session.call("strings", { query: "x", guessed: true });
|
||||
assert.equal(invalid.error.code, "invalid_input");
|
||||
const wrongIdentity = await session.call("relations", {
|
||||
snapshot: "snap_test",
|
||||
kind: "incoming",
|
||||
seeds: ["0"],
|
||||
});
|
||||
assert.equal(wrongIdentity.error.code, "invalid_input");
|
||||
assert.equal(provider.calls.length, 0);
|
||||
await session.open("second");
|
||||
const stale = await session.call("strings", { query: "x" }, undefined, lease);
|
||||
assert.equal(stale.error.code, "stale_context");
|
||||
assert.deepEqual(provider.calls, ["close"]);
|
||||
await session.close();
|
||||
});
|
||||
|
||||
test("cancellation after a completed read retains observations under a cancelled outcome", async () => {
|
||||
const controller = new AbortController();
|
||||
const session = new AtomicSession(async () => ({
|
||||
context: { lease: "late-cancel" },
|
||||
close: async () => {},
|
||||
strings: async () => {
|
||||
controller.abort();
|
||||
return {
|
||||
source: { evidence_id: "ev_observed" },
|
||||
items: [{ value: "retained" }],
|
||||
};
|
||||
},
|
||||
}));
|
||||
await session.open("target");
|
||||
const result = await session.call(
|
||||
"strings",
|
||||
{ query: "x" },
|
||||
controller.signal,
|
||||
);
|
||||
assert.equal(result.ok, false);
|
||||
assert.equal(result.error.code, "cancelled");
|
||||
assert.equal(
|
||||
result.error.details.partial_observation.items[0].value,
|
||||
"retained",
|
||||
);
|
||||
assert.equal(result.context.lease, "late-cancel");
|
||||
await session.close();
|
||||
});
|
||||
test("close drains admitted reads and a failed cleanup retains ownership for retry", async () => {
|
||||
let release;
|
||||
let reads = 0;
|
||||
let closes = 0;
|
||||
const session = new AtomicSession(async () => ({
|
||||
context: { lease: "owned" },
|
||||
strings: () => {
|
||||
reads++;
|
||||
return new Promise((resolve) => {
|
||||
release = resolve;
|
||||
});
|
||||
},
|
||||
close: () => {
|
||||
if (++closes === 1) throw new Error("cleanup failed");
|
||||
},
|
||||
cancel() {},
|
||||
}));
|
||||
await session.open("target");
|
||||
const read = session.call("strings", { query: "x" });
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
const close = session.close();
|
||||
assert.equal(closes, 0);
|
||||
assert.equal(reads, 1);
|
||||
release({ items: [] });
|
||||
assert.equal((await read).ok, true);
|
||||
await assert.rejects(close, /cleanup failed/u);
|
||||
assert.equal(session.context.lease, "owned");
|
||||
await session.close();
|
||||
assert.equal(session.context, null);
|
||||
});
|
||||
for (const action of ["close", "replace"])
|
||||
test(`failed open retains session file owners through ${action} and cleanup retry`, async () => {
|
||||
let acquisitions = 0,
|
||||
cleanupAttempts = 0,
|
||||
releasable = false;
|
||||
const primary = new Error(
|
||||
"Engine inspection failed after acquiring a file",
|
||||
);
|
||||
const session = new AtomicSession(async (path, { fileResources }) => {
|
||||
acquisitions++;
|
||||
if (acquisitions === 1)
|
||||
return fileResources.run(async () => {
|
||||
fileResources.retain({
|
||||
kind: "lease",
|
||||
resource: "/selected/engine",
|
||||
lease: {
|
||||
release: async () => {
|
||||
cleanupAttempts++;
|
||||
if (!releasable) throw new Error("Descriptor remains open");
|
||||
},
|
||||
},
|
||||
});
|
||||
throw primary;
|
||||
});
|
||||
return {
|
||||
context: { lease: "recovered", selected_path: path },
|
||||
close: async () => {},
|
||||
};
|
||||
});
|
||||
await assert.rejects(session.open("first"), (error) => error === primary);
|
||||
assert.equal(session.context, null);
|
||||
assert.equal(
|
||||
(await session.call("strings", { query: "x" })).error.code,
|
||||
"no_target",
|
||||
);
|
||||
const retry = () =>
|
||||
action === "close" ? session.close() : session.open("second");
|
||||
await assert.rejects(
|
||||
retry(),
|
||||
(error) =>
|
||||
error.code === "cleanup_incomplete" &&
|
||||
error.details.resources.length === 1 &&
|
||||
error.details.resources[0] === "/selected/engine",
|
||||
);
|
||||
assert.equal(acquisitions, 1, "Unresolved owners block replacement");
|
||||
assert.equal(cleanupAttempts, 1);
|
||||
releasable = true;
|
||||
assert.equal((await retry()).ok, true);
|
||||
assert.equal(cleanupAttempts, 2);
|
||||
if (action === "close") {
|
||||
assert.equal(session.context, null);
|
||||
assert.equal((await session.open("second")).ok, true);
|
||||
}
|
||||
assert.equal(acquisitions, 2);
|
||||
assert.equal(session.context.lease, "recovered");
|
||||
await session.close();
|
||||
assert.equal(cleanupAttempts, 2, "Released owners are not retried");
|
||||
});
|
||||
test("cancellation before admission makes no provider query; advertised reference schemas compile", async () => {
|
||||
const provider = factory();
|
||||
const session = new AtomicSession(provider.create);
|
||||
await session.open("target");
|
||||
const stop = new AbortController();
|
||||
stop.abort();
|
||||
const cancelled = await session.call("strings", { query: "x" }, stop.signal);
|
||||
assert.equal(cancelled.error.code, "cancelled");
|
||||
assert.deepEqual(provider.calls, []);
|
||||
const ajv = new Ajv2020({ strict: false });
|
||||
for (const method of reference().methods) ajv.compile(method.input_schema);
|
||||
await session.close();
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
# Calls and values surviving full-graph capacity
|
||||
|
||||
The question is `sqlite-boundary-question.txt`. Fix it and this acceptance oracle
|
||||
before either real-model run. Both lanes use the same complete fourteen-method
|
||||
API, preserved engine, model/effort request, common guidance and resource limits.
|
||||
This task requires VM decompilation once per fresh lease; it is different work
|
||||
from the earlier shallow-reference question. Do not compare their task times as
|
||||
an adapter speedup. Actual client JavaScript dispatch is available in both lanes.
|
||||
|
||||
Artifact: Debian `libsqlite3-0:amd64` version `3.40.1-2+deb12u2`,
|
||||
`libsqlite3.so.0.8.6`, SHA-256
|
||||
`2e6eef9a727f081f0d453b4e5e6cbd8b9ef8b6f86cbf7681cbad444d3b0b55c8`.
|
||||
The selected VM implementation entry is `0xea6d0`, not its same-name PLT entry.
|
||||
|
||||
Pre-model public MCP capture with the new exporter establishes:
|
||||
|
||||
- Code is available. Full graph is unavailable with `atomic operation capacity
|
||||
exceeded`. Calls remain available: 416 retained block-member operations,
|
||||
consisting of 395 CALL and 21 CALLIND. The 395 direct targets are known, all
|
||||
21 indirect targets remain unknown. Call-boundary values are available (1,294),
|
||||
covering targets, arguments and outputs only, with 21,349 operations scanned
|
||||
over 1,229 recovered blocks. These do not supply a complete definition/use graph.
|
||||
- At `0xf115c`, recovered call ID `0xf115c:6a84` targets `ram:0x296c0`.
|
||||
Input zero is `v1000118d6`, `fspec:0x102f4`, annotation true, width 8.
|
||||
Three recovered inputs use passing storage `register:0x38/8`, `0x30/8`,
|
||||
`0x10/8` (RDI, RSI, RDX in this verified x86-64 lane).
|
||||
- At `0xf238b`, call ID `0xf238b:7130` has the same resolved target.
|
||||
Input zero is `v100012a80`, `fspec:0x1030c`, annotation true, width 8.
|
||||
Two recovered inputs use passing storage `register:0x38/8`, `0x30/8`.
|
||||
- Both first arguments are the same snapshot-local SSA value `v30000004b`,
|
||||
`register:0x38/8`, `is_input:true`, definition null. Other retained argument
|
||||
values have defining operation IDs outside this boundary view. Exact SSA
|
||||
identity is supported; source parameter ordinals and general aliases are not.
|
||||
|
||||
Independent GNU objdump decoding from the exported VM entry verifies the two
|
||||
machine CALL targets and register setup. The earlier complete direct-call pair
|
||||
oracle contains both. Of the 396 physical direct immediate calls, the only one
|
||||
absent from the recovered 395 is `0xf2493 -> 0x29370` (stack check failure).
|
||||
The question does not require rediscovering this extra call; the recovered-call
|
||||
count must not be claimed as complete machine/runtime coverage.
|
||||
|
||||
Required final facts: correct selected entry and facet availability/scope; both
|
||||
call-count groups and target-unknown distinction; both resolved targets separated
|
||||
from annotation offsets; argument slots/locations; shared first-input identity;
|
||||
selected machine checks; explicit unreadable definition/use and alias/runtime
|
||||
limits; real Evidence and subject digest. Do not require the model to report
|
||||
every additional native metadata counter. Check that its API source arguments
|
||||
show only one VM analysis and all relevant reads reuse its snapshot/Evidence.
|
||||
|
||||
Raw public verification is retained as `facets-v3-mcp.json` and its Evidence
|
||||
directory under `.cache/atomic-codemode/`. The ordinary VM record (C, mappings,
|
||||
variables and other ordinary metadata) equals the prior captured engine output.
|
||||
The independent oracle and precomputed answer are absent from the model workspace.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Frozen shared-byte model task
|
||||
|
||||
Use the unchanged `native-string-query-question.txt` and all exact target/string/
|
||||
byte facts in `native-string-query-oracle.md`. The target digest and 4+1 string
|
||||
objects are unchanged. This phase's pinned engine is `bce4dc97fda99a028aca6b2b40a0a593c87b5224ac9e03221a69313faba2d3e8`,
|
||||
with both `REA_ATOMIC_NATIVE_STRING_QUERY=1` and `REA_ATOMIC_NATIVE_BYTE_BATCH=1`.
|
||||
The earlier oracle's engine digest describes its earlier frozen runtime only.
|
||||
|
||||
Both query reports remain distinct and each covers 602,544 candidates. A native
|
||||
byte report may now contain several requested windows with one shared source ID;
|
||||
source_row identifies a native window row, not the caller's ordinal after reuse.
|
||||
Repeated or reordered ranges may refer to the same original row. Fewer distinct
|
||||
byte Evidence IDs are valid when the cited source actually covers every claimed
|
||||
window. Counts/hex and provenance must remain exact. Focused covering reads are
|
||||
still allowed. Do not require ten commands or unique source IDs per window.
|
||||
|
||||
Grade complete original answers, all cited source hashes/contexts, raw byte
|
||||
payloads and actual source-window reads. Keep failed calls and all costs, with no
|
||||
answer repair or winning retry. Direct and Code Mode use the same 19 methods,
|
||||
question, model/reasoning, static authority and resource controls; actual Code
|
||||
Mode MCP execution must be observed. Report cumulative tokens, cached/uncached
|
||||
input, output/reasoning, schemas/help/calls/retries, wall, local CPU and kernel
|
||||
family peak. Actual clients have common JavaScript dispatch. Remote costs and
|
||||
resolved model builds are unmeasured. One run per lane does not establish broad
|
||||
RE superiority; historical model results use a different pinned runtime, while
|
||||
the SDK acquisition-toggle comparison uses the same current engine and code.
|
||||
@@ -0,0 +1,99 @@
|
||||
# Shared native byte reads: checkpoint
|
||||
|
||||
The user cleared the active goal after implementation and real preflight.
|
||||
Work stopped before new model trials. No PR or merge into main is requested.
|
||||
Main was refreshed to `5112fe07a` in `2dc3820b6`. LeanToken returned not_indexed
|
||||
for this experimental path; scoped native reads were used instead.
|
||||
|
||||
Opt in with `REA_ATOMIC_NATIVE_BYTE_BATCH=1` and an exact experimental native
|
||||
engine pin. Unset/0 preserves single-window acquisition. The 19 shared methods,
|
||||
22 Direct tools and four Code Mode tools are unchanged. The byte batch reads
|
||||
only selected static loaded-image ranges; no target execution or modification.
|
||||
|
||||
`disassemble/kuna_batch.rs` shares one existing ConsoleProgram load, range
|
||||
resolution, mapped-end clipping and data renderer across at most 16 windows /
|
||||
64 KiB selected bytes. It rejects ignored options and bounds encoded output
|
||||
against the existing 8 MiB capture ceiling. Each native row retains its exact
|
||||
request, ordinal and success or window_unavailable error. Global load or report
|
||||
encoding failure fails explicitly. The old read path can initialize again when
|
||||
a bounded anonymous region lacks a name; this is source-derived reasoning, not
|
||||
a measured count of internal translator initialization.
|
||||
|
||||
`NativeByteBatchReads` caches validated exact address/length facts for this target
|
||||
lease, deduplicates missing ranges, batches only missing work and preserves caller
|
||||
order. Source + source_row identify a window in retained raw Evidence; duplicates
|
||||
or reordered calls can share that row. Partial reads remain partial. Successful
|
||||
siblings survive bad per-row data; global failures preserve cached facts. Transient
|
||||
capture failures are not cached here. Close clears the cache. Its retained entries
|
||||
are bounded by source admission (128 sources times at most 16 windows); no global
|
||||
cache or live-memory freshness claim is added.
|
||||
|
||||
Old and new byte reports use one normalization owner. Exact JSON numeric tokens
|
||||
preserve u64 aliases and reject rounded fractional counters, with shared KunaJson
|
||||
support; alias disagreements fail instead of publishing contradictory facts.
|
||||
Original-file mapping and runtime memory remain unknown/not-observed.
|
||||
|
||||
## Executed evidence
|
||||
|
||||
- Native disassemble tests: 15 passed, including the two new protocol/budget tests.
|
||||
- Runtime build passed; final experimental JS tests: 128 passed.
|
||||
- Kuna reference files/ranges boundary tests: 27 passed.
|
||||
- Changed-file lint/format, module boundaries, affected-source typecheck and
|
||||
converted actual MCP schema/catalog checks passed.
|
||||
- Real SDK, Direct and Code Mode LLVM checks passed all prior five literal-query
|
||||
goldens, paging, projection, exact ten independent byte windows and 13 complete
|
||||
retained source hashes per lane.
|
||||
- Both actual MCP adapters passed SQLite mixed success/error, short reads,
|
||||
repeated exact windows and the full 64 KiB request.
|
||||
- Same-engine SDK comparison passed reordered/duplicate reuse, mixed cached/new
|
||||
windows, all raw hashes and stale Evidence rejection after reopen.
|
||||
- Actual producer cancellation preserved cached facts in partial_observation,
|
||||
allowed a fresh retry and completed owned cleanup. Target bytes were unchanged.
|
||||
|
||||
The existing full repository typecheck memory refusal is not a pass. No full
|
||||
check:fast/check:pr, full native workspace gate, new architecture/provider parity,
|
||||
or new real-model result is claimed for this phase. Earlier model outcomes retain
|
||||
their own immutable revisions. The prepared byte-batch oracle is unexecuted by models.
|
||||
|
||||
## Same-engine acquisition comparison
|
||||
|
||||
Both runs use engine `bce4dc97fda99a028aca6b2b40a0a593c87b5224ac9e03221a69313faba2d3e8`, the same LLVM artifact and independent
|
||||
file oracle. Only acquisition is toggled between 0 and 1. Cold means a new lease,
|
||||
not dropped OS caches. These are single scripted observations with no model tokens.
|
||||
|
||||
| Phase | Single-window ms / CPU s | Batched ms / CPU s |
|
||||
| --------------------------- | -----------------------: | ------------------: |
|
||||
| cold_ten_windows | 94269.834 / 94.110456 | 8505.789 / 8.488729 |
|
||||
| warm_reordered_duplicates | 2.598 / 0.002657 | 10.494 / 0.010407 |
|
||||
| mixed_cached_and_new_window | 6385.777 / 6.374731 | 6446.780 / 6.438594 |
|
||||
|
||||
Cold ten-window retrieval drops from about 94.3 to 8.5 seconds. The warm sample
|
||||
is slower in the batch run; it is retained without claiming a warm speedup.
|
||||
New unseen windows still incur program initialization. The old workflow retains
|
||||
11 native sources for the completed task; batching retains two.
|
||||
|
||||
| Whole task | Wall s | Local family CPU s | Kernel family peak MiB |
|
||||
| ------------ | ------: | -----------------: | ---------------------: |
|
||||
| before | 102.304 | 101.898599 | 861.9 |
|
||||
| after | 16.533 | 16.327818 | 858.1 |
|
||||
| cancellation | 15.324 | 15.107833 | 862.8 |
|
||||
|
||||
Counters are verified at payload exit while the observer lives, not final whole-
|
||||
scope counters. Memory includes charged file cache. Heavy work was serial, one
|
||||
CPU, hard 4 GiB/no swap, with early stopping at 3 GiB (3.25 GiB for builds).
|
||||
The first compiled native version was replaced before real provider verification
|
||||
to distinguish request_address_hex from numeric native address aliases; original
|
||||
builds/logs remain. No failed run was relabeled as passing.
|
||||
|
||||
## Reproduction anchors
|
||||
|
||||
The canonical native patch targets Kuna `fe01d6294eb0d1053ce343c8943646df88e143fc`.
|
||||
Binaries, captures and explicit provider settings remain ignored. Source patch
|
||||
SHA-256: `56d2cd197bfcab9566c055c32ee0aece4805c7708f0a0117a8fa06a768969055`.
|
||||
|
||||
- `native-byte-batch-before-v1.json`: `ec7c9ab21ef91ff6f965d8e6efc9da97c4a6593d19fde660ba5cb2b1c4459dcb`.
|
||||
- `native-byte-batch-after-v1.json`: `9737291a03ad7c12700bf124134c4c06d4ef5beb8c31dda102eaa5ae0752aa47`.
|
||||
- `native-byte-batch-cancellation-v1.json`: `6dd58baed164df0747573b143c31f01d12d5d697ca7c3ff4813b545c355d0d18`.
|
||||
- `native-byte-batch-llvm-sdk-v1.json`: `04d2ee586f376c41d86d1e9c4508c6b84fcb04d71b7ce2aab6b2580169367a1e`.
|
||||
- `native-byte-batch-llvm-direct-v1.json`: `53be8d5e5ce0f70d015be98d7ac0b500702fb414bd7a0b41be023a660717eff0`.
|
||||
- `native-byte-batch-llvm-codemode-v1.json`: `d94e171953fcc86a09b38e730564fae0d42068e1d2ac59b5547bd3c4837d5d42`.
|
||||
@@ -0,0 +1,141 @@
|
||||
// Native loaded-image data is not instruction decoding or original-file mapping.
|
||||
import { z } from "zod";
|
||||
import { FactFailure } from "./fact-error.mjs";
|
||||
import { MAX_BYTE_BATCH_BYTES, NATIVE_OUTPUT_BYTES } from "./limits.mjs";
|
||||
import { parseKunaJson } from "../../dist/kuna/KunaJson.js";
|
||||
|
||||
const hex = z.string().regex(/^0x(?:0|[1-9a-f][0-9a-f]{0,15})$/u);
|
||||
const payload = z.string().regex(/^(?:[0-9a-f]{2})*$/u);
|
||||
const header = z.object({
|
||||
binary: z.string(),
|
||||
kind: z.literal("data"),
|
||||
start_hex: hex,
|
||||
end_hex: hex,
|
||||
start: hex.optional(),
|
||||
end: hex.optional(),
|
||||
target: z.object({ address: hex, address_hex: hex }).optional(),
|
||||
count: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.max(MAX_BYTE_BATCH_BYTES / 16),
|
||||
bytes: z.number().int().nonnegative().max(MAX_BYTE_BATCH_BYTES),
|
||||
hex: payload,
|
||||
truncated: z.boolean(),
|
||||
notes: z.array(z.string()),
|
||||
});
|
||||
const row = z.object({
|
||||
address: hex.optional(),
|
||||
address_hex: hex,
|
||||
size: z.number().int().min(1).max(16),
|
||||
bytes: payload,
|
||||
});
|
||||
const requireFact = (valid, message) => {
|
||||
if (!valid) throw new FactFailure("invalid_provider_output", message);
|
||||
};
|
||||
|
||||
export function parseByteFacts(text, inputPath, request) {
|
||||
try {
|
||||
requireFact(
|
||||
Buffer.byteLength(text) <= NATIVE_OUTPUT_BYTES,
|
||||
"Byte source exceeds capture capacity",
|
||||
);
|
||||
return normalizeByteFacts(parseByteSourceJson(text), inputPath, request);
|
||||
} catch (error) {
|
||||
throw byteFailure(error);
|
||||
}
|
||||
}
|
||||
|
||||
export function parseByteSourceJson(text, integerKeys = []) {
|
||||
return parseKunaJson(
|
||||
text,
|
||||
NATIVE_OUTPUT_BYTES,
|
||||
new Set(["start", "end", "address"]),
|
||||
new Set(["count", "bytes", "size", ...integerKeys]),
|
||||
);
|
||||
}
|
||||
|
||||
export function normalizeByteFacts(raw, inputPath, request) {
|
||||
try {
|
||||
requireFact(
|
||||
Array.isArray(raw?.rows) && raw.rows.length <= MAX_BYTE_BATCH_BYTES / 16,
|
||||
"Byte rows exceed capacity or have invalid shape",
|
||||
);
|
||||
const doc = header.parse(raw);
|
||||
requireFact(
|
||||
(doc.start === undefined || doc.start === doc.start_hex) &&
|
||||
(doc.end === undefined || doc.end === doc.end_hex) &&
|
||||
(doc.target === undefined ||
|
||||
(doc.target.address === doc.start_hex &&
|
||||
doc.target.address_hex === doc.start_hex)),
|
||||
"Byte address aliases disagree",
|
||||
);
|
||||
requireFact(
|
||||
doc.binary === inputPath && doc.start_hex === request.address,
|
||||
"Byte source names a different target/window",
|
||||
);
|
||||
requireFact(
|
||||
doc.bytes <= request.length && doc.count === raw.rows.length,
|
||||
"Byte source exceeds the request or disagrees with row count",
|
||||
);
|
||||
let end = BigInt(request.address);
|
||||
const pieces = raw.rows.map((value, index) => {
|
||||
const item = row.parse(value);
|
||||
requireFact(
|
||||
item.address === undefined || item.address === item.address_hex,
|
||||
"Byte row address aliases disagree",
|
||||
);
|
||||
requireFact(
|
||||
BigInt(item.address_hex) === end && item.bytes.length === item.size * 2,
|
||||
"Byte row address/length is inconsistent",
|
||||
);
|
||||
requireFact(
|
||||
index === raw.rows.length - 1 || item.size === 16,
|
||||
"Nonfinal byte row is not the declared native width",
|
||||
);
|
||||
end += BigInt(item.size);
|
||||
return item.bytes;
|
||||
});
|
||||
requireFact(
|
||||
end === BigInt(doc.end_hex) &&
|
||||
end - BigInt(request.address) === BigInt(doc.bytes) &&
|
||||
pieces.join("") === doc.hex &&
|
||||
doc.hex.length === doc.bytes * 2,
|
||||
"Byte rows, payload and extent disagree",
|
||||
);
|
||||
return {
|
||||
hex: doc.hex,
|
||||
returned_bytes: doc.bytes,
|
||||
end_address: doc.end_hex,
|
||||
coverage: {
|
||||
authority: "native loaded-image bytes",
|
||||
requested_bytes: request.length,
|
||||
status:
|
||||
doc.bytes === request.length
|
||||
? "complete-for-requested-range"
|
||||
: "partial",
|
||||
provider_truncated: doc.truncated,
|
||||
notes: doc.notes,
|
||||
original_file_mapping: "unknown",
|
||||
runtime_memory: "not-observed",
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
throw byteFailure(error);
|
||||
}
|
||||
}
|
||||
|
||||
function byteFailure(error) {
|
||||
return error instanceof FactFailure
|
||||
? error
|
||||
: new FactFailure(
|
||||
"invalid_provider_output",
|
||||
"Native byte window does not match the declared format",
|
||||
{
|
||||
reason:
|
||||
error instanceof z.ZodError
|
||||
? error.issues[0]?.message.slice(0, 256)
|
||||
: String(error.message).slice(0, 256),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { parseByteFacts } from "./byte-facts.mjs";
|
||||
import { AtomicSession } from "./session.mjs";
|
||||
|
||||
const make = () => ({
|
||||
binary: "/input",
|
||||
kind: "data",
|
||||
start_hex: "0x20000000000001",
|
||||
end_hex: "0x20000000000005",
|
||||
count: 1,
|
||||
bytes: 4,
|
||||
hex: "00417fff",
|
||||
truncated: false,
|
||||
notes: [],
|
||||
rows: [
|
||||
{
|
||||
address_hex: "0x20000000000001",
|
||||
size: 4,
|
||||
bytes: "00417fff",
|
||||
},
|
||||
],
|
||||
});
|
||||
const request = { address: "0x20000000000001", length: 4 };
|
||||
test("byte facts keep exact u64 extents, null/nontext bytes and loaded-image authority", () => {
|
||||
const facts = parseByteFacts(JSON.stringify(make()), "/input", request);
|
||||
assert.equal(facts.hex, "00417fff");
|
||||
assert.equal(facts.end_address, "0x20000000000005");
|
||||
assert.equal(facts.coverage.status, "complete-for-requested-range");
|
||||
assert.equal(facts.coverage.original_file_mapping, "unknown");
|
||||
assert.equal(facts.coverage.runtime_memory, "not-observed");
|
||||
const clipped = parseByteFacts(JSON.stringify(make()), "/input", {
|
||||
...request,
|
||||
length: 5,
|
||||
});
|
||||
assert.equal(clipped.coverage.status, "partial");
|
||||
const flagged = make();
|
||||
flagged.truncated = true;
|
||||
assert.equal(
|
||||
parseByteFacts(JSON.stringify(flagged), "/input", request).coverage.status,
|
||||
"complete-for-requested-range",
|
||||
);
|
||||
});
|
||||
|
||||
test("wrong byte subject, contradictory duplicated payload, gaps and counts fail before publishing facts", () => {
|
||||
for (const mutate of [
|
||||
(d) => (d.binary = "/other"),
|
||||
(d) => (d.kind = "code"),
|
||||
(d) => (d.hex = "00417f00"),
|
||||
(d) => (d.rows[0].address_hex = "0x20000000000000"),
|
||||
(d) => (d.rows[0].size = 3),
|
||||
(d) => (d.end_hex = "0x20000000000006"),
|
||||
(d) => (d.count = 2),
|
||||
(d) => (d.rows = Array(4097).fill(null)),
|
||||
]) {
|
||||
const document = make();
|
||||
mutate(document);
|
||||
assert.throws(
|
||||
() => parseByteFacts(JSON.stringify(document), "/input", request),
|
||||
{ code: "invalid_provider_output" },
|
||||
);
|
||||
}
|
||||
const empty = make();
|
||||
Object.assign(empty, {
|
||||
hex: "",
|
||||
rows: [],
|
||||
count: 0,
|
||||
bytes: 0,
|
||||
end_hex: request.address,
|
||||
});
|
||||
assert.equal(
|
||||
parseByteFacts(JSON.stringify(empty), "/input", request).coverage.status,
|
||||
"partial",
|
||||
);
|
||||
});
|
||||
|
||||
test("byte input capacity, malformed addresses and u64 end overflow reject before native admission", async () => {
|
||||
let reads = 0;
|
||||
const session = new AtomicSession(async () => ({
|
||||
context: { lease: "bytes" },
|
||||
bytes: () => {
|
||||
reads += 1;
|
||||
},
|
||||
close: () => {},
|
||||
}));
|
||||
await session.open("/input");
|
||||
try {
|
||||
for (const windows of [
|
||||
[{ address: "invalid", length: 1 }],
|
||||
[{ address: "0xffffffffffffffff", length: 1 }],
|
||||
[
|
||||
{ address: "0x1000", length: 65536 },
|
||||
{ address: "0x2000", length: 1 },
|
||||
],
|
||||
[{ address: "0x1000", length: 0 }],
|
||||
]) {
|
||||
const result = await session.call("bytes", { windows });
|
||||
assert.equal(result.error.code, "invalid_input", JSON.stringify(result));
|
||||
}
|
||||
assert.equal(reads, 0);
|
||||
} finally {
|
||||
await session.close();
|
||||
}
|
||||
});
|
||||
|
||||
test("byte aliases and kept counters are validated from exact numeric source tokens", () => {
|
||||
const raw = JSON.stringify({
|
||||
...make(),
|
||||
start: "9007199254740993",
|
||||
end: "9007199254740997",
|
||||
target: { address: "9007199254740993", address_hex: request.address },
|
||||
rows: [{ ...make().rows[0], address: "9007199254740993" }],
|
||||
})
|
||||
.replaceAll('"9007199254740993"', "9007199254740993")
|
||||
.replaceAll('"9007199254740997"', "9007199254740997");
|
||||
assert.equal(parseByteFacts(raw, "/input", request).returned_bytes, 4);
|
||||
for (const invalid of [
|
||||
raw.replace('"count":1', '"count":1.0000000000000000001'),
|
||||
raw.replace('"bytes":4', '"bytes":4e0'),
|
||||
raw.replace('"size":4', '"size":4.0000000000000000001'),
|
||||
raw.replace('"start":9007199254740993', '"start":9007199254740992'),
|
||||
raw.replace('"end":9007199254740997', '"end":9007199254740996'),
|
||||
raw.replace('"address":9007199254740993', '"address":9007199254740992'),
|
||||
])
|
||||
assert.throws(() => parseByteFacts(invalid, "/input", request), {
|
||||
code: "invalid_provider_output",
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
# Cross-function context experiment: pinned question and oracle
|
||||
|
||||
This is an experiment acceptance oracle, unavailable to the isolated model.
|
||||
The question is `sqlite-call-question.txt`. Fix this question and the required
|
||||
facts before launching either model lane. Both adapters expose the same complete
|
||||
fourteen-method fact API; Code Mode has four MCP tools, direct has seventeen.
|
||||
Use the same pinned engine, artifact, model request, reasoning effort, common
|
||||
envelope guidance, fresh target leases and resource limits. Do not change runtime
|
||||
sources or HEAD during the model batch. One sample per lane cannot establish a
|
||||
general advantage, and the client itself already offers JavaScript dispatch in
|
||||
both lanes. This comparison isolates the server calling adapter, not all forms of
|
||||
composition or a traditional provider workflow.
|
||||
|
||||
The artifact is the local Debian ELF `libsqlite3.so.0.8.6`, SHA-256
|
||||
`2e6eef9a727f081f0d453b4e5e6cbd8b9ef8b6f86cbf7681cbad444d3b0b55c8`.
|
||||
Independent GNU objdump decoding from the function entries covers `0x64060`
|
||||
through `0x65400`; existing earlier captures independently pin the same flow.
|
||||
No target execution or source-code answer is used.
|
||||
|
||||
Required facts for an equal completed answer:
|
||||
|
||||
- Wrapper entry `0x65180`; direct machine CALL `0x65211` targets internal helper
|
||||
`0x64060`. The recovered call operation has an fspec annotation as input zero;
|
||||
that annotation's offset is not the target address.
|
||||
- Caller LEA `0x65201` passes post-prologue `RSP+0x20` in RDI. Structured passing
|
||||
storage is `register:0x38`, width 8. The SSA argument and the callee's retained
|
||||
input are separate snapshot-local identities; matching their storage supplies a
|
||||
candidate connection. The direct machine transfer and pointer setup support
|
||||
this particular connection. Do not globally infer source parameter ordinal,
|
||||
alias completeness or runtime binding from a slot number or a name.
|
||||
- The helper preserves the input context pointer in RBP. Its 32-bit field at
|
||||
context offset `0x30` is incremented at `0x64693`/`0x64696`/`0x64699` for an
|
||||
opening parenthesis and decremented at `0x64c92` for a closing parenthesis.
|
||||
The parser's token/branch context must support the parenthesis interpretation;
|
||||
an ADD/SUB instruction alone does not identify the meaning of a field.
|
||||
- In the wrapper this is `[RSP+0x50]`, initialized to zero with the other context
|
||||
tail fields. After helper return zero, LOAD `0x65268` and TEST/JZ
|
||||
`0x65270`/`0x65272` check it. Zero skips the malformed block; nonzero frees the
|
||||
expression at `0x65274`, clears its output pointer at `0x65279`, then reaches
|
||||
the malformed diagnostic at `0x65281` through formatter call `0x65290`.
|
||||
- Return-code-one errors can also reach the malformed block, via
|
||||
`0x65239`/`0x6523c`; return code 18 selects a separate depth-limit diagnostic
|
||||
at `0x65330`. No demonstrated runtime-feasibility or full memory-alias claim.
|
||||
|
||||
The producer verifier additionally checks two formatter call targets:
|
||||
`0x5f031 -> 0x2adc0` (free PLT) and `0x5f062 -> 0x27e50` (vmprintf PLT), whereas
|
||||
their input-zero fspec offsets are `0x10000`/`0x10001`. Resolving these PLT entries
|
||||
to runtime implementations is outside this task.
|
||||
|
||||
Native producer fidelity is checked against previously retained captures of all
|
||||
three functions: C, ordinary metadata/line mappings, blocks, operations, values
|
||||
and coverage are identical. Only schema version and structured call records are
|
||||
added. Older sources used pretty JSON; their smaller/newer encoded sizes must
|
||||
not be attributed to the call exporter. The earlier compact-writer change is a
|
||||
separate experiment. Unsupported old schema graphs remain unavailable with valid
|
||||
C retained, rather than acquiring guessed call records.
|
||||
|
||||
The first paired question runs at `01e5c5955` both explain the primary state flow
|
||||
correctly but omit the oracle's separate return-1/return-18 distinctions. Because
|
||||
the initial question did not explicitly enumerate those codes, the next round
|
||||
clarifies that requirement in `sqlite-call-question.txt` before either lane
|
||||
starts. The required facts and independent oracle stay unchanged. Earlier
|
||||
questions and costs remain pinned to their original commits; neither incomplete
|
||||
sample is counted as a full-oracle success.
|
||||
@@ -0,0 +1,141 @@
|
||||
# Capability and comparison scope
|
||||
|
||||
The experiment has nineteen fact methods behind a shared SDK/CLI owner, exposed
|
||||
as twenty-two direct MCP tools or four Code Mode tools. The structured IR/call/
|
||||
projection/switch facts require the explicitly pinned experimental Kuna patch;
|
||||
they are not capabilities added to stock Kuna or integrated REA by registration
|
||||
alone. Other providers are not wired to this experimental service.
|
||||
|
||||
A fair completed-task comparison first needs sufficient facts on both paths,
|
||||
with a common correctness oracle. A complete universal RE interface is not
|
||||
established here. The selected-case question requires native row/edge identities,
|
||||
so it compares the two atomic adapters; no traditional-provider result for that
|
||||
question is invented. Earlier traditional comparisons retain their own questions,
|
||||
engine profiles and limitations in [the trial record](trials.md).
|
||||
|
||||
| Analyst question | Composable facts/relations | Executed evidence and limits |
|
||||
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Which implementation owns an observed message? | Callable entries/aliases, encoded strings, exact-address xrefs with occurrence identity and function attribution | Both recent SQLite tasks select the owner before capture. Name equality alone is insufficient; discovery/unattributed coverage remains explicit. |
|
||||
| Which local condition controls a selected value/call? | Snapshot-local operations, SSA values, indexed operands, definitions/uses with PHI predecessor edges, recovered CFG edges | [Four real control-task runs](savepoint-control-study.md) verify the selected guards and machine instructions. [Full graph transport checks](native-graph-transport-study.md) establish producer fidelity, not global machine equivalence. |
|
||||
| What crosses a call boundary? | Native call specifications, argument values and separate passing storage; selected callee inputs and bounded definition projections | Earlier pinned [call/boundary trials](trials.md) exercise these relations. Storage matches are candidates, not proof of runtime binding or complete ABI/memory effects; a new exporter hash alone is not a repeated cross-function model trial. |
|
||||
| Which cases map to a recovered edge? | Original case identity/label/address, independent native default, flattened case/out-edge relations | [All 182 SQLite original targets](switch-study.md) match independent ELF table bytes. Four real models answer selected cases and distinguish the native default from the machine range guard. No complete case inventory is needed in model context. |
|
||||
| What machine bytes support the interpretation? | Batched loaded-image bytes and selected linear instruction windows, each with source/coverage | The case models independently derive signed relative targets. These windows do not establish runtime execution/alignment, a complete machine CFG, live memory or arbitrary file-offset mappings. |
|
||||
| Can the answer be audited without returning the report? | Snapshot/source identity, selected fields, batch reads, paging and retained raw/decoded Evidence | Real CLI/MCP checks verify source access and capacity fallbacks. Scope/partial/unknown survive composition; a guest-derived answer keeps its own authority. |
|
||||
|
||||
The [string-span experiment](string-span-study.md) extends exact xrefs with
|
||||
batched incoming target-coordinate spans. It preserves all eleven selected
|
||||
SQLite data occurrences, including nine pooled suffix pointers, with individual
|
||||
endpoints/owners and raw source rows. Kuna already had aggregate string-span
|
||||
counts; the new occurrence query shares its sparse index. Range membership alone
|
||||
does not establish whole-string use, access overlap or runtime behavior.
|
||||
Three real models complete the pooled-string task. The traditional original
|
||||
inventory has a partial source audit after client truncation; atomic source
|
||||
captures are fully checked. Code Mode's cumulative input/time improve in this
|
||||
sample, while uncached input and memory exceed Direct. This remains task evidence,
|
||||
not provider parity or a stable adapter advantage.
|
||||
|
||||
The useful grain so far is an identified object plus a relation with its exact
|
||||
qualifiers: an operand needs its slot and PHI binding; a case/out-edge pair needs
|
||||
both identities; an address needs its artifact/address space; an optimized
|
||||
operation needs its snapshot and representation. One small JSON row is not
|
||||
automatically one independently meaningful fact. Machine instructions and
|
||||
normalized operations also cannot substitute for each other.
|
||||
|
||||
An identified object may still contain a huge field. The [capacity study](large-result-study.md)
|
||||
adds string metadata selection and pre-allocation transport accounting with
|
||||
recoverable source handles. Real SDK/MCP checks cover both escaping layers and
|
||||
in-program recovery. In the frozen model pair, Code Mode passes; Direct reports
|
||||
17-byte prefixes as 16 despite correct provider data. Preserve that failure;
|
||||
the pair cannot rank efficiency at matched correctness. Native capture still
|
||||
reads the complete bounded inventory, so small replies alone do not establish
|
||||
scalable producer work. The [streamed inventory experiment](streamed-inventory-study.md)
|
||||
restores FFmpeg queries over a 16.8 MB source with bounded files and the production
|
||||
parser. Both corrected real-model answers pass with all sources checked; setup
|
||||
failures remain in the ledger. Costs are mixed, and LLVM/Node still exceed the
|
||||
unchanged 64 MiB retained-source ceiling.
|
||||
|
||||
Selection, projection, batching, paging and bounded traversal compose those
|
||||
facts. The analysis owner derives/validates relations; Code Mode selects and
|
||||
combines them. A query can be fine-grained even when its fresh native capture
|
||||
still computes a whole function. Same-lease reuse is measured separately from
|
||||
that work and does not establish a cross-session cache or native acceleration.
|
||||
|
||||
The [control-query study](control-query-study.md) independently verifies all
|
||||
2,845 control-dependence triples in the real SQLite VM through both MCP adapters.
|
||||
Two real models also complete a two-level controller/SSA/path-witness task and
|
||||
distinguish alternative predicates from conjunction. Unknown CFG seeds are
|
||||
explicit, and the snapshot owner reuses a bounded lazy postdominator index.
|
||||
Code Mode has lower cumulative input but higher uncached input and runtime costs
|
||||
in that pair; precise derived facts do not imply a preferred calling adapter.
|
||||
|
||||
The [OpenSSH value-query study](value-query-study.md) adds exact location lookup
|
||||
and inverse operand occurrences for value identities, including inputs/constants
|
||||
without definitions. It checks every retained selected version/use against the
|
||||
complete source graph; this is separate from machine-byte evidence and does not
|
||||
turn SSA occurrences into a memory-alias proof.
|
||||
|
||||
The [stripped OpenSSH model comparison](ssh-warning-study.md) also verifies a
|
||||
common warning/caller/stack/guard question through the two atomic adapters and
|
||||
the traditional Kuna workflow. Exact machine facts suffice for the direct
|
||||
answer; extra SSA capture is not required by every RE question. The corrected
|
||||
traditional baseline has its complete declared native toolset. This expands
|
||||
the completed-task evidence while retaining the local scope and cost confounds.
|
||||
|
||||
Memory alias dependencies, full machine-flow recovery, indirect runtime binding,
|
||||
feasible paths and nontermination remain unknown. The current evidence does
|
||||
not establish provider parity, broad complex-software superiority or a stable
|
||||
Code Mode cost advantage. The [wait repeat](client-wait-study.md) shows why fewer
|
||||
MCP requests or polls cannot replace correct answers and whole-task costs.
|
||||
|
||||
The [path query](path-query-study.md) composes selected recovered edges into one
|
||||
paged witness under explicit exclusions, with zero-edge/not-found/unknown
|
||||
outcomes. Both real SQLite MCP lanes preserve every original edge field; complete
|
||||
native function fidelity is checked. This removes an observed graph-reading
|
||||
burden without establishing feasible runtime paths or an adapter cost advantage.
|
||||
|
||||
The completed path-query pair answers the unchanged two-level task correctly in
|
||||
both actual models; each uses four path reads and three selected block reads,
|
||||
without a complete graph inventory in model context. Direct and Code Mode have
|
||||
similar wall time with mixed token/resource costs. Stock 1.833 explicitly rejects
|
||||
the unsupported path query while preserving readable Evidence/code in a real SDK
|
||||
check. These are scoped observations, not stock-provider parity or complete
|
||||
runtime reachability coverage.
|
||||
|
||||
The [function-boundary study](function-boundary-study.md) adds independent native
|
||||
prototype entries/return descriptors. On real stripped SSH, prototype counts
|
||||
4/10 differ from raw input counts 3/44; both actual models preserve that distinction,
|
||||
all exact matches/missing tuples and the selected caller-to-callee/helper transfer.
|
||||
Call-passing storage is separate from the caller value's own coordinate. Native
|
||||
model labels and recovered entries do not prove original source arity/ABI.
|
||||
Complete old function fidelity is preserved except for the new facet. Actual
|
||||
old-native/stock checks return explicit unavailability with readable Evidence.
|
||||
The two completed model tasks have mixed token/time/resource costs; no stable
|
||||
Code Mode advantage or provider parity follows.
|
||||
|
||||
The [storage study](storage-study.md) exposes native address-space descriptors
|
||||
and exact varnode_xref names without function decompilation. Width-qualified
|
||||
coordinates compose with prototype/value/passing-storage facts. Real x86-64
|
||||
and AArch64 OpenSSH catalog checks do not establish big-endian, alias, runtime
|
||||
or full provider parity coverage.
|
||||
|
||||
Both real models complete the extended native storage/prototype/call task.
|
||||
Code Mode reduces cumulative/uncached input and wall time in that pair but uses
|
||||
more local CPU and more inner fact reads. The shared metadata capability is
|
||||
verified separately from this adapter observation; earlier mixed pairs remain.
|
||||
|
||||
The [AArch64 reference study](aarch64-xref-study.md) corrects an observed native
|
||||
ADRP+ADD/LOAD/STORE gap through the shared PC-relative value owner. Real arm64
|
||||
SSH checks verify both warning owners, callers, selected machine words and
|
||||
77 GOT-slot reads. Coverage stays bounded and does not propagate live GOT
|
||||
contents. Traditional C/assembly preflight can answer the same new behavior-level
|
||||
question, avoiding a baseline missing necessary facts. All three real models
|
||||
complete it, while token/time/resource tradeoffs remain mixed. That pinned run
|
||||
preserves the recovered no-return disagreement and uses machine facts for the
|
||||
post-call path.
|
||||
|
||||
The [return-coverage study](aarch64-return-study.md) fixes the BTI entry split
|
||||
and a separate false no-return promotion through the native owners. The fresh
|
||||
three-way task passes with the strict call restored in both atomic captures;
|
||||
their complete selected function documents agree. Direct has lower input,
|
||||
time and CPU than Code Mode in this sample. Memory, analysis-profile differences,
|
||||
the common client executor and n=1 sampling prevent a universal adapter claim.
|
||||
@@ -0,0 +1,132 @@
|
||||
# Reuse proven native source refusals
|
||||
|
||||
After the streamed-inventory model pair, main was fetched again and remained
|
||||
`150e996a8`. Baseline runtime is `b88c75df8`. Native engine remains
|
||||
`2e398e7229e30b6d2387a802db8a0050764119a6b457020d334855e36e69d6c5`.
|
||||
This is an experimental follow-up, with no PR or integration into main.
|
||||
|
||||
## Observed redundant work
|
||||
|
||||
Two identical real LLVM string queries in one target lease first hit the 64 MiB
|
||||
source ceiling after 8.363 seconds. The second still runs native analysis for
|
||||
3.024 seconds / 3.021736 CPU seconds, retaining another partial prefix and
|
||||
reporting cleanup uncertainty. The provider discarded every failed work entry,
|
||||
even a proven output-size refusal for the identical immutable native capture.
|
||||
The source budget cannot grow within that lease. Neither query produces valid
|
||||
string facts; absence must remain unknown.
|
||||
|
||||
The same two-request probe after the change takes 7.603 seconds for the first
|
||||
refusal and 1.528 ms / 0.001567 CPU seconds for reuse. Only one partial source is
|
||||
captured, with the same readable Evidence handle on both errors. The added
|
||||
`cached_observation:{kind:"source_budget_refusal",scope:"target_lease"}` labels
|
||||
the original observation being reused; it does not report a fresh native run or
|
||||
current process status. Cold-time variation is not a causal speed claim.
|
||||
|
||||
| Same two-request diagnostic probe | Wall s | Local family CPU s | Kernel family peak MiB |
|
||||
| --------------------------------- | -----: | -----------------: | ---------------------: |
|
||||
| Before | 12.406 | 12.192070 | 1,745.6 |
|
||||
| After | 8.579 | 8.364375 | 1,492.5 |
|
||||
|
||||
This compares the same diagnostic intent, not successful LLVM analysis. The
|
||||
second original attempt adds a cleanup-uncertainty failure, whereas reuse keeps
|
||||
the original proven resource refusal without starting another process. Different
|
||||
cold costs and transient ownership observations prevent a pure latency ratio or
|
||||
general memory/speedup claim. The decisive signal is avoided native work.
|
||||
|
||||
## Cache ownership and invalidation
|
||||
|
||||
`NativeCaptureCache` owns pending/completed native work in one provider lease.
|
||||
It replaces the old map wrapper. It retains a refusal only for the understood
|
||||
`FactFailure` resource code, native-source scope, positive safe byte limit and
|
||||
observed lower bound above that limit, with a retained partial source ID and
|
||||
only the six understood refusal fields. Secondary file-cleanup uncertainty and
|
||||
unexamined metadata also prevent reuse. Classification copies own data properties without
|
||||
invoking getters; unknown/primitive failures retain their original identity.
|
||||
|
||||
Cancellation, I/O, cleanup uncertainty, other resources and unproven constraints
|
||||
remain uncached. The cache never turns an unknown primary cleanup outcome into
|
||||
resource success. Error views are separate from the immutable retained refusal,
|
||||
so editing an SDK error cannot alter later Evidence IDs or limits. At most the
|
||||
existing 128-source policy's number of work entries is memoized. When that table
|
||||
is full, new producer results still return without adding retention; the shared
|
||||
application owner continues to bound native admission. This also bounds any future source/key aliases. No additional source budget is introduced.
|
||||
|
||||
Keys keep the existing native request inputs, with target/engine/profile fixed
|
||||
by the owner instance. Catalog selectors do not change native capture arguments.
|
||||
Cache validity follows the immutable artifact capture and nonincreasing source
|
||||
budget, not live state. Successful captures retain the previous reuse semantics;
|
||||
close clears the cache after confirmed resource cleanup. A new lease gets a new
|
||||
owner. No cross-session negative cache is claimed.
|
||||
|
||||
## Actual adapters, failures and verification scope
|
||||
|
||||
Real LLVM SDK and Direct MCP checks pass refusal reuse, unchanged target/lease,
|
||||
identical refusal details except the explicit reuse label, one raw source,
|
||||
readable partial Evidence and exact full raw digest. SDK warm latency is 2.282 ms
|
||||
/ 0.001675 CPU seconds; Direct is 6.412 ms / 0.005566 CPU seconds. Their fresh
|
||||
first calls take 7.350 / 7.756 seconds respectively.
|
||||
|
||||
The first scripted Code Mode check fails its cache-hit precondition because the
|
||||
first call reports `cleanup_incomplete`. It correctly does not reuse that
|
||||
uncertain failure, and the second native attempt takes about 2.905 seconds.
|
||||
Both partial raw captures independently validate target/engine/hash/length. The
|
||||
original verifier recorded phases/stack but placed the complete API observation
|
||||
after its assertions, so the failed API payload is not fully auditable. Preserve
|
||||
that limitation and the original failed receipt; do not relabel it a pass.
|
||||
|
||||
The verifier now records replies before assertions and stops if cleanup is
|
||||
uncertain. One fresh scripted coverage repeat then reaches the proven-refusal
|
||||
path. In one actual MCP execution, the guest calls strings twice and Evidence
|
||||
once: the second call is 3 ms by guest `Date.now` (millisecond precision, separate
|
||||
warm CPU unmeasured), with the same handle and exactly one raw source. The full
|
||||
8.126-second program uses 8.119767 local CPU seconds. The two error results remain
|
||||
errors; successful composition does not establish successful LLVM analysis.
|
||||
This is a scripted coverage repeat after a verifier correction, not another
|
||||
model answer or a replacement for the failed observation.
|
||||
|
||||
| Whole verifier | Wall s | Local family CPU s | Kernel family peak MiB | Result |
|
||||
| ---------------------------------------- | -----: | -----------------: | ---------------------: | ---------------------------------- |
|
||||
| SDK refusal + reuse + Evidence | 9.092 | 8.908659 | 1,516.8 | pass |
|
||||
| Direct MCP same task | 9.886 | 9.666791 | 1,635.9 | pass |
|
||||
| First Code Mode attempt | 12.909 | 12.680445 | 1,939.9 | cache-hit precondition unavailable |
|
||||
| Corrected Code Mode coverage repeat | 10.088 | 9.885309 | 1,698.8 | pass |
|
||||
| Capacity + partial source + cancellation | 9.885 | 9.632806 | 1,487.4 | pass |
|
||||
|
||||
Both Code Mode attempts cost 22.997 family-wall seconds / 22.565754 CPU seconds;
|
||||
peak across them is 1,939.9 MiB, not the sum of peaks. These receipts are not a
|
||||
matched adapter performance ranking: verifier work and failure paths differ.
|
||||
All are one-CPU, 3 GiB early-stop / 4 GiB hard-limit, no-swap runs; payload-exit
|
||||
observers verify cleanup and OOM=0, including the failed attempt. Final exited-
|
||||
cgroup counters are unavailable. Kernel family memory includes file cache.
|
||||
|
||||
All 116 experimental JS tests pass, including in-flight reuse, invalidation,
|
||||
mutable caller views, zero/false/null/unknown errors, noncacheable cleanup,
|
||||
accessor avoidance and bounded memo admission. Real FFmpeg selected facts,
|
||||
Evidence, bytes and stale-handle checks pass in SDK/Direct/Code Mode after the
|
||||
cache change. Cancellation/owned cleanup checks pass. Changed-file lint and
|
||||
format checks pass. After tightening the sealed-source/secondary-cleanup eligibility guard, the full
|
||||
116-test suite passes again, and captured SDK/Direct/Code Mode refusal DTOs all
|
||||
pass through that sealed contract in replay. That replay is a production-boundary
|
||||
check, not another live-provider or model run. Existing full-suite/resource-gate
|
||||
limitations from the
|
||||
[streaming study](streamed-inventory-study.md) remain. No new model trial was
|
||||
performed for this cache change; the earlier fixed-runtime model costs remain
|
||||
attached to that earlier runtime. Scripted probes consume no model tokens.
|
||||
|
||||
LLVM and Node inventories still exceed the source budget. This optimization
|
||||
makes known refusal cheap; producer-side selective computation remains the next
|
||||
coverage/computation question. It does not improve provider parity or prove
|
||||
complex reverse-engineering superiority.
|
||||
|
||||
Local artifact SHA-256 (raw documents remain uncommitted):
|
||||
|
||||
- `capacity-cache-before.json`: `68fbd4444c81b4a4435a8d300f8b1ea7365f140078ab3cc322bde140be74db24`
|
||||
- `capacity-cache-after.json`: `66491d37d85c3748578022e0f7e0f8013c2bf19ecec6d0c73db33d2246c7485e`
|
||||
- `capacity-cache-before.log`: `d57684ede8f9d01bf9750b78f400b4bb529e2d7a23b84195d79d6d729cba6190`
|
||||
- `capacity-cache-after.log`: `30039f832930680a8cc128c8a372c0018be08c88ac84e4db03d2cc15e4623b38`
|
||||
- `capacity-cache-final-sdk.json`: `95326d584a88ca5130e79e116b5c0a14bdbaa0a6016342d58010515e8a6c22f9`
|
||||
- `capacity-cache-final-direct.json`: `ead7e2c5976e13876d1d34cd336e88f62a2e9bba4b3812bc012efbc64d272473`
|
||||
- `capacity-cache-final-codemode.json`: `8bb64217d52bdbd1771968b9274d6ae04a6ea3b0ae1e5a09d0510bf180320e7b`
|
||||
- `capacity-cache-final2-codemode.json`: `4ccf81f282a2f62db00638b6a94feaf80992aacc8096ea15d3fc419f0d2789a3`
|
||||
- `capacity-cache-js-precommit.log`: `d22b3e948baf2a36ae262786d470af0fc3d631ddd79d88a879ac9f2103352792`
|
||||
- `capacity-cache-js-sealed.log`: `004ffeac2994612f1608fd5904eff15c41ea059d4ad91644abce8532669a5ea0`
|
||||
@@ -0,0 +1,123 @@
|
||||
import { freezeFacts as freeze } from "./fact-reads.mjs";
|
||||
import { nativePage } from "./native-reads.mjs";
|
||||
|
||||
function search(outgoing, from, target, avoid) {
|
||||
const blocked = new Set(avoid);
|
||||
if (blocked.has(from) || (target.kind === "block" && blocked.has(target.id)))
|
||||
return {
|
||||
status: "not-found",
|
||||
end: null,
|
||||
items: [],
|
||||
examined_blocks: 0,
|
||||
examined_edges: 0,
|
||||
search: "excluded-endpoint",
|
||||
};
|
||||
const queue = [from],
|
||||
predecessor = new Map([[from, null]]);
|
||||
let examined_blocks = 0,
|
||||
examined_edges = 0;
|
||||
for (let cursor = 0; cursor < queue.length; cursor++) {
|
||||
const current = queue[cursor],
|
||||
edges = outgoing.get(current) ?? [];
|
||||
examined_blocks++;
|
||||
if (target.kind === "block" ? current === target.id : edges.length === 0) {
|
||||
const path = [];
|
||||
for (let at = current; predecessor.get(at) !== null;) {
|
||||
const edge = predecessor.get(at);
|
||||
path.push(edge);
|
||||
at = edge.from;
|
||||
}
|
||||
path.reverse();
|
||||
return {
|
||||
status: "found",
|
||||
end: current,
|
||||
items: path.map((edge, step_index) => freeze({ ...edge, step_index })),
|
||||
examined_blocks,
|
||||
examined_edges,
|
||||
search: "shortest-witness",
|
||||
};
|
||||
}
|
||||
for (const edge of edges) {
|
||||
examined_edges++;
|
||||
if (!blocked.has(edge.to) && !predecessor.has(edge.to)) {
|
||||
predecessor.set(edge.to, edge);
|
||||
queue.push(edge.to);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
status: "not-found",
|
||||
end: null,
|
||||
items: [],
|
||||
examined_blocks,
|
||||
examined_edges,
|
||||
search: "reachable-subgraph-exhausted",
|
||||
};
|
||||
}
|
||||
|
||||
// Consume validated identities/edges, never provider text or machine predicates.
|
||||
// A resident immutable graph owns at most one cached query and O(V) search state.
|
||||
export function createGraphPathReader(blocks, outgoing) {
|
||||
let last;
|
||||
return (input) => {
|
||||
const avoid = [...new Set(input.avoid ?? [])];
|
||||
const selected = [
|
||||
input.from,
|
||||
...(input.target.kind === "block" ? [input.target.id] : []),
|
||||
...avoid,
|
||||
];
|
||||
const unretained_blocks = [...new Set(selected)].filter(
|
||||
(id) => !blocks.has(id),
|
||||
);
|
||||
let result;
|
||||
if (unretained_blocks.length) {
|
||||
result = {
|
||||
status: "unknown",
|
||||
end: null,
|
||||
items: [],
|
||||
examined_blocks: 0,
|
||||
examined_edges: 0,
|
||||
search: "unretained-selection",
|
||||
};
|
||||
} else {
|
||||
const key = JSON.stringify([
|
||||
input.from,
|
||||
input.target.kind,
|
||||
input.target.kind === "block" ? input.target.id : null,
|
||||
[...avoid].sort((a, b) => a - b),
|
||||
]);
|
||||
if (last?.key !== key)
|
||||
last = {
|
||||
key,
|
||||
result: freeze(search(outgoing, input.from, input.target, avoid)),
|
||||
};
|
||||
result = last.result;
|
||||
}
|
||||
const {
|
||||
items,
|
||||
examined_blocks,
|
||||
examined_edges,
|
||||
search: scope,
|
||||
...outcome
|
||||
} = result;
|
||||
return {
|
||||
...outcome,
|
||||
from: input.from,
|
||||
target: { ...input.target },
|
||||
avoid,
|
||||
...nativePage(items, input),
|
||||
total: outcome.status === "unknown" ? null : items.length,
|
||||
unretained_blocks,
|
||||
path_coverage: {
|
||||
scope:
|
||||
"recovered CFG under requested exclusions; one shortest edge-count witness in native edge order",
|
||||
search: scope,
|
||||
examined_blocks,
|
||||
examined_edges,
|
||||
branch_predicate_feasibility: "unknown",
|
||||
machine_semantic_equivalence: "unknown",
|
||||
runtime_reachability: "unknown",
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { createGraphPathReader } from "./cfg-path.mjs";
|
||||
import { MAX_GRAPH_BLOCKS } from "./graph-limits.mjs";
|
||||
|
||||
const graph = (successors) => {
|
||||
const blocks = new Map(successors.map((_, id) => [id, { id }]));
|
||||
const outgoing = new Map(
|
||||
successors.map((targets, from) => [
|
||||
from,
|
||||
targets.map((to, index) =>
|
||||
Object.freeze({
|
||||
id: `${from}:${index}`,
|
||||
from,
|
||||
to,
|
||||
target: to,
|
||||
index,
|
||||
operation: `op${from}`,
|
||||
polarity: null,
|
||||
condition_value: null,
|
||||
condition_test: null,
|
||||
}),
|
||||
),
|
||||
]),
|
||||
);
|
||||
return { blocks, outgoing, read: createGraphPathReader(blocks, outgoing) };
|
||||
};
|
||||
|
||||
function floydDistances(successors, allowed) {
|
||||
const distances = Array.from({ length: 3 }, (_, from) =>
|
||||
Array.from({ length: 3 }, (_, to) =>
|
||||
!allowed(from) || !allowed(to)
|
||||
? Infinity
|
||||
: from === to
|
||||
? 0
|
||||
: successors[from].includes(to)
|
||||
? 1
|
||||
: Infinity,
|
||||
),
|
||||
);
|
||||
for (let k = 0; k < 3; k++)
|
||||
for (let i = 0; i < 3; i++)
|
||||
for (let j = 0; j < 3; j++)
|
||||
distances[i][j] = Math.min(
|
||||
distances[i][j],
|
||||
distances[i][k] + distances[k][j],
|
||||
);
|
||||
return distances;
|
||||
}
|
||||
function assertWitness(result, { distance, ends, from, outgoing, allowed }) {
|
||||
assert.equal(result.status, distance === Infinity ? "not-found" : "found");
|
||||
assert.equal(result.total, distance === Infinity ? 0 : distance);
|
||||
if (result.status !== "found") return;
|
||||
assert.ok(ends.includes(result.end));
|
||||
let at = from;
|
||||
for (const [step, edge] of result.items.entries()) {
|
||||
assert.equal(edge.step_index, step);
|
||||
assert.equal(edge.from, at);
|
||||
assert.equal(outgoing.get(at)[edge.index].id, edge.id);
|
||||
assert.equal(outgoing.get(at)[edge.index].to, edge.to);
|
||||
assert.ok(allowed(edge.to));
|
||||
at = edge.to;
|
||||
}
|
||||
assert.equal(at, result.end);
|
||||
}
|
||||
|
||||
test("all three-node digraphs and exclusions agree with independent Floyd-Warshall distances", () => {
|
||||
for (let mask = 0; mask < 512; mask++) {
|
||||
const successors = Array.from({ length: 3 }, (_, from) =>
|
||||
[0, 1, 2].filter((to) => mask & (1 << (from * 3 + to))),
|
||||
);
|
||||
const { read, outgoing } = graph(successors);
|
||||
for (let exclusions = 0; exclusions < 8; exclusions++) {
|
||||
const avoid = [0, 1, 2].filter((id) => exclusions & (1 << id));
|
||||
const allowed = (id) => !avoid.includes(id);
|
||||
const distances = floydDistances(successors, allowed);
|
||||
const queries = [0, 1, 2].flatMap((from) =>
|
||||
[
|
||||
{ kind: "exit" },
|
||||
...[0, 1, 2].map((id) => ({ kind: "block", id })),
|
||||
].map((target) => ({ from, target })),
|
||||
);
|
||||
for (const { from, target } of queries) {
|
||||
const ends =
|
||||
target.kind === "block"
|
||||
? [target.id]
|
||||
: [0, 1, 2].filter((id) => successors[id].length === 0);
|
||||
const distance = Math.min(...ends.map((to) => distances[from][to]));
|
||||
assertWitness(read({ from, target, avoid }), {
|
||||
distance,
|
||||
ends,
|
||||
from,
|
||||
outgoing,
|
||||
allowed,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("paging retains original edge ordinal, source fields and full-path outcome", () => {
|
||||
const { read } = graph([[0, 1, 1], [2], []]);
|
||||
const request = { from: 0, target: { kind: "exit" } };
|
||||
const first = read({ ...request, limit: 1 });
|
||||
assert.equal(first.status, "found");
|
||||
assert.equal(first.total, 2);
|
||||
assert.equal(first.end, 2);
|
||||
assert.equal(first.next_offset, 1);
|
||||
assert.equal(first.items[0].id, "0:1");
|
||||
assert.equal(first.items[0].index, 1);
|
||||
assert.equal(first.items[0].step_index, 0);
|
||||
assert.equal(first.items[0].operation, "op0");
|
||||
assert.throws(() => {
|
||||
first.items[0].to = 999;
|
||||
}, TypeError);
|
||||
const second = read({ ...request, offset: 1, limit: 1 });
|
||||
assert.equal(second.items[0].step_index, 1);
|
||||
assert.equal(second.next_offset, null);
|
||||
const beyond = read({ ...request, offset: 9 });
|
||||
assert.equal(beyond.status, "found");
|
||||
assert.equal(beyond.total, 2);
|
||||
assert.equal(beyond.end, 2);
|
||||
assert.deepEqual(beyond.items, []);
|
||||
});
|
||||
|
||||
test("unknown selections, duplicates and excluded endpoints stay explicit", () => {
|
||||
const { read } = graph([[1], []]);
|
||||
for (const input of [
|
||||
{ from: 9, target: { kind: "exit" } },
|
||||
{ from: 0, target: { kind: "block", id: 9 } },
|
||||
{ from: 0, target: { kind: "exit" }, avoid: [9, 9] },
|
||||
]) {
|
||||
const result = read(input);
|
||||
assert.equal(result.status, "unknown");
|
||||
assert.equal(result.total, null);
|
||||
assert.equal(result.end, null);
|
||||
assert.deepEqual(result.unretained_blocks, [9]);
|
||||
}
|
||||
assert.equal(
|
||||
read({ from: 0, target: { kind: "block", id: 0 }, avoid: [0] }).status,
|
||||
"not-found",
|
||||
);
|
||||
const zero = read({ from: 1, target: { kind: "exit" } });
|
||||
assert.equal(zero.status, "found");
|
||||
assert.equal(zero.total, 0);
|
||||
assert.equal(zero.end, 1);
|
||||
assert.equal(zero.path_coverage.runtime_reachability, "unknown");
|
||||
});
|
||||
|
||||
test("one graph-owned cache covers paging and normalized exclusions, replaces on input change", () => {
|
||||
const { blocks, outgoing } = graph([[1], [2], [], []]);
|
||||
let reads = 0;
|
||||
const observed = {
|
||||
get(id) {
|
||||
reads++;
|
||||
return outgoing.get(id);
|
||||
},
|
||||
};
|
||||
const read = createGraphPathReader(blocks, observed);
|
||||
const request = { from: 0, target: { kind: "exit" }, avoid: [3, 3] };
|
||||
read(request);
|
||||
const initial = reads;
|
||||
read({ ...request, avoid: [3], offset: 1, limit: 1 });
|
||||
assert.equal(reads, initial);
|
||||
read({ ...request, avoid: [99] });
|
||||
read(request);
|
||||
assert.equal(reads, initial);
|
||||
read({ from: 0, target: { kind: "block", id: 1 }, avoid: [3] });
|
||||
assert.ok(reads > initial);
|
||||
const changed = reads;
|
||||
read(request);
|
||||
assert.ok(reads > changed);
|
||||
const other = createGraphPathReader(blocks, observed);
|
||||
const before = reads;
|
||||
other(request);
|
||||
assert.ok(reads > before, "fresh owner must not share the cache");
|
||||
});
|
||||
|
||||
test("maximum admitted chain is iterative, paged and does not expand caller output", () => {
|
||||
const { read } = graph(
|
||||
Array.from({ length: MAX_GRAPH_BLOCKS }, (_, i) =>
|
||||
i + 1 < MAX_GRAPH_BLOCKS ? [i + 1] : [],
|
||||
),
|
||||
);
|
||||
const result = read({ from: 0, target: { kind: "exit" }, limit: 1 });
|
||||
assert.equal(result.total, MAX_GRAPH_BLOCKS - 1);
|
||||
assert.equal(result.items.length, 1);
|
||||
assert.equal(result.end, MAX_GRAPH_BLOCKS - 1);
|
||||
assert.equal(result.path_coverage.examined_blocks, MAX_GRAPH_BLOCKS);
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { AtomicSession } from "./session.mjs";
|
||||
import { executeJavaScript } from "./executor.mjs";
|
||||
|
||||
const [binary, script] = process.argv.slice(2);
|
||||
if (!binary || !script)
|
||||
throw new Error("Usage: node cli.mjs BINARY JAVASCRIPT_FILE");
|
||||
const session = new AtomicSession();
|
||||
try {
|
||||
await session.open(binary);
|
||||
const result = await executeJavaScript(
|
||||
session,
|
||||
await readFile(script, "utf8"),
|
||||
);
|
||||
console.log(JSON.stringify(result));
|
||||
process.exitCode = result.ok ? 0 : 1;
|
||||
} finally {
|
||||
session.abort();
|
||||
await session.close();
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
# Client waiting and whole-task cost
|
||||
|
||||
The [selected-case pair](switch-study.md) exposes one-second client polls after
|
||||
the snapshot execution yields. Direct makes six waits (three one-second then
|
||||
three ten-second requests); Code Mode makes three one-second requests. Five
|
||||
direct and two Code Mode wait responses still report a running cell. Initial
|
||||
execution yields after about 31 seconds in both lanes. This is observed client
|
||||
behavior, separate from MCP attempts and native source-capture time.
|
||||
|
||||
Native latency remains variable, including in sequential scripted MCP runs
|
||||
without models. The [overlap canary](overlap-study.md) did not establish a cause.
|
||||
No analysis acceleration or cache invalidation change is proposed here.
|
||||
|
||||
## Frozen diagnostic
|
||||
|
||||
The opt-in runner flag `--guide-long-waits` appends exactly the same client wait
|
||||
policy in both lanes: resume an already-running cell with a 30,000 ms wait,
|
||||
respect the advertised schema, and do not sleep or duplicate analysis merely
|
||||
to check progress. It changes neither the initial execution yield policy nor
|
||||
the provider/Code Mode deadlines. It supplies no analysis facts. The policy,
|
||||
flag and instruction digest are recorded in each trial's settings. Older runs
|
||||
without this flag remain a separate stratum.
|
||||
|
||||
Run Code Mode first, then direct, with the unchanged
|
||||
[question](sqlite-switch-question.txt) and [oracle](switch-oracle.md), final
|
||||
`a9ca8a8a...` engine, complete four/eighteen-tool catalogs and the same exact
|
||||
discovery/envelope guidance as the first pair. Use fresh leases and isolated
|
||||
model workspaces, requested `gpt-6.1-sol/high`, Codex 0.161.0 and the same one-CPU,
|
||||
4 GiB hard / 3 GiB early-stop resource policy. No runtime edits during the pair.
|
||||
Local records use `sqlite-switch-{codemode,direct}-v2*`.
|
||||
|
||||
Review complete answers against the frozen independent machine oracle and
|
||||
retained source, including selector widths, all requested cases, signed target
|
||||
arithmetic, case/edge identities, native default versus machine out-of-range
|
||||
guard, provenance and unknown runtime behavior. Require one VM capture and
|
||||
focused reads; a lower token count without a correct answer is not a win.
|
||||
|
||||
Record actual wait arguments and running/completed responses, model responses,
|
||||
all input/cached/uncached/output/reasoning tokens, MCP/API attempts, wall time,
|
||||
family CPU, kernel family peak, native source-capture time, identity/freshness
|
||||
and cleanup/OOM status. Count discovery, guidance and unsuccessful waits in
|
||||
whole-task usage. Fewer polls would establish adherence in this client, not
|
||||
causally lower tokens or native latency. A before/after pair remains subject to
|
||||
model choices, prompt caches, host contention and run order; do not subtract
|
||||
native or polling intervals to manufacture an adapter speedup.
|
||||
|
||||
The [official Codex CLI reference](https://learn.chatgpt.com/docs/cli/reference)
|
||||
documents client configuration but does not establish the `wait` contract used
|
||||
here. The actual captured client calls and subsequent run establish behavior;
|
||||
no configuration feature flag is treated as proof of the available surface.
|
||||
The native/API contracts are unchanged.
|
||||
|
||||
## Executed repeat
|
||||
|
||||
Both runs pin `790cdfdef`, with Code Mode first and direct second. Their shared
|
||||
frozen runtime is preserved by tag
|
||||
[`experiment/atomic-codemode-wait-runtime-20261016`](https://github.com/morluto/rea/tree/experiment/atomic-codemode-wait-runtime-20261016),
|
||||
which retains the original revision before commit-attribution metadata cleanup.
|
||||
Both complete answers again pass the frozen oracle: format ownership before capture, selector
|
||||
widths, all five selected case identities/edges/targets, signed table arithmetic,
|
||||
the absent explicit `0xb6` case and distinct native-default/machine-guard
|
||||
destinations. Direct cites eleven observed source IDs; Code Mode cites ten.
|
||||
Each has one VM source, equal to the full prior graph/ordinary-field golden,
|
||||
and no complete case/C/graph fetch. Both close the lease and retain the stated
|
||||
static/alias/runtime limits. Source fidelity does not prove global equivalence.
|
||||
|
||||
| Whole-task measure | Direct atomic | Code Mode |
|
||||
| ------------------------------ | ------------: | --------: |
|
||||
| Cumulative input tokens | 280,035 | 372,288 |
|
||||
| Included cached input | 221,312 | 343,168 |
|
||||
| Uncached input | 58,723 | 29,120 |
|
||||
| Output tokens | 4,648 | 5,384 |
|
||||
| Included reasoning output | 1,122 | 862 |
|
||||
| Observed model responses | 12 | 16 |
|
||||
| Client execution / wait calls | 10 / 1 | 14 / 1 |
|
||||
| MCP attempts, including reject | 17 | 15 |
|
||||
| Successful atomic fact reads | 14 | 19 |
|
||||
| Model wall seconds | 175.908 | 196.640 |
|
||||
| Family wall seconds | 176.382 | 197.767 |
|
||||
| Family CPU seconds | 66.735 | 56.081 |
|
||||
| Kernel process-family peak MiB | 786.6 | 870.3 |
|
||||
| VM source-capture wall seconds | 47.010 | 39.828 |
|
||||
|
||||
Both request `yield_time_ms:30000` once, resuming their pending snapshot cell;
|
||||
the waits return completed results after 16.5 seconds direct and 6.5 Code Mode.
|
||||
Neither adds an unsuccessful running-cell poll. This establishes adherence,
|
||||
and reduces waits from six/three to one/one in these samples. It does not
|
||||
establish a causal token/latency reduction: native capture times and subsequent
|
||||
investigation choices differ, and the Code Mode repeat makes more fact reads.
|
||||
|
||||
Code Mode's attempts include a schema-rejected `timeout_ms:200000` (maximum
|
||||
120,000), then a valid retry. Later a script returns complete input arrays from
|
||||
operations at a PHI-heavy origin and exceeds the 32 KiB result budget. Its three
|
||||
host reads succeed and source Evidence survives; the next script returns a
|
||||
smaller projection successfully. Both costs stay in the ledger. Direct has no
|
||||
failed attempts. The timeout mistake also occurred in the earlier control task:
|
||||
the next interface check should make the default/maximum explicit in discovery,
|
||||
using the execution owner's policy rather than another copied constant.
|
||||
|
||||
Within this repeat, Code Mode uses 32.9% more cumulative input, 15.8% more output
|
||||
and 11.8% more model wall time, while using 50.4% less uncached input and less
|
||||
family CPU. Relative to the first pair, direct cumulative input falls but its
|
||||
uncached input rises; Code Mode cumulative and uncached input both rise despite
|
||||
fewer waits. There is no stable whole-task winner across these strata.
|
||||
|
||||
Per-response usage matches the ledger; guidance is included in token usage.
|
||||
Runtime, engine and target fingerprints remain unchanged. OOM is zero and
|
||||
payload/profile cleanup is verified. Resource/model settings and the cold-lease,
|
||||
uncontrolled-cache/host and unmeasured-remote-compute limitations remain as above.
|
||||
Kernel peaks include charged file cache, not RSS. Both clients already provide
|
||||
JavaScript composition. Full records use the declared `-v2` local paths; the
|
||||
unchanged summarizer reconstructs actual usage but does not grade correctness.
|
||||
|
||||
## Discovery follow-up
|
||||
|
||||
The execution owner, MCP admission schema and Code Mode help now use one frozen
|
||||
policy in `limits.mjs`. Both the execution description and detailed reference
|
||||
state that omitting `timeout_ms` uses the 120,000 ms default/maximum; the separate
|
||||
2,000 ms guest CPU budget remains explicit. Heap, stack, host-call, source and
|
||||
result budgets are unchanged. The direct adapter omits Code Mode execution
|
||||
limits/notes. Snapshot documentation also names the optional independent switch
|
||||
facet, avoiding a stale return description after the new exporter.
|
||||
|
||||
All 73 shared JS tests pass (4.349 family wall / 4.114 CPU seconds, 79.6 MiB
|
||||
kernel peak). The actual SDK catalogs and named references validate in both
|
||||
lanes. The Code Mode MCP check rejects the observed 200,000 ms parameter, then
|
||||
successfully executes a defaulted request with zero host calls (final catalog
|
||||
check: 5.086 family wall / 4.111 CPU seconds, 142.2 MiB kernel peak).
|
||||
A real zlib MCP check also verifies bounded
|
||||
ordinary/oversized guest errors and retained source access after failure
|
||||
(1.530 wall / 1.338 CPU seconds, 136.6 MiB). All have OOM 0 and verified cleanup;
|
||||
focused lint has no warnings and formatting passes. No native rebuild or full
|
||||
repository gate ran for this discovery change. No new model pair has measured
|
||||
whether it reduces mistakes or whole-task cost; earlier results retain their
|
||||
original runtime pins.
|
||||
@@ -0,0 +1,92 @@
|
||||
// Stream a complete legacy native inventory; retain only small expected query pages.
|
||||
import assert from "node:assert/strict";
|
||||
import { createReadStream } from "node:fs";
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { createHash } from "node:crypto";
|
||||
import { createGunzip } from "node:zlib";
|
||||
import { Transform } from "node:stream";
|
||||
import chain from "stream-chain";
|
||||
import { parser } from "stream-json";
|
||||
import { pick } from "stream-json/filters/pick.js";
|
||||
import { streamArray } from "stream-json/streamers/stream-array.js";
|
||||
import { join } from "node:path";
|
||||
|
||||
const [directory, output] = process.argv.slice(2);
|
||||
assert(directory && output);
|
||||
const manifest = JSON.parse(
|
||||
await readFile(join(directory, "manifest.json"), "utf8"),
|
||||
);
|
||||
const queries = [
|
||||
"undefined symbol",
|
||||
"Invalid bitcode signature",
|
||||
"",
|
||||
"\ud800",
|
||||
"a.b+",
|
||||
].map((query) => ({ query, total: 0, sample: [] }));
|
||||
const rawHash = createHash("sha256");
|
||||
let bytes = 0,
|
||||
total = 0,
|
||||
group = [],
|
||||
previous = -1;
|
||||
const emit = () => {
|
||||
group.sort((a, b) => a.encoding.localeCompare(b.encoding, "en"));
|
||||
for (const row of group) {
|
||||
for (const selection of queries)
|
||||
if (row.text.includes(selection.query)) {
|
||||
selection.total++;
|
||||
if (selection.sample.length < 16)
|
||||
selection.sample.push({ ...row, source_row: total });
|
||||
}
|
||||
total++;
|
||||
}
|
||||
group = [];
|
||||
};
|
||||
const stream = chain([
|
||||
createReadStream(join(directory, "inventory.json.gz")),
|
||||
createGunzip(),
|
||||
new Transform({
|
||||
transform(chunk, _encoding, done) {
|
||||
rawHash.update(chunk);
|
||||
bytes += chunk.length;
|
||||
done(null, chunk);
|
||||
},
|
||||
}),
|
||||
parser(),
|
||||
pick({ filter: "strings" }),
|
||||
streamArray(),
|
||||
]);
|
||||
for await (const { value } of stream) {
|
||||
assert(Number.isSafeInteger(value.address) && typeof value.text === "string");
|
||||
assert.equal(value.address_hex, "0x" + value.address.toString(16));
|
||||
assert(value.address >= previous);
|
||||
if (value.address !== previous) {
|
||||
emit();
|
||||
previous = value.address;
|
||||
}
|
||||
group.push(value);
|
||||
}
|
||||
emit();
|
||||
assert.equal(rawHash.digest("hex"), manifest.raw_sha256);
|
||||
assert.equal(bytes, manifest.raw_bytes);
|
||||
await writeFile(
|
||||
output,
|
||||
JSON.stringify(
|
||||
{
|
||||
manifest,
|
||||
total,
|
||||
queries,
|
||||
scope:
|
||||
"Complete legacy producer comparison; query matches use JavaScript UTF16 includes, only first 16 per query retained. Not an independent proof of all string recognition.",
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
{ flag: "wx" },
|
||||
);
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
total,
|
||||
bytes,
|
||||
queries: queries.map(({ query, total }) => ({ query, total })),
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,144 @@
|
||||
// Immediate postdominators on the reversed recovered CFG, using linear retained
|
||||
// state. Control dependence is derived for finite paths to recovered exits.
|
||||
import { FactFailure } from "./fact-error.mjs";
|
||||
import { freezeFacts } from "./fact-reads.mjs";
|
||||
|
||||
const workBudget = (limit) => {
|
||||
let work = 0;
|
||||
return () => {
|
||||
if (++work > limit)
|
||||
throw new FactFailure(
|
||||
"capacity",
|
||||
"Control-dependence work budget exceeded",
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
// Retain one linear-size index per resident graph. Selected rows are generated
|
||||
// per read, so paging does not retain a potentially quadratic relation set.
|
||||
export function createControlDependenceIndex(
|
||||
blocks,
|
||||
{ workLimit = 2_000_000 } = {},
|
||||
) {
|
||||
const exit = Symbol("recovered-exit");
|
||||
const successors = new Map(
|
||||
blocks.map((block) => [
|
||||
block.id,
|
||||
block.successors.map((edge) => edge.target),
|
||||
]),
|
||||
);
|
||||
const reverse = new Map([
|
||||
[exit, []],
|
||||
...blocks.map((block) => [block.id, []]),
|
||||
]);
|
||||
const tick = workBudget(workLimit);
|
||||
for (const [from, targets] of successors) {
|
||||
if (!targets.length) targets.push(exit);
|
||||
for (const to of targets) reverse.get(to).push(from);
|
||||
}
|
||||
const { parent, visited } = postdominatorParents(
|
||||
exit,
|
||||
successors,
|
||||
reverse,
|
||||
tick,
|
||||
);
|
||||
const coverage = freezeFacts({
|
||||
scope:
|
||||
"derived control dependence in the recovered graph; zero-successor blocks treated as exits; finite paths only",
|
||||
status:
|
||||
visited.size === blocks.length + 1
|
||||
? "complete-for-recovered-finite-exit-paths"
|
||||
: "partial",
|
||||
exit_unreachable_blocks: blocks
|
||||
.filter((block) => !visited.has(block.id))
|
||||
.map((block) => block.id),
|
||||
nontermination: "unknown",
|
||||
runtime_reachability: "unknown",
|
||||
});
|
||||
function* relations(dependents) {
|
||||
const tick = workBudget(workLimit);
|
||||
for (const block of blocks) {
|
||||
if (!parent.has(block.id)) continue;
|
||||
for (const edge of block.successors) {
|
||||
let runner = edge.target;
|
||||
while (
|
||||
parent.has(runner) &&
|
||||
runner !== parent.get(block.id) &&
|
||||
runner !== exit
|
||||
) {
|
||||
tick();
|
||||
if (!dependents || dependents.has(runner))
|
||||
yield { controller: block.id, dependent: runner, edge };
|
||||
runner = parent.get(runner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Object.freeze({
|
||||
relations,
|
||||
coverage,
|
||||
read: ({ seeds, offset = 0, limit = 20 }) => {
|
||||
const selected = new Set(seeds),
|
||||
items = [];
|
||||
let total = 0;
|
||||
// Exhaust for a truthful total, retaining only the requested page.
|
||||
for (const row of relations(selected)) {
|
||||
if (total >= offset && items.length < limit) items.push(row);
|
||||
total++;
|
||||
}
|
||||
return {
|
||||
items,
|
||||
total,
|
||||
next_offset: offset + limit < total ? offset + limit : null,
|
||||
relation_coverage: coverage,
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function postdominatorParents(exit, successors, reverse, tick) {
|
||||
const visited = new Set([exit]);
|
||||
const stack = [[exit, 0]],
|
||||
postorder = [];
|
||||
while (stack.length) {
|
||||
tick();
|
||||
const frame = stack.at(-1),
|
||||
children = reverse.get(frame[0]);
|
||||
if (frame[1] < children.length) {
|
||||
const child = children[frame[1]++];
|
||||
if (!visited.has(child)) {
|
||||
visited.add(child);
|
||||
stack.push([child, 0]);
|
||||
}
|
||||
} else {
|
||||
postorder.push(frame[0]);
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
const order = postorder.reverse();
|
||||
const position = new Map(order.map((id, i) => [id, i]));
|
||||
const parent = new Map([[exit, exit]]);
|
||||
const intersect = (a, b) => {
|
||||
while (a !== b) {
|
||||
tick();
|
||||
if (position.get(a) > position.get(b)) a = parent.get(a);
|
||||
else b = parent.get(b);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
let changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (const node of order.slice(1)) {
|
||||
tick();
|
||||
const known = successors.get(node).filter((id) => parent.has(id));
|
||||
if (!known.length) continue;
|
||||
const next = known.slice(1).reduce(intersect, known[0]);
|
||||
if (parent.get(node) !== next) {
|
||||
parent.set(node, next);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return { parent, visited };
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Test/evaluator oracle only. Removing a node and searching for exits is
|
||||
// independent of the runtime's immediate-postdominator algorithm.
|
||||
export function finiteExitControlOracle(blocks) {
|
||||
const reverse = new Map(blocks.map((block) => [block.id, []]));
|
||||
for (const block of blocks)
|
||||
for (const edge of block.successors)
|
||||
reverse.get(edge.target).push(block.id);
|
||||
const exits = blocks
|
||||
.filter((block) => !block.successors.length)
|
||||
.map((b) => b.id);
|
||||
const reachesExitWithout = (forbidden) => {
|
||||
const seen = new Set(exits.filter((id) => id !== forbidden));
|
||||
const queue = [...seen];
|
||||
for (let i = 0; i < queue.length; i++)
|
||||
for (const previous of reverse.get(queue[i]))
|
||||
if (previous !== forbidden && !seen.has(previous)) {
|
||||
seen.add(previous);
|
||||
queue.push(previous);
|
||||
}
|
||||
return seen;
|
||||
};
|
||||
const active = reachesExitWithout(undefined),
|
||||
relations = [];
|
||||
for (const dependent of active) {
|
||||
const avoiding = reachesExitWithout(dependent);
|
||||
const postdominates = (node) => active.has(node) && !avoiding.has(node);
|
||||
for (const block of blocks) {
|
||||
if (!active.has(block.id)) continue;
|
||||
// Strict postdominance excludes the node itself, preserving loop
|
||||
// self-dependence when a recovered edge leads back to its controller.
|
||||
if (block.id !== dependent && postdominates(block.id)) continue;
|
||||
for (const edge of block.successors)
|
||||
if (postdominates(edge.target))
|
||||
relations.push({ controller: block.id, dependent, edge_id: edge.id });
|
||||
}
|
||||
}
|
||||
return {
|
||||
relations,
|
||||
exit_unreachable_blocks: blocks
|
||||
.filter((b) => !active.has(b.id))
|
||||
.map((b) => b.id),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
# Correct and reusable control queries
|
||||
|
||||
Retained-source inspection exposed a correctness gap: a nonexistent CFG seed
|
||||
returned an empty set without saying that the block was unretained. Source-wide
|
||||
control coverage could be mistaken for proof that the requested block had no
|
||||
controllers. Incoming/outgoing queries shared this selection boundary. They now
|
||||
deduplicate seeds and return `unretained_seeds`, distinguishing a retained block
|
||||
with no relations. Incoming/outgoing order follows caller seeds then native
|
||||
edges; controller order stays native controller/edge then postdominator ancestor.
|
||||
|
||||
`createControlDependenceIndex` replaces the one-shot implementation. The native
|
||||
graph owner constructs it lazily and retains it only with that resident snapshot.
|
||||
It holds linear-size postdominator/coverage state, without query keys or a
|
||||
potentially quadratic complete relation set. Page reads generate relations,
|
||||
count the entire selected set and retain only the requested page. Construction
|
||||
and each relation walk have separate two-million-step budgets; capacity failure
|
||||
is explicit. Coverage/edges are immutable; fresh reply row containers cannot
|
||||
change subsequent reads. The index follows the existing two-resident-model
|
||||
lifetime. CLI, SDK and both adapters use this owner; no native rebuild or new
|
||||
public method is required.
|
||||
|
||||
Semantics remain finite paths to recovered zero-successor exits. Loop
|
||||
self-dependence is possible; exit-unreachable blocks are explicit. Runtime
|
||||
feasibility, memory aliases and nontermination remain unknown.
|
||||
|
||||
## Independent verification
|
||||
|
||||
The test/evaluator-only `control-path-oracle.mjs` removes each candidate node
|
||||
and searches backward from exits. It independently verifies all 512 three-node
|
||||
directed graphs, including cycles, alongside the existing 64 four-node DAGs,
|
||||
multiple exits, unreachable regions and work-capacity checks. Single-row paging,
|
||||
unknown/duplicate seeds and immutable coverage/edges pass. The related suite
|
||||
passes 82 tests; the final added edge-mutation assertion also passes its focused
|
||||
ten-test suite. Experiment lint has no warnings; formatting passes.
|
||||
|
||||
The real Debian SQLite VM has 1,229 blocks, 2,061 edges and 2,845 derived control
|
||||
triples. Both actual MCP adapters page every triple and match the independent
|
||||
oracle, including exact native edge metadata. Each executes 52 MCP requests.
|
||||
Full graph, ordinary function/call records and Evidence views equal the earlier
|
||||
golden; former projection frontiers remain readable. All three CFG relation
|
||||
kinds correctly report unknown-only and mixed/duplicate seeds. Target and
|
||||
preserved `a9ca8a8a...` engine match the [switch study](switch-study.md). No target
|
||||
execution or modification occurs.
|
||||
|
||||
## Executed costs
|
||||
|
||||
| Scope | Family wall s | Family CPU s | Kernel peak MiB |
|
||||
| --------------------------- | ------------: | -----------: | --------------: |
|
||||
| Related 82 tests | 20.342 | 13.857 | 93.5 |
|
||||
| Real Code Mode MCP | 103.417 | 78.642 | 713.2 |
|
||||
| Real direct MCP | 42.702 | 42.301 | 725.4 |
|
||||
| Equivalent-query diagnostic | 2.636 | 2.482 | 309.0 |
|
||||
|
||||
One CPU, 4 GiB hard / 3 GiB early-stop bounds apply. All have OOM/kill 0 and
|
||||
verified payload cleanup. Kernel family peak includes charged file cache, not
|
||||
RSS. Code Mode's fresh native capture takes 95.068 wall / 72.758 CPU seconds;
|
||||
direct's takes 39.432 / 39.408. This native/host variation is not a dispatch
|
||||
measurement. The first selected eight-row query takes 61.2 ms / 0.0616 CPU
|
||||
seconds Code Mode, 15.0 ms / 0.0157 direct. The identical same-lease warm query
|
||||
takes 3.2 ms / 0.00384 and 1.8 ms / 0.00242. Paging all triples takes 274.9/224.2
|
||||
ms. Cumulative peaks only upper-bound warm memory. Private native caches are
|
||||
fresh; OS caches and host contention are uncontrolled. Receipts remain local
|
||||
as `controls-{code,direct}-v1*`.
|
||||
|
||||
`profile-controls.mjs` compares baseline
|
||||
`d7d95c7dcc824cc90f63de7a8e2efa2237c53d8f` with the current owner on the same
|
||||
validated retained graph. The complete task returns eight relations for blocks
|
||||
1154/1159 in four two-row pages. Both return identical facts:
|
||||
|
||||
| Core task | Reads | Elapsed ms | Process CPU s |
|
||||
| ----------------------------- | ----: | ---------: | ------------: |
|
||||
| Previous implementation | 4 | 75.33 | 0.0751 |
|
||||
| First indexed task | 4 | 23.33 | 0.0233 |
|
||||
| Identical complete task, warm | 4 | 1.27 | 0.0013 |
|
||||
| Previous, 50 complete tasks | 200 | 420.03 | 0.4174 |
|
||||
| Indexed, 50 complete tasks | 200 | 60.27 | 0.0603 |
|
||||
|
||||
Parsing/validation separately takes 1,013.4 ms / 1.0127 CPU seconds. Order,
|
||||
JIT and caches are uncontrolled within the shared process. This diagnostic
|
||||
excludes fresh native work, MCP discovery/serialization and model tokens;
|
||||
it does not establish a whole-agent speedup or fewer reads/tokens. Source/module
|
||||
hashes and facts are retained in `controls-profile-v1.json`.
|
||||
|
||||
## Real-agent two-level investigation
|
||||
|
||||
The [question and oracle](controller-oracle.md) and runtime were frozen at
|
||||
`8d13c67e7` before either model launch, Code Mode first and direct second.
|
||||
Both complete answers pass the frozen oracle/source review: format ownership,
|
||||
PHI/call binding, both complete controller levels, all four Boolean guards and
|
||||
operand widths/LOADs, exact shared/distinct SSA identities, alternative predicates,
|
||||
valid recovered witnesses, machine corroboration and explicit limits. Both close
|
||||
the lease. The relation list is correctly distinguished from a conjunction.
|
||||
|
||||
Direct chooses longer bypass witnesses than the oracle examples. Every reported
|
||||
edge is valid; both paths end at zero-successor block 1207 and avoid block 1159.
|
||||
Including the initial controller edge, direct uses nine/twelve edges, Code Mode
|
||||
six/six; shortest paths were not required. Both full native function records equal
|
||||
the earlier golden. All thirteen Code Mode and ten direct cited source IDs exist
|
||||
with matching artifact/engine identities. Code Mode's extra pointer/spill facts
|
||||
also match the retained IR and selected GNU decoding. The cost summarizer does
|
||||
not automatically grade natural language.
|
||||
|
||||
| Whole-task measure | Direct atomic | Code Mode |
|
||||
| ------------------------------ | ------------: | --------: |
|
||||
| Cumulative input tokens | 935,185 | 503,113 |
|
||||
| Included cached input | 878,592 | 436,736 |
|
||||
| Uncached input | 56,593 | 66,377 |
|
||||
| Output tokens | 7,320 | 7,450 |
|
||||
| Included reasoning output | 757 | 835 |
|
||||
| Observed model responses | 24 | 17 |
|
||||
| Client executions / waits | 22 / 1 | 15 / 1 |
|
||||
| MCP attempts | 36 | 15 |
|
||||
| Rejected MCP / inner API reads | 0 / 0 | 0 / 0 |
|
||||
| Successful atomic fact reads | 32 | 33 |
|
||||
| Model wall seconds | 230.280 | 246.479 |
|
||||
| Family wall seconds | 230.755 | 248.500 |
|
||||
| Family CPU seconds | 52.458 | 72.837 |
|
||||
| Kernel process-family peak MiB | 876.5 | 944.3 |
|
||||
| Native source-capture wall s | 37.852 | 52.471 |
|
||||
|
||||
Both request `gpt-6.1-sol/high` via Codex 0.161.0, with complete 18/4-tool catalogs
|
||||
and common exact-name/envelope/stopping/long-wait guidance. Actual client calls
|
||||
use JavaScript `exec`/`wait` in both lanes despite false client Code Mode flags.
|
||||
This compares server Code Mode with direct atomic MCP on that host, not
|
||||
composition against its absence. Resolved service build and remote compute are
|
||||
unknown. Per-response usage sums match the ledger; cached input is included in
|
||||
input, reasoning in output. Discovery, schemas, waits and all calls are charged.
|
||||
Runtime, target and engine remain unchanged; both profiles/payloads have verified
|
||||
cleanup, OOM/kill 0 and no resource abort under the same one-CPU / 4 GiB / 3 GiB
|
||||
bounds. No new warm real-agent task was run.
|
||||
|
||||
Both actually query `controllers` at both levels. Neither uses the C tool or
|
||||
fetches the complete raw IR report. Code Mode reads the complete block-successor
|
||||
inventory internally for path search and does extra pointer/spill analysis:
|
||||
fourteen block, six operation and three instruction API reads. Direct uses ten
|
||||
block, five operation, two instruction reads, two bounded slices and more selected
|
||||
CFG reads. Different strategies and native capture times remain confounds;
|
||||
source-capture time is not an isolated native-drive interval and must not be
|
||||
subtracted to manufacture a dispatch-only effect.
|
||||
|
||||
In this single pair, Code Mode reduces cumulative input by about 46% and uses
|
||||
fewer model rounds, but increases uncached input, output, elapsed time, CPU and
|
||||
peak memory. The index's core-query improvement does not establish a causal
|
||||
whole-agent benefit. Correct composable facts support both strategies; there is
|
||||
still no stable overall Code Mode advantage or broad complex-software superiority
|
||||
claim. No traditional-provider cell is invented for this native-identity question.
|
||||
|
||||
Local records: `sqlite-controller-{direct,codemode}-v1*`,
|
||||
`controller-matrix-costs.json` and `controller-answer-checks.json` under
|
||||
`.cache/atomic-codemode/`. `summarize-trials.py` reconstructs costs. Fresh leases
|
||||
and private native caches do not control OS/model-service caches; kernel peaks
|
||||
include charged file cache, not RSS. Scripted warm/core results stay separate.
|
||||
@@ -0,0 +1,108 @@
|
||||
# Two-level recovered controller oracle
|
||||
|
||||
Freeze this oracle and [question](sqlite-controller-question.txt) before model
|
||||
launches. Both lanes get the same question without addresses, native IDs or
|
||||
precomputed paths; this oracle stays outside their isolated workspace. Complete
|
||||
catalogs are eighteen direct tools or four Code Mode tools over the same API.
|
||||
The question requires native identities/derived relations absent from the
|
||||
traditional catalog, so there is no traditional-provider cell or parity claim.
|
||||
Both clients already expose JavaScript dispatch.
|
||||
|
||||
Target: Debian SQLite `3.40.1-2+deb12u2` amd64
|
||||
`/usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6`, SHA-256
|
||||
`2e6eef9a727f081f0d453b4e5e6cbd8b9ef8b6f86cbf7681cbad444d3b0b55c8`.
|
||||
Engine SHA-256:
|
||||
`a9ca8a8ac224936afb08a9d4be9c1225feb69473ad9f35764e8d1c4f04875b5b`.
|
||||
REA was refreshed from main `4838f444939677107902549c59b73439e14d3ae9`
|
||||
before this work. Freeze runtime/HEAD during both runs. Request
|
||||
`gpt-6.1-sol/high`, Codex 0.161.0, common exact-name/envelope/stopping/long-wait
|
||||
guidance, fresh leases/private caches, one CPU and 4 GiB hard / 3 GiB early-stop
|
||||
bounds. Charge all discovery, retries, waits and actual model usage. Preserve
|
||||
native timing variation and incomplete attempts.
|
||||
|
||||
## Formats and first-level controllers
|
||||
|
||||
References select VM entry `0xea6d0`, rather than same-name stub `0x288f0`.
|
||||
Open format `0x12c500` is produced by `0xf2381:712c` in block 1142; release
|
||||
format `0x12c538` by `0xf2437:753c` in block 1158. PHI `0xf238b:ceb7`, output
|
||||
`v100033f25`, binds slots 0/1 to incoming edges `1142:0`/`1158:0`. Shared CALL
|
||||
`0xf238b:7130` in block 1159 takes this format at input 2, with eight-byte
|
||||
`register:0x30` (RSI) passing storage. Target `ram:0x296c0`, native label
|
||||
`sqlite3VdbeError`, does not establish a complete source signature or runtime
|
||||
binding.
|
||||
|
||||
The complete direct controller set of block 1159 is exactly:
|
||||
|
||||
- Block 1141, CBRANCH `0xedc01:7065`: selected `1141:1 -> 1142`, true/ne-zero;
|
||||
other `1141:0 -> 1143`, false/ne-zero. One-byte condition `v100012864` is
|
||||
defined by `0xedc01:7064 INT_SLESS`: slot 0 four-byte zero `v30001285f`,
|
||||
slot 1 four-byte `v100012840` from LOAD `0xedbf8:7056`. Guard: signed loaded32 > 0.
|
||||
- Block 1157, CBRANCH `0xf0389:71b8`: selected `1157:1 -> 1158`, true/ne-zero;
|
||||
other `1157:0 -> 1161`, false/ne-zero. One-byte condition `v100012bd9` is
|
||||
`0xf0384:71b3 INT_EQUAL`: slot 0 four-byte `v10001280a` from LOAD
|
||||
`0xedbe5:7041`, slot 1 four-byte one `v3000393a3`. Guard: loaded32 == 1.
|
||||
|
||||
## Exactly one further level
|
||||
|
||||
- The complete direct set for 1141 is block 1140, CBRANCH `0xedbf2:7054`.
|
||||
Selected `1140:0 -> 1141`, false/ne-zero; other `1140:1 -> 1149`, true/ne-zero.
|
||||
One-byte `v10001282b` is `0xedbf0:704e INT_NOTEQUAL`: slot 0 four-byte
|
||||
`v10001280a`, LOAD `0xedbe5:7041`, slot 1 four-byte zero `v10001282d`.
|
||||
The selected edge negates NOTEQUAL: loaded32 == 0.
|
||||
- The complete direct set for 1157 is block 1156, CBRANCH `0xf0382:71ab`.
|
||||
Selected `1156:1 -> 1157`, true/ne-zero; other `1156:0 -> 1161`, false/ne-zero.
|
||||
One-byte `v100012bc0` is `0xf0382:71aa INT_SLESSEQUAL`: slot 0 four-byte
|
||||
one `v500038ab1`, slot 1 four-byte `v100012b9e`, LOAD `0xf0378:719d`.
|
||||
Guard: signed loaded32 >= 1.
|
||||
|
||||
Open outer and release inner comparisons share exactly `v10001280a` (P).
|
||||
Conjoining their selected predicates would require P == 0 and P == 1. These
|
||||
are alternatives, not simultaneous prerequisites. Locally open combines
|
||||
P == 0 with signed S > 0; release combines signed T >= 1 with P == 1.
|
||||
These are not complete VM-entry path conditions or a demonstrated SQL trigger.
|
||||
|
||||
P, S (`v100012840`) and T (`v100012b9e`) all have unique-space coordinate
|
||||
`0x23d00`/4 but are distinct SSA values. S/T have separate LOAD definitions,
|
||||
even though machine code reads `[R13+0xd8]` in each path. Matching coordinates
|
||||
or memory expressions do not equate contents across reads/paths or solve aliases.
|
||||
|
||||
## Graph witnesses
|
||||
|
||||
Accept any edge-valid witnesses with the required endpoints and omitted block,
|
||||
not only these shortest examples:
|
||||
|
||||
- Selected: `1142 -> 1159`, edge `1142:0`; `1158 -> 1159`, edge `1158:0`.
|
||||
- Open alternative avoiding 1159:
|
||||
`1143 -> 1144 -> 1201 -> 1204 -> 1205 -> 1207`, edges
|
||||
`1143:0, 1144:0, 1201:0, 1204:0, 1205:1`.
|
||||
- Release alternative avoiding 1159:
|
||||
`1161 -> 1162 -> 1163 -> 1164 -> 1205 -> 1207`, edges
|
||||
`1161:1, 1162:1, 1163:1, 1164:0, 1205:1`.
|
||||
|
||||
1207 has zero successors. Check every edge against the retained graph. These
|
||||
finite recovered paths establish neither machine paths, feasible predicates nor
|
||||
termination.
|
||||
|
||||
## Independent machine checks and grading
|
||||
|
||||
ELF64LE PT_LOAD/file reads verify sixteen instruction sites and eight relative
|
||||
targets; GNU decoding corroborates them. Receipt: `controller-machine-oracle.json`
|
||||
locally. Earlier sites are in the [savepoint oracle](savepoint-control-oracle.md).
|
||||
Additional facts:
|
||||
|
||||
- `0xedbf0 85f6` TESTs ESI; `0xedbf2 0f8548270000` is JNE `0xf0340`,
|
||||
zero falls through to `0xedbf8`. Native successor origins are separate metadata.
|
||||
- `0xf0378 458b9dd8000000` loads R11D from `[R13+0xd8]`; `0xf037f 4585db`
|
||||
TESTs it; `0xf0382 7e0b` is signed JLE `0xf038f`, positive falls through
|
||||
to `0xf0384`. Native true/ne-zero here is not machine JLE-taken.
|
||||
- Other guards remain signed JG `0xedc01 -> 0xf2372` and equality JE
|
||||
`0xf0389 -> 0xf242d`; format setups and shared CALL bytes are unchanged.
|
||||
|
||||
The full graph has 21,349 operations, 35,755 values, 1,229 blocks and 2,061 edges.
|
||||
Both actual MCP adapters match all 2,845 control triples against the independent
|
||||
node-removal/exit-reachability oracle, with source fidelity and exact native edge
|
||||
metadata. This is not global machine/IR equivalence. Grade the complete answer
|
||||
and actual calls: both controller levels, all four conditions, shared/distinct
|
||||
SSA identities, valid witnesses, selected machine corroboration, real source
|
||||
IDs/digest and explicit recovered/alias/machine/nontermination/runtime limits.
|
||||
A cheap incomplete/incorrect answer is not an efficiency success. Close the lease.
|
||||
Loaded 100 of 1053 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user