fix(native): preserve function byte source qualifications (#8606)

* fix(native): preserve function byte source qualifications

* fix(native): recover oversized inline matching sources

* test(native): verify matching byte source recovery

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
morlutoandCursor Agent authored and GitHub committed 2026-11-05 04:01:16 +08:00
1 parent 4ec2726b1b
commit 2b740cab36
7 files changed
+524 -3

No files matched your search

+12
View File
@@ -46,6 +46,18 @@ fingerprint and the same known architecture. Extents are never guessed from the
next entry, and relocations are not normalized. A larger mapped read can serve
several observed bodies; only needed ranges need to be captured.
For a matched function, its `evidence_links` include the selected byte reads
that covered its body. Request the `function-matches` view with
`collection: "byte-sources"` to page the selected `read_bytes` source IDs,
sides and limitations; intersect those IDs with the function's links. This
distinguishes, for example, Ghidra initialized-memory bytes from file bytes.
Identical overlapping reads retain the selected covering source, not every
corroborating read. Pages preserve the original source limitations and may end
early when the response budget is reached. If one source is too large for a
page, the error identifies its Evidence and the next offset; inspect the
original matching Evidence or export it if retained, then resume at that
offset. Older matching Evidence may not record this source selection.
This first slice reuses existing range observations. Stripped builds can require
many lightweight range queries when those facts are not retained yet. Matching
does not hide that acquisition cost or silently start those queries. Full
@@ -12,6 +12,7 @@ import { createEvidence, type Evidence } from "../../domain/evidence.js";
import { readFunctionInventory } from "../../domain/native/functionInventory.js";
import {
nativeFunctionMatchingSchema,
nativeFunctionByteSourceGuidance,
NATIVE_FUNCTION_MATCHING_PREDICATE,
} from "../../domain/native/functionMatching.js";
import { AnalysisError } from "../../domain/analysisErrorBase.js";
@@ -94,6 +95,38 @@ const matchWithAdmission = async (
rightFunctions,
{ identicalBytesComparable: compatible, checkpoint },
);
const byteSources: {
side: "left" | "right";
evidence_id: string;
limitations: string[];
}[] = [];
for (const [side, functions, observations] of [
["left", leftFunctions, leftObservations],
["right", rightFunctions, rightObservations],
] as const) {
const used = new Set<string>();
for (const item of functions)
for (const id of item.member.evidence_links) {
if (!used.has(id)) await checkpoint(128 + id.length * 4);
used.add(id);
}
for (const observation of observations) {
if (
observation.operation !== "read_bytes" ||
!used.has(observation.evidence_id)
)
continue;
used.delete(observation.evidence_id);
await checkpoint(512 + observation.evidence_id.length * 8);
for (const limitation of observation.limitations)
await checkpoint(128 + limitation.length * 8);
byteSources.push({
side,
evidence_id: observation.evidence_id,
limitations: [...observation.limitations],
});
}
}
const limitations = [
...new Set([
...left.limitations.map((x) => `Left: ${x}`),
@@ -101,6 +134,7 @@ const matchWithAdmission = async (
"Coverage is restricted to the supplied provider-observed inventories; missing/truncated inventory facts never prove absence from either binary.",
"Only unique exact symbols and bytes are paired. Compatible observed CFG/call/string fingerprints propose unresolved candidates, never identity or equivalence. Missing structural coverage stays unknown.",
"Name or byte correspondence is not behavioral equivalence; use analyze_function for selected pairs, then compare_functions. Existing dossier pairs include directly usable retained-reference inputs.",
...(byteSources.length === 0 ? [] : [nativeFunctionByteSourceGuidance]),
...(!compatible
? [
"Identical-byte matching unavailable: input architectures are missing or differ.",
@@ -141,6 +175,8 @@ const matchWithAdmission = async (
).length,
},
summary,
byte_sources_count: byteSources.length,
byte_sources: byteSources,
matches,
limitations,
});
+1 -1
View File
@@ -118,7 +118,7 @@ export const SESSION_TOOL_CONTRACTS = [
),
session(
"match_native_functions",
"Match two retained list_procedures inventories by unique exact reported symbols, then unique identical observed function bytes. Optional same-context list_names/procedure_info/read_bytes/analyze_function Evidence supplies symbol origin, exact bodies, bytes and dossier links as supplied static facts. Optional compatible CFG/call/string fingerprints from supplied dossiers propose unresolved groups only. Duplicate candidates remain unresolved groups; only_left/right mean unpaired within supplied observations, never proof of addition/removal. Default summary retains complete Evidence for filtered, selected-column, paged function-matches views. Complete detail returns every group. Existing dossier pairs provide direct retained-reference compare_functions inputs.",
"Match two retained list_procedures inventories by unique exact reported symbols, then unique identical observed function bytes. Optional same-context list_names/procedure_info/read_bytes/analyze_function Evidence supplies symbol origin, exact bodies, bytes and dossier links as supplied static facts. Optional compatible CFG/call/string fingerprints from supplied dossiers propose unresolved groups only. Duplicate candidates remain unresolved groups; only_left/right mean unpaired within supplied observations, never proof of addition/removal. Default summary retains complete Evidence for filtered, selected-column, paged function-matches views. The byte-sources collection identifies selected read_bytes Evidence and its limitations; intersect its IDs with each function's evidence_links to identify its sources. Complete detail returns every group. Existing dossier pairs provide direct retained-reference compare_functions inputs.",
matchNativeFunctionsInputSchema,
),
session(
@@ -1129,6 +1129,7 @@ export const analysisViewResultSchema = z.discriminatedUnion("kind", [
artifact: z.null(),
view: nativeFunctionMatchingViewRequestSchema,
items: nativeFunctionMatchingViewItemsSchema,
byte_limited: z.boolean().optional(),
parent_operation: z.literal("match_native_functions"),
}),
z.strictObject({
@@ -3,6 +3,8 @@ import {
nativeFunctionMatchingSchema,
nativeFunctionMatchSchema,
nativeFunctionMatchMemberSchema,
nativeFunctionByteSourceSchema,
nativeFunctionByteSourceGuidance,
nativeMatchStateSchema,
type NativeFunctionMatching,
} from "../native/functionMatching.js";
@@ -23,6 +25,8 @@ import {
type SummaryAnalysisView,
} from "./analysisViewShape.js";
import type { JsonValue } from "../jsonValue.js";
import { jsonValueByteLength } from "../jsonValueByteLength.js";
import { AnalysisResourceConstraintError } from "../analysisErrorCore.js";
const matchRow = nativeFunctionMatchSchema.extend({
left_count: z.number().int().nonnegative(),
@@ -56,9 +60,18 @@ export const nativeFunctionMatchingViewRequestSchema = z.discriminatedUnion(
names: z.array(z.string()).optional(),
fields: z.array(functionRow.keyof()).optional(),
}),
z.strictObject({
kind: z.literal("function-matches"),
collection: z.literal("byte-sources"),
sides: z.array(z.enum(["left", "right"])).optional(),
evidence_ids: z.array(z.string()).optional(),
offset: z.number().int().nonnegative().default(0),
limit: z.number().int().positive().default(64),
}),
],
);
export const nativeFunctionMatchingViewItemsSchema = z.union([
z.array(nativeFunctionByteSourceSchema),
z.array(
matchRow.partial().required({
match_id: true,
@@ -93,8 +106,14 @@ interface Checked {
}
const checked = new WeakMap<object, Checked>();
const readReport = createAnalysisViewResultReader(nativeFunctionMatchingSchema);
// Leave room for the Evidence envelope and duplicated MCP text/structured output.
const BYTE_SOURCE_PAGE_BYTES = 1024 * 1024;
const BYTE_SOURCE_PROJECTION_BYTES =
BYTE_SOURCE_PAGE_BYTES -
(jsonValueByteLength({ view_digest: "0".repeat(64) }) - 1);
type Request = z.output<typeof nativeFunctionMatchingViewRequestSchema>;
type MatchRequest = Exclude<Request, { collection: "byte-sources" }>;
const checkedReport = (
parent: AnalysisViewParent,
): Result<Checked, AnalysisError> => {
@@ -134,6 +153,7 @@ const sharedContext = (
[...parent.limitations, ...report.limitations],
parent.evidenceId,
"limitations",
report.byte_sources_count ? [nativeFunctionByteSourceGuidance] : [],
),
unknowns: [
"Unpaired observations and page exhaustion do not establish binary-wide function absence or behavioral equivalence.",
@@ -141,7 +161,7 @@ const sharedContext = (
});
const selected = (values: readonly string[] | undefined) =>
values === undefined ? undefined : new Set(values);
const filterRows = (entry: Checked, view: Request): readonly number[] => {
const filterRows = (entry: Checked, view: MatchRequest): readonly number[] => {
const key = JSON.stringify([
view.collection,
view.states,
@@ -188,7 +208,7 @@ const filterRows = (entry: Checked, view: Request): readonly number[] => {
};
const selectedItems = (
entry: Checked,
view: Request,
view: MatchRequest,
rows: readonly number[],
) => {
const indices = rows.slice(view.offset, view.offset + view.limit);
@@ -283,6 +303,7 @@ export const projectNativeFunctionMatchingView = (
const {
matches: _matches,
limitations: _limitations,
byte_sources: _byteSources,
...context
} = entry.report;
const shared = sharedContext(parent, entry.report);
@@ -294,6 +315,102 @@ export const projectNativeFunctionMatchingView = (
summary: context,
coverage: completeWithinViewCoverage(1, 1),
});
if (view.collection === "byte-sources") {
if (entry.report.byte_sources === undefined)
return err(
analysisViewInputError([
{
path: ["view"],
reason: "invalid_value",
message:
"This historical report did not record byte-source qualifications; inspect its linked Evidence.",
},
]),
);
const sides = selected(view.sides),
ids = selected(view.evidence_ids);
const items: z.output<typeof nativeFunctionByteSourceSchema>[] = [];
const fixed = {
kind: "function-matches" as const,
view,
...shared,
...context,
};
let bytes = jsonValueByteLength(
{
...fixed,
items: [],
byte_limited: true,
coverage: pageViewCoverage(
Number.MAX_SAFE_INTEGER,
Number.MAX_SAFE_INTEGER,
Number.MAX_SAFE_INTEGER,
),
} as JsonValue,
BYTE_SOURCE_PROJECTION_BYTES,
);
const tooLarge = (source?: { evidence_id: string; next_offset: number }) =>
err(
new AnalysisResourceConstraintError(
"inspect_analysis_view",
"transport",
"The selected byte-source view exceeds the projection allowance.",
{
parent_evidence_id: parent.evidenceId,
limit_bytes: BYTE_SOURCE_PAGE_BYTES,
...(source === undefined
? {}
: {
source_evidence_id: source.evidence_id,
next_offset: source.next_offset,
}),
},
{
retryable: false,
remediationAction:
source === undefined
? "Narrow the selection or inspect the original matching Evidence."
: "Inspect the original matching Evidence, or export it if retained; use next_offset to continue after the oversized source.",
},
),
);
if (bytes > BYTE_SOURCE_PROJECTION_BYTES) return tooLarge();
let total = 0,
byteLimited = false;
for (const row of entry.report.byte_sources) {
if (
(sides !== undefined && !sides.has(row.side)) ||
(ids !== undefined && !ids.has(row.evidence_id))
)
continue;
if (total >= view.offset && items.length < view.limit && !byteLimited) {
const item = row;
const size =
jsonValueByteLength(
item,
Math.max(0, BYTE_SOURCE_PROJECTION_BYTES - bytes),
) + 1;
if (bytes + size > BYTE_SOURCE_PROJECTION_BYTES) {
if (items.length === 0)
return tooLarge({
evidence_id: row.evidence_id,
next_offset: total + 1,
});
byteLimited = true;
} else {
items.push(item);
bytes += size;
}
}
total++;
}
return ok({
...fixed,
items,
byte_limited: byteLimited,
coverage: pageViewCoverage(view.offset, items.length, total),
});
}
const rows = filterRows(entry, view),
items = selectedItems(entry, view, rows);
return ok({
+39
View File
@@ -26,6 +26,13 @@ export const nativeFunctionMatchMemberSchema = z.strictObject({
evidence_links: z.array(evidenceId).min(1),
limitations: z.array(z.string()),
});
export const nativeFunctionByteSourceSchema = z.strictObject({
side: z.enum(["left", "right"]),
evidence_id: evidenceId,
limitations: z.array(z.string()),
});
export const nativeFunctionByteSourceGuidance =
"A function's selected byte sources are its evidence_links listed in the function-matches byte-sources view. Inspect their limitations before interpreting the byte basis.";
export const nativeFunctionMatchSchema = z.strictObject({
match_id: prefixedDigestSchema("match"),
state: nativeMatchStateSchema,
@@ -68,15 +75,21 @@ export const nativeFunctionMatchingContextSchema = z.strictObject({
right_structural_candidates: z.number().int().nonnegative(),
}),
summary: nativeFunctionMatchingSummarySchema,
byte_sources_count: z.number().int().nonnegative().optional(),
});
export const nativeFunctionMatchingSchema = nativeFunctionMatchingContextSchema
.extend({
matches: z.array(nativeFunctionMatchSchema),
limitations: z.array(z.string()),
byte_sources: z.array(nativeFunctionByteSourceSchema).optional(),
})
.superRefine((report, context) => {
const seen = new Set<string>();
const members = { left: new Set<string>(), right: new Set<string>() };
const byteReferences = {
left: new Set<string>(),
right: new Set<string>(),
};
const fingerprints = { left: 0, right: 0 };
const candidates = { left: 0, right: 0 };
const counts = { matched: 0, only_left: 0, only_right: 0, unresolved: 0 };
@@ -119,6 +132,7 @@ export const nativeFunctionMatchingSchema = nativeFunctionMatchingContextSchema
"Function occurrence identity, provenance or uniqueness disagrees with its selected inventory",
});
members[side].add(member.function_id);
for (const id of member.evidence_links) byteReferences[side].add(id);
if (member.body_sha256 !== null) fingerprints[side]++;
if (member.structural_candidate_sha256 !== null) candidates[side]++;
}
@@ -170,6 +184,31 @@ export const nativeFunctionMatchingSchema = nativeFunctionMatchingContextSchema
message: "Match state contradicts its occurrences",
});
}
if (
(report.byte_sources === undefined) !==
(report.byte_sources_count === undefined) ||
(report.byte_sources !== undefined &&
report.byte_sources_count !== report.byte_sources.length)
)
context.addIssue({
code: "custom",
message: "Byte-source count disagrees with recorded sources",
});
if (report.byte_sources !== undefined) {
const recorded = { left: new Set<string>(), right: new Set<string>() };
for (const source of report.byte_sources) {
if (
recorded[source.side].has(source.evidence_id) ||
!byteReferences[source.side].has(source.evidence_id)
)
context.addIssue({
code: "custom",
message:
"Byte source is duplicated or not used on its recorded side",
});
recorded[source.side].add(source.evidence_id);
}
}
if (
report.source_coverage.status !==
(counts.only_left + counts.only_right + counts.unresolved > 0
@@ -653,3 +653,319 @@ cliTest(
},
60000,
);
cliTest.for([{ profile: "full" }, { profile: "compact" }] as const)(
"ties byte qualifications to selected observations through paged and offline MCP ($profile)",
{ timeout: 60000 },
async ({ profile }) => {
const left = nativeMatchingInventory("1", [
{ address: "0x10", value: "left" },
]);
const right = nativeMatchingInventory("2", [
{ address: "0x20", value: "right" },
]);
const [leftInfo] = nativeMatchingDetails("1", "0x10", "c3");
const [rightInfo] = nativeMatchingDetails("2", "0x20", "c3");
const read = (side: "1" | "2", address: string, limitation: string) =>
createEvidence(nativeMatchingTarget(side), nativeMatchingProvider, {
operation: "read_bytes",
parameters: { address, length: 1 },
result: {
address,
requested_bytes: 1,
returned_bytes: 1,
bytes_hex: "c3",
complete: true,
},
limitations: [limitation],
});
const first = read("1", "0x10", "First selected source limitation");
const duplicate = read("1", "0x10", "Alternative source limitation");
const unused = read("1", "0x99", "Unused source limitation");
const other = read("2", "0x20", "Right source limitation");
const reference = (evidence_id: string) => ({
kind: "retained-evidence",
evidence_id,
});
const { call } = await connectLocalToolsMcp({
REA_MCP_INPUT_SCHEMA_PROFILE: profile,
REA_MCP_OUTPUT_SCHEMA_PROFILE: profile,
});
const execute = async (
firstRead: typeof first,
secondRead: typeof first,
) => {
const reply = await call("match_native_functions", {
left,
right,
left_observations: [leftInfo, firstRead, firstRead, secondRead, unused],
right_observations: [rightInfo, other],
detail: "complete",
});
expect(reply.isError, JSON.stringify(reply)).not.toBe(true);
return parseEvidence(reply.structuredContent);
};
const evidence = await execute(first, duplicate);
const report = nativeFunctionMatchingSchema.parse(
evidence.normalized_result,
);
const match = report.matches.find(
(item) => item.basis === "identical-bytes",
);
expect(match?.left[0]?.evidence_links).toContain(first.evidence_id);
expect(match?.left[0]?.evidence_links).not.toContain(duplicate.evidence_id);
expect(match?.right[0]?.evidence_links).toContain(other.evidence_id);
expect(report.byte_sources).toEqual([
{
side: "left",
evidence_id: first.evidence_id,
limitations: ["First selected source limitation"],
},
{
side: "right",
evidence_id: other.evidence_id,
limitations: ["Right source limitation"],
},
]);
const alternate = nativeFunctionMatchingSchema.parse(
(await execute(duplicate, first)).normalized_result,
);
expect(
alternate.matches.find((item) => item.basis === "identical-bytes")
?.left[0]?.evidence_links,
).toContain(duplicate.evidence_id);
expect(alternate.byte_sources?.map((item) => item.evidence_id)).toEqual([
duplicate.evidence_id,
other.evidence_id,
]);
const sourcePage = async (caller: typeof call, offset: number) => {
const reply = await caller("inspect_analysis_view", {
source: reference(evidence.evidence_id),
view: {
kind: "function-matches",
collection: "byte-sources",
offset,
limit: 1,
},
});
expect(reply.isError, JSON.stringify(reply)).not.toBe(true);
return parseEvidence(reply.structuredContent).normalized_result;
};
expect(await sourcePage(call, 0)).toMatchObject({
items: [
{
side: "left",
evidence_id: first.evidence_id,
limitations: ["First selected source limitation"],
},
],
coverage: { total: 2, next_offset: 1 },
});
expect(await sourcePage(call, 1)).toMatchObject({
items: [
{
side: "right",
evidence_id: other.evidence_id,
limitations: ["Right source limitation"],
},
],
coverage: { total: 2, next_offset: null },
});
const root = await createTestTempDirectory("rea-match-byte-sources-");
const path = join(root, "bundle.json");
const exported = await call("export_evidence_bundle", { path });
expect(exported.isError, JSON.stringify(exported)).not.toBe(true);
const offline = await connectLocalToolsMcp({
REA_MCP_INPUT_SCHEMA_PROFILE: profile,
REA_MCP_OUTPUT_SCHEMA_PROFILE: profile,
});
const imported = await offline.call("import_evidence_bundle", { path });
expect(imported.isError, JSON.stringify(imported)).not.toBe(true);
expect(await sourcePage(offline.call, 0)).toMatchObject({
items: [{ evidence_id: first.evidence_id }],
});
},
);
cliTest(
"bounds byte-source pages and recovers an oversized source",
{ timeout: 60000 },
async () => {
const left = nativeMatchingInventory("1", [
{ address: "0x10", value: "left" },
]);
const right = nativeMatchingInventory("2", [
{ address: "0x20", value: "right" },
]);
const [info] = nativeMatchingDetails("1", "0x10", "00".repeat(256));
if (info === undefined) throw new Error("Missing synthetic body");
const reads = Array.from({ length: 256 }, (_, index) => {
const address = `0x${(16 + index).toString(16)}`;
return createEvidence(nativeMatchingTarget("1"), nativeMatchingProvider, {
operation: "read_bytes",
parameters: { address, length: 1 },
result: {
address,
requested_bytes: 1,
returned_bytes: 1,
bytes_hex: "00",
complete: true,
},
limitations: [
`${index}:` +
"x".repeat(index === 0 ? 1_100_000 : index === 1 ? 6000 : 4500),
],
});
});
const reference = (evidence_id: string) => ({
kind: "retained-evidence",
evidence_id,
});
const root = await createTestTempDirectory("rea-match-large-source-");
const path = join(root, "inputs.json");
await writeFile(
path,
JSON.stringify(createEvidenceBundle([left, right, info, ...reads])),
);
const { call } = await connectLocalToolsMcp();
const imported = await call("import_evidence_bundle", { path });
expect(imported.isError, JSON.stringify(imported)).not.toBe(true);
const result = await call("match_native_functions", {
left: reference(left.evidence_id),
right: reference(right.evidence_id),
left_observations: [info, ...reads].map((record) =>
reference(record.evidence_id),
),
detail: "summary",
});
expect(result.isError, JSON.stringify(result)).not.toBe(true);
const parent = parseEvidence(result.structuredContent)
.normalized_result as { parent_evidence_id: string };
const oversized = await call("inspect_analysis_view", {
source: reference(parent.parent_evidence_id),
view: { kind: "function-matches", collection: "byte-sources" },
});
expect(parseMcpToolError(oversized).error).toMatchObject({
code: "resource_constraint",
details: {
resource: "transport",
reported_limits: {
source_evidence_id: reads[0]!.evidence_id,
next_offset: 1,
},
},
});
let offset = 1;
const ids: string[] = [reads[0]!.evidence_id];
let limited = false;
while (true) {
const reply = await call("inspect_analysis_view", {
source: reference(parent.parent_evidence_id),
view: {
kind: "function-matches",
collection: "byte-sources",
offset,
limit: 1000,
},
});
expect(reply.isError, JSON.stringify(reply)).not.toBe(true);
const page = parseEvidence(reply.structuredContent).normalized_result as {
byte_limited: boolean;
items: { evidence_id: string; limitations: string[] }[];
coverage: { total: number; next_offset: number | null };
};
limited ||= page.byte_limited;
if (offset === 1)
expect(page.items[0]?.limitations).toEqual(reads[1]!.limitations);
ids.push(...page.items.map((item) => item.evidence_id));
expect(page.coverage.total).toBe(256);
if (page.coverage.next_offset === null) break;
expect(page.coverage.next_offset).toBe(ids.length);
offset = page.coverage.next_offset;
}
expect(limited).toBe(true);
expect(ids).toEqual(reads.map((record) => record.evidence_id));
const original = await call("get_evidence_bundle", {
detail: "records",
filters: { evidence_id: reads[0]!.evidence_id },
});
expect(original.isError, JSON.stringify(original)).not.toBe(true);
expect(JSON.stringify(original.structuredContent)).toContain(
reads[0]!.limitations[0],
);
},
);
cliTest(
"oversized inline matching Evidence points back to the caller's original record",
{ timeout: 60000 },
async () => {
const left = nativeMatchingInventory("1", [
{ address: "0x10", value: "left" },
]);
const right = nativeMatchingInventory("2", [
{ address: "0x20", value: "right" },
]);
const [info] = nativeMatchingDetails("1", "0x10", "c3");
if (info === undefined) throw new Error("Missing synthetic body");
const read = createEvidence(
nativeMatchingTarget("1"),
nativeMatchingProvider,
{
operation: "read_bytes",
parameters: { address: "0x10", length: 1 },
result: {
address: "0x10",
requested_bytes: 1,
returned_bytes: 1,
bytes_hex: "c3",
complete: true,
},
limitations: ["x".repeat(1_100_000)],
},
);
const { call } = await connectLocalToolsMcp();
const match = await call("match_native_functions", {
left,
right,
left_observations: [info, read],
detail: "complete",
});
expect(match.isError, JSON.stringify(match)).not.toBe(true);
const matchingEvidence = parseEvidence(match.structuredContent);
const offline = await connectLocalToolsMcp();
const page = await offline.call("inspect_analysis_view", {
source: { kind: "inline", evidence: matchingEvidence },
view: { kind: "function-matches", collection: "byte-sources" },
});
const error = parseMcpToolError(page).error;
expect(error).toMatchObject({
code: "resource_constraint",
details: {
reported_limits: {
source_evidence_id: read.evidence_id,
next_offset: 1,
},
},
});
const report = nativeFunctionMatchingSchema.parse(
matchingEvidence.normalized_result,
);
expect(report.byte_sources).toEqual([
{
side: "left",
evidence_id: read.evidence_id,
limitations: read.limitations,
},
]);
const lookup = await offline.call("get_evidence_bundle", {
detail: "records",
filters: { evidence_id: read.evidence_id },
});
expect(lookup.isError, JSON.stringify(lookup)).not.toBe(true);
expect(
(lookup.structuredContent as { result: { records: unknown[] } }).result
.records,
).toEqual([]);
},
);