perf(domain): order JSON shapes through their structural tree

Traverse sorted siblings instead of comparing complete shared path prefixes. Return the typed producer result directly while preserving independent path segments and schema validation at unknown-input boundaries.

Validation: 12 domain/CDP boundary tests, build, and check:fast passed. Six paired Flameox blocks retained identical full-output digests across deep, mixed, Unicode, and wide controls. Depth-512 inference median fell from 10.78 ms to 1.51 ms (120 samples per variant); whole harness median fell from 518.6 ms to 327.5 ms.

Flameox evidence: f4a93424f34e5bfea254ada4ef278dc9bbb6c21047c977e20da130e11a8899e9. Timings describe this bounded workload only.
This commit is contained in:
morluto
2026-10-11 09:30:05 +08:00
parent 026126eafe
commit 31bfff6fdf
2 changed files with 65 additions and 29 deletions
+35 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { inferJsonShape } from "./jsonShape.js";
import { inferJsonShape, jsonShapeSchema } from "./jsonShape.js";
const property = (name: string) => ({ kind: "property" as const, name });
const element = { kind: "array-element" as const };
@@ -68,6 +68,40 @@ describe("inferJsonShape", () => {
it("rejects malformed JSON", () => {
expect(inferJsonShape("not-json")).toBeNull();
});
it("orders mixed array and property descendants with parents first", () => {
const shape = inferJsonShape('[{"z":1,"a":{"x":true}},[null],{"a":2}]');
expect(shape?.properties.map(({ path }) => path)).toEqual([
[element],
[element, element],
[element, property("a")],
[element, property("a"), property("x")],
[element, property("z")],
]);
expect(shape?.properties[2]).toMatchObject({
types: ["number", "object"],
observations: 2,
});
});
it("retains deep coverage and independently owned path segments", () => {
const depth = 512;
const shape = inferJsonShape("[".repeat(depth) + "1" + "]".repeat(depth));
expect(shape).not.toBeNull();
if (shape === null) return;
expect(shape.node_count).toBe(depth + 1);
expect(shape.max_depth_observed).toBe(depth);
expect(shape.properties).toHaveLength(depth);
expect(shape.properties.at(-1)).toEqual({
path: Array.from({ length: depth }, () => element),
types: ["number"],
observations: 1,
});
expect(jsonShapeSchema.parse(shape)).toEqual(shape);
expect(shape.properties[0]?.path[0]).not.toBe(shape.properties[1]?.path[0]);
});
});
describe("JSON shape completeness and ordering", () => {
+30 -28
View File
@@ -52,7 +52,6 @@ export const inferJsonShape = (text: string): JsonShape | null => {
void cause;
return null;
}
const properties: ShapeNode[] = [];
const rootShape: ShapeNode = {
path: [],
types: new Set(),
@@ -77,7 +76,6 @@ export const inferJsonShape = (text: string): JsonShape | null => {
observations: 0,
};
children.set(key, node);
properties.push(node);
return node;
};
const pending: Array<{
@@ -109,18 +107,26 @@ export const inferJsonShape = (text: string): JsonShape | null => {
pending.push({ value, shape: childShape(current.shape, name) });
}
}
return jsonShapeSchema.parse({
// Preorder over sorted siblings gives canonical paths without repeatedly
// comparing their shared prefixes. Each returned path owns its segments.
const properties: JsonShape["properties"] = [];
const shapes = orderedChildren(rootShape);
while (shapes.length > 0) {
const shape = shapes.pop();
if (shape === undefined) break;
properties.push({
path: shape.path.map((segment) => ({ ...segment })),
types: [...shape.types].sort(),
observations: shape.observations,
});
for (const child of orderedChildren(shape)) shapes.push(child);
}
return {
root_type: jsonValueType(root),
node_count: nodeCount,
max_depth_observed: maxDepthObserved,
properties: properties
.map((value) => ({
path: value.path,
types: [...value.types].sort(),
observations: value.observations,
}))
.sort((left, right) => compareShapePaths(left.path, right.path)),
});
properties,
};
};
const jsonValueType = (value: unknown): JsonValueType => {
@@ -141,20 +147,16 @@ const jsonValueType = (value: unknown): JsonValueType => {
const isRecord = (value: unknown): value is Readonly<Record<string, unknown>> =>
typeof value === "object" && value !== null && !Array.isArray(value);
const compareShapePaths = (
left: readonly JsonShapePathSegment[],
right: readonly JsonShapePathSegment[],
): number => {
for (let index = 0; index < Math.min(left.length, right.length); index += 1) {
const a = left[index];
const b = right[index];
if (a === undefined || b === undefined) break;
const order =
compareUnicodeCodePoints(a.kind, b.kind) ||
(a.kind === "property" && b.kind === "property"
? compareUnicodeCodePoints(a.name, b.name)
: 0);
if (order !== 0) return order;
}
return left.length - right.length;
};
/** Reverse sibling order for the traversal stack; array elements sort first. */
const orderedChildren = (node: ShapeNode): ShapeNode[] =>
[...(node.children ?? [])]
.sort(([left], [right]) =>
left === right
? 0
: left === arrayElementKey
? 1
: right === arrayElementKey
? -1
: compareUnicodeCodePoints(right, left),
)
.map(([, child]) => child);