[GH-ISSUE #8449] [Bug] Native Evidence views accept incompatible predicates #6609

Open
opened 2026-11-01 21:12:39 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @morluto on GitHub (Nov 1, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8449

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

inspect_analysis_view accepts native observations with the wrong Evidence predicate, including a function dossier supplied as a standalone file or inline; its one-record canonical bundle representation is rejected. On main, I constructed a synthetic record with a valid semantic Evidence ID, operation: "analyze_function", a valid function-dossier result, and predicate_type: "rea.process-capture". The standalone file produced a function summary; the same record in a canonical bundle failed with evidence_integrity_mismatch because its result is not a valid process capture. import_evidence_bundle also rejected that bundle.

Reproduction

  1. Construct a record from FUNCTION_COMPARISON_EXAMPLE.left using createEvidence, retaining its function-dossier result but setting the predicate to rea.process-capture; write the record and createEvidenceBundle([record]) to separate files.
  2. In a fresh target-free stdio MCP session, call inspect_analysis_view with source: {kind: "evidence-file", path: <record>} and view: {kind: "summary"}. Repeat with the bundle path.
  3. The standalone record succeeds; the bundle is rejected as an invalid process capture. Supplying the same record inline to inspect_analysis_view also succeeds. By contrast, build_call_path with that inline record rejects it because function analysis requires the rea.analysis predicate. This occurred in full and compact schema profiles.

A positive control using an actual Ghidra function dossier produced the same view Evidence ID from its standalone and bundle files in both profiles. A second synthetic control used predicate_type: "rea.unrelated": both inline and bundle-backed function views accepted it while build_call_path rejected it. Replacing that predicate with rea.analysis made all three succeed. Thus the function-view mismatch is not limited to process-capture bundle validation. I also took previously captured real Kuna 1.986 and Ghidra 12.1.4 list_procedures records, created new synthetic records with their observed fields and predicate rea.unrelated, and replayed them offline on main. Native-inventory views accepted both synthetic records while match_native_functions rejected them as requiring rea.analysis. Both original provider records were accepted by both workflows in both profiles. As a separate control, match_native_functions produced legitimate Evidence with predicate rea.native-function-matching from each real inventory; its summary view accepted those records. It also accepted a synthetic copy using rea.analysis, so any fix must check the expected identity for each operation rather than require rea.analysis for all native views.

Expected behavior

Native views should not treat a differently typed predicate as an analyze_function or list_procedures observation; build_call_path and match_native_functions already require rea.analysis for those operations. Predicate-specific validation should be consistent for inline and file-backed inputs, including canonical bundles. If the intended contract permits such a mismatch, the path and bundle rejections need reconsideration. Preserve the exact input, ID and all source evidence; do not infer authenticity of an external producer merely from the digest.

Impact and scope

Observed on intentionally contradictory, self-authenticated synthetic records with two different predicates, including records constructed from existing Kuna and Ghidra inventories. The accepted summary carries the same parent ID even though bundle import refuses that parent. No real provider was observed to generate such a record, and no target was executed. Frequency and other predicate types are unknown.

REA version

Source revision e18594b24754ab95ebd119311cc32a1d1ad6fa13.

Runtime and platform

Node 24.22.1, macOS arm64, public stdio MCP with TypeScript SDK; full and compact schema profiles.

Target and artifact context

Synthetic Evidence record and canonical bundle; positive control is a previously captured static Ghidra dossier. No provider started during the offline check.

Interface

MCP

Earliest failure stage

Artifact or evidence registration

Relevant output or evidence

  • Standalone view: success, normalized_result.kind: "summary" with the selected parent ID.
  • Bundle view and session import: evidence_integrity_mismatch, reporting an invalid process-capture normalized_result.
  • Inline view: success. Inline build_call_path: invalid_request explicitly requiring rea.analysis. With synthetic rea.unrelated instead, both inline and bundle views succeeded while the path still rejected it; the matching rea.analysis control succeeded across all three.
  • Synthetic Kuna and Ghidra inventory records with rea.unrelated: native-inventory view accepted, match_native_functions rejected; original inventories succeeded in both.
  • Source-derived: evidenceFileSource.ts authenticates standalone records directly, while the bundle path calls authenticateEvidenceBundleValue, which validates process captures.

Analysis or suspected cause

File shape selects two validation paths. Separately, projectResolvedAnalysisView projects the authenticated parent into AnalysisViewParent without carrying predicate_type; native views then dispatch on operation and cannot apply the predicate checks used by build_call_path and match_native_functions. The producing representation and semantic owner should preserve that fact rather than having consumers reinterpret raw input. A file-only patch would leave the inline inconsistency. Compatibility effects need review. This was discovered while investigating #8427's proposed record-import workflow; it is not a claim about that unmerged prototype or an upstream Ghidra/Kuna defect.

cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Originally created by @morluto on GitHub (Nov 1, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8449 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior `inspect_analysis_view` accepts native observations with the wrong Evidence predicate, including a function dossier supplied as a standalone file or inline; its one-record canonical bundle representation is rejected. On main, I constructed a **synthetic** record with a valid semantic Evidence ID, `operation: "analyze_function"`, a valid function-dossier result, and `predicate_type: "rea.process-capture"`. The standalone file produced a function summary; the same record in a canonical bundle failed with `evidence_integrity_mismatch` because its result is not a valid process capture. `import_evidence_bundle` also rejected that bundle. ### Reproduction 1. Construct a record from `FUNCTION_COMPARISON_EXAMPLE.left` using `createEvidence`, retaining its function-dossier result but setting the predicate to `rea.process-capture`; write the record and `createEvidenceBundle([record])` to separate files. 2. In a fresh target-free stdio MCP session, call `inspect_analysis_view` with `source: {kind: "evidence-file", path: <record>}` and `view: {kind: "summary"}`. Repeat with the bundle path. 3. The standalone record succeeds; the bundle is rejected as an invalid process capture. Supplying the same record inline to `inspect_analysis_view` also succeeds. By contrast, `build_call_path` with that inline record rejects it because function analysis requires the `rea.analysis` predicate. This occurred in full and compact schema profiles. A positive control using an actual Ghidra function dossier produced the same view Evidence ID from its standalone and bundle files in both profiles. A second synthetic control used `predicate_type: "rea.unrelated"`: both inline and bundle-backed function views accepted it while `build_call_path` rejected it. Replacing that predicate with `rea.analysis` made all three succeed. Thus the function-view mismatch is not limited to process-capture bundle validation. I also took previously captured real Kuna 1.986 and Ghidra 12.1.4 `list_procedures` records, created new synthetic records with their observed fields and predicate `rea.unrelated`, and replayed them offline on main. Native-inventory views accepted both synthetic records while `match_native_functions` rejected them as requiring `rea.analysis`. Both original provider records were accepted by both workflows in both profiles. As a separate control, `match_native_functions` produced legitimate Evidence with predicate `rea.native-function-matching` from each real inventory; its summary view accepted those records. It also accepted a synthetic copy using `rea.analysis`, so any fix must check the expected identity for each operation rather than require `rea.analysis` for all native views. ### Expected behavior Native views should not treat a differently typed predicate as an `analyze_function` or `list_procedures` observation; `build_call_path` and `match_native_functions` already require `rea.analysis` for those operations. Predicate-specific validation should be consistent for inline and file-backed inputs, including canonical bundles. If the intended contract permits such a mismatch, the path and bundle rejections need reconsideration. Preserve the exact input, ID and all source evidence; do not infer authenticity of an external producer merely from the digest. ### Impact and scope Observed on intentionally contradictory, self-authenticated synthetic records with two different predicates, including records constructed from existing Kuna and Ghidra inventories. The accepted summary carries the same parent ID even though bundle import refuses that parent. No real provider was observed to generate such a record, and no target was executed. Frequency and other predicate types are unknown. ### REA version Source revision `e18594b24754ab95ebd119311cc32a1d1ad6fa13`. ### Runtime and platform Node 24.22.1, macOS arm64, public stdio MCP with TypeScript SDK; full and compact schema profiles. ### Target and artifact context Synthetic Evidence record and canonical bundle; positive control is a previously captured static Ghidra dossier. No provider started during the offline check. ### Interface MCP ### Earliest failure stage Artifact or evidence registration ### Relevant output or evidence - Standalone view: success, `normalized_result.kind: "summary"` with the selected parent ID. - Bundle view and session import: `evidence_integrity_mismatch`, reporting an invalid process-capture `normalized_result`. - Inline view: success. Inline `build_call_path`: `invalid_request` explicitly requiring `rea.analysis`. With synthetic `rea.unrelated` instead, both inline and bundle views succeeded while the path still rejected it; the matching `rea.analysis` control succeeded across all three. - Synthetic Kuna and Ghidra inventory records with `rea.unrelated`: native-inventory view accepted, `match_native_functions` rejected; original inventories succeeded in both. - Source-derived: [`evidenceFileSource.ts`](https://github.com/morluto/rea/blob/e18594b24754ab95ebd119311cc32a1d1ad6fa13/src/application/analysisView/evidenceFileSource.ts#L119-L186) authenticates standalone records directly, while the bundle path calls [`authenticateEvidenceBundleValue`](https://github.com/morluto/rea/blob/e18594b24754ab95ebd119311cc32a1d1ad6fa13/src/application/EvidenceBundleFiles.ts#L140-L205), which validates process captures. ### Analysis or suspected cause File shape selects two validation paths. Separately, [`projectResolvedAnalysisView`](https://github.com/morluto/rea/blob/e18594b24754ab95ebd119311cc32a1d1ad6fa13/src/application/analysisView/AnalysisViewService.ts#L217-L243) projects the authenticated parent into [`AnalysisViewParent`](https://github.com/morluto/rea/blob/e18594b24754ab95ebd119311cc32a1d1ad6fa13/src/domain/analysisView/analysisViewParent.ts#L10-L25) without carrying `predicate_type`; native views then dispatch on operation and cannot apply the predicate checks used by `build_call_path` and `match_native_functions`. The producing representation and semantic owner should preserve that fact rather than having consumers reinterpret raw input. A file-only patch would leave the inline inconsistency. Compatibility effects need review. This was discovered while investigating #8427's proposed record-import workflow; it is not a claim about that unmerged prototype or an upstream Ghidra/Kuna defect. cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

An isolated candidate carries the authenticated parent's predicate into AnalysisViewParent, then checks the expected predicate for native function, inventory, observation and matching views. The native matching predicate comes from its producing domain; ordinary provider observations use the shared analysis predicate. This is not a blanket rea.analysis rule.

Executed controls: the public MCP regression rejects synthetic incompatible predicates for function, inventory, primitive and call-graph observations, and matching views across inline, retained, standalone-file and bundle-file inputs in both schema profiles. It fails on the original code and passes with the candidate. The affected view suites passed (34 files, 598 tests), and typecheck and lint passed. Fresh real Kuna 1.986 and Ghidra 12.1.4 runs completed summary → retained-parent handoffs for function, inventory, call-graph and matching views in both profiles; the owned static fixture hash was unchanged and it was not executed.

Limits: This is not yet merged. Non-native view identities, the separate standalone-versus-bundle process-payload validation discrepancy, and other provider platforms remain unverified. A further synthetic control supplied a correctly typed matching result while claiming Ghidra as provider and shipped-artifact authority; the view accepted it and inherited that authority, whereas the real matching producer uses analyst-inference. Whether views should validate that producer identity or preserve caller-supplied claims needs a separate contract decision. A semantic digest does not authenticate an external producer.

<!-- gh-comment-id:6554753888 --> @morluto commented on GitHub (Nov 1, 2026): An isolated candidate carries the authenticated parent's predicate into `AnalysisViewParent`, then checks the expected predicate for native function, inventory, observation and matching views. The native matching predicate comes from its producing domain; ordinary provider observations use the shared analysis predicate. This is not a blanket `rea.analysis` rule. **Executed controls:** the public MCP regression rejects synthetic incompatible predicates for function, inventory, primitive and call-graph observations, and matching views across inline, retained, standalone-file and bundle-file inputs in both schema profiles. It fails on the original code and passes with the candidate. The affected view suites passed (34 files, 598 tests), and typecheck and lint passed. Fresh real Kuna 1.986 and Ghidra 12.1.4 runs completed summary → retained-parent handoffs for function, inventory, call-graph and matching views in both profiles; the owned static fixture hash was unchanged and it was not executed. **Limits:** This is not yet merged. Non-native view identities, the separate standalone-versus-bundle process-payload validation discrepancy, and other provider platforms remain unverified. A further synthetic control supplied a correctly typed matching result while claiming Ghidra as provider and `shipped-artifact` authority; the view accepted it and inherited that authority, whereas the real matching producer uses `analyst-inference`. Whether views should validate that producer identity or preserve caller-supplied claims needs a separate contract decision. A semantic digest does not authenticate an external producer.
Author
Owner

@BeqaKs commented on GitHub (Nov 3, 2026):

Closing as fixed on main by #8451 (fix(evidence)!: validate native view parent predicates). Stayed open because the PR used Refs rather than Fixes/Closes.

<!-- gh-comment-id:6599992495 --> @BeqaKs commented on GitHub (Nov 3, 2026): Closing as fixed on main by #8451 (`fix(evidence)!: validate native view parent predicates`). Stayed open because the PR used Refs rather than Fixes/Closes.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#6609
No description provided.