Skip to content

Knowledge schema: enforce every declared select enum, not just type - #2042

Open
hjbrandt wants to merge 1 commit into
danielmiessler:mainfrom
hjbrandt:kb-schema-enforce-select-values
Open

Knowledge schema: enforce every declared select enum, not just type#2042
hjbrandt wants to merge 1 commit into
danielmiessler:mainfrom
hjbrandt:kb-schema-enforce-select-values

Conversation

@hjbrandt

@hjbrandt hjbrandt commented Sep 1, 2026

Copy link
Copy Markdown

The bug

validate() in KnowledgeSchema.ts checks CANONICAL_TYPES by hand and never reads the values list declared on the other select fields. So source_kind, status and quality_inferred can hold any string and still lint clean.

I found it because a note in my archive carries source_kind: external — not in SOURCE_KINDS — and passed a 100%-conformant run.

The fix

Walk ENVELOPE and check every select that declares values. Adding a new controlled vocabulary to the envelope is then enforced by construction, instead of needing a matching hand-written branch that nobody remembers to write.

Three regression tests added (#7). They fail on current main and pass here.

Evidence

  • Smoke suite: 32 passed, 0 failed. Reverting only the new loop: 30 passed, 2 failed, and only the two enforcement tests go red.
  • KnowledgeLint over a 334-note archive: 333/334 → 334/334 envelope-conformant, catching exactly the one off-vocabulary note and nothing else. No false positives across 334 real notes.

Two smaller things in the same area

  • _schema.md now says when book and blog apply, next to the existing bookmark rule. type and source_kind both contain the value blog and nothing stated which axis a blog post belongs on. It is type: idea + source_kind: blog; type: blog is the archived post itself. Both lines are descriptive of how the types are already used, not a new policy.
  • The shipped Cortex skill listed four note types in five places. There are six — Books and Blogs were missing.

Scope

No migrations, no vocabulary changes, no behaviour change for conformant notes. A non-conformant note starts reporting the violation it always had.

Related: #1986.

`validate()` checked CANONICAL_TYPES by hand and never read the `values`
list declared on the other select fields. `source_kind`, `status` and
`quality_inferred` could therefore hold any string and still lint clean:
a note carrying `source_kind: external` passed a 100%-conformant run in
my archive, which is how I found this.

Walk ENVELOPE instead and check every select that declares `values`, so
adding a new controlled vocabulary to the envelope is enforced by
construction rather than needing a matching hand-written branch.

Three regression tests added (danielmiessler#7); they fail on the current code and
pass on this one. Full smoke suite: 32 passed, 0 failed. Lint over a
334-note archive goes 333/334 -> 334/334, catching exactly the one
off-vocabulary note.

Two smaller things in the same area:

- `_schema.md` now says when `book` and `blog` apply, next to the
  existing bookmark rule. `type` and `source_kind` both contain the
  value `blog`, and nothing said which axis a blog post belongs on.
  (It is `type: idea` + `source_kind: blog`; `type: blog` is the
  archived post itself.)
- The shipped Cortex skill still listed four note types in five places.
  There are six.

No migrations, no vocabulary changes, no behaviour change for
conformant notes.
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