fix(schema): preserve graph kind field through validateGraph#440
fix(schema): preserve graph kind field through validateGraph#440tirth8205 wants to merge 2 commits into
kind field through validateGraph#440Conversation
`KnowledgeGraphSchema` declares an optional `kind` enum
("codebase" | "knowledge") and the `KnowledgeGraph` type mirrors it,
but `validateGraph` rebuilds its return object from scratch and never
copied `kind`. A valid input graph with `kind: "knowledge"` therefore
came back with `kind === undefined` — silent data loss on the declared
API surface (loadGraph round-trips strip it, and the dashboard had to
read `kind` from the raw pre-validation data to work around it).
Carry the validated `kind` through, only when it is a valid enum value
(mirroring how `version` is already preserved).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
thejesh23
left a comment
There was a problem hiding this comment.
1. Invalid kind values are silently coerced to undefined with no issue logged.
The guard fixed.kind === "codebase" || fixed.kind === "knowledge" drops anything else (e.g. kind: "unknown", kind: 123, a typo from a hand-edited graph or older language extractor — relevant to extractors like the one in #435) into the no-kind branch without pushing a GraphIssue. Everywhere else in validateGraph an invalid field becomes an auto-corrected or dropped issue; this is the one silent narrowing. Consider pushing an auto-corrected issue when fixed.kind !== undefined but does not match the enum.
2. Consumer workarounds called out in the PR body are not cleaned up.
The description explicitly identifies that App.tsx reads kind from the raw pre-validation data and loadGraph in persistence/index.ts round-trips and strips kind. With this fix landed, those become dead workarounds that the next reader will assume are still load-bearing. Either remove them here or open a follow-up — leaving them silently undoes part of the value of this fix.
3. Test coverage is asymmetric — only "knowledge" and undefined exercised.
No test pins behavior for kind: "codebase" (the other enum branch, presumably the more common production value) or for an invalid kind value, which is exactly the path that motivates concern #1. A three-line it.each over ["codebase","knowledge","bogus",undefined] would lock all four arms of the new branch.
…d data Concern 1: validateGraph now pushes an auto-corrected GraphIssue when `kind` is present but not "codebase"/"knowledge", instead of silently narrowing it to undefined — surfacing typos and stale extractor values like every other invalid field. Concern 2: App.tsx reads `result.data.kind` (the validated source of truth) rather than the raw pre-validation payload now that kind is preserved. Concern 3: replace the two kind tests with an it.each over ["codebase","knowledge","bogus",undefined] locking all four arms of the branch, plus issue-emission coverage for the out-of-enum path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
All three points addressed in 190bf01. 1. Out-of-enum 2. Consumer workaround. Changed 3. Asymmetric coverage. Replaced the two kind tests with an Full core suite green (698 passed); core and dashboard both typecheck clean. |
Problem
KnowledgeGraphSchemadeclares an optionalkindenum field (z.enum(["codebase", "knowledge"]).optional()) and theKnowledgeGraphtype mirrors it (kind?: "codebase" | "knowledge"). However,validateGraphbuilds its return object from scratch and never copieskind. So a valid input graph withkind: "knowledge"comes back withresult.data.kind === undefined— silent data loss on the declared API surface.This forces consumers into workarounds: the dashboard (
App.tsx) readskindfrom the raw pre-validationdatainstead of fromresult.data, andloadGraph(persistence/index.ts) round-trips a saved knowledge graph and silently strips itskind. Note thatversionis already preserved in the same constructed object, so omittingkindis an oversight rather than intent.Fix
Carry the validated
kindthrough in the objectvalidateGraphconstructs, gated on it being a valid enum value (mirroring howversionis handled):The spread guard ensures an input without
kindstill yieldskind === undefined(no spurious field added).Testing
Added two tests to
schema.test.ts:preserves the kind field for knowledge graphs— fails before the fix (expected undefined to be 'knowledge'), passes after.leaves kind undefined when the input omits it— confirms the guard does not fabricate akind.Verification: the new test was confirmed red before the fix and green after. The full core package test suite passes (694 tests),
tsc --noEmitexits 0, and ESLint is clean on both changed files.🤖 Generated with Claude Code