Skip to content

feat: add feedback insights view, closing the write-only gap in #823#845

Open
Rudra-clrscr wants to merge 2 commits into
Userunknown84:mainfrom
Rudra-clrscr:feature/823-feedback-insights
Open

feat: add feedback insights view, closing the write-only gap in #823#845
Rudra-clrscr wants to merge 2 commits into
Userunknown84:mainfrom
Rudra-clrscr:feature/823-feedback-insights

Conversation

@Rudra-clrscr

Copy link
Copy Markdown
Contributor

Summary

Related to #823.

Issue #823 asked for a feedback loop (thumbs up/down UI, /feedback endpoint,
persistence, retraining docs) — all of which already existed on main
(FeedbackWidget.jsx, /feedback in both api.py and
predictionRoutes.js, feedback_store.csv, retrain.py, and a README
section documenting all of it). Verified this directly before starting:
checked out a clean branch off upstream/main and ran the existing
test_feedback.py (6/6 passing).

The one real gap: feedback was completely write-only. Nothing read
feedback_store.csv back out except retrain.py (as a training corpus) —
there was no way to see what had been collected, how often the model's
predictions were being corrected, or what they were corrected to, without
opening the CSV by hand.

Changes

  • api.py: new GET /feedback/stats route (same
    validate_request/validate_internal_request gate as POST /feedback)
    that reads feedback_store.csv and returns total/corrections/
    correction_rate, a per-predicted-label breakdown of confirmations vs.
    corrections (and what each label gets corrected to), and the 20 most
    recent submissions (text truncated to 100 chars, matching the privacy
    posture already used elsewhere in this file for Sentry payloads).
  • predictionRoutes.js: matching GET /feedback/stats proxy, same
    pattern as the existing /spam-insights proxy.
  • frontend/src/components/FeedbackInsights.jsx: new component
    rendering this data (stat cards, a by-label breakdown table, a
    recent-submissions table), mounted inside SpamInsightsDashboard.jsx
    (the existing "Insights" tab) below the existing spam-pattern insights.
  • backend/tests/test_feedback.py: 4 new tests covering the empty
    case, correction/confirmation aggregation, the 20-item/most-recent-first
    cap, and text_preview truncation.
  • README: documents the new endpoint's response shape under the
    existing "User Feedback Loop" section.

Note: App.jsx and ManipulationIndex.jsx again carry the same
parse-error fixes from the pending fix/frontend-eslint-errors PR —
needed here for the same reason as prior issues this session (this branch
also forks from upstream/main before that fix lands, and
SpamInsightsDashboard is only reachable through App.jsx). Will need
reconciling with whichever PR merges first.

Test plan

  • cd backend && pytest tests/test_feedback.py -q — 10/10 pass
  • Verified live end-to-end against the real Flask API: submitted feedback,
    confirmed /feedback/stats aggregated it correctly against the actual
    production feedback_store.csv, then removed the test rows to leave
    that file exactly as it was (gitignored runtime data, not something to
    commit test pollution into)
  • cd backend && pytest tests/ -q (excluding two unrelated pre-existing
    collection errors already tracked separately) — 107 passed, same 5
    known pre-existing failures, no new regressions
  • cd frontend && npx vite build — succeeds
  • npx eslint on new/touched frontend files — clean (aside from one
    pre-existing, unrelated exhaustive-deps warning)

…nknown84#823

Issue Userunknown84#823 asked for a feedback loop (thumbs up/down UI, /feedback
endpoint, persistence, retraining docs) - all of which already existed
on main (FeedbackWidget.jsx, /feedback in both api.py and
predictionRoutes.js, feedback_store.csv, retrain.py, and a README
section documenting all of it). Verified this directly: checked out a
clean branch off upstream/main and ran the existing test_feedback.py
(6/6 passing) before starting this work.

The one real gap: feedback was completely write-only. Nothing read
feedback_store.csv back out except retrain.py (as a training corpus) -
there was no way to see what had been collected, how often the model's
predictions were being corrected, or what they were corrected to,
without opening the CSV by hand.

- api.py: new GET /feedback/stats route (same
  validate_request/validate_internal_request gate as POST /feedback)
  that reads feedback_store.csv and returns total/corrections/
  correction_rate, a per-predicted-label breakdown of confirmations vs.
  corrections (and what each label gets corrected to), and the 20 most
  recent submissions (text truncated to 100 chars, matching the privacy
  posture already used elsewhere in this file for Sentry payloads).
- predictionRoutes.js: matching GET /feedback/stats proxy, same pattern
  as the existing /spam-insights proxy.
- frontend/src/components/FeedbackInsights.jsx: new component rendering
  this data (stat cards, a by-label breakdown table, a recent-submissions
  table), mounted inside SpamInsightsDashboard.jsx (the existing
  "Insights" tab) below the existing spam-pattern insights.
- backend/tests/test_feedback.py: 4 new tests covering the empty case,
  correction/confirmation aggregation, the 20-item/most-recent-first cap,
  and text_preview truncation.
- README: documents the new endpoint's response shape under the existing
  "User Feedback Loop" section.

Verified live end-to-end against the real Flask API (submitted feedback,
confirmed /feedback/stats aggregated it correctly against the actual
production feedback_store.csv, then removed the test rows to leave that
file exactly as it was - it's gitignored runtime data, not something to
commit test pollution into).

App.jsx and ManipulationIndex.jsx again carry the same parse-error fixes
from the pending frontend-eslint-errors PR, needed here for the same
reason as the other issues worked this session (this branch also forks
from upstream/main before that fix lands, and SpamInsightsDashboard is
only reachable through App.jsx).
Copilot AI review requested due to automatic review settings July 13, 2026 20:49
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the Aditya Sharma's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

The container's Flask process defaults to FLASK_HOST=127.0.0.1 (a
deliberate secure default for bare-metal runs), so inside the CI
container it never listens on an interface reachable through the
-p 5000:5000 port mapping, and the smoke test's curl always times out.
docker-compose.yml already sets FLASK_HOST=0.0.0.0 for the same reason;
the CI workflow's docker run step needs the same override.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants