Immutable
release. Only release title and notes can be modified.
Review precision: confidence now decides where a finding lands, newly-added parsers and regexes are stress-tested for their own failure modes, and several classes of false positive are guarded at both the generator and the verifier. Operators gain configurable CI-gating and blocking strictness, structured skip reasons, and per-model generation parameters.
Added
- Mock-fidelity review check (#111): when a PR changes tests, the review prompt compares stubs/mocks (
when/doThrow/doReturn) against the real collaborator's contract when that definition is already in the provided material, and flags contradictions (e.g. a mock that throws an exception the real method swallows) at low/medium confidence instead of treating the green test as proof. Softens the related-tests framing that previously reinforced unfaithful stubs; the skeptical verifier gains a matching rule. Broader cross-file collaborator retrieval remains with #55 - Structured skip transparency for automatic reviews (#341): every path that skips an automatic review (draft, base-branch and label gates,
/pause, rate window, duplicate webhook delivery, rejected dispatch) now emits a structured reason code — aAutomatic review skipped [reason=...]log line, athrillhouse.review.skipsOTLP counter tagged withreasonandrepository, and per-reason counts on the dashboard summary endpoint (skippedReviewsByReason). README gains a "PR opened but no review posted" troubleshooting checklist - Bug-fix efficacy check (#110): when a PR declares itself a bug fix (the PR-template "Bug fix" checkbox or a
Fixes/Closes/Resolves #Nreference), the review prompt now extracts the concrete failure trigger from the PR description and the linked issues' text (fetched best-effort, up to 3 issues) and verifies the change actually alters behavior on that trigger's path — a locally-correct fix that the stated trigger never reaches is reported as a finding instead of passing silently, and when the deciding code is outside the diff the verdict is held at low confidence as a verification request rather than approved - Finding feedback capture for the learnings pipeline: records maintainer 👍/👎 reactions (and conservative "not useful" reply heuristics) on bot finding comments into a
finding_feedbacktable, with per-repo aggregates onGET /api/dashboard/feedbackand a documented data model/retention policy (docs/FEEDBACK.md). GitHub Apps have noreactionwebhook, so reactions are polled via the Reactions API on review-thread replies and follow-up reviews. Feedback is permission-gated in both directions: only verified write-capable collaborators reacting on bot-authored finding threads are recorded, andGET /api/dashboard/feedbackreturns only repositories the authenticated user can access — so the endpoint cannot be used to enumerate activity on repos you are not a member of. Capture runs on a bounded executor that prioritizes newer findings and drops work rather than queueing without limit, and review logs no longer carry source-line contents at INFO. Precursor to cross-review learnings (#38); does not yet feed prompts (#324) - Adversarial failure-mode characterization for new heuristics (#123): when a diff introduces parsing, regex, validation, or heuristic code — a
Pattern.compile, a tokenizer, a normalize step, a scope window or threshold constant — the reviewer switches those hunks from happy-path reading into decision-boundary characterization: it synthesizes the inputs that probe the rule's edges (a lambda against a paren-counting regex, an NBSP against an ASCII whitespace class, a token inside a fenced code block against a "starts with" check, a present-but-wrong-shape value against a presence check), names them literally, and reports false negatives as well as false positives. The triggering input is absent from the diff by definition, so the verifier gains a matching exemption from the verbatim-quote rule — without it the quote requirement rejects this entire class. Findings land at low/medium confidence as verification requests, and a synthesized failure is only confirmed when the expected domain or contract is visible in the material — a contract-free probe stays a low-confidence verification request. Executing the synthesized inputs is #96. The trigger spans languages: explicit regex construction (Java, JS/TS, Python, Go, C#, Kotlin), JS/TS regex literals andfunction/arrow validators, declared parse/validate/tokenize members including package-private Java methods, and construction split across lines via a bounded, file-reset-aware window. It stays deliberately narrow so ordinarysubstring/indexOf/trim/parseIntcode does not trigger it (dogfood: three review rounds on PR #114 returned "no issues" while human review found ~10 precision/recall defects in exactly this kind of code) - Configurable CI gating strictness for APPROVE (#322):
REVIEW_CI_GATINGchooses how CI status factors into approval —strict(default) holds APPROVE while required CI is pending, failing, or unreadable;warnallows APPROVE but records the CI uncertainty in the summary and check run;offdecides on findings alone - Configurable blocking strictness (#323):
REVIEW_BLOCKING_STRICTNESSsets when findings escalate toREQUEST_CHANGES—balanced(default: CRITICAL/HIGH at high confidence),strict(any CRITICAL/HIGH), orlenient(CRITICAL at high confidence only), so a repo can tune how loudly the bot blocks without editing prompts - Model generation parameters (#64):
frequency-penalty,presence-penaltyandseedjoin the existing per-model settings underthrillhousebot.ai.models.<model>.*, sent on every chat call when set.seedmakes a provider's sampling reproducible where supported, which is what lets the #113 eval corpus compare runs meaningfully
Changed
- Passing in-diff tests must exercise the claimed path before suppressing a finding (#116): the review and verifier prompts no longer treat a green test in the same diff as automatic disproof. A test may invalidate (generator) or reject (verifier) a finding only when it demonstrably exercises the claimed path — asserting on the path's output and stubbing collaborators into the relevant state, not leaving them unmocked so a default bypasses it (and not with stubs that contradict the real collaborator — see #111). When that exercise cannot be shown from the provided material, confidence is lowered with an explanation instead of dropping the finding (dogfood: PR #99 approve-path test green because
getPullRequestwas unmocked) - Low-confidence findings post in the summary instead of inline (#105): inline review comments are now gated on confidence — a low-confidence finding is listed in the summary body rather than anchored to a line. Uncertain claims still surface, but they stop occupying the position that reads as "this line is wrong", and they can no longer request changes on their own
- Exact-arithmetic and "this test fails" claims are capped and hedged (#97): a finding that rests on line-count, array-length, or index arithmetic the model performed by counting, or that asserts a specific test fails, is now capped at low confidence when nothing but counting backs it, and must be phrased as a verification request ("CI will confirm") rather than settled fact. The verifier gains the symmetric rule and rejects such a claim stated as fact with no execution or CI signal behind it — it cannot settle the question by recounting, being the same modality reading the same diff. The cap is evidence-dependent, not absolute: when an execution or CI signal in the provided material actually shows the failure, the finding keeps the confidence that evidence justifies instead of being forced low. Mirrors the existing "why would this test still pass" guard for the failure direction (dogfood: PR #84 produced a definitively-worded off-by-one — "the section is 7 lines, so 7 − 3 = 4 omitted" — against a test that passes as written, and the verifier re-did the same arithmetic and agreed)
- Dual-gate merge policy for contributors (#342): merging now requires both the static analysis gate and a ThrillhouseBot review, so neither signal alone can carry a change in. Affects anyone opening a PR against this repo rather than anyone running the bot
- Wider default ignored-files patterns (#52):
thrillhousebot.review.ignored-filesnow skips far more generated and vendored output out of the box —pnpm-lock.yaml,go.sum, protobuf output (*.pb.go,*_pb2.py), minified bundles and sourcemaps (*.min.js,*.min.css,*.map), and the directoriesnode_modules/,dist/,build/,out/,.next/,vendor/,__pycache__/,.venv/,bin/,obj/, alongside the previous lockfile/pom.xml/target/set. Less budget burned on artifacts nobody reviews. Worth checking on upgrade: the directory globs match by name, so a repository that keeps handwritten source underbuild/,bin/,out/orvendor/will stop having it reviewed — narrow the list per deployment if that applies to you
Fixed
- False parameter-nullability / precondition findings when the caller is outside the diff: a finding could assert a method parameter may be null (or violates a precondition) and post at MEDIUM even when the only callers that supply the argument were unchanged and absent from the reviewed material — so nullability was assumed rather than demonstrated (a MEDIUM false positive on
DashboardAccessChecker.installedReposin PR #101 claimedaccountOwnercould be null while the unshowncheckAccess/evaluateAccesscallers already guarantee non-null). The reviewer now caps such claims to low confidence unless the calling code is present and shown to pass a violating value (or the changed signature itself declares a nullable contract such as@Nullable/Optional), and the verifier rejects them when neither the caller nor such a contract is in the material — with the PR #101 case embedded as an inline regression example (#107) - Findings survived a force-push that removed the lines they targeted (#336): when a rebase or amend made a targeted diff hunk disappear, prior findings anchored there were still carried forward and re-reported against code that no longer existed. Presence is now re-checked against the current diff and findings whose anchors are gone are invalidated instead of re-raised
- False injection and constructor findings on framework-idiomatic code (#337): the reviewer flagged idiomatic framework usage as broken — most visibly a "missing no-arg/default constructor" on a CDI/Quarkus bean whose constructor is annotated
@Inject(and the Spring@Autowiredequivalent), where constructor injection is the documented idiom and needs no such constructor. The generator and verifier now recognise these shapes and refuse the claim rather than posting it - Duplicate CI-pending comment when the summary already listed the pending checks (#334): a follow-up COMMENT review announcing pending CI could post alongside a summary that already enumerated the same checks, telling maintainers the same thing twice. The extra comment is now suppressed unless the summary did not actually post
Performance
- Pure renames no longer consume AI review budget (#386): a rename with no content change contributes an empty hunk, so it was spending token budget while carrying no reviewable text. Renamed files are excluded from the reviewable diff (still passed to the related-tests and mock-fidelity context so test moves stay visible), leaving more of the budget for files that actually changed
- Deduplicated work on the follow-up backstop hot path (#135): the #118 backstop rebuilt the
DiffLineResolver, re-parsed prior AI responses, and copied the status list more than once per review. Each is now built once and shared across the pass
Dependencies
- Bumped the Quarkus platform group, the frontend npm-minor-patch group,
@testing-library/jest-domto 7.0.0, the website docs-minor-patch group,dompurifyto 3.4.12,svgoto 4.0.2, and the GitHub Actions minor/patch group - The docs site now requires Node 22 and pins PostCSS 8.5.23 and Sharp 0.35.3, so a clean
npm cion npm 11 resolves without known high-severity advisories
What's Changed
Features
- fix(review): clear the Sonar findings and coverage gaps on the release diff (#427) by @devops-thiago in #428
- feat(release): credit contributors automatically in the release notes by @devops-thiago in #432
- Release/v0.5.0 by @devops-thiago in #427
Fixes
- fix(release): webhook env docs and feedback repo case matching by @devops-thiago in #431
- fix(config): warn when a per-model env var maps to nothing by @devops-thiago in #433
Other changes
- fix(sonar): clear maintainability issues introduced on main by @devops-thiago in #383
- fix(docs): repair architecture Mermaid diagrams on the docs site by @devops-thiago in #385
- docs: remove accidental review-quality evaluation probe by @devops-thiago in #388
- feat(ai): expose model generation parameters (frequency/presence penalties, seed) (#64) by @devops-thiago in #389
- fix(review): suppress duplicate CI-pending COMMENT only when the summary actually posted (#334) by @devops-thiago in #390
- ci: dual-gate merge policy (static + ThrillhouseBot) (#342) by @devops-thiago in #391
- feat(review): configurable blocking strictness (#323) by @devops-thiago in #392
- feat(review): capture maintainer finding feedback for learnings (#324) by @devops-thiago in #394
- fix(review): framework-aware false-positive guards for injection/constructor claims (#337) by @devops-thiago in #396
- fix(review): invalidate findings when targeted diff hunks disappear on force-push (#336) by @devops-thiago in #397
- feat(review): eval/regression corpus for the review and verifier prompts (#113) by @devops-thiago in #400
- feat(review): verify a bug-fix PR changes behavior for its stated trigger (#110) by @devops-thiago in #399
- feat(observability): surface why automatic review was skipped (#341) by @devops-thiago in #398
- feat(review): configurable CI gating strictness for APPROVE (#322) by @devops-thiago in #393
- perf(review): dedupe DiffLineResolver, prior-response parse, and status copy (#135) by @devops-thiago in #395
- feat(review): gate inline posting on confidence (#105) by @devops-thiago in #407
- feat(review): flag tests whose mocks contradict real collaborator behavior (#111) by @devops-thiago in #409
- fix(review): cap/reject precondition findings whose caller isn't in the diff (#107) by @devops-thiago in #406
- feat(review): require path exercise before a green test suppresses a finding (#116) by @devops-thiago in #408
- feat(review): downgrade exact-arithmetic claims and add a symmetric "test fails" self-check (#97) by @devops-thiago in #419
- feat(review): adversarially stress-test newly-added parsers/regex/validators for their own failure modes (#123) by @devops-thiago in #420
- test(webhook): remove the interrupt-test race that fails CI with UnnecessaryStubbing by @devops-thiago in #421
- test(frontend): add Vitest coverage for the overview and sessions dashboard pages (#15, #16) by @devops-thiago in #422
- test(review): drive the real backstop computation through review() (#136) by @devops-thiago in #424
- fix(release): address v0.5.0 audit findings by @devops-thiago in #423
- docs(changelog): record the v0.5.0 changes missing from [Unreleased] by @devops-thiago in #425
- chore(release): cut v0.5.0 — version bump, changelog date, docs freeze by @devops-thiago in #426
- feat(review): enhance ignored files configuration and add tests for default patterns by @matheusandre1 in #429
- docs(changelog): correct the v0.5.0 entries the post-audit commits invalidated by @devops-thiago in #430
New Contributors
- @matheusandre1 made their first contribution in #429
Full Changelog: v0.4.0...v0.5.0