refactor(runtime): retain complete reconciliation outputs
This commit is contained in:
parent
7b3c797237
commit
79ea571512
|
|
@ -156,16 +156,18 @@ silently equated with the generated bytes observed by CDP.
|
|||
|
||||
## Bounds and determinism
|
||||
|
||||
Inputs allow up to eight static layers and 32 passive captures. Runtime entity,
|
||||
reconciliation item, and static load-state projections have caller-visible
|
||||
limits and report omitted counts when reached. The merged application graph
|
||||
retains all selected roots, nodes, edges, and observations from those inputs;
|
||||
it adds no second aggregate prefix cap. Reaching an input projection limit
|
||||
reports exact omitted counts and `coverage.status: truncated`.
|
||||
The workflow does not impose aggregate count caps on static layers, passive
|
||||
captures, runtime entities, reconciliation items, static load states, runtime
|
||||
mapping declarations, or candidate references. These collections remain
|
||||
subject to the structural validation applied to each Evidence record and
|
||||
application graph; passive capture collection limits are committed by the
|
||||
observation operation that produced that Evidence. Reconciliation reports zero
|
||||
omitted items when it projects the complete supplied inputs. Static JavaScript
|
||||
analysis can still report its own bounded AST coverage as partial or truncated.
|
||||
|
||||
Layers, captures, nodes, edges, matches, and evidence links are canonically
|
||||
ordered. Repeating the same verified Evidence, mappings, and limits produces
|
||||
the same reconciliation, graph, and Evidence identifiers.
|
||||
ordered. Repeating the same verified Evidence and mappings produces the same
|
||||
reconciliation, graph, and Evidence identifiers.
|
||||
|
||||
## Non-goals
|
||||
|
||||
|
|
|
|||
|
|
@ -12,10 +12,6 @@ import { flattenSemanticReturnValue } from "../domain/javascriptSemanticReturns.
|
|||
import type { JavaScriptSourceRange } from "../domain/javascriptStaticAnalysisTypes.js";
|
||||
import type { JavaScriptArtifactGraphCoverage } from "./JavaScriptArtifactGraphContext.js";
|
||||
|
||||
const MAX_PROJECTED_RETURN_SHAPES = 32;
|
||||
const MAX_PROJECTED_RETURN_FIELDS = 64;
|
||||
const MAX_PROJECTED_PROPERTY_COVERAGE = 64;
|
||||
|
||||
export interface JavaScriptReturnShapeProjection {
|
||||
readonly properties: ReturnType<typeof jsonObjectSchema.parse>;
|
||||
readonly range: JavaScriptSourceRange;
|
||||
|
|
@ -46,24 +42,7 @@ export const projectJavaScriptExportReturnShapes = (input: {
|
|||
input.baseCoverage.status === "complete" &&
|
||||
callable.returnCoverage.status === "complete" &&
|
||||
projectionOmitted === 0;
|
||||
const limits = [
|
||||
...input.baseCoverage.limits,
|
||||
{
|
||||
name: "return-shape-sites",
|
||||
value: MAX_PROJECTED_RETURN_SHAPES,
|
||||
unit: "items" as const,
|
||||
},
|
||||
{
|
||||
name: "return-shape-fields",
|
||||
value: MAX_PROJECTED_RETURN_FIELDS,
|
||||
unit: "items" as const,
|
||||
},
|
||||
{
|
||||
name: "return-shape-property-coverage",
|
||||
value: MAX_PROJECTED_PROPERTY_COVERAGE,
|
||||
unit: "items" as const,
|
||||
},
|
||||
];
|
||||
const limits = input.baseCoverage.limits;
|
||||
const omitted =
|
||||
semanticOmitted === null ? null : semanticOmitted + projectionOmitted;
|
||||
const coverage = complete
|
||||
|
|
@ -79,9 +58,6 @@ export const projectJavaScriptExportReturnShapes = (input: {
|
|||
"No direct return value was retained; runtime return behavior remains unknown.",
|
||||
]
|
||||
: []),
|
||||
...(projectionOmitted > 0
|
||||
? ["Return-shape graph projection reached explicit retention limits."]
|
||||
: []),
|
||||
];
|
||||
return {
|
||||
properties: jsonObjectSchema.parse({
|
||||
|
|
@ -110,37 +86,14 @@ export const projectJavaScriptExportReturnShapes = (input: {
|
|||
};
|
||||
|
||||
const projectReturnSites = (callable: JavaScriptSemanticCallable) => {
|
||||
let retainedFields = 0;
|
||||
let retainedCoverage = 0;
|
||||
let omittedFields = 0;
|
||||
let omittedCoverage = 0;
|
||||
const retainedSites = callable.returnSites.slice(
|
||||
0,
|
||||
MAX_PROJECTED_RETURN_SHAPES,
|
||||
);
|
||||
const retainedSites = callable.returnSites;
|
||||
const shapes = retainedSites.map((site) => {
|
||||
const flattened = flattenSemanticReturnValue(site.value);
|
||||
const remainingFields = Math.max(
|
||||
0,
|
||||
MAX_PROJECTED_RETURN_FIELDS - retainedFields,
|
||||
);
|
||||
const fields = flattened.fields.slice(0, remainingFields).map((field) => ({
|
||||
const fields = flattened.fields.map((field) => ({
|
||||
...field,
|
||||
value: jsonValueSchema.parse(field.value),
|
||||
}));
|
||||
retainedFields += fields.length;
|
||||
omittedFields += flattened.fields.length - fields.length;
|
||||
const remainingCoverage = Math.max(
|
||||
0,
|
||||
MAX_PROJECTED_PROPERTY_COVERAGE - retainedCoverage,
|
||||
);
|
||||
const propertyCoverage = flattened.propertyCoverage.slice(
|
||||
0,
|
||||
remainingCoverage,
|
||||
);
|
||||
retainedCoverage += propertyCoverage.length;
|
||||
omittedCoverage +=
|
||||
flattened.propertyCoverage.length - propertyCoverage.length;
|
||||
const propertyCoverage = flattened.propertyCoverage;
|
||||
return {
|
||||
source_range: site.location,
|
||||
value_status: site.value.status,
|
||||
|
|
@ -150,8 +103,8 @@ const projectReturnSites = (callable: JavaScriptSemanticCallable) => {
|
|||
});
|
||||
return {
|
||||
shapes,
|
||||
omittedSites: callable.returnSites.length - retainedSites.length,
|
||||
omittedFields,
|
||||
omittedCoverage,
|
||||
omittedSites: 0,
|
||||
omittedFields: 0,
|
||||
omittedCoverage: 0,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,5 +39,4 @@ const parameters = (
|
|||
runtime_evidence_ids: input.runtime_observations.map(
|
||||
({ evidence_id: id }) => id,
|
||||
),
|
||||
limits: input.limits,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -32,11 +32,6 @@ const reconciliationEvidence = createEvidence(
|
|||
JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE.runtime_observations.map(
|
||||
({ evidence_id: id }) => id,
|
||||
),
|
||||
limits: {
|
||||
max_runtime_entities: 10_000,
|
||||
max_reconciliation_items: 20_000,
|
||||
max_static_load_states: 20_000,
|
||||
},
|
||||
},
|
||||
result: reconciliation,
|
||||
confidence: "inferred",
|
||||
|
|
|
|||
|
|
@ -208,9 +208,6 @@ export const applicationVersionComparisonResultSchema = z
|
|||
});
|
||||
});
|
||||
|
||||
export type CompareApplicationVersionsInput = z.infer<
|
||||
typeof compareApplicationVersionsInputSchema
|
||||
>;
|
||||
export type ApplicationVersionComparisonItem = z.infer<
|
||||
typeof comparisonItemSchema
|
||||
>;
|
||||
|
|
|
|||
|
|
@ -25,21 +25,17 @@ export const classifyStaticLoadStates = (
|
|||
runtimeEntities: readonly RuntimeReconciliationEntity[],
|
||||
matches: readonly JavaScriptRuntimeReconciliationItem[],
|
||||
options: {
|
||||
readonly maximumStates: number;
|
||||
readonly reconciliationComplete: boolean;
|
||||
},
|
||||
): StaticLoadStateProjection => {
|
||||
const states: JavaScriptStaticLoadState[] = [];
|
||||
let totalStates = 0;
|
||||
for (const layer of layers) {
|
||||
const projection = classifyLayer(layer, runtimeEntities, matches, {
|
||||
reconciliationComplete: options.reconciliationComplete,
|
||||
maximumStates: Math.max(0, options.maximumStates - states.length),
|
||||
});
|
||||
totalStates += projection.total;
|
||||
states.push(...projection.states);
|
||||
}
|
||||
return { states, omittedStates: totalStates - states.length };
|
||||
return { states, omittedStates: 0 };
|
||||
};
|
||||
|
||||
const classifyLayer = (
|
||||
|
|
@ -48,11 +44,9 @@ const classifyLayer = (
|
|||
matches: readonly JavaScriptRuntimeReconciliationItem[],
|
||||
options: {
|
||||
readonly reconciliationComplete: boolean;
|
||||
readonly maximumStates: number;
|
||||
},
|
||||
): { readonly states: JavaScriptStaticLoadState[]; readonly total: number } => {
|
||||
): { readonly states: JavaScriptStaticLoadState[] } => {
|
||||
const nodes = layer.graph.nodes.filter(isLoadStateNode);
|
||||
if (options.maximumStates === 0) return { states: [], total: nodes.length };
|
||||
const direct = new Map<string, string[]>();
|
||||
for (const match of matches)
|
||||
if (
|
||||
|
|
@ -73,7 +67,7 @@ const classifyLayer = (
|
|||
scopedEntities.every(({ capture }) =>
|
||||
captureScriptsComplete(capture.evidence.evidence_id, runtimeEntities),
|
||||
);
|
||||
const states = nodes.slice(0, options.maximumStates).map((node) => {
|
||||
const states = nodes.map((node) => {
|
||||
const runtimeNodeIds = uniqueSorted(direct.get(node.node_id) ?? []);
|
||||
if (runtimeNodeIds.length > 0)
|
||||
return state(layer, node, {
|
||||
|
|
@ -102,7 +96,7 @@ const classifyLayer = (
|
|||
: "static-or-runtime-coverage-incomplete",
|
||||
});
|
||||
});
|
||||
return { states, total: nodes.length };
|
||||
return { states };
|
||||
};
|
||||
|
||||
const residentNodes = (
|
||||
|
|
|
|||
|
|
@ -18,23 +18,18 @@ export const reconcileJavaScriptRuntime = (
|
|||
const parsed = reconcileJavaScriptRuntimeInputSchema.parse(input);
|
||||
const layers = parseStaticLayers(parsed.static_layers);
|
||||
const captures = parseRuntimeCaptures(parsed.runtime_observations);
|
||||
const runtime = projectRuntimeCaptures(
|
||||
captures,
|
||||
parsed.limits.max_runtime_entities,
|
||||
);
|
||||
const runtime = projectRuntimeCaptures(captures);
|
||||
const candidates = collectStaticRuntimeCandidates(layers);
|
||||
const matching = reconcileRuntimeEntities({
|
||||
entities: runtime.entities,
|
||||
candidates,
|
||||
layers,
|
||||
maximumItems: parsed.limits.max_reconciliation_items,
|
||||
});
|
||||
const loadStates = classifyStaticLoadStates(
|
||||
layers,
|
||||
runtime.entities,
|
||||
matching.items,
|
||||
{
|
||||
maximumStates: parsed.limits.max_static_load_states,
|
||||
reconciliationComplete:
|
||||
runtime.omittedEntities === 0 && matching.omittedItems === 0,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export const buildReconciledApplicationGraph = (
|
|||
: []),
|
||||
...(facts.outputTruncated
|
||||
? [
|
||||
"The reconciled graph omitted entities or classifications at caller limits.",
|
||||
"The reconciled graph omitted entities or classifications during projection.",
|
||||
]
|
||||
: []),
|
||||
]),
|
||||
|
|
|
|||
|
|
@ -27,24 +27,21 @@ export const reconcileRuntimeEntities = (input: {
|
|||
readonly entities: readonly RuntimeReconciliationEntity[];
|
||||
readonly candidates: readonly StaticRuntimeCandidate[];
|
||||
readonly layers: readonly ParsedStaticLayer[];
|
||||
readonly maximumItems: number;
|
||||
}): RuntimeMatchingProjection => {
|
||||
const index = indexCandidates(input.candidates);
|
||||
const evaluated = input.entities.map((entity) =>
|
||||
reconcileEntity(entity, index, input.layers),
|
||||
);
|
||||
const retained = evaluated
|
||||
.sort((left, right) =>
|
||||
compareCodePoints(
|
||||
left.item.reconciliation_id,
|
||||
right.item.reconciliation_id,
|
||||
),
|
||||
)
|
||||
.slice(0, input.maximumItems);
|
||||
const retained = evaluated.sort((left, right) =>
|
||||
compareCodePoints(
|
||||
left.item.reconciliation_id,
|
||||
right.item.reconciliation_id,
|
||||
),
|
||||
);
|
||||
return {
|
||||
items: retained.map(({ item }) => item),
|
||||
edges: retained.flatMap(({ edge }) => (edge === null ? [] : [edge])),
|
||||
omittedItems: evaluated.length - retained.length,
|
||||
omittedItems: 0,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -419,11 +416,10 @@ const uniqueCandidateReferences = (
|
|||
if (seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
count += 1;
|
||||
if (items.length < 1_000)
|
||||
items.push({
|
||||
static_layer_id: layer.layerId,
|
||||
static_node_id: node.node_id,
|
||||
});
|
||||
items.push({
|
||||
static_layer_id: layer.layerId,
|
||||
static_node_id: node.node_id,
|
||||
});
|
||||
}
|
||||
return { count, items };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ const reconciliationLimitations = (completion: CompletionFlags): string[] =>
|
|||
: []),
|
||||
...(completion.outputTruncated
|
||||
? [
|
||||
"Caller limits omitted runtime entities or reconciliation classifications.",
|
||||
"Runtime reconciliation omitted entities or classifications during projection.",
|
||||
]
|
||||
: []),
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -31,16 +31,9 @@ export interface RuntimeProjection {
|
|||
/** Project authorized passive capture metadata into capture-scoped JAG nodes. */
|
||||
export const projectRuntimeCaptures = (
|
||||
captures: readonly ParsedRuntimeCapture[],
|
||||
maximumEntities: number,
|
||||
): RuntimeProjection => {
|
||||
if (maximumEntities < captures.length)
|
||||
throw new TypeError(
|
||||
"Runtime entity limit must admit one target for every capture",
|
||||
);
|
||||
const all = captures.flatMap(projectCapture);
|
||||
const targets = all.filter(({ kind }) => kind === "target");
|
||||
const nonTargets = all.filter(({ kind }) => kind !== "target");
|
||||
const retained = [...targets, ...nonTargets].slice(0, maximumEntities);
|
||||
const retained = all;
|
||||
const retainedIds = new Set(retained.map(({ node }) => node.node_id));
|
||||
const nodes = retained.map(({ node }) => node);
|
||||
const edges = captures
|
||||
|
|
@ -59,7 +52,7 @@ export const projectRuntimeCaptures = (
|
|||
nodes,
|
||||
edges,
|
||||
targetNodeByEvidenceId,
|
||||
omittedEntities: all.length - retained.length,
|
||||
omittedEntities: 0,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@ const staticLayerSchema = z.strictObject({
|
|||
analysis: evidenceSchema,
|
||||
runtime_mappings: z
|
||||
.array(runtimeLocationMappingSchema)
|
||||
.max(32)
|
||||
.overwrite(normalizeRuntimeMappings)
|
||||
.default([]),
|
||||
});
|
||||
|
|
@ -103,22 +102,11 @@ function runtimeMappingKey(mapping: RuntimeLocationMapping): string {
|
|||
: `url-prefix\0${mapping.prefix}\0${mapping.artifact_prefix}`;
|
||||
}
|
||||
|
||||
const reconciliationLimitsSchema = z.strictObject({
|
||||
max_runtime_entities: z.number().int().min(1).max(50_000).default(10_000),
|
||||
max_reconciliation_items: z.number().int().min(1).max(50_000).default(20_000),
|
||||
max_static_load_states: z.number().int().min(1).max(50_000).default(20_000),
|
||||
});
|
||||
|
||||
/** Evidence-backed static layers and passive captures to reconcile. */
|
||||
export const reconcileJavaScriptRuntimeInputSchema = z
|
||||
.strictObject({
|
||||
static_layers: z.array(staticLayerSchema).min(1).max(8),
|
||||
runtime_observations: z.array(evidenceSchema).min(1).max(32),
|
||||
limits: reconciliationLimitsSchema.default({
|
||||
max_runtime_entities: 10_000,
|
||||
max_reconciliation_items: 20_000,
|
||||
max_static_load_states: 20_000,
|
||||
}),
|
||||
static_layers: z.array(staticLayerSchema).min(1),
|
||||
runtime_observations: z.array(evidenceSchema).min(1),
|
||||
})
|
||||
.superRefine((input, context) => {
|
||||
if (
|
||||
|
|
@ -148,12 +136,6 @@ export const reconcileJavaScriptRuntimeInputSchema = z
|
|||
path: ["runtime_observations"],
|
||||
message: "Runtime observation Evidence must be unique",
|
||||
});
|
||||
if (input.limits.max_runtime_entities < input.runtime_observations.length)
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: ["limits", "max_runtime_entities"],
|
||||
message: "Runtime entity limit must retain one target per observation",
|
||||
});
|
||||
});
|
||||
|
||||
const layerSummarySchema = z.strictObject({
|
||||
|
|
@ -164,7 +146,7 @@ const layerSummarySchema = z.strictObject({
|
|||
root_artifact_sha256: digestSchema,
|
||||
input_path: z.string().min(1).max(16_384),
|
||||
format: z.enum(["asar", "directory"]),
|
||||
runtime_mappings: z.array(runtimeLocationMappingSchema).max(32),
|
||||
runtime_mappings: z.array(runtimeLocationMappingSchema),
|
||||
});
|
||||
|
||||
const captureSummarySchema = z.strictObject({
|
||||
|
|
@ -209,15 +191,13 @@ const reconciliationItemShape = {
|
|||
]),
|
||||
confidence: z.enum(["exact", "high", "medium", "low", "unknown"]),
|
||||
reason: reconciliationReasonSchema,
|
||||
candidate_static_count: z.number().int().min(0).max(800_000),
|
||||
candidate_static_nodes: z
|
||||
.array(
|
||||
z.strictObject({
|
||||
static_layer_id: z.string().regex(/^jrl_[a-f0-9]{64}$/u),
|
||||
static_node_id: nodeIdSchema,
|
||||
}),
|
||||
)
|
||||
.max(1_000),
|
||||
candidate_static_count: z.number().int().min(0),
|
||||
candidate_static_nodes: z.array(
|
||||
z.strictObject({
|
||||
static_layer_id: z.string().regex(/^jrl_[a-f0-9]{64}$/u),
|
||||
static_node_id: nodeIdSchema,
|
||||
}),
|
||||
),
|
||||
};
|
||||
const reconciliationItemSchema = z.union([
|
||||
z.strictObject({
|
||||
|
|
@ -244,7 +224,7 @@ const staticLoadStateSchema = z.strictObject({
|
|||
"not-observed-in-capture",
|
||||
"unknown",
|
||||
]),
|
||||
runtime_node_ids: z.array(nodeIdSchema).max(10_000),
|
||||
runtime_node_ids: z.array(nodeIdSchema),
|
||||
reason: z.enum([
|
||||
"runtime-script-correspondence",
|
||||
"containing-asset-was-loaded",
|
||||
|
|
@ -257,8 +237,8 @@ const staticLoadStateSchema = z.strictObject({
|
|||
/** Deterministic static/passive-runtime reconciliation with a combined JAG. */
|
||||
export const javascriptRuntimeReconciliationResultSchema = z.strictObject({
|
||||
reconciliation_id: z.string().regex(/^jrr_[a-f0-9]{64}$/u),
|
||||
static_layers: z.array(layerSummarySchema).min(1).max(8),
|
||||
runtime_captures: z.array(captureSummarySchema).min(1).max(32),
|
||||
static_layers: z.array(layerSummarySchema).min(1),
|
||||
runtime_captures: z.array(captureSummarySchema).min(1),
|
||||
graph: javascriptApplicationGraphSchema,
|
||||
summary: z.strictObject({
|
||||
runtime_targets: z.number().int().min(0),
|
||||
|
|
@ -274,8 +254,8 @@ export const javascriptRuntimeReconciliationResultSchema = z.strictObject({
|
|||
static_not_observed: z.number().int().min(0),
|
||||
static_unknown: z.number().int().min(0),
|
||||
}),
|
||||
reconciliations: z.array(reconciliationItemSchema).max(50_000),
|
||||
static_load_states: z.array(staticLoadStateSchema).max(50_000),
|
||||
reconciliations: z.array(reconciliationItemSchema),
|
||||
static_load_states: z.array(staticLoadStateSchema),
|
||||
source_map_authority: z.strictObject({
|
||||
used_for_primary_matching: z.literal(false),
|
||||
static_layer_count: z.number().int().min(0),
|
||||
|
|
@ -290,8 +270,8 @@ export const javascriptRuntimeReconciliationResultSchema = z.strictObject({
|
|||
omitted_static_load_states: z.number().int().min(0),
|
||||
omitted_graph_items: z.number().int().min(0),
|
||||
}),
|
||||
evidence_links: z.array(evidenceIdSchema).min(2).max(40),
|
||||
limitations: z.array(boundedTextSchema).max(1_000),
|
||||
evidence_links: z.array(evidenceIdSchema).min(2),
|
||||
limitations: z.array(boundedTextSchema),
|
||||
});
|
||||
|
||||
export type ReconcileJavaScriptRuntimeInput = z.infer<
|
||||
|
|
|
|||
|
|
@ -118,9 +118,6 @@ export const sourceToBundleComparisonResultSchema = z.strictObject({
|
|||
limitations: z.array(boundedTextSchema).max(1_000),
|
||||
});
|
||||
|
||||
export type CompareSourceToBundleInput = z.infer<
|
||||
typeof compareSourceToBundleInputSchema
|
||||
>;
|
||||
export type SourceToBundleComparisonResult = z.infer<
|
||||
typeof sourceToBundleComparisonResultSchema
|
||||
>;
|
||||
|
|
|
|||
|
|
@ -205,7 +205,42 @@ describe("JavaScript export return-shape selection", () => {
|
|||
});
|
||||
|
||||
describe("JavaScript export return-shape projection", () => {
|
||||
it("marks graph field projection omissions as truncated", async () => {
|
||||
it("retains more than 64 inferred return fields", async () => {
|
||||
const properties = Array.from(
|
||||
{ length: 70 },
|
||||
(_, index) => `field${String(index)}: ${String(index)}`,
|
||||
).join(",");
|
||||
const root = await temporaryRoot();
|
||||
await writeFile(
|
||||
join(root, "parser.mjs"),
|
||||
`export const parse = () => ({ ${properties} });`,
|
||||
);
|
||||
const analyzed = await analyzeGraph(root);
|
||||
const returnShape = analyzed.graph.nodes
|
||||
.flatMap(({ observations }) => observations)
|
||||
.find(
|
||||
({ properties: value }) =>
|
||||
value.semantic_role === "export-return-shapes",
|
||||
);
|
||||
|
||||
const shapes = returnShape?.properties.static_return_shapes;
|
||||
expect(Array.isArray(shapes)).toBe(true);
|
||||
if (!Array.isArray(shapes)) throw new TypeError("Missing return shapes");
|
||||
const firstShape = shapes[0];
|
||||
if (
|
||||
firstShape === null ||
|
||||
typeof firstShape !== "object" ||
|
||||
Array.isArray(firstShape)
|
||||
)
|
||||
throw new TypeError("Missing first return shape");
|
||||
expect(firstShape.fields).toHaveLength(70);
|
||||
expect(returnShape?.properties.return_shape_coverage).toMatchObject({
|
||||
omitted_fields: 0,
|
||||
projection_complete: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps incomplete source property coverage partial", async () => {
|
||||
const properties = [
|
||||
'a_type: "item"',
|
||||
...Array.from(
|
||||
|
|
@ -219,9 +254,9 @@ describe("JavaScript export return-shape projection", () => {
|
|||
});
|
||||
const result = compare(left, right);
|
||||
|
||||
expect(result.coverage.status).toBe("truncated");
|
||||
expect(result.coverage.left_omitted_fields).toBeGreaterThan(0);
|
||||
expect(result.coverage.right_omitted_fields).toBeGreaterThan(0);
|
||||
expect(result.coverage.status).toBe("partial");
|
||||
expect(result.coverage.left_omitted_fields).toBe(0);
|
||||
expect(result.coverage.right_omitted_fields).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ it("keeps byte-identical cross-layer candidates explicitly ambiguous", async ()
|
|||
).toBe(2);
|
||||
});
|
||||
|
||||
it("retains one target per capture and keeps load-state absence unknown when output is bounded", async () => {
|
||||
it("retains all runtime entities and static load states without projection caps", async () => {
|
||||
const fixture = await applicationFixture();
|
||||
temporary.push(fixture);
|
||||
const staticEvidence = await analyzeFixture(fixture);
|
||||
|
|
@ -85,11 +85,6 @@ it("retains one target per capture and keeps load-state absence unknown when out
|
|||
const result = reconcileJavaScriptRuntime({
|
||||
static_layers: [{ role: "application", analysis: staticEvidence }],
|
||||
runtime_observations: runtimeObservations,
|
||||
limits: {
|
||||
max_runtime_entities: 2,
|
||||
max_reconciliation_items: 2,
|
||||
max_static_load_states: 20_000,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.runtime_captures).toHaveLength(2);
|
||||
|
|
@ -98,19 +93,22 @@ it("retains one target per capture and keeps load-state absence unknown when out
|
|||
).toBe(2);
|
||||
expect(result.summary).toMatchObject({
|
||||
runtime_targets: 2,
|
||||
runtime_frames: 0,
|
||||
runtime_scripts: 0,
|
||||
runtime_frames: 2,
|
||||
runtime_scripts: 2,
|
||||
runtime_workers: 0,
|
||||
static_not_observed: 0,
|
||||
static_not_observed: 2,
|
||||
});
|
||||
expect(result.coverage).toMatchObject({
|
||||
status: "truncated",
|
||||
truncated: true,
|
||||
omitted_runtime_entities: 4,
|
||||
omitted_runtime_entities: 0,
|
||||
omitted_reconciliation_items: 0,
|
||||
omitted_static_load_states: 0,
|
||||
});
|
||||
expect(
|
||||
result.static_load_states.every(({ status }) => status === "unknown"),
|
||||
).toBe(true);
|
||||
expect(result.static_load_states).toHaveLength(
|
||||
result.summary.static_loaded +
|
||||
result.summary.static_resident +
|
||||
result.summary.static_not_observed +
|
||||
result.summary.static_unknown,
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects runtime source bytes whose Evidence omits source-capture approval", async () => {
|
||||
|
|
@ -233,15 +231,6 @@ const electronRuntimeEvidence = (
|
|||
target_id: targetId,
|
||||
observation_ms: 100,
|
||||
include_script_sources: sourceIncluded,
|
||||
limits: {
|
||||
max_frames: 200,
|
||||
max_dom_nodes: 2_000,
|
||||
max_scripts: 500,
|
||||
max_resources: 2_000,
|
||||
max_workers: 500,
|
||||
max_script_source_bytes: 1_048_576,
|
||||
max_total_script_source_bytes: 4_194_304,
|
||||
},
|
||||
});
|
||||
return createElectronEvidence(
|
||||
"inspect_electron_page",
|
||||
|
|
|
|||
|
|
@ -354,15 +354,6 @@ const electronRuntimeEvidence = (
|
|||
target_id: targetId,
|
||||
observation_ms: 100,
|
||||
include_script_sources: sourceIncluded,
|
||||
limits: {
|
||||
max_frames: 200,
|
||||
max_dom_nodes: 2_000,
|
||||
max_scripts: 500,
|
||||
max_resources: 2_000,
|
||||
max_workers: 500,
|
||||
max_script_source_bytes: 1_048_576,
|
||||
max_total_script_source_bytes: 4_194_304,
|
||||
},
|
||||
});
|
||||
return createElectronEvidence(
|
||||
"inspect_electron_page",
|
||||
|
|
|
|||
Loading…
Reference in New Issue