Skip to content

feat: fixing duplicate schedule creation and manage in-flight state f…#70

Merged
BeWelsh merged 4 commits into
mainfrom
schedule-fixes
Apr 23, 2026
Merged

feat: fixing duplicate schedule creation and manage in-flight state f…#70
BeWelsh merged 4 commits into
mainfrom
schedule-fixes

Conversation

@Saisri24
Copy link
Copy Markdown
Collaborator

@Saisri24 Saisri24 commented Apr 23, 2026

…or schedule operations

Description

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactoring (code improvement without changing functionality)
  • Documentation update
  • Configuration/infrastructure change
  • Performance improvement
  • Test coverage improvement

What Changed?

  • fixed the fact that multiple of the same schedules show up on the frontend
  • fixed the fact that once you delete a schedule you can't create another one for that semester

Testing & Validation

How this was tested

Screenshots/Recordings

Unfinished Work & Known Issues

  • None, this PR is complete and production-ready
  • The following items are intentionally deferred:



Notes & Nuances



Reviewer Notes

  • Areas needing extra attention: ...
  • Questions for reviewers: ...

Summary by CodeRabbit

Bug Fixes

  • Fixed an issue where schedule creation would error when multiple inactive schedules existed
  • Prevented duplicate concurrent requests for schedule creation and generation operations
  • Fixed duplicate schedules appearing in the list after creation

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 23, 2026

Walkthrough

Backend course service now raises a "multiple schedules" error only when multiple active schedules exist for a semester/campus. Frontend schedule list component guards concurrent requests with in-flight tracking refs and deduplicates newly created schedules by ID to prevent duplicates and race conditions.

Changes

Cohort / File(s) Summary
Backend Course Service
backend/app/services/course.py
Modified generate_course_list error condition to check for multiple active schedules instead of all schedules regardless of status before raising ValueError.
Frontend Schedule Handlers
frontend/src/pages/ScheduleList.tsx
Added concurrent request guards using createInFlightRef and generateInFlightRef to prevent duplicate in-flight requests, and implemented schedule deduplication by schedule_id on creation to prevent duplicate list entries.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A schedule once tangled, now flows clean and bright,
No duplicate requests will muddy the night,
Active schedules counted, not all in the pile,
De-duplication hops bring order with style! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description is incomplete; it identifies two key issues fixed but lacks concrete testing steps, implementation details, and most template sections remain empty with placeholder content. Complete the description by: filling in specific testing steps for both fixes, detailing why the in-flight state and deduplication changes prevent duplicate schedules and soft-delete issues, and clarifying the backend change to ValueError logic.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: fixing duplicate schedule creation and managing in-flight state for schedule operations, which aligns with the primary frontend and backend fixes.
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 schedule-fixes

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 and usage tips.

Copy link
Copy Markdown
Collaborator

@BeWelsh BeWelsh left a comment

Choose a reason for hiding this comment

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

actually - I don't think this will work as most schedules from the year prior will be finalize and not be active. We still want to use these schedules. I dont think a user should run into this if they are deleted competing schedules for the same semester- i will investigate

Copy link
Copy Markdown
Collaborator

@BeWelsh BeWelsh left a comment

Choose a reason for hiding this comment

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

Take a look at what i changed - this is so we are making sure there are no other active schedules for that semester, but we are still using course data from the inactive schedules to build the new schedule

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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/app/services/course.py (1)

116-125: ⚠️ Potential issue | 🔴 Critical

schedules[0] may reference a soft-deleted schedule — copy from prior year silently uses wrong data.

The code filters the error check for active schedules (line 118) but continues to use schedules[0] without filtering. Since get_schedules(db, semester, campus_id) is called without the active_only parameter, it returns all schedules (both active and soft-deleted) in undefined order. If the soft-deleted row sorts first, the new draft copies courses/sections from a soft-deleted schedule, contradicting the stated intent.

Additionally, if no active prior schedule exists but inactive ones do, the code silently bootstraps from soft-deleted data instead of raising an error—inconsistent with the docstring requirement for "a prior schedule with historical data."

Fix: Extract active schedules first, use the filtered list, and raise when no active schedule exists.

Proposed fix
-    # Only consider active schedules.
     schedules = semester_repo.get_schedules(db, semester, campus_id)
-    if len([s for s in schedules if s.active]) > 1:
+    active_schedules = [s for s in schedules if s.active]
+    if len(active_schedules) > 1:
         raise ValueError(f"Semester {semester_id} has multiple schedules for campus {campus_id}; expected 1")
+    if not active_schedules:
+        raise ValueError(f"No active prior schedule found for semester {semester_id}, campus {campus_id}")
 
-    courses = schedule_repo.get_courses(schedules[0])
+    prior = active_schedules[0]
+    courses = schedule_repo.get_courses(prior)
     if not courses:
-        raise ValueError(f"Prior schedule (id={schedules[0].schedule_id}) has no sections to copy from")
+        raise ValueError(f"Prior schedule (id={prior.schedule_id}) has no sections to copy from")
 
-    return sort_course_list(get_section_count(schedules[0], courses, []))
+    return sort_course_list(get_section_count(prior, courses, []))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/services/course.py` around lines 116 - 125, The code currently
calls semester_repo.get_schedules(...) and then uses schedules[0] without
filtering out soft-deleted rows; change to first obtain only active schedules
(filter schedules by s.active or request active_only from
semester_repo.get_schedules if available), then validate there is exactly one
active schedule (raise ValueError if none or >1), and use that active schedule
when calling schedule_repo.get_courses(...), get_section_count(...) and
sort_course_list(...); ensure error messages reference the semester_id/campus_id
and the chosen schedule_id when raising to avoid silently copying from a
soft-deleted schedule.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@backend/app/services/course.py`:
- Around line 116-125: The code currently calls semester_repo.get_schedules(...)
and then uses schedules[0] without filtering out soft-deleted rows; change to
first obtain only active schedules (filter schedules by s.active or request
active_only from semester_repo.get_schedules if available), then validate there
is exactly one active schedule (raise ValueError if none or >1), and use that
active schedule when calling schedule_repo.get_courses(...),
get_section_count(...) and sort_course_list(...); ensure error messages
reference the semester_id/campus_id and the chosen schedule_id when raising to
avoid silently copying from a soft-deleted schedule.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2ee508b2-9f8c-4cf8-92c9-b9a35f2b354e

📥 Commits

Reviewing files that changed from the base of the PR and between f312da9 and 3acf2cf.

📒 Files selected for processing (2)
  • backend/app/services/course.py
  • frontend/src/pages/ScheduleList.tsx

@BeWelsh BeWelsh merged commit 779230e into main Apr 23, 2026
3 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Apr 24, 2026
10 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.

2 participants