feat(javascript): report observed export property presence (#1160)

* feat(javascript): report observed export property presence

Extend compare_javascript_export_shapes so each retained return variant
lists observed property names and each change reports presence independently
of value resolution. Complete parent coverage classifies one-sided names as
added or removed even when static values stay unknown.

Fixes #725

* test(javascript): match unknown export-shape values by availability

Nested availability objects include a reason when values stay unresolved.
Assert availability through objectContaining so presence-only added and
removed rows still verify unknown values.

* fix(javascript): preserve uncertain export property presence and locations

* fix(javascript): normalize presence and preserve local property coverage

* fix(javascript): require present discriminants for return pairing

* fix(javascript): normalize retained shapes before comparison

* refactor(javascript): share return projection with executable examples

* fix(javascript): localize uncertainty for missing mutated slots

* fix(javascript): bind advertised export examples to exact artifacts

* fix(javascript): keep uncertain property flow as candidates

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
This commit is contained in:
Matt Van Hornandmorluto authored and GitHub committed 2026-10-09 18:30:31 +08:00
1 parent 04aef6df33
commit 45e3edc17f
25 files changed
+1552 -113

No files matched your search

@@ -1,6 +1,9 @@
import { expect, it } from "vitest";
import { projectedExportReturnShapesSchema } from "./javascriptExportShapeComparisonSchemas.js";
import {
javaScriptExportShapeComparisonChangeSchema,
projectedExportReturnShapesSchema,
} from "./javascriptExportShapeComparisonSchemas.js";
const projectionWithField = (field: unknown) => ({
semantic_role: "export-return-shapes",
@@ -29,6 +32,40 @@ const projectionWithField = (field: unknown) => ({
},
});
it("rejects a comparison change object missing presence", () => {
const digest = "a".repeat(64);
const change = {
change_id: `jesc_change_${digest}`,
status: "added",
path: "/total",
discriminant: { path: "/kind", value: "results" },
left: { availability: "absent" },
right: {
availability: "unknown",
reason: "Static field value is unknown.",
},
left_source_range: {
start: { line: 4, column: 9 },
end: { line: 4, column: 48 },
},
right_source_range: {
start: { line: 4, column: 9 },
end: { line: 4, column: 62 },
},
evidence_links: [`ev_${digest}`, `ev_${"b".repeat(64)}`],
limitations: [],
};
expect(
javaScriptExportShapeComparisonChangeSchema.safeParse(change).success,
).toBe(false);
expect(
javaScriptExportShapeComparisonChangeSchema.safeParse({
...change,
presence: { left: "absent", right: "present" },
}).success,
).toBe(true);
});
it("parses projected fields into literal, union, or unknown values", () => {
expect(
projectedExportReturnShapesSchema.safeParse(