fix(skill): resolve references/ wikilinks whose stem contains a dot#120
Conversation
`validate_skill` appended the implicit `.md` to a `[[references/...]]` link only when `Path(link).suffix` was empty. `Path.suffix` returns everything after the last dot, so a reference whose stem contains a dot — e.g. `[[references/api.v2]]` or `[[references/v1.2-guide]]` — has a truthy suffix (`.v2` / `.2-guide`). The `.md` was therefore never appended and the validator looked for an extension-less `references/api.v2`, emitting a false "doesn't exist" error even though `references/api.v2.md` is present and correctly linked. (`WIKILINK_RE` allows `.` in the target, so such links are legal and reach this branch.) Append `.md` based on a literal `.md` check instead of `Path.suffix`, so a dotted stem is suffixed correctly while an explicit `...md` link is left alone. Genuinely missing references still error. Adds a regression test for the dotted-stem case (the existing `test_wikilink_without_md_suffix_resolves` only covered a dot-free stem).
There was a problem hiding this comment.
Pull request overview
Fixes validate_skill false negatives when resolving [[references/...]] wikilinks whose stems contain dots (e.g. api.v2), by appending .md based on a literal suffix check rather than Path.suffix. This aligns validator behavior with the allowed wikilink pattern and adds a regression test to cover the previously untested path.
Changes:
- Update
openkb/skill/validator.pyto treat links as “already suffixed” only when they literally end with.md(case-insensitive). - Add a unit test ensuring dotted stems without an explicit
.mdsuffix resolve correctly.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
openkb/skill/validator.py |
Fixes reference target path construction so dotted stems still resolve to *.md. |
tests/test_skill_validator.py |
Adds regression coverage for [[references/api.v2]] resolving to references/api.v2.md. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # The link may already include the .md suffix; append it otherwise. | ||
| # Test the literal ".md" rather than Path.suffix — a dotted stem like | ||
| # "api.v2" has a truthy suffix (".v2"), so Path.suffix would skip the | ||
| # ".md" and then look for a non-existent extension-less file. | ||
| target = refs_dir / (link if link.lower().endswith(".md") else f"{link}.md") |
Review feedback: WIKILINK_RE allows '.' and '/', so '[[references/../SKILL]]' resolved outside references/ and was accepted whenever the resolved file existed (and would crash the not-found message's relative_to(skill_dir)). Reject any link whose resolved target is not under references/.
There was a problem hiding this comment.
Thanks @jichaowang02-lang — clean fix. The dotted-stem resolution is correct, and the escape guard is a nice catch (the old code silently accepted [[references/../SKILL]]). LGTM 👍
Summary
validate_skillreports a false "doesn't exist" error for a valid[[references/...]]wikilink whose target stem contains a dot (e.g.[[references/api.v2]],[[references/v1.2-guide]]), even when the file(
references/api.v2.md) is present and correctly linked.Root cause
openkb/skill/validator.pyonly appended the implicit.mdwhenPath(link).suffixwas empty:Path.suffixreturns everything after the last dot, soapi.v2has atruthy suffix (
.v2). The.mdis never appended, and the validator thenchecks for an extension-less
references/api.v2, which doesn't exist —producing a false error.
WIKILINK_RE([a-z0-9._/-]+) allows.in thetarget, so such links are legal and reach this branch.
[[references/topic]]topic.md[[references/api.v2.md]]api.v2.md[[references/api.v2]]api.v2.md[[references/ghost]]Fix
Append
.mdbased on a literal.mdcheck instead ofPath.suffix:A dotted stem is now suffixed correctly; an explicit
...mdlink is leftalone; genuinely missing references still error.
Testing
Adds
test_wikilink_dotted_stem_without_md_suffix_resolves— the existingtest_wikilink_without_md_suffix_resolvesonly covered a dot-free stem, sothis path was uncovered.