[GH-ISSUE #8348] [Design] Make incoming reference evidence actionable with Kuna #6553

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

Originally created by @morluto on GitHub (Oct 31, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8348

Before submitting

  • I searched the open and closed issues and pull requests for a related discussion.
  • I understand the contribution scope must be reviewed before integration; open questions are welcome here.
  • This discussion does not include credentials, private samples, or sensitive target data.

Decision needed

How should an agent distinguish an incoming call from an address reference and find its containing function when using Kuna, without overstating the provider's reference coverage or changing the meaning of xrefs?

Context and evidence

On REA 60149282fcfc05ac32fbc94434c107710120da6f, macOS arm64, I used real stdio MCP sessions with Kuna 1.986 and Ghidra 12.1.4 on an unexecuted, self-built x86-64 ELF shared library (SHA-256 a795b954d45b321ca77b641784fca0b3a1e33f17bd826e2d5ebf8de9543de1bd; unchanged after both sessions). Its audit_direct has a NOP followed by call audit_target; audit_address has a NOP followed by lea audit_target(%rip),%rax.

  • REA/Kuna xrefs for audit_target returned ["0x12ab", "0x12b2"]. procedure_callers returned audit_direct's entry 0x12aa. Both source addresses are inside procedures, not entries: procedure_assembly rejected them and resolve_containing_procedure and procedure_references(direction: incoming) were capability_unavailable. Assembly by the already-known function names showed the CALL and LEA.
  • Direct kuna xrefs <fixture> --to audit_target --json returned both rows with kind, source procedure and instruction: call / audit_direct / CALL 0x12a4 and data / audit_address / LEA RAX,[0x12a4]. Its --kind call and --kind data each returned the corresponding row. These observations are available upstream but are not conveyed by REA's address-only xrefs result.
  • REA/Ghidra's procedure_references(direction: incoming) reported a call and a DATA reference with their source procedures, plus two DATA references without source procedures. Its image addresses differ from Kuna's. resolve_containing_procedure found both instruction owners. Those extra references demonstrate why a bare incoming address need not be an executable caller.

The LEA forms an address; it is not evidence of a memory read or a runtime call. The example does not establish the providers' general completeness or accuracy, or how frequently agents encounter this situation.

Expected interaction with targets

Read existing files and use the existing static provider; no target execution or target mutation is proposed.

Boundary details (optional)

Preserve provider-specific kinds, coordinates, source/target identity, provenance, and incomplete or unknown coverage. An absent or unsupported owner is distinct from a verified non-procedure address. Do not infer that every incoming reference is a call or silently change the existing address-only contract.

Options and tradeoffs

Investigate whether an existing task-oriented incoming-reference workflow can provide compact, typed observations and optional owners, with explicit unknowns, or whether a separate bounded view is needed. Compare provider semantics before mapping kinds: direct Kuna labels are not automatically equivalent to Ghidra ReferenceManager types, and known Kuna reference gaps need to remain visible. Avoid requiring a full dossier per address or merely exposing the raw provider API.

Verification available so far

I have a prototype or observed results.

Success criteria and open questions

Exercise the call, address-formation, non-procedure source, unresolved owner and no-reference cases through public CLI/MCP with real providers; verify retained Evidence, provider-specific address spaces and honest coverage. The observation above is limited to one constructed x86-64 ELF; other formats, architectures, indirect calls, data reads/writes and SDK/schema behavior remain to be checked.

References

Related: #8190 (outgoing data references and provider coverage), #8288 (feature-trace behavior when containment is unavailable), #1245 (closed earlier Ghidra incoming-reference discussion). Upstream false-reference and omitted-reference examples: Noelo-Lab/kuna#1334 and Noelo-Lab/kuna#1360.

Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0.

Kuna 1.988 import-slot control

On REA bafe3784c plus the version-only #8509 change, real Kuna 1.986/1.988 compact stdio MCP analyzed the same owned, unexecuted arm64 Mach-O import-slot fixture. For slot 0x4000, 1.986 returned no incoming references; 1.988 returned 0x1360, 0x1364, and 0x1368. Direct Kuna 1.988 xrefs --to 0x4000 --json identifies those rows respectively as address-formation data, slot read, and indirect call, with instructions. REA's xrefs Evidence contains the three addresses and a digest/count of the raw provider response, but not the per-row kinds or instructions; procedure_references remains unavailable with Kuna. The target SHA-256 was unchanged. This confirms the new release makes the existing task-level distinction more useful, but a call-kind row is still a static provider observation, not runtime call proof. One fixture and host; no all-reference coverage claim.

Following the 1.988 slot references through REA

With real Kuna 1.988, Ghidra 12.1.4, and the import-slot fixture above, I tested the following public stdio MCP sequence on #8509 head 7f344af1a in both full and compact schema profiles. Kuna xrefs(0x4000) returned three instruction addresses. For each, resolve_containing_procedure and inspect_native_instruction returned capability_unavailable; procedure_assembly refused the interior address as not an inventory entry. If the caller already knows _audit_import_call, its assembly succeeds. Explicitly switching to Ghidra resolves all three owners to _audit_import_call and decodes adrp, ldr, and blr; the target digest remained unchanged and it was not executed. Switching providers has the session-state implications in #8289.

The tested Kuna producer parser already validates each upstream row's source/target, kind, owner and instruction, but retains only deduplicated addresses and an output digest/count. A task-level optional incoming-reference detail in an existing address investigation could preserve those producer-owned facts and explicit unknown coverage without requiring a full dossier per result. Its contract would need to preserve exact-address filtering and alias exclusions, provider-specific kind meanings, null owners, limits/paging and offline Evidence; adding every upstream xrefs option or silently changing the existing address-only result is not implied. No autonomous agent trace, other hosts, or exhaustive xref coverage was tested.

Existing typed-reference alternative and schema boundary

On #8509 head 7f344af1a, real compact and full MCP inspect_native_instruction at the function target in a mixed arm64 Mach-O distinguished Ghidra UNCONDITIONAL_CALL at 0x10000042c from DATA at pointer slot 0x100004008. The same operation at the slot returned status: data and its incoming READ. In a separate statically linked x86-64 ELF, Ghidra likewise identified slot 0x202190 as DATA to target 0x201159. Typed Ghidra Evidence and xrefs survived export/import into a fresh target-free MCP session, and successful workflow responses validated against both advertised output schemas (Ajv 2020, strict and format validation disabled). Both targets remained unchanged and were not executed. These are static observations, not runtime calls.

Kuna 1.988 returned capability_unavailable for the same instruction inspections while its direct xrefs reports the Mach-O stored pointer separately. Source inspection shows the existing nativeInstructionSchema requires a listing status, architecture, mode, and reference fields including boolean indirect/computed and numeric operand_index. A Kuna xrefs row alone does not establish all those facts; forcing it into that result could invent values. Preserve provider-reported kinds and unavailable facets explicitly. The CLI handoff to the existing typed alternative is addressed by draft #8514; this does not add Kuna support. Two controlled fixtures on one host do not establish general provider equivalence.

Mixed instruction and pointer provenance in the unmerged prototype

On the existing source-built arm64 Mach-O fixture (SHA-256 9fc02faea0c3723a094c209adbe62a279011df4d508298625bd766fa20ed7c46), direct Kuna 1.988 reported a call at 0x10000042c, owned by _audit_direct_call with instruction bl 0x100000410, and a separate chained-fixups pointer at 0x100004008 to the same target. In both full and compact real stdio MCP sessions, the unmerged #8510 pointer prototype returned both addresses, and its trace linked the xrefs Evidence. The linked source's raw result preserved the pointer row and origin, but retained only the instruction-row count, not that row's kind, instruction, or owner. The inline trace represented both addresses with containing_procedure: unavailable; it did not identify either reference kind. The target was unchanged and unexecuted.

Thus the prototype repairs pointer omission but does not yet make a mixed set fully actionable. A consumer must not infer the remaining address is an instruction merely by subtracting reported pointer rows: address deduplication and independently incomplete categories do not establish mutually exclusive kinds. Preserve producer-observed rows and their distinctions or explicitly represent unavailable facts, subject to bounded delivery and offline provenance. This is one fixture on macOS arm64, not a general accuracy or autonomous-agent study.

Source-row preservation experiment

A further unmerged local experiment retains validated, exact-target Kuna instruction rows alongside stored-pointer rows in the linked xrefs Evidence. On the same mixed Mach-O, real compact and full stdio MCP returned both addresses; the source Evidence retained Kuna's call, _audit_direct_call, bl 0x100000410 and the separate chained-fixup pointer. Export and import into a fresh target-free session preserved the trace and linked source Evidence exactly in both profiles; the fixture digest remained unchanged and the target was not executed. The focused Kuna reference-file suite passed (22 tests).

This shows the existing Evidence path can carry these parsed producer facts; it does not make them inline trace observations or establish a final contract. Exact-target and alias behavior, duplicate or overlapping rows, admission and retained-size growth, partial publication, historical profiles, and larger/cross-platform examples still require design and verification. The experiment is neither an API-parity proposal nor a shipped fix.

Many incoming references and reported owners

An owned arm64 Mach-O with 100 noinline callers and one function-pointer slot gave direct Kuna 1.988 exactly 100 call rows, each with a distinct reported source function, plus one chained-fixup pointer row. On #8509, compact stdio MCP xrefs returned 100 addresses; trace_feature returned 100 references and 100 residual questions because separate containment resolution is unavailable. On the unmerged source-row/pointer experiment, xrefs returned 101 addresses and preserved the 100 instruction rows and pointer; its trace returned 101 references and 102 unknowns (101 unavailable containment results plus the stored-pointer coverage gap). The owned target (SHA-256 3d39bb659d0ec6fdc907ef9ea3d88c2f59fa1b3b870a6f743f518c227c3b18af) remained unchanged and was never executed.

For this one case the retained producer rows contain 100 candidate reported owners even though the composed trace cannot use them. A task-oriented view could expose those as Kuna-reported source-function associations while keeping independent containment resolution unavailable; it must not silently promote them to independently verified containment. In serialized SDK call responses, the baseline and experimental direct xrefs responses were 7,639 and 95,885 bytes, respectively; exported bundles after both calls were 318,256 and 365,743 bytes. The runs differ in preserved facts and unknowns, so these sizes describe the tested tradeoff, not a controlled performance benchmark or token measurement. Normal capacity exhaustion, other architectures, full schema profile, and automated agent selection were not tested.

Cross-provider owner and artifact control

On the same 100-caller Mach-O, real Ghidra 12.1.4 through REA compact stdio MCP returned 102 incoming references to the target. All 100 Kuna call source addresses had matching Ghidra source-procedure names and entries. Independent nm -nm matched those 100 function entries, and otool -tvV showed a branch-and-link to the target at each source address. Five sampled addresses also resolved through Ghidra's resolve_containing_procedure and decoded as direct calls through inspect_native_instruction. Ghidra additionally reported two DATA references, including the pointer slot. The target digest was unchanged and it was not executed.

This supports the reported owner facts for these 100 compiler-generated calls, not provider equivalence or general correctness. Kuna's owner remains its own reported association; any future inline view should preserve that provenance, handle missing or conflicting owners, and avoid silently treating Ghidra's additional references as Kuna observations. One fixture, one host and one MCP profile.

Stripped local-symbol control

On a source-built arm64 Mach-O copied and stripped of local symbols, direct Kuna 1.988 reported two calls with owners sub_100000340 and sub_100000368. Real REA/Ghidra 12.1.4 independently resolved those call addresses to entries 0x100000340 and 0x100000368, named FUN_100000340 and FUN_100000368. The unstripped fixture's local symbol table identifies those same entries as the two original source-built callers. Real compact stdio MCP on the unmerged source-row prototype retained both Kuna rows; the trace still returned two unavailable-containment questions and a stored-pointer coverage question.

The stripped target SHA-256 was beb335dd869d22d160ea3365e0b689a366e00e329cb20c622ab43766b472ae1c, unchanged and unexecuted. This one control shows why provider-reported names and canonical entry addresses should remain distinct: generated names are not original source names, even when entry addresses agree. It does not establish general owner correctness or behavior for binaries with no function boundaries.

Inline observation experiment

An unmerged local prototype adds provider-attributed observation rows to each existing trace reference, keeping containing_procedure separate. Real Kuna 1.988 compact and full stdio MCP on the mixed call/pointer fixture returned the call kind and provider-reported owner for the instruction, and a stored-pointer row with no reported procedure for the slot; containment remained explicitly unavailable. Both responses validated against their fetched output schemas (Ajv 2020, strict and format validation disabled), and trace and linked source Evidence survived export/import into fresh target-free sessions. The target was unchanged and unexecuted.

A synthetic parser/workflow control placed an instruction row and pointer row at the same source address: one normalized address retained both observations. This is a boundary experiment, not a claim that Kuna emitted such a collision for a real artifact. On the 100-caller fixture in compact MCP, the prototype returned 100 owner observations and one pointer observation inline; it still produced 102 existing coverage/containment questions. The trace SDK response was 118,867 serialized bytes versus 74,739 for the previous source-only experiment; the bundle was 386,397 versus 365,743 bytes. These contain different facts and are not a token or performance benchmark.

This is a design probe, not a proposed final contract: provider kind semantics, null owner versus unavailable containment, source associations, independently resolvable unknowns, bounded output and partial publication still need design and broader validation. The prototype currently retains per-source raw rows and adds inline projections, with associated duplication.

Snapshot handoff and repeated-question identity

On the mixed call/pointer Mach-O, real Kuna 1.988 stdio MCP in compact and full profiles ran xrefs and trace_feature, closed with a snapshot, then opened that snapshot in a fresh session and repeated the calls. The unmerged inline/source prototype returned equal normalized traces with the same two references and three question texts before and after. The exported snapshot had no provider cache entries, so this exercised a fresh provider observation after handoff, not snapshot-cache replay. The fixture stayed unchanged and was not executed.

In both profiles, the prototype's xrefs raw-output hash and source Evidence ID changed after reopening; the trace Evidence differed only in its source link and identity. The retained unknown registry grew from three to six, with each same-text question tied to its respective distinct trace Evidence. On unchanged #8509, the analogous trace had no source links, its ID stayed stable, and the one containment question remained one across the same sequence. These are different implementations and observed facts: baseline stability omits the pointer and linked xrefs source, so it is not a replacement for preserving provenance.

Earlier direct Kuna controls established that its serialized input path changes the raw-output digest across staged sessions. The raw digest must remain truthful; whether a separate semantic source identity or another explicit relationship can prevent repeated questions without conflating distinct observations or losing provenance is unresolved. This control covered one warm-cache fixture on one macOS host; it does not establish cache-eviction behavior, generic snapshot replay, or prevalence. Related: #8510 and #8546.

Manual association of two observations

Using the two distinct real trace Evidence records from the snapshot-handoff experiment, compact and full stdio MCP controls imported the bundle, opened the matching target, recorded a new caller-chosen coverage question supported by the first trace, then updated that same unknown to revision 2 with both trace IDs as supporting Evidence. A separately worded containment question retained a different unknown ID. After export and import into a fresh target-free session, list_unknowns returned the revision-2 head with both support IDs and both immutable trace records were present. The binary was unchanged and unexecuted. Bundle unknowns includes revision history, so selecting the first matching revision is not equivalent to selecting the current head; initial test-harness attempts were corrected to use list_unknowns.

This demonstrates an explicit manual association, not automatic semantic equivalence, deduplication of existing workflow questions, or a supported bulk migration. It also required opening the intended target to select its current scope (#8546). Automatic joining must define identity across target addresses, provider observations, changed coverage and resolved or contradicted questions; retaining both Evidence IDs alone does not justify merging questions.

Shared kind contract and partial provider facts

On REA source 6c7592d1f, direct Kuna 1.988 on the existing mixed call/pointer Mach-O again reported one call instruction row (0x10000042c to 0x100000410, owner _audit_direct_call) and one separate chained-fixup pointer row (0x100004008 to 0x100000410). These are static provider observations, not runtime call or binding evidence.

A local schema control passed the reported call label and a hypothetical positive call classification to the existing referenceKindSchema. It rejected the value because flow, jump, data, read, write, indirect, computed, conditional, terminal, primary, operand_index and external were absent. The available: false variant also rejects carrying the reported type. The shared contract can represent Ghidra's fully populated classification or wholly unavailable classification, but not this partial kind observation with the remaining attributes unknown. Setting the missing fields to false without evidence would manufacture negative facts.

This is a schema/control observation, not a claim that all those attributes are necessarily unknowable from every Kuna feature. Source inspection also shows NativeCallRoutes currently treats kind.available as sufficient to select call rows and classifies a call as direct when both computed and indirect are false; functionRelationshipComparison likewise takes an available kind as a complete known record. A partial-kind design must update these consumers so unknown flags do not become negative facts or a direct-call claim. Before adapting Kuna to procedure_references or a shared typed view, decide how the existing semantic owner represents partial provider-reported kinds, distinguish provider labels from cross-provider interpretations, and verify Ghidra consumers and existing Evidence. Do not infer API parity or make pointer rows into calls. Related address-only paging work: #8591.

Address formation is not an object read

On a source-owned, unexecuted arm64 Mach-O using REA 859e5fb95 (based on d3ab0faf5, with an unrelated matching change), I placed _audit_other at 0x100004000 and _audit_value at 0x100004004. In _audit_clobbered, ADRP computes page 0x100004000, mov x8, x0 overwrites that value, then ldr w0, [x8] reads from the incoming pointer. In the positive _audit_read control, ADRP followed by ldr w0, [x8, #4] reads _audit_value. nm and otool -tvV independently confirmed the layout and instruction sequence.

Direct Kuna 1.988 reports a data reference from the first ADRP 0x100000370 to the page address 0x100004000; it does not report a read of _audit_value for _audit_clobbered. For _audit_read it reports read from 0x100000384 to 0x100004004. Real REA/Ghidra outgoing procedure references return no rows for _audit_clobbered, and a READ for the positive control at the same instruction and target. Real REA/Kuna compact stdio MCP xrefs returns only ["0x100000370"] for the page address and ["0x100000384"] for the value, without the respective data and read kinds. Both are provider reference observations; the page-address row alone does not establish a read of the symbol placed there. Target SHA-256 52619ee4646fa08cea1f1c042a606d04e2215898e4f4d7234cc46fdf66f98eb7 remained unchanged.

This is a positive/negative static control of one architecture and one host, not an upstream defect or proof of general completeness. It reinforces that the proposed agent workflow should preserve the provider's kind, instruction and source association and leave object use uncertain where the provider only observed page formation. A raw address-only result cannot communicate this distinction.

Producer-owned instruction rows and Evidence delivery

An unmerged experiment on the separate pointer/coverage prototype at ce9095d72 retains the instruction rows already validated by KunaReferenceFiles, after its exact-target and alias checks. On the two-address overwritten-register control above, real Kuna 1.988 in full and compact stdio MCP returned the unchanged address-only xrefs result and retained the corresponding data/ADRP and read/LDR observations, with their reported owners, in each xrefs Evidence raw_result.references. After bundle export and import into a fresh target-free session, both records and their instruction strings remained retrievable. The target was unchanged and unexecuted. The prototype does not add a typed output contract or a paged view.

The extra data is not free. A separate unexecuted source-built arm64 Mach-O with 1,000 call sites to one target produced 1,000 address rows in both runs. On current baseline d3ab0faf5, the SDK-serialized compact MCP reply was 34,573 bytes and the exported bundle was 16,389 bytes. An initial prototype that retained the parsed provider row with duplicate numeric/hex endpoint fields returned 1,000 typed rows in an 896,803-byte reply and a 417,498-byte bundle. A second producer representation retained each kind, instruction, source address and nullable source/target function identities, using the already-validated parent target instead of repeating the equivalent endpoint forms: its reply was 474,803 bytes and bundle 220,498 bytes. The same target SHA-256 ae01effbd75a6d8685342dec622bac0471ae8c659d725f158aa2b6ee10d72359 stayed unchanged. These are serialized byte counts for different information, not model-token, time, CPU or memory benchmarks; this is one stress fixture and host.

Source inspection shows AnalysisViewParent presently receives normalizedResult but not raw_result, and #8591 pages only the normalized address list. Exposing provider rows by teaching the shared view to parse Kuna's raw JSON would move provider interpretation into a consumer and would still not solve bounded complete-result delivery. The experiment suggests a producer-owned, provider-attributed normalized observation contract with a bounded selection or linked Evidence, while preserving the existing address result, exact target, source identities, coverage and offline handoff. Its location and publication/lifecycle semantics remain a design question. Prototype alias collisions, large typed-row pagination, provider coverage differences, cancellation and other platforms remain unverified; no proposed change is ready for integration.

Typed instruction rows at the real response boundary

I combined the unmerged normalized-instruction-source experiment above with the address paging work in draft #8591 and used real Kuna 1.988 through compact stdio MCP on macOS arm64. An unexecuted source-built Mach-O has 1,200 functions with 20 distinct call instructions apiece to one target. Direct Kuna reports 24,000 call rows (13,202,112 bytes of JSON, below the existing Kuna xrefs input bound). The experimental REA xrefs completed, retained its Evidence and returned the existing default 10 MiB MCP resource_constraint with an address-view continuation. Following that continuation with 1,000-row pages recovered all 24,000 normalized addresses, in original index order, in 24 pages; its rows contained no kind or instruction. Exact get_evidence_bundle(detail: records) for the parent also returned resource_constraint. export_evidence_bundle succeeded: the 6,407,910-byte bundle retained all 24,000 normalized addresses and all 24,000 typed instruction rows, including their call labels. The target SHA-256 39635cc81931a1214e09b724aec705a6376912d0836455aeed44c6fbfa31a1a3 remained unchanged.

This is one stress fixture and an unmerged combination, not current-main pointer or typed-row behavior. It confirms that the existing address continuation is useful but does not provide bounded MCP access to the new typed facts. Complete export is a tested recovery when filesystem access is available. A production contract needs a bounded way to select the producer-owned observations and their qualifications, not just a larger response or the raw provider JSON; full-profile, independent schema validation for a typed page, cancellation, and other platforms remain unverified.

Experimental typed-source pages

A further unmerged experiment gives the producer a provider-attributed normalized instruction-observation envelope and adds an instruction-references native-context facet. In the combined prototype, real Kuna 1.988 compact MCP hit the same 10 MiB xrefs response boundary on the 24,000-site fixture. From its retained parent ID, 24 typed pages reconstructed every source address, original Kuna kind, instruction and reported function name in provider row order. Each successful response validated against the fetched output schema using Ajv 2020 (strict/format validation disabled), and rows were checked against direct Kuna JSON. After export, a fresh full-profile target-free session imported the bundle and repeated the complete typed paging with the same parent ID and schema validation. The target remained unchanged and unexecuted. The bundle exported after generating the compact pages was 10,947,963 bytes and contained those retained page Evidence records as well as the parent; this is serialized size, not a token or resource benchmark.

An old real baseline xrefs record without this envelope exposed an additional contract issue in the first experiment: a null row set accompanied by complete-within-view, total 0 and exhausted true falsely suggested an examined empty set. The revised experiment rejects that facet request with invalid_request and says the observations were not recorded; the old record remains importable. This is a possible recovery, not an established final UX.

This prototype demonstrates a feasible handoff but is not ready to integrate. It currently adds a raw-result field to the generic view parent, has not established a bounded policy for arbitrarily large single rows or caller-selected pages, does not page stored-pointer observations, and needs explicit target/operation identity validation, lifecycle/cancellation and malformed-source tests. The intermediate view records themselves increase retained state. Decide whether a linked normalized Evidence record or another domain-owned representation can address those boundaries without provider protocol leaking into application code. Do not infer real-provider completeness or cross-provider semantic equivalence from this one host/fixture.

Typed-page identity, byte bounds and inline recovery controls

On the unmerged typed-page experiment, I constructed digest-valid synthetic inline Evidence with a requested xrefs target 0x100004004 but a typed-observation target 0x100004000. The first projector accepted and displayed the conflicting target. A revised experiment rejects mismatched xrefs target, a typed source address absent from the normalized xrefs result, and a non-xrefs parent operation with explicit invalid_request results. The real 24,000-site compact run and fresh full-profile offline import still reconstructed and schema-validated all observations against direct Kuna. This is experimental consumer-side validation, not a shipped integrity guarantee or a complete producer/consumer ownership design.

Requesting 24,000 typed rows in one page originally produced another MCP resource_constraint after materializing an oversized view. An experimental byte-bound projection returned 4,470 rows and byte_limited: true with next_offset: 4470; repeatedly requesting the full remaining set recovered all 24,000 rows in six pages in compact live and full offline sessions. This uses a 1 MiB projection allowance to leave room for the larger MCP response envelope; it is an implementation budget, not an upstream row-count limit. Single oversized rows still return a constraint with the parent ID and next offset.

A synthetic 1.1 MB instruction row exposed a recovery distinction: inline Evidence is not automatically retained, so instructing the caller simply to export it was wrong. The prototype now directs the caller to its original Evidence or, if retained, a bundle export. This control does not establish that Kuna emits such an instruction in practice; it tests the public boundary and explicit recovery. The typed-page experiment remains unmerged and still needs lifecycle, target-ownership-at-the-producing-boundary, bounded admission before parsing/cloning, stored-pointer rows and real-provider cross-platform verification. The narrower inline recovery issue also reproduced in #8606 and was fixed there with a public MCP regression.

Post-1.988 incoming-reference coverage control

Upstream Noelo-Lab/kuna#1412 merged after 1.988 and adds coverage to xrefs. On macOS arm64 I built its exact merge commit b8eae8b660ceb0dc2a9162d0df2e63272c9280ed in an isolated debug worktree and supplied the 1.988 specs. This is an unverified source build reporting 0.1.0, not a released Kuna version.

On an unexecuted arm64 Mach-O with _main calling _middle in an executable but unflagged section and _middle calling _goal, direct source-build xrefs --to _goal --json returned the known _direct_goal caller and reported _middle in coverage.unwalked, with a note that its references were omitted. The source build's --from _middle --kind call returned the _middle → _goal call with coverage.decoded: true. A paired NOP fixture returned zero outgoing rows while still reporting decoded: true; released Kuna 1.988 returned zero outgoing rows for both. The incoming query still omitted _middle on both and marked it unwalked in the new build. The two fixture SHA-256 values were 59f969db3cc65c93ab6e412f85a60094437ee600e7e4aac73d9dd0d7e3164b04 and 309ca96fafea56d504aa9be7b3ce140ac5d7b9175caf0a38521c8fa2d9e2fd32; neither changed or ran.

Real REA stdio MCP on #8608 head 5fad84347, using a local wrapper to supply the source-build specs, returned the known incoming address in both compact and full profiles; successful responses validated against the advertised schemas. Its Evidence contained an output digest, byte count and examined row count but neither the unwalked address nor the producer's reason, and its generic limitation only warns that an empty result does not prove absence. Source inspection shows xrefsDocument does not retain the new coverage field. This is one real unverified-source control; it does not claim current verified 1.988 emits that field or that the upstream coverage is exhaustive.

This strengthens the task-level case for preserving provider-reported coverage alongside reference observations, including nonempty answers: an agent can otherwise see a real caller while losing a concrete provider-reported omission. Any integration should parse at the producer boundary, preserve unknown/missing and unrecognized coverage rather than inventing completeness, bound large lists, and retain the facts through composed traces and Evidence handoffs. Evaluate a released Kuna and other formats before claiming verified support; this does not imply adding a raw outgoing-xrefs wrapper. Related path-coverage issue: #8362.

The same real unverified-source control through trace_feature({query: "goal"}) in compact and full stdio MCP returned the _direct_goal reference, truncated: false, and a residual unknown about that reference's unavailable containing procedure. It did not name the separately reported unwalked _middle, its coverage reason, or a linked xrefs Evidence record; the generic xrefs limitation remained present. Both trace outputs validated against their advertised schemas. This shows the specific coverage gap also affects the composed workflow; the containing-procedure unknown is a different fact and does not communicate the missing source. A follow-up exported the trace through the public bundle tool and imported it into a fresh target-free stdio MCP session in both profiles. The imported trace exactly matched the live record: it retained the caller and the containing-procedure unknown, but had no xrefs Evidence link or specific unwalked-source warning. The target digest stayed unchanged. This validates faithful handoff of that already incomplete trace; it does not establish cross-provider or general bundle behavior.

Released Kuna 1.989 coverage control

On current REA main 9ebbe67e and the released Kuna 1.989 executable on macOS arm64, a self-built, unexecuted Mach-O (17a184835ff22f86c6398d96b699acdd2eb200ebb3d966d6fb5af7d0cebff4ed) has _direct_goal and _middle calling _goal, with _middle in executable __TEXT,__const that is not marked as code. Direct kuna xrefs --to _goal --json returned _direct_goal and explicitly named _middle in coverage.unwalked, including the producer's omission explanation; direct --from _middle --kind call independently returned its call to _goal and marked that source decoded. This repeats the earlier source-build observation with the released provider, not just the unverified build.

Real REA stdio MCP in compact and full profiles returned the direct caller address through xrefs, with output digest, byte count, examined-row count and generic alias/empty-result limitation, but no unwalked address or producer coverage reason. trace_feature({query: "goal"}) returned that caller, truncated: false, and an unknown for its unavailable containing-procedure lookup; it likewise omitted _middle and the producer's separate coverage warning, and had no linked xrefs Evidence. Both calls were checked with the SDK's fetched tool definitions. The target digest stayed unchanged. This is one intentionally constructed input; it does not establish general provider completeness or autonomous-agent behavior.

Coverage ownership and bounds

Source-derived at 9ebbe67e: KunaReferenceFiles.xrefsDocument does not retain the producer's coverage, and KunaIncomingReferences keeps only the normalized addresses, source digest/byte count, examined rows and alias exclusions. KunaReferenceQueries bounds native output to 16 MiB and charges cached queries against a 16 MiB/128-entry budget; it does not retain the original JSON after parsing. trace_feature propagates referencesTruncated as its output-truncation flag, while the unwalked-section fact describes provider discovery coverage and is not the same claim. An implementation should account for the raw output's size and accessible lifetime, carry complete source facts or explicit omissions, and keep discovery completeness separate from delivery truncation. A generic warning alone would not identify the omitted function; setting truncated: true without defining that distinction would misstate the existing contract. These are source-derived constraints, not an implemented design.

Empty-result coverage control

On the same unexecuted Mach-O and released Kuna 1.989, direct xrefs --to _unrelated --json returned no incoming rows but still reported _middle in coverage.unwalked with the reason its outgoing references were omitted. REA xrefs returned an empty array with its existing generic warning that emptiness does not prove absence. In both real stdio MCP profiles, trace_feature({query: "unrelated"}) returned the match, no references, truncated: false and residual_unknowns: [], while its top-level Evidence limitations retained that same generic xrefs warning. It did not report the concrete unwalked function. This is not a claim that _middle actually references _unrelated, or that REA has no warning at all; it demonstrates that the specific producer coverage fact is missing even for an empty result. The target hash remained unchanged.

Released-provider Evidence handoff

Using released Kuna 1.989 and REA 9ebbe67e, the goal trace above was exported with export_evidence_bundle and imported into a fresh target-free stdio MCP session, in compact and full profiles. The imported trace exactly matched the live record: it retained the observed caller, the distinct containing-procedure unknown, and the generic empty-result caveat. The bundle contained the trace and its unknown record, but no xrefs Evidence record or link, and did not identify the producer-reported unwalked _middle. The target hash remained unchanged. This confirms the earlier source-build handoff result on the released provider; it is not an assertion about other providers or exhaustive coverage.

Same-fixture Ghidra comparison

On the same arm64 Mach-O (17a184835ff22f86c6398d96b699acdd2eb200ebb3d966d6fb5af7d0cebff4ed), real REA/Ghidra 12.1.4 stdio MCP in compact and full profiles returned incoming xrefs 0x1000003d0, 0x1000003e0 and 0x1000080ba for _goal. procedure_references(direction: incoming) classified the first two as unconditional calls owned by _direct_goal and _middle, respectively, and the third as DATA with no containing procedure. trace_feature({query: "goal"}) also retained these three sources and resolved the first two owners. Ghidra and Kuna agree on the observed direct caller but differ on the unwalked source and extra data reference in this fixture; neither result establishes general completeness or runtime execution. The target hash remained unchanged. This makes provider-attributed kind, owner and coverage important without requiring the tools to return identical rows.

String-to-reference workflow on Kuna 1.989

On REA 9ebbe67e05af08b567e215340da993c08dae378f, real full-profile MCP with Ghidra 12.1.4 and Kuna 1.989 analyzed a self-built, unexecuted arm64 Mach-O containing rea_static_reference_marker_92 passed to puts. Both search_strings calls found the string at 0x1000004b0; both xrefs calls returned the source 0x10000046c. Ghidra trace_feature reported its containing _show_marker entry at 0x100000460. Kuna trace_feature retained the source site and explicitly reported the containing procedure unavailable, with a corresponding residual unknown.

Direct Kuna 1.989 xrefs --to 0x1000004b0 --json reported that same source as a data reference, included the observed add x0, x0, #0x4b0 instruction, and associated it with _show_marker at 0x100000460. Its own data_refs_coverage was none; this does not establish complete reference coverage or a runtime read. The executable SHA-256 505c40c275630562f6e3d17c7eed368692de7d4f24040372631eb654c1c31a2d was unchanged. This is one fixture and output profile, not a general provider comparison or agent study.

For the same Kuna 1.989 string-reference source 0x10000046c, real REA MCP address_name returned null, resolve_containing_procedure returned capability unavailable, and procedure_assembly rejected the interior address because it was not a discovered entry. inspect_address_context preserved the unavailable owner and other unsupported facets. With the independently known entry 0x100000460, procedure_assembly succeeded and included the add at the reference site. The target digest was unchanged. This checks the available follow-up workflow on this fixture; it does not imply that all source sites have an owner or that a null name rules one out.

Source inspection explains the information boundary: the Kuna incoming-reference parser validates each row's kind, endpoints, function records and instruction, but stores only distinct exact-target source addresses plus aggregate digest/count/alias metadata. The existing shared typed-reference shape requires Ghidra-like boolean classifications that Kuna's kind does not necessarily establish. A task-level solution should retain provider-observed owner/kind as such, preserve unavailable attributes and coverage, and keep raw and derived provenance linked; it should not invent a full Ghidra reference classification or silently change the address-only xrefs result.

Multi-reference string control

A separate self-built arm64 Mach-O had five distinct functions each pass the same string to puts. On REA 9ebbe67e with real full-profile MCP, Kuna 1.989 and Ghidra 12.1.4 both returned the same five reference sites. Ghidra trace_feature associated each site with its function; Kuna's trace returned each site with an unavailable owner and five corresponding residual-unknown messages. Direct Kuna xrefs --to reported data kind and a distinct source function name and entry for each of the five rows. These provider-reported owners are static observations, not runtime calls or a completeness guarantee. The target SHA-256 bd6fa99310d3d201cc1dec615458a5814a5be055d16191d7280d7414d6042db9 remained unchanged.

This makes the handoff useful for more than a single site and shows that any compact task-level result must preserve per-site distinctions. It does not establish agent token use, latency, or how often this pattern occurs. An implementation must also preserve producer coverage and explicitly distinguish a reported owner from an independently resolved containing-procedure result.

Combined stored-pointer and unwalked-source control

On macOS arm64 I built an unexecuted Mach-O containing _direct_goal calling _goal, a stored pointer _goal_pointer to _goal, and _middle in an executable but unflagged section calling _goal. Its SHA-256 remained bfce057bbe8c7611cb6b86ae3d646e80d953b9da41ec90963991958f40e60bff. Direct released Kuna 1.989 xrefs --to _goal --json returned the call at 0x1000003d0, a separate chained-fixup pointer from 0x100004008, and coverage.unwalked identifying _middle at 0x1000003e0. An explicit direct Kuna xrefs --from 0x1000003e0 --kind call decoded the call to _goal; dyld_info -fixups independently identified the pointer slot's rebase to _goal.

REA main 9ebbe67e with real Kuna 1.989 in both compact and full stdio MCP profiles returned only the call source from xrefs; trace_feature retained that source with owner unavailable, truncated: false, and the owner unknown. Neither result identified the provider-reported pointer or unwalked function. This combines the two separately documented omissions (#8510 and the coverage observations above) in one answer: preserving a pointer row alone would still lose discovery coverage, and preserving the coverage warning alone would still lose the pointer. truncated is a delivery property and should not be repurposed to mean unwalked code. This is one controlled static artifact; neither a stored pointer nor a decoded call proves runtime use.

Ghidra metadata references and unclassified stored words

On a separate source-built, unexecuted x86-64 ELF shared object (SHA-256 967b95de168d4c41f039449e6e379a05c1e1ded75ce3427b6359a21f22655a83), a veneer jumps indirectly through a function-pointer slot, while two other stored pointers refer to the veneer and slot. Ghidra 12.1.4 loads the image at a different base from Kuna. In both REA/Ghidra MCP profiles, xrefs for veneer 0x1013a0 returned 0x1000c0 and _elfSectionHeaders:0x1d0; trace_feature("audit_veneer") carried those as bare source addresses with not_in_procedure and no residual unknowns. A separate direct Ghidra headless ReferenceManager query identified both as imported DATA references, the latter in the ELF-header address space. These observations are not calls or runtime execution evidence.

Direct Ghidra analysis also showed the loaded words at 0x103468 and 0x103470 hold the rebased addresses of the veneer and slot, but had no ReferenceManager references from either word; its Listing classified them as undefined8. Thus their absence from Ghidra xrefs in this case is not a lost REA ReferenceManager row. By contrast the defined slot at 0x103460 had a Ghidra DATA reference to 0x1013b0; REA's incoming xrefs included the slot, while inspect_native_instruction at the slot returned status: data and an empty instruction-reference list. The target hash remained unchanged. These are static observations for one fixture, not proof that either provider exhaustively finds pointers or metadata.

Consider preserving the provider's source kind, address space and attribution when a trace presents incoming references. Do not equate not_in_procedure with a code caller, treat imported metadata as runtime reachability, or infer a reference from a loaded word without stating the derivation and coverage. This complements #8245's string-match provenance and #8510's stored-pointer observations.

Originally created by @morluto on GitHub (Oct 31, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8348 ### Before submitting - [x] I searched the open and closed issues and pull requests for a related discussion. - [x] I understand the contribution scope must be reviewed before integration; open questions are welcome here. - [x] This discussion does not include credentials, private samples, or sensitive target data. ### Decision needed How should an agent distinguish an incoming call from an address reference and find its containing function when using Kuna, without overstating the provider's reference coverage or changing the meaning of `xrefs`? ### Context and evidence On REA `60149282fcfc05ac32fbc94434c107710120da6f`, macOS arm64, I used real stdio MCP sessions with Kuna 1.986 and Ghidra 12.1.4 on an unexecuted, self-built x86-64 ELF shared library (SHA-256 `a795b954d45b321ca77b641784fca0b3a1e33f17bd826e2d5ebf8de9543de1bd`; unchanged after both sessions). Its `audit_direct` has a NOP followed by `call audit_target`; `audit_address` has a NOP followed by `lea audit_target(%rip),%rax`. - REA/Kuna `xrefs` for `audit_target` returned `["0x12ab", "0x12b2"]`. `procedure_callers` returned `audit_direct`'s entry `0x12aa`. Both source addresses are inside procedures, not entries: `procedure_assembly` rejected them and `resolve_containing_procedure` and `procedure_references(direction: incoming)` were `capability_unavailable`. Assembly by the already-known function names showed the CALL and LEA. - Direct `kuna xrefs <fixture> --to audit_target --json` returned both rows with kind, source procedure and instruction: `call` / `audit_direct` / `CALL 0x12a4` and `data` / `audit_address` / `LEA RAX,[0x12a4]`. Its `--kind call` and `--kind data` each returned the corresponding row. These observations are available upstream but are not conveyed by REA's address-only `xrefs` result. - REA/Ghidra's `procedure_references(direction: incoming)` reported a call and a DATA reference with their source procedures, plus two DATA references without source procedures. Its image addresses differ from Kuna's. `resolve_containing_procedure` found both instruction owners. Those extra references demonstrate why a bare incoming address need not be an executable caller. The LEA forms an address; it is not evidence of a memory read or a runtime call. The example does not establish the providers' general completeness or accuracy, or how frequently agents encounter this situation. ### Expected interaction with targets Read existing files and use the existing static provider; no target execution or target mutation is proposed. ### Boundary details (optional) Preserve provider-specific kinds, coordinates, source/target identity, provenance, and incomplete or unknown coverage. An absent or unsupported owner is distinct from a verified non-procedure address. Do not infer that every incoming reference is a call or silently change the existing address-only contract. ### Options and tradeoffs Investigate whether an existing task-oriented incoming-reference workflow can provide compact, typed observations and optional owners, with explicit unknowns, or whether a separate bounded view is needed. Compare provider semantics before mapping kinds: direct Kuna labels are not automatically equivalent to Ghidra ReferenceManager types, and known Kuna reference gaps need to remain visible. Avoid requiring a full dossier per address or merely exposing the raw provider API. ### Verification available so far I have a prototype or observed results. ### Success criteria and open questions Exercise the call, address-formation, non-procedure source, unresolved owner and no-reference cases through public CLI/MCP with real providers; verify retained Evidence, provider-specific address spaces and honest coverage. The observation above is limited to one constructed x86-64 ELF; other formats, architectures, indirect calls, data reads/writes and SDK/schema behavior remain to be checked. ### References Related: #8190 (outgoing data references and provider coverage), #8288 (feature-trace behavior when containment is unavailable), #1245 (closed earlier Ghidra incoming-reference discussion). Upstream false-reference and omitted-reference examples: Noelo-Lab/kuna#1334 and Noelo-Lab/kuna#1360. Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0. ### Kuna 1.988 import-slot control On REA `bafe3784c` plus the version-only #8509 change, real Kuna 1.986/1.988 compact stdio MCP analyzed the same owned, unexecuted arm64 Mach-O import-slot fixture. For slot `0x4000`, 1.986 returned no incoming references; 1.988 returned `0x1360`, `0x1364`, and `0x1368`. Direct Kuna 1.988 `xrefs --to 0x4000 --json` identifies those rows respectively as address-formation `data`, slot `read`, and indirect `call`, with instructions. REA's `xrefs` Evidence contains the three addresses and a digest/count of the raw provider response, but not the per-row kinds or instructions; `procedure_references` remains unavailable with Kuna. The target SHA-256 was unchanged. This confirms the new release makes the existing task-level distinction more useful, but a call-kind row is still a static provider observation, not runtime call proof. One fixture and host; no all-reference coverage claim. ### Following the 1.988 slot references through REA With real Kuna 1.988, Ghidra 12.1.4, and the import-slot fixture above, I tested the following public stdio MCP sequence on #8509 head `7f344af1a` in both full and compact schema profiles. Kuna `xrefs(0x4000)` returned three instruction addresses. For each, `resolve_containing_procedure` and `inspect_native_instruction` returned `capability_unavailable`; `procedure_assembly` refused the interior address as not an inventory entry. If the caller already knows `_audit_import_call`, its assembly succeeds. Explicitly switching to Ghidra resolves all three owners to `_audit_import_call` and decodes `adrp`, `ldr`, and `blr`; the target digest remained unchanged and it was not executed. Switching providers has the session-state implications in #8289. The tested Kuna producer parser already validates each upstream row's source/target, kind, owner and instruction, but retains only deduplicated addresses and an output digest/count. A task-level optional incoming-reference detail in an existing address investigation could preserve those producer-owned facts and explicit unknown coverage without requiring a full dossier per result. Its contract would need to preserve exact-address filtering and alias exclusions, provider-specific kind meanings, null owners, limits/paging and offline Evidence; adding every upstream xrefs option or silently changing the existing address-only result is not implied. No autonomous agent trace, other hosts, or exhaustive xref coverage was tested. ### Existing typed-reference alternative and schema boundary On #8509 head `7f344af1a`, real compact and full MCP `inspect_native_instruction` at the function target in a mixed arm64 Mach-O distinguished Ghidra `UNCONDITIONAL_CALL` at `0x10000042c` from `DATA` at pointer slot `0x100004008`. The same operation at the slot returned `status: data` and its incoming `READ`. In a separate statically linked x86-64 ELF, Ghidra likewise identified slot `0x202190` as `DATA` to target `0x201159`. Typed Ghidra Evidence and xrefs survived export/import into a fresh target-free MCP session, and successful workflow responses validated against both advertised output schemas (Ajv 2020, strict and format validation disabled). Both targets remained unchanged and were not executed. These are static observations, not runtime calls. Kuna 1.988 returned `capability_unavailable` for the same instruction inspections while its direct xrefs reports the Mach-O stored pointer separately. Source inspection shows the existing `nativeInstructionSchema` requires a listing status, architecture, mode, and reference fields including boolean `indirect`/`computed` and numeric `operand_index`. A Kuna xrefs row alone does not establish all those facts; forcing it into that result could invent values. Preserve provider-reported kinds and unavailable facets explicitly. The CLI handoff to the existing typed alternative is addressed by draft #8514; this does not add Kuna support. Two controlled fixtures on one host do not establish general provider equivalence. ### Mixed instruction and pointer provenance in the unmerged prototype On the existing source-built arm64 Mach-O fixture (SHA-256 `9fc02faea0c3723a094c209adbe62a279011df4d508298625bd766fa20ed7c46`), direct Kuna 1.988 reported a `call` at `0x10000042c`, owned by `_audit_direct_call` with instruction `bl 0x100000410`, and a separate `chained-fixups` pointer at `0x100004008` to the same target. In both full and compact real stdio MCP sessions, the unmerged #8510 pointer prototype returned both addresses, and its trace linked the xrefs Evidence. The linked source's raw result preserved the pointer row and origin, but retained only the instruction-row count, not that row's kind, instruction, or owner. The inline trace represented both addresses with `containing_procedure: unavailable`; it did not identify either reference kind. The target was unchanged and unexecuted. Thus the prototype repairs pointer omission but does not yet make a mixed set fully actionable. A consumer must not infer the remaining address is an instruction merely by subtracting reported pointer rows: address deduplication and independently incomplete categories do not establish mutually exclusive kinds. Preserve producer-observed rows and their distinctions or explicitly represent unavailable facts, subject to bounded delivery and offline provenance. This is one fixture on macOS arm64, not a general accuracy or autonomous-agent study. ### Source-row preservation experiment A further unmerged local experiment retains validated, exact-target Kuna instruction rows alongside stored-pointer rows in the linked xrefs Evidence. On the same mixed Mach-O, real compact and full stdio MCP returned both addresses; the source Evidence retained Kuna's `call`, `_audit_direct_call`, `bl 0x100000410` and the separate chained-fixup pointer. Export and import into a fresh target-free session preserved the trace and linked source Evidence exactly in both profiles; the fixture digest remained unchanged and the target was not executed. The focused Kuna reference-file suite passed (22 tests). This shows the existing Evidence path can carry these parsed producer facts; it does not make them inline trace observations or establish a final contract. Exact-target and alias behavior, duplicate or overlapping rows, admission and retained-size growth, partial publication, historical profiles, and larger/cross-platform examples still require design and verification. The experiment is neither an API-parity proposal nor a shipped fix. ### Many incoming references and reported owners An owned arm64 Mach-O with 100 noinline callers and one function-pointer slot gave direct Kuna 1.988 exactly 100 call rows, each with a distinct reported source function, plus one chained-fixup pointer row. On #8509, compact stdio MCP `xrefs` returned 100 addresses; `trace_feature` returned 100 references and 100 residual questions because separate containment resolution is unavailable. On the unmerged source-row/pointer experiment, `xrefs` returned 101 addresses and preserved the 100 instruction rows and pointer; its trace returned 101 references and 102 unknowns (101 unavailable containment results plus the stored-pointer coverage gap). The owned target (SHA-256 `3d39bb659d0ec6fdc907ef9ea3d88c2f59fa1b3b870a6f743f518c227c3b18af`) remained unchanged and was never executed. For this one case the retained producer rows contain 100 candidate reported owners even though the composed trace cannot use them. A task-oriented view could expose those as Kuna-reported source-function associations while keeping independent containment resolution unavailable; it must not silently promote them to independently verified containment. In serialized SDK call responses, the baseline and experimental direct xrefs responses were 7,639 and 95,885 bytes, respectively; exported bundles after both calls were 318,256 and 365,743 bytes. The runs differ in preserved facts and unknowns, so these sizes describe the tested tradeoff, not a controlled performance benchmark or token measurement. Normal capacity exhaustion, other architectures, full schema profile, and automated agent selection were not tested. ### Cross-provider owner and artifact control On the same 100-caller Mach-O, real Ghidra 12.1.4 through REA compact stdio MCP returned 102 incoming references to the target. All 100 Kuna call source addresses had matching Ghidra source-procedure names and entries. Independent `nm -nm` matched those 100 function entries, and `otool -tvV` showed a branch-and-link to the target at each source address. Five sampled addresses also resolved through Ghidra's `resolve_containing_procedure` and decoded as direct calls through `inspect_native_instruction`. Ghidra additionally reported two DATA references, including the pointer slot. The target digest was unchanged and it was not executed. This supports the reported owner facts for these 100 compiler-generated calls, not provider equivalence or general correctness. Kuna's owner remains its own reported association; any future inline view should preserve that provenance, handle missing or conflicting owners, and avoid silently treating Ghidra's additional references as Kuna observations. One fixture, one host and one MCP profile. ### Stripped local-symbol control On a source-built arm64 Mach-O copied and stripped of local symbols, direct Kuna 1.988 reported two calls with owners `sub_100000340` and `sub_100000368`. Real REA/Ghidra 12.1.4 independently resolved those call addresses to entries `0x100000340` and `0x100000368`, named `FUN_100000340` and `FUN_100000368`. The unstripped fixture's local symbol table identifies those same entries as the two original source-built callers. Real compact stdio MCP on the unmerged source-row prototype retained both Kuna rows; the trace still returned two unavailable-containment questions and a stored-pointer coverage question. The stripped target SHA-256 was `beb335dd869d22d160ea3365e0b689a366e00e329cb20c622ab43766b472ae1c`, unchanged and unexecuted. This one control shows why provider-reported names and canonical entry addresses should remain distinct: generated names are not original source names, even when entry addresses agree. It does not establish general owner correctness or behavior for binaries with no function boundaries. ### Inline observation experiment An unmerged local prototype adds provider-attributed observation rows to each existing trace reference, keeping `containing_procedure` separate. Real Kuna 1.988 compact and full stdio MCP on the mixed call/pointer fixture returned the call kind and provider-reported owner for the instruction, and a stored-pointer row with no reported procedure for the slot; containment remained explicitly unavailable. Both responses validated against their fetched output schemas (Ajv 2020, strict and format validation disabled), and trace and linked source Evidence survived export/import into fresh target-free sessions. The target was unchanged and unexecuted. A synthetic parser/workflow control placed an instruction row and pointer row at the same source address: one normalized address retained both observations. This is a boundary experiment, not a claim that Kuna emitted such a collision for a real artifact. On the 100-caller fixture in compact MCP, the prototype returned 100 owner observations and one pointer observation inline; it still produced 102 existing coverage/containment questions. The trace SDK response was 118,867 serialized bytes versus 74,739 for the previous source-only experiment; the bundle was 386,397 versus 365,743 bytes. These contain different facts and are not a token or performance benchmark. This is a design probe, not a proposed final contract: provider kind semantics, null owner versus unavailable containment, source associations, independently resolvable unknowns, bounded output and partial publication still need design and broader validation. The prototype currently retains per-source raw rows and adds inline projections, with associated duplication. ### Snapshot handoff and repeated-question identity On the mixed call/pointer Mach-O, real Kuna 1.988 stdio MCP in compact and full profiles ran `xrefs` and `trace_feature`, closed with a snapshot, then opened that snapshot in a fresh session and repeated the calls. The unmerged inline/source prototype returned equal normalized traces with the same two references and three question texts before and after. The exported snapshot had no provider cache entries, so this exercised a fresh provider observation after handoff, not snapshot-cache replay. The fixture stayed unchanged and was not executed. In both profiles, the prototype's xrefs raw-output hash and source Evidence ID changed after reopening; the trace Evidence differed only in its source link and identity. The retained unknown registry grew from three to six, with each same-text question tied to its respective distinct trace Evidence. On unchanged #8509, the analogous trace had no source links, its ID stayed stable, and the one containment question remained one across the same sequence. These are different implementations and observed facts: baseline stability omits the pointer and linked xrefs source, so it is not a replacement for preserving provenance. Earlier direct Kuna controls established that its serialized input path changes the raw-output digest across staged sessions. The raw digest must remain truthful; whether a separate semantic source identity or another explicit relationship can prevent repeated questions without conflating distinct observations or losing provenance is unresolved. This control covered one warm-cache fixture on one macOS host; it does not establish cache-eviction behavior, generic snapshot replay, or prevalence. Related: #8510 and #8546. ### Manual association of two observations Using the two distinct real trace Evidence records from the snapshot-handoff experiment, compact and full stdio MCP controls imported the bundle, opened the matching target, recorded a new caller-chosen coverage question supported by the first trace, then updated that same unknown to revision 2 with both trace IDs as supporting Evidence. A separately worded containment question retained a different unknown ID. After export and import into a fresh target-free session, `list_unknowns` returned the revision-2 head with both support IDs and both immutable trace records were present. The binary was unchanged and unexecuted. Bundle `unknowns` includes revision history, so selecting the first matching revision is not equivalent to selecting the current head; initial test-harness attempts were corrected to use `list_unknowns`. This demonstrates an explicit manual association, not automatic semantic equivalence, deduplication of existing workflow questions, or a supported bulk migration. It also required opening the intended target to select its current scope (#8546). Automatic joining must define identity across target addresses, provider observations, changed coverage and resolved or contradicted questions; retaining both Evidence IDs alone does not justify merging questions. ### Shared kind contract and partial provider facts On REA source `6c7592d1f`, direct Kuna 1.988 on the existing mixed call/pointer Mach-O again reported one `call` instruction row (`0x10000042c` to `0x100000410`, owner `_audit_direct_call`) and one separate chained-fixup `pointer` row (`0x100004008` to `0x100000410`). These are static provider observations, not runtime call or binding evidence. A local schema control passed the reported `call` label and a hypothetical positive call classification to the existing `referenceKindSchema`. It rejected the value because `flow`, `jump`, `data`, `read`, `write`, `indirect`, `computed`, `conditional`, `terminal`, `primary`, `operand_index` and `external` were absent. The `available: false` variant also rejects carrying the reported `type`. The shared contract can represent Ghidra's fully populated classification or wholly unavailable classification, but not this partial kind observation with the remaining attributes unknown. Setting the missing fields to false without evidence would manufacture negative facts. This is a schema/control observation, not a claim that all those attributes are necessarily unknowable from every Kuna feature. Source inspection also shows `NativeCallRoutes` currently treats `kind.available` as sufficient to select call rows and classifies a call as direct when both `computed` and `indirect` are false; `functionRelationshipComparison` likewise takes an available kind as a complete known record. A partial-kind design must update these consumers so unknown flags do not become negative facts or a direct-call claim. Before adapting Kuna to `procedure_references` or a shared typed view, decide how the existing semantic owner represents partial provider-reported kinds, distinguish provider labels from cross-provider interpretations, and verify Ghidra consumers and existing Evidence. Do not infer API parity or make pointer rows into calls. Related address-only paging work: #8591. ### Address formation is not an object read On a source-owned, unexecuted arm64 Mach-O using REA `859e5fb95` (based on `d3ab0faf5`, with an unrelated matching change), I placed `_audit_other` at `0x100004000` and `_audit_value` at `0x100004004`. In `_audit_clobbered`, ADRP computes page `0x100004000`, `mov x8, x0` overwrites that value, then `ldr w0, [x8]` reads from the incoming pointer. In the positive `_audit_read` control, ADRP followed by `ldr w0, [x8, #4]` reads `_audit_value`. `nm` and `otool -tvV` independently confirmed the layout and instruction sequence. Direct Kuna 1.988 reports a `data` reference from the first ADRP `0x100000370` to the page address `0x100004000`; it does not report a read of `_audit_value` for `_audit_clobbered`. For `_audit_read` it reports `read` from `0x100000384` to `0x100004004`. Real REA/Ghidra outgoing procedure references return no rows for `_audit_clobbered`, and a `READ` for the positive control at the same instruction and target. Real REA/Kuna compact stdio MCP `xrefs` returns only `["0x100000370"]` for the page address and `["0x100000384"]` for the value, without the respective `data` and `read` kinds. Both are provider reference observations; the page-address row alone does not establish a read of the symbol placed there. Target SHA-256 `52619ee4646fa08cea1f1c042a606d04e2215898e4f4d7234cc46fdf66f98eb7` remained unchanged. This is a positive/negative static control of one architecture and one host, not an upstream defect or proof of general completeness. It reinforces that the proposed agent workflow should preserve the provider's kind, instruction and source association and leave object use uncertain where the provider only observed page formation. A raw address-only result cannot communicate this distinction. ### Producer-owned instruction rows and Evidence delivery An unmerged experiment on the separate pointer/coverage prototype at `ce9095d72` retains the instruction rows already validated by `KunaReferenceFiles`, after its exact-target and alias checks. On the two-address overwritten-register control above, real Kuna 1.988 in full and compact stdio MCP returned the unchanged address-only `xrefs` result and retained the corresponding `data`/ADRP and `read`/LDR observations, with their reported owners, in each xrefs Evidence `raw_result.references`. After bundle export and import into a fresh target-free session, both records and their instruction strings remained retrievable. The target was unchanged and unexecuted. The prototype does not add a typed output contract or a paged view. The extra data is not free. A separate unexecuted source-built arm64 Mach-O with 1,000 call sites to one target produced 1,000 address rows in both runs. On current baseline `d3ab0faf5`, the SDK-serialized compact MCP reply was 34,573 bytes and the exported bundle was 16,389 bytes. An initial prototype that retained the parsed provider row with duplicate numeric/hex endpoint fields returned 1,000 typed rows in an 896,803-byte reply and a 417,498-byte bundle. A second producer representation retained each kind, instruction, source address and nullable source/target function identities, using the already-validated parent target instead of repeating the equivalent endpoint forms: its reply was 474,803 bytes and bundle 220,498 bytes. The same target SHA-256 `ae01effbd75a6d8685342dec622bac0471ae8c659d725f158aa2b6ee10d72359` stayed unchanged. These are serialized byte counts for different information, not model-token, time, CPU or memory benchmarks; this is one stress fixture and host. Source inspection shows `AnalysisViewParent` presently receives `normalizedResult` but not `raw_result`, and #8591 pages only the normalized address list. Exposing provider rows by teaching the shared view to parse Kuna's raw JSON would move provider interpretation into a consumer and would still not solve bounded complete-result delivery. The experiment suggests a producer-owned, provider-attributed normalized observation contract with a bounded selection or linked Evidence, while preserving the existing address result, exact target, source identities, coverage and offline handoff. Its location and publication/lifecycle semantics remain a design question. Prototype alias collisions, large typed-row pagination, provider coverage differences, cancellation and other platforms remain unverified; no proposed change is ready for integration. ### Typed instruction rows at the real response boundary I combined the unmerged normalized-instruction-source experiment above with the address paging work in draft #8591 and used real Kuna 1.988 through compact stdio MCP on macOS arm64. An unexecuted source-built Mach-O has 1,200 functions with 20 distinct call instructions apiece to one target. Direct Kuna reports 24,000 call rows (13,202,112 bytes of JSON, below the existing Kuna xrefs input bound). The experimental REA `xrefs` completed, retained its Evidence and returned the existing default 10 MiB MCP `resource_constraint` with an address-view continuation. Following that continuation with 1,000-row pages recovered all 24,000 normalized addresses, in original index order, in 24 pages; its rows contained no kind or instruction. Exact `get_evidence_bundle(detail: records)` for the parent also returned `resource_constraint`. `export_evidence_bundle` succeeded: the 6,407,910-byte bundle retained all 24,000 normalized addresses and all 24,000 typed instruction rows, including their `call` labels. The target SHA-256 `39635cc81931a1214e09b724aec705a6376912d0836455aeed44c6fbfa31a1a3` remained unchanged. This is one stress fixture and an unmerged combination, not current-main pointer or typed-row behavior. It confirms that the existing address continuation is useful but does not provide bounded MCP access to the new typed facts. Complete export is a tested recovery when filesystem access is available. A production contract needs a bounded way to select the producer-owned observations and their qualifications, not just a larger response or the raw provider JSON; full-profile, independent schema validation for a typed page, cancellation, and other platforms remain unverified. ### Experimental typed-source pages A further unmerged experiment gives the producer a provider-attributed normalized instruction-observation envelope and adds an `instruction-references` native-context facet. In the combined prototype, real Kuna 1.988 compact MCP hit the same 10 MiB `xrefs` response boundary on the 24,000-site fixture. From its retained parent ID, 24 typed pages reconstructed every source address, original Kuna kind, instruction and reported function name in provider row order. Each successful response validated against the fetched output schema using Ajv 2020 (strict/format validation disabled), and rows were checked against direct Kuna JSON. After export, a fresh full-profile target-free session imported the bundle and repeated the complete typed paging with the same parent ID and schema validation. The target remained unchanged and unexecuted. The bundle exported after generating the compact pages was 10,947,963 bytes and contained those retained page Evidence records as well as the parent; this is serialized size, not a token or resource benchmark. An old real baseline xrefs record without this envelope exposed an additional contract issue in the first experiment: a null row set accompanied by `complete-within-view`, total 0 and exhausted true falsely suggested an examined empty set. The revised experiment rejects that facet request with `invalid_request` and says the observations were not recorded; the old record remains importable. This is a possible recovery, not an established final UX. This prototype demonstrates a feasible handoff but is not ready to integrate. It currently adds a raw-result field to the generic view parent, has not established a bounded policy for arbitrarily large single rows or caller-selected pages, does not page stored-pointer observations, and needs explicit target/operation identity validation, lifecycle/cancellation and malformed-source tests. The intermediate view records themselves increase retained state. Decide whether a linked normalized Evidence record or another domain-owned representation can address those boundaries without provider protocol leaking into application code. Do not infer real-provider completeness or cross-provider semantic equivalence from this one host/fixture. ### Typed-page identity, byte bounds and inline recovery controls On the unmerged typed-page experiment, I constructed digest-valid synthetic inline Evidence with a requested xrefs target `0x100004004` but a typed-observation target `0x100004000`. The first projector accepted and displayed the conflicting target. A revised experiment rejects mismatched xrefs target, a typed source address absent from the normalized xrefs result, and a non-xrefs parent operation with explicit `invalid_request` results. The real 24,000-site compact run and fresh full-profile offline import still reconstructed and schema-validated all observations against direct Kuna. This is experimental consumer-side validation, not a shipped integrity guarantee or a complete producer/consumer ownership design. Requesting 24,000 typed rows in one page originally produced another MCP `resource_constraint` after materializing an oversized view. An experimental byte-bound projection returned 4,470 rows and `byte_limited: true` with `next_offset: 4470`; repeatedly requesting the full remaining set recovered all 24,000 rows in six pages in compact live and full offline sessions. This uses a 1 MiB projection allowance to leave room for the larger MCP response envelope; it is an implementation budget, not an upstream row-count limit. Single oversized rows still return a constraint with the parent ID and next offset. A synthetic 1.1 MB instruction row exposed a recovery distinction: inline Evidence is not automatically retained, so instructing the caller simply to export it was wrong. The prototype now directs the caller to its original Evidence or, if retained, a bundle export. This control does not establish that Kuna emits such an instruction in practice; it tests the public boundary and explicit recovery. The typed-page experiment remains unmerged and still needs lifecycle, target-ownership-at-the-producing-boundary, bounded admission before parsing/cloning, stored-pointer rows and real-provider cross-platform verification. The narrower inline recovery issue also reproduced in #8606 and was fixed there with a public MCP regression. ### Post-1.988 incoming-reference coverage control Upstream [Noelo-Lab/kuna#1412](https://github.com/Noelo-Lab/kuna/pull/1412) merged after 1.988 and adds `coverage` to `xrefs`. On macOS arm64 I built its exact merge commit `b8eae8b660ceb0dc2a9162d0df2e63272c9280ed` in an isolated debug worktree and supplied the 1.988 specs. This is an unverified source build reporting `0.1.0`, not a released Kuna version. On an unexecuted arm64 Mach-O with `_main` calling `_middle` in an executable but unflagged section and `_middle` calling `_goal`, direct source-build `xrefs --to _goal --json` returned the known `_direct_goal` caller and reported `_middle` in `coverage.unwalked`, with a note that its references were omitted. The source build's `--from _middle --kind call` returned the `_middle → _goal` call with `coverage.decoded: true`. A paired NOP fixture returned zero outgoing rows while still reporting `decoded: true`; released Kuna 1.988 returned zero outgoing rows for both. The incoming query still omitted `_middle` on both and marked it unwalked in the new build. The two fixture SHA-256 values were `59f969db3cc65c93ab6e412f85a60094437ee600e7e4aac73d9dd0d7e3164b04` and `309ca96fafea56d504aa9be7b3ce140ac5d7b9175caf0a38521c8fa2d9e2fd32`; neither changed or ran. Real REA stdio MCP on #8608 head `5fad84347`, using a local wrapper to supply the source-build specs, returned the known incoming address in both compact and full profiles; successful responses validated against the advertised schemas. Its Evidence contained an output digest, byte count and examined row count but neither the unwalked address nor the producer's reason, and its generic limitation only warns that an empty result does not prove absence. Source inspection shows `xrefsDocument` does not retain the new `coverage` field. This is one real unverified-source control; it does not claim current verified 1.988 emits that field or that the upstream coverage is exhaustive. This strengthens the task-level case for preserving provider-reported coverage alongside reference observations, including nonempty answers: an agent can otherwise see a real caller while losing a concrete provider-reported omission. Any integration should parse at the producer boundary, preserve unknown/missing and unrecognized coverage rather than inventing completeness, bound large lists, and retain the facts through composed traces and Evidence handoffs. Evaluate a released Kuna and other formats before claiming verified support; this does not imply adding a raw outgoing-xrefs wrapper. Related path-coverage issue: #8362. The same real unverified-source control through `trace_feature({query: "goal"})` in compact and full stdio MCP returned the `_direct_goal` reference, `truncated: false`, and a residual unknown about that reference's unavailable containing procedure. It did not name the separately reported unwalked `_middle`, its coverage reason, or a linked xrefs Evidence record; the generic xrefs limitation remained present. Both trace outputs validated against their advertised schemas. This shows the specific coverage gap also affects the composed workflow; the containing-procedure unknown is a different fact and does not communicate the missing source. A follow-up exported the trace through the public bundle tool and imported it into a fresh target-free stdio MCP session in both profiles. The imported trace exactly matched the live record: it retained the caller and the containing-procedure unknown, but had no xrefs Evidence link or specific unwalked-source warning. The target digest stayed unchanged. This validates faithful handoff of that already incomplete trace; it does not establish cross-provider or general bundle behavior. ### Released Kuna 1.989 coverage control On current REA main `9ebbe67e` and the released Kuna 1.989 executable on macOS arm64, a self-built, unexecuted Mach-O (`17a184835ff22f86c6398d96b699acdd2eb200ebb3d966d6fb5af7d0cebff4ed`) has `_direct_goal` and `_middle` calling `_goal`, with `_middle` in executable `__TEXT,__const` that is not marked as code. Direct `kuna xrefs --to _goal --json` returned `_direct_goal` and explicitly named `_middle` in `coverage.unwalked`, including the producer's omission explanation; direct `--from _middle --kind call` independently returned its call to `_goal` and marked that source decoded. This repeats the earlier source-build observation with the released provider, not just the unverified build. Real REA stdio MCP in compact and full profiles returned the direct caller address through `xrefs`, with output digest, byte count, examined-row count and generic alias/empty-result limitation, but no unwalked address or producer coverage reason. `trace_feature({query: "goal"})` returned that caller, `truncated: false`, and an unknown for its unavailable containing-procedure lookup; it likewise omitted `_middle` and the producer's separate coverage warning, and had no linked xrefs Evidence. Both calls were checked with the SDK's fetched tool definitions. The target digest stayed unchanged. This is one intentionally constructed input; it does not establish general provider completeness or autonomous-agent behavior. ### Coverage ownership and bounds Source-derived at `9ebbe67e`: `KunaReferenceFiles.xrefsDocument` does not retain the producer's `coverage`, and `KunaIncomingReferences` keeps only the normalized addresses, source digest/byte count, examined rows and alias exclusions. `KunaReferenceQueries` bounds native output to 16 MiB and charges cached queries against a 16 MiB/128-entry budget; it does not retain the original JSON after parsing. `trace_feature` propagates `referencesTruncated` as its output-truncation flag, while the unwalked-section fact describes provider discovery coverage and is not the same claim. An implementation should account for the raw output's size and accessible lifetime, carry complete source facts or explicit omissions, and keep discovery completeness separate from delivery truncation. A generic warning alone would not identify the omitted function; setting `truncated: true` without defining that distinction would misstate the existing contract. These are source-derived constraints, not an implemented design. ### Empty-result coverage control On the same unexecuted Mach-O and released Kuna 1.989, direct `xrefs --to _unrelated --json` returned no incoming rows but still reported `_middle` in `coverage.unwalked` with the reason its outgoing references were omitted. REA `xrefs` returned an empty array with its existing generic warning that emptiness does not prove absence. In both real stdio MCP profiles, `trace_feature({query: "unrelated"})` returned the match, no references, `truncated: false` and `residual_unknowns: []`, while its top-level Evidence limitations retained that same generic xrefs warning. It did not report the concrete unwalked function. This is not a claim that `_middle` actually references `_unrelated`, or that REA has no warning at all; it demonstrates that the specific producer coverage fact is missing even for an empty result. The target hash remained unchanged. ### Released-provider Evidence handoff Using released Kuna 1.989 and REA `9ebbe67e`, the `goal` trace above was exported with `export_evidence_bundle` and imported into a fresh target-free stdio MCP session, in compact and full profiles. The imported trace exactly matched the live record: it retained the observed caller, the distinct containing-procedure unknown, and the generic empty-result caveat. The bundle contained the trace and its unknown record, but no `xrefs` Evidence record or link, and did not identify the producer-reported unwalked `_middle`. The target hash remained unchanged. This confirms the earlier source-build handoff result on the released provider; it is not an assertion about other providers or exhaustive coverage. ### Same-fixture Ghidra comparison On the same arm64 Mach-O (`17a184835ff22f86c6398d96b699acdd2eb200ebb3d966d6fb5af7d0cebff4ed`), real REA/Ghidra 12.1.4 stdio MCP in compact and full profiles returned incoming `xrefs` `0x1000003d0`, `0x1000003e0` and `0x1000080ba` for `_goal`. `procedure_references(direction: incoming)` classified the first two as unconditional calls owned by `_direct_goal` and `_middle`, respectively, and the third as DATA with no containing procedure. `trace_feature({query: "goal"})` also retained these three sources and resolved the first two owners. Ghidra and Kuna agree on the observed direct caller but differ on the unwalked source and extra data reference in this fixture; neither result establishes general completeness or runtime execution. The target hash remained unchanged. This makes provider-attributed kind, owner and coverage important without requiring the tools to return identical rows. ### String-to-reference workflow on Kuna 1.989 On REA `9ebbe67e05af08b567e215340da993c08dae378f`, real full-profile MCP with Ghidra 12.1.4 and Kuna 1.989 analyzed a self-built, unexecuted arm64 Mach-O containing `rea_static_reference_marker_92` passed to `puts`. Both `search_strings` calls found the string at `0x1000004b0`; both `xrefs` calls returned the source `0x10000046c`. Ghidra `trace_feature` reported its containing `_show_marker` entry at `0x100000460`. Kuna `trace_feature` retained the source site and explicitly reported the containing procedure unavailable, with a corresponding residual unknown. Direct Kuna 1.989 `xrefs --to 0x1000004b0 --json` reported that same source as a `data` reference, included the observed `add x0, x0, #0x4b0` instruction, and associated it with `_show_marker` at `0x100000460`. Its own `data_refs_coverage` was `none`; this does not establish complete reference coverage or a runtime read. The executable SHA-256 `505c40c275630562f6e3d17c7eed368692de7d4f24040372631eb654c1c31a2d` was unchanged. This is one fixture and output profile, not a general provider comparison or agent study. For the same Kuna 1.989 string-reference source `0x10000046c`, real REA MCP `address_name` returned null, `resolve_containing_procedure` returned capability unavailable, and `procedure_assembly` rejected the interior address because it was not a discovered entry. `inspect_address_context` preserved the unavailable owner and other unsupported facets. With the independently known entry `0x100000460`, `procedure_assembly` succeeded and included the `add` at the reference site. The target digest was unchanged. This checks the available follow-up workflow on this fixture; it does not imply that all source sites have an owner or that a null name rules one out. Source inspection explains the information boundary: the Kuna incoming-reference parser validates each row's kind, endpoints, function records and instruction, but stores only distinct exact-target source addresses plus aggregate digest/count/alias metadata. The existing shared typed-reference shape requires Ghidra-like boolean classifications that Kuna's `kind` does not necessarily establish. A task-level solution should retain provider-observed owner/kind as such, preserve unavailable attributes and coverage, and keep raw and derived provenance linked; it should not invent a full Ghidra reference classification or silently change the address-only `xrefs` result. ### Multi-reference string control A separate self-built arm64 Mach-O had five distinct functions each pass the same string to `puts`. On REA `9ebbe67e` with real full-profile MCP, Kuna 1.989 and Ghidra 12.1.4 both returned the same five reference sites. Ghidra `trace_feature` associated each site with its function; Kuna's trace returned each site with an unavailable owner and five corresponding residual-unknown messages. Direct Kuna `xrefs --to` reported `data` kind and a distinct source function name and entry for each of the five rows. These provider-reported owners are static observations, not runtime calls or a completeness guarantee. The target SHA-256 `bd6fa99310d3d201cc1dec615458a5814a5be055d16191d7280d7414d6042db9` remained unchanged. This makes the handoff useful for more than a single site and shows that any compact task-level result must preserve per-site distinctions. It does not establish agent token use, latency, or how often this pattern occurs. An implementation must also preserve producer coverage and explicitly distinguish a reported owner from an independently resolved containing-procedure result. ### Combined stored-pointer and unwalked-source control On macOS arm64 I built an unexecuted Mach-O containing `_direct_goal` calling `_goal`, a stored pointer `_goal_pointer` to `_goal`, and `_middle` in an executable but unflagged section calling `_goal`. Its SHA-256 remained `bfce057bbe8c7611cb6b86ae3d646e80d953b9da41ec90963991958f40e60bff`. Direct released Kuna 1.989 `xrefs --to _goal --json` returned the call at `0x1000003d0`, a separate chained-fixup pointer from `0x100004008`, and `coverage.unwalked` identifying `_middle` at `0x1000003e0`. An explicit direct Kuna `xrefs --from 0x1000003e0 --kind call` decoded the call to `_goal`; `dyld_info -fixups` independently identified the pointer slot's rebase to `_goal`. REA main `9ebbe67e` with real Kuna 1.989 in both compact and full stdio MCP profiles returned only the call source from `xrefs`; `trace_feature` retained that source with owner unavailable, `truncated: false`, and the owner unknown. Neither result identified the provider-reported pointer or unwalked function. This combines the two separately documented omissions (#8510 and the coverage observations above) in one answer: preserving a pointer row alone would still lose discovery coverage, and preserving the coverage warning alone would still lose the pointer. `truncated` is a delivery property and should not be repurposed to mean unwalked code. This is one controlled static artifact; neither a stored pointer nor a decoded call proves runtime use. ### Ghidra metadata references and unclassified stored words On a separate source-built, unexecuted x86-64 ELF shared object (SHA-256 `967b95de168d4c41f039449e6e379a05c1e1ded75ce3427b6359a21f22655a83`), a veneer jumps indirectly through a function-pointer slot, while two other stored pointers refer to the veneer and slot. Ghidra 12.1.4 loads the image at a different base from Kuna. In both REA/Ghidra MCP profiles, `xrefs` for veneer `0x1013a0` returned `0x1000c0` and `_elfSectionHeaders:0x1d0`; `trace_feature("audit_veneer")` carried those as bare source addresses with `not_in_procedure` and no residual unknowns. A separate direct Ghidra headless ReferenceManager query identified both as imported DATA references, the latter in the ELF-header address space. These observations are not calls or runtime execution evidence. Direct Ghidra analysis also showed the loaded words at `0x103468` and `0x103470` hold the rebased addresses of the veneer and slot, but had no ReferenceManager references from either word; its Listing classified them as `undefined8`. Thus their absence from Ghidra xrefs in this case is not a lost REA ReferenceManager row. By contrast the defined slot at `0x103460` had a Ghidra `DATA` reference to `0x1013b0`; REA's incoming `xrefs` included the slot, while `inspect_native_instruction` at the slot returned `status: data` and an empty instruction-reference list. The target hash remained unchanged. These are static observations for one fixture, not proof that either provider exhaustively finds pointers or metadata. Consider preserving the provider's source kind, address space and attribution when a trace presents incoming references. Do not equate `not_in_procedure` with a code caller, treat imported metadata as runtime reachability, or infer a reference from a loaded word without stating the derivation and coverage. This complements #8245's string-match provenance and #8510's stored-pointer observations.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

The public CLI gives the same address-only observations on the same fixture and provider versions: rea xrefs <fixture> audit_target --provider kuna --format json returned 0x12ab and 0x12b2; --provider ghidra returned the four Ghidra addresses listed by the MCP session. Both outputs included provider identity, target digest and limitations. In particular, Ghidra's limitation points to procedure_references and analyze_function for kind metadata; that recovery is unavailable for Kuna's procedure_references in this test. These CLI checks were read-only and do not establish other reference cases.

<!-- gh-comment-id:6546714228 --> @morluto commented on GitHub (Oct 31, 2026): The public CLI gives the same address-only observations on the same fixture and provider versions: `rea xrefs <fixture> audit_target --provider kuna --format json` returned `0x12ab` and `0x12b2`; `--provider ghidra` returned the four Ghidra addresses listed by the MCP session. Both outputs included provider identity, target digest and limitations. In particular, Ghidra's limitation points to `procedure_references` and `analyze_function` for kind metadata; that recovery is unavailable for Kuna's `procedure_references` in this test. These CLI checks were read-only and do not establish other reference cases.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

I checked the nearest existing alternatives on the same real sessions and fixture. analyze_function({procedure: "audit_target", detail: "complete"}) with Kuna correctly reported audit_direct as a caller, but its incoming_references was empty with facet_availability.references.available: false and the reason that the provider does not report typed references. list_procedures gave the three entry names and addresses, without body ranges; sorting these entries alone would not prove ownership of the interior addresses. inspect_native_instruction at both reference sites was capability_unavailable.

The same complete dossier with Ghidra retained the four typed incoming observations, including both instruction owners and the two sources with no owner; instruction inspection separately reported decoded CALL and LEA, and data for the other two sources. This confirms an existing task-level Ghidra path and an explicit Kuna limitation, not evidence that an empty Kuna dossier means no incoming references. Fixture digest remained unchanged; the calls were static and no target was executed.

<!-- gh-comment-id:6546726121 --> @morluto commented on GitHub (Oct 31, 2026): I checked the nearest existing alternatives on the same real sessions and fixture. `analyze_function({procedure: "audit_target", detail: "complete"})` with Kuna correctly reported `audit_direct` as a caller, but its `incoming_references` was empty with `facet_availability.references.available: false` and the reason that the provider does not report typed references. `list_procedures` gave the three entry names and addresses, without body ranges; sorting these entries alone would not prove ownership of the interior addresses. `inspect_native_instruction` at both reference sites was `capability_unavailable`. The same complete dossier with Ghidra retained the four typed incoming observations, including both instruction owners and the two sources with no owner; instruction inspection separately reported decoded CALL and LEA, and `data` for the other two sources. This confirms an existing task-level Ghidra path and an explicit Kuna limitation, not evidence that an empty Kuna dossier means no incoming references. Fixture digest remained unchanged; the calls were static and no target was executed.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Evidence handoff control: for each provider on the same fixture, analyze_function(detail: summary) → retained incoming_references view → export bundle → close → import into a fresh target-free MCP server → inspect the same view produced an exactly equal normalized view before and after export/import. For Kuna this was the explicit unavailable status; for Ghidra it was the first two typed rows. The SDK client fetched the advertised compact schemas before calls and validated successful results. Bundle and target hashes were unchanged during replay. This covers one page and one fixture, not every reference kind or provider scenario.

<!-- gh-comment-id:6546741330 --> @morluto commented on GitHub (Oct 31, 2026): Evidence handoff control: for each provider on the same fixture, `analyze_function(detail: summary)` → retained `incoming_references` view → export bundle → close → import into a fresh target-free MCP server → inspect the same view produced an exactly equal normalized view before and after export/import. For Kuna this was the explicit unavailable status; for Ghidra it was the first two typed rows. The SDK client fetched the advertised compact schemas before calls and validated successful results. Bundle and target hashes were unchanged during replay. This covers one page and one fixture, not every reference kind or provider scenario.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

A recent unreleased upstream source-build control adds another useful reference type to consider. Kuna #1359 reports relocation-backed pointer rows separately as data_refs, with a data_refs_coverage source. This does not change the call graph or make a pointer a call.

On the previously exercised unexecuted arm64 C++ fixture, direct Kuna 1.986 reported zero instruction xrefs to Doubler::transform at 0x10000053c. A build of upstream 8c74a944d74f8d3349755e05441a9628b4753111, using the release's compiled SLEIGH tree, still reported zero instruction xrefs, but additionally reported an 8-byte pointer from 0x100004060 to that method, source chained-fixups, with data_refs_coverage: "chained-fixups". It similarly reported 0x1000040a0 for Offsetter::transform. The earlier independent REA/Ghidra relocation/read control observed those same slots; neither establishes runtime dispatch.

On REA main d54a4661d, a real MCP session with that source build returned xrefs: [] for both targets, while correctly warning that an empty result does not prove no references. To check the actual handoff rather than compare separate invocations, I used a test-only wrapper to capture the exact xrefs JSON that REA consumed. Its SHA-256 matched REA's recorded source hash; that document contained the first pointer row above, but the REA Evidence recorded examined_rows: 0 for the instruction-xref array and did not include the separate pointer row or its coverage. Exporting and importing the resulting Evidence preserved the same REA result. procedure_callers remained empty and the call path remained unknown, which is appropriate for these data pointers.

This source build identified itself as 0.1.0 / verified_release: false; it is not the currently verified Kuna release or an upgrade recommendation. When evaluating a future verified release, this is a task-level opportunity to expose the typed pointer observation, source and coverage separately from instruction references and caller edges, while keeping exact-address and alias semantics. Avoid silently promoting pointer slots to calls or treating one metadata source as complete reference coverage. The target hash stayed unchanged and the target was not executed.

<!-- gh-comment-id:6547883853 --> @morluto commented on GitHub (Oct 31, 2026): A recent **unreleased upstream source-build control** adds another useful reference type to consider. Kuna [#1359](https://github.com/Noelo-Lab/kuna/pull/1359) reports relocation-backed pointer rows separately as `data_refs`, with a `data_refs_coverage` source. This does not change the call graph or make a pointer a call. On the previously exercised unexecuted arm64 C++ fixture, direct Kuna 1.986 reported zero instruction xrefs to `Doubler::transform` at `0x10000053c`. A build of upstream `8c74a944d74f8d3349755e05441a9628b4753111`, using the release's compiled SLEIGH tree, still reported zero instruction xrefs, but additionally reported an 8-byte pointer from `0x100004060` to that method, source `chained-fixups`, with `data_refs_coverage: "chained-fixups"`. It similarly reported `0x1000040a0` for `Offsetter::transform`. The earlier independent REA/Ghidra relocation/read control observed those same slots; neither establishes runtime dispatch. On REA main `d54a4661d`, a real MCP session with that source build returned `xrefs: []` for both targets, while correctly warning that an empty result does not prove no references. To check the actual handoff rather than compare separate invocations, I used a test-only wrapper to capture the exact `xrefs` JSON that REA consumed. Its SHA-256 matched REA's recorded source hash; that document contained the first pointer row above, but the REA Evidence recorded `examined_rows: 0` for the instruction-xref array and did not include the separate pointer row or its coverage. Exporting and importing the resulting Evidence preserved the same REA result. `procedure_callers` remained empty and the call path remained `unknown`, which is appropriate for these data pointers. This source build identified itself as `0.1.0` / `verified_release: false`; it is not the currently verified Kuna release or an upgrade recommendation. When evaluating a future verified release, this is a task-level opportunity to expose the typed pointer observation, source and coverage separately from instruction references and caller edges, while keeping exact-address and alias semantics. Avoid silently promoting pointer slots to calls or treating one metadata source as complete reference coverage. The target hash stayed unchanged and the target was not executed.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Mixed-reference control on REA main d54a4661d, using the current unverified Kuna source build 8c74a944d74f8d3349755e05441a9628b4753111 and Ghidra 12.1.4. I built a small unexecuted arm64 Mach-O with a direct caller, an adrp/add address-forming function, and a stored pointer, all targeting the same function.

For a layout with target 0x1004, direct current Kuna reported a call at 0x1014, a data address-formation observation at 0x1024, and a separate 8-byte pointer at 0x4000 from chained-fixup metadata. REA/Kuna xrefs returned the first two bare addresses, not the pointer or the distinction between the first two. REA/Ghidra xrefs returned those two plus 0x4000 and another source address. Both REA providers' procedure_callers returned only the direct caller, and their call-only paths from the address-forming function did not claim a call. This preserves the important distinction: address formation and a pointer slot are not themselves calls or runtime reachability.

A second, otherwise similar zero-based dylib put the function at 0x360: direct current Kuna reported the call and pointer but omitted the address-forming pair. The current build reports the pair in a nonzero-base executable control as well. I filed the narrowed provider observation as Kuna #1364; REA and Ghidra also did not report that low-address pair on the tested dylib, so this is not a claim of a generally complete Ghidra reference set. The fixed-layout REA controls passed their advertised compact SDK schemas, and target hashes remained unchanged.

Design implication: a task-oriented incoming-reference result needs provider-labeled partial classification and coverage. The current referenceKindSchema requires every boolean when available: true; Kuna's data label for an address-forming instruction alone does not establish the read/write flags, and the pointer row is a different fact. Filling unobserved flags as false, or silently appending pointer slots to callers, would overstate evidence. This is a source-derived contract observation and a design question, not a request to wrap the upstream JSON or ship compatibility code for an unverified build.

<!-- gh-comment-id:6547916817 --> @morluto commented on GitHub (Oct 31, 2026): Mixed-reference control on REA main `d54a4661d`, using the current unverified Kuna source build `8c74a944d74f8d3349755e05441a9628b4753111` and Ghidra 12.1.4. I built a small unexecuted arm64 Mach-O with a direct caller, an `adrp`/`add` address-forming function, and a stored pointer, all targeting the same function. For a layout with target `0x1004`, direct current Kuna reported a `call` at `0x1014`, a `data` address-formation observation at `0x1024`, and a separate 8-byte `pointer` at `0x4000` from chained-fixup metadata. REA/Kuna `xrefs` returned the first two bare addresses, not the pointer or the distinction between the first two. REA/Ghidra `xrefs` returned those two plus `0x4000` and another source address. Both REA providers' `procedure_callers` returned only the direct caller, and their call-only paths from the address-forming function did not claim a call. This preserves the important distinction: address formation and a pointer slot are not themselves calls or runtime reachability. A second, otherwise similar zero-based dylib put the function at `0x360`: direct current Kuna reported the call and pointer but omitted the address-forming pair. The current build reports the pair in a nonzero-base executable control as well. I filed the narrowed provider observation as [Kuna #1364](https://github.com/Noelo-Lab/kuna/issues/1364); REA and Ghidra also did not report that low-address pair on the tested dylib, so this is not a claim of a generally complete Ghidra reference set. The fixed-layout REA controls passed their advertised compact SDK schemas, and target hashes remained unchanged. Design implication: a task-oriented incoming-reference result needs provider-labeled partial classification and coverage. The current [`referenceKindSchema`](https://github.com/morluto/rea/blob/d54a4661da20382ad8456564a08569fdd24131c5/src/domain/native/nativeReference.ts) requires every boolean when `available: true`; Kuna's `data` label for an address-forming instruction alone does not establish the read/write flags, and the pointer row is a different fact. Filling unobserved flags as `false`, or silently appending pointer slots to callers, would overstate evidence. This is a source-derived contract observation and a design question, not a request to wrap the upstream JSON or ship compatibility code for an unverified build.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Independent ARM64 Mach-O control on REA d54a4661da20382ad8456564a08569fdd24131c5, verified Kuna 1.986 and Ghidra 12.1.4 (public stdio MCP, full advertised schemas): _main at 0x1000002d8 contains nop; bl _goal; ret; the call site is 0x1000002dc and _goal is 0x1000002e4.

  • REA/Kuna xrefs(_goal) returns the interior call site. Direct Kuna xrefs --to also reports that source's kind call, instruction, and from_function _main at 0x1000002d8.
  • Passing the returned site to procedure_address, procedure_pseudo_code, procedure_assembly, or analyze_function is rejected because it is not a discovered procedure entry. resolve_containing_procedure is unavailable. The first three error responses also advise inspecting the input schema, even though the request conforms to it; that advice cannot resolve the entry-versus-interior distinction. Selecting _main explicitly succeeds, and its assembly confirms the instruction.
  • For this known call target, procedure_callers(_goal) is a working narrower route: both providers returned the _main entry. It does not map every non-call xref or establish complete call coverage.
  • In the Ghidra session the same interior address resolves to entry 0x1000002d8; pseudocode and assembly work at both the call site and the explicit entry. Its xrefs also contains an additional reference of a different kind, so the complete address list must not be treated as all callers.

An unverified build of current Kuna source behaved the same on these requests, which is not a verified-release or upgrade claim. The synthetic target was not executed and its SHA-256 266a48ebeff34f2d28a2432dc0cf379872ad73f5212c63aac60ad6fe49033eb5 was unchanged. This broadens the earlier ELF example to one ARM64 Mach-O case; it does not establish reliable function extents or general reference completeness. In particular, the direct xref's source-function association is useful evidence for this particular call site, not a license to infer arbitrary address containment from neighboring entries.

<!-- gh-comment-id:6548112996 --> @morluto commented on GitHub (Oct 31, 2026): Independent ARM64 Mach-O control on REA `d54a4661da20382ad8456564a08569fdd24131c5`, verified Kuna 1.986 and Ghidra 12.1.4 (public stdio MCP, full advertised schemas): `_main` at `0x1000002d8` contains `nop; bl _goal; ret`; the call site is `0x1000002dc` and `_goal` is `0x1000002e4`. - REA/Kuna `xrefs(_goal)` returns the interior call site. Direct Kuna `xrefs --to` also reports that source's kind `call`, instruction, and `from_function` `_main` at `0x1000002d8`. - Passing the returned site to `procedure_address`, `procedure_pseudo_code`, `procedure_assembly`, or `analyze_function` is rejected because it is not a discovered procedure **entry**. `resolve_containing_procedure` is unavailable. The first three error responses also advise inspecting the input schema, even though the request conforms to it; that advice cannot resolve the entry-versus-interior distinction. Selecting `_main` explicitly succeeds, and its assembly confirms the instruction. - For this known call target, `procedure_callers(_goal)` is a working narrower route: both providers returned the `_main` entry. It does not map every non-call xref or establish complete call coverage. - In the Ghidra session the same interior address resolves to entry `0x1000002d8`; pseudocode and assembly work at both the call site and the explicit entry. Its `xrefs` also contains an additional reference of a different kind, so the complete address list must not be treated as all callers. An unverified build of current Kuna source behaved the same on these requests, which is not a verified-release or upgrade claim. The synthetic target was not executed and its SHA-256 `266a48ebeff34f2d28a2432dc0cf379872ad73f5212c63aac60ad6fe49033eb5` was unchanged. This broadens the earlier ELF example to one ARM64 Mach-O case; it does not establish reliable function extents or general reference completeness. In particular, the direct xref's source-function association is useful evidence for this particular call site, not a license to infer arbitrary address containment from neighboring entries.
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#6553
No description provided.