fix(evidence): make evidence.file repo-relative so site deep-links resolve#82
Merged
Conversation
…solve Phase 2/3 (#81) published evidence.file relative to the skill's own directory (what scanPieces uses), e.g. bare "SKILL.md" — but the site resolves a per-plugin source link from the plugin's REPO root, and a skill is usually nested under it (skills/<name>/…). A bare skill- relative file can't be appended to that link to build a working github.com/.../blob/<sha>/<file>#L<line> deep link. Thread through skillPath (the skill's own dir relative to the repo root discoverMarketplaceSkills resolved it under) and join it onto each evidence entry's file before publishing, in both corpus and legacy scan modes. Closes #80 (phase 4's actual requirement — the tree/ -> blob/#Lline swap — needs this on the data side; site-side render in a truecopy-site PR).
sprayberry-reviewer
approved these changes
Jul 21, 2026
sprayberry-reviewer
left a comment
Collaborator
There was a problem hiding this comment.
Automated review from the Sprayberry Labs fleet code reviewer.
Verdict: No blocking issues found — approving.
What I checked
- Diff:
support/marketplace-watch.mjs(+17/-5) andtest/marketplace-watch.test.mjs(+19). - Traced the join invariant end-to-end: in
support/marketplace-fetch.mjs,canon-corpus.jsonrows storediras the exact directory the site's tree/blob link resolves to — forkind:'local'it'spath.resolve(clone, e.rel), forkind:'external'with asubpath it'spath.resolve(r.dir, e.sub)(already sub-adjusted).discoverMarketplaceSkills(row.dir)(viacollectPluginSkills,src/claude.mjs:84-92) always nests discovered skills atrow.dir/skills/<name>(or one level deeper forplugins//external_plugins/trees), sopath.relative(row.dir, s.dir)(support/marketplace-watch.mjs:98,106) never produces..and always lands on the correct relative join for the tree link's root. - New test
test/marketplace-watch.test.mjs:105-121exercises exactly the case described in the PR body (skill nested at<repo>/skills/sneaky/) and assertsevidence[].file === 'skills/sneaky/SKILL.md', not the bareSKILL.mdthatevidence.mjs'slocate()would otherwise return. - CI check-rollup: all 9 checks green (CI on ubuntu/windows/macos × node 20/22, CodeQL, truecopy gate) —
gh pr checks 82.
What's good
- Good in-code comment (
support/marketplace-watch.mjs:56-62) explaining why the join is needed, tied back to issue #80's phase-4 spec — makes the non-obvious repo-root vs. skill-root distinction easy to verify later. - Keeps
evidence.mjs'slocate()untouched and does the join once at publish time, which is the right layer — avoids threading a new concept through the confabulation-guard matching logic. - Test targets the actual regression shape (nested skill dir), not just a trivial case.
Minor (non-blocking)
repoRelative'sskillPath !== '.'branch (support/marketplace-watch.mjs:63) looks currently unreachable: every path intodiscoverMarketplaceSkills/collectPluginSkillsnests skill dirs under<pluginRoot>/skills/<name>, sos.diris never equal torow.dir/rootandskillPathis never'.'. Harmless defensive code, but worth a one-line note if it's meant to guard a future discovery shape rather than dead code.
askalf
added a commit
that referenced
this pull request
Jul 21, 2026
#83) #81 and #82 shipped user-facing behavior with no changelog entry: `scan --json` findings/advisories now carry `evidence[]`, and the watch publishes `evidenceMismatches` plus repo-relative evidence paths. Both belong under Unreleased so the next release notes are complete. Documentation only — no code or behavior change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
#80's phase 4 spec calls for swapping the site's
/tree/<sha>/<path>source link for/blob/<sha>/<path>/<file>#L<line>per evidence item — a real deep link to the exact matched line, not justfile:lineas text.That's blocked on the data side:
evidence.file(fromsupport/evidence.mjs'slocate()) is relative to the skill's own directory (whatscanPiecesuses), e.g. bareSKILL.md. But the site resolves one source link per plugin, anchored at the plugin's repo root — and a skill is normally nested under that asskills/<name>/…. Appending a skill-relativefileto the plugin's tree link produces a broken URL.What changed
support/marketplace-watch.mjsnow capturesskillPath— the skill's own directory relative to the repo rootdiscoverMarketplaceSkillsresolved it under (alwaysskills/<name>in practice, since that's the only shapecollectPluginSkillsrecognizes) — for every skill, in both corpus and legacy scan modes. Each evidence entry'sfileis joined withskillPathbefore publishing, so it's now genuinely repo-relative and safe to append directly to the plugin's resolved tree/blob link.evidence.mjs'slocate()is untouched — it still matches against skill-root-relativescanPieces, which is correct; the join happens once, at publish time, in the watch.Verification
New test:
evidence file is repo-relative to the skill's source repo, not just the skill dir— a skill nested at<repo>/skills/sneaky/now publishes evidence withfile: "skills/sneaky/SKILL.md", not bareSKILL.md. Full suite 156/156 (4 environment-skipped, unrelated).Companion site PR (renders the actual
<a href=".../blob/.../file#Lline">instead of plain text) lands separately intruecopy-site.Part of #80.