Merge pull request #300 from morluto/agent/docs-managed-normalized-cil-v1

docs(managed): align normalized CIL claims with shipped v1 semantics
This commit is contained in:
N0zoM1z0 2026-07-17 23:08:28 +09:00 committed by GitHub
commit 9a92a7958c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 183 additions and 48 deletions

View File

@ -358,7 +358,7 @@ REA is already useful for native application, browser, and Electron investigatio
- Reconstruct bounded static package, entrypoint, Webpack/Rspack module, import, worker, endpoint, storage, source-map, BrowserWindow, preload, contextBridge, IPC, utility-process, and native-add-on structure from an approved local directory or ASAR through `analyze_javascript_application` or `rea analyze-javascript-application`. The AST-only [application service](docs/javascript-artifact-reconstruction.md) never executes bootstrap code, pairs only unique exact literal IPC channels, and reports dynamic or ambiguous channels as unresolved.
- Reconcile that static graph with existing passive web or Electron Evidence through `reconcile_javascript_runtime` or `rea reconcile-javascript-runtime`. Exact captured bytes outrank caller-declared file/URL mappings; target, frame, script, worker, cache, and asset ambiguity stays explicit, source-map authority stays separate, and a module resident in an observed bundle is never reported as executed. See [JavaScript static/runtime reconciliation](docs/javascript-runtime-reconciliation.md).
- Trace a literal route, string, API, IPC channel, module, or native export through authenticated application Evidence with explicit traversal bounds, then hand exact native artifact digests and requested exports to retained Ghidra or Hopper Evidence without automatic provider switching. Compare application versions using unique-only digest, source-map, structural, and semantic tiers; duplicate, incomplete, and truncated matches stay unknown. See [cross-layer JavaScript application workflows](docs/javascript-application-workflows.md).
- Classify PE/CLI managed artifacts with `inspect_managed_artifact` / `rea inspect-managed-artifact`, inspect bounded metadata members, signatures, method-body CIL hashes, exception regions, call edges, and field-access anchors with `inspect_managed_members` / `rea inspect-managed-members`, inventory declared ModuleRef/ImplMap/PInvoke and non-IL method boundary indicators with `inspect_managed_native_boundaries` / `rea inspect-managed-native-boundaries`, then compare two authenticated member observations with `compare_managed_members` / `rea compare-managed-members`. `verify_managed_native_boundaries` / `rea verify-managed-native-boundaries` checks managed P/Invoke declarations against authenticated native export or function Evidence while keeping verified, inferred, contradicted, and unresolved states distinct. The comparison remaps build-local tokens using unique CIL/signature and structural method-shape tiers, never names alone. `project_managed_application_graph` / `rea project-managed-application-graph` projects authenticated managed artifact/member/native-boundary Evidence into the existing application graph for cross-layer feature tracing. `import_managed_reconstruction` / `rea import-managed-reconstruction` admits user-supplied decompiler C#/IL/pseudocode as analyst inference only after exact artifact SHA-256, MVID, signature, and normalized IL commitments match. Separately, `plan_managed_runtime_correlation` / `rea plan-managed-runtime-correlation` can admit a default-disabled, permission-gated runtime-correlation plan locked to the same build evidence. These paths never load the assembly, resolve CLR dependencies, execute target code, run a decompiler, or translate managed tokens into native addresses; native-body bridge mapping and an actual runtime executor remain future managed-code contracts.
- Classify PE/CLI managed artifacts with `inspect_managed_artifact` / `rea inspect-managed-artifact`, inspect bounded metadata members, signatures, raw CIL hashes, limited decoded-instruction-tuple v1 hashes, separately reported exception regions, call edges, and field-access anchors with `inspect_managed_members` / `rea inspect-managed-members`, inventory declared ModuleRef/ImplMap/PInvoke and non-IL method boundary indicators with `inspect_managed_native_boundaries` / `rea inspect-managed-native-boundaries`, then compare two authenticated member observations with `compare_managed_members` / `rea compare-managed-members`. `verify_managed_native_boundaries` / `rea verify-managed-native-boundaries` checks managed P/Invoke declarations against authenticated native export or function Evidence while keeping verified, inferred, contradicted, and unresolved states distinct. The comparison treats build-local tokens as build-local and uses unique decoded-CIL/signature and structural method-shape tiers, never names alone; the v1 tuple hash does not itself resolve tokens or fully commit control flow. `project_managed_application_graph` / `rea project-managed-application-graph` projects authenticated managed artifact/member/native-boundary Evidence into the existing application graph for cross-layer feature tracing. `import_managed_reconstruction` / `rea import-managed-reconstruction` admits user-supplied decompiler C#/IL/pseudocode as analyst inference only after exact artifact SHA-256, MVID, signature, and the shipped v1 decoded-IL commitment match. Separately, `plan_managed_runtime_correlation` / `rea plan-managed-runtime-correlation` can admit a default-disabled, permission-gated runtime-correlation plan locked to the same build evidence. These paths never load the assembly, resolve CLR dependencies, execute target code, run a decompiler, or translate managed tokens into native addresses; full normalized-CIL v2 semantics, native-body bridge mapping, and an actual runtime executor remain future managed-code contracts.
- Configure `REA_ILSPY_CMD_PATH=/absolute/path/to/ilspycmd` only when you want
doctor and `verify:managed` to inspect a bring-your-own ILSpy command as a
real reconstruction oracle. REA does not install ILSpy and does not treat

View File

@ -4,9 +4,10 @@
- Date: 2026-07-16
- Implementation status: Read-only PE/CLI triage and exact identity are shipped
through `inspect_managed_artifact` / `rea inspect-managed-artifact`. Bounded
metadata, signatures, method bodies, normalized CIL, exception regions, call
edges, and field-access anchors are shipped through `inspect_managed_members`
/ `rea inspect-managed-members`. Static member comparison and build-local
metadata, signatures, method bodies, raw CIL hashes, limited
decoded-instruction-tuple v1 hashes, exception regions, call edges, and
field-access anchors are shipped through `inspect_managed_members`; `rea
inspect-managed-members` provides CLI parity. Static member comparison and build-local
token remapping are shipped through `compare_managed_members` /
`rea compare-managed-members`. Declaration-only managed/native boundary
inventory for ModuleRef, ImplMap/PInvoke, ReadyToRun indicators, and non-IL
@ -216,22 +217,50 @@ Method observations add:
declaring type + normalized CLI signature
build-local metadata token
RVA/file extent when present
exact method-body SHA-256
normalized-CIL schema version + SHA-256 when CIL is valid
max stack + locals signature + exception-region commitment
raw CIL byte length + SHA-256 when the body is admitted
member-result schema version + decoded-instruction-tuple SHA-256 when CIL is valid
separate max-stack, locals-token, and exception-region observations
```
The exact body hash commits header bytes, CIL bytes, and admitted extra
sections. Normalized CIL decodes instructions, converts branch operands to
instruction coordinates, and resolves metadata operands to canonical
signatures or literal identities under a versioned algorithm. It preserves
opcode, prefix, constant, local/argument, generic, and exception semantics. It
does not erase differences merely to make two builds match.
The shipped `il_sha256` commits only the raw CIL byte stream identified by the
method header's `il_size`. It does not commit the method header, local-signature
blob, alignment padding, or extra sections such as exception clauses. Those
facts remain separate observations and the enclosing artifact SHA-256 binds
them to the exact file. A digest over the complete method body is not shipped.
The caller-visible field remains named `normalized_il_sha256`, but its shipped
v1 meaning is deliberately narrower than a canonical semantic CIL identity.
For a completely decoded method, REA serializes the instruction-order array of
`[opcode, operand_kind, operand]` tuples with JavaScript `JSON.stringify`,
encodes that text as UTF-8, and reports its lowercase SHA-256. The member
result's `schema_version: 1` scopes this convention; there is no independent
normalized-CIL algorithm-version field in v1.
Operands retain the current decoder projection: metadata and user-string
operands are build-local lowercase hexadecimal tokens, scalar branch operands
are decimal target CIL byte offsets, and `switch` retains only its decimal case
count. Constants and variable indexes are decimal strings; an operand-free
instruction uses kind `none` and value `null`. Opcode names preserve distinct
short forms and prefix instructions, but instruction offsets, branch target
instruction identity, switch targets, resolved token identities, method
headers, locals, and exception regions are not part of this digest. A partial
or malformed decode has no `normalized_il_sha256`.
Consequently v1 is a deterministic decoded-tuple fingerprint, not proof of
semantic equivalence. In particular, methods with the same opcodes and switch
case counts can share it despite different switch targets, and token movement
can change it without a semantic change. Cross-build comparison may use it as
one unique-only structural tier while retaining artifact/MVID commitments and
ambiguity; it must not describe the digest itself as token-remapped canonical
CIL. Canonical operand resolution, complete control-flow operands,
exception/local commitments, and an explicit algorithm version require a new
normalized-CIL schema.
Metadata tokens are reported because they are precise coordinates inside one
module. Cross-version identity never consists of a token alone. A structural
match cites both build commitments, both local tokens, the normalized inputs,
the matching algorithm version, and all competing candidates.
match cites both build commitments, both local tokens, the v1 tuple inputs, the
member-result schema version, and all competing candidates. V1 cannot cite a
separate matching-algorithm version because none is exposed.
### 5. Separate five evidence layers
@ -356,8 +385,9 @@ requires its own threat model and admission decision.
coverage; it never returns a partial list labeled complete.
- Managed addresses distinguish file offsets, RVAs, native virtual addresses,
metadata tokens, and CIL offsets. They are not interchangeable.
- Cache compatibility is exact on artifact/component commitment, parser
profile, normalized-CIL schema, and producer version.
- Cache compatibility is exact on artifact/component commitment, member-result
schema, parser profile, and producer version. For shipped v1,
`normalized_il_sha256` has no independent algorithm-version field.
- Provider-neutral workflows may compose canonical managed findings with the
one native binding, but every source operation retains its actual producer.
@ -400,7 +430,9 @@ or development-only oracles.
## Rollout gates
1. Add read-only triage and identity with malformed-input bounds. Shipped.
2. Add metadata, signatures, method bodies, normalized CIL, and exact Evidence. Shipped.
2. Add metadata, signatures, method bodies, deterministic decoded-CIL tuple
fingerprints, and exact artifact Evidence. Shipped with the v1 limitations
above; full normalized-CIL semantics remain planned.
3. Add obfuscation-resistant slices and cross-build match states. Shipped.
4. Compose explicit managed/native boundaries with Hopper/Ghidra. Declaration
inventory and native export/function Evidence matching shipped; native-body

View File

@ -13,7 +13,7 @@
<h1>Type Alias ManagedArtifactInspection</h1></div>
<div class="tsd-signature"><span class="tsd-kind-type-alias">ManagedArtifactInspection</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">z.infer</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-keyword">typeof</span> <a href="../variables/domain_managedArtifact.managedArtifactInspectionSchema.html" class="tsd-signature-type tsd-kind-variable">managedArtifactInspectionSchema</a><span class="tsd-signature-symbol">&gt;</span></div><aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L488">src/domain/managedArtifact.ts:488</a></li></ul></aside></div>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L496">src/domain/managedArtifact.ts:496</a></li></ul></aside></div>
<div class="col-sidebar">
<div class="page-menu">
<div class="tsd-navigation settings">

View File

@ -13,7 +13,7 @@
<h1>Type Alias ManagedMemberInspection</h1></div>
<div class="tsd-signature"><span class="tsd-kind-type-alias">ManagedMemberInspection</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">z.infer</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-keyword">typeof</span> <a href="../variables/domain_managedArtifact.managedMemberInspectionSchema.html" class="tsd-signature-type tsd-kind-variable">managedMemberInspectionSchema</a><span class="tsd-signature-symbol">&gt;</span></div><aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L491">src/domain/managedArtifact.ts:491</a></li></ul></aside></div>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L499">src/domain/managedArtifact.ts:499</a></li></ul></aside></div>
<div class="col-sidebar">
<div class="page-menu">
<div class="tsd-navigation settings">

View File

@ -13,7 +13,7 @@
<h1>Type Alias ManagedNativeBoundaryInspection</h1></div>
<div class="tsd-signature"><span class="tsd-kind-type-alias">ManagedNativeBoundaryInspection</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">z.infer</span><span class="tsd-signature-symbol">&lt;</span><br/>    <span class="tsd-signature-keyword">typeof</span> <a href="../variables/domain_managedArtifact.managedNativeBoundaryInspectionSchema.html" class="tsd-signature-type tsd-kind-variable">managedNativeBoundaryInspectionSchema</a><span class="tsd-signature-symbol">,</span><br/><span class="tsd-signature-symbol">&gt;</span></div><aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L494">src/domain/managedArtifact.ts:494</a></li></ul></aside></div>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L502">src/domain/managedArtifact.ts:502</a></li></ul></aside></div>
<div class="col-sidebar">
<div class="page-menu">
<div class="tsd-navigation settings">

View File

@ -13,7 +13,7 @@
<h1>Type Alias ManagedParseIssue</h1></div>
<div class="tsd-signature"><span class="tsd-kind-type-alias">ManagedParseIssue</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">z.infer</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-keyword">typeof</span> <span class="tsd-signature-type">managedParseIssueSchema</span><span class="tsd-signature-symbol">&gt;</span></div><aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L497">src/domain/managedArtifact.ts:497</a></li></ul></aside></div>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L505">src/domain/managedArtifact.ts:505</a></li></ul></aside></div>
<div class="col-sidebar">
<div class="page-menu">
<div class="tsd-navigation settings">

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@
<div class="tsd-comment tsd-typography"><p>Provider-neutral, execution-free PE/CLI triage and identity result.</p>
</div><aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L308">src/domain/managedArtifact.ts:308</a></li></ul></aside></div>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L316">src/domain/managedArtifact.ts:316</a></li></ul></aside></div>
<div class="col-sidebar">
<div class="page-menu">
<div class="tsd-navigation settings">

View File

@ -15,7 +15,7 @@
<div class="tsd-comment tsd-typography"><p>Provider-neutral, execution-free metadata/signature/IL member inspection.</p>
</div><aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L404">src/domain/managedArtifact.ts:404</a></li></ul></aside></div>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L412">src/domain/managedArtifact.ts:412</a></li></ul></aside></div>
<div class="col-sidebar">
<div class="page-menu">
<div class="tsd-navigation settings">

View File

@ -15,7 +15,7 @@
<div class="tsd-comment tsd-typography"><p>Provider-neutral managed/native boundary observations from PE/CLI metadata.</p>
</div><aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L440">src/domain/managedArtifact.ts:440</a></li></ul></aside></div>
<li>Defined in <a href="https://github.com/morluto/rea/blob/main/src/domain/managedArtifact.ts#L448">src/domain/managedArtifact.ts:448</a></li></ul></aside></div>
<div class="col-sidebar">
<div class="page-menu">
<div class="tsd-navigation settings">

View File

@ -104,8 +104,50 @@ EncBaseId because ECMA-335 metadata does not require those bit patterns.
- row/heap/body locations expressed as typed file offsets, RVAs, or CIL
offsets;
- exact raw bytes or bounded value digest;
- method body, normalized CIL, locals, exception-region, and generic-context
commitments where applicable.
- raw CIL digest plus separately reported method-header, locals-token, and
exception-region observations where available;
- a deterministic v1 decoded-instruction-tuple digest for completely decoded
CIL, with the limitations below.
### Shipped decoded-CIL fingerprint v1
`inspect_managed_members` exposes two method CIL hashes with different byte
boundaries:
| Field | Shipped v1 input | Excluded from the digest |
| ---------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `il_sha256` | The exact `il_size` raw CIL bytes after the tiny or fat method header | Method header, locals signature blob, alignment, and extra sections including exception clauses |
| `normalized_il_sha256` | UTF-8 `JSON.stringify` output for the instruction-order array of `[opcode, operand_kind, operand]` tuples | Instruction offsets except projected scalar branch targets, switch targets, resolved metadata/string identities, method header, locals, and exception regions |
The normalized field is available only when the entire CIL stream decodes with
status `present`. A partial, malformed, absent, or over-limit body reports
`null`. The containing member result's `schema_version: 1` scopes the tuple
format; v1 does not expose a separate algorithm-version field.
Tuple operands use these exact projections:
- operand-free instructions: `none` and `null`;
- metadata and user-string operands: the build-local token as lowercase
`0x`-prefixed eight-digit hexadecimal;
- scalar branches: the target CIL byte offset as a decimal string;
- `switch`: the case count as a decimal string, without target offsets;
- signed integer and variable operands: decimal strings; floating-point
operands: JavaScript's `String` representation of the decoded IEEE value.
Opcode names retain short/long forms and prefix opcodes. This makes v1 a
reproducible decoded-tuple fingerprint, not a canonical semantic CIL identity:
it does not resolve tokens across MVIDs, does not commit full control flow or
exception semantics, and does not replace the raw CIL digest. Cross-build
comparison uses the value only as one unique-only structural tier and reports
ambiguity when that evidence is insufficient. A future normalized-CIL v2 must
have an explicit algorithm version, canonical token/literal identities,
complete branch and switch targets, and explicit locals/exception semantics.
For example, a decoded `nop; ret` body serializes exactly as
`[["nop","none",null],["ret","none",null]]` and has v1 digest
`5e5fad7741cb44bca3a4f045546b7449990da343f612f5f34c0ca30e9eee0636`.
This vector specifies the tuple order, `null` handling, absence of whitespace,
UTF-8 encoding, and lowercase hexadecimal output.
### Epistemic commitment
@ -163,7 +205,8 @@ bounded set of observations needed to investigate a proposition:
- exact strings, numeric constants, enum-like values, and serialization keys;
- branch, switch, exception, loop, call, and field-flow shape;
- construction and generic-instantiation sites;
- exact body and normalized-CIL commitments;
- raw CIL and decoded-tuple-v1 commitments, plus separate header, locals, and
exception observations;
- callers, callees, shared fields, and competing candidates; and
- limitations from reflection, dynamic dispatch, generated code, protection,
native transitions, or incomplete coverage.
@ -174,12 +217,14 @@ turn that role into the method's durable identity.
Cross-version matching is two-stage:
1. Exact identity requires compatible artifact/module commitments and an exact
entity/body identity.
2. Structural identity compares schema-versioned signatures, normalized CIL,
APIs, constants, and bounded graph context. It reports all candidates at the
winning score and remains ambiguous when the evidence does not distinguish
them.
1. Exact identity requires compatible artifact/module commitments and exact
raw CIL identity; v1 does not expose a standalone complete-method-body
digest.
2. Structural identity compares schema-versioned signatures, the limited v1
decoded-CIL tuple fingerprint, constants, and bounded shape context. It
reports all candidates at the winning score and remains ambiguous when the
evidence does not distinguish them. The v1 digest does not itself remap
metadata tokens.
Tokens are always remapped through observed structure. A caller cannot carry
`0x06001234` into a new MVID and assume it names the same method.
@ -330,7 +375,8 @@ manifest supplies those fields. It then pages each declared MethodDef token
directly by row, so selected methods do not need to appear in the first member
page of a large application. `il_length` remains accepted as a legacy alias for
`il_size`; optional `il_sha256` locks the exact raw CIL bytes in addition to
REA's schema-versioned normalized instruction digest.
REA's member-result-v1 decoded-instruction-tuple digest. That normalized field
has the v1 limits documented above and is not a complete semantic CIL identity.
The optional `application_graph` block reuses those exact-build method
commitments. For each referenced MethodDef token, the verifier builds a bounded
@ -378,7 +424,9 @@ The managed-code track advances as reviewable pull requests:
1. accepted evidence/provider boundary (this document and ADR);
2. read-only artifact triage and exact identity (shipped);
3. bounded metadata, signatures, method bodies, and normalized CIL (shipped);
3. bounded metadata, signatures, method bodies, raw CIL hashes, and the limited
decoded-instruction-tuple fingerprint v1 (shipped; normalized-CIL v2
semantics remain planned);
4. obfuscation-resistant slices and cross-version comparison (shipped for
static member observations);
5. decompiler reconstruction import (shipped as analyst inference; REA does

View File

@ -566,10 +566,10 @@
"mcp_resource_templates": 8
},
"digests": {
"tools_sha256": "b9cea5c401d28e7f2bbd32a058dab8cf5c1b044a60fb5b2ec90584dcd2c781bb",
"tools_sha256": "4f19c5773a44980e176978f05626f2d82c95d49e4b86d024ce515c3ff1670bae",
"prompts_sha256": "f6da3ad38a1000c11364d1710f122ac4990551f04efd8c53ffb2e819b5cf5707",
"resources_sha256": "5dca0fcdad3e78d71a1b6ef7b4f0c12bdcd8e3ec11fcbdd9ccd3a68edadf5c80",
"combined_sha256": "d0e2eae4dbc245ff58042a075276a501872a5bf7405a18d1b4e0163cbdf138f9"
"combined_sha256": "b6840d7c79ffdfe8a2ef65fb66c1694f3631bacbc22a0456abbe12aca2d53969"
}
}
}

View File

@ -4,7 +4,7 @@ description: Reverse engineer native, Electron/JavaScript, and web applications
metadata:
version: "21"
tool_count: 95
catalog_digest: "d0e2eae4dbc245ff58042a075276a501872a5bf7405a18d1b4e0163cbdf138f9"
catalog_digest: "b6840d7c79ffdfe8a2ef65fb66c1694f3631bacbc22a0456abbe12aca2d53969"
---
# REA

View File

@ -137,7 +137,7 @@ export const MANAGED_TOOL_CONTRACTS = [
name: "inspect_managed_members",
...toolContractMetadata("inspect_managed_members"),
description:
"Inspect bounded PE/CLI metadata members, signatures, method body IL hashes, exception regions, call edges, and field-access anchors without loading or executing target code. Metadata tokens are reported as build-local coordinates bound to the artifact SHA-256 and MVID.",
"Inspect bounded PE/CLI metadata members, signatures, raw CIL hashes, limited member-result-v1 decoded-instruction-tuple hashes, separately reported exception regions, call edges, and field-access anchors without loading or executing target code. Metadata tokens are reported as build-local coordinates bound to the artifact SHA-256 and MVID; the v1 tuple hash does not resolve them or fully commit control flow.",
kind: "managed-provider",
inputSchema: managedMemberInputSchema,
outputSchema: memberOutputSchema,

View File

@ -160,7 +160,7 @@ export const MANAGED_WORKFLOW_TOOL_CONTRACTS = [
name: "compare_managed_members",
...toolContractMetadata("compare_managed_members"),
description:
"Compare two authenticated inspect_managed_members Evidence records using unique-only CIL/signature and structural method-shape tiers. Names are reported as observations but are not used as a matching basis; metadata tokens are remapped as build-local coordinates bound to each artifact SHA-256 and MVID.",
"Compare two authenticated inspect_managed_members Evidence records using unique-only decoded-CIL-v1/signature and structural method-shape tiers. Names are reported as observations but are not used as a matching basis; metadata tokens remain build-local coordinates bound to each artifact SHA-256 and MVID, and the v1 tuple digest does not itself remap them.",
kind: "application",
inputSchema: compareManagedMembersReferenceInputSchema,
outputSchema: comparisonOutputSchema,
@ -203,7 +203,7 @@ export const MANAGED_WORKFLOW_TOOL_CONTRACTS = [
name: "import_managed_reconstruction",
...toolContractMetadata("import_managed_reconstruction"),
description:
"Import decompiler-produced managed reconstruction against authenticated inspect_managed_members Evidence. The workflow locks each method to artifact SHA-256, MVID, metadata token, signature hash, and normalized IL hash, records the decompiler identity and options, and marks C# or pseudocode as analyst inference rather than canonical byte observation.",
"Import decompiler-produced managed reconstruction against authenticated inspect_managed_members Evidence. The workflow locks each method to artifact SHA-256, MVID, metadata token, signature hash, and the limited member-result-v1 decoded-IL tuple hash, records the decompiler identity and options, and marks C# or pseudocode as analyst inference rather than canonical byte observation.",
kind: "application",
inputSchema: managedReconstructionReferenceInputSchema,
outputSchema: reconstructionOutputSchema,
@ -224,7 +224,7 @@ export const MANAGED_WORKFLOW_TOOL_CONTRACTS = [
name: "plan_managed_runtime_correlation",
...toolContractMetadata("plan_managed_runtime_correlation"),
description:
"Prepare a separately authorized managed runtime-correlation admission plan from authenticated inspect_managed_members Evidence. The operation is default-disabled, requires the managed_runtime permission ceiling and grant, locks the exact artifact SHA-256, MVID, method signature, and normalized IL shape, distinguishes attach/load/debugger/reflection/instrumentation effects, and records that no target code was executed.",
"Prepare a separately authorized managed runtime-correlation admission plan from authenticated inspect_managed_members Evidence. The operation is default-disabled, requires the managed_runtime permission ceiling and grant, locks the exact artifact SHA-256, MVID, method signature, and limited member-result-v1 decoded-IL tuple hash, distinguishes attach/load/debugger/reflection/instrumentation effects, and records that no target code was executed.",
kind: "application",
inputSchema: managedRuntimeCorrelationReferenceInputSchema,
outputSchema: runtimeOutputSchema,

View File

@ -170,8 +170,16 @@ const managedMethodBodySchema = z.object({
init_locals: z.boolean().nullable(),
local_var_sig_token: tokenSchema.nullable(),
il_size: z.number().int().min(0),
il_sha256: digestSchema.nullable(),
normalized_il_sha256: digestSchema.nullable(),
il_sha256: digestSchema
.nullable()
.describe(
"SHA-256 of exactly the raw il_size CIL bytes; excludes the method header, locals signature, alignment, and extra sections",
),
normalized_il_sha256: digestSchema
.nullable()
.describe(
"Member-result-v1 SHA-256 of UTF-8 JSON [opcode, operand_kind, operand] tuples for a complete decode; retains build-local tokens, omits switch targets, and excludes headers, locals, and exception regions",
),
instruction_count: z.number().int().min(0),
decoded_instruction_count: z.number().int().min(0),
truncated_instructions: z.number().int().min(0),

View File

@ -232,6 +232,53 @@ describe("managed PE/CLI static provider", () => {
});
});
it("keeps the documented decoded-CIL v1 golden vector stable", () => {
const il = Buffer.from([0x00, 0x2a]);
const tinyBytes = buildManagedPeFixture({
ilBody: Buffer.from([0x0a, ...il]),
});
const fatHeader = Buffer.alloc(12);
fatHeader.writeUInt16LE(0x3013, 0);
fatHeader.writeUInt16LE(32, 2);
fatHeader.writeUInt32LE(il.length, 4);
fatHeader.writeUInt32LE(0x1100_0001, 8);
const fatBytes = buildManagedPeFixture({
ilBody: Buffer.concat([fatHeader, il]),
});
const tiny = inspectManagedMembersBytes(
tinyBytes,
target(tinyBytes),
memberLimits,
);
const fat = inspectManagedMembersBytes(
fatBytes,
target(fatBytes),
memberLimits,
);
expect(tiny.methods.items[0]?.body).toMatchObject({
status: "present",
header_format: "tiny",
max_stack: 8,
init_locals: false,
local_var_sig_token: null,
il_size: 2,
il_sha256: createHash("sha256").update(il).digest("hex"),
normalized_il_sha256:
"5e5fad7741cb44bca3a4f045546b7449990da343f612f5f34c0ca30e9eee0636",
opcode_counts: { nop: 1, ret: 1 },
exception_regions: [],
});
expect(fat.methods.items[0]?.body).toMatchObject({
header_format: "fat",
max_stack: 32,
init_locals: true,
local_var_sig_token: "0x11000001",
il_sha256: tiny.methods.items[0]?.body.il_sha256,
normalized_il_sha256: tiny.methods.items[0]?.body.normalized_il_sha256,
});
});
it("marks instruction-limited CIL as partial without assigning normalized identity", () => {
const bytes = buildManagedPeFixture();
const result = inspectManagedMembersBytes(bytes, target(bytes), {