56 Commits
  • 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
  • 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>
  • 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>
  • 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.
  • 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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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.
  • 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>
  • 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>
  • 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>
  • fix(managed): budget decoding before representation expansion
    Validation: integrated changes passed formatting, typecheck, lint, resolved module-boundary verification and git diff --check. Tests and real-provider workflows were not run.
  • fix(build): make catalogs and packaged skills generated outputs (#1086)
    * fix(build): generate catalogs and packaged skills without snapshot commits
    
    * fix(build): point skill drift recovery to uncached generation
  • fix(dotnet): treat ambiguous undecoded members as possible counterparts
    An undecoded member in an ambiguous exact-signature group stays unpaired,
    like a one-sided member, but the counterpart check considered only
    one-sided members. A decoded member with the same declared type and name
    on the other side was therefore reported as removed or added. Ambiguous
    candidates now count as possible changed counterparts too.
    
    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
  • fix(dotnet): keep a decoded member unknown beside an undecoded counterpart
    A field that changed from a decodable to an undecoded signature was
    reported as removed on the decoded side and unknown on the other. The
    undecoded member with the same declared type and name may be that field
    with a changed signature, so its decoded counterpart is now unknown too,
    with a counterpart-signature-not-decoded limitation.
    
    The compare_managed_members description now names the exact declared
    type, name, and raw signature tier and the undecoded handling.
    
    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
  • docs: clarify NativeAOT scope and regenerate conformance ledger
    Documents NativeAOT as a native-analysis route with format/architecture limits, keeps the skill DOS-guide link inside the installed bundle convention, and regenerates the managed conformance manifest.
  • fix: integrate 14 approved fix PRs (668,671,673,675,678-681,685-690) (#705)
    * fix(javascript): preserve array index positions
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(javascript): respect object property overwrite order
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * test(javascript): cover uncertain spread discriminants
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(javascript): keep nonfinite values outside JSON lattice
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(dotnet): keep non-CIL method implementations unknown
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * test(package): separate CIL reconstruction from native imports
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(javascript): invalidate values on nontrivial binding writes
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(artifacts): align native DMG mount and detach lifecycle
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(browser): retain all literal worker import arguments
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(native): preserve final demangled symbol whitespace
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(dotnet): preserve C identifier underscores in native matching
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(browser): respect metadata key and overwrite semantics
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(javascript): keep optional parameter input unknown
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(dotnet): report observed method metadata changes
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * docs(dotnet): synchronize generated conformance skill digest
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(browser): reject malformed indexed source-map offsets
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * fix(native): preserve numeric-looking Mach-O identifiers
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    
    * docs: regenerate catalogs for integrated fix batch
    
    * docs: regenerate catalogs after merging main (#702)
    
    ---------
    
    Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
    Co-authored-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
  • fix!: repair boundary contracts across CLI and MCP (#597)
    * fix(comparisons)!: preserve unknowns across partial observations
    
    Share absence and digest semantics, keep unobserved managed bodies unknown, and match unique managed type/name/signatures before structural fallback.
    
    BREAKING CHANGE: Managed comparison metadata adds exact-signature matching and its count, and name_matching now reports exact-signature-fallback.
    
    * fix(javascript): preserve projected result binding semantics
    
    Share syntax-aware property reads and assigned-result resolution. Retain destructuring paths and downgrade downstream whole-result relationships instead of resolving nested or wrapped calls as aliases.
    
    * fix(native)!: admit complete parser values and preserve typed failures
    
    Decode Mach headers by named columns, validate complete slice keys and lipo alignment, and preserve codesign runtime flags and tagged parser errors. Rename the Ghidra test dossier fixture and connect fake-backed suites to real verification lanes.
    
    BREAKING CHANGE: Native load-command results no longer contain the unused, always-null file_offset field.
    
    * fix(process): preserve host identity and actionable boundary failures
    
    Thread selected platform and environment through process and Doctor seams, stamp observed producer identity in Evidence, and retain PTY, filesystem, lease and lazy-provider failure causes. Drain cancelled lazy loads and omit exited descendants from verified lineage.
    
    * fix(browser): preserve cleanup and document-transition evidence
    
    Make V8 and Playwright teardown cancellation-aware, expose primary failures alongside incomplete cleanup, share frame-tree and navigation rules, and clear stale WebMCP registrations without pruning unrelated child frames.
    
    * fix(adapters): align managed targets and typed CLI outcomes
    
    Inspect managed PE/CLI targets independently of native provider selection, reuse successful managed selections, and keep evidence bound to the actual inspected target. Classify canonical CLI error envelopes and exhaustive setup/update/uninstall outcomes, audit registered CLI coverage, and assert platform-specific runtime results.
    
    * docs: refresh boundary contracts and shipped roadmap behavior
  • refactor!: simplify runtime tools and remove replay engines (#572)
    * fix(hopper): report unavailable procedure body coverage
    
    * refactor!: simplify runtime tools and remove replay engines
    
    Keep direct inspection, capture, and comparison tools. Bind handlers to named contracts and let agents compose experiments with commands and local fixture servers.
    
    BREAKING CHANGE: Remove controlled replay, Node characterization, finite replay-machine, managed runtime planning, and redundant string-tracing tools. Retire process replay, shims, reactive scenarios, custom checkpoints, and active browser replay and origin-scope inputs.
  • fix(tools)!: simplify direct invocation and harden boundary contracts (#555)
    Remove REA permission grants, scope ceilings, approval confirmations, and inert settings. Preserve selected local evidence, accept caller-chosen commands and paths, and report actual runtime failures.
    
    Harden provider results, schema serialization, snapshot evidence binding, archive paths, source maps, native screenshots, managed EH parsing, and cancellation cleanup. Regenerate tool metadata and document direct invocation.
    
    BREAKING CHANGE: Removed permission configuration and policy commands, approval fields, filesystem scope inputs, and fixed confirmation options. Process capture inherits the host environment and accepts command names; callers must refresh tool schemas and migrate removed fields.
  • feat(dotnet): verify managed native boundaries
    Add the verify_managed_native_boundaries workflow for comparing authenticated inspect_managed_native_boundaries Evidence with supplied native export or function Evidence. The workflow verifies only P/Invoke declaration names against observed native symbols, keeps verified, inferred, contradicted, unresolved, and unsupported-native states explicit, and does not translate managed metadata tokens or RVAs into native addresses.
    
    Expose schema-identical MCP and CLI surfaces, update managed workflow contracts, product catalog facts, TypeDoc output, README/localized docs, ADR status, package verification, and the REA analysis skill metadata for the 90-tool/50-command inventory.
    
    Verification: npx vitest run tests/managedNativeVerification.test.ts --coverage=false; npm run typecheck; npm run docs:generate; npm run check (first run hit a load-sensitive sessionMcp timeout, isolated rerun passed); npx vitest run tests/sessionMcp.test.ts --coverage=false; npm run check; npm run knip; npm run jscpd; npm run scan:todos; npm run verify:managed; CXX=/usr/bin/g++-13 CC=/usr/bin/gcc-13 npm run verify:package.