Skip to content

feat(devpass): add model census survey + reward - #3169

Merged
smakosh merged 16 commits into
mainfrom
feat/devpass-model-survey
Jul 22, 2026
Merged

smakosh merged 16 commits into
mainfrom
feat/devpass-model-survey

Conversation

@smakosh

@smakosh smakosh commented Jul 21, 2026 •

Copy link
Copy Markdown
Member

What

The DevPass Model Census — a quarterly-wave, DevPass-only survey answering one question: which coding models are actually worth the money? Usage-triggered reminder → 1-minute survey → free Reset Pass → public data report.

The flow

  1. Reminder dialog (dashboard shell): when a member has 50+ requests on a model in the last 30 days, a census dialog appears — "You and {model} have been logging serious miles… rate it and a free Reset Pass is stamped into your passport." "Maybe later" snoozes it via cookie for 14 days; a submission silences it server-side for the year.
  2. Survey (/dashboard/survey): passport-styled form — value-for-money, output quality, speed (1–5 stamp scores), APPROVED/DENIED recommend stamps, primary use case, required field notes. Members can rate every model they qualify for; each response snapshots the qualifying request count.
  3. Reward: the org's first response each year grants one free Reset Pass on the current tier — the same devPlanResetPasses<Tier> increment as a purchase, recorded as a $0 dev_plan_reset_pass_reward transaction (new type) + dev_plan.reset_pass_reward audit event. Redeemable through the existing redeem flow, refund-ineligible, excluded from invoices, revenue metrics, and paidTransactionTypes.
  4. Public report (/data/[year], e.g. /data/2026): "The 2026 DevPass Model Census" — registry ranked by value score with quality/speed meters, recommend %, stat tiles, methodology, Dataset JSON-LD, sitemap entry. Fed by GET /public/model-survey/results.

Design decisions (deviations/additions beyond the original ask)

  • Usage-verified responses only (≥50 req/30d on the org's own stats, from projectHourlyModelStats with the model-ratings name normalization) — the published data can honestly claim every rating is backed by real usage.
  • One reward per org per quarter, but unlimited ratings (members can re-rate a model each wave, giving trend data) — richer dataset, no pass farming. Reward grant is race-safe (FOR UPDATE on the org row inside the insert transaction).
  • k-anonymity: models publish only at ≥5 responses; only aggregates are ever exposed.
  • Year-agnostic: (year, quarter) columns + /data/[year] route (yearly report aggregates all four waves) — 2027 needs zero code.
  • Separate table from model_rating (richer dimensions, DevPass-only, usage-window-verified). Cross-posting the quality score to public model pages is a possible follow-up.
  • New transaction type instead of reusing dev_plan_reset_pass so reset-pass revenue analytics don't count free grants.
  • PostHog funnel: model_survey_prompt_shown/dismissed/accepted, model_survey_completed (client) + model_survey_submitted (server).
  • First Playwright e2e infra in the repo (apps/code/e2e, *.pw.ts so root vitest globs never pick them up): pnpm --filter code test:e2e against a freshly seeded local stack.

Testing

  • apps/api/src/routes/model-survey.spec.ts — 14 specs: eligibility gating (auth, non-devpass, inactive plan, threshold, window, ordering), submit + reward grant (org counter, $0 transaction), no double reward, 409 dupes, tier-bound grant, public aggregation + anonymity threshold + year scoping. ✅
  • Full unit suite: 173 files / 2880 tests ✅
  • Playwright e2e (3 tests): snooze cookie flow, full dialog→survey→reward flow with DB-verified grant, public census page. ✅
  • pnpm build (all apps) ✅, pnpm format ✅
  • Seed adds census responses + the existing DevPass usage stats make the seeded admin eligible out of the box.

https://claude.ai/code/session_019bW8g9tRS3vXnUjezwoJZN

Summary by CodeRabbit

  • New Features

    • Added the Model Census survey for eligible DevPass users, including model ratings, recommendations, use cases, and comments.
    • Eligible submissions can earn a free Reset Pass once per quarter.
    • Added a public, year-based census results page with anonymized model rankings and aggregate insights.
    • Added dashboard reminders and navigation to the survey and public census.
  • Bug Fixes

    • Prevented rewarded survey transactions from affecting plan-credit metrics.
  • Tests

    • Added API and browser coverage for survey submission, rewards, reminders, and public results.

Yearly DevPass-only "Model Census" asking which coding models are
worth their cost, based on verified usage:

- model_survey_response table (per user+model+year, value/quality/
  speed scores, recommend, use case, usage snapshot)
- /model-survey eligibility + submit routes; the org's first entry
  each year grants a free current-tier Reset Pass ($0
  dev_plan_reset_pass_reward transaction, audit-logged)
- /public/model-survey/results with a 5-response anonymity threshold
- usage-triggered census reminder dialog in the dashboard shell with
  a 14-day snooze cookie, survey form at /dashboard/survey
- public results registry at /data/[year] with Dataset JSON-LD
- seeded census data, API spec tests, and Playwright e2e for
  apps/code (pnpm --filter code test:e2e)

Claude-Session: https://claude.ai/code/session_019bW8g9tRS3vXnUjezwoJZN
@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a quarterly model survey with database storage, authenticated eligibility and submission APIs, Reset Pass rewards, public anonymized census results, dashboard survey flows, year-specific census pages, seed data, and Playwright coverage.

Changes

Model census

Layer / File(s) Summary
Survey storage and reward contracts
packages/db/..., apps/api/src/routes/organization.ts, apps/api/src/utils/devpass-filter.ts
Adds the survey response table, constraints, relations, reward transaction type, audit action, seed data, migration metadata, and metrics exclusion.
Eligibility and survey submission API
apps/api/src/routes/model-survey.ts, apps/api/src/routes/index.ts, apps/api/src/routes/model-survey.spec.ts
Adds authenticated eligibility and submission endpoints with usage thresholds, quarterly duplicate handling, transactional reward grants, and API tests.
Public census aggregation API
apps/api/src/routes/public-model-survey.ts, apps/api/src/index.ts, apps/api/src/routes/model-survey.spec.ts
Adds year-scoped public aggregation with respondent and use-case suppression, model metrics, route wiring, and aggregation tests.
Dashboard survey flow and reminder
apps/code/src/app/dashboard/..., apps/code/src/lib/cookies.ts, apps/code/src/lib/model-survey.ts
Adds dashboard navigation, eligibility reminders, snooze cookies, survey form controls, submission feedback, and reward-state handling.
Public census pages and data fetching
apps/code/src/app/data/..., apps/code/src/lib/model-survey.ts, apps/code/src/app/sitemap.ts
Adds year validation, ISR census pages, metadata, JSON-LD, registry rendering, methodology content, redirects, and sitemap registration.
Browser validation and test tooling
apps/code/e2e/*, apps/code/playwright.config.ts, apps/code/package.json, apps/code/tsconfig.json, apps/code/.gitignore
Adds Playwright configuration, scripts, compiler inclusion, ignored artifacts, and end-to-end tests for reminder, submission, rewards, and census pages.

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

Sequence Diagram(s)

sequenceDiagram
  participant Developer
  participant Dashboard
  participant SurveyAPI
  participant Database
  participant CensusPage
  Developer->>Dashboard: Open dashboard
  Dashboard->>SurveyAPI: GET /model-survey/eligibility
  SurveyAPI->>Database: Read usage and survey responses
  Database-->>SurveyAPI: Eligible models and reward state
  SurveyAPI-->>Dashboard: Eligibility payload
  Dashboard->>SurveyAPI: POST /model-survey
  SurveyAPI->>Database: Store response and grant quarterly reward
  Database-->>SurveyAPI: Stored response and reward result
  SurveyAPI-->>Dashboard: Submission result
  CensusPage->>SurveyAPI: GET /public/model-survey/results?year=year
  SurveyAPI->>Database: Aggregate anonymized responses
  Database-->>SurveyAPI: Published census metrics
  SurveyAPI-->>CensusPage: Yearly census results
Loading

Possibly related PRs

  • theopenco/llmgateway#3093: Updates shared DevPass reset-pass transaction typing and filtering used by the survey reward integration.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% 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
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding the DevPass model census survey and reward flow.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/devpass-model-survey

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (4)
apps/code/src/app/dashboard/DashboardShell.tsx (1)

72-79: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Nav item year is computed once at module load, not per render.

resourceNavItems is a module-scope constant, so new Date().getUTCFullYear() is evaluated once when the module is first loaded, not on each render. A user who keeps a tab open across the UTC year boundary will see the "Model census" link keep pointing at the previous year until a full page reload.

♻️ Proposed fix: compute the href at render time
-const resourceNavItems: Array<{
-	label: string;
-	href: Route;
-	icon: typeof BarChart3;
-}> = [
-	{ label: "Coding models", href: "/coding-models" as Route, icon: Code },
-	{
-		label: "Model census",
-		href: `/data/${new Date().getUTCFullYear()}` as Route,
-		icon: Stamp,
-	},
-];
+const staticResourceNavItems: Array<{
+	label: string;
+	href: Route;
+	icon: typeof BarChart3;
+}> = [{ label: "Coding models", href: "/coding-models" as Route, icon: Code }];

Then inside DashboardShell, build resourceNavItems with useMemo(() => [...staticResourceNavItems, { label: "Model census", href: \/data/${new Date().getUTCFullYear()}` as Route, icon: Stamp }], [])`.

🤖 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 `@apps/code/src/app/dashboard/DashboardShell.tsx` around lines 72 - 79, Move
the dynamic “Model census” year calculation out of the module-scope
resourceNavItems constant and compute it inside DashboardShell during rendering,
using useMemo with the existing static navigation items as the base. Ensure the
href reflects the current UTC year when the component renders.
apps/code/e2e/census.pw.ts (1)

34-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace fixed waitForTimeout(3000) sleeps with a direct polling assertion.

Both sites use a hardcoded 3s sleep before asserting the dialog stays hidden. expect(...).not.toBeVisible() already polls internally, so the sleep just adds fixed latency and can still flake under slower CI if the negative assertion runs before the (500-900ms) dialog logic would have fired again on a regression.

  • apps/code/e2e/census.pw.ts#L34-L36: drop page.waitForTimeout(3000) and let await expect(dialog).not.toBeVisible({ timeout: 5000 }) do the waiting after page.reload().
  • apps/code/e2e/census.pw.ts#L73-L75: same change after page.goto("/dashboard") — drop the sleep and pass an explicit timeout to the not.toBeVisible() assertion instead.
🤖 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 `@apps/code/e2e/census.pw.ts` around lines 34 - 36, Replace the fixed 3-second
sleeps at apps/code/e2e/census.pw.ts:34-36 and apps/code/e2e/census.pw.ts:73-75
with direct polling assertions: remove each page.waitForTimeout call and set the
corresponding dialog not.toBeVisible assertion timeout to 5000ms after
page.reload() and page.goto("/dashboard"), respectively.
packages/db/src/schema.ts (2)

590-609: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Same enum literal sets are independently redefined in three places. The primaryUseCase (7 values) and tier ("lite"/"pro"/"max") sets have one root cause — no shared source of truth — but are copy-pasted across the DB schema and two API route files, risking silent drift.

  • packages/db/src/schema.ts#L590-L609: export the primaryUseCase and tier literal arrays as named constants (e.g. MODEL_SURVEY_USE_CASES, DEV_PLAN_TIERS) from this file (or a small shared module) instead of inlining them only here.
  • apps/api/src/routes/model-survey.ts#L31-L41: build useCaseEnum/tierEnum from the shared constants instead of re-listing the literals.
  • apps/api/src/routes/public-model-survey.ts#L14-L22: build useCaseEnum from the same shared constant instead of a third independent copy.
🤖 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/db/src/schema.ts` around lines 590 - 609, Create and export shared
primary-use-case and development-plan-tier literal arrays from the schema
definitions around primaryUseCase and devPlanTier, then use those constants to
build the enums in model-survey.ts and public-model-survey.ts instead of
duplicating literals. Update packages/db/src/schema.ts lines 590-609 to define
the constants, apps/api/src/routes/model-survey.ts lines 31-41 to consume both
shared constants, and apps/api/src/routes/public-model-survey.ts lines 14-22 to
consume the shared use-case constant.

610-617: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Consider a DB-level guardrail for the one-reward-per-org-per-year invariant.

The single-reward-per-org-per-year rule is currently enforced only by the SELECT ... FOR UPDATE lock in model-survey.ts. A partial unique index would make this invariant hold even if a future code path (e.g. a backfill script, a refactor) skips the lock.

🛡️ Optional defense-in-depth index
 		index("model_survey_response_organization_id_idx").on(table.organizationId),
+		uniqueIndex("model_survey_response_org_year_reward_unique")
+			.on(table.organizationId, table.year)
+			.where(sql`${table.rewardTier} IS NOT NULL`),
🤖 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/db/src/schema.ts` around lines 610 - 617, Add a database-level
partial unique index in the table definition callback for model survey
responses, keyed by organizationId and year and restricted to rows representing
a reward. Use the schema’s existing reward-presence column or predicate, and
generate the corresponding migration so the one-reward-per-organization-per-year
invariant is enforced independently of the SELECT ... FOR UPDATE path in
model-survey.ts.
🤖 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.

Inline comments:
In `@apps/api/src/routes/public-model-survey.ts`:
- Around line 99-146: Apply the anonymity threshold to the per-use-case buckets
built in useCasesByModel before returning them from the models mapping. Omit or
aggregate buckets whose counts are below the chosen threshold, reusing
MIN_PUBLIC_RESPONSES where appropriate, and ensure the returned useCases cannot
expose low-count individual responses while preserving published model totals.

In `@apps/code/src/app/dashboard/survey/SurveyClient.tsx`:
- Around line 229-236: Update rateAnother to reset every controlled survey
field, including valueScore, qualityScore, speedScore, wouldRecommend, and
primaryUseCase, alongside modelId and comment. Use the form’s empty/default
values so the next model starts without selections from the previous submission.

In `@apps/code/src/lib/model-survey.ts`:
- Around line 22-29: Replace the raw fetch and manual ModelSurveyResults
assertion in the model survey results helper with the applicable generated typed
API client, passing the client into the helper if necessary. Preserve the year
query parameter, revalidation behavior, null return for unsuccessful responses,
and typed result handling.
- Around line 17-33: Update fetchModelSurveyResults so fetch exceptions and
non-OK responses are not converted to null, which CensusPage interprets as an
empty registry. Remove the failure-to-null handling in fetchModelSurveyResults
and propagate the error to Next’s error handling, while preserving the
successful JSON result path.

In `@packages/db/src/seed.ts`:
- Around line 1865-1873: The seed flow must create the census respondent users
and organizations before inserting survey responses. In the setup around
censusRespondents and the EXTRA_USERS/EXTRA_ORGS upserts, move
bulkInsert(tables.modelSurveyResponse, censusResponses) to run after those
upserts while preserving the existing response data.

---

Nitpick comments:
In `@apps/code/e2e/census.pw.ts`:
- Around line 34-36: Replace the fixed 3-second sleeps at
apps/code/e2e/census.pw.ts:34-36 and apps/code/e2e/census.pw.ts:73-75 with
direct polling assertions: remove each page.waitForTimeout call and set the
corresponding dialog not.toBeVisible assertion timeout to 5000ms after
page.reload() and page.goto("/dashboard"), respectively.

In `@apps/code/src/app/dashboard/DashboardShell.tsx`:
- Around line 72-79: Move the dynamic “Model census” year calculation out of the
module-scope resourceNavItems constant and compute it inside DashboardShell
during rendering, using useMemo with the existing static navigation items as the
base. Ensure the href reflects the current UTC year when the component renders.

In `@packages/db/src/schema.ts`:
- Around line 590-609: Create and export shared primary-use-case and
development-plan-tier literal arrays from the schema definitions around
primaryUseCase and devPlanTier, then use those constants to build the enums in
model-survey.ts and public-model-survey.ts instead of duplicating literals.
Update packages/db/src/schema.ts lines 590-609 to define the constants,
apps/api/src/routes/model-survey.ts lines 31-41 to consume both shared
constants, and apps/api/src/routes/public-model-survey.ts lines 14-22 to consume
the shared use-case constant.
- Around line 610-617: Add a database-level partial unique index in the table
definition callback for model survey responses, keyed by organizationId and year
and restricted to rows representing a reward. Use the schema’s existing
reward-presence column or predicate, and generate the corresponding migration so
the one-reward-per-organization-per-year invariant is enforced independently of
the SELECT ... FOR UPDATE path in model-survey.ts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b65fffc9-60f8-4e08-97da-b304fad8f2d8

📥 Commits

Reviewing files that changed from the base of the PR and between 57ad9fc and 080bbf4.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (27)
  • apps/api/src/index.ts
  • apps/api/src/routes/index.ts
  • apps/api/src/routes/model-survey.spec.ts
  • apps/api/src/routes/model-survey.ts
  • apps/api/src/routes/organization.ts
  • apps/api/src/routes/public-model-survey.ts
  • apps/api/src/utils/devpass-filter.ts
  • apps/code/.gitignore
  • apps/code/e2e/census.pw.ts
  • apps/code/package.json
  • apps/code/playwright.config.ts
  • apps/code/src/app/dashboard/DashboardShell.tsx
  • apps/code/src/app/dashboard/components/SurveyReminderDialog.tsx
  • apps/code/src/app/dashboard/survey/SurveyClient.tsx
  • apps/code/src/app/dashboard/survey/page.tsx
  • apps/code/src/app/data/[year]/page.tsx
  • apps/code/src/app/data/page.tsx
  • apps/code/src/app/sitemap.ts
  • apps/code/src/lib/cookies.ts
  • apps/code/src/lib/model-survey.ts
  • apps/code/tsconfig.json
  • packages/db/migrations/1784664094_quick_mercury.sql
  • packages/db/migrations/meta/1784664094_snapshot.json
  • packages/db/migrations/meta/_journal.json
  • packages/db/src/relations.ts
  • packages/db/src/schema.ts
  • packages/db/src/seed.ts

Comment thread apps/api/src/routes/public-model-survey.ts
Comment thread apps/code/src/app/dashboard/survey/SurveyClient.tsx
Comment on lines +17 to +33
export async function fetchModelSurveyResults(
year: number,
): Promise<ModelSurveyResults | null> {
const config = getConfig();
try {
const res = await fetch(
`${config.apiBackendUrl}/public/model-survey/results?year=${year}`,
{ next: { revalidate: 300 } },
);
if (!res.ok) {
return null;
}
return (await res.json()) as ModelSurveyResults;
} catch {
return null;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not convert API failures into an empty census.

CensusPage treats null as an empty registry, so a timeout or non-2xx response is published as “Registry open” rather than an unavailable result. Let the error reach Next’s error handling (or return an explicit unavailable state).

Proposed fix
 export async function fetchModelSurveyResults(
 	year: number,
 ): Promise<ModelSurveyResults | null> {
 	const config = getConfig();
-	try {
-		const res = await fetch(
-			`${config.apiBackendUrl}/public/model-survey/results?year=${year}`,
-			{ next: { revalidate: 300 } },
-		);
-		if (!res.ok) {
-			return null;
-		}
-		return (await res.json()) as ModelSurveyResults;
-	} catch {
-		return null;
+	const res = await fetch(
+		`${config.apiBackendUrl}/public/model-survey/results?year=${year}`,
+		{ next: { revalidate: 300 } },
+	);
+	if (!res.ok) {
+		throw new Error(`Model census request failed: ${res.status}`);
 	}
+	return (await res.json()) as ModelSurveyResults;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function fetchModelSurveyResults(
year: number,
): Promise<ModelSurveyResults | null> {
const config = getConfig();
try {
const res = await fetch(
`${config.apiBackendUrl}/public/model-survey/results?year=${year}`,
{ next: { revalidate: 300 } },
);
if (!res.ok) {
return null;
}
return (await res.json()) as ModelSurveyResults;
} catch {
return null;
}
}
export async function fetchModelSurveyResults(
year: number,
): Promise<ModelSurveyResults | null> {
const config = getConfig();
const res = await fetch(
`${config.apiBackendUrl}/public/model-survey/results?year=${year}`,
{ next: { revalidate: 300 } },
);
if (!res.ok) {
throw new Error(`Model census request failed: ${res.status}`);
}
return (await res.json()) as ModelSurveyResults;
}
🤖 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 `@apps/code/src/lib/model-survey.ts` around lines 17 - 33, Update
fetchModelSurveyResults so fetch exceptions and non-OK responses are not
converted to null, which CensusPage interprets as an empty registry. Remove the
failure-to-null handling in fetchModelSurveyResults and propagate the error to
Next’s error handling, while preserving the successful JSON result path.

Comment thread apps/code/src/lib/model-survey.ts Outdated
Comment thread packages/db/src/seed.ts Outdated
smakosh added 4 commits July 21, 2026 23:13
Comment is now mandatory on model-survey submissions (API validation
+ form), so every census response carries qualitative feedback.

Claude-Session: https://claude.ai/code/session_019bW8g9tRS3vXnUjezwoJZN
The census block referenced EXTRA_USERS rows before they were
inserted, so seeding a fresh database (CI) failed on the user FK.

Claude-Session: https://claude.ai/code/session_019bW8g9tRS3vXnUjezwoJZN
- suppress single-respondent use-case buckets in public results
- add partial unique index backing one-reward-per-org-per-year
- share survey enum literals from @llmgateway/db
- fully reset the census form when rating another model
- distinguish registry-offline from registry-empty on /data/[year]
- compute the census nav year at render time

Claude-Session: https://claude.ai/code/session_019bW8g9tRS3vXnUjezwoJZN

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@apps/api/src/routes/public-model-survey.ts`:
- Around line 22-26: Update the top-level total calculations in the survey
aggregation flow to include only responses associated with published model IDs
that meet the five-response threshold. Ensure totalResponses, totalRespondents,
and totalModelsRated are all derived from that filtered set, or return
suppressed totals when no model qualifies; preserve the existing per-use-case
bucket suppression.

In `@packages/db/migrations/1784744600_overjoyed_war_machine.sql`:
- Line 1: Update the migration statement for model_survey_response to create the
unique index concurrently, and configure the migration so this statement runs
outside Drizzle Kit’s default transaction boundary. Preserve the existing index
name, columns, and reward_tier predicate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3c8c4811-05a5-4e1b-989e-596a41a48488

📥 Commits

Reviewing files that changed from the base of the PR and between e881c90 and b7d9fee.

📒 Files selected for processing (10)
  • apps/api/src/routes/model-survey.spec.ts
  • apps/api/src/routes/model-survey.ts
  • apps/api/src/routes/public-model-survey.ts
  • apps/code/src/app/dashboard/DashboardShell.tsx
  • apps/code/src/app/dashboard/survey/SurveyClient.tsx
  • apps/code/src/app/data/[year]/page.tsx
  • packages/db/migrations/1784744600_overjoyed_war_machine.sql
  • packages/db/migrations/meta/1784744600_snapshot.json
  • packages/db/migrations/meta/_journal.json
  • packages/db/src/schema.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/db/src/schema.ts
  • apps/code/src/app/dashboard/DashboardShell.tsx
  • apps/api/src/routes/model-survey.spec.ts
  • apps/api/src/routes/model-survey.ts
  • apps/code/src/app/dashboard/survey/SurveyClient.tsx
  • apps/code/src/app/data/[year]/page.tsx

Comment thread apps/api/src/routes/public-model-survey.ts
Comment thread packages/db/migrations/1784744600_overjoyed_war_machine.sql Outdated
smakosh added 11 commits July 22, 2026 21:02
Responses and the free Reset Pass reward are now scoped to
(year, quarter): members can re-rate models each quarter (trend
data) and earn one pass per org per wave. The public /data/[year]
report still aggregates the full year. Migration regenerated as a
single artifact since the table never shipped.

Claude-Session: https://claude.ai/code/session_019bW8g9tRS3vXnUjezwoJZN
Stat tiles now count only registry-published models, so totals
always match the table and sub-threshold models never surface.

Claude-Session: https://claude.ai/code/session_019bW8g9tRS3vXnUjezwoJZN
Replace the raw fetch in fetchModelSurveyResults with a shared
createPublicServerApiClient (openapi-fetch, no cookie read) so the
/data/[year] page keeps its typed contract and stays static/ISR.

Claude-Session: https://claude.ai/code/session_019bW8g9tRS3vXnUjezwoJZN
…rvey

# Conflicts:
#	apps/api/src/routes/organization.ts
#	apps/api/src/utils/devpass-filter.ts
#	packages/db/src/schema.ts
@smakosh
smakosh enabled auto-merge July 22, 2026 21:07
@smakosh
smakosh added this pull request to the merge queue Jul 22, 2026
Merged via the queue into main with commit 36b5a70 Jul 22, 2026
27 checks passed
@smakosh
smakosh deleted the feat/devpass-model-survey branch July 22, 2026 21:27
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