Bug Report
Summary
PRHealthWorkflow.score_pr() always inserts a new PRHealthScore row on every call. Because it's triggered on both opened and synchronize PR events, every push to a PR branch creates a new row. A PR with 30 force-pushes accumulates 30 rows. Over time this makes the pr_health_scores table grow without bound and corrupts averages and dashboard stats.
Location
app/workflows/prhealth.py — score_pr() (~line 48)
app/github/webhooks.py — _handle_pull_request() (line ~190–196)
Root Cause
# prhealth.py — always inserts, never updates
record = PRHealthScore(
owner=owner, repo=repo, pr_number=pr_number, ...
)
db.add(record) # ← new row every time, no upsert
# webhooks.py — fires on opened AND synchronize
if action in ("opened", "synchronize", "reopened"):
await wf_health.score_pr(ctx, payload)
Impact
pr_health_scores table grows proportionally to commits × PRs with no cleanup mechanism
/api/v1/pr-health and /api/v1/repos/stats return inflated counts and incorrect averages (all historical rows for the same PR are averaged together rather than using the latest score)
- Dashboard PR health charts show duplicate entries for the same PR number
Expected Behavior
Re-scoring a PR should update the existing row for that (owner, repo, pr_number), not insert a new one.
Suggested Fix
Upsert instead of insert:
from sqlalchemy.dialects.postgresql import insert as pg_insert
stmt = pg_insert(PRHealthScore).values(
owner=owner, repo=repo, pr_number=pr_number, ...
).on_conflict_do_update(
index_elements=["owner", "repo", "pr_number"],
set_={...}
)
await db.execute(stmt)
Or add a UniqueConstraint("owner", "repo", "pr_number") to the model and use SQLAlchemy merge(). A migration adding this unique constraint should also deduplicate existing rows.
Bug Report
Summary
PRHealthWorkflow.score_pr()always inserts a newPRHealthScorerow on every call. Because it's triggered on bothopenedandsynchronizePR events, every push to a PR branch creates a new row. A PR with 30 force-pushes accumulates 30 rows. Over time this makes thepr_health_scorestable grow without bound and corrupts averages and dashboard stats.Location
app/workflows/prhealth.py—score_pr()(~line 48)app/github/webhooks.py—_handle_pull_request()(line ~190–196)Root Cause
Impact
pr_health_scorestable grows proportionally to commits × PRs with no cleanup mechanism/api/v1/pr-healthand/api/v1/repos/statsreturn inflated counts and incorrect averages (all historical rows for the same PR are averaged together rather than using the latest score)Expected Behavior
Re-scoring a PR should update the existing row for that
(owner, repo, pr_number), not insert a new one.Suggested Fix
Upsert instead of insert:
Or add a
UniqueConstraint("owner", "repo", "pr_number")to the model and use SQLAlchemymerge(). A migration adding this unique constraint should also deduplicate existing rows.