Compare commits

..
Author SHA1 Message Date
Cursor Agent 14e2971eb9 chore: merge main into codex/audit-artifact-view-coverage 2026-11-11 02:26:28 +00:00
Cursor Agent d3a97d54e8 test(views): expect unavailable Go dependency pages
Missing Go build metadata is unavailable coverage, so the MCP page reports a null total instead of an empty collection.
2026-11-10 23:06:23 +00:00
morluto 68df93fd28 fix(views)!: distinguish unavailable artifact collections
Keep missing BEAM tables and unavailable Go and Rust build metadata
separate from decoded empty collections. Retain producer limitations
on model metadata, tensor, and type pages.

BREAKING CHANGE: BEAM, Go, and Rust analysis view pages for unavailable
collections now report coverage.status "unavailable", coverage.total
null, and coverage.exhausted false. Refresh saved result schemas and
handle unknown totals before using coverage to infer absence.
2026-11-10 17:31:23 -05:00
15 changed files with 316 additions and 242 deletions

No files matched your search

@@ -5,8 +5,6 @@ import { expect, it, vi } from "vitest";
import { ArtifactResourceScope } from "../../artifacts/ArtifactResourceScope.js";
import { apiContractSchema } from "../../domain/apiContract/apiContract.js";
import { AnalysisResourceConstraintError } from "../../domain/analysisErrorCore.js";
import { parseEvidence } from "../../domain/evidence.js";
import { projectAnalysisView } from "../../domain/analysisView/analysisView.js";
import { createTestTempDirectory } from "../../../tests/fixtures/temporaryDirectory.js";
import { inspectApiContractEvidence } from "./ApiContractService.js";
import * as readOwner from "./ApiContractRead.js";
@@ -319,89 +317,3 @@ it("cancels a cooperative document traversal after the actual verified file read
await resources.close();
}
});
it.each(["between-paths", "after-projection"] as const)(
"preserves authenticated OpenAPI facts on cancellation %s",
async (stage) => {
const bytes = JSON.stringify({
openapi: "3.1.2",
info: { title: "Cancellation", version: "1" },
paths: { "/first": { get: {} }, "/second": { post: {} } },
});
const { path } = await inputFile(bytes);
const resources = new ArtifactResourceScope();
const controller = new AbortController();
const realParse = parser.parseApiContractSteps;
try {
const baseline = await inspectApiContractEvidence({ path }, resources);
if (!baseline.ok) throw baseline.error;
const complete = apiContractSchema.parse(
baseline.value.normalized_result,
);
const scheduled = vi
.spyOn(parser, "parseApiContractSteps")
.mockImplementationOnce(function* (...args) {
const steps = realParse(...args);
if (stage === "between-paths") {
expect(steps.next().done).toBe(false);
expect(steps.next().done).toBe(false);
setImmediate(() => controller.abort(stage));
return yield* steps;
}
const result = yield* steps;
setImmediate(() => controller.abort(stage));
return result;
});
try {
const result = await inspectApiContractEvidence({ path }, resources, {
signal: controller.signal,
});
if (result.ok) throw new Error("Expected cancellation");
expect(result.error._tag).toBe("AnalysisCancelledError");
expect(result.error.cause).toBe(stage);
const evidence = parseEvidence(result.error.partialObservation);
const retained = apiContractSchema.parse(evidence.normalized_result);
expect(evidence.subject).toEqual(baseline.value.subject);
expect(evidence.parameters).toEqual(baseline.value.parameters);
expect(retained.artifact).toEqual(complete.artifact);
expect(retained.contract_id).toBe(complete.contract_id);
if (stage === "between-paths") {
expect(retained.operations).toEqual(complete.operations.slice(0, 1));
expect(retained.source_coverage.status).toBe("partial");
expect(evidence.evidence_id).not.toBe(baseline.value.evidence_id);
const page = projectAnalysisView(
{
evidenceId: evidence.evidence_id,
operation: evidence.operation,
predicateType: evidence.predicate_type,
normalizedResult: evidence.normalized_result,
limitations: evidence.limitations,
},
{
kind: "api-contract",
collection: "operations",
offset: 0,
limit: 1,
},
);
expect(page).toMatchObject({
ok: true,
value: {
parent_evidence_id: evidence.evidence_id,
items: [{ path: "/first", state: "declared" }],
coverage: { exhausted: true },
source_coverage: { status: "partial" },
},
});
} else {
expect(retained).toEqual(complete);
expect(evidence.evidence_id).toBe(baseline.value.evidence_id);
}
} finally {
scheduled.mockRestore();
}
} finally {
await resources.close();
}
},
);
@@ -11,8 +11,6 @@ import { err, ok, type Result } from "../../domain/result.js";
import {
API_CONTRACT_OPERATION as operation,
API_CONTRACT_PROVIDER,
apiContractSchema,
type ApiContract,
type ApiContractArtifact,
} from "../../domain/apiContract/apiContract.js";
import {
@@ -72,32 +70,8 @@ function* documentSteps(document: unknown, artifact: ApiContractArtifact) {
return yield* parseApiContractSteps(document, artifact);
}
type OpenApiInput = Extract<
InspectApiContractInput,
{ format: "openapi-json" }
>;
const documentEvidence = (input: OpenApiInput, result: ApiContract): Evidence =>
createEvidence(
{ path: input.path, format: "file", sha256: result.artifact.sha256 },
API_CONTRACT_PROVIDER,
{
operation,
predicateType: "rea.api-contract-inventory",
parameters: {
path: input.path,
format: input.format,
max_file_bytes: input.max_file_bytes,
},
result,
confidence: "observed",
limitations: result.limitations,
locations: [{ kind: "artifact-path", path: input.path }],
},
);
const importDocument = async (
input: OpenApiInput,
input: Extract<InspectApiContractInput, { format: "openapi-json" }>,
bytes: Buffer,
sha256: string,
signal?: AbortSignal,
@@ -112,16 +86,26 @@ const importDocument = async (
}),
signal,
);
if (!parsed.ok) {
const partial = apiContractSchema.safeParse(
parsed.error.partialObservation,
);
if (partial.success)
parsed.error.partialObservation = documentEvidence(input, partial.data);
return parsed;
}
if (!parsed.ok) return parsed;
const result = parsed.value;
return completeProviderEvidence(
documentEvidence(input, parsed.value),
createEvidence(
{ path: input.path, format: "file", sha256 },
API_CONTRACT_PROVIDER,
{
operation,
predicateType: "rea.api-contract-inventory",
parameters: {
path: input.path,
format: input.format,
max_file_bytes: input.max_file_bytes,
},
result,
confidence: "observed",
limitations: result.limitations,
locations: [{ kind: "artifact-path", path: input.path }],
},
),
signal,
);
};
-2
View File
@@ -1,7 +1,6 @@
import type { PartialTaskMeasurement } from "./desktop/taskDifficulty.js";
import type { AppleIpsPartialObservation } from "./native/appleIps.js";
import type { PlaywrightTrace } from "./playwrightTrace/playwrightTrace.js";
import type { ApiContract } from "./apiContract/apiContract.js";
import type { GraphqlContract } from "./apiContract/graphqlContract.js";
import type { SavedAnalysisSnapshotPartialObservation } from "./savedAnalysisSnapshot.js";
import type { AnalysisSettingLimit } from "./analysisSettings.js";
@@ -499,7 +498,6 @@ export type AnalysisPartialObservation =
}
| { readonly kind: "unretained-evidence"; readonly evidence: Evidence }
| { readonly kind: "retained-evidence"; readonly evidence_id: string }
| ApiContract
| GraphqlContract
| PlaywrightTrace
| SavedAnalysisSnapshotPartialObservation
@@ -559,6 +559,7 @@ export const erlangBeamSummaryViewResultSchema = z.strictObject({
});
export const erlangBeamTableViewResultSchema = z.strictObject({
...viewResultBase,
coverage: nullableCollectionViewCoverageSchema,
kind: z.literal("beam"),
parent_operation: z.literal("inspect_erlang_beam"),
view: erlangBeamViewRequestSchema,
@@ -624,6 +625,7 @@ export const rustBinarySummaryViewResultSchema = z.strictObject({
export const rustBinaryPageViewResultSchema = z.strictObject({
...viewResultBase,
coverage: nullableCollectionViewCoverageSchema,
...rustBinaryViewContextSchema.shape,
kind: z.literal("rust"),
parent_operation: z.literal("inspect_rust_binary"),
@@ -1505,6 +1507,7 @@ export const analysisViewResultSchema = z.discriminatedUnion("kind", [
z.strictObject({
...viewResultBase,
...goBinaryViewContextSchema.shape,
coverage: nullableCollectionViewCoverageSchema,
kind: z.literal("go"),
parent_operation: z.literal("inspect_go_binary"),
view: goBinaryViewRequestSchema,
+1 -1
View File
@@ -185,7 +185,7 @@ export const projectApiContractView = (
unknowns:
context.source_coverage.status === "partial"
? [
"This inventory is partial. Inspect limitations for coverage and query path-item-references and diagnostics for any retained source pointers.",
"Unresolved or malformed declarations limit this inventory; query path-item-references and diagnostics for exact source pointers.",
]
: [],
};
@@ -0,0 +1,125 @@
import { expect, it } from "vitest";
import { createEvidence } from "../evidence.js";
import type { ErlangBeam } from "../erlang/beam.js";
import type { ModelArtifact } from "../model/modelArtifact.js";
import {
projectAnalysisView,
type AnalysisViewParent,
} from "./analysisView.js";
const parent = (
operation: string,
result: ErlangBeam | ModelArtifact,
): AnalysisViewParent => {
const evidence = createEvidence(
{ path: result.artifact.path, sha256: "a".repeat(64), format: "file" },
{ id: "fixture", name: "Fixture reader", version: "1" },
{ operation, parameters: {}, result },
);
return {
predicateType: evidence.predicate_type,
evidenceId: evidence.evidence_id,
operation,
subject: evidence.subject,
normalizedResult: result,
limitations: [],
};
};
const beam: ErlangBeam = {
artifact: {
path: "/artifacts/module.beam",
sha256: "a".repeat(64),
bytes: 12,
},
form: { location: { offset: 0, bytes: 12 }, size: 4 },
chunks: [],
atoms: null,
atom_encoding: null,
exports: null,
imports: null,
lambdas: null,
code: null,
module: null,
coverage: { status: "complete", examined_chunks: 0, atoms: 0 },
limitations: [],
};
it.each(["atoms", "exports", "imports", "lambdas"] as const)(
"distinguishes unavailable BEAM %s from a decoded empty table",
(collection) => {
for (const available of [false, true]) {
const result = projectAnalysisView(
parent("inspect_erlang_beam", {
...beam,
[collection]: available ? [] : null,
}),
{ kind: "beam", collection, offset: 7, limit: 1 },
);
if (!result.ok) throw result.error;
expect(result.value.coverage).toEqual({
status: available ? "empty" : "unavailable",
examined: 0,
total: available ? 0 : null,
next_offset: null,
exhausted: available,
});
expect(result.value).toMatchObject({ page: { collection, items: [] } });
if (!available)
expect(result.value.unknowns.join(" ")).toContain(
`No ${collection} table was decoded`,
);
}
},
);
const model: ModelArtifact = {
artifact: {
path: "/artifacts/model.gguf",
file_size: 32,
header_sha256: "a".repeat(64),
header_length: 32,
sha256: "a".repeat(64),
bytes_read: 32,
read_scope: "full-file",
},
format: "gguf",
version: 3,
byte_order: "little",
alignment: 32,
tensor_data_offset: 32,
metadata: [],
tensors: [],
totals: {
confidence: "derived",
parameter_count: "0",
tensor_bytes: 0,
by_type: [],
},
coverage: {
header: "complete",
tensor_data: "not-interpreted",
array_values: "preview",
tensor_ranges: "partial",
storage_sizes: "partial",
},
limitations: [
"Array metadata retains only the requested preview; storage sizes remain unknown.",
],
};
it.each(["metadata", "tensors", "types"] as const)(
"retains producer limitations on model %s pages with no envelope warnings",
(collection) => {
const input = parent("inspect_model_artifact", model);
const result = projectAnalysisView(input, {
kind: "model-artifact",
collection,
offset: 0,
limit: 1,
});
if (!result.ok) throw result.error;
expect(result.value.limitations).toEqual(model.limitations);
expect(input.limitations).toEqual([]);
},
);
+13 -3
View File
@@ -13,6 +13,7 @@ import {
boundedViewMessages,
completeWithinViewCoverage,
pageViewCoverage,
unavailableViewCoverage,
} from "./analysisViewCoverage.js";
import { selectViewRows } from "./selectViewRows.js";
@@ -120,7 +121,7 @@ type Row = NonNullable<ErlangBeam[Table]>[number];
type BeamView = z.infer<typeof erlangBeamViewRequestSchema>;
/** Select already parsed rows; original atom/lambda indexes are never repurposed. */
const selectRows = (rows: readonly Row[] | null, view: BeamView) => {
const selectRows = (source: readonly Row[], view: BeamView) => {
const names = view.names === undefined ? undefined : new Set(view.names);
const indices =
view.indices === undefined ? undefined : new Set(view.indices);
@@ -138,7 +139,6 @@ const selectRows = (rows: readonly Row[] | null, view: BeamView) => {
),
source_index,
});
const source = rows ?? [];
if (names === undefined && indices === undefined && modules === undefined)
return {
rows: source
@@ -223,7 +223,17 @@ export const projectErlangBeamView = (
summary,
coverage: completeWithinViewCoverage(chunks.length, chunks.length),
});
const selected = selectRows(parsed.value[view.collection], view);
const rows = parsed.value[view.collection];
if (rows === null)
return ok({
...shared,
kind: "beam" as const,
view,
beam: summary,
page: { collection: view.collection, items: [] },
coverage: unavailableViewCoverage(),
});
const selected = selectRows(rows, view);
return ok({
...shared,
kind: "beam" as const,
@@ -238,3 +238,53 @@ it("refuses string_literals view when unrequested and projects filtered/truncate
],
});
});
it.each(["dependencies", "settings"] as const)(
"distinguishes unavailable Go %s from decoded empty records",
(collection) => {
for (const available of [false, true]) {
const input = parent();
const result = projectAnalysisView(
{
...input,
normalizedResult: {
...report,
build_info: available
? {
header_offset: 0,
encoding: "inline",
go_version: null,
go_version_bytes_base64: "",
module_text: null,
module_bytes_base64: "",
version_location: { offset: 32, bytes: 0 },
module_location: { offset: 32, bytes: 0 },
module: {
path: null,
main: null,
dependencies: [],
settings: [],
unparsed_lines: [],
unparsed_line_bytes_base64: [],
complete: true,
},
}
: null,
},
},
{ kind: "go", collection, offset: 3, limit: 1 },
);
if (!result.ok) throw result.error;
expect(result.value.coverage).toEqual({
status: available ? "empty" : "unavailable",
examined: 0,
total: available ? 0 : null,
next_offset: null,
exhausted: available,
});
expect(result.value).toMatchObject({
source_coverage: { build_info_available: available },
});
}
},
);
+11 -2
View File
@@ -20,6 +20,7 @@ import {
boundedViewMessages,
completeWithinViewCoverage,
pageViewCoverage,
unavailableViewCoverage,
} from "./analysisViewCoverage.js";
import { analysisViewInputError } from "./analysisViewErrors.js";
import { createAnalysisViewResultReader } from "./analysisViewParent.js";
@@ -322,10 +323,18 @@ export const projectGoBinaryView = (
),
});
}
if (info === null)
return ok({
kind: "go" as const,
view,
...shared,
page: { collection: view.collection, rows: [] },
coverage: unavailableViewCoverage(),
});
if (view.collection === "dependencies") {
const paths = view.paths === undefined ? undefined : new Set(view.paths);
const selected = selectViewRows(
info?.module.dependencies ?? [],
info.module.dependencies,
view,
(row, index) =>
(indices?.has(index) ?? true) && (paths?.has(row.path) ?? true),
@@ -353,7 +362,7 @@ export const projectGoBinaryView = (
}
const keys = view.keys === undefined ? undefined : new Set(view.keys);
const selected = selectViewRows(
info?.module.settings ?? [],
info.module.settings,
view,
(row, index) =>
(indices?.has(index) ?? true) && (keys?.has(row.key) ?? true),
+1 -1
View File
@@ -217,7 +217,7 @@ export const projectModelArtifactView = (
parent_digest: parent.evidenceId.slice(3),
artifact: { path: report.artifact.path, sha256: report.artifact.sha256 },
limitations: boundedViewMessages(
parent.limitations,
[...parent.limitations, ...report.limitations],
parent.evidenceId,
"limitations",
),
@@ -206,3 +206,40 @@ it("pages matching original indices and omits dependency vectors unless selected
next_offset: null,
});
});
it.each(["packages", "edges"] as const)(
"distinguishes unavailable Rust %s from decoded empty records",
(collection) => {
for (const available of [false, true]) {
const metadata = report.auditable_metadata!;
const result = projectAnalysisView(
parent({
...report,
auditable_metadata: available
? {
...metadata,
packages: [],
root_package_index: null,
dependency_edges: [],
cyclic_dependency_indices: [],
}
: null,
}),
{ kind: "rust", collection, offset: 3, limit: 1 },
);
if (!result.ok) throw result.error;
expect(result.value.coverage).toEqual({
status: available ? "empty" : "unavailable",
examined: 0,
total: available ? 0 : null,
next_offset: null,
exhausted: available,
});
expect(result.value).toMatchObject({
source_coverage: {
embedded_records: available ? "complete" : "unknown",
},
});
}
},
);
+12 -2
View File
@@ -22,6 +22,7 @@ import {
boundedViewMessages,
completeWithinViewCoverage,
pageViewCoverage,
unavailableViewCoverage,
} from "./analysisViewCoverage.js";
import { analysisViewInputError } from "./analysisViewErrors.js";
import { selectViewRows } from "./selectViewRows.js";
@@ -190,6 +191,15 @@ export const projectRustBinaryView = (
summary,
coverage: completeWithinViewCoverage(1, 1),
});
if (metadata === null)
return ok({
kind: "rust" as const,
view,
...shared,
rust: summary,
page: { collection: view.collection, rows: [] },
coverage: unavailableViewCoverage(),
});
const indices =
view.indices === undefined ? undefined : new Set(view.indices);
const fields =
@@ -199,7 +209,7 @@ export const projectRustBinaryView = (
const versions =
view.versions === undefined ? undefined : new Set(view.versions);
const selected = selectViewRows(
metadata?.packages ?? [],
metadata.packages,
view,
(row, index) =>
(indices?.has(index) ?? true) &&
@@ -238,7 +248,7 @@ export const projectRustBinaryView = (
const to =
view.to_indices === undefined ? undefined : new Set(view.to_indices);
const selected = selectViewRows(
metadata?.dependency_edges ?? [],
metadata.dependency_edges,
view,
(row, index) =>
(indices?.has(index) ?? true) &&
@@ -3,7 +3,6 @@ import { readFileSync } from "node:fs";
import { expect, it } from "vitest";
import { apiContractSchema, type ApiContractArtifact } from "./apiContract.js";
import { parseApiContractSteps } from "./parseApiContract.js";
import { AnalysisCancelledError } from "../analysisErrorCore.js";
const artifact: ApiContractArtifact = {
path: "/contract.json",
@@ -306,39 +305,9 @@ it("handles 3.2 QUERY and case-sensitive additional methods, diagnosing invalid
it("bounds expanded identities and source pointers before building a giant row", () => {
const result = parse(
document({
"/retained": { get: {} },
[`/${"a".repeat(1_100_000)}`]: { get: {} },
}),
document({ [`/${"a".repeat(1_100_000)}`]: { get: {} } }),
);
expect(result.ok).toBe(false);
if (result.ok) throw new Error("Expected a retained-facts refusal");
expect(result.error._tag).toBe("AnalysisResourceConstraintError");
const partial = apiContractSchema.parse(result.error.partialObservation);
expect(partial.operations.map((row) => row.path)).toEqual(["/retained"]);
expect(partial.source_coverage.status).toBe("partial");
});
it("retains an interpreted path when cancellation interrupts traversal", () => {
const input = document({
"/first": { get: { operationId: "first" } },
"/second": { get: { operationId: "second" } },
});
const steps = parseApiContractSteps(input, artifact);
for (let checkpoint = 0; checkpoint < 3; checkpoint++)
expect(steps.next().done).toBe(false);
const cancellation = new AnalysisCancelledError("inspect_api_contract");
const stopped = steps.throw(cancellation);
if (!stopped.done || stopped.value.ok)
throw new Error("Expected cancellation");
expect(stopped.value.error).toBe(cancellation);
const partial = apiContractSchema.parse(cancellation.partialObservation);
const complete = report(input);
expect(partial.operations).toEqual(complete.operations.slice(0, 1));
expect(partial.summary.operation_slots).toBe(1);
expect(partial.source_coverage).toMatchObject({
status: "partial",
path_entries_examined: 1,
});
expect(complete.source_coverage.status).toBe("complete-within-scope");
if (!result.ok)
expect(result.error._tag).toBe("AnalysisResourceConstraintError");
});
+39 -72
View File
@@ -1,5 +1,4 @@
import {
AnalysisCancelledError,
AnalysisInputError,
AnalysisResourceConstraintError,
AnalysisUnsupportedTargetError,
@@ -317,17 +316,14 @@ function* pathItem(
return ok(undefined);
}
interface ContractReportContext {
readonly openapi: string;
readonly info: ApiContract["info"];
readonly pathsState: ApiContract["source_coverage"]["paths_state"];
examined: number;
}
const contractReport = (
const completedInventory = (
inventory: ContractInventory,
context: ContractReportContext,
incomplete = false,
context: {
openapi: string;
info: ApiContract["info"];
pathsState: ApiContract["source_coverage"]["paths_state"];
examined: number;
},
): ApiContract => {
const artifact = inventory.artifact;
let declared = 0;
@@ -352,9 +348,7 @@ const contractReport = (
source_coverage: {
scope: "inline-path-operations",
status:
incomplete ||
inventory.references.length > 0 ||
inventory.diagnostics.length > 0
inventory.references.length > 0 || inventory.diagnostics.length > 0
? "partial"
: "complete-within-scope",
paths_state: context.pathsState,
@@ -364,11 +358,6 @@ const contractReport = (
duplicate_json_members: "last-value-wins",
},
limitations: [
...(incomplete
? [
"Traversal stopped before the inventory was complete. Counts describe the retained rows.",
]
: []),
"Operations are document declarations, not evidence of runtime implementation, reachability or authorization.",
"Only inline operations under paths are inventoried; callbacks, webhooks, components, servers, parameters, schemas, request/response contracts and security are not analyzed.",
"No reference is resolved, including local fragments. A Path Item reference makes its effective operations unknown; adjacent inline slots are preserved without merging referenced definitions.",
@@ -379,32 +368,6 @@ const contractReport = (
};
};
function* collectPaths(
sourcePaths: Record<string, unknown>,
inventory: ContractInventory,
context: ContractReportContext,
modern: boolean,
): Generator<void, Result<void, AnalysisError>> {
for (const path in sourcePaths) {
if (!Object.hasOwn(sourcePaths, path) || path.startsWith("x-")) continue;
yield;
context.examined++;
// Reserve expanded pointer/path strings before escaping or building a row.
const admitted = inventory.reserve(512 + path.length * 16);
if (!admitted.ok) return admitted;
const pointer = `/paths/${pointerPart(path)}`;
const read = path.startsWith("/")
? yield* pathItem(sourcePaths[path], { inventory, path, pointer, modern })
: inventory.diagnostic(
"invalid-path-key",
pointer,
"A Paths entry must start with /; it was not interpreted as an endpoint.",
);
if (!read.ok) return read;
}
return ok(undefined);
}
/** Enumerate declarations only; never resolve references, servers, callbacks or runtime expressions. */
export function* parseApiContractSteps(
value: unknown,
@@ -454,32 +417,36 @@ export function* parseApiContractSteps(
);
if (!diagnosed.ok) return diagnosed;
}
const context: ContractReportContext = {
openapi: root.openapi,
info: info.value,
pathsState,
examined: 0,
};
const interrupted = (error: AnalysisError) => {
const retainedRows =
inventory.operations.length +
inventory.references.length +
inventory.diagnostics.length;
if (retainedRows > 0)
error.retainPartialObservation(contractReport(inventory, context, true));
return err(error);
};
try {
const read = yield* collectPaths(
paths ?? {},
inventory,
context,
version[1] === "2",
);
if (!read.ok) return interrupted(read.error);
} catch (cause: unknown) {
if (cause instanceof AnalysisCancelledError) return interrupted(cause);
throw cause;
let examined = 0;
const sourcePaths = paths ?? {};
for (const path in sourcePaths) {
if (!Object.hasOwn(sourcePaths, path) || path.startsWith("x-")) continue;
yield;
examined++;
// Reserve expanded pointer/path strings before escaping or building a row.
const admitted = inventory.reserve(512 + path.length * 16);
if (!admitted.ok) return admitted;
const pointer = `/paths/${pointerPart(path)}`;
const read = path.startsWith("/")
? yield* pathItem(sourcePaths[path], {
inventory,
path,
pointer,
modern: version[1] === "2",
})
: inventory.diagnostic(
"invalid-path-key",
pointer,
"A Paths entry must start with /; it was not interpreted as an endpoint.",
);
if (!read.ok) return read;
}
return ok(contractReport(inventory, context));
return ok(
completedInventory(inventory, {
openapi: root.openapi,
info: info.value,
pathsState,
examined,
}),
);
}
+1 -1
View File
@@ -368,7 +368,7 @@ mcpTest(
const page = goPage(parseEvidence(empty.structuredContent));
expect(page).toMatchObject({
page: { rows: [] },
coverage: { total: 0 },
coverage: { status: "unavailable", total: null, exhausted: false },
source_coverage: {
build_info_available: false,
module_parse_complete: null,