Skip to content

feat(review): add per-repo review.visual capture config - #3644

Merged
JSONbored merged 2 commits into
mainfrom
feat/selfhost-visual-config-preview-routes
Jul 5, 2026
Merged

feat(review): add per-repo review.visual capture config#3644
JSONbored merged 2 commits into
mainfrom
feat/selfhost-visual-config-preview-routes

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

  • Adds review.visual to the .gittensory.yml manifest so a self-hoster can point the before/after screenshot capture pipeline at their own repo's preview setup, purely through config:
    • preview.url_template: an explicit "after" preview URL template ({number}/{head_sha}/{head_sha_short} placeholders) that always wins over the existing GitHub-native discovery chain (Deployments API → commit checks → cloudflare-bot PR comment) — the only option for a provider (e.g. Cloudflare Workers Builds' non-production branch builds) that never surfaces a GitHub-visible deployment at all. Validated at parse time against the same SSRF guard (isSafeHttpUrl) the renderer applies at render time, so a malformed template warns immediately at config-read time instead of silently degrading to a blank cell later.
    • routes.paths / routes.max_routes: an explicit route list that replaces automatic file-to-route inference for a repo whose routing convention isn't gittensory-ui's TanStack file-based one, plus an override for the built-in per-PR route cap (applies to either source).
  • All-absent (the default for every repo today) resolves to the existing discovery/inference behavior unchanged — this is byte-identical until a maintainer opts in, and only takes effect at all when the operator has separately enabled GITTENSORY_REVIEW_SCREENSHOTS + the repo cutover allowlist.
  • Also documents finding_categories and visual in .gittensory.yml.example's field-exhaustiveness map, which docs(config): make .gittensory.yml.example genuinely exhaustive, add a drift check #3635 (merged after this branch was cut) otherwise leaves them out of.

Part of #3607. Closes #3609. Closes #3610.

Scope

  • The PR title follows type(scope): short summary Conventional Commit format, for example fix(api): restore profile access checks.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked an issue, or this is small enough that the summary explains why an issue is not needed.

Validation

  • git diff --check
  • npm run actionlint (not run — no workflow files changed)
  • npm run typecheck
  • npm run test:coverage locally; codecov/patch requires ≥99% coverage of the lines AND branches you changed (aim for 100% on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate.
  • npm run test:workers (not run — no Worker-runtime-specific code touched)
  • npm run build:mcp (not run — no MCP package changes)
  • npm run test:mcp-pack (not run — no MCP package changes)
  • npm run ui:openapi:check (not run — no API/OpenAPI changes)
  • npm run ui:lint (not run — no apps/gittensory-ui/** changes)
  • npm run ui:typecheck (not run — no apps/gittensory-ui/** changes)
  • npm run ui:build (not run — no apps/gittensory-ui/** changes)
  • npm audit --audit-level=moderate
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries

If any required check was skipped, explain why:

  • This PR only touches src/queue/processors.ts, src/review/visual/capture.ts, src/signals/focus-manifest.ts, .gittensory.yml.example, and test/unit/** — no UI, MCP, wrangler binding, OpenAPI, or workflow files changed, so the UI/MCP/workers/openapi/actionlint checks above have no surface to exercise. Ran npx tsc --noEmit -p . (full project, clean) and targeted vitest run across every affected test file (focus-manifest.test.ts, visual-capture.test.ts, visual-paths.test.ts, visual-wire.test.ts, visual-collapsible.test.ts, visual-diff.test.ts, visual-shot.test.ts, visual-config-wiring.test.ts, signals-coverage.test.ts, auto-review-wiring.test.ts, and the full queue.test.ts suite) — 1132/1132 passing — plus a scoped vitest --coverage pass confirming every new line in src/signals/focus-manifest.ts, src/review/visual/capture.ts, and src/queue/processors.ts is hit, including the processors.ts call site inside the screenshotsAllowed(...) branch (added a new queue.test.ts integration test that drives a real webhook through processJob with the screenshots flag on and a visual-path file changed, since that branch previously had zero test coverage even before this PR — see test/unit/queue.test.ts, "threads review.visual config into the capture pipeline...").

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests. (N/A — no auth/session/CORS changes; url_template is validated against the existing SSRF guard, with new tests covering both a non-HTTPS and a private-host rejection.)
  • API/OpenAPI/MCP behavior is updated and tested where needed. (N/A — no API/OpenAPI/MCP surface touched.)
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks. (N/A — no UI changes.)
  • Visible UI changes include a UI Evidence section below with JPG/JPEG or PNG screenshots arranged as organized, captioned, clickable thumbnails. SVG screenshots are not used as review evidence. Review-only screenshots or recordings are not committed to the repository. (N/A — backend/config-only change, no visible UI surface.)
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs. (.gittensory.yml.example updated; CHANGELOG.md untouched.)

UI Evidence

N/A — this PR has no visible UI/frontend surface (backend config-schema + capture-pipeline wiring only).

Notes

@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

Adds `review.visual` to the .gittensory.yml manifest so a self-hoster
can point the before/after screenshot pipeline at their own repo's
preview setup without any code changes:

- preview.url_template: an explicit "after" preview URL template
  ({number}/{head_sha}/{head_sha_short} placeholders) that always wins
  over GitHub-native preview discovery -- the only option for a
  provider (e.g. Cloudflare Workers Builds' non-production branch
  builds) that never surfaces a GitHub-visible deployment at all.
  Validated at parse time against the same SSRF guard the renderer
  applies at render time (isSafeHttpUrl), so a malformed template
  warns immediately instead of silently degrading to a blank cell.
- routes.paths / routes.max_routes: an explicit route list that
  replaces automatic file-to-route inference for a repo whose routing
  convention isn't gittensory-ui's TanStack file-based one, plus an
  override for the built-in per-PR route cap.

All-absent (default, every repo today) resolves to the existing
GitHub-native discovery chain and automatic route inference, so this
is byte-identical until a maintainer opts in. Also documents the two
review.* fields (finding_categories, visual) that were still missing
from .gittensory.yml.example's field-exhaustiveness map after #3635.

Part of #3607. Closes #3609. Closes #3610.
@JSONbored
JSONbored force-pushed the feat/selfhost-visual-config-preview-routes branch from 789706f to 5dbbb8a Compare July 5, 2026 21:57
@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 5, 2026
@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.28%. Comparing base (39431cc) to head (7f6e15f).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3644      +/-   ##
==========================================
+ Coverage   93.13%   93.28%   +0.15%     
==========================================
  Files         314      314              
  Lines       32005    32054      +49     
  Branches    11725    11747      +22     
==========================================
+ Hits        29807    29903      +96     
+ Misses       1552     1517      -35     
+ Partials      646      634      -12     
Files with missing lines Coverage Δ
src/queue/processors.ts 94.01% <100.00%> (+0.26%) ⬆️
src/review/visual/capture.ts 69.13% <100.00%> (+26.08%) ⬆️
src/signals/focus-manifest.ts 99.03% <100.00%> (+0.03%) ⬆️

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@loopover-orb

loopover-orb Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Tip

🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩

✅ Gittensory review result - approve/merge recommended

Review updated: 2026-07-05 22:31:54 UTC

9 files · 1 AI reviewer · no blockers · readiness 82/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This PR adds an optional `review.visual` block to the focus manifest (preview.url_template + routes.paths/max_routes) that lets a self-hoster override GitHub-native preview discovery and file-to-route inference for the before/after screenshot capture pipeline. The wiring is threaded consistently: parse → EMPTY_MANIFEST/emptyManifest defaults → present-flag → reviewConfigToJson round-trip → resolveReviewVisualConfig → resolveVisualCaptureConfig (processors.ts) → buildCapture/resolveVisualRoutes/resolvePreviewUrlTemplate (capture.ts), with the SSRF guard (isSafeHttpUrl) applied both at parse time (dummy-substituted probe) and again unconditionally at render time. All-absent config is verified byte-identical to prior behavior via dedicated tests, and the webhook-level integration test (queue.test.ts) proves the config actually reaches buildCapture end-to-end rather than just the pure-function unit tests.

Nits — 6 non-blocking
  • codecov/patch failed at 91.17% vs the repo's 99% patch-coverage target — worth checking which branch is uncovered (likely one of the `record.preview`/`record.routes` non-mapping-but-not-null edge cases or the `visualConfigPresent` false path) before merge.
  • resolveVisualCaptureConfig (src/queue/processors.ts) does its own loadRepoFocusManifest call rather than reusing the manifest already loaded/cached for the AI-review path in the same request — a minor duplicate fetch per PR capture, not a correctness issue given manifests are presumably cached/cheap.
  • The external secret scanner flag on test/unit/queue.test.ts's GITHUB_APP_PRIVATE_KEY looks like a false positive — the value comes from `await generatePrivateKeyPem()`, a freshly generated test key, not a hardcoded credential — but worth a quick human glance to confirm no literal PEM was pasted nearby.
  • src/signals/focus-manifest.ts: consider a short comment on why `resolveVisualCaptureConfig` intentionally bypasses the AI-review manifest cache (deterministic/non-AI feature) — it's explained in the JSDoc already, so this is just a readability nit for future readers scanning the call site in processors.ts.
  • Confirm the uncovered branch(es) behind the 91.17% patch coverage number and add a targeted test (e.g., the `record.preview`/`record.routes` present-but-non-mapping vs undefined-vs-null permutations in parseVisualConfig, src/signals/focus-manifest.ts).
  • PR author also opened the linked issue — Link an issue that was opened by a different contributor, or provide a rationale for why this self-authored issue represents genuine discovery work.
Signal Result Evidence
Code review ✅ No blockers 1 reviewer
Linked issue ✅ Linked #3609, #3610
Related work ⚠️ 3 scoped overlaps Top overlaps are listed below; lower-confidence bulk is hidden.
Change scope ❌ 8/20 High review scope from cached public metadata (2 linked issues).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 55 registered-repo PR(s), 46 merged, 480 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 55 PR(s), 480 issue(s).
Gate result ✅ Passing No configured blocker found.
Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository registration is not available in the local Gittensory cache.
  • Public profile languages: Python, TypeScript, JavaScript, Ruby, Go, Kotlin, MDX, Shell
  • Official Gittensor activity: 55 PR(s), 480 issue(s).
  • Related work: Titles/paths share 7 meaningful terms. (issue #2152, issue #2150)
  • Related work: Titles/paths share 8 meaningful terms. (issue #2189, issue #2184)
  • Related work: Titles/paths share 6 meaningful terms. (issue #1959, issue #2156)
  • Additional title-only matches omitted; title-only overlap does not block.
Contributor next steps
  • Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • Review top overlaps.
  • Add a concise scope and risk note.
  • No action.
  • Check active issues and PRs before submitting.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.

  • Re-run Gittensory review

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 5, 2026
…nches

codecov/patch flagged 91.18% on the prior commit: wrapping the existing
GitHub-native discovery chain in a new `else` block (so the explicit
url_template check could run first) re-indented every line inside it,
which counts as "changed" for patch coverage even though the logic
itself didn't change. Adds the missing branch coverage:
- target.previewUrl already set (skips discovery, no fetch calls)
- getLatestDeploymentStatus throwing (defense-in-depth; the callee
  itself always catches internally and never actually throws today)
- a preview URL found via a commit check run (skips the PR-comment
  fallback)
- every getPreviewBuildState outcome the pending-poll branch reads:
  building, succeeded, and absent (no matching check run at all)
@JSONbored
JSONbored merged commit cedbba0 into main Jul 5, 2026
10 checks passed
@JSONbored
JSONbored deleted the feat/selfhost-visual-config-preview-routes branch July 5, 2026 22:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. manual-review Gittensor contributor context

Projects

None yet

1 participant