Indent the optional language selector with its value so a nonindexable draft does not generate a line containing only spaces. Indexed-page markup is unchanged.
Validation: website.py check passes all 12 maintenance regressions; synchronization changes only the draft header blank line.
Select SQLite compatibility by explicit source, fixture, lifecycle, and script ownership while retaining every version in full qualification. Share the canonical scope inventory between planning and the required gate.
Reuse recent exact-SHA full qualification only for hourly schedules, with trusted successful-run metadata and receipts. Force a daily refresh, reject stale original runs even after retries, and never renew proof from reused validation.
Report attempt-specific queue, execution, and matched step timing in a separate completion workflow using trusted default-branch code and read-only API access. Preserve raw metadata and unknown timings without delaying validation or publication.
Validation: 177 focused tests; typecheck/lint; knip; actionlint 1.7.7; all 1046 tests discovered; live 37-job API report smoke. Remote workflow scheduling and real-provider matrices remain CI verification.
Scope main pushes from a successful ancestor so canceled runs cannot hide changes. Keep the complete portable suite in fast feedback and move coverage plus Intel macOS to hourly, manual, explicit-full, and release qualification. Let qualification finish independently of superseded feedback.
Bind publication to full qualification at its exact revision and publish the verified tarball after checking workflow identity, version, and SHA-256. Keep trusted cache writers and reject incomplete merged test inventories.
Validation: 151 focused CI tests; typecheck/lint; actionlint 1.7.7; knip; all 1044 files discovered; bounded blob/merge smoke; macOS package verifier with retention and cleanup; npm pack dry run. Native Linux/ARM/Windows and remote workflow execution remain CI verification.
* fix(windows): preserve caller affinity only within one processor group
`spawnProcess` read the caller's affinity mask and applied it to the
suspended child unconditionally. A mask names processors relative to one
processor group, and Windows assigns each new process to a group of its
own choosing, so on hosts with more than 64 logical processors the child
is often placed in another group. `SetProcessAffinityMask` then rejects
the mask with ERROR_INVALID_PARAMETER (87) and the spawn fails, making
every owned provider process start intermittently on such hosts.
Affinity is a nicety, not an authority or isolation control, so it is now
applied only when the caller and the suspended child both occupy the same
single processor group. A child placed in another group keeps that group's
default affinity and the spawn proceeds. Job Object membership,
kill-on-owner-close policy, owner normalization and priority preservation
are unchanged, and the mask failure remains fatal within a shared group,
where it is not expected.
Single-group hosts, including every host with 64 or fewer logical
processors, are unaffected: `GetProcessGroupAffinity` reports one group
for both processes and the same mask is applied as before.
The optional process-boundary fixture gains an `affinity` observation,
and the native verification lane asserts that an owned spawn succeeds and
that the child's mask matches the caller's whenever both share a single
group.
Fixes#2181
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(windows): refuse to widen a pinned caller's affinity across groups
Addresses review feedback on the first commit.
An unconstrained caller loses nothing when Windows places an owned child
in another processor group, so that spawn proceeds with the group's
default. A caller deliberately pinned to fewer processors than its group
holds is a different case: silently accepting the default would hand the
provider tree the whole group, which `docs/installation.md` tells
operators to rely on affinity to prevent. Such a spawn now fails naming
the constraint instead. `GetProcessAffinityMask` already reports the
group's active set, which distinguishes the two without another query.
Selecting the caller's group at creation through
PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY was tried first and rejected:
`CreateProcessW` fails with ERROR_INVALID_PARAMETER on a host with a
single processor group, both alongside PROC_THREAD_ATTRIBUTE_JOB_LIST and
on its own, so it cannot carry the ordinary path.
The boundary fixture's affinity observation now reports a process id's
own mask rather than its own, because a separate probe process is
assigned its own group and cannot stand in for the process that spawns
the child. Masks and the group's active set cross as fixed-width
hexadecimal strings: a mask can set bits above the safe-integer range,
where `JSON.parse` would round two different masks to one value.
The verification lane asserts the mask is inherited exactly when caller
and child share a group, and otherwise that the caller was unconstrained.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(windows): record what owned-process affinity does not preserve
A mask covering its group's whole active set does not distinguish a
caller the system placed in that group from one that selected the group
deliberately, so an owned child can still be placed elsewhere with its
processor count bounded and its group placement lost. Treating that case
as constrained instead is not available: on a multi-group host an
ordinary process is assigned a group by the system and its mask is that
group's active set, so refusing it would fail every owned spawn there.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Bind the owned demo helper to REA's private stdin stream and unwind child
cleanup on EOF during startup or analysis. Verify graceful and SIGKILL owner
exit through real CLI/MCP workflows and preserve unrelated processes.
Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
Summarize saved Wireshark4.x captures with enforced native resource limits, serialized admission, stable snapshot verification and retained fact/text pages. Preserve complete inventories within resource budgets and source uncertainty; report cleanup failure with partial Evidence and retained ownership.
Verified six recorded corpora /13026 packets with independent Scapy/Python oracles, real CLI/MCP/schema parity,60 SNI names,132 DNS addresses and1000 URIs. Real TShark CI now exercises summary/paging. Actual Windows/Bun Wireshark remains unverified; macOS capture requires a separate enforceable-bound decision.
Co-authored-by: 3QL <85309073+3QL@users.noreply.github.com>
Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
Follow-up to #2345; thanks to @gefrezim for the import-time home lookup diagnosis.
Normalize only an empty Windows USERPROFILE before runtime dependency imports, preserving all nonempty caller selections. Reuse the existing public setup dry-run regression in the Windows curated CI lane. No additional filesystem query, engine call, cache or retry.
Verified real Windows Node 24.18.0 CLI unset/empty/selected-profile controls, setup dry-run home selection and unchanged configuration, and baseline/candidate SDK stdio MCP catalogue parity. Nine related tests and static/docs checks passed. No IDA or Ghidra engine was used. Scoped resource observations and measurement limits are recorded in experiments/analysis-efficiency/windows-empty-profile.md.
Fixed the review finding and original CI package-scope ownership failure. Current-head CI is green; the unrelated MCP identity timeout passed on a failed-job rerun without changing its code or timeout. Current-head review completed with no further findings.
Reuse the domain ZIP format list for session schemas, verify full Harmony
CLI/MCP lifecycles, and correct native view guidance and audited docs drift.
Refresh locked dependency notices and gate inventory/provenance consistency,
including notice inputs in the cached documentation gate.
Fixes#2454
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Fixes#2257. Thanks to @chqcjq for the native self-test retry diagnosis in #2266.
Preserve retry disposition through analysis workflows. Native warm admission requires exact sharing/lock codes and affirmative pre-allocation evidence; cleanup ownership takes precedence. No automatic retry or new analysis cache.
Verified with real Windows 11 CLI, same-connection SDK MCP normal/conflict/recovery, the Windows native verifier, 99 focused tests and static/docs gates. Official npm 11.16.0 launcher sources were the application input. No IDA or Ghidra engine was used for this change. Win32 5 was not reproduced; no resolution claim for #1701/#2196. Performance measurements and limits are recorded in experiments/analysis-efficiency/windows-runtime-retry.md.
Inspect bounded recorded raw HTTP/XML SAZ archives and page retained capture Evidence. Preserve exact stored bytes and provenance, validate ZIP/XML integrity, and require an enforceable decoder memory bound.
Verified 356 real recorded sessions against independent byte and metadata oracles, public CLI/MCP parity, retained pages, and related interface checks. Current Fiddler Everywhere GUI and non-Linux producer workflows remain unverified.
Co-authored-by: zahhak <1792039+zahhak@users.noreply.github.com>
Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
Reject native callee successes without an explicit truncation marker while preserving provider failure reasons. Verify positive procedure inventory/search and function-result parity in the real-provider lane; support independent string/xref oracles and label their absence as unverified.
Verified with Windows IDA Pro 9.3: eight normal production CLI/MCP checks passed, and six real-provider response-fault cases reproduced old false positives and validated the correction. Windows IDA Free was not used. No personal paths or license registration information are included.
Repair inconsistent complete-file Ghidra test probe sizes after the shared ELF-header validation change, deriving sizes from the fixture buffers. Reproduced the three failures before the correction; 115 related installation/doctor and ELF tests pass afterward. Runtime parsing and installation behavior are unchanged; no real-Ghidra verification is claimed.
207 focused IDA tests and static/documentation checks passed. Automated review completed on d1e0b1095 without findings. CI run 38327862093 passed all 36 jobs, including Windows, all six test shards, coverage/timing, and real Apple CLI/MCP workflows.
Follow-up to #1544.
@modelcontextprotocol/client 2.3.1 declares callTool(params, options).
Three verifiers still used the v1 shape callTool(params, undefined,
{ timeout }), so the third argument was dropped and those calls ran
under the SDK's 60 s default instead of the 150-180 s they request.
Pass the options second.
* fix(native): honor Mach-O chained pointer locations and library ordinals
Walk declared page starts and next links before decoding chained pointers,
preserving plain pointers between fixups, zero-offset rebases, and known
facts in malformed chains. Interpret positive dylib ordinals with dyld's
special-ordinal cutoff so valid dependency provenance is retained.
Give the Swift verification fixture an explicit module name so link-mode
filenames do not produce invalid identifiers.
Validation: 46 focused regressions; pre-fix reproductions in an isolated
copy; real macOS CLI/MCP verification of 10 compiled Objective-C/Swift,
arm64/arm64e, chained/legacy and symbols/stripped fixture variants.
* perf(native): reuse parsed Mach-O chain membership
* test(native): validate parsed-chain repair against local gates
* test(native): pin chained fixup page failure provenance
* fix(native): bound parsed chained page facts and metadata
* test(server): pin shared partial Evidence provenance
---------
Co-authored-by: baron <richstyles@gmail.com>
Use the existing pinned cross-spawn dependency at the command-spawn boundary instead of forcing every Windows executable and argument vector through cmd.exe. Preserve native executable arguments while retaining PATH/PATHEXT and command-shim support.
Validation: public runner argv and lock/cancellation tests passed on POSIX. Windows-only tests cover an executable path with spaces, bare node, npm, and the local turbo shim; native Windows execution remains unverified.
Fixes#2319
Resolve each caller-selected Electron path once at the application boundary, collect field-specific failures with original causes, and pass canonical paths directly to the provider. Update direct provider consumers and route the real verifier through the shared application workflow.
Validation: public CLI/MCP invalid-path acceptance, canonicalization boundary, provider tests, and cancellation/cleanup checks. Live Electron launch was not verified. This does not address the separate Playwright launch-rejection crash in #2269.
Fixes#2272
Validate unmapped segment file ranges without adding virtual mappings or fallback metadata addresses. Keep mapped-segment bounds and reject build-info sections declared in unmapped segments.
Validation: real unstripped Go 1.26.5 Darwin arm64 and amd64 artifacts passed CLI/MCP oracle, Evidence, source-range and unchanged-byte checks. Retained malformed-input regressions; removed the weaker synthetic acceptance test. Full cross-platform verifier not run. Fixes#2167.
Inspect selected fields in existing captures through shared CLI/MCP Evidence.
Page matching frames without changing dissection or two-pass read coverage;
retain failed descriptor/process cleanup ownership and reject excess admission.
Verified with real TShark 4.0.17 and 4.2.2, public Wireshark recordings,
owned HTTP application traffic, real CLI/MCP workflows and schema checks.
Co-authored-by: Olorinm <59321404+Olorinm@users.noreply.github.com>
Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
Add an explicit attached native IDA MCP compatibility profile while preserving the legacy and headless workflows. Keep recorded input identity, complete source observations and the user's open GUI database. Batch unique callee lookups, conservatively prefilter literal strings, preserve Unicode matching and unavailable caller coverage, and require distinct-function switching in native verification.
Verified with Windows IDA Pro 9.3 and the native MCP plugin built from c9d15d98e8a143fc74f6e14037c48f63889b6d6c with a loopback listener. Production CLI/MCP and an unchanged Windows whoami.exe passed. Windows IDA Free was not used. No personal paths or license registration information are included.
Validation: 200 focused tests, static and documentation checks, architecture guards and discovery passed. Historical same-main warm task measurements improved from 675 to 317 ms; response token estimates fell from 16618 to 11509. Fresh-start, overall CPU and memory improvement were not established. Detailed scope is in experiments/analysis-efficiency/ida-native-windows.md.
Co-authored-by: imissapixel <140405963+imissapixel@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
Add offline SQLite database/WAL inspection through the shared CLI/MCP.
Use compact inventory, selected-table schema, exact ordered columns and
bounded row samples while preserving source identity and lossless values.
Retain completed Evidence through late cancellation and private-root cleanup
failures, bound concurrent inspections, and recheck journal validity after
acquisition. Reuse prepared CI runtime artifacts across supported Node lines.
Co-authored-by: Y0UW1SH <29498139+Y0UW1SH@users.noreply.github.com>
Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
Let the fixture lifecycle own CDP readiness with the same 60-second startup deadline as the broader browser verifier. Return the discovered port to both consumers and clean up failed startup before returning a lease.
Validation: five startup/cleanup boundary tests, npm run check, and real Chrome 154 runtime and source-map CLI/MCP verifiers passed on macOS arm64. Hosted Linux verification follows the push.
Keep static feedback concise while retaining complete diagnostic reports,
visible lint errors, module-boundary checks, and the 3% duplication gate.
Upload complete reports after static failures and restore their outputs
from Turbo caches. Preserve unambiguous, checkout-relative clone locations.
Bind both lint caches to the website, documentation configuration and
experiment sources actually scanned by oxlint, including ignore policy.
Guard this ownership by comparing live checker discovery with resolved
Turbo inputs. A real website syntax error now invalidates a cached pass.
Validation: full current-head CI and the separate Go lane passed. Seven
real-checker regressions passed; failure-status and stale-report mutations
were rejected, and restored source passed. Actual Turbo restored both
reports byte-for-byte; full static/docs/workflow checks passed.
Closes#2238.
Refs #2190.
Assisted-by: Kogasa (gensokyo-skills:kogasa-surprise-testing)
* feat(ghidra): admit RISC-V ELF analysis through a pinned generic lane
Refs #2063.
Recognize `EM_RISCV` (243) as a provider-neutral family that carries its own ELF
facts, and bound the first Ghidra lane to little-endian `ET_EXEC` images that
declare the double-float ABI, pinned to `RISCV:LE:32:default` or
`RISCV:LE:64:default` with the `gcc` compiler specification.
Ghidra 12.1.4 is not reliable without the pin: its `riscv.opinion` pins
`variant="default"` for the 64-bit constraint and leaves the 32-bit constraint
with the comment that the loader "must choose between 'default' and 'AndeStar'
variants". Measured on the installed release tree, a source-owned generic RV32
ELF with no Andes declaration imports as `RISCV:LE:32:AndeStar_v5:gcc`, while
RV64 resolves to `RISCV:LE:64:default:gcc`. The lane therefore states the
language per width and refuses any caller-selected processor outside it instead
of inheriting the header guess.
Refusals name the declaration rather than falling back to a guessed profile:
big-endian images (Ghidra 12.1.4 ships no big-endian RISC-V language),
non-`ET_EXEC` images, `EF_RISCV_RVE`, `EF_RISCV_TSO`, and every float ABI other
than double, which the pinned generic compiler specifications model. The raw
e_flags bits stay in Evidence as declarations, not as instruction semantics.
Family recognition now has one owner for the ELF-metadata families:
`ELF_METADATA_ARCHITECTURES`, `isElfMetadataArchitecture`, and
`HeaderArchitecture` replace ten `Exclude<BinaryArchitecture, "mips">` sites that
would each have needed a second hand-edited member. `ghidraPinnedLanguage` is
that owner for the import commitment: the session readback previously re-derived
only the MIPS pin, so a profile committing any second pinned language failed with
a language-mismatch error before the bridge started.
Hopper and IDA refuse RISC-V by name, matching the MIPS wording. Caller-supplied
raw-binary entry keeps its existing four-family list; this lane is ELF-header
admission only.
Verification on macOS 15.7.7 arm64, Node 24.18.0, Ghidra 12.1.4 PUBLIC and JDK
21.0.12.1, with the host decompiler built from the release sources for
`os/mac_arm_64`: `npm run check` passes; `npm run test:fast` passes 396 test
files; `npm run verify:test-discovery` discovers all 917 test files exactly once.
Source-owned RV32 and RV64 double-float `ET_EXEC` fixtures complete
`rea analyze --provider ghidra` and `rea decompile rea_riscv_entry`, committing
`RISCV:LE:32:default` and `RISCV:LE:64:default` with `language_selection:
provider-pinned-v1`; the soft-float RV64 shape is refused with the named
float-ABI reason, and the full refusal matrix including the RV32 and
width-mismatch shapes is covered by unit tests. No `verify:ghidra:riscv` lane
script is included in this change; the runs above were performed manually against
the installed engine. Fork pull requests receive no CI check runs, so the
real-provider scope above is the evidence available for review.
* fix(ghidra): bound the RISC-V lane by declared flags and document it
Address review feedback on #2151.
`e_flags` bits outside `EF_RISCV_RVC | EF_RISCV_FLOAT_ABI` are now refused with
the offending value named, so a reserved or newer producer declaration cannot
enter the verified generic lane by falling through the RVE, TSO and float-ABI
checks.
Admission reads `e_type` only, so the refusal text no longer calls `ET_EXEC`
static: a fixed-address declaration does not establish static linkage, and
`PT_INTERP` and dynamic dependencies are not inspected. The session records that
boundary as a limitation rather than inferring a load model.
Add `docs/ghidra-riscv.md` in the shape of the MIPS lane guide (admission
boundary, refusal table, why the language is pinned per class, Evidence fields,
and what the fixtures do not establish), and correct
`docs/firmware-analysis.md`, which still told users that MIPS and RISC-V
decompilation had not been added.
Verification after the change: `npm run check` and `npm run docs:check` pass; the
RISC-V module tests pass (17 lane cases plus 9 parser cases); on Ghidra 12.1.4
with JDK 21.0.12.1 the RV32 and RV64 double-float fixtures still analyze and
decompile with `RISCV:LE:32:default` / `RISCV:LE:64:default` and
`language_selection: provider-pinned-v1`, the soft-float fixture is still refused
by name, and the new linkage limitation appears in the emitted Evidence.
* fix(ghidra): align RISC-V pinning with admission
Reuse the complete lane admission boundary when selecting a language, retain unsigned unsupported flag bits in diagnostics, and derive float ABI metadata from the source declaration.
* test(ghidra): verify RISC-V CLI and MCP workflows
Build source-owned RV32/RV64 fixtures with Clang and LLD, establish independent ELF and symbol facts with LLVM readelf, and verify real provider evidence, instruction bytes, calls, decompilation, schema projections, snapshot replay, refusal diagnostics, source immutability and cleanup.
Verified on macOS ARM64 with Ghidra 12.1.4, JDK 21 and LLVM/LLD 23.1.2. Dynamic linkage, big-endian, Andes and RVE/TSO workflows remain unverified; ISA attributes are not inspected.
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
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)
* 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>
createCli parsed REA_LOG_LEVEL with a throwing schema, so an invalid or
uppercase value crashed every command, including doctor and --help, with
a ZodError stack trace. Parse it into a ConfigurationError result and have
the executable print the same configuration message as the MCP adapter
and exit 1 before building the CLI.
Fixes#2135
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.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>
Exercise cold and warm completion through ordinary provider operations. Bind fixture observations to the selected analysis profile so the warm-up call satisfies session validation, and make package completion candidates explicit with useful failure diagnostics.
07b36c148 made document and procedure completion read only from an
already-started provider client. Two checks still completed right after
opening a target, so they observed an empty cold result:
- promptCompletion.test.ts used a fixture client without executeIfReady
and never ran an ordinary operation, so the composite provider had not
created a client yet.
- The packaged MCP smoke expected live completions on non-Linux hosts
immediately after open_binary, before current_document started Hopper.
Both now assert the cold result is empty, ready the provider through an
ordinary operation, and then assert the unchanged live candidates.
Fixes#2123
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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>
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.