Skip to content

Add steward score reasons#829

Merged
JoaquinBN merged 2 commits into
devfrom
JoaquinBN/score-reasons-for-stewards
Jun 23, 2026
Merged

Add steward score reasons#829
JoaquinBN merged 2 commits into
devfrom
JoaquinBN/score-reasons-for-stewards

Conversation

@JoaquinBN

@JoaquinBN JoaquinBN commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds an optional reason field to steward feature candidate scores so each score can capture what stood out about the project.
Updates the feature scoring view to let stewards draft a score and reason before saving.
Includes API, serializer, admin, migration, and coverage updates for storing and returning each steward's own reason.

Summary by CodeRabbit

  • New Features

    • Added an optional “Reason” field (up to 2,000 characters) when reviewers score feature candidates, and included it in saved results.
    • Reviewer reasons are now shown in the scoring interface and surfaced in the admin listing for easier review.
  • Bug Fixes

    • Improved scoring validation and error handling to ensure overly long reasons are rejected and missing reasons return as empty strings.
  • Tests

    • Added end-to-end coverage for creating/editing reviewer scores with reasons, including validation cases.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an optional reason TextField to FeatureCandidateScore (model + migration), renames the internal score map to _own_review_map returning {score, reason}, updates the score endpoint to validate and persist reason, propagates own_score_reason through the serializer, exposes a truncated preview in the admin, and introduces a draft-based score+reason UI in the Svelte frontend.

Changes

Feature Candidate Score Reason Field

Layer / File(s) Summary
Model field and migration
backend/stewards/models.py, backend/stewards/migrations/0012_feature_candidate_score_reason.py
Adds an optional reason TextField to FeatureCandidateScore with blank=True and empty-string default, backed by a new migration depending on 0011_feature_candidate_scoring.
View: _own_review_map refactor and score/list/admin endpoints
backend/stewards/views.py
Replaces _own_score_map with _own_review_map returning {score, reason} dicts. The score endpoint validates and persists reason (max 2000 chars), returning it in the response. Both list and admin pass own_review_map into serializer context.
Serializer own_score_reason field and admin reason_preview
backend/stewards/serializers.py, backend/stewards/admin.py
Adds own_score_reason SerializerMethodField to FeatureCandidateSubmissionSerializer reading from own_review_map. Adds a reason_preview column (80-char truncation) to FeatureCandidateScoreAdmin.
Frontend API and draft-based score+reason UI
frontend/src/lib/api.js, frontend/src/routes/StewardFeatureReviews.svelte
Extends scoreFeatureReviewCandidate to accept reason. Introduces scoreDrafts state initialized from saved values, draft helpers, and a scoreCandidate save function. Adds a Reason textarea and "Save opinion" button; score buttons update draft state instead of persisting immediately.
Tests
backend/stewards/tests.py
Asserts own_score_reason in list responses, submits reason in create/edit tests verifying persistence, and validates rejection of too-long reason values with errors under score or reason keys.

Sequence Diagram(s)

sequenceDiagram
  actor Reviewer
  participant StewardFeatureReviews
  participant stewardAPI
  participant FeatureCandidateReviewViewSet
  participant FeatureCandidateScore

  Reviewer->>StewardFeatureReviews: click score option
  StewardFeatureReviews->>StewardFeatureReviews: updateScoreDraft(candidate, {score})
  Reviewer->>StewardFeatureReviews: type in Reason textarea
  StewardFeatureReviews->>StewardFeatureReviews: updateScoreDraft(candidate, {reason})
  Reviewer->>StewardFeatureReviews: click "Save opinion"
  StewardFeatureReviews->>stewardAPI: scoreFeatureReviewCandidate(id, score, reason)
  stewardAPI->>FeatureCandidateReviewViewSet: POST /score/ {score, reason}
  FeatureCandidateReviewViewSet->>FeatureCandidateScore: update_or_create(score, reason)
  FeatureCandidateScore-->>FeatureCandidateReviewViewSet: saved
  FeatureCandidateReviewViewSet-->>stewardAPI: {submission, score, reason}
  stewardAPI-->>StewardFeatureReviews: response
  StewardFeatureReviews->>StewardFeatureReviews: update candidate own_score + own_score_reason, increment progress
  StewardFeatureReviews-->>Reviewer: success toast
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • genlayer-foundation/points#821: Introduced the original FeatureCandidateScore model and FeatureCandidateReviewViewSet (list, score, admin endpoints) that this PR directly extends with the reason field.
  • genlayer-foundation/points#825: Modified the same views.py score map/query logic and StewardFeatureReviews.svelte scoring UI that this PR further reworks for draft-based submission.
🚥 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 'Add steward score reasons' directly and accurately summarizes the main change: adding a reason field to steward feature candidate scores across the backend API, serializers, models, migrations, and frontend UI.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 JoaquinBN/score-reasons-for-stewards

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

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@backend/stewards/models.py`:
- Around line 45-49: The `reason` TextField in the model is unconstrained while
the API serializer enforces a max_length of 2000 characters, allowing non-API
writes to persist oversized values. Add a max_length=2000 parameter to the
`reason` field definition in the model to enforce the constraint at the
model/schema boundary and ensure consistency with the API contract defined in
the serializer.

In `@backend/stewards/tests.py`:
- Around line 269-274: The assertion on line 274 is too generic for the test
case on line 269 which has a valid score but invalid reason (exceeding 2000
characters). Replace the weak assertion `self.assertTrue('score' in
response.data or 'reason' in response.data)` with a more specific check that
validates only the 'reason' key is present in response.data for that particular
subTest payload. This ensures the test tightly verifies that the error is
specifically about the reason field validation failure, not accidentally
accepting other field errors.

In `@frontend/src/routes/StewardFeatureReviews.svelte`:
- Line 204: The showError function call is receiving potentially non-string
values like arrays from DRF field errors, which results in unreadable toast
messages. Before passing the error value to the showError function, normalize it
to a readable string format by converting the selected error field (detail,
score, reason, or the fallback message) to a string. You may want to use
JSON.stringify for complex objects or implement a helper function that converts
various error types into human-readable messages, ensuring that the toast always
displays legible text regardless of the error structure.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 20ad1a87-b230-4673-a558-fdc7f5eebd49

📥 Commits

Reviewing files that changed from the base of the PR and between e121f85 and 7a17ff8.

📒 Files selected for processing (8)
  • backend/stewards/admin.py
  • backend/stewards/migrations/0012_feature_candidate_score_reason.py
  • backend/stewards/models.py
  • backend/stewards/serializers.py
  • backend/stewards/tests.py
  • backend/stewards/views.py
  • frontend/src/lib/api.js
  • frontend/src/routes/StewardFeatureReviews.svelte

Comment thread backend/stewards/models.py
Comment thread backend/stewards/tests.py Outdated
Comment thread frontend/src/routes/StewardFeatureReviews.svelte Outdated

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/stewards/models.py (1)

45-50: 🗄️ Data Integrity & Integration | 🟠 Major

Add a CheckConstraint for the reason field's max length to enforce database-level validation.

The max_length=2000 on line 46 only provides application-level validation. Direct ORM writes or bulk imports can bypass this and persist oversized values. Add a CheckConstraint on the reason field in the model's Meta.constraints list, and create a corresponding migration to enforce this at the database level.

🤖 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 `@backend/stewards/models.py` around lines 45 - 50, The reason field has
application-level max_length validation but lacks database-level enforcement,
allowing direct ORM writes or bulk imports to bypass this constraint. Add a
CheckConstraint in the Meta.constraints list of the model class that limits the
reason field to a maximum length of 2000 characters using a character length
condition, then create and apply a Django migration to enforce this constraint
at the database level.
🤖 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.

Outside diff comments:
In `@backend/stewards/models.py`:
- Around line 45-50: The reason field has application-level max_length
validation but lacks database-level enforcement, allowing direct ORM writes or
bulk imports to bypass this constraint. Add a CheckConstraint in the
Meta.constraints list of the model class that limits the reason field to a
maximum length of 2000 characters using a character length condition, then
create and apply a Django migration to enforce this constraint at the database
level.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5dc1efaf-0384-4362-84a1-3c0380341dfd

📥 Commits

Reviewing files that changed from the base of the PR and between 7a17ff8 and 543fbce.

📒 Files selected for processing (4)
  • backend/stewards/migrations/0012_feature_candidate_score_reason.py
  • backend/stewards/models.py
  • backend/stewards/tests.py
  • frontend/src/routes/StewardFeatureReviews.svelte

@JoaquinBN JoaquinBN merged commit e71352c into dev Jun 23, 2026
3 checks passed
@JoaquinBN JoaquinBN deleted the JoaquinBN/score-reasons-for-stewards branch June 23, 2026 12:30
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