Commit Graph
87 Commits
Author SHA1 Message Date
+1 1ddee1089b feat(dotnet): expose field constant defaults (#8015)
* feat(dotnet): expose field constant defaults

* test(dotnet): guard field default comparison warning

Compare actual ordinary and constant-bearing observations independently of the limitation producer. Preserve warning delivery and unchanged matching assertions while allowing harmless wording changes.

Refs #5150

* test(mcp): retain structured bundle path diagnostics

Keep absolute-path refusal and all rejected parameter facts independent of legacy flat or current structured SDK diagnostic rendering. Retain relative CLI, absolute MCP and no-Evidence controls.

Refs #5150

* Revert "fix(ci): integrate main and repair inherited static checks"

This reverts commit afd4d571f6, reversing
changes made to 317bf3fe23.

* fix(ci): replay reviewed field-default integration

* fix(analysis-view): keep inferred confidence on views of inferred Evidence (#8099)

createAnalysisViewEvidence chose view confidence from the view result kind
only, so every summary, page or item view of an inferred parent
(compare_source_to_bundle, inspect_evm_interface, partially resolved
inspect_il2cpp_metadata) was sealed as derived while keeping the parent's
authority. A projection never makes its facts more certain: an inferred
parent now yields inferred views through CLI and MCP alike. Observed and
derived parents keep their existing view confidence and identities.

Fixes #8098

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(apple): read flattened framework Info.plist from Resources (#8101)

A macOS framework without Versions/ keeps its binary, _CodeSignature/ and
Resources/Info.plist directly in the .framework, as Electron and Gecko apps
ship it. Bundle anatomy looked for a shallow bundle's plist only at its root
and reported info_plist_path: null under complete coverage.

Resolve a shallow bundle's root Info.plist first, then Resources/Info.plist,
the same layout a framework version directory uses. Keep the iOS platform
rule tied to a root-level Info.plist so a Resources/-only application root
is not classified as iOS.

Fixes #8100

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(desktop): charge retained rows at their measured representation (#8105)

* fix(desktop): charge retained rows at their measured representation

The desktop scan reserved 1024 + 24 bytes per path character for every
row, omission and the root against its 32 MiB representation budget. Real
rows cost 800-940 heap and 490-640 JSON bytes, so the charge overstated
them 6-13 times and large macOS bundles stopped at 3,700-7,200 entries,
far below max_entries.

Charge each path at the larger of its UTF-16 heap size and its escaped
JSON size, plus the existing fixed row and omission overheads, in one
helper. The bound still covers the retained heap and the serialized
report, including control-character paths that expand six times in JSON.

Fixes #8104

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(desktop): charge every retained copy of a path

The tighter row charge counted each path once, but rows repeat it in
convention-fact values and the next probes those facts offer, and host
failure issues name the absolute path. Control-character paths under a
convention such as Content/Paks or resources/app.asar therefore serialized
47-80 MiB of reports within the 32 MiB budget.

Reserve each copy through the same text helper where it is stored: path
convention facts with their row, the probes any fact offers (at most two,
pinned by a projection test) with that fact, retained read ranges before
their read, and probe failure issues before they are recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(source-maps): resolve empty sourceRoot sources against the map URL (#8107)

webpack 5 and tsc write "sourceRoot": "" for map-relative sources. Since
5f702dd6c the shared join added "/" for any non-null root, so these
sources resolved from the URL root: rxjs's ../../../src/internal/Observable.ts
under /npm/rxjs@7.8.1/dist/cjs/internal/ became /src/internal/Observable.ts,
and xterm's webpack://xterm/./src/... became https://host/webpack://xterm/....

Treat an empty root like a null root in sourceMapReference, the single join
used by trace-web-source-location, analyze-javascript-application and the
web source-map fetcher. Chrome, Firefox and trace-mapping skip an empty root,
and tc39/ecma426#183 wrote the current steps to match them. Non-empty roots,
including "/" and repeated slashes (#6726), keep their existing behavior.

Fixes #8106

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(javascript): stop reporting self-defaulted receivers as module loads (#8109)

The CommonJS loader search treated any repeated state on its own ancestor
chain as an unknown loader. A self-default such as
`session.messages = session.messages || []` forms that cycle, because a
member read inside the assigned value was attributed to the later call's
read site and selected the same write again. Each `push` on the value was
then reported as an unresolved `require` load, and graph coverage became
partial.

Record a member read inside a flowed value as a depth-1 captured selection
at its own position, as member mutations already do for flowed origins.
Treat a revisited state as adding no source; the cycle's other entries are
still expanded once each. Remove the superseded ancestor tracking.

Fixes #8102

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(captures): admit browser-serialized HAR request URLs (#8112)

* fix(captures): admit browser-serialized HAR request URLs

har-schema@2.0.0 checks request.url with ajv-formats' strict RFC 3986
`uri` format. Browsers record and send URLs as WHATWG serializes them,
which keeps characters such as `|` and `{` unescaped in the query, so one
Google Fonts or GraphQL GET entry made inspect-web-network-capture and
environment-build reject the whole HAR.

HAR 1.2 defines request.url only as the absolute request URL. Own that
correction in the HAR validator: every URL the RFC 3986 check accepts
stays accepted, and a URL that WHATWG URL serialization reproduces
unchanged is accepted too. Spellings WHATWG would rewrite (a backslash
authority, a tab, a space) and relative references still fail.

Fixes #8110

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(captures): state that RFC 3986 request URLs stay admitted

The HAR request URL rule is "passes RFC 3986, or WHATWG serialization
reproduces it unchanged". A spelling WHATWG would rewrite therefore fails
only when it also fails the RFC 3986 check; an uppercase host still
passes. Say so in the docs and the validator comment, and pin the
accepted uppercase-host case in the CLI test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(apple): charge the XML plist decoder's DOM before decoding (#8115)

* fix(apple): charge the XML plist decoder's DOM before decoding

The XML preflight charged 4 bytes per character and 256 bytes per start
or end tag. The decoder builds an @xmldom/xmldom DOM that measured
1,000-1,160 bytes per element and up to 240 bytes per text, comment or
CDATA node, which were not charged at all. A 1.75 MB plist of 230,000
<true/> lines was admitted under the 64 MiB decode budget and peaked at
249 MiB of heap; shipped Apple plists peaked at 80-104 MiB.

Charge each element and each text, comment, CDATA or DOCTYPE node at a
measured upper bound, keeping the character and number-projection terms.
The binary estimator already bounds its decoder and is unchanged.

Fixes #8113

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(apple): charge every XML element, attribute and reference

The XML preflight recognized only element names starting with an ASCII
letter, so names such as é, _, a CJK or astral character escaped the
element charge: 100,000 <é/> elements (0.5 MB) built an 84 MiB DOM before
the plist decoder rejected the tag. Attributes and entity or character
references were also uncharged; 20 attributes per element measured about
210 bytes each, and each reference about 26 bytes beyond its characters.

Classify markup by the character after "<" instead of a name pattern, so
anything other than an end tag, comment, CDATA, PI or declaration counts as
an element (saxes rejects malformed markup before the DOM is built). Charge
each unquoted "=" in a start tag as an attribute node and every "&" as a
reference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(apple): charge XML references only where the parser expands them

The previous commit charged every "&" in the document as a reference,
including literal ampersands inside CDATA sections and comments. A valid
plist with one CDATA string of 1,000,000 ampersands was refused although
it is a single node the decoder holds as one string.

Count "&" during the existing token walk, only in text runs and in the
attribute values of start tags, so comments, CDATA, PIs and declarations
add no reference charge and the scan stays a single pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(fit): preserve leading U+FEFF in property strings (#8083)

* fix(environment): retain conflicting scenario MIME uncertainty (#8082)

* fix(environment): retain conflicting scenario MIME uncertainty

* test(mcp): assert structured absolute-path diagnostics

* test(mcp): assert typed selector and stdio diagnostics

* fix(electron): keep literal IPC sends ambiguous beside unresolved handlers (#8120)

* fix(electron): keep literal IPC sends ambiguous beside unresolved handlers

A main handler on an unresolved channel can receive any literal renderer
send of a compatible mode, but pairing ignored it unless it had a scoped
receiver. The send was then reported unpaired, or paired with another
handler. Treat an unresolved-channel handler as a competitor that never
pairs.

The wrapper pass seeds only calls with a literal first argument, so it now
records which invocations of a dynamic site it traced. The syntax finding
gains `invocation_channels: "literal"` only when every invocation is a
traced direct call of an unexported local function supplying a literal
channel. Such a site is already represented by its per-invocation findings
and does not compete.

Fixes #8118

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(electron): keep guarded wrapper registrations competing in IPC pairing

A guarded wrapper registration keeps its predicate on a call path and has
no IPC finding. It still counted toward `invocation_channels: "literal"`,
so pairing lost it: a send on that channel was reported unpaired, or
paired uniquely with a direct handler. The enumerated site now carries
these channels as `guarded_invocation_channels`, and each one competes for
its own channel without pairing.

Index each binding's direct call sites by appending in place. Spreading
the earlier calls on every reference was quadratic in a file's call count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ci): remove unused exports that fail deep static checks (#8095)

* fix(ci): remove unused exports that fail deep static checks

Knip on main reports three analysis-view hub re-exports, two type
re-exports, an unused artifact-format guard and an alias constant. Drop
the dead re-exports and guard, and give the debugger control-reply budget
its own literal: it is a separate budget from the caller command-output
default, as its comment already states.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(config): read the Rizin control budget from its own constant

The Rizin control-reply admission limit still took its value from the
caller command-output default, while GDB used DEBUGGER_CONTROL_REPLY_BYTES.
Read the dedicated constant in both so the control budget has one owner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* perf(javascript): keep one member-effect record per stored fact (#8103)

Member-mutation indexing appended a binding write or escape record for
every traversal state that reached it. States that differ only in
coverage fields the record never stores (origin, owner initializer,
getter widening) produced identical records, and each later receiver
query rescanned all of them. Record each stored fact once, alongside the
existing required-module effect deduplication. Propagation is unchanged.

Effect ordering also re-walked the same top-level statement ancestry for
every candidate record. Cache it with the other initializer positions,
and test the selected path before the costlier receiver comparison.

On the #7774 reproducer the semantic IR and the complete
analyze-javascript-application Evidence are byte-identical, while the
CLI run drops from 146 s to 40 s.

Refs #7774

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(native): open extension, framework, XPC and plug-in bundle directories (#8117)

* feat(native): open extension, framework, XPC and plug-in bundle directories

open_binary and the CLI inspection commands admitted only .app
directories and pointed every other Apple bundle at the JavaScript
analyzer. Resolve .appex, .framework, .xpc, .systemextension, .bundle
and .plugin directories through their Info.plist CFBundleExecutable, in
the Contents or flat root layout, plus the versioned framework layout
under Versions/Current. Exactly one layout may declare the bundle and
every resolved path must stay inside it.

Unresolvable bundles fail closed with typed constraints, probed paths
and the Info.plist that was read. Other Apple bundle types are refused as
unsupported instead of being offered the JavaScript route. Resource-root
discovery shares the same layout rule, so inspect_plist reads a
versioned framework's Info.plist. The recognized bundle vocabulary now
has one owner in the domain.

Refs #4310

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(native): refuse kernel extensions and state bundle error fields

Name the Apple bundle types binary routes recognize but do not open
(.dext, .kext, .qlgenerator, .mdimporter) explicitly, so a kernel
extension is refused as unsupported instead of receiving the JavaScript
route. Document which bundle refusals carry probed_paths and info_plist,
and make success tests throw the typed admission error before asserting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(native): open flattened frameworks through Resources/Info.plist

Electron and Gecko apps ship frameworks without Versions/: the program
file sits at the framework root beside Resources/Info.plist, the layout
#8101 taught bundle anatomy. Read that layout for a framework without
Versions/, and keep the versioned layout for one with it, so a versioned
framework's root Resources link is never read as a second declaration.
The resource root reports it as flattened-framework.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* chore(security): configure dependency and ownership reviews

* perf(javascript): index member-effect paths for projected reads (#8108)

* perf(javascript): index member-effect paths for projected reads

Each projected read scanned every member-write record of its binding and
tested the record path against the selection. On the #7774 reproducer
only 3.7% of scanned records pass that test. Index each binding's
append-only records by path in a lazily built trie that extends itself
with newly appended records, and visit only records whose exact keys a
selected choice names or whose keys are wildcards. Candidates come back
in record order and still pass the exact predicate, now owned next to
the index as semanticEffectPathMatches.

The semantic IR and the complete analyze-javascript-application Evidence
are byte-identical. On the full reproducer each worker phase drops from
about 80 s to 29 s, and to 8 s together with #8103.

Refs #7774

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* perf(javascript): stop escape checks at the first indexed match

The escape check only asks whether any matching escape is unsuperseded,
so it does not need ordered candidates. Share one trie traversal between
the ordered write candidates and an early-exit visitor for this check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(hopper): distinguish an absent demo dialog from publisher rejection (#8074)

* fix(hopper): distinguish an absent demo dialog from publisher rejection

The Linux demo watcher collapsed an admitted launcher with no first-run dialog into unsupported_demo_dialog. Report that post-authentication timeout as demo_dialog_absent, keep the unsupported dialog code for an observed but unrecognized Hopper window, and allow REA_HOPPER_DEMO_DIALOG_TIMEOUT_MS to widen the fixed wait. Closes #8008.

* fix(hopper): tolerate callers without the dialog timeout argument

* fix(hopper): report an invalid demo dialog timeout as its own failure

An invalid REA_HOPPER_DEMO_DIALOG_TIMEOUT_MS exited 73 and was shown as
invalid_launch_command. Exit 82 is invalid_dialog_timeout. The public error
names the setting, shows the rejected value and source, lists the allowed
range, and says to restart REA.

Drive the demo watcher with controlled windows and time. No window exits 81,
a Hopper window without a supported dialog exits 76, and a dialog that arrives
after the old 10 second limit is still accepted.

* fix(hopper): keep startup stderr capture on AdapterFailure

DemoWatchStop was inserted above with_stderr, so launch failures called a
method they no longer had and became unexpected_failure. Restore with_stderr
on AdapterFailure and reject a watcher fixture that cannot capture stderr.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

* test(ci): require provider checks and reduce test startup (#8145)

* test(ci): require provider coverage and reuse test sessions

* fix(ci): prepare the runtime before Python producer tests

The fast Python job ran the suite on a fresh checkout, so analysis-efficiency
checks failed without compiled process modules. Install locked dependencies
and prepare the runtime before the suite.

* fix(ci): keep provider test reports inside the checkout

The provider-report reader accepted an arbitrary path from argv. Resolve the
path and reject anything outside the checkout before reading it. The packet
and signal workflows write those reports under .cache.

* fix(ci): require a test module in each named Python bridge family

Discovery still runs every bridge test. The mitmproxy, native, and pwndbg
families must each keep a test module, so deleting one cannot pass through
the others.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

* fix(javascript): emit no http request for a target that is not a URL (#8147)

* fix(javascript): emit no http request for a target that is not a URL

`node:http` parses a string target with `new URL(...)` before a request object
exists, so a literal that is not an absolute URL throws `ERR_INVALID_URL`
synchronously. The analysis reported `endpoint` at `resolution: "complete"` for
those calls, and the graph then projected `constructs-request` as `resolved`.

Measured on Node 24.22.1:

    http.get("nope")                     -> THREW ERR_INVALID_URL
    http.get("example.test/api")         -> THREW ERR_INVALID_URL
    http.get("/api/items")               -> THREW ERR_INVALID_URL
    http.get("/api/items", { host })     -> THREW ERR_INVALID_URL
    http.get("")                         -> THREW ERR_INVALID_URL
    http.get("//example.test/x")         -> THREW ERR_INVALID_URL
    http.get("http://")                  -> THREW ERR_INVALID_URL
    http.request("nope")                 -> THREW ERR_INVALID_URL
    https.get("/api/items")              -> THREW ERR_INVALID_URL
    --- accepted ---
    http.get("http://example.test/x")    -> OK ClientRequest
    http.get("HTTP://example.test/x")    -> OK ClientRequest
    http.get("http:/x")                  -> OK ClientRequest
    http.get("http:///x")                -> OK ClientRequest
    http.get("http:x")                   -> OK ClientRequest

`URL.canParse` is the exact predictor of that branch, so a relative spelling such
as `"http:x"` keeps its operation. It already has precedent in this codebase
(`javascriptPackageImportAliases.ts`).

Two boundaries are deliberate. `fetch` and `new WebSocket` are host-supplied
globals: a browser resolves a relative target against the document URL, so their
spellings are not judged by Node's absolute-URL rule. A protocol mismatch such as
`http.get("ftp://...")` is also left alone because an options object can rescue
it, so it is not a provable throw.

The guard is scoped to `method === "get" | "request"`, which only
`requestMethod`'s `http`/`https` builtin branch can produce.

* chore: retrigger title and readiness checks after the title was corrected

* refactor(ci): unify lane ownership and guard Python tests (#8150)

* refactor(ci): unify lane ownership and guard Python tests

* fix(ci): reject entirely skipped bridge subtests

* docs: correct the raw ARM example and document a Cortex-M language override (#7483)

* docs(raw-binary): replace the STM32-style ARM example

The headline raw example opened ecu.bin at 0x8000000, an STM32 flash
address, while the arm lane decodes in ARM state. Map a 32-bit ARM-state
image at 0x8000 instead, and state beside the example that Thumb-only
images, including Cortex-M firmware, are not supported.

* docs(ghidra): document an interim Cortex-M language override

Ghidra imports little-endian ARM ELF files as ARM:LE:32:v8, which
defaults to ARM state and marks Thumb code only from $t mapping symbols
and odd function-symbol addresses. Unpinned arm ELF already admits
REA_GHIDRA_LANGUAGE_ID, so document ARM:LE:32:Cortex (ARMv6-M, ARMv7-M,
ARMv7E-M) and ARM:LE:32:v8-m (ARMv8-M) as an unverified interim.

State the override's full effect while it is set: raw-binary, DOS, DOL,
PSP and language-pinned lanes such as RISC-V refuse it, and REA asks
Ghidra to import every other target in the ARM language, because it does
not check the override's processor against the target.

* fix(ida): admit architecture families by allowlist (#7485)

IDA refused MIPS, RISC-V, PowerPC, Hexagon and arm64_32 by denylist, so
any family nobody excluded was reported supported, and the label ternary
printed "Hexagon" for any other metadata family. Admit exactly the
families IDA admits today (x86, x86_64, arm, arm64) and name every other
family from its own architecture id. Families that Ghidra admits keep
the pointer to a Ghidra profile.

Refusal text now uses architecture ids, for example "no verified mips
lane" instead of "no verified MIPS lane".

* ci(ghidra): probe M-profile ARM and Xtensa decoding (#7482)

* ci(ghidra): probe M-profile ARM and Xtensa decoding

The embedded plan relies on ARM:LE:32:Cortex, ARM:LE:32:v8-m and
Xtensa:LE:32:default, but CI only exercised ARM:LE:32:v7. Import
source-owned bytes for each language at 0x1000 with -noanalysis and
check how they decode from the language's default context: Cortex and
v8-m must start in Thumb state, v8-m must decode the ARMv8-M MSPLIM
register, and Xtensa must decode entry and retw.n.

Add the probe scripts the job runs, including the existing ARM context
probe, to the ghidra_bridge change scope.

* ci(ghidra): match decode-probe operands as complete operands

The operand expectation searched the instruction text for a substring,
so mrs/4/msp also accepted mrs r0,msplim. Compare it with each operand
Ghidra reports for the instruction, so only a complete operand matches.
The Cortex (msp, lr), v8-M (msplim, lr) and Xtensa (a1) expectations are
unchanged.

* test: guard target format vocabularies and DOL snapshot saves (#7481)

* test(mcp): save and reopen a GameCube DOL snapshot

#7290 reported that DOL Evidence could not be bundled or saved; 50822e1ef
fixed the bundle manifest and added bundle export/import coverage, but no
test saved a DOL session through close_binary. Save a DOL snapshot with
recorded Evidence, check its target and artifact manifest, then reopen it
and replay the read without running the provider again.

* test(binary): require every target format in each target vocabulary

A new target format must be added by hand to the Evidence subject,
bundle manifest, snapshot target and live summary vocabularies; missing
one caused #7290. Give every BinaryTarget format a fixture through a
mapped type, so a new format fails compilation until it has one, and
push each fixture through the producers that persist or project targets.
Caller-selected format hints must name executable target formats.

This is a guard until target formats have a single owner.

* test(mcp): assert the replayed DOL result and the owned replay limitation

The DOL snapshot replay test checked the subject and the provider-call
count but not the answer, so a replay returning null or another value
would pass. Compare the replayed normalized result with the original.
Name the replay limitation as SNAPSHOT_REPLAY_LIMITATION in the snapshot
cache that adds it, and assert that value instead of repeating the
sentence.

* test: list Intel HEX and S-record targets in the vocabulary guard

Upstream added the intel-hex and srec formats (#7136). The guard requires
a fixture for every target format, so after merging main it no longer
typechecked; both formats now have archive fixtures and pass the same
persistence and projection checks.

* test: list UnityFS among the target format fixtures

Upstream #7699 added the unityfs target format, so the vocabulary test's
per-format fixtures must name it; without one the test no longer typechecks
against main.

* test: list uImage among the target format fixtures

Upstream #7234 added the uimage target format, so the vocabulary test's
per-format fixtures must name it; without one the test no longer typechecks
against main.

* test: list the ESP image among the target format fixtures

Upstream #7498 added the esp-image target format, so the vocabulary test's
per-format fixtures must name it; without one the test no longer typechecks
against main.

* fix: correct stale provider refusal and diagnostic text (#7484)

* fix(ghidra): name every admitted family in the architecture refusal

The refusal listed x86, x86_64, arm, arm64, MIPS, RISC-V, raw 6502 and
raw m68k, but the admission set also holds powerpc and hexagon. Build
the text from SUPPORTED_ARCHITECTURES, marking raw-only families, so a
newly admitted family cannot be left out again, and name the refused
family.

* fix(hopper): stop calling the Ghidra Hexagon lane verified

Hopper declined Hexagon targets with "Select a verified Ghidra Hexagon
profile instead", but REA has no verified Hexagon lane. Record whether
each declined family's Ghidra lane is verified, and say that Ghidra
admits Hexagon through an unverified lane.

Name declined families by architecture id, as the Ghidra and IDA
refusals do.

* fix(ghidra): name the pinned language in profile readback refusals

The session readback said "MIPS" whenever a provider-pinned profile
conflicted with the target or with REA_GHIDRA_LANGUAGE_ID, although the
RISC-V, PowerPC and DOL lanes are pinned too. The readback helper was
MIPS-named and re-parsed the language slot that
ghidraProfileLanguageOverride already owns. Move it beside that owner as
a family-neutral readback and name the pinned language id instead.

* fix(ghidra): list DOL among independently verified load images

GameCube DOL load images are independently verified, but the declined
format reason, the inspect_native_load_image capability note and the
Windows P0 guide listed only DOS MZ, DOS COM and raw-binary.

* fix(ghidra): count RV32E's sixteen integer registers

The EF_RISCV_RVE refusal described a 15-register ABI. RV32E has 16
integer registers, x0-x15, as docs/ghidra-riscv.md already says.

* fix(elf): name the refused e_machine

"unsupported ELF architecture" did not say which machine was refused.
Include the numeric e_machine, for example EM_XTENSA 94.

* test(hopper): assert declined-lane facts and owned refusal reasons

The MIPS case banned the phrase "not verified" instead of checking
facts, so wrong advice would still pass. Expose each declined family's
Ghidra lane status, assert those statuses, check that the advice depends
on the status, and compare Hopper's refusals with
hopperDeclinedArchitectureReason. The RISC-V refusal table now compares
the provider's reason with ghidraRiscvUnsupportedReason and expects the
EF_RISCV_RVE declaration name rather than fixed wording.

* test(ghidra): assert verified load-image formats as owned facts

The declined-format test required display phrases such as "DOS MZ" and
"GameCube DOL", so harmless rewording failed it while wrong guidance
containing those names passed. The format list was also spelled three
times: in the attestation's membership check, its reason and the
inspect_native_load_image capability note. Give the verified formats one
owner with the formatters for both texts, assert the list as a fact, and
compare the delivered reason and capability note with those formatters.

* fix(hopper): stop restating which Ghidra lanes REA has verified

Hopper's refusal for families it declines carried its own table of
which Ghidra lanes REA has verified (mips, riscv and powerpc verified,
hexagon not). That restated the Ghidra provider's facts in Hopper and
goes stale whenever they change, the drift that made the Hexagon refusal
wrong in the first place. Reading Ghidra's facts from Hopper would
couple the providers instead; no module in src/hopper imports from
src/ghidra.

The table and hopperDeclinedGhidraLane are removed.
hopperDeclinedArchitectureReason now states only what Hopper owns: it
does not admit the family, and the Ghidra provider's lane reports
whether REA has verified it. The arm64_32 sentence is unchanged.

The test checks every declined family against the formatter: each
reason names the family and Ghidra, and apart from the name all reasons
are the same text, so none states a per-family Ghidra status.

* fix(hopper): route declined families to Ghidra without promising its lane facts

The refusal said the Ghidra lane reports whether REA has verified it, but
Ghidra admits Hexagon with no such note, so a caller could not find the
promised status. Hopper now only states that it does not admit the family
and routes the caller to the Ghidra provider.

---------

Co-authored-by: hhang <169027046+xu91102@users.noreply.github.com>
Co-authored-by: Kaoru0822 <kanadekitauji@proton.me>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: ShuaixinHuang <1836656514@qq.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: Henglie <90338155+Henglie@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: 吴佳浩Alben <35291372+XiaoBinGan@users.noreply.github.com>
Co-authored-by: Entrpi <133157614+Entrpi@users.noreply.github.com>
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-10-31 00:10:36 +08:00
记得吃中饭andgensokyo-dev 22cab8215a feat(artifacts): inspect and extract .NET single-file bundles (#3787)
* feat(artifacts): inventory and extract .NET single-file bundles

* fix(artifacts): retain bundle source I/O failure reasons

* docs(artifacts): record Linux bundle regression verification

* fix(artifacts): preserve bundle source failures and cancellation

* docs(artifacts): record synchronized bundle verification

* fix(artifacts): bind bundle extraction to inventoried host

* docs(artifacts): record bundle verification outcome

* fix(artifacts): bound bundle paths and suggest extraction

* fix(artifacts): preserve nested executable container boundaries

* test(artifacts): verify projected .NET members and simplify extraction admission

* fix(artifacts): explain fixed bundle limits at their producing boundary

---------

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-10-29 20:06:58 +08:00
LN Bodicherlaandgensokyo-dev c9bf6a9df7 feat(managed)!: show readable type names in member signatures (#5309)
feat(managed): show readable type names in member signatures

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-10-29 14:34:42 +08:00
gensokyo-dev cf9f010dcd feat(managed): filter and project retained member views (#7968)
* feat(managed): filter and project retained member views

* test(managed): guard relationship endpoint filter semantics
2026-10-29 10:39:34 +08:00
morluto e3044645c7 fix(managed): retain local signature comparison coverage 2026-10-27 08:46:31 +08:00
morluto 263a98c6ce fix(managed): preserve malformed signature uncertainty in comparisons
Consume the signature producer status before inferring operand-resolution limits. Preserve exact byte-match provenance while malformed paired signatures remain unknown through current and historical Evidence, CLI and MCP.
2026-10-24 10:17:23 +08:00
morluto 96ad94f69e fix(managed): attribute malformed comparison inputs to their arguments
Pass the caller-selected input field to the shared managed parse-failure
owner. Derive filename and field from one comparison selection, reporting
leftPath or rightPath while ordinary inspection continues to report path.
Preserve typed input classification and completed-left partial Evidence.

Replace weaker direct malformed-input cases with a compiled CLI workflow
covering both sides, the healthy comparison, and sibling inspection.
Document the input-attribution contract.

Validation: the public regression reproduced the generic path issue;
focused CLI, comparison and shared-reader controls passed after repair.
No managed assembly or external analysis provider was executed.
2026-10-24 09:17:10 +08:00
morluto 64fa1db130 fix(managed): honor native platform symbol lookup
Restrict Windows A/W suffix and stdcall candidates to their applicable native format. Preserve original metadata and per-observation Evidence ownership. Exercise identity contradictions and wrong-role controls through the shared CLI and stdio MCP workflows.

Fixes #6926
2026-10-24 08:01:25 +08:00
morluto fc2dddc1d9 fix(managed): retain facts without inventing delta identities
Recognize baseline-dependent #JTD metadata at the shared layout owner before table sizing and decoding. Report unsupported partial metadata across all inspection workflows, preserve admitted PE/CLI and metadata header facts, and keep member identities and inventories unknown without the baseline.

A generated PE carrier reproduced complete coverage and a wrong standalone MethodDef token before the fix. Producer and actual CLI/MCP checks now cover all three inspections, normal metadata, retained comparison after source deletion, exact caller selection, source digests, unchanged bytes, and known header facts. Released .NET writer/reader sources establish framing applicability; natural PE occurrence and real CLR/Edit-and-Continue execution were not verified.
2026-10-24 07:31:55 +08:00
morluto 0785223582 fix(managed): share nominal scope across member comparisons
Resolve declaring TypeDef tokens within their own source and reuse the retained nominal identities for pairing, absence, and aggregate coverage. Remove display-name membership interpretation while preserving partial known pairs and whole-inventory matching.

A generated managed fixture reproduced false additions and removals for distinct nested owners sharing a display name before this change. All 305 focused producer and public CLI-to-stdio-MCP checks passed, including comparisons after source removal, missing identities, and genuine whole-inventory changes. Clarify selected-scope semantics in the docs; no live managed runtime was used.
2026-10-24 07:07:06 +08:00
morluto 091d6209af fix(managed): compare retained declaring-type selection scope
Derive aggregate selected-scope agreement from retained nominal type identities instead of requested spellings. Keep incomplete or historical selected scope unknown while preserving caller selections, whole-inventory distinction, paging and member absence behavior.

Cover equivalent requests, same-label nested owners, missing and partial identity facts, and complete empty selections. Exercise CLI inspection Evidence through stdio MCP comparison after removing its selected source file.
2026-10-24 06:48:16 +08:00
morluto 08e8a568f8 docs(managed): distinguish oracle conformance from host verification 2026-10-24 03:00:09 +08:00
morluto 1f0eb228e5 fix(managed): derive selected scope from parsed declarations 2026-10-24 02:37:47 +08:00
morluto bc2d494030 fix(managed): retain declaration kind and runtime implementation facts 2026-10-24 02:36:50 +08:00
morluto 4345a45982 fix(managed): share source identity and input failure ownership 2026-10-24 02:35:22 +08:00
morluto db923eba44 fix(managed): preserve verification input and coverage semantics 2026-10-24 02:29:08 +08:00
morluto 357e354ac7 fix(managed): preserve member scope and nominal edge identity 2026-10-24 01:47:31 +08:00
morluto 87fa1b613d fix(managed): retain nested names and ReadyToRun observations
Resolve attribute display names from validated nesting and parsed member facts, admit composed names before allocation, and preserve unknown malformed chains. Keep ReadyToRun classification ahead of metadata hints while retaining each observed hint.

Fixes #6815
Fixes #6810
2026-10-24 00:11:41 +08:00
morluto ecd997e512 fix(managed): compare catch types by scoped nominal identity
Preserve boundary facts and uncertainty through their consumers. Add focused production-boundary regressions and update affected documentation.

Fixes #6760
2026-10-23 23:49:26 +08:00
morluto 529038f557 fix(managed): retain unknown catch identity beside observed name changes 2026-10-23 21:28:11 +08:00
morluto b305104e4a fix(dotnet): keep TypeRef catch identity unknown
Fixes #6712
2026-10-23 21:28:10 +08:00
morluto a8b8ff2acf fix(dotnet): preserve managed metadata comparison facts
Decode VARARG sentinels and allow omitted empty blob heaps while retaining failures for referenced missing data. Compare field and catch targets using owning parsed facts instead of build-local tokens.

Fixes #6720
Fixes #6686
Fixes #6713
Fixes #6712
2026-10-23 21:28:10 +08:00
morluto 72dd48a44c fix(managed): respect native module case semantics
Preserve the observed native format when comparing module identities so ELF case-only differences remain mismatches while unknown platform behavior stays unresolved.

Fixes #6652
2026-10-23 19:20:52 +08:00
morluto 5a5bcb6b54 test(managed): align source goldens with metadata validation
Fixes #6650
2026-10-23 19:10:32 +08:00
morluto c70eefad50 fix(managed): compare observed call targets
Compare aligned managed call edges by their reported declaring type and method name, keeping missing target facts unknown without comparing build-local tokens. Document the static comparison limits.

Fixes #6630
2026-10-23 19:07:46 +08:00
morluto 667402846c fix(managed): validate metadata operands and locals declarations
Classify MemberRef operands from parsed signatures, validate signature table references and LocalVarSig blobs, and compare observed locals declaration presence. Keep partial CIL facts and transient-budget ownership at the method reader.

Fixes #6578
Fixes #6572
Fixes #6558
Fixes #6513
2026-10-23 18:30:45 +08:00
371f3d91ae fix(managed): retain type discovery after member limits (#5312)
fix(managed): retain types after member limits

Admit type identity and a bounded recovery envelope before member decoding so callers can discover smaller selections after capacity exhaustion.

Fixes #5146

Co-authored-by: eco-null <eco-null@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-23 06:07:03 +08:00
Kaoru0822andClaude Opus 5.5 c9b4cae9dc feat(managed): project call and field-access edges into the application graph (#6260)
project_managed_application_graph dropped the call_edges and
field_accesses that member Evidence already decodes, so the graph was a
containment tree that could not answer who calls a P/Invoke wrapper or
which methods touch a field, while reporting complete-within-inputs.

In-module call/callvirt/newobj/jmp sites now become one calls edge per
caller and target, and field loads, stores and address-takes become one
accesses edge per method and field, each with site and per-opcode counts
and member Evidence links. MemberRef and MethodSpec targets, unknown
targets, ldftn/ldvirtftn loads, recursive self-calls (the graph has no
self-loops), MemberRef fields and sites whose node is absent are counted
by reason in limitations, and the graph is partial with that
omitted_count. Add the provider-neutral accesses relation.

Graph Evidence projected before these counters existed still parses,
with null calls and field_accesses summaries.

Fixes #4056

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:26:56 -07:00
Jay-Alexander Elliot 57fd3ea5d8 feat(cli): summarize managed members with durable Evidence paging (#5167)
Fixes #5148.

Add opt-in durable managed member summaries and authenticated paging while preserving complete default output, original Evidence, cleanup ownership and queued cancellation.

Verified with bounded real Newtonsoft/Redux/Rust tasks, independent oracles, 556 focused tests and the expanded domain gate; paired token estimates and latency tradeoffs are recorded in experiments/analysis-efficiency/managed-cli.md.
2026-10-22 00:43:30 +00:00
xjh 14c4c2a1d7 fix(managed): preserve observed method header differences (#3814) 2026-10-22 06:12:55 +08:00
JANG BYUNGKUNandgensokyo-dev 833136507d feat(il2cpp): inventory Unity IL2CPP global-metadata images, types and methods (#3807)
* feat(il2cpp): inventory IL2CPP global-metadata images, types and methods

Add inspect_il2cpp_metadata (CLI inspect-il2cpp-metadata), a read-only
in-process decoder for unencrypted Unity global-metadata.dat version 39.
It reports header sections, serialized index widths, images, type
definitions (nesting from the nestedTypes section) and method names.

Unrecognized magic and other versions are unsupported; damaged headers,
overlapping sections, inconsistent record sizes, out-of-range indices and
invalid strings fail with a reason code and no partial success. MCP
detail summary retains the complete Evidence and pages rows through
inspect_analysis_view kind il2cpp-metadata.

Adds an opt-in verify:il2cpp:metadata -- --metadata PATH check.

* feat(il2cpp): deliver metadata summaries by default over MCP

A 112,232-method file produced a 10.5 MB complete response, above the
10 MiB stdio budget. Default MCP delivery is now the retained summary;
detail complete stays available, and the one-shot CLI requests it.

* fix(il2cpp): reject shifted strings, nesting cycles and method owner drift

Review fuzzing showed that moving the strings section offset by one byte
silently renamed every image, type and method. Name indices must now start
a string, which also bounds total decoding by the section size.

Nesting cycles and methods whose declaring type disagrees with the owning
type range are rejected instead of returned. Adds service, shutdown and
index-width coverage, and moves environment-specific measurements out of
the public guide and tool description.

* feat(il2cpp): decode global-metadata versions 29 and 31

Unity 2022.3 writes version 29 or 31 metadata: a 256-byte header of
(offset, size) pairs, fixed 4-byte indices, type records with
elementTypeIndex, and method records that gained returnParameterToken in
version 31. Record counts come from section sizes and must be whole.

Sections report a null count for these versions and index widths report
fixed-width-version. Image, type and method rows keep the same shape, and
the string, nesting and method-ownership checks apply to every version.

* fix(il2cpp): bound report size before serializing and tighten coverage

Rows share decoded names, so a 130 KB file could expand into gigabytes of
JSON before the 64 MiB budget check, ending in an internal RangeError. The
provider now refuses from a lower bound on the serialized rows first.

The decoder also rejects non-empty sections inside the header, methods
outside their declaring type's range and overlapping image type ranges, and
keeps a leading byte order mark in names. Layouts now carry one indexing
mode instead of two coupled flags, and the tool description explains
nested_type_start.

* fix(il2cpp): refuse oversized metadata before decoding rows

Address review findings on the IL2CPP metadata inventory:

- check a lower bound from header row counts before any row object is
  allocated, so a large rejected file no longer builds every row first;
- validate sealed parent Evidence and count its rows once per report
  instead of on every inspect_analysis_view page;
- decode version 39 fixtures with 2- and 4-byte type-definition,
  generic-container and parameter indices.

* docs(il2cpp): attach the decoder comment to readIl2cppMetadata

* fix(il2cpp): deliver complete rows by default like the other inspection tools

inspect_il2cpp_metadata defaulted to detail summary, the only inspection
tool to do so. Omitted detail now returns every row inline, as
inspect_artifact, decode_interface_builder and the capture tools do;
summary stays one argument away and the guide, CLI reference and skill
reference say to select it first for large games, whose complete MCP
delivery is refused at the stdio budget with retained Evidence.

* test(il2cpp): cover narrow-width -1 sentinels and fix the skill's default

An empty image stores its type start as the all-ones value of a one- or
two-byte index; the decoder reads it as -1, but no fixture exercised it,
so removing either conversion passed the suite. The fixture can now append
an empty image, and both widths decode it. The skill still described a
summary default; it now says to select summary first, as the guide does.

* docs(il2cpp): request summary explicitly in the summary example

* chore(il2cpp): hash the verifier metadata through owned file resources

* fix(il2cpp): count escaped name length without building the escaped string

* fix(il2cpp): keep the verifier's check failure and small-table last page

* feat(domain): count JSON string length without building the escaped string

* fix(il2cpp): keep descriptor cleanup owners and share the JSON length count

* test(domain): give the backslash case real backslashes

* fix(il2cpp): select the CLI path and finish the command like the other tools

Follow main's absoluteCallerPath (#4067) and pass the command signal to finishAnalysisCommand.

* fix(il2cpp): select the verifier input path like the CLI

Use absoluteCallerPath (#4067) so a path with a symlink followed by .. names the same file the CLI and MCP inspect.

* feat(il2cpp): add compact composable metadata queries

Retain source-indexed Evidence for filtered batch and field queries. Bound representation growth before serialization, yield decoding for cancellation, and share CLI Evidence publication with desktop inspection. Verify public Unity metadata against independent byte and managed-DLL oracles and exercise actual stdio SDK workflows.

* fix(il2cpp): retain the validated metadata header magic

* test(il2cpp): remove obsolete execution wording exception

* fix(artifacts): preserve export selection and completed source facts

---------

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-10-20 07:20:47 +08:00
Ysopwnable 2b5ee72d26 feat(ghidra): admit ARM PE targets on Windows (#3965)
Admit Windows ARMNT/Thumb-2 and ARM64 PE targets using preserved COFF machine facts. Keep unsupported machine gates explicit and distinguish loader-selected versus configured language provenance.

Verified with real Windows Ghidra 12.1.4 CLI/MCP workflows, ARM fixtures and Microsoft-signed Coreinfo ARM64 / MSVCR120 ARM inputs. Resource limits, analyzer overrides, startup timeout observations and verification gaps are documented in the PR. Final CI and automated review passed.

Fixes #2186
2026-10-15 20:11:26 +08:00
1438422dfe fix(managed): preserve enclosing identity in member comparisons (#3079)
Keep same-named nested members paired by their source-owned enclosing identity, including selected inventories that omit the parent TypeDefs. Share the cached, bounded nominal type-name digest owner with signature resolution; preserve current unknown identity through matching, remapping and absence instead of repairing it with display names or historical compatibility.

Verification: 457 related tests passed after preserving TypeDef visibility/parent applicability and coherent fixtures; the complete static/architecture gate and real pinned-SDK MCP nested/official .NET DLL workflows passed after a sigrok-experiment-only main refresh. Documentation checks passed after the compatibility fix. Full CoreLib inspection retains the pre-existing explicit representation limit. No target assembly execution; local verification used two CPUs and an 8 GiB RSS guard.

Co-authored-by: 8rulerstar <190670431+8rulerstar@users.noreply.github.com>
Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
2026-10-14 23:20:07 +08:00
eab789aed7 fix(managed): compare nominal signatures across metadata builds (#3059)
Compare managed member signatures using bounded, framed nominal type identities rather than build-local metadata row numbers. Preserve unresolved and historical evidence semantics, and share TypeRef, nesting and member-list facts at their producing boundaries.

Validation: current-head CI and Greptile pass; all 435 related managed tests pass. Genuine Microsoft .NET DLL CLI comparison and bounded SDK MCP paging pass without modifying targets. A local CLI filter deadline also fails on clean main; no unrelated timeout or product change is included.

Co-authored-by: JayOfTheKeyboard <140487034+JayOfTheKeyboard@users.noreply.github.com>
Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
2026-10-14 21:16:48 +08:00
morluto 3f6b5755b3 fix(managed)!: share member list facts and retain verification uncertainty
Parse TypeDef member lists once at their owning boundary, retain malformed ranges as unknown, and admit representation storage before allocation. Reuse parsed facts across member ownership, inventory, attributes, and native boundaries. Preserve constant operands in structural matching.

Refs: #3202, #3201, #3199

BREAKING CHANGE: unresolved managed/native verification results may retain a non-null matched_native and candidate facts when module identity is unknown. Consumers must use status and reason rather than assume unresolved observations are empty.
2026-10-14 17:49:18 +08:00
Kaoru0822andClaude Opus 5.5 7484401601 perf(managed): add retained member summary and pages (#3061)
* perf(managed): add retained member summary and pages

inspect_managed_members always returned the assembly-wide member_refs, so
one selected or unmatched type produced megabytes, and an unselected
ordinary assembly exceeded the MCP response budget. Add opt-in
detail: "summary" that retains the complete Evidence and returns identity,
selection with unmatched names, coverage, user-string coverage, limitations
and per-collection counts. Page original rows through inspect_analysis_view
with kind managed-members; each page names its collection so no row schema
is chosen by union order. Complete delivery stays the default.

Refs #3010

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* perf(managed): validate a sealed member parent once across pages

Each managed-members page reparsed the whole parent report, about 35 ms
for an 18 MB assembly result regardless of the page size. The analysis
view service now reports whether the parent Evidence is a sealed
snapshot, and the member view reuses the validated report for that
sealed result through a weak reference. Unsealed input is still
validated on every call.

The round-trip test fixture now carries an exported type, an ldstr
literal, a field access and a call edge, and requires every collection
to be nonempty so a row schema that drops facts cannot pass on empty
arrays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): keep delivery detail out of retained Evidence identity

Summary, omitted and complete delivery of the same managed inspection
now retain one parent record, as inspect_macho already does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 23:16:38 -07:00
Jeremy Levartovskyandmorluto 1ebbc3b371 fix(managed): pair members by declared identity before name-free remaps (#2116)
* fix(managed): pair members by declared identity before name-free remaps

The first matching round keyed methods on signature and normalized CIL,
and fields on signature, without the declared type or name. Identical
members of different types fell into one ambiguous group, so a file
compared with itself reported unknowns, and a lone match across types
was reported as an unchanged exact pair while the member's own
counterpart went unpaired.

Pair by declared type, name, and exact CIL/signature first, then by
declared type, name, and raw signature. The name-free CIL/signature,
field-signature, and structural rounds now run last, as remaps, and
skip a pair across declared identities while either member's own type
and name remain unpaired on the other side.

Nested types that share a bare name still share one declared identity,
so their identical members stay ambiguous in a self-comparison.

* fix(managed): keep members with kept identities out of remap rounds

The cross-identity check applied only to one-to-one groups. A member
whose own declared type and name were still unpaired on the other side
could fall into a larger remap group and be reported ambiguous, and a
blocked candidate could make an otherwise unique remap ambiguous.

A remap round now drops such members before grouping, along with
members whose declaring type is unresolved. Same-identity structural
pairs get their own round before the remaps. Each member's declared
identity is computed once.

Ambiguity limitations now name the evidence a group shares, which
stays true whether the round keyed on names or not.

* fix(managed): keep names in unresolved identities and hold ambiguous ones

A member of an unresolved declaring type had no declared identity, so
the declared-identity rounds keyed it by CIL or signature alone. Two
unresolved members with different names paired as an exact match, and
a file compared with itself reported unresolved members ambiguous.

The declared identity now always includes the name, with a null type
for an unresolved one. Remap rounds still leave such members out.

A remap round now also leaves out a member whose own identity sits in
an ambiguous group on the other side, not only one left one-sided.

The undecoded-counterpart check uses the same declared identity.

* fix(managed): keep remap groups with unresolved owners ambiguous

Remap rounds dropped members of an unresolved declaring type before
grouping. Such a member can be another member's own counterpart, so a
resolved member could remap to a copy in another type while its
unresolved counterpart was reported added.

Unresolved members now join remap grouping, and a group that contains
one stays ambiguous instead of pairing.

The undecoded-counterpart set reuses each member's computed identity.

* fix(managed): keep ownerless members out of declared rounds when shared

A member whose declaring type did not resolve has a declared identity
of a null type and its name. The declared rounds paired two such
same-named members even when the other side also held a resolved
member with the same CIL and signature, which could be the owner. The
old name-free first round reported that group as ambiguous.

An ownerless member now enters the declared rounds only when no other
member on either side shares its exact CIL/signature key, and never
the declared structural round. Otherwise it reaches the remap rounds,
which keep any group with an unresolved member ambiguous.

* fix(managed): keep competitors of an ownerless member out of the declared round

When an ownerless member shares its exact CIL/signature key with another
member on the same side, its owner may be that member. The resolved
members holding the key now stay out of the declared round too, so they
cannot pair and consume the candidate the ownerless member may own, and
the remap round keeps the whole group ambiguous as main does. A lone
ownerless member still pairs with its lone counterpart.

* test(managed): split the ownerless comparison tests under the function length limit

The ownerless describe block reached 181 lines, past oxlint's
max-lines-per-function limit of 150. Move the structural-competitor
case into its own block.

* fix(managed): contest signatures and remap only open candidates

* fix(managed): retain blocked raw-signature choices as unknown

* fix(managed): keep member names in signature contention

* fix(managed): scope residual signature contention by name once

ownerlessContested applies competitionIdentityKey itself, but
unresolvedSignatureAmbiguities passed it keys that were already
name-scoped, so the contested set never matched the groups and the
same-signature, different-body case reported additions and removals
instead of one unknown group. Pass the raw signature key.

* fix(managed): constrain matchObserved to declared members

matchObserved passes its items to matchByKeys, which needs Declared, so
its looser { declaring_type } bound failed typecheck (TS2344, TS2322).

* fix(managed): retain held ownership contention for residual matches

* fix(test): bind workspace fixture in Hopper launch cases

* fix(ci): prepare worker tests and preserve Hopper cleanup ordering

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-14 06:36:43 +08:00
Devulapalli Naga Sri Vaishnavi a9195c3a98 fix(managed): retain raw CIL changes in member comparison (#2912) 2026-10-14 03:07:12 +08:00
26525706fc feat(managed): decode ldstr user strings in member inspection (#2162)
* feat(managed): decode ldstr user strings in member inspection

inspect_managed_members reported every ldstr operand as a bare 0x70 token,
so an analyst could see that a method loads a literal but not which one.
Answering "where is this path or key used" required a second tool.

Read the optional #US stream and add a top-level user_strings inventory:
each distinct token loaded by an inspected method body, once, in token
order, with its #US file offset and decoded UTF-16 value. Instruction
anchors and normalized CIL digests keep their build-local tokens. A missing
#US stream or malformed item is reported against its token as partial
coverage. Evidence recorded before this field reads user_strings as null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): collect user strings only from ldstr

A malformed ldtoken can carry a 0x70 token, which the operand decoder
classifies as a string operand. Only ldstr loads a literal, so collect
user strings by opcode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): admit user-string tokens and failures before collecting them

Charge each distinct ldstr token to the decode budget before adding it to
the collection set, and admit each #US failure before retaining it. A
missing #US stream is now one stream-level issue rather than one per
token.

Document why the #US terminal flag is not validated: Mono and Roslyn
assemblies disagree with ECMA-335 II.24.2.4 and the runtime ignores it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(managed): describe missing #US reporting and the unvalidated flag byte

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(managed): cover #US items that run past the stream end

An odd length whose payload crosses the end of #US, and a two-byte
length prefix that starts on the last #US byte, are both rejected as
"User string leaves #US" beside a readable literal. The test fails if
that bounds check is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): report reserved #US length prefixes as string failures

The compressed-length reader shared by #Blob and #US hard-coded
invalid-blob and "Metadata blob" for a reserved prefix, so a malformed
user string was published as a blob failure. The caller now names the
item it reads: #Blob keeps its code and message, and #US reports
invalid-string.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): append member inspection issues without argument spreading

inspectManagedMembersBytes gathered every producer's issues with
issues.push(...list), passing one argument per issue. A large malformed
input, such as hundreds of thousands of distinct bad ldstr operands or
MemberRef rows, overflows the stack with an untyped RangeError instead of
returning partial coverage. All six sites now use
appendManagedParseIssues, which appends one issue at a time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): classify truncated #US and #Blob length prefixes by item

A two- or four-byte compressed-length prefix cut off by the end of the
artifact went through the generic range check and was reported as
invalid-row. The prefix reader now uses the item's own code for both
reserved and truncated prefixes: invalid-string for #US, invalid-blob for
#Blob. The unused generic range helper is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): retain user-string terminal flag conformance issues

* test(managed): write ECMA-335 #US terminal flags and cover flag issues

d5b7b0704 reports a #US terminal flag that differs from ECMA-335
II.24.2.4. The fixture heap always wrote 0, so its non-Latin-1 literals
now read as nonconforming. The fixture writes the spec flag, and a new
test flips one flag each way ("ok" set to 1, "it's" set to 0) and checks
that both literals remain beside one issue each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): classify ldstr operands before collapsing a missing #US

With no #US stream, every collected ldstr operand was counted as a #US
reference and reported only as missing-stream, while the same non-0x70
operand got invalid-heap-index when the stream existed. parseUserStrings
now owns which operands are user-string tokens: any other operand is
invalid-heap-index either way, and only 0x70 tokens count toward the
missing-stream issue. The heap reader drops its duplicate kind check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): state user-string limits in member comparisons

compare_managed_members ignored user_strings, so a method whose ldstr
literal changed at the same token, or legacy Evidence that never examined
literals, could read as unchanged with no caveat. The comparison now adds
an unknown limitation when either side predates user strings and a
not-compared limitation when literals were observed. ExportedType and
user-string inventories share one uncomparedInventory rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(managed): advertise ldstr literals in member inspection help

The MCP tool description, the type_names input, and the CLI command and
--type help now say that inspect_managed_members returns the #US string
literals that ldstr loads, and that a type selection limits them to the
literals the selected types' method bodies load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): read the empty #US entry at offset 0

ECMA-335 II.24.2.4 makes the first #US entry the empty blob: a zero
length with no terminal flag byte. ldstr 0x70000000 loads it, but the
odd-length check rejected it as invalid-string, dropping the literal and
making coverage partial. Offset 0 with length 0 now reads as "".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): reserve #US offset 0 and admit literals before scanning

Offset 0 is the reserved empty #US entry, so a nonempty item there is now
invalid-string instead of a published literal. The literal's projection
is reserved before the terminal-flag scan, so an inadmissible item fails
at the budget without reading every code unit. The scan's loop index no
longer shadows the token's heap index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): report #US length prefixes wider than ECMA-335 assigns

compressedLength accepted an overlong encoding, such as 0x80 0x05 for a
5-byte item, without comment. It now reports whether the width is the
one ECMA-335 II.23.2 assigns, and the #US reader reports a non-minimal
prefix as an invalid-string conformance issue beside the readable
literal, like the terminal flag. readMetadataUserString returns every
issue it observes. #Blob behavior is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): check the #US length width before the empty entry

The offset-0 empty entry returned "" before the length-width check, so an
overlong empty entry such as 0x80 0x00 read as complete. The width issue
is now collected first and returned with the empty literal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): admit #US width issues only for returned literals

The overlong-prefix issue was reserved before the fatal shape checks, so
an item that then failed, such as 0x80 0x00 away from offset 0, leaked
512 bytes of budget per token. The width issue is now built and admitted
only on paths that return the literal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): keep #US issues out of member metadata status

User-string issues, including terminal-flag and length-prefix
conformance differences, marked metadata.status partial, so
compare_managed_members turned one-sided methods and fields into unknown
even though every member row was examined. #US issues now make coverage
partial while metadata.status describes the member inventory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): give user strings their own coverage

#US issues entered the member coverage, so every consumer that reads it
as member coverage (application graph member facts, comparison status)
reported examined members as partial over a literal conformance
difference. user_strings is now { state, literals, issues }: #US issues
live there and never change the member coverage or metadata.status.
parseUserStrings returns that inventory directly.

compare_managed_members inspects with user strings skipped, since it
never reads literals, so a large literal cannot exhaust the decode budget
of a comparison. Its limitations state once that literals are not
compared, and the ExportedType limitations return to their main form.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): mark user strings partial when a body is not fully decoded

With user strings owning their coverage, an inspected method body that
was partial, malformed, or truncated no longer reached their state, so a
literal after the decode stopped was missing from a "complete" inventory.
parseUserStrings now marks the inventory partial unless every inspected
body was fully decoded, keeping the literals it did observe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): mark user strings partial when a method row is omitted

A MethodDef row that failed before its body was read was recorded as an
issue and omitted, so its ldstr instructions were never scanned, yet the
user-string inventory could still read as complete. parseUserStrings now
takes the parseMethods result and stays partial whenever a method row
failed, as well as when an inspected body was not fully decoded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): count only method rows that may hide a selected body

Any parseMethods issue marked user strings partial, including an
unreadable name on a method outside the type selection, so a fully
scanned selection read as incomplete. parseMethods now reads each row's
owner first and reports unscannedRows: rows that produced no method while
their owner is selected or unknown. parseUserStrings uses that count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): treat unreadably named types as possibly selected

Under a type_names selection, a type whose name could not be read may be
a requested type, but its methods were skipped without counting toward
unscannedRows, so an unexamined body left user strings complete. A
method whose owner's name is unreadable now counts as possibly selected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): judge user-string scans by CIL decoding, not body status

body.status is malformed for an invalid exception section even when
every instruction decoded, so user strings read as partial although every
ldstr was examined. The body reader now reports whether its CIL was fully
scanned, independent of exception-region validity, and parseMethods folds
unscanned bodies and unproduced rows into one unscannedMethods count that
parseUserStrings uses instead of reinterpreting body.status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): stop deduplicating user-string issues

The inventory passed its issues through uniqueManagedParseIssues, which
serializes every issue into an unbudgeted map: about 42 MB of heap and
113 ms for 125,000 issues on Node 24. The issues are unique by
construction (one failure or per-offset conformance issues per distinct
token, one missing-stream issue), so the inventory now returns them, and
its literals, without copies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): preserve selected string coverage unknowns

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-14 03:01:23 +08:00
pablodiazjorgeandpablodiazjorge 75e7965dc3 docs(nativeaot): document the verified Windows-host parser route (#2497)
Squash merge of https://github.com/morluto/rea/pull/2497.

Co-authored-by: pablodiazjorge <pablodiazjorgegarcia@gmail.com>
2026-10-13 23:48:41 +08:00
91830f1e0e feat(managed): name the declaring type of call and field targets (#2163)
* feat(managed): name the declaring type of call and field targets

Call edges named external targets by member name alone (Join, ToJson,
WriteAllText), and method-spec edges had no name at all, so an analyst could
not tell which library a method calls or find every use of a type without a
decompiler. Field accesses through MemberRefs had no name either.

Name each TypeDef, TypeRef, and generic-instantiation TypeSpec once, in the
namespace-qualified form TypeDef full_name uses, and add member_refs
parent_name, call_edges target_declaring_type, and field_accesses
field_declaring_type. A method-spec target reports the generic method it
instantiates. Fields, member references, methods, and method specs now
resolve through one token-keyed MemberCore lookup instead of three maps.
Evidence recorded before these fields reads them as null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): validate spec blobs and member kinds before naming targets

Address review findings on declaring-type naming:

- A generic instantiation must name a TypeDef or TypeRef, so a TypeSpec
  base is reported as malformed instead of followed. Naming no longer
  recurses.
- TypeSpec and MethodSpec instantiation blobs are decoded with the
  member-signature grammar. Malformed blobs and out-of-range TypeDef rows
  are reported against their owning row and make coverage partial.
- A MethodSpec reads both columns. An invalid Method coded index is
  reported; a readable Method keeps its name beside a malformed
  instantiation.
- MemberCore carries its signature kind, so a field operand is named only
  by a field or field-signature MemberRef. This replaces the token-table
  guard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): validate MethodSpec arity and report unsupported spec blobs

- A MethodSpec now checks that its method signature is generic and that
  the instantiation supplies as many type arguments as it declares. A
  non-generic target, a field reference, or a count mismatch is reported
  as invalid-row; the readable method keeps its name.
- Unsupported TypeSpec and MethodSpec forms raise an owner-scoped
  unsupported-signature issue instead of reading as an intentional
  unknown.
- MethodSpec reading moves to ManagedMethodSpecs.ts, and its tests get
  their own describe block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): reject non-method signature headers and invalid TypeRef scopes

The method signature header reader now owns the calling-convention rule
that only FNPTR applied: FIELD, LOCAL_SIG, PROPERTY, and GENERICINST
headers, the reserved bit, and EXPLICITTHIS without HASTHIS are malformed.
A MethodSpec whose method has a PROPERTY header is no longer accepted as a
generic method, and member signatures with such headers no longer decode
as methods.

The type-name lookup validates a TypeRef's ResolutionScope coded index and
reports an out-of-range scope as invalid-row, keeping the readable name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): hold member rows to MethodDefSig and FieldSig headers

Method signature headers are now checked in context. MethodDef and
MemberRef rows accept only the MethodDefSig/MethodRefSig headers: DEFAULT,
VARARG, or GENERIC with DEFAULT. FNPTR keeps the unmanaged conventions
compilers emit for function pointers. A field signature must be exactly
FIELD, so a flagged FIELD header is malformed and never names a field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): accept MethodSpec arity only from a fully decoded signature

The arity check read only the target's signature header, so a truncated
generic method signature passed. Under type selection a MethodDef target
outside the selection is never decoded elsewhere, so coverage stayed
complete. The arity now comes from a transient full decode, and only a
decoded method signature supplies it. signature() keeps its raw length
and digest around the shared decodeSignature.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* perf(managed): decode each MethodSpec target signature once

edgeTargets caches the generic arity, including a failed decode, by
target method token, so many instantiations of one generic method share
a single signature decode. Unity.InputSystem has 472 distinct MethodSpecs
over about 133 target methods.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): validate spec type operands and transitive reference scopes

* fix(managed): retain readable names when a scope row is unreadable

* test(managed): pin owner-scoped spec operand and scope-chain checks

e59217c83 validates spec type operands inside specSignature, so a
malformed generic TypeSpec base is now invalid-row under its owning
TypeSpec row; the three stale expectations follow that. New cases cover
a TypeSpec argument and a MethodSpec argument that name a missing TypeRef,
and a TypeRef whose ResolutionScope names itself. The scope cases move to
their own describe block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): keep field targets from naming MethodSpecs

A MethodSpec over a field-signature MemberRef inherited kind "field", so
an ldsfld on that MethodSpec published a field name and declaring type
for malformed IL. A MethodSpec now borrows its target's name only when
the target is not a field; the arity check still reports it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): reuse owner-decoded signatures for MethodSpec arity

MemberRef signatures, and MethodDef signatures in the type selection, are
already fully decoded, but the MethodSpec arity check decoded them again
and admitted a second transient allocation, which could exhaust the
budget. MemberCore now carries the owner's genericArity, and only a target
nothing decoded, such as an unselected MethodDef, falls back to the raw
signature. signatureGenericArity is the one rule for both paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:12:15 +08:00
Ysopwnableandfactory-droid[bot] a86deecac5 fix: align MCP archive contracts and documentation (#2478)
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>
2026-10-13 12:06:41 +08:00
Ysopwnableandfactory-droid[bot] 82cfcee19f feat(managed): add retained metadata overview and pages (#2413)
Add caller-selected managed metadata summaries and original collection pages while preserving complete CLI/MCP defaults and previous-runtime Evidence. Real SDK replies shrink substantially; actual Codex token/latency results remain mixed and are documented without a token-saving claim.

Validated focused SDK/domain tests, full static/docs checks, real two-assembly repeated workflows and portable old Evidence, real SQLite WASM, and all exact-head CI checks. Raw experimental artifacts remain private.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-10-13 07:41:20 +08:00
Ysopwnableandfactory-droid[bot] 7ae3c50a9d docs: correct drift and reorganize English guides (#2207)
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>
2026-10-12 22:14:25 +08:00
morluto 98d8470d36 fix(io): consolidate managed snapshots and retain cleanup ownership
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.
2026-10-12 14:46:37 +08:00
a149d183ef feat(managed): select declaring types in inspect_managed_members
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>
2026-10-12 08:31:37 +08:00
fb43dd9716 fix(managed): honor metadata ExtraData before table decoding (#1893)
Co-authored-by: LouisChen <3361008+chqcjq@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-12 02:28:22 +08:00
LouisChenandLouisChen a95795c6ed fix(managed): resolve member ownership through pointer tables (#1886)
Co-authored-by: LouisChen <3361008+chqcjq@users.noreply.github.com>
2026-10-12 01:40:48 +08:00
Kaoru0822andClaude Opus 5.5 ed1519ddee fix(managed): report ExportedType rows in managed member inspection (#1828)
* fix(managed): report ExportedType rows in managed member inspection

Facade assemblies such as System.Runtime.dll provide their types only
through ExportedType rows (type forwarders), which member inspection
never read, so they reported complete coverage with no types. Report
each row as declared with its flags, forwarder bit, TypeDefId hint, and
implementation token, and record invalid or null implementation coded
indexes as partial coverage. Comparisons now state that exported types
are not compared when either side has them.

Fixes #1812

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): read earlier member Evidence without exported types

Member Evidence recorded before ExportedType rows were read omits the
field. Parse it as null (not examined) instead of rejecting it, and
state in comparisons that such an observation's exported types are
unknown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): leave exported types unknown when metadata is unavailable

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 07:02:16 -07:00
AlexandAC 81dc64e3cd fix(managed): distinguish .NET Standard targets from runtimes
Preserve .NET Standard as an API compatibility target while leaving the runtime family unknown unless independent markers identify it. Keep real DLL metadata and existing runtime-marker precedence intact.

Closes #1736.

Co-authored-by: AC <ac@fabtek.cn>
2026-10-11 15:32:22 +08:00