Skip to content

feat: per-response and general widget feedback#284

Merged
neuromechanist merged 2 commits into
developfrom
feature/issue-282-per-response-feedback
Jun 5, 2026
Merged

feat: per-response and general widget feedback#284
neuromechanist merged 2 commits into
developfrom
feature/issue-282-per-response-feedback

Conversation

@neuromechanist

Copy link
Copy Markdown
Member

Summary

Adds a feedback channel to the OSA chat widget and surfaces it to community admins.

  • Widget: thumbs up/down under each assistant reply (sentiment only, one-vote-lock, keyed to a new per-response request_id) plus a Send-feedback footer link opening a free-text modal for general feedback.
  • Backend: anonymous POST /feedback (the Cloudflare worker already proxies to it) writing to a new feedback_log table in the existing metrics.db (auto-created via CREATE TABLE IF NOT EXISTS; rides the osa-data volume). request_id is exposed on the chat/ask done event and ChatResponse/AskResponse. page_url is scheme-validated to prevent stored XSS in the admin view.
  • Admin: GET /metrics/feedback (per-community scoped key, strictly confined) and a Feedback panel on the status dashboard.

Closes #282

Test plan

  • 23 new tests (feedback_log table + write_feedback + summary/entries queries; POST /feedback validation and GET /metrics/feedback scoping). No mocks.
  • ruff clean; widget JS node --check valid; full api+metrics suite green (the only 2 failing tests in the repo are pre-existing .env-contamination failures, unrelated).

Widget: thumbs up/down under each assistant reply (sentiment only,
one-vote-lock, keyed to a new per-response request_id) plus a
Send-feedback footer link opening a free-text modal for general feedback.

Backend: anonymous POST /feedback (worker already proxies to it) writing
to a new feedback_log table in the existing metrics.db (auto-created via
CREATE TABLE IF NOT EXISTS; rides the osa-data volume). request_id is now
exposed on the chat/ask done event and ChatResponse/AskResponse. page_url
is scheme-validated to prevent stored XSS in the admin view.

Admin: GET /metrics/feedback (per-community scoped key, strictly confined)
and a Feedback panel on the status dashboard.

Tested: 23 new tests (db/queries + endpoint scoping); ruff clean.

Closes #282
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

Name Link
Preview URL https://feature-issue-282-per-respon-demo.osc.earth
Branch feature/issue-282-per-response-feedback
Commit 26840b5

This preview will be updated automatically when you push new commits.

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Dashboard Preview

Name Link
Preview URL https://feature-issue-282-per-respon.osa-dash.pages.dev
Branch feature/issue-282-per-response-feedback
Commit 26840b5

This preview will be updated automatically when you push new commits.

- FeedbackEntry: narrow to Literal types + __post_init__ enforcing the
  per-type invariants at the storage layer (last checkpoint before SQLite);
  add CHECK constraints + a UNIQUE index on feedback_id to the schema.
- feedback.py: move sentiment/comment normalization into a mode=before
  validator (drop object.__setattr__); remove the unreachable manual
  whitelist checks and the dead try/except (write_feedback never raises).
- write_feedback: acquire the connection inside the try so it honors its
  never-raises contract on a connect failure.
- Widget: submitResponseFeedback now awaits the POST and rolls back the
  optimistic vote (with an error) if it fails, instead of silently dropping.
- Tests: replace the mock-based fixture with a DATA_DIR env fixture; add
  __post_init__ invariant tests, write-failure counter + CRITICAL escalation,
  comments_only/offset/limit-floor coverage, data:/ftp page_url rejection,
  general-sentiment-stripping, request_id round-trip, cross-community admin
  aggregation; fix the no-op test_limit_clamped.
- Docs/comments: db module docstring, warning SSE event, request_id wording,
  widget/dashboard comment and error-message fixes.
@neuromechanist

Copy link
Copy Markdown
Member Author

PR review (pr-review-toolkit, 5 agents, sonnet) — findings addressed in c1d823c

Correctness / security

  • write_feedback had a dead try/except sqlite3.Error in the router (it never raises) — removed; write_feedback now also acquires its connection inside the try so it honors its never-raises contract. Misleading comment fixed.
  • Storage-layer invariants: FeedbackEntry narrowed to Literal types + __post_init__ rejecting illegal shapes (e.g. a response with no sentiment); added SQLite CHECK constraints + a UNIQUE index on feedback_id.
  • object.__setattr__ in the validator replaced with an idiomatic mode="before" normalizer; removed the now-unreachable manual whitelist checks.
  • Silent vote-drop: submitResponseFeedback now awaits the POST and rolls back the optimistic vote (with an error) on failure.

Tests (no mocks)

  • Replaced the unittest.mock.patch fixture with a DATA_DIR env fixture.
  • Added: __post_init__ invariant tests, write-failure counter + CRITICAL escalation, comments_only/offset/limit-floor, data:/ftp: page_url rejection, general-sentiment-stripping, request_id round-trip, cross-community admin aggregation; fixed the no-op test_limit_clamped. 38 feedback tests pass; 468 in the broader suite (1 pre-existing .env-contamination failure, unrelated).

Docs/comments: db module docstring, warning SSE event, request_id wording, widget/dashboard comment + error-message fixes.

Skipped (by design, noted): discriminated-union split for FeedbackRequest (the __post_init__ + Literal + CHECK trio gives the safety with less complexity); module-global failure-counter refactor (pre-existing pattern shared with log_request; tests reset it); redundant community_id echoed in the summary dict (intentional parallel with get_community_summary).

@neuromechanist neuromechanist merged commit 8d13bf5 into develop Jun 5, 2026
8 checks passed
@neuromechanist neuromechanist deleted the feature/issue-282-per-response-feedback branch June 5, 2026 02:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant