Skip to content

Commit a9c2dea

Browse files
committed
feat(lint): flag knowledge pages missing OKF type/description
1 parent a41d8a9 commit a9c2dea

2 files changed

Lines changed: 69 additions & 0 deletions

File tree

openkb/lint.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,39 @@ def find_invalid_frontmatter(wiki: Path) -> list[str]:
485485
return issues
486486

487487

488+
def find_missing_okf_fields(wiki: Path) -> list[str]:
489+
"""Return knowledge pages missing a non-empty ``type`` or ``description``.
490+
491+
OKF v0.1 requires every non-reserved knowledge page to carry a non-empty
492+
``type``; ``description`` is OpenKB's required one-liner. Only summaries/,
493+
concepts/, entities/ are checked — index.md, log.md and sources/ are exempt.
494+
"""
495+
issues: list[str] = []
496+
if not wiki.exists():
497+
return issues
498+
for subdir in PAGE_CONTENT_DIRS:
499+
subdir_path = wiki / subdir
500+
if not subdir_path.exists():
501+
continue
502+
for path in sorted(subdir_path.glob("*.md")):
503+
text = _read_md(path)
504+
fm = None
505+
if text.startswith("---"):
506+
end = text.find("\n---", 3)
507+
if end != -1:
508+
try:
509+
fm = yaml.safe_load(text[3:end].strip("\n"))
510+
except yaml.YAMLError:
511+
fm = None
512+
fm = fm if isinstance(fm, dict) else {}
513+
rel = path.relative_to(wiki)
514+
if not str(fm.get("type") or "").strip():
515+
issues.append(f"{rel}: missing non-empty 'type'")
516+
if not str(fm.get("description") or "").strip():
517+
issues.append(f"{rel}: missing non-empty 'description'")
518+
return issues
519+
520+
488521
def run_structural_lint(kb_dir: Path) -> str:
489522
"""Run all structural lint checks and return a formatted Markdown report.
490523
@@ -502,6 +535,7 @@ def run_structural_lint(kb_dir: Path) -> str:
502535
missing = find_missing_entries(raw, wiki, kb_dir=kb_dir)
503536
sync_issues = check_index_sync(wiki)
504537
bad_frontmatter = find_invalid_frontmatter(wiki)
538+
missing_okf = find_missing_okf_fields(wiki)
505539

506540
lines = ["## Structural Lint Report\n"]
507541

@@ -548,5 +582,14 @@ def run_structural_lint(kb_dir: Path) -> str:
548582
lines.append(f"- {issue}")
549583
else:
550584
lines.append("All frontmatter parses as valid YAML.")
585+
lines.append("")
586+
587+
# OKF conformance
588+
lines.append(f"### OKF Conformance ({len(missing_okf)})")
589+
if missing_okf:
590+
for issue in missing_okf:
591+
lines.append(f"- {issue}")
592+
else:
593+
lines.append("All knowledge pages carry required OKF fields.")
551594

552595
return "\n".join(lines)

tests/test_lint.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
check_index_sync,
1111
find_broken_links,
1212
find_missing_entries,
13+
find_missing_okf_fields,
1314
find_orphans,
1415
fix_broken_links,
1516
list_existing_wiki_targets,
@@ -649,3 +650,28 @@ def test_whitelist_includes_entities(tmp_path):
649650
(tmp_path / "entities" / "anthropic.md").write_text("# A", encoding="utf-8")
650651
targets = list_existing_wiki_targets(tmp_path)
651652
assert "entities/anthropic" in targets
653+
654+
655+
def test_flags_missing_type_and_description(tmp_path):
656+
wiki = tmp_path / "wiki"
657+
for sub in ("summaries", "concepts", "entities"):
658+
(wiki / sub).mkdir(parents=True)
659+
(wiki / "concepts" / "good.md").write_text(
660+
'---\ntype: "Concept"\ndescription: "ok"\n---\n\n# Good\n', encoding="utf-8")
661+
(wiki / "concepts" / "no_type.md").write_text(
662+
'---\ndescription: "x"\n---\n\n# Bad\n', encoding="utf-8")
663+
(wiki / "summaries" / "no_desc.md").write_text(
664+
'---\ntype: "Summary"\n---\n\n# Bad\n', encoding="utf-8")
665+
issues = find_missing_okf_fields(wiki)
666+
assert any("no_type.md" in i and "type" in i for i in issues)
667+
assert any("no_desc.md" in i and "description" in i for i in issues)
668+
assert not any("good.md" in i for i in issues)
669+
670+
671+
def test_flags_null_type_as_missing(tmp_path):
672+
wiki = tmp_path / "wiki"
673+
(wiki / "concepts").mkdir(parents=True)
674+
(wiki / "concepts" / "null_type.md").write_text(
675+
'---\ntype: null\ndescription: "x"\n---\n\n# Bad\n', encoding="utf-8")
676+
issues = find_missing_okf_fields(wiki)
677+
assert any("null_type.md" in i and "type" in i for i in issues)

0 commit comments

Comments
 (0)