diff --git a/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts b/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts index d81759bdf..2c29f24c5 100644 --- a/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts +++ b/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts @@ -66,6 +66,42 @@ describe("schema validation", () => { expect(result.issues).toEqual([]); }); + it.each([ + ["codebase", "codebase"], + ["knowledge", "knowledge"], + ["bogus", undefined], + [undefined, undefined], + ] as const)("carries kind=%j through validation as %j", (input, expected) => { + const graph = structuredClone(validGraph); + if (input === undefined) { + delete (graph as any).kind; + } else { + (graph as any).kind = input; + } + + const result = validateGraph(graph); + expect(result.success).toBe(true); + expect(result.data!.kind).toBe(expected); + }); + + it("emits an auto-corrected issue when kind is out of enum", () => { + const graph = structuredClone(validGraph); + (graph as any).kind = "bogus"; + + const result = validateGraph(graph); + expect(result.success).toBe(true); + expect(result.data!.kind).toBeUndefined(); + expect(result.issues).toContainEqual( + expect.objectContaining({ level: "auto-corrected", category: "out-of-range", path: "kind" }) + ); + }); + + it("does not emit a kind issue when kind is omitted", () => { + const result = validateGraph(validGraph); + expect(result.success).toBe(true); + expect(result.issues).toEqual([]); + }); + it("rejects graph with missing required fields", () => { const incomplete = { version: "1.0.0" }; const result = validateGraph(incomplete); diff --git a/understand-anything-plugin/packages/core/src/schema.ts b/understand-anything-plugin/packages/core/src/schema.ts index 71b9cd8ab..8134bf693 100644 --- a/understand-anything-plugin/packages/core/src/schema.ts +++ b/understand-anything-plugin/packages/core/src/schema.ts @@ -650,8 +650,24 @@ export function validateGraph(data: unknown): ValidationResult { } } + // Preserve a valid `kind` enum value; an out-of-enum value is dropped with + // an auto-corrected issue so a typo / stale extractor value is surfaced + // rather than silently narrowed to undefined. + const validKind = fixed.kind === "codebase" || fixed.kind === "knowledge" + ? (fixed.kind as "codebase" | "knowledge") + : undefined; + if (fixed.kind !== undefined && validKind === undefined) { + issues.push({ + level: "auto-corrected", + category: "out-of-range", + message: `"kind" ${JSON.stringify(fixed.kind)} is not one of "codebase" | "knowledge" — dropped`, + path: "kind", + }); + } + const graph = { version: typeof fixed.version === "string" ? fixed.version : "1.0.0", + ...(validKind !== undefined ? { kind: validKind } : {}), project: projectResult.data, nodes: validNodes, edges: validEdges, diff --git a/understand-anything-plugin/packages/dashboard/src/App.tsx b/understand-anything-plugin/packages/dashboard/src/App.tsx index cd1b33c79..359917b3c 100644 --- a/understand-anything-plugin/packages/dashboard/src/App.tsx +++ b/understand-anything-plugin/packages/dashboard/src/App.tsx @@ -139,7 +139,7 @@ function Dashboard({ accessToken }: { accessToken: string }) { if (result.success && result.data) { setGraph(result.data); setGraphIssues(result.issues); - if ((data as Record).kind === "knowledge") { + if (result.data.kind === "knowledge") { useDashboardStore.getState().setViewMode("knowledge"); useDashboardStore.getState().setIsKnowledgeGraph(true); }