Skip to content

Finding feedback

ThrillhouseBot records lightweight maintainer signals about review findings so a future cross-review learnings store (#38) has training data. This is the precursor shipped for #324; it does not yet inject preferences into review prompts.

GitHub Apps do not receive a reaction webhook event. The bot therefore lists 👍 (+1) and 👎 (-1) on finding comments via the Reactions REST API when:

  1. A human replies on an inline review thread (pull_request_review_comment with in_reply_to_id), or
  2. A follow-up review already loaded inline comments — every bot finding-root comment across prior rounds is scanned (capped, ordered by comment id), not only findings from the immediately previous AI response.

Capture is best-effort and never fails the webhook 200 or the review.

SignalSourceMeaning
usefulreaction (+1)Maintainer marked the finding comment 👍
not_usefulreaction (-1)Maintainer marked the finding comment 👎
not_usefulreply_heuristicReply body matched a conservative phrase (not useful, false positive, noise, 👎, :-1:)

Only comments that carry the hidden <!-- thrillhousebot:finding=N --> marker are eligible. The bot's own reactions (e.g. 👀 command ack) are ignored.

Table finding_feedback (Hibernate schema-update; no Flyway):

ColumnTypeNotes
idbigintPanache / sequence PK
repositorystringowner/repo
prNumberintPR on that repository
githubCommentIdbigintFinding root review-comment id
findingIndexint (nullable)1-based index from the marker
signalstringuseful or not_useful
sourcestringreaction or reply_heuristic
reactorLoginstringGitHub login only (lower-cased)
githubReactionIdbigint (nullable)Unique when present (idempotent re-poll)
createdAtinstantInsert time

Unique constraints:

  • githubReactionId (when non-null) — reaction redeliveries / re-polls
  • (githubCommentId, reactorLogin, signal, source) — one logical event per actor

Stored PII is limited to the GitHub login already present on webhook and API payloads. No email, display name, IP, or reaction text beyond the fixed emoji content codes (+1 / -1) is persisted. Finding title/description are not copied into this table.

Rows are retained for the lifetime of the deployment database. There is no automatic purge. Operators may DELETE rows or drop the table when decommissioning an installation. Uninstalling the GitHub App does not currently auto-delete feedback rows (same posture as ReviewSession history).

FindingFeedbackService.summarize(repository) and summarizeAll() return per-repo useful / not_useful counts for a future ContextProvider. The dashboard exposes the same aggregates at GET /api/dashboard/feedback (session cookie required; optional ?repository=owner/repo).

  • FindingFeedback / FindingFeedbackRepository / FindingFeedbackService
  • FindingFeedbackCaptureService — poll + heuristics
  • GitHubReactionClient.listReviewCommentReactions
  • WebhookController — schedules capture on review-thread replies
  • ReviewOrchestrator — capture pass on follow-up reviews