Commit Graph

115 Commits

Author SHA1 Message Date
Rodin 9e15b73a23 revert: remove YAML support, keep JSON-only
PR Ready Gate / clear-labels (pull_request) Successful in 2s
CI / test (pull_request) Successful in 15s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 28s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 30s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 51s
The external dependency (goccy/go-yaml) violates the repository's
stdlib-only convention (CONVENTIONS.md). While YAML provides better
readability for multi-line strings, the convenience doesn't justify
breaking a hard rule.

Reverts:
- External dependency on github.com/goccy/go-yaml
- YAML parsing logic in persona.go
- YAML persona files (restored as JSON)
- YAML-specific tests
- Design document (feature rejected)

The persona files work fine with JSON. Multi-line strings use \n escapes
which is less pretty but acceptable for internal files.

This addresses all MAJOR findings from review bots regarding the external
dependency violation.
2026-05-10 13:34:09 -07:00
Rodin 006b7a3b27 feat: add YAML support for persona files (#57)
CI / test (pull_request) Successful in 9m33s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 10m1s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 10m39s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 11m6s
- Add github.com/goccy/go-yaml dependency (v1.19.2)
- Update parsePersona to detect format by file extension
- Support both .yaml and .yml extensions (case-insensitive)
- Convert built-in personas to YAML format
- Add comprehensive tests for YAML parsing
- Update README with YAML examples and documentation

YAML provides cleaner multi-line strings via literal block scalars
and supports comments, making persona definitions more readable.
JSON remains supported for backwards compatibility.

Closes #57
2026-05-10 13:08:06 -07:00
rodin 230419f0e2 Merge pull request 'feat: native SAP AI Core support' (#54) from feat/aicore-provider-v2 into main
CI / test (push) Successful in 14s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
feat: native SAP AI Core support (#54)
2026-05-10 20:03:32 +00:00
Rodin 7dab35de41 feat: native SAP AI Core support
PR Ready Gate / clear-labels (pull_request) Successful in 2s
CI / test (pull_request) Successful in 14s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 35s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m30s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 2m0s
Add native SAP AI Core provider that handles OAuth token management and
deployment discovery automatically. This eliminates the need for the
external LLM proxy when running in SAP environments.

Changes:
- Add AICoreClient with OAuth token caching and deployment URL discovery
- Support both Anthropic and OpenAI models via AI Core deployments
- Update CI to use native AI Core provider
- Update action inputs to accept AI Core credentials
- Update README with AI Core configuration examples

Model names must match AI Core deployment names (e.g. anthropic--claude-4.6-sonnet, gpt-5).
2026-05-10 10:25:10 -07:00
aweiker c41c9590b7 Merge pull request 'feat(persona): add role-based review personas' (#55) from issue-51 into main
CI / test (push) Successful in 12s
CI / review (/anthropic/v1, anthropic--claude-4.6-sonnet, sonnet, anthropic, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
Reviewed-on: #55
Reviewed-by: security-review-bot <10+security-review-bot@noreply.gitea.weiker.me>
Reviewed-by: Aaron Weiker <aaron@weiker.org>
2026-05-10 17:16:10 +00:00
Rodin 4dd67742f9 fix: address review feedback on persona feature
PR Ready Gate / clear-labels (pull_request) Successful in 2s
CI / test (pull_request) Successful in 15s
CI / review (/anthropic/v1, anthropic--claude-4.6-sonnet, sonnet, anthropic, SONNET_REVIEW_TOKEN) (pull_request) Successful in 43s
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m28s
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m55s
MAJOR fixes:
- Remove external YAML dependency (github.com/goccy/go-yaml)
  Per project convention: Go standard library only, zero dependencies.
  Convert all persona files from YAML to JSON format.
- Fix TestValidateWorkspacePath error expectation
  Go 1.21+ filepath.Join normalizes absolute paths differently.

MINOR fixes:
- Remove custom contains helper in persona_test.go (use strings.Contains)
- Add Unicode-safe CapitalizeFirst function for header titles
- ListBuiltinPersonas returns empty slice instead of nil on error
- Fix test comment about filepath.Join behavior

Documentation:
- Update README to reflect JSON-only persona format
- Update design doc with note about JSON decision
- Fix action.yml description for persona-file input
2026-05-10 10:01:34 -07:00
Rodin 57e62a345f feat(persona): add role-based review personas
PR Ready Gate / clear-labels (pull_request) Successful in 2s
CI / test (pull_request) Successful in 9m31s
CI / review (/anthropic/v1, anthropic--claude-4.6-sonnet, sonnet, anthropic, SONNET_REVIEW_TOKEN) (pull_request) Successful in 10m3s
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 11m30s
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 10m56s
Add persona system for specialized review roles. Each persona defines:
- A specific review focus (security, architecture, documentation)
- Custom system prompt additions
- Personality/tone adjustments

Built-in personas: security, architect, docs
Custom personas: load from JSON via persona-file flag

Includes workspace validation to prevent path traversal attacks.

Closes #51
2026-05-10 09:14:48 -07:00
Rodin 44d6fa9d57 ci: always run ready gate on synchronize
CI / test (push) Successful in 13s
CI / review (/anthropic/v1, anthropic--claude-4.6-sonnet, sonnet, anthropic, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
Remove conditional - just always try to clear the labels. The curl
commands handle missing labels gracefully with || true.
2026-05-10 08:47:36 -07:00
Rodin 4ea41e164e ci: add ready label to PR ready gate
CI / test (push) Successful in 14s
CI / review (/anthropic/v1, anthropic--claude-4.6-sonnet, sonnet, anthropic, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
Also clear the ready label (ID 38) on push, matching gargoyle behavior.
2026-05-10 08:44:24 -07:00
aweiker 0e3c85f05c Merge pull request 'ci: add PR ready gate to clear self-reviewed label on push' (#56) from ci/pr-ready-gate into main
CI / test (push) Successful in 15s
CI / review (/anthropic/v1, anthropic--claude-4.6-sonnet, sonnet, anthropic, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
Reviewed-on: #56
Reviewed-by: security-review-bot <10+security-review-bot@noreply.gitea.weiker.me>
Reviewed-by: Aaron Weiker <aaron@weiker.org>
2026-05-10 15:41:37 +00:00
Rodin b24c4dcc86 ci: add PR ready gate to clear self-reviewed label on push
CI / test (pull_request) Successful in 14s
CI / review (/anthropic/v1, anthropic--claude-4.6-sonnet, sonnet, anthropic, SONNET_REVIEW_TOKEN) (pull_request) Successful in 26s
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m10s
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m5s
When a PR is pushed after being marked self-reviewed, the label is now
stale and should be removed. This matches the gargoyle CI behavior.

On synchronize:
- Remove self-reviewed label if present
- Reassign PR back to the author
2026-05-10 08:39:19 -07:00
aweiker 4bb3a2f960 Merge pull request 'fix: skip posting review when HEAD moves during evaluation' (#53) from fix/stale-commit-check into main
CI / test (push) Successful in 15s
CI / review (/anthropic/v1, anthropic--claude-4.6-sonnet, sonnet, anthropic, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
Reviewed-on: #53
Reviewed-by: Aaron Weiker <aaron@weiker.org>
Reviewed-by: security-review-bot <10+security-review-bot@noreply.gitea.weiker.me>
2026-05-10 15:26:11 +00:00
Rodin ced1fa7ffd ci: fix model names to match SAP AI Core deployments
CI / test (pull_request) Successful in 14s
CI / review (/anthropic/v1, anthropic--claude-4.6-sonnet, sonnet, anthropic, SONNET_REVIEW_TOKEN) (pull_request) Successful in 26s
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 35s
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 50s
- Restore sonnet reviewer with correct model name (anthropic--claude-4.6-sonnet)
- Remove gpt-4.1, gpt-4.1-mini, gpt-5-mini (not deployed on SAP AI Core)
- Keep gpt-5 and security reviewers

The previous model names (claude-sonnet-4-6, etc.) were incorrect —
SAP AI Core uses 'anthropic--claude-4.6-sonnet' format.
2026-05-10 08:23:10 -07:00
Rodin 6b615c77d5 ci: remove unavailable models from review matrix
CI / test (pull_request) Successful in 15s
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 38s
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 49s
Models claude-sonnet-4-6, gpt-4.1, gpt-4.1-mini, and gpt-5-mini are not
deployed on the LLM proxy, causing 502 errors. Keep only gpt-5 which
is the only available model.
2026-05-10 03:15:04 -07:00
Rodin b43b86a4a5 fix: skip posting review when HEAD moves during evaluation
CI / test (pull_request) Successful in 13s
CI / review (/anthropic/v1, claude-sonnet-4-6, sonnet, anthropic, SONNET_REVIEW_TOKEN) (pull_request) Failing after 13s
CI / review (/openai/v1, gpt-4.1, gpt41, openai, GPT_REVIEW_TOKEN) (pull_request) Failing after 13s
CI / review (/openai/v1, gpt-4.1-mini, gpt41-mini, openai, GPT_REVIEW_TOKEN) (pull_request) Failing after 13s
CI / review (/openai/v1, gpt-5-mini, gpt5-mini, openai, GPT_REVIEW_TOKEN) (pull_request) Failing after 13s
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 53s
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m3s
When a new push arrives while review-bot is processing, the review
would be posted against a stale commit. This causes noise in the
PR timeline with findings that reference code that no longer exists.

Before posting, re-fetch PR metadata and compare HEAD SHA with the
commit we evaluated against. If they differ, log a warning and exit
successfully — a new workflow run should already be processing the
new HEAD.

Fixes #52
2026-05-09 23:18:13 -07:00
aweiker 2089ca0f2d Merge pull request 'fix: retry on transient LLM response body truncation' (#48) from fix/response-body-truncation into main
CI / test (push) Successful in 12s
CI / review (/anthropic/v1, claude-sonnet-4-6, sonnet, anthropic, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-4.1, gpt41, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-4.1-mini, gpt41-mini, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5-mini, gpt5-mini, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
Reviewed-on: #48
Reviewed-by: Aaron Weiker <aaron@weiker.org>
2026-05-08 02:32:37 +00:00
claw db479d0ff4 fix: retry on transient LLM response body truncation
CI / test (pull_request) Successful in 15s
CI / review (/openai/v1, gpt-4.1, gpt41, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 25s
CI / review (/openai/v1, gpt-4.1-mini, gpt41-mini, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 29s
CI / review (/anthropic/v1, claude-sonnet-4-6, sonnet, anthropic, SONNET_REVIEW_TOKEN) (pull_request) Successful in 49s
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 50s
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m15s
CI / review (/openai/v1, gpt-5-mini, gpt5-mini, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 52s
Addresses intermittent 'unexpected end of JSON input' failures where the
LLM response body is truncated in transit between the proxy and client.

Root cause: network-level truncation where io.ReadAll returns partial data
(observed in 3/50 CI runs through HAI proxy). The response body reading
was already using io.ReadAll correctly, but transient network issues
between the proxy and client can still cause partial reads.

Changes:
- Add Content-Length validation in doRequest: detect when fewer bytes
  arrive than the server declared, triggering a retry
- Add retry logic in Complete: retries once on retryable errors (body
  read failures, content-length mismatches) with a 500ms backoff
- Add parse-level retry in main: if ParseResponse fails, re-requests
  from the LLM once before giving up (defensive, since retries always
  succeed per issue evidence)
- Improve ParseResponse error diagnostics: log raw vs cleaned lengths
  and a preview of the cleaned content to aid future debugging

Does NOT retry on API errors (4xx/5xx) or structural issues — only
transient body read problems.

Closes #47
2026-05-07 00:44:32 -07:00
rodin cabbb5a55a fix: repair unescaped quotes in LLM JSON responses (#45)
CI / test (push) Successful in 14s
CI / review (/anthropic/v1, claude-sonnet-4-6, sonnet, anthropic, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-4.1, gpt41, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-4.1-mini, gpt41-mini, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5-mini, gpt5-mini, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
Release / release (push) Successful in 34s
fix: repair unescaped quotes in LLM JSON responses

Add repairJSON fallback that handles unescaped quotes in LLM string
values using first-valid-candidate heuristic with structural lookahead.

Reviewed-by: sonnet-review-bot
Reviewed-by: gpt-review-bot
Reviewed-by: security-review-bot
v0.3.2
2026-05-05 12:40:39 +00:00
rodin 55cf3fd4b9 Merge pull request 'ci: fix reviewer models — sonnet uses Anthropic, gpt uses GPT-5' (#44) from fix/sonnet-reviewer into main
CI / test (push) Successful in 13s
CI / review (/anthropic/v1, claude-sonnet-4-6, sonnet, anthropic, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-4.1, gpt41, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-4.1-mini, gpt41-mini, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
CI / review (/openai/v1, gpt-5-mini, gpt5-mini, openai, GPT_REVIEW_TOKEN) (push) Has been skipped
ci: fix reviewer models — sonnet uses Anthropic, gpt uses GPT-5
2026-05-05 04:20:54 +00:00
Rodin f48288bf2e fix: address review feedback — tokens, secrets, no hardcoded IPs
CI / test (pull_request) Successful in 14s
CI / review (/anthropic/v1, claude-sonnet-4-6, sonnet, anthropic, SONNET_REVIEW_TOKEN) (pull_request) Successful in 22s
CI / review (/openai/v1, gpt-4.1-mini, gpt41-mini, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 21s
CI / review (/openai/v1, gpt-4.1, gpt41, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 22s
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 45s
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 52s
CI / review (/openai/v1, gpt-5-mini, gpt5-mini, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 48s
- Fix token_secret for gpt41/gpt5-mini/gpt41-mini: use GPT_REVIEW_TOKEN
  instead of SONNET_REVIEW_TOKEN (wrong reviewer identity)
- Move LLM base URL back to secrets.LLM_BASE_URL (prevents exfiltration
  via PR-controlled matrix values)
- Remove hardcoded internal IP from workflow file; only provider path
  suffix (/anthropic/v1, /openai/v1) remains in matrix

Addresses: security-review-bot REQUEST_CHANGES (major: exfiltration risk,
minor: HTTP/hardcoded IP) and sonnet-review-bot REQUEST_CHANGES (major:
wrong token_secret on gpt entries).
2026-05-03 08:42:08 -07:00
Rodin b4c994d0fa ci: fix reviewer models — sonnet uses Anthropic, gpt uses GPT-5
CI / test (pull_request) Successful in 14s
CI / review (http://100.86.77.84:6655/openai/v1, gpt-4.1-mini, gpt41-mini, openai, SONNET_REVIEW_TOKEN) (pull_request) Successful in 19s
CI / review (http://100.86.77.84:6655/openai/v1, gpt-4.1, gpt41, openai, SONNET_REVIEW_TOKEN) (pull_request) Successful in 22s
CI / review (http://100.86.77.84:6655/anthropic/v1, claude-sonnet-4-6, sonnet, anthropic, SONNET_REVIEW_TOKEN) (pull_request) Successful in 24s
CI / review (http://100.86.77.84:6655/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m14s
CI / review (http://100.86.77.84:6655/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 54s
CI / review (http://100.86.77.84:6655/openai/v1, gpt-5-mini, gpt5-mini, openai, SONNET_REVIEW_TOKEN) (pull_request) Successful in 55s
The matrix was wrong: "sonnet" was running GPT-5 and "gpt" was running
GPT-4.1. Now:
- sonnet → Claude Sonnet 4.6 via HAI Anthropic endpoint
- gpt → GPT-5 via HAI OpenAI endpoint
- security → GPT-5 via HAI OpenAI endpoint

Each matrix entry specifies its own provider and base_url.
2026-05-02 21:06:11 -07:00
rodin 8d8a249481 Merge pull request 'fix: supersede ALL old reviews, not just the most recent' (#43) from fix/supersede-all-old-reviews into main
CI / test (push) Successful in 13s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
Release / release (push) Successful in 31s
v0.3.1
2026-05-02 20:35:23 +00:00
Rodin a0fd882b0d fix: address review findings
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 24s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 37s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m4s
- Tighten timeline matching: also check ev.User.Login matches
  the review author (prevents collision on identical body prefix)
- Remove unused sharedTokenMode variable (inline condition)
- Aggregate resolution failures with warn-level summary
2026-05-02 13:31:59 -07:00
Rodin d4bf13eeab fix: supersede ALL old reviews, not just the most recent
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 22s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 46s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m7s
Previously findOwnReview returned only the single most-recent matching
review, so on PRs with multiple force-pushes only the latest old review
got superseded. The rest accumulated as unsuperseded stale reviews.

Changes:
- Add findAllOwnReviews() to collect all non-superseded matching reviews
- Loop over all old reviews in the supersede phase
- Add GetTimelineReviewCommentIDForReview() to find comment IDs by
  review ID (fetches review body, matches in timeline by prefix)
- Each old review gets independently superseded and its inline comments
  resolved

The old findOwnReview is kept for backward compat (tested, may be
useful as a utility).
2026-05-02 13:28:03 -07:00
rodin 23443ef378 Merge pull request 'feat: resolve old inline comments when superseding review' (#42) from feat/27-resolve-inline-comments into main
CI / test (push) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
Release / release (push) Successful in 32s
v0.3.0
2026-05-02 19:18:41 +00:00
Rodin bc5a4a1dcd feat: resolve old inline comments when superseding review
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 22s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 44s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 46s
Closes #27

After superseding an old review, resolves all its inline comments via
POST /pulls/comments/{id}/resolve. This clears unresolved conversation
markers from the PR timeline and diff view.

New API methods:
- ListReviewComments: paginated GET /repos/.../pulls/{n}/reviews/{id}/comments
- ResolveComment: POST /repos/.../pulls/comments/{id}/resolve

Behavior:
- Only resolves after successful supersede (gated on supersedeOK)
- Aggregates failures and logs at warn level
- Truncates error bodies to 256 bytes (security)
- Non-fatal: review still posts even if resolution fails
2026-05-02 12:15:52 -07:00
rodin d30f3d4278 Merge pull request 'feat: self-request as reviewer before posting' (#41) from feat/35-self-request-reviewer into main
CI / test (push) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
2026-05-02 19:11:15 +00:00
Rodin 2507ee22e7 fix: address review findings on RequestReviewer
CI / test (pull_request) Successful in 13s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 21s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 35s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m3s
- Accept 204 No Content as success (idempotent operations)
- Truncate error response body to 256 bytes (prevent log leakage)
- Add unit tests for GetAuthenticatedUser and RequestReviewer
2026-05-02 12:09:25 -07:00
Rodin c39845ca03 feat: self-request as reviewer before posting
CI / test (pull_request) Successful in 13s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 21s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 48s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 58s
Closes #35

Before posting a review, the bot:
1. Discovers its own Gitea login via GET /user
2. Calls POST /requested_reviewers to add itself

This ensures the bot appears in the required-reviewers list without
manual configuration on the repo. The call is idempotent (no-op if
already requested).

Both failures are non-fatal (warn + continue) — the review still posts
even if the self-request fails.
2026-05-02 12:04:55 -07:00
rodin cd601bdcf4 Merge pull request 'fix: trim trailing slash from giteaURL when building review link' (#40) from fix/url-normalization into main
CI / test (push) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
2026-05-02 18:52:13 +00:00
Rodin 50091941e1 fix: trim trailing slash from giteaURL when building review link
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 20s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 28s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 41s
Prevents double-slash in supersede URL if GITEA_URL ends with '/'.
Aligns with how gitea.NewClient already normalizes the base URL.
2026-05-02 11:49:24 -07:00
rodin ed06cdd942 Merge pull request 'fix: post new review first, then supersede old with link' (#39) from fix/34-supersede-order into main
CI / test (push) Successful in 13s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
2026-05-02 18:46:50 +00:00
Rodin ed69d26e87 fix: post new review first, then supersede old with link
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 22s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 44s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m8s
Changes the order of operations:
1. POST new review (gets non-stale badge immediately)
2. PATCH old review with superseded message linking to the new one

This gives the superseded comment a clickable link to the current
review, making navigation between review iterations easy.

buildSupersededBody now accepts a newReviewURL parameter.
2026-05-02 11:43:53 -07:00
rodin da586a512a Merge pull request 'feat: always post fresh review, supersede old with collapsed body' (#38) from feat/34-always-post-fresh into main
CI / test (push) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
2026-05-02 18:36:42 +00:00
Rodin f6baa41b2c fix: remove findOwnReviewStrict, use findOwnReview directly
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 23s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 42s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m31s
The strict authorship check compared reviewer-name to User.Login which
could mismatch. The sentinel is already role-specific (e.g.
<!-- review-bot:sonnet -->) and Gitea's API blocks editing others'
comments (403). Defense-in-depth via login comparison is unnecessary
complexity that introduced a bug. Removed.
2026-05-02 11:33:57 -07:00
Rodin ecbae332f4 fix: address review findings
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 23s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m17s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m22s
- findOwnReview: skip superseded reviews, pick highest ID (most recent)
- findOwnReviewStrict: verify authorship before superseding (defense-in-depth)
- buildSupersededBody: handle empty commitSHA gracefully
- Tests: add cases for superseded skip, highest-ID selection
2026-05-02 11:30:34 -07:00
Rodin fdd75699d9 feat: always post fresh review, supersede old with collapsed body
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 23s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m2s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m25s
Closes #34

- Remove reviewUnchanged() skip logic — every push gets a fresh review
- Remove edit-in-place (PATCH same body) — always POST new
- Supersede old review: PATCH with struck-through banner + collapsed
  original body in <details> for historical reference
- Add commit footer to every review: 'Evaluated against <sha>'
- Remove --update-existing flag (no longer needed)
- Add CommitID field to Review struct
- Add TestBuildSupersededBody tests
2026-05-02 11:26:06 -07:00
rodin dc450f7771 Merge pull request 'feat: improve test coverage for cmd/review-bot' (#37) from feat/32-test-coverage into main
CI / test (push) Successful in 13s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
2026-05-02 18:21:17 +00:00
Rodin 3a3c60a3c6 chore: retrigger reviews
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 22s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m20s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m24s
2026-05-02 11:19:04 -07:00
Rodin 504f616e99 fix: add coverage to .PHONY in Makefile (NIT)
CI / test (pull_request) Successful in 13s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 22s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 33s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m3s
2026-05-02 11:17:05 -07:00
Rodin bb596db3c1 feat: improve test coverage for cmd/review-bot
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 22s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 39s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m6s
Partially addresses #32

- Tests for setupLogger, isPatternFile, evaluateCIStatus, envOrDefault*, validateReviewerName
- Subprocess tests for main() error paths (version, missing flags, invalid inputs)
- Integration test scaffold (build tag: integration)
- Makefile with build/test/lint/coverage targets
- Coverage: 16.7% → 42.3% for cmd/review-bot
2026-05-02 11:13:59 -07:00
rodin cdd4f4fdf4 Merge pull request 'feat: replace log.Printf with structured slog logging' (#36) from feat/23-structured-logging into main
CI / test (push) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
2026-05-02 18:07:13 +00:00
Rodin d83ea4f726 feat: replace log.Printf with structured slog logging
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 23s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 52s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m5s
- Add --log-format flag (text/json) and --verbosity flag (debug/info/warn/error)
- Replace all log.Printf with slog.Info/Debug/Warn with structured key-value attrs
- Replace all log.Fatalf with slog.Error + os.Exit(1)
- Convert gitea/client.go warnings to slog.Warn
- Add comprehensive tests for logger initialization and level filtering

Closes #23
Partially addresses #32
2026-05-02 11:01:55 -07:00
Rodin 6c46220a53 docs: document runner requirements for composite action
CI / test (push) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
Add a Runner Requirements section to the README documenting that
the composite action needs python3, sha256sum, and curl on the
runner. All are pre-installed on ubuntu-* runners but custom
images need to provide them.

Closes #12
2026-05-02 10:21:53 -07:00
rodin d640eb6e71 Merge pull request 'fix: distinguish 404 in GetAllFilesInPath, make uploads idempotent' (#33) from fix/8-10-error-handling-idempotent-upload into main
CI / test (push) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
2026-05-02 17:07:22 +00:00
Rodin 2339999d37 fix: URL-encode asset filename, truncate error body in APIError
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 23s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 51s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m21s
- URL-encode filename in release upload query param (MINOR)
- Truncate APIError.Body to 200 chars in Error() to avoid leaking
  verbose server responses into logs (NIT)
2026-05-02 10:02:03 -07:00
Rodin bfca28b2b2 fix: address review findings from PR #33
CI / test (pull_request) Successful in 13s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 22s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m9s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m42s
- Wrap fileErr instead of err in GetAllFilesInPath fallback (MINOR)
- Use env var for asset name in release workflow to avoid quoting issues (NIT)
2026-05-02 09:58:41 -07:00
Rodin f047c994bf fix: distinguish 404 in GetAllFilesInPath, make uploads idempotent
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 22s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 58s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m7s
- Add APIError type with StatusCode field so callers can inspect HTTP
  status codes from Gitea API responses
- Add IsNotFound helper for ergonomic 404 checks
- GetAllFilesInPath now only falls back to single-file fetch on 404;
  all other errors (auth failures, server errors, rate limits) propagate
- Release workflow asset uploads are now idempotent: existing assets
  with the same name are deleted before re-upload on workflow re-runs

Closes #8
Closes #10
2026-05-02 09:50:35 -07:00
rodin b51a19d8b9 Merge pull request 'fix: remove worst-wins escalation logic' (#31) from fix/28-remove-escalation into main
CI / test (push) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
2026-05-02 16:46:05 +00:00
Rodin ceefa4c2e0 ci: use separate SECURITY_REVIEW_TOKEN for security reviewer
CI / test (pull_request) Successful in 13s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 23s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 41s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 58s
The security-review-bot Gitea user now has its own token. This
completes the token separation so each reviewer role posts under
its own identity, enabling native Gitea multi-reviewer blocking.
2026-05-02 07:25:43 -07:00