Skip to content

PRHealthScore inserts a new DB row on every synchronize event — unbounded table growth on active #87

Description

@BHUVANSH855

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.pyscore_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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is needed

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions