Skip to content

feat(review): advisory-only AI-vision analysis of before/after visual captures - #4120

Merged
JSONbored merged 1 commit into
mainfrom
feat/ai-vision-visual-findings-4111
Jul 8, 2026
Merged

feat(review): advisory-only AI-vision analysis of before/after visual captures#4120
JSONbored merged 1 commit into
mainfrom
feat/ai-vision-visual-findings-4111

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

Scope

Validation

  • git diff --check
  • npm run typecheck — clean.
  • Targeted + affected tests: npm run test:changed — 260 files / 6936 tests passed (2 pre-existing skips), including test/unit/visual-findings.test.ts (new), test/unit/unified-comment-bridge.test.ts (extended), test/unit/ai-review.test.ts, test/unit/selfhost-ai.test.ts.
  • Scoped coverage check across every touched source file (visual-findings.ts, unified-comment-bridge.ts, selfhost/ai.ts, services/ai-review.ts, types.ts) — 100% branch/line on every changed hunk; the small number of uncovered lines reported (bridge:77, ai.ts:1149, ai-review.ts:1280-1322) are pre-existing and outside this diff's hunks (confirmed via git diff origin/main...HEAD hunk ranges).
  • npm run ui:openapi:check — clean (no schema drift).
  • npm audit --audit-level=moderate — 0 vulnerabilities.

Safety

  • No secrets/wallets/hotkeys/trust-scores exposed — visual findings route through the same publicSafeNit scrub boundary as every other bridge-recovered Nit string.
  • N/A — no auth/session/CORS changes.
  • N/A — no API/OpenAPI/MCP surface touched (ui:openapi:check confirms).
  • N/A — no UI changes.
  • Advisory-only by construction: visual_regression_finding is excluded from isConfiguredGateBlocker, so this can never flip a merge/close decision — only ever adds a "Visual findings" collapsible to the comment.

@superagent-security

superagent-security Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Superagent did not find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.66%. Comparing base (1ec9f94) to head (784b2cd).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4120      +/-   ##
==========================================
+ Coverage   93.65%   93.66%   +0.01%     
==========================================
  Files         384      385       +1     
  Lines       35865    35930      +65     
  Branches    13160    13185      +25     
==========================================
+ Hits        33589    33654      +65     
  Misses       1618     1618              
  Partials      658      658              
Files with missing lines Coverage Δ
src/review/unified-comment-bridge.ts 99.57% <100.00%> (+0.02%) ⬆️
src/review/visual/visual-findings.ts 100.00% <100.00%> (ø)
src/selfhost/ai.ts 98.65% <100.00%> (+0.04%) ⬆️
src/services/ai-review.ts 96.59% <100.00%> (+0.04%) ⬆️
src/types.ts 100.00% <ø> (ø)
🚀 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 added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 8, 2026
@JSONbored JSONbored self-assigned this Jul 8, 2026
@loopover-orb

loopover-orb Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Warning

🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨

⏸️ Gittensory review result - manual review recommended

Review updated: 2026-07-08 02:49:14 UTC

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

⏸️ Suggested Action - Manual Review

  • Touches a guarded path — held for manual review: This PR changes guardrail-protected path(s): src/selfhost/ai.ts (matched src/selfhost/**), src/services/ai-review.ts (matched src/services/**).
Nits — 2 non-blocking
  • 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.
  • Touches a guarded path — held for manual review — A maintainer must review and merge this change.
Signal Result Evidence
Code review ✅ No blockers No AI review summary
Linked issue ✅ Linked #4111
Related work ⚠️ 1 scoped overlap Top overlaps are listed below; lower-confidence bulk is hidden.
Change scope ❌ 8/20 High review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 51 registered-repo PR(s), 43 merged, 509 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 51 PR(s), 509 issue(s).
Gate result ⚠️ Not blocking Advisory; not blocking this PR.
Linked issue satisfaction

Partially addressed
The PR adds the text|image content-block union across all message-construction call sites (including the tie-break judge), the pixel-diff/reputation/BYOK gating logic, and the advisory-only visualFindings surfacing in the unified comment with tests for each — but the module itself is explicitly pure/decision-only, and the PR description states that actually wiring a live caller (fetching screensho

Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, TypeScript, JavaScript, Ruby, Go, Kotlin, MDX, Shell
  • Official Gittensor activity: 51 PR(s), 509 issue(s).
  • Related work: Titles/paths share 6 meaningful terms. (issue #4111, issue #4110)
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.
  • 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

@JSONbored
JSONbored force-pushed the feat/ai-vision-visual-findings-4111 branch from 32648c9 to edc50ee Compare July 8, 2026 02:26
@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 8, 2026
Add a text|image content-block union (AiContentBlock) to both AI
message-construction paths -- selfhost/ai.ts::toMessages (the live
production path) and every services/ai-review.ts content: call site,
including the dual-AI tie-break judge, so a split visual verdict can
receive the same screenshots the two reviewers saw instead of falling
back to text-only reasoning. The HTTP providers (OpenAI-compatible,
Anthropic) translate blocks to their native image shape; the
subscription CLIs (claude-code/codex) degrade to text-only since they
cannot consume inline image bytes through stdin.

Add review/visual/visual-findings.ts: pure gating (pixel-diff
threshold via the existing diff-overlay URL, submitter reputation,
BYOK) plus prompt/response/finding-construction helpers for an
advisory-only visual-regression finding. The finding rides the exact
same advisory-findings pipeline ai_consensus_defect/ai_review_split
use and is not one of the codes isConfiguredGateBlocker recognizes, so
it can never become a gate blocker.

Wire a new "Visual findings" collapsible into the unified PR comment,
recovered from advisoryFindings the same way the consensus defect is
recovered, and excluded from the generic Nits list so it renders
exactly once.
@JSONbored
JSONbored force-pushed the feat/ai-vision-visual-findings-4111 branch from edc50ee to 784b2cd Compare July 8, 2026 02:39
@JSONbored
JSONbored merged commit 6cbd0e8 into main Jul 8, 2026
11 checks passed
@JSONbored
JSONbored deleted the feat/ai-vision-visual-findings-4111 branch July 8, 2026 02:49
JSONbored added a commit that referenced this pull request Jul 27, 2026
Follows #9276, which fixed 8 files / 12 cases and left these 4 files / 5 cases
still red on main (and therefore red on every open PR). Each diagnosed to its
introducing commit; two are real source gaps, two are stale sibling tests a
deliberate behavior change never updated.

SOURCE fixes:
- selfhost/metrics.ts: register two counters emitted since #9243 and #9245 but
  never added to DEFAULT_METRIC_META, so renderMetrics() emitted them as bare
  undocumented samples with no HELP/TYPE — exactly what that drift guard exists
  to catch. Both commits even name the counter in their own body text; a pure
  registration miss, not a behavior decision.

TEST fixes (source verified correct in both cases):
- selfhost-pg-retention: the fake Postgres still matched the pre-#9083 ctid
  semi-join, so every DELETE fell through to rowCount 0. #9083 deliberately
  moved retention to an index-backed PK range delete with ORDER BY (the fix for
  prune-retention blowing its timeout and stalling permanently); it updated the
  SQLite twin but not the Postgres one. Regex now captures whichever key column
  is in play, keeping BOTH the mapped-PK and ctid-fallback paths exercised.
- salvageability: #9085 made an absent blocker confidence degrade to
  CONFIDENCE_WHEN_UNSTATED (0.5) instead of 1.0, so it is sub-floor against the
  0.93 default and the low-confidence hold owns the case. It renamed both
  sibling assertions in rules.test.ts but missed this third consumption site.
  Both calls kept — they are the only coverage of the default-floor arm and the
  nullish-confidence arm respectively.
- worker-entry-boundary: false positive, not a real dependency leak. The check
  grepped whole-file text, so #9230's user-facing string "crossed the
  visual-diff threshold" failed a green tree over a sentence, in a file
  worker-reachable since #4120 that imports none of these deps. Narrowed to scan
  module specifiers (reusing the file's own parseImportSpecifiers) — the only
  way a Node-only dep can actually reach the bundle. Added a discriminating test
  so it cannot pass vacuously; verified by injecting a real `import sharp` and
  confirming it fails, naming the file and specifier.
JSONbored added a commit that referenced this pull request Jul 27, 2026
)

* fix: close the remaining 5 pre-existing test failures on main

Follows #9276, which fixed 8 files / 12 cases and left these 4 files / 5 cases
still red on main (and therefore red on every open PR). Each diagnosed to its
introducing commit; two are real source gaps, two are stale sibling tests a
deliberate behavior change never updated.

SOURCE fixes:
- selfhost/metrics.ts: register two counters emitted since #9243 and #9245 but
  never added to DEFAULT_METRIC_META, so renderMetrics() emitted them as bare
  undocumented samples with no HELP/TYPE — exactly what that drift guard exists
  to catch. Both commits even name the counter in their own body text; a pure
  registration miss, not a behavior decision.

TEST fixes (source verified correct in both cases):
- selfhost-pg-retention: the fake Postgres still matched the pre-#9083 ctid
  semi-join, so every DELETE fell through to rowCount 0. #9083 deliberately
  moved retention to an index-backed PK range delete with ORDER BY (the fix for
  prune-retention blowing its timeout and stalling permanently); it updated the
  SQLite twin but not the Postgres one. Regex now captures whichever key column
  is in play, keeping BOTH the mapped-PK and ctid-fallback paths exercised.
- salvageability: #9085 made an absent blocker confidence degrade to
  CONFIDENCE_WHEN_UNSTATED (0.5) instead of 1.0, so it is sub-floor against the
  0.93 default and the low-confidence hold owns the case. It renamed both
  sibling assertions in rules.test.ts but missed this third consumption site.
  Both calls kept — they are the only coverage of the default-floor arm and the
  nullish-confidence arm respectively.
- worker-entry-boundary: false positive, not a real dependency leak. The check
  grepped whole-file text, so #9230's user-facing string "crossed the
  visual-diff threshold" failed a green tree over a sentence, in a file
  worker-reachable since #4120 that imports none of these deps. Narrowed to scan
  module specifiers (reusing the file's own parseImportSpecifiers) — the only
  way a Node-only dep can actually reach the bundle. Added a discriminating test
  so it cannot pass vacuously; verified by injecting a real `import sharp` and
  confirming it fails, naming the file and specifier.

* fix(github): guard backfill GraphQL helpers' repoFullName parsing

fetchLiveCiAggregateViaGraphQl, fetchLivePullRequestReviewDecision, and
fetchLiveReviewThreadBlockers parsed repoFullName with a bare split/truthiness
check, so extra segments and whitespace-padded slugs reached GraphQL queries.
Add a local parseBackfillRepoFullName helper mirroring #8311's segment-count and
whitespace guard, preserving each call site's fail-soft return contract.

Closes #9317

---------

Co-authored-by: JSONbored <49853598+JSONbored@users.noreply.github.com>
JSONbored added a commit that referenced this pull request Jul 27, 2026
…locked (#9375)

* fix: close the remaining 5 pre-existing test failures on main

Follows #9276, which fixed 8 files / 12 cases and left these 4 files / 5 cases
still red on main (and therefore red on every open PR). Each diagnosed to its
introducing commit; two are real source gaps, two are stale sibling tests a
deliberate behavior change never updated.

SOURCE fixes:
- selfhost/metrics.ts: register two counters emitted since #9243 and #9245 but
  never added to DEFAULT_METRIC_META, so renderMetrics() emitted them as bare
  undocumented samples with no HELP/TYPE — exactly what that drift guard exists
  to catch. Both commits even name the counter in their own body text; a pure
  registration miss, not a behavior decision.

TEST fixes (source verified correct in both cases):
- selfhost-pg-retention: the fake Postgres still matched the pre-#9083 ctid
  semi-join, so every DELETE fell through to rowCount 0. #9083 deliberately
  moved retention to an index-backed PK range delete with ORDER BY (the fix for
  prune-retention blowing its timeout and stalling permanently); it updated the
  SQLite twin but not the Postgres one. Regex now captures whichever key column
  is in play, keeping BOTH the mapped-PK and ctid-fallback paths exercised.
- salvageability: #9085 made an absent blocker confidence degrade to
  CONFIDENCE_WHEN_UNSTATED (0.5) instead of 1.0, so it is sub-floor against the
  0.93 default and the low-confidence hold owns the case. It renamed both
  sibling assertions in rules.test.ts but missed this third consumption site.
  Both calls kept — they are the only coverage of the default-floor arm and the
  nullish-confidence arm respectively.
- worker-entry-boundary: false positive, not a real dependency leak. The check
  grepped whole-file text, so #9230's user-facing string "crossed the
  visual-diff threshold" failed a green tree over a sentence, in a file
  worker-reachable since #4120 that imports none of these deps. Narrowed to scan
  module specifiers (reusing the file's own parseImportSpecifiers) — the only
  way a Node-only dep can actually reach the bundle. Added a discriminating test
  so it cannot pass vacuously; verified by injecting a real `import sharp` and
  confirming it fails, naming the file and specifier.

* fix(review): honor autoCloseExemptLogins in closeDraftDodgeAttemptIfBlocked

closeDraftDodgeAttemptIfBlocked was the one remaining review-evasion auto-close
guard that skipped isProtectedAutomationAuthor and isAutoCloseExempt, so authors
on the operator allowlist or protected automation bots were still draft-dodge
closed despite every sibling guard honoring those exemptions (#6165 pattern).

Closes #9294

---------

Co-authored-by: JSONbored <49853598+JSONbored@users.noreply.github.com>
Co-authored-by: loopover-orb[bot] <296761690+loopover-orb[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(review): advisory-only AI-vision analysis of before/after visual captures

1 participant