Run the existing README consistency and Python producer guards from their
CI owners. Execute full local validation fresh while preserving cached
preparation, and permit scoped reuse of earlier portable build entries.
Collect failed-shard diagnostics before enforcing success and publish
compact, portable timing history only after a complete successful merge.
Preserve installer truncation failure across supported Bash versions.
Keep cancellation tests focused on the called MCP tool, observe server
progress before timing target readiness, and retain delayed-startup,
cancellation, cleanup, and live follow-up request assertions.
Validation: all 32 CI jobs and the separate Go lane passed; 935 files,
9,630 cases, 9,544 passed, 86 skipped, zero failed. Controlled regressions
and fault/restoration probes are recorded in PR #2210.
Refs #2190.
Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
Keep the former native-ui-and-dispatch-investigation fragment after the
page title was changed in #2207. The old and current fragments resolve to
the same heading position in the generated page.
Validation: VitePress production build, generated-document checks, format
and link checks, and real Chrome navigation to both fragments.
Refs #2156.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
* feat(clients): register Qoder CLI during setup
- SupportedClients: qoder definition (~/.qoder/settings.json, format
json, QODER_CONFIG_DIR override honored)
- Qoder CLI documents mcpServers as the user-scope server table with
command/args/env and stdio as the default transport; no personal
skills directory is documented, so setup skips the skill copy
- tests: qoderClientConfiguration.test.ts (path resolution and
QODER_CONFIG_DIR override, upsert preserving unrelated settings,
fresh/empty configs, uninstall)
Verified: tsc --noEmit clean; vitest run
tests/boundary/filesystem/qoderClientConfiguration.test.ts 6/6.
* fix(clients): install Qoder CLI's personal REA skill
Review follow-up (#1572): the Qoder CLI Skills documentation lists
~/.qoder/skills/{skill-name}/SKILL.md with automatic discovery, so the
definition now carries skillPath following Qoder's configuration
location (QODER_CONFIG_DIR honored) and setup installs the bundled
skill copy there. The installation docs no longer claim Qoder has no
personal skills directory, and the bundled REA skill's supported
client list includes qoder.
Verified: tsc --noEmit clean; vitest run
tests/boundary/filesystem/qoderClientConfiguration.test.ts 7/7.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(clients): register Trae during setup
- SupportedClients: trae definition (VS Code-style user directory,
User/mcp.json, format json)
- Trae documents mcpServers as the top-level server table with
command/args/env and stdio as the default transport; it has no
personal skills directory, so setup skips the skill copy
- tests: traeClientConfiguration.test.ts (per-platform user directory
resolution, upsert preserving unrelated settings, fresh/empty
configs, uninstall)
Verified: tsc --noEmit clean; vitest run
tests/boundary/filesystem/traeClientConfiguration.test.ts 6/6.
* fix(clients): install Trae's personal REA skill
Review follow-up (#1573): the Trae Skills documentation lists global
skills under ~/.trae/skills on macOS/Linux and %userprofile%/.trae/skills
on Windows, so the definition now carries that skillPath and setup
installs the bundled skill copy there. The installation docs no longer
claim Trae has no personal skills directory, and the bundled REA
skill's supported client list includes trae.
Verified: tsc --noEmit clean; vitest run
tests/boundary/filesystem/traeClientConfiguration.test.ts 7/7.
* docs(clients): qualify Trae configuration path evidence
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(clients): register ZCode during setup
- SupportedClients: zcode definition (~/.zcode/cli/config.json, format
zcode, personal skills at ~/.zcode/skills)
- ClientConfigurationDocument: zcode dialect reads/writes the nested
mcp.servers table; withClientServers now tolerates a missing outer
table for fresh documents
- docs: add ZCode to the supported-clients table with configuration notes
- tests: zcodeClientConfiguration.test.ts (path resolution, nested
upsert, fresh/empty configs, uninstall)
Verified: tsc --noEmit clean; vitest run
tests/boundary/filesystem/zcodeClientConfiguration.test.ts 6/6.
* fix(clients): preserve ZCode fallback servers and honor enable flag
Review follow-up (#1564), two integration gaps:
- ZCode reads the user-scope ~/.agents/mcp.json fallback only while the
native .zcode config defines no servers at all, with no merging. Setup
now copies the fallback's mcpServers entries into the native table when
writing the first native server, so registrations that only live in
the fallback keep loading; the fallback file is left untouched. A
malformed fallback fails setup closed (configure and preflight)
instead of being silently suppressed.
- ZCode disables a server with "enable": false on its entry, which the
generic status parsing (disabled/enabled) did not recognize: doctor
reported such a registration as aligned although ZCode never starts
it. The ZCode dialect now treats enable: false as disabled (state
stale) and setup rewrites the entry on rerun.
Docs describe both behaviors; the bundled REA skill's supported client
list includes zcode.
Verified: tsc --noEmit clean; vitest run
tests/boundary/filesystem/zcodeClientConfiguration.test.ts 10/10;
npm run check:fast green; npm run verify:test-discovery 733 files.
* fix(clients): reject non-regular ZCode fallback files before reading
Resolve the fallback through the client-config transaction path and the
regular-file admission before parsing it, so a FIFO or other non-regular
file at ~/.agents/mcp.json fails setup closed instead of blocking the
read indefinitely. Directory and FIFO fallback cases are covered in
tests, and the preflight remediation names unreadable fallbacks too.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(flutter): identify Dart snapshot builds by pure APK parsing
Add a flutter-provider family with one operation, identify_flutter_build,
that reads an APK's lib/<abi>/libapp.so and libflutter.so through the
hardened ZIP reader and reports build facts as observations:
- The Dart VM snapshot hash, read 20 bytes after every snapshot magic
(f5f5dcdc). The vm and isolate sections are cross-checked: agreeing
sections collapse to one snapshot_hash, disagreeing sections keep every
candidate with snapshot_hash null and partial coverage.
- Per-ABI library digests and byte sizes, plus the engine library's GNU
build-id note and any labeled 'Dart VM version' or Android clang/LLVM
toolchain strings, verbatim; release builds without a version string
report null rather than a guess.
- The APK is digested before parsing so Evidence binds the observation to
the exact input, and a target with no libapp.so reports not-detected
with complete coverage.
The scanner is streaming with explicit pending-magic and rescan
bookkeeping, so chunk boundaries cannot double-count or drop sections, and
magic-free streams never accumulate. No engine, no external lookups: the
hash-to-SDK mapping stays with external datasets by design.
Verified against Flutter Gallery 2.9.2 (112 MB, three ABIs): every ABI
reports the same agreeing hash 65817c30a78bb44c3dc3771876b6010a from two
sections, per-ABI build-ids, and the clang toolchain line; a plain
aapt2-built APK reports not-detected with complete coverage. Scanner
goldens come from the same libraries. READMEs carry the new 'Flutter apps'
row in every supported language.
* feat(flutter): inspect Dart AOT snapshots through the ELF symbol table
Add inspect_dart_aot to the flutter family: for one ABI's libapp.so it
locates the four _kDart*Snapshot* symbols through the ELF dynamic symbol
table (ELF32 and ELF64 little-endian, bounds-checked reads; a payload
without exported symbols is refused), reports each section's offset and
size, validates data-section headers (magic, kind, length; instructions
sections honestly report nulls for the fields their layout does not
carry), and projects a bounded string pool from the isolate data section:
distinct package: source URIs (the app's dependency inventory), dart: SDK
URIs, and identifier-shaped tokens, each with counts, bounds, and partial
coverage when truncated.
The string pool is labeled as a byte-pattern projection, not deserialized
cluster semantics: typed class and function recovery remains an
SDK-specific parser, which the snapshot hash now unlocks. The ABI is
caller-selected with a deterministic default (arm64-v8a, x86_64, then
first available).
Verified against Flutter Gallery 2.9.2: all four symbols on both ELF64
(arm64-v8a) and ELF32 (armeabi-v7a) images, header validation, hash
agreement with identify_flutter_build, and a 756 package: / 201 dart:
URI pool from the isolate data section; goldens in DartElf.test.ts come
from the same libraries.
* fix(flutter): own snapshots, bound image reads, and preserve cancellation
Mirror the ownership bar the maintainers applied across the merged JEB,
ADB, and Apktool PRs:
- Copy the admitted APK into a provider-owned, read-only snapshot (EXCL
create, chmod 0400) before digesting and parsing; every later read uses
the snapshot, so a concurrently modified original cannot mix into one
observation. The result reports the snapshot's byte size and digest.
- Retain failed snapshot-root cleanup in a provider set and retry it on
close(), throwing an aggregate error when a root is still owned; root
removal is injectable so the retention is testable.
- Allocate the AOT image buffer at exactly the declared library size
before reading (bounded before allocation, not concat-after-stream),
keep the 256 MiB ceiling, and check cancellation between digest and
stream chunks through a captured abort reason.
- Accept APK paths containing spaces (covered by a fixture test) and
escape the ABI pattern's dash for v-mode regex compatibility.
Also add tests for cleanup retention with close retry and for
cancellation before any snapshot root is created.
* docs(flutter): cover the Italian README with the Flutter row
The Italian translation landed between the merged feature PRs; its table
now carries every merged row plus this one, keeping its documentation-link
set identical to README.md.
* fix(flutter): make the ABI pattern portable for v-mode validators
Use a hex-escaped hyphen in the ABI character class, matching the form
the ADB portability fix uses, so clients compiling advertised schemas in
unicodeSets mode accept the inspect_dart_aot input schema.
* refactor(flutter): reuse shared harnesses and deduplicate the vertical
The duplicate-detection gate (jscpd, 2.5% threshold) tipped to 2.51% with
the flutter files added. Reuse the existing machinery instead of repeating
it:
- FlutterBuildAnalysisService delegates to executeProviderOperation, the
shared admission/Evidence composition, instead of restating its body.
- The CLI registers both commands from one table-driven spec.
- Boundary tests use the shared serveCli and assertAdvertisedMcpContracts
harnesses rather than hand-rolled equivalents.
- The provider test consolidates the four payload-shape cases into one
table-driven case; the service test uses one admission table and
distinct phrasings.
Duplicate lines fall from 2.51% to 2.48%, back under the gate.
* fix(flutter): address review findings from real-app verification
CassieFox23 verified the PR against three real F-Droid Flutter apps and
a control app, and found five gaps. All are fixed and re-verified against
cone (info.tangential.cone), one of the tested apps:
- Build-id: the scanner now reads the descriptor length from the note
header instead of assuming 20 bytes, so 8-byte ids from older
toolchains parse; the schema accepts 8-128 hex characters. Verified
against cone's readelf-reported ids on all three ABIs.
- Compiler line: the toolchain capture bound rises from 200 to 500
characters, keeping cone's 262-character clang line verbatim.
- Zero-byte libapp.so: the extraction target is created before streaming,
so an empty entry yields a clean unsupported_target refusal for
inspect_dart_aot and elf_header_valid: false with partial coverage for
identify_flutter_build, instead of a raw ENOENT with code UNKNOWN.
- Truncated library: identify_flutter_build marks fewer than two snapshot
sections as partial coverage with a limitation naming the count, and a
missing ELF magic gets its own limitation.
- Docs: the default ABI preference now matches the code exactly
(arm64-v8a, x86_64, x86, armeabi-v7a, then the rest alphabetically).
Also: every test that read the author's /tmp/opencode goldens now builds
a self-contained synthetic ELF64 image with dynsym, four snapshot
symbols, two snapshot sections, and a string pool, so the suite runs
anywhere; the verify lane now requires a present hex build-id per ABI
instead of accepting null.
* fix(flutter): address the Codex review findings
Eight findings, all applied:
- P1: SnapshotHashScanner keeps candidates in a Set (no quadratic
Array.includes) with a 64-distinct-hash cap, so a hostile payload of
magic+hash records cannot stall the scan or bloat the response.
- P1: projectStringPool stops admitting new distinct entries once each
category reaches twice its projection bound and reports
collectionCapped; allocation and sorting now track the response, not
the payload.
- P2: ZIP reader rejections during entry iteration or entry streaming
map into the typed error algebra (cancellation vs input refusal)
instead of escaping as unhandled exceptions in both operations.
- P2: magic_valid now marks coverage only for the *Data symbols; a
complete four-symbol image with valid data magics reports complete
coverage (the instruction symbols intentionally lack the magic).
- P2: the MCP server closes the Flutter provider during shutdown, so a
retained snapshot root is retried and reported, not leaked.
- P2: LabeledStringScanner commits matches only when a printable run is
delimiter-terminated; the carry grows to 600 bytes so a 500-character
toolchain line survives any chunk boundary untruncated.
- P2: both Flutter tool effects declare writesFilesystem: true; the
owned APK snapshot and extracted libapp.so are temporary writes.
- P2: the verify lane asserts every ABI agrees on exactly one snapshot
hash instead of discarding the computed set.
* fix(flutter): address the second Codex review round
Nine findings on the first-round fixes:
- P1: identify_flutter_build enforces a cumulative extraction budget
(768 MiB) across every library entry, not just per library, so an APK
with many ABIs cannot stream an unbounded total.
- P1: a single NUL-free printable run stops materializing at 1024 bytes
and marks the pool capped, so an adversarial one-run section cannot
allocate unbounded strings.
- P1: ELF cString bounds the NUL-terminator scan to the name maximum
plus one, so malformed symbol tables cannot scan the whole image per
entry.
- P2: mapReaderFailure distinguishes ArtifactReaderFailure texts —
budget/limit rejections map to resource constraints, integrity
failures (CRC/overlap/signature) to their own input refusal — instead
of collapsing all reader failures into one message.
- P2: the labeled-string carry is cleared when a delimiter commits a
run, so consecutive toolchain lines are never concatenated.
- P2: string-pool counts are renamed *_count_at_least and documented as
lower bounds, because capped collection discards values beyond twice
the projection bound.
- P2: inspect_dart_aot marks hash disagreements, non-pair source counts,
and candidate-cap saturation as partial coverage.
- P2: only valid lowercase-hex hash records count as snapshot sources;
complete magic records with non-hex fields do not inflate agreement.
- P2: the per-entry size refusal in inspect_dart_aot moves after ABI
selection, so an oversized unselected ABI no longer refuses a small
request.
* fix(flutter): address the third Codex review round
Five findings:
- P2: the owned snapshot revalidates the source after the copy (size,
mtime, inode), so an in-place replacement or swap mid-copy refuses
the observation instead of publishing mixed bytes.
- P2: a failed ZipArtifactReader close retains the snapshot root for
close() retry instead of silently swallowing the descriptor leak,
in both operations.
- P2: snapshot headers are parsed within their symbol bounds and a
symbol smaller than the 16-byte header reports magic_valid false,
so trailing-image bytes can no longer fake a valid data section.
- P2: the verify lane counts provider.close() cleanup failures as
lane failures instead of certifying a run with retained roots.
- P2: LabeledStringScanner reports toolchain_capped when further
distinct matching lines are observed past the 4-line projection;
identify marks such results partial with a naming limitation.
* fix(flutter): address rounds three and four of the Codex review
Round three (one missed finding) plus round four (five findings):
- P2: the GNU build-id note descriptor size is decoded from all four
bytes of the little-endian field, rejecting nonzero high bytes
instead of masking them to 16 bits.
- P1: the Flutter MCP handlers route through createContractToolHandler
and the session's analysisAdmission, so close_binary and snapshot
operations drain in-flight Flutter calls instead of racing them.
- P2: the owned-snapshot copy is a streamed, abort-checked write (no
copyFile), so cancellation stops the write promptly while the
source-identity revalidation (size, mtime, inode) still guards
against mid-copy replacement.
- P2: identify marks any snapshot_hash_sources value other than exactly
two as partial, matching the inspection path's pair requirement.
- P2: the verify lane refuses to run without --apk (exit 2) instead of
printing a false-green pass, and the engine check requires every
libapp-carrying ABI to have a present libflutter with a valid hex
build-id rather than filtering missing engines away vacuously.
* fix(flutter): address the fifth Codex review round
Six findings plus the upstream duplication baseline:
- P2: the flutter-provider kind reports available in the capability
inventory, so binary_session no longer lists always-registered
Flutter tools as provider_missing.
- P2: printable runs that exceed the 1024-byte cap are discarded at
their delimiter instead of emitting their truncated prefix as a
fabricated observation.
- P2: ELF symbols must fit inside the file-backed portion of their
PT_LOAD segment (p_filesz), so addresses in gaps or BSS are refused
instead of accepting unrelated bytes.
- P2: the build-id carry spans the complete 80-byte maximum note
(16-byte header + 64-byte descriptor) so chunk-boundary splits
cannot drop the first byte.
- P2: the labeled-string carry is sized for the toolchain pattern's
true 605-byte maximum, not the previous 600.
- P2: the AOT completeness predicate requires exactly two sources and
one candidate unconditionally, so zero-source images with valid data
magics report partial instead of complete.
Also: the shared ELF fixture builder and snapshot-section helper moved
to a dedicated FlutterTestFixtures module, eliminating cross-file test
duplication; jscpd now passes at 2.50% while main sits at 2.52%.
* fix(flutter): address the sixth Codex review round
Five findings:
- P2: snapshot-hash scanning is bounded to the exported data symbols'
byte ranges, so decoy or stale magic/hash sequences elsewhere in the
image cannot inflate source counts or contribute candidates.
- P2: labeled-string runs longer than the carry bound are rejected
instead of truncated, preventing a regex prefix from being published
as a verbatim source string.
- P2: the AOT image reread checks cancellation between file reads and
before the synchronous parsing stage, so a cancelled caller cannot
receive a success from a completed 256 MiB read.
- P2: the verify lane requires exactly two snapshot sources per ABI,
matching the provider's pair requirement, instead of accepting any
count >= 2.
- P2: ELF section and program header entry sizes are validated against
the class-defined minimum widths before walking either table, so
undersized entries cannot cause field reads to cross into
neighboring bytes.
* fix(flutter): address the seventh Codex review round
Six findings:
- P2: data-symbol ranges are deduplicated by offset and size, so aliased
symbols mapping to the same bytes are scanned once and the result
marks partial coverage with a limitation naming the shared range.
- P2: openEntrySafely forwards return/throw to the underlying Readable's
iterator, so an early for-await exit closes the ZIP entry stream and
releases its producer instead of leaking a backpressured pipe.
- P2: inspect_dart_aot now reports snapshot_hash_candidates and
snapshot_hash_sources alongside snapshot_hash, so a null hash from
conflicting evidence is distinguishable from missing hash data.
- P2: overlong printable runs only set toolchain_capped when they begin
with a recognized label prefix (Dart VM version: or Android (); other
long strings such as license text are skipped without marking partial.
- P2: readElfSymbol falls back to PT_DYNAMIC/DT_SYMTAB when section
headers are absent (e_shnum 0, ET_DYN), so stripped Flutter libraries
with exported snapshot symbols are no longer refused; the dynamic
table is bounded by DT_STRSZ, DT_SYMENT, and the image end.
- P2: the verify lane exercises inspect_dart_aot for every ABI carrying
libapp.so, not just the preferred default.
* fix(flutter): address the eighth Codex review round
Five findings:
- P2: each data-symbol range gets a fresh SnapshotHashScanner so the
carry from one noncontiguous slice cannot fabricate a record spanning
into the next; results are aggregated after scanning.
- P2: dynsym name lookups are bounded to the linked string table —
st_name offsets outside the table and terminators beyond it are
rejected instead of reading unrelated payload bytes as symbol names,
in both the section-header and PT_DYNAMIC paths.
- P2: identify_flutter_build routes its reader.entries and reader.open
calls through the same collectEntriesSafely and openEntrySafely
wrappers as inspect_dart_aot, so malformed ZIPs surface as input
refusals instead of AnalysisProtocolError.
- P2: mapReaderFailure recognizes ArtifactReaderFailure texts carrying
a cancelled reason, mapping them to AnalysisCancelledError instead
of AnalysisInputError.
- P2: the cumulative extraction cap is enforced inside the chunk loop,
not after each library completes, so refusal happens before the
remaining bytes are streamed and hashed.
* fix(flutter): harden streaming, sizes, and cancellation after self-review
Four issues found in a systematic self-audit across all bug classes
from eight Codex rounds:
- createReadStream in both the digest function and the owned-snapshot
copy now receives the AbortSignal directly, so cancellation aborts
the filesystem read at the source instead of waiting for the next
chunk to arrive on a slow filesystem.
- The owned snapshot enforces a 2 GiB APK-level size cap before any
copy I/O, so a path pointing at an enormous file is refused before
disk usage grows.
- identify_flutter_build preflights the sum of declared entry sizes
against the 768 MiB cumulative budget, refusing before any ZIP
extraction when the declared total already exceeds it.
- The LabeledStringScanner triple result() call is collapsed to a
single invocation (the previous code called result() three times in
the emission, relying on end() being idempotent).
No behavior change for valid inputs; all 36 tests, check:fast, and
the cone verify lane pass unchanged.
* fix(flutter): require structurally parseable ELF headers for complete coverage
CassieFox23's third corrupt-header case: an ELF with valid magic but
zeroed section/program header offsets passes the 4-byte magic check
and the byte scanner still finds hash patterns in the data sections,
so identify_flutter_build reports complete coverage for a structurally
broken file.
The elf_header_valid check now also verifies beyond the magic:
e_type must be a known value (ET_REL/ET_EXEC/ET_DYN), at least one
of e_shoff/e_phoff must be non-zero, and at least one of
e_shnum/e_phnum must be non-zero. A file with valid magic but zeroed
structure reports partial coverage with the existing ELF-magic
limitation.
* fix(flutter): validate ELF and snapshot coverage
Share bounded ELF header parsing between identification and inspection. Accumulate headers across ZIP chunks and validate table entry widths and extents before claiming complete identification coverage.
Bind AOT hashes to the exported VM and isolate headers, validate stored snapshot lengths including the magic bytes, and preserve partial evidence for missing, malformed, aliased, or overlapping data headers.
Preserve native stream cancellations and APK resource constraints across both operations. Bound snapshot copies while streaming and retain useful input-failure diagnostics and lower-bound count wording.
Validation: 72 focused tests; check:fast; check including formatting; docs:check; test discovery; jscpd; real cone APK and non-Flutter control on Linux. Verified CLI/MCP parity for valid and corrupted ELF headers and AOT inspection across three ABIs. Native Windows and macOS were not run.
* fix(flutter): unify artifact ownership and bound ELF evidence
* fix(flutter): preserve ELF provenance and partial coverage
Read GNU build IDs only from bounded ELF note ranges and retain conflicting candidates. Preserve source versus owned storage failures and honor cancellation through parsing and final cleanup.
Separate snapshot structure from string-pool coverage. Verify every Gallery ABI with digest-bound engine labels and URI counts, and document the supported snapshot-kind layout.
---------
Co-authored-by: REA Contributor <contributor@rea.tools>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Put setup, developer commands, MCP replies, and investigation recipes before
client details and implementation references. Preserve existing guide anchors,
examples, provenance, partial-result recovery, and provider restrictions.
Correct verified documentation drift, synchronize the Ghidra capability
wording, and regenerate metadata for skill version 40. Keep uncertain platform
and lifecycle findings unchanged. Refs #2156.
Validation: 56 focused tests, check:fast, docs:check, VitePress production build,
format and link/example checks. Real isolated CLI/MCP probes cover Ghidra,
NativeAOT, HAR, cancellation, Chrome, large ELF delivery, native type limits,
and the new JS/managed/process/setup recipes. Heavy work uses two CPUs;
a resource-heavy DOM probe was stopped and replaced by a smaller real CDP
payload-limit control. Windows, macOS GUI, ADB, and the full CI matrix were
not executed.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add opt-in retained inventory and WASM Evidence views with exact nested output contracts and a small static WASM descriptor. Preserve old complete CLI/MCP workflows, producer choices, original authenticated Evidence and cleanup ownership.
Validated with real public applications, genuine old Evidence migration, 123 focused assertions, 11 synchronized description checks and 42 installed-package WABT cases. Detailed generated experiment JSON stays outside the final tree; concise findings and reproduction inputs remain. Main-existing completion/package CI failures are separately attributed and left unchanged.
Refs #2016
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
* ci: narrow native-host lane selection and reuse build caches
Unowned src/ and bridge/ files no longer fall back to the full baseline.
They run the Linux suite plus the Linux x64 installed-package/Inspector
baseline. New apple and package scopes own the Apple artifact lane, the
package matrix and the Windows curated lane, including the test files those
lanes invoke. Manual-only verifier entrypoints run static checks and the
Linux suite. CHANGELOG, SECURITY, GitHub templates and the native Windows
README are documentation-only.
Pull requests omit the macOS x64 package host unless labelled ci:full.
The Windows and Apple lanes restore the shared Turbo build cache, the
Windows lane drops its duplicate typecheck, and the Linux suite uses six
shards. Main pushes keep the full baseline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: match package script entrypoints against scope globs
Script-only package.json edits resolved their entrypoint with literal
equality, so glob-owned verifiers such as scripts/verify/apple/** and
scripts/verify/inspector/** fell back to the full baseline instead of
selecting their owning lane.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Use POSIX mkdtemp owner-only allocation directly instead of adding a fallible permission rewrite and rollback before returning the cleanup owner. Respect restrictive umasks, assert privacy and real scratch access, and align provider documentation.
Reuse managed snapshot admission and hashing in sequential path comparisons, retaining caller paths and completed inspection Evidence on later failure. Preserve exact failed-close owners alongside typed read and cancellation failures, and retry them through caller-owned resource scopes. Require canonical Hopper lease identities, remove signed offset coercion, and repair stale setup cleanup expectations that failed CI.
Distinguish an unresolved goal from an exhausted call graph and preserve provider failures through cancellation. Retain completed IDA replies and post-operation identity observations as partial Evidence without claiming a verified final binding. Remove source-wide bundler cache-name heuristics and stale expectations.
Label new captured response bytes as Playwright body API results and retain the possibility of a credentialed follow-up load. Preserve legacy representations and source limitations through export without treating body-origin uncertainty as missing event coverage.
Validated source and filesystem boundary tests plus real Chrome CLI and MCP network workflows covering binary, compressed, empty, unfinished, and same-URL responses and profile cleanup.
* fix(scripts): defer dist/ imports in verifier helpers so test:fast runs without build
Two helpers under scripts/lib/ reached into ../../dist/ at module load even
though the top-level import was only needed by one of their exports. That
turned mocked, dist-free tests into failing tests under `npm run test:fast`,
which docs/testing.md § test scripts explicitly promises runs "without build":
- tests/conformance/providers/hopper/realHopperSemantic.test.ts only calls
requireCurrentDocument and resolveFixtureProcedure (both mock-only), but
scripts/lib/real-hopper-semantic.mjs eagerly imported
requireFunctionDossierOracle from dist/application/RealHopperAssertions.js.
Moved the dist-dependent dossier oracle into a lazy loader called from
verifyRealHopperFixture, which is where it is actually used (against the
real Hopper bridge, after build:cached).
- tests/evaluation/package/packagePlatformDiagnostics.test.ts only uses
assertLinuxPackageProviderFailure, which depends on `json`, but
scripts/lib/verify-package-core.mjs eagerly re-exported helpers from
mcp-verifier-results.mjs, which in turn pulls four dist/ modules. Moved
that import into verifyCompleteToolCatalog (the only consumer in this
file). Downstream scripts (verify-recorded-crash.mjs, verify-package-mcp.mjs,
verify-windows-package.mjs) are unaffected because they already run after
build:cached.
Reproduction before fix:
rm -rf dist && npm run test:fast → 2 failed (both import-time errors)
Reproduction after fix:
rm -rf dist && npm run test:fast → 388 passed, 4924 tests, 0 failed
npm run build:cached && npm run test:fast → 388 passed, 4924 tests, 0 failed
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(install): orient Node.js version mismatch failures with actionable remediation
install.sh previously told operators "use Node.js 22.x (>=22.19), 24.x (>=24.11),
or 26+" without saying how to install one. The curl|bash onboarding path then
left the operator to guess between nvm, fnm, n, Volta, system packages, or
nodejs.org — a lookup that bounces across search engines for a first-time user.
Replace the one-line failure with a block that:
- Names the detected Node.js version (so the operator confirms it is theirs).
- Shows the three most common install paths (nvm, fnm, direct tarball).
- Pins the Node.js release line (24) that satisfies the engine, so copy-paste
commands produce a supported runtime instead of whichever "latest" is on top.
- Maps uname -m / uname -s to the Node.js tarball label pair for this host
(e.g. darwin/arm64, linux/x64), so the operator can grab the right archive
from https://nodejs.org/dist/latest-v24.x/ without a second lookup.
Verified with four Node.js versions (24.18 compatible, 25.9/20.11 outside the
supported ranges, 22.18 below the minor floor) that remediation triggers only
on real mismatches and names the host labels correctly. shellcheck install.sh
and npm run check:fast remain clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Use Android 8-compatible batched find/stat with NUL-framed names and raw symlink targets. Preserve malformed or invalid UTF-8 records as partial evidence with exact source bytes. List hidden direct children without synthetic navigation entries.
Share process byte capture with UTF-8 callers and screenshots, removing duplicate timeout and cancellation supervision. Verified 35 focused process, ADB, CLI and MCP tests; compatibility checked against AOSP Oreo sources. Live Android device/emulator verification was not run.
Keep omitted discovery attachment state as null through Node, browser, Electron, and reconciliation evidence. Report the uncertainty while retaining Node observation unless discovery explicitly marks the target attached. Reject worker TargetInfo records missing the required boolean with partial coverage.
Validate omitted and explicit states through provider, CLI, and MCP boundaries and real Node 24 Inspector workflows. Consolidate Electron regression coverage into the existing list-and-inspect workflow.
BREAKING CHANGE: attached fields in JavaScript runtime, browser, and Electron target discovery and inspection results may be null when discovery does not report attachment state.
Stop cached metadata replay before a provider write starts, including while its reply is pending or fails after applying the mutation. Keep snapshot import and export disabled until the target is reopened.
Validate failed replies, conflicting provider identity, and overlapping reads through the shared session boundary.
Incorporate the independent query-bearing ESM and cjs-only directory cases from #2031 and #2032 into existing Node-backed CLI/MCP tests. Their production patches are already superseded on main.
Make invalid Swift-symbol validation prove it precedes artifact access, and bound the test child so failures retain output before the outer test deadline. Clarify that network API content types project only the type/subtype essence.
Validation: module lookup CLI/MCP and native demangle CLI tests pass. A bounded Flameox reproduction passed in under one second; the CI timeout was not reproduced and no provider hang fix is claimed.
Co-authored-by: hhang <169027046+xu91102@users.noreply.github.com>
Claude Code turns MCP tool search off when ANTHROPIC_BASE_URL points to a
non-first-party host, so every REA tool definition is sent with every
request. On main at 04089d5be the forwarded names, descriptions and input
schemas measure about 496 KB (~120k tokens) with the full profile and about
290 KB (~68k tokens) with the compact profile. When Claude Code assumes a
smaller window than the model has, as with `deepseek-v4-flash` without the
`[1m]` suffix, autocompact thrashes because compaction cannot remove tool
definitions.
Document the window, tool-search and compact-profile remedies, and that
DeepSeek's Anthropic API does not list `tool_reference` blocks.
Refs #2019
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(go): inspect embedded binary build metadata
* fix(go): preserve byte metadata and validate container mappings
* fix(go): support moduleless legacy build metadata
Recognize optional module string headers in declared zero-filled memory while rejecting ambiguous and unmapped pointers. Preserve the original module-pointer field as the zero-byte source anchor.
Classify initial symlink-loop and overlong-path failures as invalid input, with CLI and MCP regressions.
* fix(go): reject undersized PE optional headers
* fix(native): stabilize ELF memory checks and clean up exec wrappers
Use existing parent/group/run-token ownership for caller-selected Python launchers, which can exec through a shell or prlimit. Add cancellation regressions for the valid wrapper and wrong-parent/token cases.
Replace the timing-dependent 30,000-section memory workload with a valid 32 MiB padded ELF under a 64 MiB address-space limit. Check the same image successfully through CLI and MCP before requiring a typed memory failure, preserving the production timeout and all error assertions.
Validation: npm run check and check:fast passed; 61 focused tests passed including Go CLI/MCP and session snapshots. Real decoder probes with pinned packages passed on Python 3.12.3 and 3.12.14. The full local ELF verifier is blocked by this container's procps/process-ownership boundary; the exact pushed head requires GitHub's real-binary-layout lane.
* test: repair Electron fixtures and stabilize catalog startup checks
Declare Electron imports in option, preload override, and path-resolution fixtures after upstream began requiring proven API provenance. Retain all option and preload assertions and adjust exact source ranges for the added import line.
Use the existing bounded acceptance timeout for the cold catalog lifecycle test instead of a separate 15-second ceiling. This retains the coverage allowance and all catalog, error, and cleanup assertions without retries.
Validation: npm run check, final check:fast, formatting and diff checks passed. Source path regression and Go boundary/MCP/service checks passed. All 20 Go CLI cases and both supported-host runtime cases passed on rerun; two macOS-only cases skipped on Linux. A prior contended local run timed out once in a Go CLI diagnostic; that case passed on rerun. Electron process-boundary verification is blocked locally by procps namespace inspection and requires fresh CI.
* test(mcp): isolate nested schema references between tool contracts
Clear Ajv's non-meta schema registry after each root, including compilation failures. Disabling root registration alone leaves nested IDs available to later tools and can let a dangling reference pass the catalog gate.
Add regressions for leakage after successful and failed compilation while retaining shared meta-schema validators. The regression failed before the fix; all 11 schema cases and full npm run check pass. Reviewed independently.
* test(ci): align Go effects and source-map verification contracts
Audit the Go inspector wording as static metadata inspection. Assert retained source declaration indexes in BOM reconstruction and the compiler-derived nested-map oracle. Keep a 45,000-map admission control below the 32 MiB output budget and the 50,000-map overflow case above it with the expanded representation.
Validation: reproduced all four failing assertions, then passed 120 focused tests and the final admission suite. npm run check and real Chrome 154 / esbuild 0.25.10 source-map verification passed, including all four nested-map scenarios and verified process lineage.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(setup): register DeepSeek Harness through setup, doctor and uninstall
DeepSeek Harness registers MCP clients through a Cordis YAML patch
sequence in the home patch rather than a server table, so setup could
not configure it and users had to append the documented entry by hand.
Add a dsh client: the home patch $DSH_HOME/cordis.patch.yml
(~/.dsh/cordis.patch.yml when unset) is parsed as a patch list, the REA
entry owns the stable rea-mcp id, and setup appends or replaces exactly
that entry while preserving unrelated patches and comments in place.
Doctor reports the registration through the same entry, and uninstall
removes it, dropping insert operations it emptied. Skill destinations
follow ~/.agents/skills ($DSH_AGENTS_HOME/skills when configured), the
home the rest of the client machinery already uses.
Fixes#1839
* fix(setup): carry environment and identity validation into DSH registrations
Address review: the DSH entry discarded discovered provider overrides;
config.env is now emitted and retained like the other dialects. An entry
carrying the rea-mcp id under a wrong or missing package name, or
duplicated entries, reads back as absent so setup rewrites exactly one
canonical entry instead of reporting unchanged. Doctor now requires
serverName rea and stdio transport before calling a DSH registration
aligned, and the Harness skill identifier in the docs matches the
installed reverse-engineer-anything skill.
* fix(setup): apply Cordis patch order and collapse DSH registrations
Address review: a later direct { id, config } operation replaces the
row's config under the native patch DSL, so the registration view now
applies patches in order instead of only reading insert operations;
doctor reports the effective command rather than the inserted one.
Setup rewrites exactly one canonical entry: duplicate id-matching rows
collapse to the first, direct patches to the entry are dropped from the
document and from the edited YAML, and uninstall removes them with the
entry. The client-location test fixture now clears DSH_HOME and
DSH_AGENTS_HOME so a developer environment cannot point the suite at
real Harness homes.
* fix(setup): repair direct-only registrations and preserve Cordis entry state
Serialize now edits the first insertion carrying rea-mcp in place, so a
grouped entry keeps its scope, neighbors, and comments instead of moving
to a fresh root-level insertion, and later carrying insertions and direct
patches collapse away. Entry-level disabled state projects into the
registration the doctor and setup compare, so a disabled row reads as
stale and the repair re-enables it. A direct-only registration no longer
suppresses the canonical insert append, and an update retains the
registration environment. Duplicate entries collapse across operations,
not only within one.
* fix(setup): preserve Harness row state through identity and refresh repairs
A wrong-package row still reads back as a server record carrying its
environment and caller fields, projected with a package marker the
alignment path treats as stale, instead of vanishing and dropping
config.env from the repair. A direct Cordis patch without a preceding
insertion configures nothing, so a direct-only registration reads as
absent even when its config matches and the repair appends the insert.
Caller-owned config fields beyond the REA-owned keys, such as the cwd
the native verifier sets, survive a refresh instead of being silently
dropped.
* fix(setup): preserve Cordis tags and collapse aligned Harness rows
A refresh rebuilt Harness config from parsed values, so a caller !!js
expression was written back as a literal. Owned keys are now overlaid on
the winning config node and other nodes stay in place. Two already-aligned
rea-mcp insertions read as stale, so setup collapses them to one row, and
the bundled skill lists dsh with the other clients.
* fix(setup): drop the unused DSH configuration type
Knip reports DshConfigurationFormat as an unused export. The format union
does not depend on that alias.
* fix(setup): keep Harness env tags and comment-only patches
A refresh replaced the whole env map, so a caller !!js value was written
back as a literal. Environment entries now stay in place unless the value
changed. A comment-only cordis.patch.yml parses as an empty patch list and
keeps those comments when the registration is appended. Docs describe
plain rea uninstall, which scans supported clients and has no --client flag.
* fix(setup): own Harness rows by entry id and expression state
Uninstall removes a rea-mcp row even when the launcher is stale or the
patch never established a server record. A non-boolean disabled value,
including a Cordis expression, reads as stale. Expression text on a known
environment setting is not validated as a literal path, so a refresh can
keep the tag.
* fix(setup): collapse aliased Harness insertions
An anchored insert followed by an alias parses as two rea-mcp rows, but
the YAML edit kept the alias, so readback stayed duplicated and setup
restored the file. Aliases that resolve to the owned entry are now
dropped, including an alias of the entry inside one insert. Aliases of
other patches stay.
* fix(setup): resolve aliased Harness lists and config maps
An insert value that aliases another entry list still loaded a second
rea-mcp row after the operation-level alias collapse. That alias is now
dropped once the anchored list is rewritten. A config: *cfg map is
resolved and cloned before the refresh, so a caller !!js field on the
aliased map is not rewritten as a plain literal.
* fix(setup): follow Harness aliases for ids, lists, and env tags
An insert alias whose anchor is not another insert is copied so
unrelated rows stay while the owned row is rewritten. An aliased
entry id is resolved before ownership checks, and an environment alias
of an unchanged !!js scalar is left in place.
* fix(setup): keep aliased Harness env maps through uninstall
An env alias is cloned before a refresh so tagged values are not rebuilt
as literals, and expression-key scans follow aliases before path checks.
Insert aliases that carry REA are recorded before uninstall empties their
anchor, so the later alias is dropped instead of dangling.
* fix(setup): follow root Harness aliases and mark dsh as main-only
Winning-config walks resolve a root alias before patch order, so a replayed direct config's !!js env is not validated as a literal path. Root aliases that own rea-mcp are recorded before uninstall empties their anchor. An insert whose only owned member is an external alias is cloned so Cordis tags survive. Docs state dsh is not in npm 6.4.0.
* fix(setup): keep rows behind inert Harness aliases
A root alias whose anchor is not a loaded operation is copied and only the owned row is edited, so unrelated rows stay active. Entry id aliases become a scalar before their anchor patch is dropped. Root-alias ownership follows insert-list aliases, so a replay is removed instead of dangling after uninstall.
* refactor(setup): centralize Cordis source ownership
* fix(javascript): share Electron mutation proof with wrapped calls
* test(mcp): align graph and catalog checks with current contracts
* fix(setup): separate Cordis ownership from editability
* docs: clarify ownership and interpretation boundaries
* fix(setup): preserve Cordis applicability and caller metadata
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* test(clients): verify native Gemini CLI integration on Windows
The Gemini CLI client lane asserted POSIX. On Windows it also needs the npm install's JavaScript entry point, because only a gemini.cmd shim reaches PATH, and two setup-plan checks compared paths with a hard-coded slash. Remove the assertion, run a selected .js, .mjs or .cjs entry point under the verifier's Node, build those prefixes with path.sep, name the entry point in the Windows preflight error, and record 0.63.0 as verified on native Windows in docs/testing.md.
Fixes#1935
* test(clients): resolve the selected Gemini CLI entry point once
The preflight runs from the caller's directory and the client run from the disposable workspace, so a relative REA_VERIFY_GEMINI_COMMAND passed the preflight and then failed with Cannot find module. Resolve a selected JavaScript entry point to an absolute path before both launches.
* feat(mcp): derive an API surface view from retained web network captures
* fix(mcp): fail closed on sensitive parents and budget api-surface path expansion
* fix(mcp): keep recorded api-surface paths and budget only templated segments
* fix(mcp): read api-surface paths only from canonical URLs and charge new values once
* fix(mcp): reject authority-less api-surface URLs and key groups by rule positions
* fix(mcp): label api-surface confidence from all groups and cap transient path memory
* fix(mcp): budget api-surface dedup sets and narrow detail outputs
Charge retained deduplication sets before allocation, advertise only
each analysis operation's summary from its detail output, and document
that any templated group makes every API-surface page inferred.
* fix(mcp): bound api-surface path text and record limitations
Charge retained literal path copies before allocation, publish only
valid media-type essences, and deduplicate examined record limitations
onto the view.
* fix(mcp): keep api-surface refusals and path splits inside the reply budget
Sensitive-parent refusals now use the token sensitive_values_unretained so declared literals are not echoed. A later path split is charged against bytes already retained, and the published example includes the HAR record limitation with its matching digest.
* fix(mcp): budget api-surface method text before group keys
Charge method and origin text against the reply budget before the group key is serialized. Document that samples merge only when method, origin, and exact segment rules match.
* fix(mcp): bound api-surface copies and control-character authorities
Reject authorities containing a tab or newline so WHATWG cannot move userinfo into the recorded path. Charge four path copies, two method and origin copies, and each distinct content type against bytes already retained.
* fix(mcp): preflight combined api-surface group charges
Total path, method, origin, and segment charges before retaining a new group. Track content types in a set so distinct MIME essences are not compared quadratically.
* fix(mcp): charge api-surface content-type sets on first use
Create the per-group content-type set when the first essence is retained, and charge it before allocation. Groups with no content type no longer keep an empty set.
* refactor(analysis): centralize API-surface ownership and admission
Own grouping, deduplication, and combined retained/temporary resource admission in one accumulator. Charge fixed group storage before allocation and materialize only the requested page.
Share recorded URL parsing between capture redaction and projection, preserving source paths and excluding ambiguous credential fields. Cover resource admission invariants and the compiled HAR-to-view workflow.
* fix(analysis): admit capture schema clone before parsing
* fix(javascript): share Electron mutation proof with wrapped calls
* test(mcp): align graph and catalog checks with current contracts
* fix(analysis): admit and validate portable capture views
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Return deduplicated execution caveats once and preserve provider-owned relationship diagnostics and completeness on graph nodes. Keep complete relationship reads exhaustive despite contextual caveats, including portable call-path reconstruction.
Preserve omitted diagnostic fields in historical Evidence and bind reported diagnostics into semantic identity. Revise graph workflow and Ghidra adapter profiles so old cached representations cannot replay under the new contracts.
Remove stale duplicate-lookup test claims and redundant fixture validation. Prune million-entry duplicate cases while retaining argument-stack and deep-chain regressions; bounded Flameox captures identified validation and canonical hashing costs.
Validation: static and architecture checks, generated docs, 364 focused tests before pruning, 21 call-path tests after pruning, public MCP schema validation and targeted profile tests. Real engine behavior was not locally exercised.
BREAKING CHANGE: get_call_graph normalized_result now contains { graph, limitations }; traversal-depth groups are under graph.
Keep FAT container format distinct from selected slice architecture through target admission, Evidence, snapshots, and CLI/MCP lifecycle results. Preserve native, Hopper, Ghidra, extraction, and dylib routing for the Mach-O family.
Reject selected FAT ranges overlapping their table or too short for a Mach-O header. Replace empty-slice fixtures with in-bounds executable headers and cover thin, universal, single-slice, FAT64, and swapped containers.
Validation: static and architecture checks, generated docs, targeted producer and public MCP tests. Provider routing uses controlled fixtures; no live Hopper, IDA, JADX, or Ghidra analysis was performed for this change.
Parse otool field occurrences once and reject valueless required fields while retaining empty dylib options. Preserve compiler exit outcomes and stderr through capture errors and nested Ghidra causes, with explicit UTF-8 truncation after redaction.
Strengthen provider failure assertions and document the manual Ghidra 12.1.4 macOS x64 decompiler build using upstream instructions.
Validation: focused producer tests, nine fake-compiler preparation and cancellation tests, temporary-directory hygiene, static and documentation checks. No real Swift or Ghidra compilation was run locally.
* test(ghidra): require pending multi-HI16 coverage in the real MIPS relocatable lane
Post-merge review on #1950: the relocation oracle exposes coverage.multiple_hi16, but the real-Ghidra lane never required it, and Clang's C output never produces a LO16 that resolves several pending HI16s. Ghidra's loader could therefore mishandle that stream while the lane still passed, although most GCC-built kernel modules checked contain it.
The relocatable fixture adds an assembly block with two lui %hi(rea_mips_rel_carry); LLVM's relocation sort then leaves one HI16 pending until a later LO16 that resolves it together with another HI16, including the carry. The lane now requires multiple_hi16: false on the previous fixture, true for all three variants (LE, BE, soft-float module) on real Ghidra 12.1.4.
* test(ghidra): make the MIPS multi-HI16 fixture independent of relocation sorting
Review on #1974: the block used two %lo of rea_mips_rel_carry, a symbol with other %lo uses, so the relocation stream depended on the assembler's HI16/LO16 sort. Clang 21 happened to leave a HI16 pending; Clang 17 (per review) and GNU as 2.45 (checked here: HI@4 LO@8 HI@0 LO@10) pair each HI16 with its own LO16, so multiple_hi16 stays false and the lane fails.
Use a dedicated symbol with two %hi and exactly one %lo. Any assembler that orders each HI16 before a matching LO16 must then emit both HI16s ahead of that single LO16: Clang 21 gives HI@0 HI@4 LO@8, GNU as 2.45 gives HI@4 HI@0 LO@8. The real-Ghidra lane passes for LE, BE and the soft-float module variant with multiple_hi16 true.
Select exact declaring types before managed signatures and CIL bodies are decoded, preserving caller choices in CLI/MCP Evidence. Keep unmatched names and selected coverage explicit; comparisons and graphs retain unknowns outside their observed scope. Reuse existing metadata ownership/accounting and advertise unique selections through the actual SDK Schema.
Validated with 229 focused tests across 21 files, 11 managed conformance controls, fullstatic/docs checks and real Linux CLI and fresh MCP inspection of two unchanged DLLs. All 118 selected CIL hashes matched original PE-mapped bytes; result/caller-argument parity and unmatched controls passed. Full artifact/native-boundary metadata is complete; whole-assembly members retain the unchanged 64 MiB resource constraint. No target code executes.
Refs #1878
Co-authored-by: skared <190618464+skoodster@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Ysopwnable <161784452+N0zoM1z0@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Group repeated session tool availability and provider capability facts, preserve complete named contracts and ordered limitations, and remove duplicate catalog descriptors. Update consumers and migration guidance.
Validated by all 31 CI jobs, focused source checks, and actual Claude Code/Linux Hopper/native Windows Ghidra small-target workflows on the current integration tree.
Refs #723.
BREAKING CHANGE: binary_session no longer includes server_identity.catalog.tools; tool_availability and provider capabilities use grouped facts documented in docs/mcp-contracts.md.
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Give atomic Evidence and snapshot writes an explicit resource owner, preserve primary failures and completed publication receipts, and retry retained staging cleanup at the owning lifecycle. Verify inode identity before publishing or deleting; unknown path disappearance remains a cleanup failure. Keep snapshot admission reusable when a session closes and reopens.
Consolidate JavaScript source-scope classification so cancellation cannot fabricate failures for unselected files. Classify configuration failures as invalid input. Remove stale assertions and reuse shared test cleanup ownership.
Validation: 266 focused tests before final ownership tightening, 108 affected tests afterward, static and documentation checks, actual invalid-configuration CLI behavior, and isolated test temporary-directory hygiene.
Refs #1968
Expose the selected Mach-O slice and its container offset, derive that identity once, and map entrypoint and nonempty segment Evidence to container coordinates. Reject relocation sections whose byte length is not divisible by the entry size instead of silently accepting a floored count.
Validation: native parser and selected-architecture boundaries, actual public CLI and stdio MCP on a compiled universal Mach-O, and a pyelftools 0.33 malformed-table probe. Full Linux pwntools bridge verification was unavailable on this host.
Refs #1973
Parse Apktool YAML and XML at the producer boundary, preserving scalar spelling, XML text and partial string coverage. Retain repeated JADX inventory rows with explicit duplicate-name counts and lookup ambiguity. Make the Apktool verifier report cleanup failures.
Validation: parser, provider and JADX fixture boundary tests; typecheck, lint and documentation checks. Real Apktool and JADX engines were not exercised.
Refs #1978
Interpret device paths once as POSIX paths and apply only the selected host's filename constraints. Preserve original PM paths and diagnostics, reject duplicate destinations before pulls, and use exact-name filesystem reservations to detect case and Unicode aliases without guessing volume rules.
Consolidate failed-package cleanup ownership and strengthen no-output assertions. Validated 44 provider fixture tests, 47 filename/parser tests, six compiled CLI tests, static/docs checks, and package checks. No Android hardware was used.
Separate observed relationship coverage from general provider caveats. Authenticate and replay coverage without changing legacy Evidence IDs; expose unknown and capped relationship sets through CLI/MCP graphs and traces.
Validated focused domain, snapshot, IDA/Ghidra boundary, MCP, schema, package and static checks. Provider fixtures establish contract behavior; licensed engine behavior was not reverified.
* fix(wasm): preserve debug module names in WABT output
* fix(native): accept otool dylib-use options
Preserve modern dylib options while requiring one encoding metadata row and retaining duplicate and multiline-output checks. Share field parsing between preservation and validation.
Verify delayed dylibs through real macOS CLI/MCP workflows and refresh the high-address golden with the provider's -h -l capture. Validated 85 focused native tests, npm run check, and verify:macos-bundle on macOS arm64.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
pull_adb_file derived its host file name from the last path segment of a
caller-supplied device path and joined it to the output directory without
checking that the name is usable on the host. A device path ending in a
separator, a dot segment, a control character, a Windows reserved device
name, a trailing dot or space, or a ':' alternate-data-stream marker could
resolve to an unexpected host path or fail opaquely after the transfer.
The single-file path now derives the name with POSIX semantics and refuses
any non-portable segment as invalid_request before creating a directory or
running adb pull. This matches the package path's pending host-name policy
and never renames a device-reported file.
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(wasm): accept unpadded WABT section rows
WABT 1.0.42 right-aligns section names in a nine-column field. DataCount
fills that field, so its objdump row has no leading whitespace. Accept
that legal row. Header recognition, the required field shape, and section
range checks still reject malformed output.
Fixes#1956
* fix(ci): refresh MIPS expectations and Windows test paths
Assert admitted soft-float ABI metadata and its committed storage policy through the public target resolver, retain FP64 rejection, and point the curated Windows lane at the moved filesystem reconstruction tests.
Validation: reproduced all four prior failures; 97 focused tests and check:ci pass. Native Windows and real Ghidra execution were not performed locally.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(ghidra): admit soft-float MIPS32r2 ELF with integer-register float storage
Soft-float o32 executables (Linux kernel builds, bare-metal firmware) were
refused because their ABI flags record declares no CPR1 and FP ABI 3.
Ghidra's MIPS32 compiler specifications model only hard-float o32, so typed
float/double signatures (DWARF) would be bound to $f12/$f14/$f0 and the
decompiler loses the real dataflow: `return sel ? a : b` decompiled to
`return in_f0;`, and callers passed phantom FPU inputs.
Admit ELF32 ET_EXEC o32 MIPS32r2 targets whose ABI record declares soft-float
with no CPR1, and commit `mips_soft_float_storage: o32-integer-registers-v1`
in their analysis profile only (hard-float profile digests are unchanged).
ReaGhidraMipsSoftFloat.java runs after auto-analysis and, for each function
with a float/double formal type, either keeps the types with the storage
Ghidra's o32 model assigns to a same-size integer (pair alignment, stack
spill), or, for auto-parameters such as hidden struct-return pointers, swaps
float types for same-size integers under dynamic storage. No function is left
on hard-float storage. The report is written last; the provider client
requires it exactly when the profile commits the policy and refuses the
session before any operation otherwise.
Verification: real Ghidra 12.1.4 lane (verify:ghidra:mips) now builds
hard- and soft-float fixtures in both byte orders and checks exact
parameter/return storage through inspect_native_api, caller constants,
snapshot profile and Evidence outcome; test:fast, verify:package and an
installed-tarball soft-float run pass.
* fix(ghidra): model soft-float MIPS as a prototype for every typed callable
Review feedback on #1949: rewriting storage per Function left external
functions and indirect calls through typed function pointers on Ghidra's
hard-float o32 prototype, which still read $f12/$f14/$f0 while the session
reported success. A negative control confirms it: without the change,
`(*rea_mips_soft_callback)(8.5f, 9.5f, sel)` decompiles to
`(*rea_mips_soft_callback)(in_f12, in_f14, sel)`.
ReaGhidraMipsSoftFloat.java now derives a `__rea_soft_float` prototype from
the program's own default o32 model (encoded, float pentries and
float-consuming rules removed, so byte-order-specific aggregate rules and the
hidden struct-return pointer are kept), installs it as a specification
extension, and assigns it with dynamic storage to every non-thunk function,
external function and function-pointer definition whose formal types use
float or double. Thunks follow their targets. Float types are kept
everywhere, so the integer-retype fallback is removed. The script fails
without writing its report if the derived prototype or any reassigned
function still uses an FPU register.
The policy becomes `o32-soft-float-prototype-v1` with a
{functions, definitions} report. The soft-float fixture adds an indirect
call through a typed pointer; the real-Ghidra lane requires its constants
with no FPU inputs and the struct return's `float scale` in $a1.
* test(ghidra): pin ODDSPREG acceptance for soft-float MIPS ABI records
Review on #1949 suggested requiring flags1 == 0 for soft-float, since MIPS_AFL_FLAGS1_ODDSPREG names CPR1 registers. GCC 5.2 kernel modules, LLVM/Rust firmware and Clang -msoft-float objects all record flags1 = 1 with FP ABI soft-float: it is the MIPS32 o32 toolchain default and selects nothing without CPR1. Keep accepting it, say why at the check, and test that soft-float with ODDSPREG is admitted while any other general flag is refused.
* feat(ghidra): admit relocatable MIPS32r2 ELF objects
Linux MIPS kernel modules (.ko) and other ELF32 o32 MIPS32r2 ET_REL objects
were refused by the Ghidra MIPS lane. Ghidra's ELF loader already places each
allocated section and applies REL relocations; this admits ET_REL alongside
ET_EXEC (ET_DYN and PRX stay refused) under its own support lane,
`elf32-rel-o32-arch32r2-standard-v1`, so executable targets keep theirs.
Relocatable sessions carry limitations: addresses are analysis coordinates,
undefined symbols live in Ghidra's EXTERNAL block, and HI16 relocations report
PARTIAL because Ghidra applies them with their paired LO16.
Verification: new `verify:ghidra:mips-relocatable` real-Ghidra lane builds
-c -G0 objects in both byte orders plus a soft-float -mlong-calls module
variant. GNU readelf supplies sections, symbols and REL entries; every
relocation in an allocated section must encode S + A in the loaded word
(S from Ghidra placement, A from original bytes), with HI16/LO16 checked as
the effective address each LO16 forms, and coverage of a shared HI16, a LO16
carry, external code/data and R_MIPS_32 is asserted. The executable lane,
unit suites pass, and on 30 real .ko files 54,972 relocations matched (93 reference empty sections and are not checkable).
* fix(ghidra): verify every MIPS HI16 and archive-typed soft-float externals
Review feedback on #1950:
- The relocation oracle kept one pending HI16, so a second HI16 before the
LO16 that resolves both overwrote the first, and unrelated relocations
cleared it; the earlier site's high half and carry were never compared
with S + A. Every HI16 now waits for the next LO16 of its symbol, which
checks all of them; later LO16s reuse those HI16s, and a HI16 left
unresolved at a section end fails. On 30 real soft-float kernel modules,
24 contain several HI16s per LO16; all 54,972 placed relocations match.
- External callees with float prototypes: the relocatable fixture now calls
powf, whose prototype Ghidra's C library archive applies by name. Every
variant must decompile `powf(1.5,2.5)` without FPU inputs, and the
soft-float module variant must report that __rea_soft_float covered it
(with the external step removed it decompiles as `powf(param_1,param_2)`).
`-fno-builtin` keeps the call from being folded.
Also updates the module variant's expected soft-float policy to
`o32-soft-float-prototype-v1`.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(ghidra): admit soft-float MIPS32r2 ELF with integer-register float storage
Soft-float o32 executables (Linux kernel builds, bare-metal firmware) were
refused because their ABI flags record declares no CPR1 and FP ABI 3.
Ghidra's MIPS32 compiler specifications model only hard-float o32, so typed
float/double signatures (DWARF) would be bound to $f12/$f14/$f0 and the
decompiler loses the real dataflow: `return sel ? a : b` decompiled to
`return in_f0;`, and callers passed phantom FPU inputs.
Admit ELF32 ET_EXEC o32 MIPS32r2 targets whose ABI record declares soft-float
with no CPR1, and commit `mips_soft_float_storage: o32-integer-registers-v1`
in their analysis profile only (hard-float profile digests are unchanged).
ReaGhidraMipsSoftFloat.java runs after auto-analysis and, for each function
with a float/double formal type, either keeps the types with the storage
Ghidra's o32 model assigns to a same-size integer (pair alignment, stack
spill), or, for auto-parameters such as hidden struct-return pointers, swaps
float types for same-size integers under dynamic storage. No function is left
on hard-float storage. The report is written last; the provider client
requires it exactly when the profile commits the policy and refuses the
session before any operation otherwise.
Verification: real Ghidra 12.1.4 lane (verify:ghidra:mips) now builds
hard- and soft-float fixtures in both byte orders and checks exact
parameter/return storage through inspect_native_api, caller constants,
snapshot profile and Evidence outcome; test:fast, verify:package and an
installed-tarball soft-float run pass.
* fix(ghidra): model soft-float MIPS as a prototype for every typed callable
Review feedback on #1949: rewriting storage per Function left external
functions and indirect calls through typed function pointers on Ghidra's
hard-float o32 prototype, which still read $f12/$f14/$f0 while the session
reported success. A negative control confirms it: without the change,
`(*rea_mips_soft_callback)(8.5f, 9.5f, sel)` decompiles to
`(*rea_mips_soft_callback)(in_f12, in_f14, sel)`.
ReaGhidraMipsSoftFloat.java now derives a `__rea_soft_float` prototype from
the program's own default o32 model (encoded, float pentries and
float-consuming rules removed, so byte-order-specific aggregate rules and the
hidden struct-return pointer are kept), installs it as a specification
extension, and assigns it with dynamic storage to every non-thunk function,
external function and function-pointer definition whose formal types use
float or double. Thunks follow their targets. Float types are kept
everywhere, so the integer-retype fallback is removed. The script fails
without writing its report if the derived prototype or any reassigned
function still uses an FPU register.
The policy becomes `o32-soft-float-prototype-v1` with a
{functions, definitions} report. The soft-float fixture adds an indirect
call through a typed pointer; the real-Ghidra lane requires its constants
with no FPU inputs and the struct return's `float scale` in $a1.
* test(ghidra): pin ODDSPREG acceptance for soft-float MIPS ABI records
Review on #1949 suggested requiring flags1 == 0 for soft-float, since MIPS_AFL_FLAGS1_ODDSPREG names CPR1 registers. GCC 5.2 kernel modules, LLVM/Rust firmware and Clang -msoft-float objects all record flags1 = 1 with FP ABI soft-float: it is the MIPS32 o32 toolchain default and selects nothing without CPR1. Keep accepting it, say why at the check, and test that soft-float with ODDSPREG is admitted while any other general flag is refused.
Supply schema-validated inspect_analysis_view arguments after completed native function Evidence is recorded and exceeds MCP delivery capacity. Preserve the full canonical result and its provenance. Verify exact source paging, export and following-call usability through real Ghidra stdio MCP.
Fixes#1849
Co-authored-by: Minghang Chamling <133689405+cold-atom@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
* test(ida): expect callee edges from the call graph on non-x86 targets
* fix(ida): read callee edges from the call graph on non-x86 targets
* test(ida): pin address order of call graph additions
* docs(ida): describe the call graph source for non-x86 callees
* test(ida): pin the x86 baseline, the call graph reader and its failure modes
* fix(ida): check the call graph root, scope truncation to the root and degrade without callgraph
* test(ida): expect managed PE off the x86 path, possible-truncation wording and a complete ARM64 traversal
* fix(ida): keep managed PE and x86 reads off the call graph path and qualify truncation
* test(ida): answer only expected leaf roots and assert the requested call graph roots
* test(ida): expect a call graph the producer cannot give consistently to fail the callee read
* fix(ida): fail the callee read when the call graph cannot be obtained consistently
* fix(ida): preserve call edge authority and workflow uncertainty
* fix(ida): preserve explicit root call graph caps
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Analyze exact selected sources in first-request order before unrelated
static scopes, preserving full artifact identity and byte verification.
Retain selection in CLI/MCP Evidence and summaries, with explicit unknowns
and partial coverage for unselected sources. Keep default full analysis.
Fixes#1848
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>