Skip to content

fix(storage): lesson-family dedup guard trusts stored type, not the call's type argument - #299

Merged
kevintseng merged 3 commits into
mainfrom
fix/lesson-dedup-guard-trusts-stored-type
Sep 4, 2026
Merged

fix(storage): lesson-family dedup guard trusts stored type, not the call's type argument#299
kevintseng merged 3 commits into
mainfrom
fix/lesson-dedup-guard-trusts-stored-type

Conversation

@kevintseng

Copy link
Copy Markdown
Contributor

What it does

createEntityInner's content-dedup exemption for lesson_learned/lesson/mistake entities now checks the entity's actual stored type for an existing entity, instead of the type string this particular call happened to pass.

Why it is needed

Found by a security review of PR #288's diff. INSERT OR IGNORE is a no-op on an existing row, and the SELECT beside it never fetched type — so re-remembering an existing lesson entity under any other type string (schemas.ts declares type as an unconstrained 1-100 char string, no enum) took the non-lesson branch and ran content dedup against observations that groupLessons/parseStructuredBlocks read as ordered Error:/Root cause:/Fix:/Prevention: blocks — silently dropping a repeated field line and corrupting the lesson, with no signal to the caller.

How to test

node scripts/run-tests-isolated.mjs tests/knowledge-graph.test.ts

The new test re-remembering a lesson entity under a different type string still skips content dedup fails on the pre-fix code (confirmed by reverting the fix and re-running — exactly that one test goes red, the other 64 stay green) and passes with the fix.

Linked issues

Found during v4.8.4 pre-release security review, no tracked issue number.

…all's type argument

createEntityInner's content-dedup exemption for lesson_learned/lesson/
mistake entities checked the incoming `type` parameter, never the
entity's actual stored type. `INSERT OR IGNORE` is a no-op on an
existing row, and the SELECT beside it didn't even fetch `type` — so
re-remembering an existing lesson entity under any other type string
(schemas.ts declares `type` as an unconstrained 1-100 char string,
no enum) took the non-lesson branch and ran content dedup against
observations that groupLessons/parseStructuredBlocks read as ordered
Error:/Root cause:/Fix:/Prevention: blocks, silently dropping a
repeated field line and corrupting the lesson.

Found by a security review of PR #288's diff; verified against the
actual code (schemas.ts:48, the existing "preserve original type on
duplicate entity" test) before fixing. The SELECT now reads `type`
and the guard uses the stored value for an existing entity, the
incoming value only when the entity is new (there is no stored value
yet). Regression test added mirroring the existing lesson-family
dedup test; reverting the fix turns exactly that one test red (64
others stay green), confirmed by running it both ways.
@kevintseng
kevintseng force-pushed the fix/lesson-dedup-guard-trusts-stored-type branch from 6970d1e to d452db4 Compare September 4, 2026 11:33
@kevintseng
kevintseng merged commit 6a1f68b into main Sep 4, 2026
13 checks passed
@kevintseng
kevintseng deleted the fix/lesson-dedup-guard-trusts-stored-type branch September 5, 2026 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant