Skip to content

Add detailed feedback notifications and admin deep links - #785

Merged
kody-bot merged 5 commits into
mainfrom
cursor/feedback-discord-details-d866
Jul 19, 2026
Merged

kody-bot merged 5 commits into
mainfrom
cursor/feedback-discord-details-d866

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 19, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • expand the consent-gated admin event with full approved feedback and snapshotted submitter attribution
  • add an audited, role-gated /admin/platform-feedback?feedbackId=… review page and JSON endpoint
  • cancel queued delivery after deletion when possible and disclose that already-delivered external copies cannot be recalled

Testing

  • npm run validate passes: formatting, lint, typecheck, primitive map, 905 unit tests, 15 Playwright E2E tests, and 2 MCP E2E tests.
  • Focused migration, snapshot, deletion, queue, event, data-loader, handler, audit, and pagination tests pass.
  • Manual admin deep-link/JSON/XSS verification passes; injected script text stays escaped and window.__feedback_xss is undefined.
  • Two independent final privacy/UI reviews report CLEAN.

Walkthrough

admin_platform_feedback_deep_link_demo.mp4

System recap — extends existing primitives (medium risk)

Mode: recap · Base: main @ f161b9b3 · Head: aa15f275

Classification: extends — broadens the explicitly consented feedback event contract, snapshots attribution, and adds a role-gated review surface without adding a new primitive.

Primitives touched

Primitive Group Impact
platform-feedback assistant extends — approved content, identity snapshots, and deep-link event
app-ui surfaces extends — admin feedback list/detail page and privacy disclosure
rbac auth extends — guarded and audited browser review surface
d1-app-db storage extends — nullable submitter username/email snapshot columns
platform-feedback-dispatch-queue storage extends — late deletion recheck and permanent cancellation
saved-packages assistant extends — admin subscriber receives expanded consented event
mcp-server surfaces extends — exact-content notification consent guidance

System map

An approved submission snapshots identity in D1 but keeps the Queue body opaque; immediately before fan-out, Kody rechecks the row and builds a stable full-content event plus guarded admin deep link.

Legend: green = composes (wiring only) · amber = extended by this PR · red = new primitive · gray = context (unchanged, included only when an edge crosses it).

flowchart LR
	mcpServer["mcp-server<br/>MCP endpoint (/mcp)"]:::extended
	platformFeedback["platform-feedback<br/>Platform feedback"]:::extended
	d1AppDb["d1-app-db<br/>D1 app database"]:::extended
	feedbackQueue["platform-feedback-dispatch-queue<br/>Platform feedback dispatch queue"]:::extended
	rbac["rbac<br/>Role-based access control"]:::extended
	savedPackages["saved-packages<br/>Saved packages"]:::extended
	appUi["app-ui<br/>Browser app (Remix 3)"]:::extended
	mcpServer -->|"exact feedback + external-copy consent"| platformFeedback
	platformFeedback -->|"text + identity snapshot"| d1AppDb
	d1AppDb -->|"opaque feedbackId"| feedbackQueue
	feedbackQueue -->|"late row recheck and full stable event"| savedPackages
	rbac -->|"admin-only event owners and page guard"| savedPackages
	rbac -->|"GET /admin/platform-feedback"| appUi
	platformFeedback -->|"feedbackId deep link"| appUi
	classDef touched fill:#1a7f37,color:#fff
	classDef extended fill:#9a6700,color:#fff
	classDef added fill:#cf222e,color:#fff
	classDef untouched fill:#57606a,color:#fff
Loading

Invariants

  • Full text and profile identity are delivered only after explicit approval of the exact proposed feedback and external notification disclosure.
  • Queue messages remain opaque; event retries use immutable attribution snapshots from the feedback row.
  • Deletion before final payload construction cancels delivery; external copies already delivered may remain under operator retention controls.
  • Event and UI label user-authored fields untrusted and never treat embedded text as instructions or HTML.
  • The deep-link page and JSON endpoint require the admin role and do not expose unrelated user content.
Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Added an admin Platform Feedback page with filtering, pagination, detailed review, submitter information, content warnings, and audit tracking.
    • Admin notifications now include approved feedback text, submitter attribution, content warnings, and a direct review link.
    • Feedback submissions now require approval of the exact proposed content before submission.
  • Documentation

    • Expanded privacy, consent, notification, retention, and account-deletion guidance for platform feedback.
  • Bug Fixes

    • Pending feedback notifications are cancelled when account deletion occurs before delivery.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@coderabbitai

coderabbitai Bot commented Jul 19, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds an audited admin platform-feedback review route, persists submitter identity snapshots, expands the feedback subscription event with approved untrusted content and metadata, and changes queued delivery to reload by feedback ID with permanent cancellation after deletion. Documentation and MCP consent guidance are updated accordingly.

Changes

Platform feedback administration and delivery

Layer / File(s) Summary
Feedback contracts and persistence
packages/worker/migrations/*, packages/worker/src/platform-feedback/{types,repo,service,submitter-identity,subscription-event}.ts, packages/worker/src/app/loader-data.ts
Feedback records now persist nullable submitter username/email snapshots. Admin and subscription payloads include approved untrusted text, content warnings, submitter data, and trusted admin links while omitting unrelated fields.
Audited admin review surface
packages/worker/src/app/{admin-platform-feedback-data.ts,handlers/admin-platform-feedback.ts,router.ts,routes.ts}, packages/worker/client/routes/*platform-feedback*, packages/worker/src/app/loader-data.ts
A role-protected, audit-logged API and UI provide filtering, pagination, list/detail views, content warnings, and selected-feedback metadata.
Lazy subscription dispatch and cancellation
packages/worker/src/platform-feedback/{dispatch-queue,package-subscriptions,errors}.ts
Queue messages carry feedback IDs; dispatch reloads feedback immediately before invocation and acknowledges deleted feedback without retrying.
Consent, privacy, and contract documentation
docs/**, packages/worker/src/mcp/**, packages/worker/src/app/*test.ts, packages/worker/src/platform-feedback/*test.ts
Approval, attribution, untrusted-content handling, notification retention, authorization boundaries, migration behavior, and delivery semantics are documented and tested.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Admin
  participant AdminPlatformFeedbackRoute
  participant AdminFeedbackAPI
  participant FeedbackLoader
  participant FeedbackDatabase
  Admin->>AdminPlatformFeedbackRoute: open queue or detail URL
  AdminPlatformFeedbackRoute->>AdminFeedbackAPI: authenticated JSON request
  AdminFeedbackAPI->>FeedbackLoader: enforce role and load filters
  FeedbackLoader->>FeedbackDatabase: query list and selected feedback
  FeedbackDatabase-->>AdminPlatformFeedbackRoute: return feedback data
Loading
sequenceDiagram
  participant FeedbackQueue
  participant SubscriptionDispatcher
  participant FeedbackRepository
  participant NotificationSubscription
  FeedbackQueue->>SubscriptionDispatcher: deliver feedbackId
  SubscriptionDispatcher->>FeedbackRepository: reload feedback before invocation
  FeedbackRepository-->>SubscriptionDispatcher: feedback row or deleted result
  SubscriptionDispatcher->>NotificationSubscription: invoke expanded event
  SubscriptionDispatcher-->>FeedbackQueue: acknowledge permanent cancellation
Loading

Possibly related PRs

  • kentcdodds/kody#783 — Related platform-feedback capability, service, repository, and admin delivery work.
  • kentcdodds/kody#784 — Related Queue dispatch, cancellation, and expanded subscription event changes.
  • kentcdodds/kody#601 — Related SSR loader-data and route integration used by the admin surface.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: richer feedback notifications and admin deep links.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/feedback-discord-details-d866

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

cursoragent and others added 4 commits July 19, 2026 06:28
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@kody-bot
kody-bot marked this pull request as ready for review July 19, 2026 07:07
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-785.kody-a99.workers.dev

Worker: kody-pr-785
D1: kody-pr-785-db
KV: kody-pr-785-oauth-kv

Mocks:

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (3)
packages/worker/client/routes/account-management-components.tsx (1)

101-121: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Nav item sourcing is inconsistent with its siblings.

The new "Platform feedback" entry derives href/paths from routes.adminPlatformFeedback.href(), but every other entry in adminNavItems still hardcodes its path as a literal string. Both approaches work today, but this creates two ways to express the same information, and only the new entry benefits from route-constant safety if routes.ts changes.

Consider migrating the whole array to reference routes.*.href() for consistency (can be deferred, not blocking this PR).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/client/routes/account-management-components.tsx` around lines
101 - 121, Standardize adminNavItems route sourcing by replacing the hardcoded
href and paths values with the corresponding routes.*.href() references for
every entry, matching the existing adminPlatformFeedback entry while preserving
labels and navigation behavior.
packages/worker/src/platform-feedback/repo.ts (1)

179-241: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated filter/where-building logic between the two admin listing functions.

listPlatformFeedbackRowsForAdmin and listPlatformFeedbackPageRowsForAdmin each independently rebuild the same filters/bindings/where clause from status/category. Any future filter added to one function but not the other would silently desync the total count from the returned page items.

♻️ Extract shared filter-building helper
+function buildPlatformFeedbackAdminFilters(input: {
+	status?: PlatformFeedbackStatus
+	category?: PlatformFeedbackCategory
+}) {
+	const filters: Array<string> = []
+	const bindings: Array<unknown> = []
+	if (input.status !== undefined) {
+		filters.push('status = ?')
+		bindings.push(input.status)
+	}
+	if (input.category !== undefined) {
+		filters.push('category = ?')
+		bindings.push(input.category)
+	}
+	return {
+		where: filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '',
+		bindings,
+	}
+}
+
 export async function listPlatformFeedbackRowsForAdmin(
 	db: D1Database,
 	input: { page: number; pageSize: number; status?: PlatformFeedbackStatus; category?: PlatformFeedbackCategory },
 ): Promise<{ total: number; items: Array<PlatformFeedbackListItem> }> {
-	const filters: Array<string> = []
-	const bindings: Array<unknown> = []
-	if (input.status !== undefined) {
-		filters.push('status = ?')
-		bindings.push(input.status)
-	}
-	if (input.category !== undefined) {
-		filters.push('category = ?')
-		bindings.push(input.category)
-	}
-	const where = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : ''
+	const { where, bindings } = buildPlatformFeedbackAdminFilters(input)
 	const countRow = await db
 		.prepare(`SELECT COUNT(*) AS total FROM platform_feedback ${where}`)
 		.bind(...bindings)
 		.first<{ total: number }>()
 	const items = await listPlatformFeedbackPageRowsForAdmin(db, input)
 	return { total: Number(countRow?.total ?? 0), items }
 }

 export async function listPlatformFeedbackPageRowsForAdmin(
 	db: D1Database,
 	input: { page: number; pageSize: number; status?: PlatformFeedbackStatus; category?: PlatformFeedbackCategory },
 ): Promise<Array<PlatformFeedbackListItem>> {
-	const filters: Array<string> = []
-	const bindings: Array<unknown> = []
-	if (input.status !== undefined) {
-		filters.push('status = ?')
-		bindings.push(input.status)
-	}
-	if (input.category !== undefined) {
-		filters.push('category = ?')
-		bindings.push(input.category)
-	}
-	const where = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : ''
+	const { where, bindings } = buildPlatformFeedbackAdminFilters(input)
 	const rows = await db
 		.prepare(`SELECT ${platformFeedbackListColumns} FROM platform_feedback ${where} ORDER BY created_at DESC, id DESC LIMIT ? OFFSET ?`)
 		.bind(...bindings, input.pageSize, (input.page - 1) * input.pageSize)
 		.all<Record<string, unknown>>()
 	return (rows.results ?? []).map(mapPlatformFeedbackListRow)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/platform-feedback/repo.ts` around lines 179 - 241,
Extract the shared status/category filter, bindings, and WHERE-clause
construction from listPlatformFeedbackRowsForAdmin and
listPlatformFeedbackPageRowsForAdmin into a helper, then reuse it in both
queries so count and page filtering remain synchronized. Preserve the existing
filter order and binding behavior.
packages/worker/src/platform-feedback/dispatch-queue.ts (1)

23-55: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider logging permanent cancellations for observability.

The cancellation branch (Lines 41-44) acks silently, unlike the failure branch which logs via console.error. A lightweight log here would help track how often feedback rows are deleted before dispatch completes.

🔎 Optional: add a log line on cancellation
 			if (error instanceof PlatformFeedbackDispatchCancelledError) {
+				console.info('platform-feedback-dispatch-cancelled', {
+					queueMessageId: queueMessage.id,
+					feedbackId: parsed.feedbackId,
+				})
 				queueMessage.ack()
 				continue
 			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/platform-feedback/dispatch-queue.ts` around lines 23 -
55, Log a lightweight cancellation event in the
PlatformFeedbackDispatchCancelledError branch of
handlePlatformFeedbackDispatchQueue before acknowledging the message, including
the queue message ID and feedback ID; preserve the existing ack-and-continue
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/worker/client/routes/account-management-components.tsx`:
- Around line 101-121: Standardize adminNavItems route sourcing by replacing the
hardcoded href and paths values with the corresponding routes.*.href()
references for every entry, matching the existing adminPlatformFeedback entry
while preserving labels and navigation behavior.

In `@packages/worker/src/platform-feedback/dispatch-queue.ts`:
- Around line 23-55: Log a lightweight cancellation event in the
PlatformFeedbackDispatchCancelledError branch of
handlePlatformFeedbackDispatchQueue before acknowledging the message, including
the queue message ID and feedback ID; preserve the existing ack-and-continue
behavior.

In `@packages/worker/src/platform-feedback/repo.ts`:
- Around line 179-241: Extract the shared status/category filter, bindings, and
WHERE-clause construction from listPlatformFeedbackRowsForAdmin and
listPlatformFeedbackPageRowsForAdmin into a helper, then reuse it in both
queries so count and page filtering remain synchronized. Preserve the existing
filter order and binding behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 15b98b6c-aa66-4c2a-9cf8-f7fdc92a5116

📥 Commits

Reviewing files that changed from the base of the PR and between f161b9b and aa15f27.

📒 Files selected for processing (38)
  • docs/contributing/architecture/authorization.md
  • docs/contributing/packages-and-manifests.md
  • docs/guides/package-subscriptions.md
  • docs/guides/platform-friction.md
  • docs/use/privacy.md
  • packages/worker/client/routes/account-management-components.tsx
  • packages/worker/client/routes/admin-platform-feedback.tsx
  • packages/worker/client/routes/index.tsx
  • packages/worker/client/routes/privacy.tsx
  • packages/worker/migrations/0063-platform-feedback-submitter-snapshot.sql
  • packages/worker/src/app/account-deletion.node.test.ts
  • packages/worker/src/app/account-export.node.test.ts
  • packages/worker/src/app/admin-platform-feedback-data.node.test.ts
  • packages/worker/src/app/admin-platform-feedback-data.ts
  • packages/worker/src/app/handlers/admin-platform-feedback.node.test.ts
  • packages/worker/src/app/handlers/admin-platform-feedback.ts
  • packages/worker/src/app/loader-data.ts
  • packages/worker/src/app/router.ts
  • packages/worker/src/app/routes.ts
  • packages/worker/src/mcp/capabilities/coding/kody-official-guide.ts
  • packages/worker/src/mcp/capabilities/meta/meta-platform-feedback-submit.ts
  • packages/worker/src/mcp/capabilities/packages/list-package-subscriptions.ts
  • packages/worker/src/mcp/capabilities/platform-feedback-capabilities.node.test.ts
  • packages/worker/src/mcp/server-instructions.ts
  • packages/worker/src/platform-feedback/dispatch-queue.node.test.ts
  • packages/worker/src/platform-feedback/dispatch-queue.ts
  • packages/worker/src/platform-feedback/errors.ts
  • packages/worker/src/platform-feedback/package-subscriptions.node.test.ts
  • packages/worker/src/platform-feedback/package-subscriptions.ts
  • packages/worker/src/platform-feedback/platform-feedback-service.node.test.ts
  • packages/worker/src/platform-feedback/platform-feedback-submitter-snapshot-migration.node.test.ts
  • packages/worker/src/platform-feedback/platform-feedback-subscriptions.workers.test.ts
  • packages/worker/src/platform-feedback/repo.ts
  • packages/worker/src/platform-feedback/service.ts
  • packages/worker/src/platform-feedback/submitter-identity.node.test.ts
  • packages/worker/src/platform-feedback/submitter-identity.ts
  • packages/worker/src/platform-feedback/subscription-event.ts
  • packages/worker/src/platform-feedback/types.ts

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.

3 participants