Skip to content

Comments

Feat/ai percentage#25

Open
axv2655 wants to merge 14 commits intomainfrom
feat/ai-percentage
Open

Feat/ai percentage#25
axv2655 wants to merge 14 commits intomainfrom
feat/ai-percentage

Conversation

@axv2655
Copy link
Collaborator

@axv2655 axv2655 commented Feb 19, 2026

Created new api route, added new migration to DB (up and down) for new field, handled backend error handling, created front end ui, made it editable only by the assigned admin and handled what happens when someone else tries to mess with it, once it is set field is no longer updatable on both front and backend

Copilot AI review requested due to automatic review settings February 19, 2026 05:48
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for recording an AI-generated content percentage on applications, including schema changes, a new admin API route to set the value (only once and only by the assigned admin), and UI updates to display/edit the value in the admin review experience.

Changes:

  • Add ai_percentage column (SMALLINT) to applications, update seed data, and propagate the field through application query/response shapes.
  • Add admin PUT endpoint /admin/applications/{applicationID}/aiPercent and Swagger documentation for setting the AI percentage.
  • Update admin UI to show AI percentage in assigned-application details and in the all-applicants table; add client API call to set it.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
internal/store/storage.go Extends ApplicationReviews storage interface with SetAIPercentage.
internal/store/reviews.go Implements SetAIPercentage update guarded by assignment and “only-once” semantics.
internal/store/mock_store.go Adds mock implementation for SetAIPercentage.
internal/store/applications.go Adds ai_percentage to application/list queries and introduces (buggy) ApplicationsStore.SetAIPercentage plus extra DTO types.
internal/db/seed.go Updates application seed insert to include ai_percentage as NULL.
docs/docs.go Adds Swagger path + schema definitions for the new endpoint and field.
cmd/migrate/migrations/000013_add_ai_percentage.up.sql Adds ai_percentage column to applications.
cmd/migrate/migrations/000013_add_ai_percentage.down.sql Drops ai_percentage column.
cmd/api/reviews.go Adds request/response DTOs and handler for setting AI percentage.
cmd/api/api.go Mounts the new admin route.
client/web/src/types.ts Extends Application type with ai_percentage.
client/web/src/pages/admin/assigned/components/ApplicationDetailsPanel.tsx Adds AI percentage display/edit UI (currently nested incorrectly).
client/web/src/pages/admin/assigned/api.ts Adds setAIPercentage client call (and contains an existing notes-route mismatch).
client/web/src/pages/admin/assigned/AssignedPage.tsx Wires UI callback to update local application detail state.
client/web/src/pages/admin/all-applicants/types.ts Extends list item type with ai_percentage.
client/web/src/pages/admin/all-applicants/components/ApplicationsTable.tsx Adds table column to display AI percentage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}

async function saveEditing() {
const percentage = Number(inputValue);
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

saveEditing() uses Number(inputValue), which treats an empty string as 0 and can produce NaN for invalid input. This can lead to accidentally saving 0% or sending invalid JSON (NaN becomes null). Add client-side validation (required, integer, 0–100) before calling the API.

Suggested change
const percentage = Number(inputValue);
const trimmed = inputValue.trim();
if (trimmed === '') {
toast.error('AI percentage is required');
return;
}
const percentage = Number(trimmed);
if (!Number.isInteger(percentage) || percentage < 0 || percentage > 100) {
toast.error('AI percentage must be an integer between 0 and 100');
return;
}

Copilot uses AI. Check for mistakes.
applicationID := chi.URLParam(r, "applicationID")

if applicationID == "" {
app.badRequestResponse(w, r, errors.New("Application ID is required"))
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The error message for a missing applicationID uses different capitalization than other handlers (e.g., "Application ID is required" vs "application ID is required"). For consistency in API error messages, align this with the existing style used elsewhere in cmd/api/reviews.go/cmd/api/applications.go.

Suggested change
app.badRequestResponse(w, r, errors.New("Application ID is required"))
app.badRequestResponse(w, r, errors.New("application ID is required"))

Copilot uses AI. Check for mistakes.
Comment on lines 52 to 57
if (res.error === "not found") {
return {success: false, error: "You do not have permission to change this review's percentage, only the assigned admin can"}
}
else{
return { success: false, error: res.error || 'Failed to set AI Percentage' };
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

This special-cases res.error === "not found" as a permission error, but the backend returns the same "not found" payload for multiple conditions (missing application, not assigned, already set). This message will be inaccurate in some cases. Consider distinguishing these cases via status codes (e.g., 403/409) or using a more generic message.

Suggested change
if (res.error === "not found") {
return {success: false, error: "You do not have permission to change this review's percentage, only the assigned admin can"}
}
else{
return { success: false, error: res.error || 'Failed to set AI Percentage' };
}
return { success: false, error: res.error || "Unable to set AI percentage for this application." };

Copilot uses AI. Check for mistakes.
Comment on lines 704 to 710
SELECT 1 from application_reviews
where application_id = $2
and admin_id = $3
)
`

result, err := s.db.ExecContext(ctx, query, percentage, applicationID, adminID)
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

ApplicationsStore.SetAIPercentage uses $3 for ai_percentage here, but later in the EXISTS subquery $3 is used for admin_id. This placeholder reuse will make the update incorrect or fail if this method is invoked. Use distinct placeholders for (applicationID, adminID, percentage).

Suggested change
SELECT 1 from application_reviews
where application_id = $2
and admin_id = $3
)
`
result, err := s.db.ExecContext(ctx, query, percentage, applicationID, adminID)
SELECT 1 FROM application_reviews
WHERE application_id = $1
AND admin_id = $2
)
`
result, err := s.db.ExecContext(ctx, query, applicationID, adminID, percentage)

Copilot uses AI. Check for mistakes.
WaitlistVotes int `json:"waitlist_votes"`
ReviewsAssigned int `json:"reviews_assigned"`
ReviewsCompleted int `json:"reviews_completed"`
AIPercentage *int `json:"ai_percentage"`
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

ApplicationListItem.AIPercentage is typed as *int, but the DB column is SMALLINT and Application.AIPercentage is *int16. This inconsistency can lead to unnecessary type conversions and makes it harder to reason about the API schema; consider making this *int16 for consistency with the underlying column and the full Application type.

Suggested change
AIPercentage *int `json:"ai_percentage"`
AIPercentage *int16 `json:"ai_percentage"`

Copilot uses AI. Check for mistakes.
Comment on lines 131 to 133
{/* Short Answers */}
{application.short_answer_questions?.length > 0 && (
<div>
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The AI Percentage section is rendered inside this Short Answers conditional block. As a result, applications without short-answer questions will never show the AI percentage UI. Move the AI percentage section outside of this conditional.

Copilot uses AI. Check for mistakes.
Comment on lines 37 to 39
return getRequest<NotesListResponse>(
`/admin/reviews/applications/${applicationId}/notes`,
"review notes"
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The backend route for notes is /admin/applications/{applicationID}/notes (see cmd/api/api.go), but this client calls /admin/reviews/applications/{applicationId}/notes. This will 404 if used; update the endpoint path to match the server.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copliot onto something here ^

@@ -0,0 +1,2 @@
ALTER TABLE applications
ADD COLUMN ai_percentage SMALLINT DEFAULT NULL;
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The migration adds ai_percentage without a DB-level constraint to enforce the documented 0–100 range. Existing migrations use CHECK constraints for similar validation (e.g., applications_age_check in 000004_create_applications.up.sql). Consider adding a CHECK constraint (or domain) so invalid values cannot be inserted outside the API validation path.

Suggested change
ADD COLUMN ai_percentage SMALLINT DEFAULT NULL;
ADD COLUMN ai_percentage SMALLINT DEFAULT NULL;
ALTER TABLE applications
ADD CONSTRAINT applications_ai_percentage_check
CHECK (ai_percentage IS NULL OR (ai_percentage >= 0 AND ai_percentage <= 100));

Copilot uses AI. Check for mistakes.
}

type SetAIPercentagePayload struct {
AIPercentage int16 `json:"ai_percentage" validate:"required,min=0, max = 100"`
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The SetAIPercentagePayload/AIPercentageResponse types here appear unused (the API layer defines these in cmd/api/reviews.go, and Swagger references main.*). Also, the validator tag includes spaces (min=0, max = 100) which go-playground/validator will not parse as intended. Consider removing these store-level DTOs or consolidating to a single canonical definition with a correct tag.

Suggested change
AIPercentage int16 `json:"ai_percentage" validate:"required,min=0, max = 100"`
AIPercentage int16 `json:"ai_percentage" validate:"required,min=0,max=100"`

Copilot uses AI. Check for mistakes.
Comment on lines 705 to 710
where application_id = $2
and admin_id = $3
)
`

result, err := s.db.ExecContext(ctx, query, percentage, applicationID, adminID)
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The ExecContext argument order doesn’t match the SQL placeholders (WHERE id = $1 ...), since it currently passes (percentage, applicationID, adminID). Fix the argument order to align with the query (applicationID/adminID/percentage), or remove this method if ApplicationReviewsStore.SetAIPercentage is the intended implementation.

Suggested change
where application_id = $2
and admin_id = $3
)
`
result, err := s.db.ExecContext(ctx, query, percentage, applicationID, adminID)
where application_id = $1
and admin_id = $2
)
`
result, err := s.db.ExecContext(ctx, query, applicationID, adminID, percentage)

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Lowkey these copilot comments are spot on.

cmd/api/api.go Outdated
r.Put("/reviews/{reviewID}", app.submitVote)
r.Get("/reviews/completed", app.getCompletedReviews)

r.Put("/applications/{applicationID}/aiPercent", app.setAIPercentage)
Copy link
Collaborator

Choose a reason for hiding this comment

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

change this to

r.Put("/applications/{applicationID}/ai-percent", app.setAIPercentage)

once you do that, update the routes in the frontend

type AIPercentageResponse struct {
AIPercentage int16 `json:"ai_percentage"`
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

can SetAIPercentagePaylod and AIPercentage response not use the same structure? You can rename it to AIPercentage and load or get depending on the endpoint.

Copy link
Collaborator

Choose a reason for hiding this comment

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

2 seperate for reponse and request is fine, it's like that everywhere else plus response may change in the future.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

kk

return emails, nil
}

func (s *ApplicationsStore) SetAIPercentage(ctx context.Context, applicationID string, adminID string, percentage int16) error {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Where are there 2 SetAIPercentage 😭

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

uhhh wtf i dont remeber puttin 2 😭

}

// SetAIPercentage sets the AI-generated percentage on an application, only if the admin is assigned to it and it hasn't been set yet.
func (s *ApplicationReviewsStore) SetAIPercentage(ctx context.Context, applicationID string, adminID string, percentage int16) error {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Where are there 2 SetAIPercentage 😭

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also can we change the naming to SetAIPercent I don't like percentage rolls off my tongue :) lol But also I think I told you to do Ai but keep it AI.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Like change all percentage --> percent

@balebbae balebbae self-requested a review February 24, 2026 04:08
@NoelVarghese2006 NoelVarghese2006 linked an issue Feb 24, 2026 that may be closed by this pull request
5 tasks
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.

Add AI% field to applications

3 participants