feat(experiment): compose bounded incoming reference spans

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
This commit is contained in:
N0zoM1z0
2026-10-17 00:34:36 +00:00
parent 391be63177
commit 4158e8a050
21 changed files with 2391 additions and 166 deletions
+6
View File
@@ -19,6 +19,12 @@ The [capability map](capability-map.md) distinguishes verified task coverage,
experimental exporter requirements and remaining unknowns before interpreting
adapter comparisons.
The [string-span study](string-span-study.md) adds paged incoming occurrence
queries for encoded object spans and independently verifies pooled suffix
references on real SQLite. The same native sparse range index serves Kuna's
existing string aggregates. Equivalent cold occurrence retrieval falls from
48.1 to 1.8 seconds; this is shared analysis reuse, not a Code Mode result.
The [AArch64 reference study](aarch64-xref-study.md) finds and fixes missing
ADRP-based string and memory references before the next model comparison.
Real SDK and traditional MCP preflights now agree with independent machine
+2 -34
View File
@@ -5,6 +5,7 @@ import { MAX_GRAPH_BLOCKS } from "./graph-limits.mjs";
import { createReference } from "./reference.mjs";
import { definition, hex, page, valueLocation } from "./api-contracts.mjs";
import { storageMethods } from "./storage-contracts.mjs";
import { referencesMethod } from "./reference-contracts.mjs";
const snapshot = z.string().startsWith("snap_");
const byteWindow = z.strictObject({
@@ -116,29 +117,7 @@ export const methods = {
"strings",
'await rea.strings({query:"incorrect header check"})',
),
references: definition(
{
summary:
"Read incoming exact-address or outgoing address/function xrefs with occurrence identity and ownership coverage.",
description:
"Batch incoming or outgoing lifted-code references without decompilation. Address scope selects exact target (incoming) or source instruction (outgoing); function scope selects outgoing native owning-function references and requires an entry address. Unknown function applicability stays unknown. Kind filtering is pushed to the native query; source rows, endpoints and Evidence identity remain. Recovered IR calls are a separate representation and may omit machine calls. Interior string references require a separate extent query.",
},
{
addresses: z.array(hex).min(1).max(16),
direction: z.enum(["incoming", "outgoing"]).default("incoming"),
scope: z.enum(["address", "function"]).default("address"),
kinds: z
.array(z.enum(["call", "jump", "data", "read", "write"]))
.min(1)
.optional(),
fields: z
.array(z.enum(["fromFunction", "toFunction", "instruction"]))
.optional(),
...page,
},
"references",
'await rea.references({addresses:["0x2000"]})',
),
references: referencesMethod,
snapshot: definition(
{
summary:
@@ -436,15 +415,4 @@ methods.bytes.input = methods.bytes.input.superRefine((value, context) => {
message: "Byte range end exceeds the native u64 address format",
});
});
methods.references.input = methods.references.input.superRefine(
(value, context) => {
if (value.direction === "incoming" && value.scope !== "address")
context.addIssue({
code: "custom",
path: ["scope"],
message: "Incoming references require exact address scope",
});
},
);
export const reference = createReference(methods);
@@ -22,6 +22,13 @@ engine profiles and limitations in [the trial record](trials.md).
| What machine bytes support the interpretation? | Batched loaded-image bytes and selected linear instruction windows, each with source/coverage | The case models independently derive signed relative targets. These windows do not establish runtime execution/alignment, a complete machine CFG, live memory or arbitrary file-offset mappings. |
| Can the answer be audited without returning the report? | Snapshot/source identity, selected fields, batch reads, paging and retained raw/decoded Evidence | Real CLI/MCP checks verify source access and capacity fallbacks. Scope/partial/unknown survive composition; a guest-derived answer keeps its own authority. |
The [string-span experiment](string-span-study.md) extends exact xrefs with
batched incoming target-coordinate spans. It preserves all eleven selected
SQLite data occurrences, including nine pooled suffix pointers, with individual
endpoints/owners and raw source rows. Kuna already had aggregate string-span
counts; the new occurrence query shares its sparse index. Range membership alone
does not establish whole-string use, access overlap or runtime behavior.
The useful grain so far is an identified object plus a relation with its exact
qualifiers: an operand needs its slot and PHI binding; a case/out-edge pair needs
both identities; an address needs its artifact/address space; an optimized
File diff suppressed because it is too large Load Diff
+8 -17
View File
@@ -5,7 +5,7 @@ import { join } from "node:path";
import { parseBinaryTarget } from "../../dist/application/BinaryTargetResolver.js";
import { inspectNativeInstallation } from "./native-installation.mjs";
import { KunaTargetCommands } from "../../dist/kuna/KunaTargetCommands.js";
import { referenceReader } from "./reference-reads.mjs";
import { NativeReferenceReads } from "./reference-reads.mjs";
import { PrivateRuntimeRoot } from "../../dist/process/PrivateRuntimeRoot.js";
import { parseNativeIR } from "./native-ir.mjs";
import { NativeEvidenceReads } from "./native-evidence-reads.mjs";
@@ -44,6 +44,11 @@ export class KunaFactOwner {
(id) => this.#sourceText(id),
() => this.#requireNativeIR(),
);
#references = new NativeReferenceReads(
(...args) => this.#native(...args),
(id) => this.#sourceText(id),
() => this.#requireNativeIR(),
);
#captureDirectory;
#evidence = new NativeEvidenceReads(async (id) => ({
text: await this.#sourceText(id),
@@ -203,22 +208,7 @@ export class KunaFactOwner {
return this.#catalogs.registers(input, signal);
}
async references(input, signal) {
return readFactBatch(
input.addresses.map((address) => referenceReader.query(input, address)),
(query) =>
this.#native(
referenceReader.key(query),
(path) => referenceReader.arguments(path, query),
signal,
),
async (capture, query) =>
referenceReader.read(
await this.#sourceText(capture.source.evidence_id),
capture.input,
query,
input,
),
);
return this.#references.read(input, signal);
}
async snapshot(input, signal) {
const capture = await this.#native(
@@ -468,6 +458,7 @@ export class KunaFactOwner {
this.#work.clear();
this.#snapshots.clear();
this.#catalogs.clear();
this.#references.clear();
this.#evidence.clear();
}
cancel() {
@@ -0,0 +1,63 @@
// One named reference operation; exact-address and image-span selectors stay distinct.
import { z } from "zod";
import { hex, page } from "./api-contracts.mjs";
const selection = {
kinds: z
.array(z.enum(["call", "jump", "data", "read", "write"]))
.min(1)
.optional(),
fields: z
.array(z.enum(["fromFunction", "toFunction", "instruction"]))
.optional(),
...page,
};
const span = z.strictObject({ start: hex, end_inclusive: hex });
const input = z
.union([
z.strictObject({
addresses: z.array(hex).min(1).max(16),
direction: z.enum(["incoming", "outgoing"]).default("incoming"),
scope: z.literal("address").default("address"),
...selection,
}),
z.strictObject({
addresses: z.array(hex).min(1).max(16),
direction: z.literal("outgoing"),
scope: z.literal("function"),
...selection,
}),
z.strictObject({
ranges: z.array(span).min(1).max(16),
direction: z.literal("incoming").default("incoming"),
scope: z.literal("range").default("range"),
...selection,
}),
])
.superRefine((value, context) => {
for (const [i, range] of (value.ranges ?? []).entries()) {
if (
!hex.safeParse(range.start).success ||
!hex.safeParse(range.end_inclusive).success
)
continue;
if (BigInt(range.start) > BigInt(range.end_inclusive)) {
context.addIssue({
code: "custom",
path: ["ranges", i, "end_inclusive"],
message: "Inclusive end precedes start",
});
}
}
});
export const referencesMethod = {
summary:
"Read exact-address/outgoing xrefs, or page batched incoming target-address spans with one native index.",
description:
"Select addresses for incoming exact-target or outgoing address/function references; function scope requires direction:outgoing and an entry. Alternatively select incoming native image ranges [{start,end_inclusive}] in caller order, including overlaps/duplicates; offset/limit apply independently to each range. Range membership tests the reference target coordinate, without callable-alias expansion. It does not prove memory-access overlap, whole-string use, or runtime binding. Both forms preserve occurrence/source-row identity, endpoints, native owning functions, paging and Evidence. A range batch builds one index; fields are projected from the same retained page. Completeness is limited to examined native references; discovery stays unknown. Recovered IR calls are a separate representation and may omit machine calls.",
input,
method: "references",
example:
'await rea.references({ranges:[{start:"0x2000",end_inclusive:"0x200d"}],kinds:["data"],limit:20})',
};
@@ -0,0 +1,143 @@
import assert from "node:assert/strict";
import test from "node:test";
import { referencesMethod } from "./reference-contracts.mjs";
import { methods } from "./api.mjs";
import { NativeReferenceReads } from "./reference-reads.mjs";
test("range selectors preserve old inputs and reject ambiguous/directional/malformed choices", () => {
assert.equal(methods.references, referencesMethod);
const schema = methods.references.input;
assert.deepEqual(schema.parse({ addresses: ["0x1"] }).addresses, ["0x1"]);
assert.equal(
schema.parse({
addresses: ["0x1"],
direction: "outgoing",
scope: "function",
}).scope,
"function",
);
const ranges = [{ start: "0x0", end_inclusive: "0xffffffffffffffff" }];
assert.equal(schema.parse({ ranges }).scope, "range");
for (const input of [
{ ranges, addresses: ["0x0"] },
{ addresses: ["0x1"], scope: "function", direction: "incoming" },
{ addresses: ["0x1"], scope: "function" },
{ ranges, scope: "function" },
{ ranges, direction: "outgoing" },
{ ranges: [] },
{ ranges: [{ start: "0x2", end_inclusive: "0x1" }] },
{ ranges: [{ start: "0xg", end_inclusive: "0x1" }] },
{ ranges: [{ start: "0x0", end_inclusive: "0x10000000000000000" }] },
{ ranges, limit: 129 },
{ ranges, offset: -1 },
])
assert.equal(schema.safeParse(input).success, false, JSON.stringify(input));
});
const range = { start: "0x100", end_inclusive: "0x10d" };
const wire = JSON.stringify({
schema_version: 1,
binary: "/input",
direction: "to",
count: 1,
ranges: [
{
...range,
index: 0,
offset: 0,
limit: 20,
total: 1,
count: 1,
next_offset: null,
},
],
xrefs: [
{
range_index: 0,
address: 8,
address_hex: "0x8",
kind: "data",
from_address: 8,
from_address_hex: "0x8",
to_address: 264,
to_address_hex: "0x108",
from_function: null,
to_function: null,
instruction: "LEA pointer",
},
],
});
const source = {
evidence_id: "ev_page",
sha256: "owned-sha",
bytes: Buffer.byteLength(wire),
elapsed_ms: 1,
};
test("range pages reuse one immutable parsed source across fields and expire on clear", async () => {
let reads = 0;
const invocations = [];
const reader = new NativeReferenceReads(
async (key, args) => {
invocations.push({ key, args: args("/input") });
return { input: "/input", source };
},
async () => {
reads++;
return wire;
},
() => {},
);
const input = referencesMethod.input.parse({ ranges: [range] });
const first = await reader.read(input);
const selected = await reader.read({ ...input, fields: [] });
assert.equal(reads, 1);
assert.equal(invocations[0].key, invocations[1].key);
assert.deepEqual(Object.keys(selected.results[0].items[0]), [
"source_row",
"from",
"to",
"kind",
]);
assert.throws(() => {
first.results[0].items[0].instruction = "corrupt";
}, TypeError);
first.results[0].items.length = 0;
assert.equal((await reader.read(input)).results[0].items.length, 1);
assert.equal(
selected.results[0].coverage.whole_string_use,
"not-established",
);
reader.clear();
await reader.read(input);
assert.equal(reads, 2);
});
test("unavailable and malformed ranges cannot masquerade as empty observations", async () => {
const input = referencesMethod.input.parse({ ranges: [range] });
const unavailable = new NativeReferenceReads(
() => {
throw Error("must not launch");
},
() => {},
() => {
throw Object.assign(Error("requires native"), {
code: "capability_unavailable",
});
},
);
await assert.rejects(
unavailable.read(input),
(e) => e.code === "capability_unavailable",
);
const malformed = new NativeReferenceReads(
async () => ({ input: "/input", source }),
async () => "{}",
() => {},
);
await assert.rejects(
malformed.read(input),
(e) =>
e.code === "invalid_provider_output" &&
e.details.evidence_id === source.evidence_id &&
e.details.source_retained === true,
);
});
+116 -1
View File
@@ -1,7 +1,122 @@
// Shared native reference selection; adapters never reinterpret wire endpoints.
import { parseKunaReferenceFacts } from "../../dist/kuna/KunaReferenceFiles.js";
import { pageFacts } from "./fact-reads.mjs";
import { requireResult } from "./fact-error.mjs";
import { FactFailure, requireResult } from "./fact-error.mjs";
import { parseKunaReferenceRanges } from "../../dist/kuna/KunaReferenceRanges.js";
import {
freezeFacts,
projectFact,
readFactBatch,
sourceSummary,
} from "./fact-reads.mjs";
import { NATIVE_OUTPUT_BYTES } from "./limits.mjs";
export class NativeReferenceReads {
#lastRange;
constructor(capture, readSource, requireRanges) {
this.capture = capture;
this.readSource = readSource;
this.requireRanges = requireRanges;
}
clear() {
this.#lastRange = undefined;
}
async read(input, signal) {
if (input.ranges) return this.#ranges(input, signal);
return readFactBatch(
input.addresses.map((address) => referenceReader.query(input, address)),
(query) =>
this.capture(
referenceReader.key(query),
(path) => referenceReader.arguments(path, query),
signal,
),
async (capture, query) =>
referenceReader.read(
await this.readSource(capture.source.evidence_id),
capture.input,
query,
input,
),
);
}
async #ranges(input, signal) {
this.requireRanges();
const capture = await this.capture(
`xref-ranges:${JSON.stringify([input.ranges, input.kinds, input.offset, input.limit])}`,
(path) => [
"xrefs",
path,
...input.ranges.flatMap((r) => [
"--to-range",
`${r.start}:${r.end_inclusive}`,
]),
"--offset",
String(input.offset),
"--limit",
String(input.limit),
"--output-bytes",
String(NATIVE_OUTPUT_BYTES),
...(input.kinds ? ["--kind", input.kinds.join(",")] : []),
"--json",
],
signal,
);
if (this.#lastRange?.source.evidence_id !== capture.source.evidence_id) {
try {
const facts = requireResult(
parseKunaReferenceRanges(
await this.readSource(capture.source.evidence_id),
capture.input,
input,
),
"invalid_provider_output",
);
this.#lastRange = freezeFacts({
facts,
source: sourceSummary(capture.source),
});
} catch (error) {
throw new FactFailure(
error.code ?? "invalid_provider_output",
error.message,
{
...error.details,
evidence_id: capture.source.evidence_id,
source_retained: true,
},
);
}
}
const { facts, source } = this.#lastRange;
return {
results: facts.results.map((page) => ({
ok: true,
range: { ...page.range },
range_index: page.range_index,
items: page.facts.map((row) =>
projectFact(row, input.fields, ["source_row", "from", "to", "kind"]),
),
total: page.total,
next_offset: page.next_offset,
source,
coverage: {
direction: "incoming",
scope: "target-address membership in the inclusive static image span",
examined_rows: page.total,
returned_rows: page.facts.length,
alias_expansion: "not-applied",
discovery: "unknown",
indirect_targets: "unknown",
machine_semantic_equivalence: "unknown",
runtime_binding: "unknown",
memory_access_overlap: "not-established",
whole_string_use: "not-established",
},
})),
};
}
}
export const referenceReader = {
query: (input, address) => ({
@@ -0,0 +1,25 @@
Analyze {{artifact_path}} statically, starting with the exact encoded strings
"no such table" and "sqlite_schema" (not longer messages that contain them).
Find each retained encoded string's inclusive byte span, including its observed
terminator when the inventory includes one. Find every retained incoming data
reference whose target coordinate lies in either span, including interior
targets. Report the distinct instruction occurrences, target offsets and owning
function entries; group counts by target offset without merging repeated sites
in the same function. State what the reference discovery actually covers.
Explain whether each interior reference establishes use of the complete text.
For the selected suffix use in sqlite3AlterRenameTable, verify the actual bytes,
passed register and next direct call target. For the base-message use in
sqlite3LocateTable, identify the local conditional message-pointer selection:
the tested mask/storage, zero/nonzero behavior, alternate string, passing
register and selected formatting/error call. Corroborate this with focused
machine instructions; distinguish a message component from the separate format
pointer. Do not infer runtime argument values, executed paths or symbol binding.
If using recovered IR, distinguish its identities/model from machine facts.
Give a focused answer with exact addresses, real Evidence IDs, target digest,
coverage and unknowns. Prefer selected facts/windows; keep full reports and
inventories out of model context. Static span membership alone proves neither
memory-access overlap nor whole-string use. Do not execute the target. Close
the target lease.
@@ -0,0 +1,18 @@
// Input for cli.mjs; the same named operations are used by both MCP adapters.
const literals = ["no such table", "sqlite_schema"];
const spans = [];
for (const literal of literals) {
const inventory = await rea.strings({query: literal, limit: 128});
if (!inventory.ok) return inventory;
const exact = inventory.data.items.filter(row => row.value === literal);
if (exact.length !== 1 || inventory.data.next_offset !== null)
return {unknown: "Resolve the inventory ambiguity or remaining pages", literal};
const row = exact[0];
if (row.string.byte_length < 1)
return {unknown: "No nonempty encoded byte extent", literal};
spans.push({start: row.address,
end_inclusive: "0x" + (BigInt(row.address) + BigInt(row.string.byte_length) - 1n).toString(16)});
}
const references = await rea.references({ranges: spans, kinds: ["data"],
fields: ["fromFunction"], limit: 20});
return references;
@@ -0,0 +1,72 @@
# Frozen SQLite pooled-string task
Freeze this question and oracle before the three model runs. The target is the
Linux x86-64 `/usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6`, SHA-256
`2e6eef9a727f081f0d453b4e5e6cbd8b9ef8b6f86cbf7681cbad444d3b0b55c8`.
It is inspected statically, never executed. The independent fixture oracle is
`verify-string-span-machine.py`; its fixed expectations are checked against ELF
loaded bytes, GNU disassembly and relocation records, without reading Kuna output.
This is a selected corpus check, not a proof of global reference completeness.
Both exact inventory strings are ASCII with an observed NUL and 14 encoded bytes:
| String | Inclusive span | Target offsets and occurrence counts |
| ------------- | ----------------- | ------------------------------------ |
| no such table | 0x11b376–0x11b383 | 0: 1; 8: 6 |
| sqlite_schema | 0x11b33f–0x11b34c | 0: 1; 7: 3 |
The complete selected data occurrence set is:
| From | Target | Owner entry | Native name |
| ------- | -------- | ----------- | ------------------------- |
| 0x4215c | 0x11b376 | 0x420d0 | sqlite3LocateTable |
| 0x2d709 | 0x11b37e | 0x2d600 | sqlite3AlterRenameTable |
| 0x4565e | 0x11b37e | 0x45590 | sqlite3StartTable |
| 0x4573d | 0x11b37e | 0x45590 | sqlite3StartTable |
| 0x48b2e | 0x11b37e | 0x47ff0 | sqlite3EndTable |
| 0xbad38 | 0x11b37e | 0xb90e0 | sqlite3Pragma |
| 0xbd1f0 | 0x11b37e | 0xbd1b0 | sqlite3InitOne |
| 0x422c5 | 0x11b33f | 0x42280 | sqlite3PreferredTableName |
| 0x41f0b | 0x11b346 | 0x41db0 | sqlite3FindTable |
| 0x41f65 | 0x11b346 | 0x41db0 | sqlite3FindTable |
| 0x41fb2 | 0x11b346 | 0x41db0 | sqlite3FindTable |
Order is irrelevant; all eleven distinct sites and owner entries are required.
Nine interior-target occurrences are suffix pointers (`table`, `schema`), not
nine uses of the entire original inventory literal. Scope is retained static
data references, not exhaustive machine dataflow, dynamic aliases or executed use.
At `0x2d709`, bytes `488d156edc0e00` form `0x11b37e` in RDX. There is no RDX
overwrite before the direct call at `0x2d716` to `0x29060`. The PLT jump slot is
`0x159fc8`, whose ELF JUMP_SLOT symbol is `sqlite3CheckObjectName`; this does not
establish the runtime bound implementation. Decoding must start at a known
instruction boundary, e.g. `0x2d706`, rather than a guessed mid-instruction start.
At `0x42158`, `AND R13D,1` (`4183e501`) sets flags. The LEAs at `0x4215c`
(`488d1513920d00`) and `0x42163` load the base `no such table` pointer into RDX
and `no such view` (`0x11b369`) into RAX. These LEAs preserve flags.
`CMOVNE RDX,RAX` at `0x4216a` (`480f45d0`) keeps the table component when the
masked result is zero and selects view when nonzero. The separate test/branch
at `0x4216e`/`0x42171` must not be substituted for this selection. On the
selected fallthrough path, RDX is still the message component at the call at
`0x42185` to `0x2a1e0`; RSI separately receives the format pointer `0x11b38c`
at `0x4217c`. The PLT slot `0x15a888` has symbol `sqlite3ErrorMsg`.
Runtime values, feasibility, effects and binding remain unknown.
Grade complete answers against these facts and verify cited Evidence IDs,
artifact/engine identity and selected source rows. An answer that misses interior
targets, merges the three FindTable sites, claims whole-message use from span
membership or reverses CMOVNE behavior fails. Record failures and retries rather
than selecting only successful runs. Full real-model task costs include tool
schemas, reference help, rejected calls, responses, cached/uncached input, output
and reasoning tokens, wall time, local family CPU and kernel family peak memory.
Use one frozen runtime, engine and target for traditional (the complete supported
16-tool selector), atomic Direct (22 tools) and Code Mode (4 tools), serially in
fresh isolated profiles. All have the common client JavaScript executor.
The canonical provider has exact-address xrefs, so complete spans can be
enumerated; only the atomic API exposes the new native span occurrence query.
Consequently this is a workflow/profile comparison, not a controlled test of
adapter overhead alone. Native Kuna already aggregates string-span counts and
owner functions, but that aggregation lacks individual reference endpoints and
is not exposed as an equivalent traditional MCP operation.
@@ -0,0 +1,148 @@
# Incoming reference spans and pooled strings
This experiment adds individually traceable incoming reference occurrences for
inclusive target-address spans. It does not establish whole-string use from a
reference into shared storage. No PR or integration is intended.
Before this work, the branch refreshed main to `0c7b6d834` in `c8d831936`.
The native overlay remains based on Kuna `fe01d6294eb0d1053ce343c8943646df88e143fc`.
The immutable tested executable SHA-256 is
`2e398e7229e30b6d2387a802db8a0050764119a6b457020d334855e36e69d6c5`;
the full overlay is `kuna-native-ir.patch`. Node is 24.18.0 / npm 11.16.0.
## Existing capability and missing composition
Native Kuna already aggregates xrefs and owner functions over a string's encoded
extent. Its string output does not include each reference's source/target pair.
REA's cheap inventory intentionally skips that analysis; the existing reference
operation selects exact addresses, so complete occurrence retrieval previously
required enumerating the encoded span. This is an interface/composition gap,
not evidence that Kuna had no string-span aggregation.
On real Linux SQLite, exact `no such table` occupies `0x11b376–0x11b383` and
`sqlite_schema` occupies `0x11b33f–0x11b34c`, both including NUL. Base-address
queries return one occurrence each; their full spans retain seven and four.
Nine interior occurrences target the `table` / `schema` suffixes. Calling all
seven references uses of the complete error message would be wrong. The frozen
[task oracle](string-span-oracle.md) separates occurrence completeness, symbol
membership, bytes, register passing and conditional message selection.
## Implementation and bounds
The existing named `references` operation accepts explicit `ranges`, preserving
the old exact-address and outgoing-function selectors. CLI, SDK, Direct MCP and
Code Mode use the same contract and owner. There remain 19 named methods, 22
Direct tools and four Code Mode tools. Both advertised catalogs were validated
after actual SDK conversion, including valid/invalid reference selectors.
The native BTreeMap index owns sparse inclusive range lookup, including u64 max
without end-address increment. The string aggregate also uses this owner,
removing its per-byte lookup loop and quadratic function deduplication. Legacy
and range wire rows share endpoint/function interpretation and one JSON escaping
writer. A batch builds one index, supports 16 spans and 128 selected rows per
span, and streams into an 8 MiB encoded-output budget. Selected row pointers are
bounded; serialization failure returns an error without partial JSON stdout.
These bounds cap native work/serialization and match the experimental fact page.
The TypeScript provider boundary owns exact u64 parsing, row consistency and
normalization for both formats. Range metadata binds by explicit query index,
not catalog/array order. Overlapping and duplicate caller ranges remain separate;
`source_row` indexes the retained batch's original flat xrefs array. It is not a
global occurrence ID. Malformed or unavailable data remains an error with source
Evidence where captured, never an empty observation.
Native capture cache keys cover target/engine identity, ordered spans, kinds,
offset and limit. Fields project the same retained source. One immutable parsed
range batch is retained per lease and cleared after successful close. Different
pages still rebuild a native index; this is not a persistent analysis database.
Coverage explicitly leaves discovery, indirect targets, runtime binding, memory
access overlap and whole-string use unknown/not established. Target-coordinate
membership does not expand import aliases or establish all bytes touched by an
access.
## Executed verification
- Native release tests: 25 `listing::xrefs`, two range CLI tests and 15 JSON
writer tests passed, including sparse/full-u64 selection, selector conflicts
and escaped-byte streaming bounds. Release binary rebuilt after final changes.
A real one-byte output-budget query exited with the explicit capacity error and
zero stdout bytes, confirming fail-closed serialization at the CLI boundary.
- Focused production boundary: 23 existing reference tests plus four new range
groups passed (27 total), with full runtime compilation. Focused owner graph
typecheck, changed-file lint and formatting passed. Full `check:fast` was
attempted but stopped at the 3.25 GiB threshold after 45.806 s; sampled peak
3,330.8 MiB, sampled OOM=0, final payload counters unavailable. Its processes
exited after owned-scope cleanup. This is not a passing full root typecheck.
`check:pr` and an exhaustive native corpus were not run. Experiment pushes
bypass the resource-limited pre-push gate rather than repeat it unbounded.
- All 90 experimental JavaScript tests passed. Five resource receipt/policy
tests passed, including rejecting unsafe bounds before process acquisition.
- Real SDK, Direct MCP and Code Mode range verifiers passed all eleven exact
occurrences/owners, field projection/source reuse, overlaps, repeated spans,
empty u64-max page, pagination, selected bytes/instructions, raw source hashes
and source-row traceability. Each verified cleanup.
- The public experimental CLI ran `string-span-example.txt` and returned totals
seven/four. Native string aggregate JSON remained semantically identical to
the previous engine, including counts and function lists. Real x86 SSH complete
function/prototype fidelity and AArch64 xref/return verifiers passed on the new
engine. Targets were never executed.
- `verify-string-span-machine.py` independently passed ELF loaded bytes, all
eleven selected GNU LEA targets, exported function interval membership, RIP
displacement math, mask/CMOV bytes and the two ELF PLT-slot relocations.
This is not a proof of dynamic binding or global xref completeness.
- The canonical native overlay passed forward application against a temporary
upstream index and reverse application against the owned patched worktree.
The first public SDK attempt exposed a stale registry refinement that rejected
the new selector despite the standalone contract passing. That redundant guard
was removed; the regression now checks the final registry, and the second SDK
attempt passed. Preserve the failed attempt (`range-sdk.log`) in the record.
An initial focused build crossed the default 3 GiB early stop, without OOM. A
validated optional threshold allows the build to use 3.25 GiB; its successful
focused run took 35.964 s / 35.703191 CPU s, peak 3,084.7 MiB. The hard cap
remains 4 GiB, swap zero, one CPU and 192 tasks. Analysis/model runs retain the
default 3 GiB early stop. Payload-exit counters verify cleanup and OOM=0 for all
successful bounded runs here; kernel process-family memory includes file cache,
not just RSS. Exited transient cgroup final counters are unavailable.
## Measured equivalent reference task
The exact-address baseline enumerates both 14-byte spans and retains all raw
sources. The new range query obtains the same eleven occurrences and owners
with one native batch. These are reference-phase measurements after inventory
selection, not complete model costs; cold means fresh lease/capture cache, not
cold kernel file pages. The same new engine is used in both rows.
| SDK reference workflow | Cold wall | Local family CPU | Warm wall |
| ------------------------ | --------: | ---------------: | --------: |
| 28 exact-address queries | 48.123 s | 47.791799 s | 9.899 ms |
| One two-span batch | 1.821 s | 1.806206 s | 0.984 ms |
The selected cold phase is about 26.4 times faster. This is shared native work,
not a Code Mode speedup. Old-engine exact enumeration also agreed on every fact
and took 46.806 s. The independent Direct and Code Mode batch preflights took
1.755 / 1.798 s cold and 3.066 / 9.542 ms warm. They have different transport
overheads and are single observations, not benchmark distributions.
Whole verifier resource receipts (which include additional validation queries):
| Run | Wall | Local family CPU | Kernel family peak |
| ------------------------- | -------: | ---------------: | -----------------: |
| New-engine exact baseline | 50.557 s | 50.055582 s | 475.6 MiB |
| SDK range verifier | 14.616 s | 14.279055 s | 482.7 MiB |
| Direct range verifier | 15.120 s | 14.742037 s | 312.6 MiB |
| Code Mode range verifier | 15.630 s | 15.257697 s | 331.8 MiB |
These suites have different validation work; their peak values do not establish
an equivalent-task memory reduction. Scripted checks have no model token usage.
Raw receipts/captures live in the ignored `.cache/atomic-codemode/range-*` paths.
Selected receipt SHA-256 values:
- `range-exact-after.log`: `cb1d19a4f58face2d442868add0289c3ca62f070ef14f5e4bf0cc101b3bd9ed8`
- `range-sdk-v2.log`: `f203ab548d7509b37a15c39aaf8e466e61f7591eddcb1868be97477811a698c8`
- `range-direct.log`: `c4efbcee95e087fa676b560f70bbb8f6617475be122289c3052f19af02efb2b8`
- `range-codemode.log`: `1d967347c31c99f8caf71391502a7e24ef5fcdcaaaddc5c8d1272eb5b8d7eeae`
Real-model results will be recorded separately after the frozen three-profile
trial. No token, general complex-software or adapter superiority claim follows
from these preflights.
@@ -51,6 +51,7 @@ for (const direct of [false, true]) {
);
const prefix = direct ? "facts_" : "rea.";
const ids = [
"references",
"spaces",
"registers",
"switches",
@@ -118,6 +119,30 @@ for (const direct of [false, true]) {
assert.ok(catalog.tools.some((tool) => tool.name === method.name));
}
for (const [name, good, bad] of [
[
"references",
{ addresses: ["0x1"], direction: "outgoing", scope: "function" },
{ addresses: ["0x1"], direction: "incoming", scope: "function" },
],
[
"references",
{ addresses: ["0x1"] },
{
addresses: ["0x1"],
ranges: [{ start: "0x0", end_inclusive: "0x1" }],
},
],
[
"references",
{
ranges: [{ start: "0x0", end_inclusive: "0xffffffffffffffff" }],
fields: [],
},
{
ranges: [{ start: "0x0", end_inclusive: "0x1" }],
direction: "outgoing",
},
],
["spaces", { indices: [3], fields: ["kind"] }, { indices: ["3"] }],
[
"registers",
@@ -0,0 +1,286 @@
// Real SDK/MCP range facts, source identity, paging and bounded native work.
import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { writeFile } from "node:fs/promises";
import { resolve } from "node:path";
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
import { AtomicSession } from "./session.mjs";
import { familyCounters } from "./family-counters.mjs";
import {
createVerifierRun,
completeVerifierRun,
assertVerifierCleanupComplete,
} from "../../scripts/lib/verifier-run.mjs";
const [binary, output, adapter = "sdk"] = process.argv.slice(2);
assert(binary && output && ["sdk", "direct", "codemode"].includes(adapter));
const verifier = createVerifierRun(),
session = adapter === "sdk" ? new AtomicSession() : null;
const client = session
? null
: new Client({ name: "rea-range-verifier", version: "0.1.0" });
const transport = session
? null
: new StdioClientTransport({
command: process.execPath,
args: [resolve("experiments/atomic-codemode/server.mjs")],
env: { ...process.env, REA_ATOMIC_ADAPTER: adapter },
stderr: "pipe",
});
const observations = [],
sources = new Map(),
phases = [],
failures = [];
const invoke = async (name, input) => {
const reply = await client.callTool(
{ name, arguments: input },
{ timeout: 180000 },
);
return JSON.parse(reply.content[0].text);
};
const read = async (method, input) => {
const reply = session
? await session.call(method, input)
: adapter === "direct"
? await invoke(`facts_${method}`, input)
: (
await invoke("execute_javascript", {
code: `return await rea.${method}(${JSON.stringify(input)});`,
})
).value;
assert.equal(reply.ok, true, JSON.stringify(reply));
assert.equal(
reply.context.artifact_sha256,
"2e6eef9a727f081f0d453b4e5e6cbd8b9ef8b6f86cbf7681cbad444d3b0b55c8",
);
for (const value of reply.data.results ?? [reply.data]) {
if (Object.hasOwn(value, "ok"))
assert.equal(value.ok, true, JSON.stringify(value));
if (value.source) sources.set(value.source.evidence_id, value.source);
}
observations.push({ method, input, data: reply.data });
return reply.data;
};
const measure = async (phase, work) => {
const a = await familyCounters(),
start = performance.now(),
value = await work(),
b = await familyCounters();
phases.push({
phase,
elapsed_ms: performance.now() - start,
family_cpu_seconds: (b.cpu - a.cpu) / 1e6,
cumulative_family_memory_peak_bytes: b.peak,
});
return value;
};
const key = (row) => [
row.from,
row.to,
row.kind,
row.fromFunction?.address ?? null,
row.fromFunction?.name ?? null,
];
const expected = [
["0x4215c", "0x11b376", "data", "0x420d0", "sqlite3LocateTable"],
["0x2d709", "0x11b37e", "data", "0x2d600", "sqlite3AlterRenameTable"],
["0x4565e", "0x11b37e", "data", "0x45590", "sqlite3StartTable"],
["0x4573d", "0x11b37e", "data", "0x45590", "sqlite3StartTable"],
["0x48b2e", "0x11b37e", "data", "0x47ff0", "sqlite3EndTable"],
["0xbad38", "0x11b37e", "data", "0xb90e0", "sqlite3Pragma"],
["0xbd1f0", "0x11b37e", "data", "0xbd1b0", "sqlite3InitOne"],
];
const schemaExpected = [
["0x422c5", "0x11b33f", "data", "0x42280", "sqlite3PreferredTableName"],
...["0x41f0b", "0x41f65", "0x41fb2"].map((from) => [
from,
"0x11b346",
"data",
"0x41db0",
"sqlite3FindTable",
]),
];
let context;
try {
if (session) {
const opened = await session.open(binary);
context = opened.context;
} else {
await client.connect(transport);
const opened = await invoke("open_binary", { path: binary });
assert.equal(opened.ok, true);
context = opened.context;
}
const ranges = [];
for (const value of ["no such table", "sqlite_schema"]) {
const strings = await read("strings", { query: value, limit: 128 });
const matches = strings.items.filter((s) => s.value === value);
assert.equal(matches.length, 1);
const string = matches[0];
assert.equal(string.string.encoding, "ascii");
assert.equal(string.string.byte_length, 14);
ranges.push({
start: string.address,
end_inclusive: `0x${(BigInt(string.address) + BigInt(string.string.byte_length) - 1n).toString(16)}`,
});
}
const input = {
ranges,
kinds: ["data"],
fields: ["fromFunction", "toFunction", "instruction"],
limit: 128,
};
const cold = await measure("cold-two-span-batch", () =>
read("references", input),
);
assert.deepEqual(cold.results[0].items.map(key), expected);
assert.deepEqual(cold.results[1].items.map(key), schemaExpected);
assert.equal(
new Set(cold.results.map((r) => r.source.evidence_id)).size,
1,
"one source covers both ranges",
);
const warm = await measure("warm-same-two-span-batch", () =>
read("references", input),
);
assert.deepEqual(warm, cold);
const narrow = await read("references", { ...input, fields: [] });
assert.deepEqual(narrow.results[0].source, cold.results[0].source);
assert.deepEqual(Object.keys(narrow.results[0].items[0]), [
"source_row",
"from",
"to",
"kind",
]);
for (const page of cold.results) {
assert.equal(page.coverage.discovery, "unknown");
assert.equal(page.coverage.whole_string_use, "not-established");
assert.equal(page.next_offset, null);
}
const overlap = await read("references", {
ranges: [
ranges[0],
{ start: "0x11b37e", end_inclusive: ranges[0].end_inclusive },
ranges[0],
{ start: "0xffffffffffffffff", end_inclusive: "0xffffffffffffffff" },
],
kinds: ["data"],
limit: 128,
});
assert.deepEqual(
overlap.results.map((r) => r.total),
[7, 6, 7, 0],
);
assert.deepEqual(
overlap.results[0].items.map(key),
overlap.results[2].items.map(key),
);
const recovered = [];
for (let offset = 0; offset !== null;) {
const reply = await read("references", {
ranges: [ranges[0]],
kinds: ["data"],
offset,
limit: 2,
});
assert.equal(reply.results[0].total, 7);
recovered.push(...reply.results[0].items.map(key));
offset = reply.results[0].next_offset;
}
assert.deepEqual(recovered, expected);
const bytes = await read("bytes", {
windows: ranges.map((r) => ({ address: r.start, length: 14 })),
});
assert.deepEqual(
bytes.results.map((r) => Buffer.from(r.hex, "hex").toString("ascii")),
["no such table\0", "sqlite_schema\0"],
);
const machine = await read("instructions", {
windows: [
{ address: "0x2d706", count: 6 },
{ address: "0x42158", count: 12 },
],
fields: ["bytes", "text"],
});
for (const [at, bytes] of [
["0x2d709", "488d156edc0e00"],
["0x4215c", "488d1513920d00"],
["0x4216a", "480f45d0"],
])
assert(
machine.results.some((r) =>
r.items.some((i) => i.address === at && i.bytes === bytes),
),
at,
);
// Check each source row against its actual native batch position and page.
for (const source of sources.values()) {
let text = "",
offset = 0;
do {
const page = await read("evidence", {
evidence_id: source.evidence_id,
offset,
limit: 16384,
});
text += page.text;
offset = page.next_offset;
} while (offset !== null);
assert.equal(Buffer.byteLength(text), source.bytes);
assert.equal(
createHash("sha256").update(text).digest("hex"),
source.sha256,
);
const raw = JSON.parse(text);
const pages = observations
.filter((o) => o.method === "references")
.flatMap((o) => o.data.results)
.filter((p) => p.source.evidence_id === source.evidence_id);
for (const page of pages)
for (const fact of page.items) {
const row = raw.xrefs[fact.source_row];
assert.equal(row.range_index, page.range_index);
assert.equal(row.from_address_hex, fact.from);
assert.equal(row.to_address_hex, fact.to);
}
}
} catch (error) {
failures.push(error.stack ?? String(error));
} finally {
if (session) await session.close();
else {
try {
await invoke("close_binary", {});
} finally {
await client.close();
}
}
}
const lifecycle = await completeVerifierRun(verifier);
assertVerifierCleanupComplete(lifecycle.process_lineage);
await writeFile(
output,
JSON.stringify({
adapter,
context,
observations,
phases,
failures,
lifecycle,
source_count: sources.size,
scope:
"Selected static SDK/MCP range facts and original-source fidelity. No target execution, complete discovery or whole-string-use proof.",
}),
{ flag: "wx" },
);
console.log(
JSON.stringify({
output,
adapter,
phases,
failures,
source_count: sources.size,
}),
);
if (failures.length) process.exitCode = 1;
@@ -0,0 +1,125 @@
"""Independent ELF/GNU oracle for the pinned SQLite pooled-string task."""
import hashlib
import json
from pathlib import Path
import re
import struct
import subprocess
import sys
if sys.flags.optimize:
raise RuntimeError('Run the oracle without Python optimization')
binary, output = map(Path, sys.argv[1:])
raw = binary.read_bytes()
digest = hashlib.sha256(raw).hexdigest()
assert digest == '2e6eef9a727f081f0d453b4e5e6cbd8b9ef8b6f86cbf7681cbad444d3b0b55c8'
assert raw[:6] == b'\x7fELF\x02\x01' and struct.unpack_from('<H', raw, 18)[0] == 62
phoff = struct.unpack_from('<Q', raw, 32)[0]
phsize, phcount = struct.unpack_from('<HH', raw, 54)
assert phsize >= 56 and phoff + phsize * phcount <= len(raw)
segments = [struct.unpack_from('<IIQQQQQQ', raw, phoff + i * phsize) for i in range(phcount)]
def loaded(address, length):
matches = [p for p in segments if p[0] == 1 and p[3] <= address
and address + length <= p[3] + p[5]]
assert len(matches) == 1
segment = matches[0]
start = segment[2] + address - segment[3]
assert start + length <= len(raw)
return raw[start:start + length]
spans = [(0x11b376, 0x11b383, b'no such table\0'),
(0x11b33f, 0x11b34c, b'sqlite_schema\0')]
for start, end, text in spans:
assert loaded(start, end - start + 1) == text
expected = {(0x4215c, 0x11b376), (0x2d709, 0x11b37e),
(0x4565e, 0x11b37e), (0x4573d, 0x11b37e),
(0x48b2e, 0x11b37e), (0xbad38, 0x11b37e),
(0xbd1f0, 0x11b37e), (0x422c5, 0x11b33f),
(0x41f0b, 0x11b346), (0x41f65, 0x11b346), (0x41fb2, 0x11b346)}
observed = set()
# Decode from the ELF's normal instruction sections, not arbitrary mid-instruction
# window starts. Nearest/synthetic symbol labels do not establish target identity.
with subprocess.Popen(['objdump', '-d', '-w', '--no-show-raw-insn', str(binary)],
stdout=subprocess.PIPE, text=True) as child:
for line in child.stdout:
match = re.match(r'\s*([0-9a-f]+):\s+lea\w*\s+.*#\s*([0-9a-f]+)\b', line)
if match:
source, target = (int(value, 16) for value in match.groups())
if any(start <= target <= end for start, end, _ in spans):
observed.add((source, target))
assert child.wait() == 0
assert observed == expected
owners = {
0x4215c: (0x420d0, 'sqlite3LocateTable'),
0x2d709: (0x2d600, 'sqlite3AlterRenameTable'),
0x4565e: (0x45590, 'sqlite3StartTable'),
0x4573d: (0x45590, 'sqlite3StartTable'),
0x48b2e: (0x47ff0, 'sqlite3EndTable'),
0xbad38: (0xb90e0, 'sqlite3Pragma'),
0xbd1f0: (0xbd1b0, 'sqlite3InitOne'),
0x422c5: (0x42280, 'sqlite3PreferredTableName'),
0x41f0b: (0x41db0, 'sqlite3FindTable'),
0x41f65: (0x41db0, 'sqlite3FindTable'),
0x41fb2: (0x41db0, 'sqlite3FindTable'),
}
symbols = set()
for line in subprocess.check_output(['readelf', '-Ws', str(binary)], text=True).splitlines():
fields = line.split()
if len(fields) == 8 and fields[3] == 'FUNC' and fields[6] != 'UND':
symbols.add((int(fields[1], 16), int(fields[2]), fields[7]))
for at, (entry, name) in owners.items():
assert any(start == entry and symbol == name and start <= at < start + size
for start, size, symbol in symbols)
def lea(at):
data = loaded(at, 7)
assert data[0] & 0xf8 == 0x48 and data[1] == 0x8d and data[2] & 0xc7 == 0x05
register = ((data[2] >> 3) & 7) | ((data[0] & 4) << 1)
names = ['rax', 'rcx', 'rdx', 'rbx', 'rsp', 'rbp', 'rsi', 'rdi',
'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15']
return at + 7 + struct.unpack_from('<i', data, 3)[0], names[register]
for source, target in expected:
assert lea(source)[0] == target
assert lea(0x2d709) == (0x11b37e, 'rdx')
assert lea(0x4215c) == (0x11b376, 'rdx')
assert lea(0x42163) == (0x11b369, 'rax')
assert lea(0x4217c) == (0x11b38c, 'rsi')
assert loaded(0x11b369, 13) == b'no such view\0'
assert loaded(0x42158, 4).hex() == '4183e501' # AND R13D,1: sets flags
assert loaded(0x4216a, 4).hex() == '480f45d0' # CMOVNE RDX,RAX
relocations = subprocess.check_output(['readelf', '-Wr', str(binary)], text=True)
calls = []
for at, target, name in [(0x2d716, 0x29060, 'sqlite3CheckObjectName'),
(0x42185, 0x2a1e0, 'sqlite3ErrorMsg')]:
call = loaded(at, 5)
assert call[0] == 0xe8 and at + 5 + struct.unpack_from('<i', call, 1)[0] == target
stub = target
if loaded(stub, 4) == b'\xf3\x0f\x1e\xfa':
stub += 4
if loaded(stub, 1) == b'\xf2':
stub += 1
jump = loaded(stub, 6)
assert jump[:2] == b'\xff\x25'
slot = stub + 6 + struct.unpack_from('<i', jump, 2)[0]
assert re.search(rf'^0*{slot:x}\s+[0-9a-f]+\s+R_X86_64_JUMP_SLOT\s+[0-9a-f]+\s+{name}\s+\+\s+0$',
relocations, re.MULTILINE)
calls.append({'origin': hex(at), 'plt_entry': hex(target), 'slot': hex(slot), 'relocation_symbol': name})
report = {'binary_sha256': digest, 'elf_machine': 62,
'spans': [{'start': hex(s), 'end_inclusive': hex(e), 'bytes_with_nul': e - s + 1} for s, e, _ in spans],
'gnu_lea_and_file_target_pairs': [[hex(a), hex(b)] for a, b in sorted(expected)],
'elf_function_symbol_membership': [
{'from': hex(at), 'entry': hex(entry), 'name': name}
for at, (entry, name) in sorted(owners.items())],
'selected_passing_register': 'rdx', 'selected_plt_calls': calls,
'conditional_message_selection': {'mask_at': '0x42158', 'mask': 1, 'cmovne_at': '0x4216a',
'zero_keeps': '0x11b376', 'nonzero_selects': '0x11b369'},
'scope': 'Independent fixed-fixture file/GNU checks; not Kuna output, global reference completeness, target execution or live PLT binding.'}
with output.open('x') as stream:
json.dump(report, stream, indent=2)
print(json.dumps(report))
+3
View File
@@ -5,3 +5,6 @@ export const KUNA_FUNCTION_TEXT_BYTES = 16 * 1024 * 1024;
export const KUNA_DIAGNOSTIC_BYTES = 8 * 1024 * 1024;
export const KUNA_STRING_MIN_LENGTH = 5;
/** Buffered xref source bytes also bound the materialized native rows. */
export const KUNA_XREF_OUTPUT_BYTES = 16 * 1024 * 1024;
+14 -79
View File
@@ -7,14 +7,20 @@ import { err, ok, type Result } from "../domain/result.js";
import { compareKunaAddresses } from "./KunaAddress.js";
import { parseKunaJson } from "./KunaJson.js";
import { KunaJsonDocumentReader, parseKunaRow } from "./KunaJsonStream.js";
import { KUNA_XREF_OUTPUT_BYTES } from "./KunaLimits.js";
/** The raw xref budget also bounds its materialized rows. */
export const KUNA_XREF_OUTPUT_BYTES = 16 * 1024 * 1024;
const addressKeys = new Set(["address", "from_address", "to_address"]);
const address = z.string().regex(/^0x(?:0|[1-9a-f][0-9a-f]{0,15})$/u);
const count = z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
const kind = z.enum(["call", "jump", "data", "read", "write"]);
import {
kunaReferenceAddressKeys as addressKeys,
kunaReferenceAddressSchema as address,
kunaReferenceCountSchema as count,
kunaReferenceKindSchema as kind,
kunaReferenceFunctionSchema as xrefFunction,
kunaReferenceRowSchema as xrefRow,
validateKunaReferenceRow,
kunaReferenceFact as referenceFact,
type KunaReferenceFact,
} from "./KunaReferenceRows.js";
export type { KunaReferenceFact } from "./KunaReferenceRows.js";
const graphHeader = z.object({
schemaVersion: z.literal(4),
@@ -206,23 +212,6 @@ export class KunaCallGraphReader extends KunaJsonDocumentReader<KunaCallGraph> {
}
}
const xrefFunction = z.object({
name: z.string().min(1),
address,
address_hex: address,
});
const xrefRow = z.object({
address,
address_hex: address,
kind,
from_address: address,
from_address_hex: address,
to_address: address,
to_address_hex: address,
from_function: xrefFunction.nullable(),
to_function: xrefFunction.nullable(),
instruction: z.string(),
});
const xrefsDocument = z.object({
binary: z.string(),
direction: z.enum(["to", "from"]),
@@ -242,20 +231,7 @@ const parseReferenceRow = (
aliases: ReadonlySet<string>,
query: KunaReferenceQuery,
) => {
const row = xrefRow.parse(raw);
if (
row.address !== row.address_hex ||
row.address !==
(query.direction === "to" ? row.from_address : row.to_address) ||
row.from_address !== row.from_address_hex ||
row.to_address !== row.to_address_hex
)
throw new Error(
"xref endpoints disagree with numeric or directional fields",
);
for (const fn of [row.from_function, row.to_function])
if (fn !== null && fn.address !== fn.address_hex)
throw new Error("xref function address disagrees with its hex field");
const row = validateKunaReferenceRow(xrefRow.parse(raw), query.direction);
if (query.direction === "to" && !aliases.has(row.to_address))
throw new Error(
"xref row targets neither the requested address nor an advertised alias",
@@ -280,22 +256,6 @@ export interface KunaReferenceAddresses {
}
/** Experimental fact projection, owned by the native protocol parser. */
export type KunaReferenceFact = {
readonly source_row: number;
readonly from: string;
readonly to: string;
readonly kind: z.infer<typeof kind>;
readonly fromFunction: {
readonly address: string;
readonly name: string;
} | null;
readonly toFunction: {
readonly address: string;
readonly name: string;
} | null;
readonly instruction: string;
};
export type KunaReferenceQuery = (
| {
readonly direction: "to";
@@ -328,31 +288,6 @@ const referenceSelection = (
return row.from_function.address === query.address ? "selected" : "scope";
};
const referenceFact = (
row: z.infer<typeof xrefRow>,
source_row: number,
): KunaReferenceFact => ({
source_row,
from: row.from_address,
to: row.to_address,
kind: row.kind,
fromFunction:
row.from_function === null
? null
: {
address: row.from_function.address,
name: row.from_function.name,
},
toFunction:
row.to_function === null
? null
: {
address: row.to_function.address,
name: row.to_function.name,
},
instruction: row.instruction,
});
/** One native-format boundary, with caller-selected endpoint/function scope. */
const parseReferenceDocument = (
text: string,
+1 -1
View File
@@ -10,13 +10,13 @@ import { ProviderAdapterError } from "../domain/providerAdapterError.js";
import { err, ok, type Result } from "../domain/result.js";
import type { KunaInstallation } from "./KunaInstallation.js";
import {
KUNA_XREF_OUTPUT_BYTES,
KunaCallGraphReader,
parseKunaIncomingReferences,
type KunaCallGraph,
type KunaGraphNode,
type KunaReferenceAddresses,
} from "./KunaReferenceFiles.js";
import { KUNA_XREF_OUTPUT_BYTES } from "./KunaLimits.js";
import { KUNA_PROVIDER_ID } from "./KunaRelease.js";
import type { KunaPendingQuery, KunaQueryWork } from "./KunaQueryWork.js";
import { kunaUnavailable } from "./KunaUnavailable.js";
+150
View File
@@ -0,0 +1,150 @@
// Paged native range batches: query identity and coverage stay with their owner.
import { createHash } from "node:crypto";
import { z } from "zod";
import { err, ok } from "../domain/result.js";
import { parseKunaJson } from "./KunaJson.js";
import { KUNA_XREF_OUTPUT_BYTES } from "./KunaLimits.js";
import {
kunaReferenceAddressKeys,
kunaReferenceAddressSchema as address,
kunaReferenceCountSchema as count,
kunaReferenceKindSchema,
kunaReferenceRowSchema,
validateKunaReferenceRow,
kunaReferenceFact,
type KunaReferenceFact,
} from "./KunaReferenceRows.js";
const span = z.strictObject({ start: address, end_inclusive: address });
const metadata = span.extend({
index: count,
offset: count,
limit: count.min(1).max(128),
total: count,
count,
next_offset: count.nullable(),
});
const wire = z.object({
schema_version: z.literal(1),
binary: z.string(),
direction: z.literal("to"),
ranges: z.array(metadata).min(1).max(16),
count,
xrefs: z.array(kunaReferenceRowSchema.extend({ range_index: count })),
});
export interface KunaReferenceRangeQuery {
readonly ranges: readonly z.infer<typeof span>[];
readonly offset: number;
readonly limit: number;
readonly kinds?: readonly z.infer<typeof kunaReferenceKindSchema>[];
}
export interface KunaReferenceRangePage {
readonly range: z.infer<typeof span>;
readonly range_index: number;
readonly total: number;
readonly next_offset: number | null;
readonly facts: readonly KunaReferenceFact[];
}
type NativeRangeDocument = z.infer<typeof wire>;
type ParsedPage = {
metadata: z.infer<typeof metadata>;
facts: KunaReferenceFact[];
keys: Set<string>;
};
const readPages = (
entries: NativeRangeDocument["ranges"],
query: KunaReferenceRangeQuery,
) => {
const pages = new Map<number, ParsedPage>();
for (const meta of entries) {
const expected = query.ranges[meta.index];
if (
pages.has(meta.index) ||
expected === undefined ||
meta.start !== expected.start ||
meta.end_inclusive !== expected.end_inclusive ||
BigInt(meta.start) > BigInt(meta.end_inclusive) ||
meta.offset !== query.offset ||
meta.limit !== query.limit
)
throw new Error("xref range metadata is not bound to the selected query");
const selected = Math.min(
meta.limit,
Math.max(0, meta.total - meta.offset),
);
if (
meta.count !== selected ||
meta.next_offset !==
(meta.offset + selected < meta.total ? meta.offset + selected : null)
)
throw new Error("xref range pagination contradicts examined coverage");
pages.set(meta.index, { metadata: meta, facts: [], keys: new Set() });
}
return pages;
};
const readRows = (
rows: NativeRangeDocument["xrefs"],
pages: Map<number, ParsedPage>,
kinds: KunaReferenceRangeQuery["kinds"],
) => {
for (const [source_row, raw] of rows.entries()) {
const row = validateKunaReferenceRow(raw, "to"),
page = pages.get(row.range_index);
if (
page === undefined ||
BigInt(row.to_address) < BigInt(page.metadata.start) ||
BigInt(row.to_address) > BigInt(page.metadata.end_inclusive) ||
(kinds !== undefined && !kinds.includes(row.kind))
)
throw new Error("xref row violates selected range or kind scope");
const key = JSON.stringify([row.from_address, row.to_address, row.kind]);
if (page.keys.has(key))
throw new Error("xref range page repeats an occurrence");
page.keys.add(key);
page.facts.push(kunaReferenceFact(row, source_row));
}
};
export const parseKunaReferenceRanges = (
text: string,
input: string,
query: KunaReferenceRangeQuery,
) => {
try {
const document = wire.parse(
parseKunaJson(text, KUNA_XREF_OUTPUT_BYTES, kunaReferenceAddressKeys),
);
if (
document.binary !== input ||
document.count !== document.xrefs.length ||
document.ranges.length !== query.ranges.length
)
throw new Error(
"xref range document has foreign input or inconsistent counts",
);
const pages = readPages(document.ranges, query);
readRows(document.xrefs, pages, query.kinds);
const results: KunaReferenceRangePage[] = query.ranges.map(
(range, index) => {
const page = pages.get(index);
if (page === undefined || page.facts.length !== page.metadata.count)
throw new Error("xref range page is missing declared observations");
return {
range: { ...range },
range_index: index,
total: page.metadata.total,
next_offset: page.metadata.next_offset,
facts: page.facts,
};
},
);
return ok({
results,
bytes: Buffer.byteLength(text),
sha256: createHash("sha256").update(text).digest("hex"),
});
} catch (cause: unknown) {
return err(cause instanceof Error ? cause.message : String(cause));
}
};
+102
View File
@@ -0,0 +1,102 @@
// Provider wire endpoints and normalized facts have one interpretation.
import { z } from "zod";
export const kunaReferenceAddressKeys = new Set([
"address",
"from_address",
"to_address",
]);
export const kunaReferenceAddressSchema = z
.string()
.regex(/^0x(?:0|[1-9a-f][0-9a-f]{0,15})$/u);
export const kunaReferenceCountSchema = z
.number()
.int()
.min(0)
.max(Number.MAX_SAFE_INTEGER);
export const kunaReferenceKindSchema = z.enum([
"call",
"jump",
"data",
"read",
"write",
]);
const address = kunaReferenceAddressSchema,
kind = kunaReferenceKindSchema;
export const kunaReferenceFunctionSchema = z.object({
name: z.string().min(1),
address,
address_hex: address,
});
export const kunaReferenceRowSchema = z.object({
address,
address_hex: address,
kind,
from_address: address,
from_address_hex: address,
to_address: address,
to_address_hex: address,
from_function: kunaReferenceFunctionSchema.nullable(),
to_function: kunaReferenceFunctionSchema.nullable(),
instruction: z.string(),
});
export const validateKunaReferenceRow = <
T extends z.infer<typeof kunaReferenceRowSchema>,
>(
row: T,
direction: "to" | "from",
): T => {
if (
row.address !== row.address_hex ||
row.address !== (direction === "to" ? row.from_address : row.to_address) ||
row.from_address !== row.from_address_hex ||
row.to_address !== row.to_address_hex
)
throw new Error(
"xref endpoints disagree with numeric or directional fields",
);
for (const fn of [row.from_function, row.to_function])
if (fn !== null && fn.address !== fn.address_hex)
throw new Error("xref function address disagrees with its hex field");
return row;
};
export type KunaReferenceFact = {
readonly source_row: number;
readonly from: string;
readonly to: string;
readonly kind: z.infer<typeof kind>;
readonly fromFunction: {
readonly address: string;
readonly name: string;
} | null;
readonly toFunction: {
readonly address: string;
readonly name: string;
} | null;
readonly instruction: string;
};
export const kunaReferenceFact = (
row: z.infer<typeof kunaReferenceRowSchema>,
source_row: number,
): KunaReferenceFact => ({
source_row,
from: row.from_address,
to: row.to_address,
kind: row.kind,
fromFunction:
row.from_function === null
? null
: {
address: row.from_function.address,
name: row.from_function.name,
},
toFunction:
row.to_function === null
? null
: {
address: row.to_function.address,
name: row.to_function.name,
},
instruction: row.instruction,
});
@@ -0,0 +1,181 @@
import { expect, it } from "vitest";
import { parseKunaReferenceRanges } from "../../../../src/kuna/KunaReferenceRanges.js";
const input = "/snapshot/program";
const maximum = "0xffffffffffffffff";
const query = {
ranges: [
{ start: "0x20000000000001", end_inclusive: maximum },
{ start: maximum, end_inclusive: maximum },
],
offset: 0,
limit: 2,
kinds: ["data"] as const,
};
const encoded = (value: unknown) =>
JSON.stringify(value).replace(/"@(\d+)"/gu, "$1");
const row = (range_index: number) => ({
range_index,
address: "@9007199254740995",
address_hex: "0x20000000000003",
kind: "data",
from_address: "@9007199254740995",
from_address_hex: "0x20000000000003",
to_address: "@18446744073709551615",
to_address_hex: maximum,
from_function: {
name: "caller 中文",
address: "@9007199254740992",
address_hex: "0x20000000000000",
},
to_function: null,
instruction: "LEA RDX,[target]",
});
const document = () => ({
schema_version: 1,
binary: input,
direction: "to",
count: 2,
ranges: query.ranges
.map((range, index) => ({
...range,
index,
offset: 0,
limit: 2,
total: 1,
count: 1,
next_offset: null as number | null,
}))
.reverse(),
xrefs: [row(1), row(0)],
});
it("binds reordered metadata by named range index, preserves u64 and original source rows", () => {
const result = parseKunaReferenceRanges(encoded(document()), input, query);
expect(result.ok).toBe(true);
if (!result.ok) return;
expect(
result.value.results.map((p) => [
p.range_index,
p.range,
p.facts[0]?.source_row,
p.total,
]),
).toEqual([
[0, query.ranges[0], 1, 1],
[1, query.ranges[1], 0, 1],
]);
expect(result.value.results[0]?.facts[0]).toMatchObject({
from: "0x20000000000003",
to: maximum,
kind: "data",
fromFunction: { name: "caller 中文" },
toFunction: null,
});
expect(result.value.results[0]?.range).not.toBe(query.ranges[0]);
});
it("rejects foreign scope, dangling or repeated queries, malformed endpoints and inconsistent paging", () => {
for (const mutate of [
(v: ReturnType<typeof document>) => {
v.binary = "/other";
},
(v: ReturnType<typeof document>) => {
v.count = 3;
},
(v: ReturnType<typeof document>) => {
v.ranges[0]!.index = 0;
},
(v: ReturnType<typeof document>) => {
v.ranges[0]!.end_inclusive = "0x1";
},
(v: ReturnType<typeof document>) => {
v.ranges[0]!.offset = 1;
},
(v: ReturnType<typeof document>) => {
v.ranges[0]!.next_offset = 1;
},
(v: ReturnType<typeof document>) => {
v.ranges[0]!.total = 2;
},
(v: ReturnType<typeof document>) => {
v.xrefs[0]!.range_index = 7;
},
(v: ReturnType<typeof document>) => {
v.xrefs[0]!.kind = "call";
},
(v: ReturnType<typeof document>) => {
v.xrefs[0]!.to_address = "@1";
v.xrefs[0]!.to_address_hex = "0x1";
},
(v: ReturnType<typeof document>) => {
v.xrefs[0]!.address = "@1";
},
(v: ReturnType<typeof document>) => {
v.xrefs[0]!.from_function.address = "@1";
},
]) {
const value = document();
mutate(value);
expect(parseKunaReferenceRanges(encoded(value), input, query).ok).toBe(
false,
);
}
});
it("preserves overlap between queries but rejects a duplicated occurrence within one page", () => {
const value = document();
value.count = 3;
value.xrefs.push(row(0));
const first = value.ranges.find((r) => r.index === 0)!;
first.total = 2;
first.count = 2;
const result = parseKunaReferenceRanges(encoded(value), input, query);
expect(result).toMatchObject({
ok: false,
error: expect.stringContaining("repeats an occurrence"),
});
});
it("distinguishes a complete page from an empty out-of-range page with observed matches", () => {
const one = {
ranges: [query.ranges[1]!],
offset: 1,
limit: 1,
kinds: query.kinds,
};
const value = {
schema_version: 1,
binary: input,
direction: "to",
count: 1,
ranges: [
{
...one.ranges[0],
index: 0,
offset: 1,
limit: 1,
total: 3,
count: 1,
next_offset: 2,
},
],
xrefs: [row(0)],
};
expect(parseKunaReferenceRanges(encoded(value), input, one)).toMatchObject({
ok: true,
value: { results: [{ total: 3, next_offset: 2 }] },
});
const empty = {
...value,
count: 0,
xrefs: [],
ranges: [{ ...value.ranges[0], offset: 4, count: 0, next_offset: null }],
};
expect(
parseKunaReferenceRanges(encoded(empty), input, { ...one, offset: 4 }),
).toMatchObject({
ok: true,
value: { results: [{ total: 3, next_offset: null, facts: [] }] },
});
});