Return wiki pages whose YAML frontmatter fails ``yaml.safe_load``. Catches the silent-write class of bug where an LLM-authored field (e.g. ``brief:``) ships unquoted and turns a colon-bearing value into invalid YAML that OpenKB itself reads with string slicing but external YAML-awar
(
wiki: Path,
pages: dict[Path, str] | None = None,
)
| 483 | |
| 484 | |
| 485 | def find_invalid_frontmatter( |
| 486 | wiki: Path, |
| 487 | pages: dict[Path, str] | None = None, |
| 488 | ) -> list[str]: |
| 489 | """Return wiki pages whose YAML frontmatter fails ``yaml.safe_load``. |
| 490 | |
| 491 | Catches the silent-write class of bug where an LLM-authored field |
| 492 | (e.g. ``brief:``) ships unquoted and turns a colon-bearing value |
| 493 | into invalid YAML that OpenKB itself reads with string slicing but |
| 494 | external YAML-aware tools (VS Code, Obsidian, doc generators) reject. |
| 495 | |
| 496 | Args: |
| 497 | wiki: Path to the wiki root directory. |
| 498 | pages: Optional pre-loaded ``{path: text}`` mapping from |
| 499 | :func:`_load_wiki_pages`. When ``None`` (the default), the |
| 500 | mapping is built internally so existing callers that pass only |
| 501 | ``wiki`` keep working unchanged. |
| 502 | """ |
| 503 | issues: list[str] = [] |
| 504 | if not wiki.exists(): |
| 505 | return issues |
| 506 | if pages is None: |
| 507 | pages = _load_wiki_pages(wiki) |
| 508 | for path, text in sorted(pages.items()): |
| 509 | parts = frontmatter.split(text) |
| 510 | if parts is None: |
| 511 | continue |
| 512 | fm_block = parts[0] |
| 513 | # Extract the raw YAML between the two ``---`` delimiters so that |
| 514 | # yaml.safe_load can surface the exact error message. The closing |
| 515 | # delimiter is line-anchored (frontmatter.split guarantees this), |
| 516 | # so we strip the opening ``---\n`` and everything from the final |
| 517 | # ``\n---`` onward. |
| 518 | inner = fm_block[4:] # drop "---\n" |
| 519 | close = inner.rfind("\n---") |
| 520 | if close != -1: |
| 521 | inner = inner[:close] |
| 522 | try: |
| 523 | yaml.safe_load(inner) |
| 524 | except yaml.YAMLError as exc: |
| 525 | rel = path.relative_to(wiki) |
| 526 | msg = str(exc).splitlines()[0] |
| 527 | issues.append(f"{rel}: {msg}") |
| 528 | return issues |
| 529 | |
| 530 | |
| 531 | def find_missing_okf_fields( |