[GH-ISSUE #2576] fix(javascript-semantic-graph): complete coverage accepts an unresolved frontier #894

Closed
opened 2026-10-15 18:29:21 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @coygeek on GitHub (Oct 13, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2576

Summary

Creating and validating a JavaScript semantic relation graph accepts a retained unresolved call frontier while both the graph and its call-flow family claim complete coverage. The trigger is an empty family unknown-ID list even though the graph still contains an unknown belonging to that family. The validated result gives consumers contradictory completeness metadata; rejection already occurs for the same complete graph when the unknown's ID is included in the family list.

Steps to reproduce

  1. Use the source revision and installed locked dependencies stated under Runtime or environment.
  2. Add src/domain/javascript/semanticCoverageIntegrity.probe.test.ts with the following observation test. It uses the repository's existing fixture containing one unresolved dynamic call and changes only coverage metadata and graph limitations.
import { expect, it } from "vitest";
import {
  createJavaScriptSemanticGraph,
  javaScriptSemanticGraphSchema,
} from "./javascriptSemanticGraph.js";
import { semanticFixtureInput } from "../../../tests/support/javascriptSemanticGraphFixture.js";

it("observes accepted complete coverage with an unresolved call", () => {
  const input = semanticFixtureInput(true);
  const graph = createJavaScriptSemanticGraph({
    ...input,
    coverage: {
      ...input.coverage,
      status: "complete" as const,
      omitted_nodes: 0,
      omitted_relations: 0,
      families: input.coverage.families.map((family) =>
        family.family === "call-flow"
          ? {
              ...family,
              status: "complete" as const,
              omitted_relations: 0,
              unknown_ids: [],
            }
          : family,
      ),
    },
    limitations: [],
  });
  const family = graph.coverage.families.find(
    (entry) => entry.family === "call-flow",
  )!;
  const parsed = javaScriptSemanticGraphSchema.safeParse(graph);
  const wireParsed = javaScriptSemanticGraphSchema.safeParse(
    JSON.parse(JSON.stringify(graph)),
  );
  console.log("OBSERVATION", JSON.stringify({
    graph_status: graph.coverage.status,
    family_status: family.status,
    unknown_ids: family.unknown_ids,
    unknown_count: graph.unknowns.length,
    unknown_family: graph.unknowns[0]?.family,
    factory_schema_success: parsed.success,
    wire_schema_success: wireParsed.success,
  }));
  expect(graph.unknowns).toHaveLength(1);
  expect(family.status).toBe("complete");
  expect(family.unknown_ids).toEqual([]);
  expect(parsed.success).toBe(true);
  expect(wireParsed.success).toBe(true);
});
  1. Run the exact focused test from the repository root:
npm run test:focused -- src/domain/javascript/semanticCoverageIntegrity.probe.test.ts
  1. Observe successful construction and validation together with complete graph/family coverage and one retained call-flow unknown. These assertions describe the current incorrect acceptance rather than a passing restoration condition. Remove the observation test after inspection.

Expected behavior

A complete semantic relation family cannot retain unresolved facts belonging to that family. A graph containing an unresolved dynamic call must not pass graph creation and validation while its call-flow family claims complete coverage, regardless of whether the caller lists the retained unknown's ID. The original fixture's partial graph coverage and unknown call-flow coverage correctly represent this uncertainty and should continue to validate.

Actual behavior

The factory returned a graph containing one unresolved call-flow frontier, with graph coverage complete, call-flow coverage complete, and an empty family unknown-ID list. The public schema accepted both that graph and its JSON round-trip. A focused local probe observed this acceptance and passed two discriminating controls: the original partial fixture validated, and the same complete input with the unknown ID restored to the family list was rejected.

Evidence

  • Expected source: src/domain/javascript/javascriptSemanticGraph.ts:330-337 enforces that complete family coverage cannot omit or retain unknown facts; lines 282-292 require complete families for complete graph coverage. These integrity checks apply to the graph factory and public schema.
  • Failure source: src/domain/javascript/javascriptSemanticGraph.ts:308-329 checks only unknown IDs listed by each coverage family, and src/domain/javascript/javascriptSemanticGraph.ts:584-601 checks only that listed IDs exist. Local execution through the factory and schema accepted the retained but unlisted call-flow unknown.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

The observation output was:

OBSERVATION {"graph_status":"complete","family_status":"complete","unknown_ids":[],"unknown_count":1,"unknown_family":"call-flow","factory_schema_success":true,"wire_schema_success":true}

The listed-unknown control was rejected with Complete family coverage cannot omit or retain unknown facts. All three focused verification cases passed, with exit status 0. The evidence establishes contradictory accepted coverage metadata; it does not establish that the normal extractor produces this input or that a downstream comparison reports false additions or removals.

Related reports cover different boundaries: https://github.com/morluto/rea/issues/796 concerns preservation of structural unknown nodes during reconstruction-obligation generation, and https://github.com/morluto/rea/issues/1831 concerns extraction of namespace re-exports. Their fixes do not address semantic graph coverage validation.

Restoration check

The inconsistent complete input must be rejected by graph construction and public record validation even when its retained unknown is absent from the family's unknown-ID list. The same input with that ID listed must remain rejected. As controls, the original partial fixture with its listed unknown must continue to validate, and a complete fixture with no unknowns must continue to validate. Validate a serialized graph record as well as factory input so the result does not depend solely on factory normalization.

Runtime or environment

Failure verified at a2d8b94dd5 and still present at 8b181716ac. Verified with Node.js v26.10.0, npm 11.19.1, Vitest 5.0.3, and the repository's installed locked dependencies. The probe used source-level domain entry points; no CLI/MCP extraction run was performed.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A bounded graph input passes the semantic integrity boundary with a false complete-family claim despite retaining an unresolved member. Consumers of validated coverage metadata receive inconsistent information. No data loss, security effect, normal-extractor occurrence, or core workflow failure was established.
  • Workaround status: available
  • Workaround basis: Callers constructing this graph can retain the original fixture's partial graph coverage, unknown call-flow status, and listed unknown ID; that representation validated in the control. This workaround avoids creating the contradictory graph but does not repair validation of incoming inconsistent records.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2576 ## Summary Creating and validating a JavaScript semantic relation graph accepts a retained unresolved call frontier while both the graph and its call-flow family claim complete coverage. The trigger is an empty family unknown-ID list even though the graph still contains an unknown belonging to that family. The validated result gives consumers contradictory completeness metadata; rejection already occurs for the same complete graph when the unknown's ID is included in the family list. ## Steps to reproduce 1. Use the source revision and installed locked dependencies stated under Runtime or environment. 2. Add `src/domain/javascript/semanticCoverageIntegrity.probe.test.ts` with the following observation test. It uses the repository's existing fixture containing one unresolved dynamic call and changes only coverage metadata and graph limitations. ```ts import { expect, it } from "vitest"; import { createJavaScriptSemanticGraph, javaScriptSemanticGraphSchema, } from "./javascriptSemanticGraph.js"; import { semanticFixtureInput } from "../../../tests/support/javascriptSemanticGraphFixture.js"; it("observes accepted complete coverage with an unresolved call", () => { const input = semanticFixtureInput(true); const graph = createJavaScriptSemanticGraph({ ...input, coverage: { ...input.coverage, status: "complete" as const, omitted_nodes: 0, omitted_relations: 0, families: input.coverage.families.map((family) => family.family === "call-flow" ? { ...family, status: "complete" as const, omitted_relations: 0, unknown_ids: [], } : family, ), }, limitations: [], }); const family = graph.coverage.families.find( (entry) => entry.family === "call-flow", )!; const parsed = javaScriptSemanticGraphSchema.safeParse(graph); const wireParsed = javaScriptSemanticGraphSchema.safeParse( JSON.parse(JSON.stringify(graph)), ); console.log("OBSERVATION", JSON.stringify({ graph_status: graph.coverage.status, family_status: family.status, unknown_ids: family.unknown_ids, unknown_count: graph.unknowns.length, unknown_family: graph.unknowns[0]?.family, factory_schema_success: parsed.success, wire_schema_success: wireParsed.success, })); expect(graph.unknowns).toHaveLength(1); expect(family.status).toBe("complete"); expect(family.unknown_ids).toEqual([]); expect(parsed.success).toBe(true); expect(wireParsed.success).toBe(true); }); ``` 3. Run the exact focused test from the repository root: ```sh npm run test:focused -- src/domain/javascript/semanticCoverageIntegrity.probe.test.ts ``` 4. Observe successful construction and validation together with complete graph/family coverage and one retained call-flow unknown. These assertions describe the current incorrect acceptance rather than a passing restoration condition. Remove the observation test after inspection. ## Expected behavior A complete semantic relation family cannot retain unresolved facts belonging to that family. A graph containing an unresolved dynamic call must not pass graph creation and validation while its call-flow family claims complete coverage, regardless of whether the caller lists the retained unknown's ID. The original fixture's partial graph coverage and unknown call-flow coverage correctly represent this uncertainty and should continue to validate. ## Actual behavior The factory returned a graph containing one unresolved call-flow frontier, with graph coverage complete, call-flow coverage complete, and an empty family unknown-ID list. The public schema accepted both that graph and its JSON round-trip. A focused local probe observed this acceptance and passed two discriminating controls: the original partial fixture validated, and the same complete input with the unknown ID restored to the family list was rejected. ## Evidence - Expected source: `src/domain/javascript/javascriptSemanticGraph.ts:330-337` enforces that complete family coverage cannot omit or retain unknown facts; lines 282-292 require complete families for complete graph coverage. These integrity checks apply to the graph factory and public schema. - Failure source: `src/domain/javascript/javascriptSemanticGraph.ts:308-329` checks only unknown IDs listed by each coverage family, and `src/domain/javascript/javascriptSemanticGraph.ts:584-601` checks only that listed IDs exist. Local execution through the factory and schema accepted the retained but unlisted call-flow unknown. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete The observation output was: ```text OBSERVATION {"graph_status":"complete","family_status":"complete","unknown_ids":[],"unknown_count":1,"unknown_family":"call-flow","factory_schema_success":true,"wire_schema_success":true} ``` The listed-unknown control was rejected with `Complete family coverage cannot omit or retain unknown facts`. All three focused verification cases passed, with exit status 0. The evidence establishes contradictory accepted coverage metadata; it does not establish that the normal extractor produces this input or that a downstream comparison reports false additions or removals. Related reports cover different boundaries: https://github.com/morluto/rea/issues/796 concerns preservation of structural unknown nodes during reconstruction-obligation generation, and https://github.com/morluto/rea/issues/1831 concerns extraction of namespace re-exports. Their fixes do not address semantic graph coverage validation. ## Restoration check The inconsistent complete input must be rejected by graph construction and public record validation even when its retained unknown is absent from the family's unknown-ID list. The same input with that ID listed must remain rejected. As controls, the original partial fixture with its listed unknown must continue to validate, and a complete fixture with no unknowns must continue to validate. Validate a serialized graph record as well as factory input so the result does not depend solely on factory normalization. ## Runtime or environment Failure verified at a2d8b94dd50dab8d966239dd63ab84718aa8b4b4 and still present at 8b181716aca2cb467be499cba226abfb5ae19141. Verified with Node.js v26.10.0, npm 11.19.1, Vitest 5.0.3, and the repository's installed locked dependencies. The probe used source-level domain entry points; no CLI/MCP extraction run was performed. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: A bounded graph input passes the semantic integrity boundary with a false complete-family claim despite retaining an unresolved member. Consumers of validated coverage metadata receive inconsistent information. No data loss, security effect, normal-extractor occurrence, or core workflow failure was established. - Workaround status: available - Workaround basis: Callers constructing this graph can retain the original fixture's partial graph coverage, unknown call-flow status, and listed unknown ID; that representation validated in the control. This workaround avoids creating the contradictory graph but does not repair validation of incoming inconsistent records.
bsakaguchi 2026-10-15 18:29:21 +00:00
Author
Owner

@morluto commented on GitHub (Oct 14, 2026):

Addressed on main in 896696b2e761e34c267977bb5c6982c607a622d0.

A complete semantic coverage family is rejected when a retained unresolved frontier of that family exists, including unlisted frontiers.

Validation: Affected suites passed in the merged 65-file run (1169 passed, 2 explicit skips), with full static/architecture checks and documentation checks passing. Final installed-package verification is recorded separately in the audit.

Verification scope: Controlled source and production-boundary verification on macOS with pinned Node 24.18.0; real external engines and Windows hosts were not independently rerun. Closure covers the described source defect, not broader provider conformance or performance.

<!-- gh-comment-id:6159191788 --> @morluto commented on GitHub (Oct 14, 2026): Addressed on main in [896696b2e761e34c267977bb5c6982c607a622d0](https://github.com/morluto/rea/commit/896696b2e761e34c267977bb5c6982c607a622d0). A complete semantic coverage family is rejected when a retained unresolved frontier of that family exists, including unlisted frontiers. Validation: Affected suites passed in the merged 65-file run (1169 passed, 2 explicit skips), with full static/architecture checks and documentation checks passing. Final installed-package verification is recorded separately in the audit. Verification scope: Controlled source and production-boundary verification on macOS with pinned Node 24.18.0; real external engines and Windows hosts were not independently rerun. Closure covers the described source defect, not broader provider conformance or performance.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#894
No description provided.