Resolve fields, methods, and attribute constructors through one budgeted index per layout. Preserve malformed-list first-match ownership without per-member TypeDef scans; remove the superseded lookup implementations.
Validate pointer identity and malformed ranges through production parsers, including a 40,000-type/method case and allocation admission. Managed source tests and CLI/MCP pointer acceptance pass. Refs #1953.
Each CustomAttribute whose constructor is a local MethodDef scanned the
TypeDef table to find the declaring type, so inspect_managed_artifact did
O(attributes x types) row decoding. A 584 KB assembly with 16,000 types
and 16,000 such attributes blocked for about 38 s.
Build a first-match owner index once per metadata layout. Already-owned
list positions are skipped, so overlapping malformed method lists keep
their previous first-match owner in near-linear time. The index is
charged to the decode budget, and a build failure is cached like the
member pointer lookup.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Charge fixed row bookkeeping once per table and row within an admitted
metadata layout. Repeated owner lookups no longer permanently consume
capacity for temporary cursors; distinct rows and failed admissions retain
the existing representation limit and typed failure behavior.
Verify repeated local attribute-constructor lookups through public CLI
metadata/member inspection and preserve the remaining capacity guards.
Closes#1878
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): decode generic, array, fnptr, and modifier signatures
Member signatures using GENERICINST, ARRAY, FNPTR, CMOD_REQD/CMOD_OPT,
or TYPEDBYREF were reported as unsupported, leaving their types unknown
and turning otherwise complete inspections partial. Decode them with an
explicit stack so nested signatures stay recursion-free, keep encoded
TypeDefOrRefOrSpec values, and report malformed shapes as malformed.
Fixes#1832
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): bound array rank before rendering dimensions
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): keep modifier order and reject non-method fnptr headers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): reject corrupt fnptr flags and misplaced typed references
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(managed): decode signature elements by grammar position
Track whether each element is a field type, return type, parameter,
nested Type, or pointee. VOID is valid only as a return type or
pointee, TYPEDBYREF only as a return type or parameter, and BYREF only
at the top of a return type, parameter, or ref field; other placements
are malformed. Function pointer items are parsed as a return type then
parameters, and generic arguments as Types.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* 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): charge retained member facts instead of decoding bounds
inspect_managed_members returned no types or methods for ordinary
assemblies: Newtonsoft.Json 13.0.3 (netstandard2.0, 705 KB) exceeded
the 64 MiB representation budget. Each method body reserved 256 bytes
per IL byte and each signature 256 bytes per blob byte before decoding,
and those worst-case bounds were never returned, so the budget scaled
with total IL size rather than with the retained output. The final
projection admission also charged every decoded string at six bytes per
character and every scalar at 32 bytes, about eight times its JSON size.
Bound IL, exception-clause and signature decoding with a transient
admission that does not consume capacity, then reserve the decoded body
or signature that is actually retained. Projection admission now
charges the exact UTF-8 JSON bytes of decoded strings, keys and scalars;
escaped and multibyte text still counts at its encoded size.
Newtonsoft.Json now yields 496 types, 4185 methods and 18846 call
edges. Assemblies whose retained facts exceed the budget, such as the
2.3 MB System.Private.ServiceModel 4.7.0, remain unavailable.
* fix(managed): bound concurrent decoding and count JSON bytes in place
Review follow-up. A method's IL bound and its exception-section bounds
were each checked against the same remaining capacity although their
bookkeeping is live at the same time, so 40 MiB of IL plus 40 MiB of
exception clauses passed a 64 MiB budget. Transient admissions now
accumulate until the method body or signature is built, and reserve
respects bounds that are still live.
Projection admission also serialized each decoded string to measure it,
which could allocate about six times a near-limit string before the
check. It now counts the exact escaped UTF-8 bytes without building the
JSON text.
* fix(managed): admit derived call and field edges as they are built
Review follow-up. Released IL bounds no longer stand in for the call and field-access records that edges() derives from anchors. Each record is now admitted before the graph grows further, so a crafted assembly cannot materialize the whole derived graph before the representation guard fails.
* fix(managed): admit derived caller names before building them
Review follow-up. The caller name of call and field-access records was interpolated per anchor before any admission saw it. It is now built once per method, after its exact JSON size, counted from the type and member names, has been admitted.
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(build): emit no runtime imports for type-only bindings
Under verbatimModuleSyntax, an import whose specifiers all carry inline
`type` modifiers compiles to `import {} from "..."`, a side-effect import
that still resolves and evaluates the module. 78 compiled modules carried
one, including `import {} from "playwright-core"` in the browser scenario
session, which loaded Playwright's module graph at MCP startup.
Use top-level `import type` for these bindings and enable oxlint's
typescript/no-import-type-side-effects rule so the pattern cannot return.
Refs #1685
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* perf(mcp): load Playwright when a scenario launches, not at startup
The browser scenario and Electron active providers are constructed before
the stdio server serves, and both bound Playwright's launchers at module
load. Resolve `chromium` and `_electron` from playwright-core when a
capture opens instead, as the web module resolver already does.
MCP startup now resolves 1,312 modules (4,902 resolutions) instead of
1,598 (6,076) before reading the first request, and no longer loads
playwright-core. Provider construction, the tool catalog, and capability
inventory are unchanged.
A boundary test spawns the stdio server, initializes, lists tools, and
asserts playwright-core and isomorphic-git were not resolved; the CLI
probe now exercises the real launch path to prove detection.
Closes#1685
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Use the shared resolver for virtual containment, overlap checks, and file-backed extent. Raw alignment padding no longer supplies method bytes or shadows a later virtual section. Preserve malformed body coverage and suppress CIL hashes outside the admitted range.
Verify zero, exact-end, truncated-body, padding, and true-overlap cases through compiled CLI and MCP consumers. Synthetic PE fixtures only; no Windows loader or real managed-provider verification.
Fixes#1596. Supersedes #1595.
Remove forwarding wrappers and shadow aliases, migrate callers and verification scripts to their owners, and share one exhaustive semantic resource-bound projection.
Deliver complete Evidence directly through MCP with required nullable analysis profiles and immutable per-server delivery settings. Bind selected environments at construction and require typed cleanup outcomes with retained retry ownership.
Remove test-only routing, duplicate session and snapshot metadata, producer-field repairs, and ambiguous provider arguments. Separate artifact byte identity from occurrence classification and retain typed source-map and partial native facts across CLI, MCP, and verifier consumers.
BREAKING CHANGE: obsolete Evidence envelopes, session aliases, incomplete snapshots, and missing normalized producer facts are no longer accepted.
When the CLI header parsed but its metadata could not be admitted, the
native-boundary fallback reported hard-coded false flags and zero header
values. A corrupt-metadata ReadyToRun image therefore appeared IL-free
and non-native. The fallback now reports the parsed CLI header and
derives the summary from it as the full inspection does. When the CLI
header itself is unreadable, a limitation says the values are defaults.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`inspect_managed_native_boundaries` wrote the PE classification
(`not-managed` or `malformed`) into `coverage.state`, which accepts only
`complete`, `partial`, or `unavailable`. Its own result validation then
threw, so every native DLL and every PE with unreadable CLI metadata
failed as a generic execution failure advising a retry. The sibling
artifact and member inspectors succeed on the same files.
Report these files with `unavailable` coverage, as the member inspector
does, keeping the metadata status and parse issues.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(domain): split error taxonomy into thematic modules
Move each error family out of domain/errors.ts into its own module
(base, core, provider selection/adapter, browser observation,
artifact, evidence, unknown registry, hopper, configuration) and
relocate AnalysisErrorProjection to analysisErrorProjection.
Migrate all 162 importers to the owning modules and delete
errors.ts. No re-export shims; behavior is unchanged.
* refactor(runtime): name all silent catch causes without changing diagnostics
Bind cause in every bare catch and unhandled rejection across src/.
Real failures preserve the cause for logging; best-effort cleanup
carries an explicit comment. Caller-visible and Evidence strings are
byte-identical to before.
Move each error family out of domain/errors.ts into its own module
(base, core, provider selection/adapter, browser observation,
artifact, evidence, unknown registry, hopper, configuration) and
relocate AnalysisErrorProjection to analysisErrorProjection.
Migrate all 162 importers to the owning modules and delete
errors.ts. No re-export shims; behavior is unchanged.