fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route - #565

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable
Aug 19, 2026
Merged

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route#565
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

The Backend (pytest) job has not actually run on staging since 2026-07-10

ruff runs beforepytest in the backend job, and 82787ca left an unused-import error behind — so the suite has been skipped, not passing, ever since. Turning the lint step green (see below) makes it run again, and it comes back red on 5 tests in tests/test_gradescope.py.

What 82787ca actually shipped

That commit replaced the finished Gradescope integration with a TODO(wire-me) scaffold (649 lines of routes/gradescope.py, mostly deletions; 413 more from services/gradescope_service.py) and did not update tests/test_gradescope.py. The scaffold is broken three independent ways:

1. Every endpoint is unreachable. The router declares its own prefix andmain.py adds the same one:

# routes/gradescope.py:50router=APIRouter(prefix="/api/gradescope", tags=["gradescope"])
# main.py:167app.include_router(gradescope.router, prefix="/api/gradescope")

Dumping the live route table confirms it:

['POST'] /api/gradescope/api/gradescope/credentials
['GET'] /api/gradescope/api/gradescope/courses
['POST'] /api/gradescope/api/gradescope/sync/{sapling_course_id}

The whole feature 404s on staging today. Some tests "passed" only because they assert 404.

2. It calls a database client that does not exist. The scaffold uses supabase-py chaining:

table("gradescope_credentials").select("*").eq("user_id", user_id).execute()

but this repo's db/connection.py is PostgREST-style — select(columns, filters=...), update(data, filters), delete(filters), upsert(data, on_conflict). There is no .eq() and no .execute(), so every handler would AttributeError even if it were reachable.

3. No rate limiting and no /credentials/bu-sso, both of which tests/test_gradescope.py requires (10/5min on courses and sync, 3/10min on bu-sso, per-user).

The fix

The tests were right; the route was wrong. This restores routes/gradescope.py and services/gradescope_service.py from main — the version that matches this branch's own test file, matches this branch's db/connection.py, and is what production runs. models/gradescope.py and services/gradescope_sync_service.py from 82787ca are left in place.

Also clears the two lint errors that gate the suite:

  • models/gradescope.py — unused pydantic.Field import.
  • settings/GradescopeConnect.tsxreact-hooks/exhaustive-deps error, fixed with useCallback keyed on userId rather than a suppression. That also fixes a real bug the empty dep array hid: switching user without unmounting kept the previous account's Gradescope state.

Verification

  • ruff check . → clean (was 1 error)
  • npx eslint on the component → clean (was 1 error); npx tsc --noEmit clean
  • tests/test_gradescope.py: 25 passed (was 5 failed / 20 passed)
  • Full hermetic backend suite: 1035 passed, 23 skipped
  • Route table now mounts 9 endpoints at a single /api/gradescope/... prefix, including credentials/bu-sso

Context

staging is 239 commits behind main and carries exactly one commit main does not — 82787ca, the one above. Worth deciding separately whether staging should simply be brought up to main rather than maintained as a fork; this PR only repairs the breakage. It also unblocks #535, whose backend job fails on these same 5 tests.

…t a doubled prefix
`82787ca` replaced the finished Gradescope integration with a
`TODO(wire-me)` scaffold and left its tests behind. Nobody saw it because
`ruff` fails before `pytest` in the backend job, so the suite has not run on
staging since 2026-07-10. It is broken three independent ways:
1. The router declares `APIRouter(prefix="/api/gradescope")` and main.py
includes it with the same prefix, so every endpoint is mounted at
`/api/gradescope/api/gradescope/...`. The whole feature 404s on staging.
2. The scaffold calls `table(...).select(...).eq(...).execute()`, but this
repo's `db.connection.table()` is PostgREST-style — `select(columns,
filters=...)`, `update(data, filters)`, `delete(filters)`. There is no
`.eq()` and no `.execute()`, so every handler would AttributeError even
if it were reachable.
3. No rate limiting and no `/credentials/bu-sso` endpoint, both of which
tests/test_gradescope.py requires.
The tests were right; the route was wrong. Restores routes/gradescope.py and
services/gradescope_service.py from main — the version that matches this
branch's own test file AND its db/connection.py, and that production runs.
models/gradescope.py and services/gradescope_sync_service.py are left in
place. Also clears the two lint errors 82787ca left, which are what gate the
suite: the unused pydantic.Field import, and GradescopeConnect's
exhaustive-deps error (useCallback keyed on userId, which additionally fixes
switching user without unmounting keeping the previous account's state).
@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:14 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c74e8e73-12c5-4b4b-93ed-deda62ee3663

📥 Commits

Reviewing files that changed from the base of the PR and between 82787ca and 74597c8.

📒 Files selected for processing (4)
  • backend/models/gradescope.py
  • backend/routes/gradescope.py
  • backend/services/gradescope_service.py
  • frontend/src/components/settings/GradescopeConnect.tsx

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.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit d6a7ce4 into stagingAug 19, 2026
5 checks passed
Sign up for freeto 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

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route - #565

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable
Aug 19, 2026
Merged

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route#565
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

The Backend (pytest) job has not actually run on staging since 2026-07-10

ruff runs beforepytest in the backend job, and 82787ca left an unused-import error behind — so the suite has been skipped, not passing, ever since. Turning the lint step green (see below) makes it run again, and it comes back red on 5 tests in tests/test_gradescope.py.

What 82787ca actually shipped

That commit replaced the finished Gradescope integration with a TODO(wire-me) scaffold (649 lines of routes/gradescope.py, mostly deletions; 413 more from services/gradescope_service.py) and did not update tests/test_gradescope.py. The scaffold is broken three independent ways:

1. Every endpoint is unreachable. The router declares its own prefix andmain.py adds the same one:

# routes/gradescope.py:50router=APIRouter(prefix="/api/gradescope", tags=["gradescope"])
# main.py:167app.include_router(gradescope.router, prefix="/api/gradescope")

Dumping the live route table confirms it:

['POST'] /api/gradescope/api/gradescope/credentials
['GET'] /api/gradescope/api/gradescope/courses
['POST'] /api/gradescope/api/gradescope/sync/{sapling_course_id}

The whole feature 404s on staging today. Some tests "passed" only because they assert 404.

2. It calls a database client that does not exist. The scaffold uses supabase-py chaining:

table("gradescope_credentials").select("*").eq("user_id", user_id).execute()

but this repo's db/connection.py is PostgREST-style — select(columns, filters=...), update(data, filters), delete(filters), upsert(data, on_conflict). There is no .eq() and no .execute(), so every handler would AttributeError even if it were reachable.

3. No rate limiting and no /credentials/bu-sso, both of which tests/test_gradescope.py requires (10/5min on courses and sync, 3/10min on bu-sso, per-user).

The fix

The tests were right; the route was wrong. This restores routes/gradescope.py and services/gradescope_service.py from main — the version that matches this branch's own test file, matches this branch's db/connection.py, and is what production runs. models/gradescope.py and services/gradescope_sync_service.py from 82787ca are left in place.

Also clears the two lint errors that gate the suite:

  • models/gradescope.py — unused pydantic.Field import.
  • settings/GradescopeConnect.tsxreact-hooks/exhaustive-deps error, fixed with useCallback keyed on userId rather than a suppression. That also fixes a real bug the empty dep array hid: switching user without unmounting kept the previous account's Gradescope state.

Verification

  • ruff check . → clean (was 1 error)
  • npx eslint on the component → clean (was 1 error); npx tsc --noEmit clean
  • tests/test_gradescope.py: 25 passed (was 5 failed / 20 passed)
  • Full hermetic backend suite: 1035 passed, 23 skipped
  • Route table now mounts 9 endpoints at a single /api/gradescope/... prefix, including credentials/bu-sso

Context

staging is 239 commits behind main and carries exactly one commit main does not — 82787ca, the one above. Worth deciding separately whether staging should simply be brought up to main rather than maintained as a fork; this PR only repairs the breakage. It also unblocks #535, whose backend job fails on these same 5 tests.

…t a doubled prefix
`82787ca` replaced the finished Gradescope integration with a
`TODO(wire-me)` scaffold and left its tests behind. Nobody saw it because
`ruff` fails before `pytest` in the backend job, so the suite has not run on
staging since 2026-07-10. It is broken three independent ways:
1. The router declares `APIRouter(prefix="/api/gradescope")` and main.py
includes it with the same prefix, so every endpoint is mounted at
`/api/gradescope/api/gradescope/...`. The whole feature 404s on staging.
2. The scaffold calls `table(...).select(...).eq(...).execute()`, but this
repo's `db.connection.table()` is PostgREST-style — `select(columns,
filters=...)`, `update(data, filters)`, `delete(filters)`. There is no
`.eq()` and no `.execute()`, so every handler would AttributeError even
if it were reachable.
3. No rate limiting and no `/credentials/bu-sso` endpoint, both of which
tests/test_gradescope.py requires.
The tests were right; the route was wrong. Restores routes/gradescope.py and
services/gradescope_service.py from main — the version that matches this
branch's own test file AND its db/connection.py, and that production runs.
models/gradescope.py and services/gradescope_sync_service.py are left in
place. Also clears the two lint errors 82787ca left, which are what gate the
suite: the unused pydantic.Field import, and GradescopeConnect's
exhaustive-deps error (useCallback keyed on userId, which additionally fixes
switching user without unmounting keeping the previous account's state).
@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:14 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c74e8e73-12c5-4b4b-93ed-deda62ee3663

📥 Commits

Reviewing files that changed from the base of the PR and between 82787ca and 74597c8.

📒 Files selected for processing (4)
  • backend/models/gradescope.py
  • backend/routes/gradescope.py
  • backend/services/gradescope_service.py
  • frontend/src/components/settings/GradescopeConnect.tsx

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.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit d6a7ce4 into stagingAug 19, 2026
5 checks passed
Sign up for freeto 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

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route - #565

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable
Aug 19, 2026
Merged

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route#565
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

The Backend (pytest) job has not actually run on staging since 2026-07-10

ruff runs beforepytest in the backend job, and 82787ca left an unused-import error behind — so the suite has been skipped, not passing, ever since. Turning the lint step green (see below) makes it run again, and it comes back red on 5 tests in tests/test_gradescope.py.

What 82787ca actually shipped

That commit replaced the finished Gradescope integration with a TODO(wire-me) scaffold (649 lines of routes/gradescope.py, mostly deletions; 413 more from services/gradescope_service.py) and did not update tests/test_gradescope.py. The scaffold is broken three independent ways:

1. Every endpoint is unreachable. The router declares its own prefix andmain.py adds the same one:

# routes/gradescope.py:50router=APIRouter(prefix="/api/gradescope", tags=["gradescope"])
# main.py:167app.include_router(gradescope.router, prefix="/api/gradescope")

Dumping the live route table confirms it:

['POST'] /api/gradescope/api/gradescope/credentials
['GET'] /api/gradescope/api/gradescope/courses
['POST'] /api/gradescope/api/gradescope/sync/{sapling_course_id}

The whole feature 404s on staging today. Some tests "passed" only because they assert 404.

2. It calls a database client that does not exist. The scaffold uses supabase-py chaining:

table("gradescope_credentials").select("*").eq("user_id", user_id).execute()

but this repo's db/connection.py is PostgREST-style — select(columns, filters=...), update(data, filters), delete(filters), upsert(data, on_conflict). There is no .eq() and no .execute(), so every handler would AttributeError even if it were reachable.

3. No rate limiting and no /credentials/bu-sso, both of which tests/test_gradescope.py requires (10/5min on courses and sync, 3/10min on bu-sso, per-user).

The fix

The tests were right; the route was wrong. This restores routes/gradescope.py and services/gradescope_service.py from main — the version that matches this branch's own test file, matches this branch's db/connection.py, and is what production runs. models/gradescope.py and services/gradescope_sync_service.py from 82787ca are left in place.

Also clears the two lint errors that gate the suite:

  • models/gradescope.py — unused pydantic.Field import.
  • settings/GradescopeConnect.tsxreact-hooks/exhaustive-deps error, fixed with useCallback keyed on userId rather than a suppression. That also fixes a real bug the empty dep array hid: switching user without unmounting kept the previous account's Gradescope state.

Verification

  • ruff check . → clean (was 1 error)
  • npx eslint on the component → clean (was 1 error); npx tsc --noEmit clean
  • tests/test_gradescope.py: 25 passed (was 5 failed / 20 passed)
  • Full hermetic backend suite: 1035 passed, 23 skipped
  • Route table now mounts 9 endpoints at a single /api/gradescope/... prefix, including credentials/bu-sso

Context

staging is 239 commits behind main and carries exactly one commit main does not — 82787ca, the one above. Worth deciding separately whether staging should simply be brought up to main rather than maintained as a fork; this PR only repairs the breakage. It also unblocks #535, whose backend job fails on these same 5 tests.

…t a doubled prefix
`82787ca` replaced the finished Gradescope integration with a
`TODO(wire-me)` scaffold and left its tests behind. Nobody saw it because
`ruff` fails before `pytest` in the backend job, so the suite has not run on
staging since 2026-07-10. It is broken three independent ways:
1. The router declares `APIRouter(prefix="/api/gradescope")` and main.py
includes it with the same prefix, so every endpoint is mounted at
`/api/gradescope/api/gradescope/...`. The whole feature 404s on staging.
2. The scaffold calls `table(...).select(...).eq(...).execute()`, but this
repo's `db.connection.table()` is PostgREST-style — `select(columns,
filters=...)`, `update(data, filters)`, `delete(filters)`. There is no
`.eq()` and no `.execute()`, so every handler would AttributeError even
if it were reachable.
3. No rate limiting and no `/credentials/bu-sso` endpoint, both of which
tests/test_gradescope.py requires.
The tests were right; the route was wrong. Restores routes/gradescope.py and
services/gradescope_service.py from main — the version that matches this
branch's own test file AND its db/connection.py, and that production runs.
models/gradescope.py and services/gradescope_sync_service.py are left in
place. Also clears the two lint errors 82787ca left, which are what gate the
suite: the unused pydantic.Field import, and GradescopeConnect's
exhaustive-deps error (useCallback keyed on userId, which additionally fixes
switching user without unmounting keeping the previous account's state).
@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:14 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c74e8e73-12c5-4b4b-93ed-deda62ee3663

📥 Commits

Reviewing files that changed from the base of the PR and between 82787ca and 74597c8.

📒 Files selected for processing (4)
  • backend/models/gradescope.py
  • backend/routes/gradescope.py
  • backend/services/gradescope_service.py
  • frontend/src/components/settings/GradescopeConnect.tsx

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.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit d6a7ce4 into stagingAug 19, 2026
5 checks passed
Sign up for freeto 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

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route - #565

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable
Aug 19, 2026
Merged

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route#565
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

The Backend (pytest) job has not actually run on staging since 2026-07-10

ruff runs beforepytest in the backend job, and 82787ca left an unused-import error behind — so the suite has been skipped, not passing, ever since. Turning the lint step green (see below) makes it run again, and it comes back red on 5 tests in tests/test_gradescope.py.

What 82787ca actually shipped

That commit replaced the finished Gradescope integration with a TODO(wire-me) scaffold (649 lines of routes/gradescope.py, mostly deletions; 413 more from services/gradescope_service.py) and did not update tests/test_gradescope.py. The scaffold is broken three independent ways:

1. Every endpoint is unreachable. The router declares its own prefix andmain.py adds the same one:

# routes/gradescope.py:50router=APIRouter(prefix="/api/gradescope", tags=["gradescope"])
# main.py:167app.include_router(gradescope.router, prefix="/api/gradescope")

Dumping the live route table confirms it:

['POST'] /api/gradescope/api/gradescope/credentials
['GET'] /api/gradescope/api/gradescope/courses
['POST'] /api/gradescope/api/gradescope/sync/{sapling_course_id}

The whole feature 404s on staging today. Some tests "passed" only because they assert 404.

2. It calls a database client that does not exist. The scaffold uses supabase-py chaining:

table("gradescope_credentials").select("*").eq("user_id", user_id).execute()

but this repo's db/connection.py is PostgREST-style — select(columns, filters=...), update(data, filters), delete(filters), upsert(data, on_conflict). There is no .eq() and no .execute(), so every handler would AttributeError even if it were reachable.

3. No rate limiting and no /credentials/bu-sso, both of which tests/test_gradescope.py requires (10/5min on courses and sync, 3/10min on bu-sso, per-user).

The fix

The tests were right; the route was wrong. This restores routes/gradescope.py and services/gradescope_service.py from main — the version that matches this branch's own test file, matches this branch's db/connection.py, and is what production runs. models/gradescope.py and services/gradescope_sync_service.py from 82787ca are left in place.

Also clears the two lint errors that gate the suite:

  • models/gradescope.py — unused pydantic.Field import.
  • settings/GradescopeConnect.tsxreact-hooks/exhaustive-deps error, fixed with useCallback keyed on userId rather than a suppression. That also fixes a real bug the empty dep array hid: switching user without unmounting kept the previous account's Gradescope state.

Verification

  • ruff check . → clean (was 1 error)
  • npx eslint on the component → clean (was 1 error); npx tsc --noEmit clean
  • tests/test_gradescope.py: 25 passed (was 5 failed / 20 passed)
  • Full hermetic backend suite: 1035 passed, 23 skipped
  • Route table now mounts 9 endpoints at a single /api/gradescope/... prefix, including credentials/bu-sso

Context

staging is 239 commits behind main and carries exactly one commit main does not — 82787ca, the one above. Worth deciding separately whether staging should simply be brought up to main rather than maintained as a fork; this PR only repairs the breakage. It also unblocks #535, whose backend job fails on these same 5 tests.

…t a doubled prefix
`82787ca` replaced the finished Gradescope integration with a
`TODO(wire-me)` scaffold and left its tests behind. Nobody saw it because
`ruff` fails before `pytest` in the backend job, so the suite has not run on
staging since 2026-07-10. It is broken three independent ways:
1. The router declares `APIRouter(prefix="/api/gradescope")` and main.py
includes it with the same prefix, so every endpoint is mounted at
`/api/gradescope/api/gradescope/...`. The whole feature 404s on staging.
2. The scaffold calls `table(...).select(...).eq(...).execute()`, but this
repo's `db.connection.table()` is PostgREST-style — `select(columns,
filters=...)`, `update(data, filters)`, `delete(filters)`. There is no
`.eq()` and no `.execute()`, so every handler would AttributeError even
if it were reachable.
3. No rate limiting and no `/credentials/bu-sso` endpoint, both of which
tests/test_gradescope.py requires.
The tests were right; the route was wrong. Restores routes/gradescope.py and
services/gradescope_service.py from main — the version that matches this
branch's own test file AND its db/connection.py, and that production runs.
models/gradescope.py and services/gradescope_sync_service.py are left in
place. Also clears the two lint errors 82787ca left, which are what gate the
suite: the unused pydantic.Field import, and GradescopeConnect's
exhaustive-deps error (useCallback keyed on userId, which additionally fixes
switching user without unmounting keeping the previous account's state).
@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:14 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c74e8e73-12c5-4b4b-93ed-deda62ee3663

📥 Commits

Reviewing files that changed from the base of the PR and between 82787ca and 74597c8.

📒 Files selected for processing (4)
  • backend/models/gradescope.py
  • backend/routes/gradescope.py
  • backend/services/gradescope_service.py
  • frontend/src/components/settings/GradescopeConnect.tsx

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.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit d6a7ce4 into stagingAug 19, 2026
5 checks passed
Sign up for freeto 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

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route - #565

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable
Aug 19, 2026
Merged

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route#565
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

The Backend (pytest) job has not actually run on staging since 2026-07-10

ruff runs beforepytest in the backend job, and 82787ca left an unused-import error behind — so the suite has been skipped, not passing, ever since. Turning the lint step green (see below) makes it run again, and it comes back red on 5 tests in tests/test_gradescope.py.

What 82787ca actually shipped

That commit replaced the finished Gradescope integration with a TODO(wire-me) scaffold (649 lines of routes/gradescope.py, mostly deletions; 413 more from services/gradescope_service.py) and did not update tests/test_gradescope.py. The scaffold is broken three independent ways:

1. Every endpoint is unreachable. The router declares its own prefix andmain.py adds the same one:

# routes/gradescope.py:50router=APIRouter(prefix="/api/gradescope", tags=["gradescope"])
# main.py:167app.include_router(gradescope.router, prefix="/api/gradescope")

Dumping the live route table confirms it:

['POST'] /api/gradescope/api/gradescope/credentials
['GET'] /api/gradescope/api/gradescope/courses
['POST'] /api/gradescope/api/gradescope/sync/{sapling_course_id}

The whole feature 404s on staging today. Some tests "passed" only because they assert 404.

2. It calls a database client that does not exist. The scaffold uses supabase-py chaining:

table("gradescope_credentials").select("*").eq("user_id", user_id).execute()

but this repo's db/connection.py is PostgREST-style — select(columns, filters=...), update(data, filters), delete(filters), upsert(data, on_conflict). There is no .eq() and no .execute(), so every handler would AttributeError even if it were reachable.

3. No rate limiting and no /credentials/bu-sso, both of which tests/test_gradescope.py requires (10/5min on courses and sync, 3/10min on bu-sso, per-user).

The fix

The tests were right; the route was wrong. This restores routes/gradescope.py and services/gradescope_service.py from main — the version that matches this branch's own test file, matches this branch's db/connection.py, and is what production runs. models/gradescope.py and services/gradescope_sync_service.py from 82787ca are left in place.

Also clears the two lint errors that gate the suite:

  • models/gradescope.py — unused pydantic.Field import.
  • settings/GradescopeConnect.tsxreact-hooks/exhaustive-deps error, fixed with useCallback keyed on userId rather than a suppression. That also fixes a real bug the empty dep array hid: switching user without unmounting kept the previous account's Gradescope state.

Verification

  • ruff check . → clean (was 1 error)
  • npx eslint on the component → clean (was 1 error); npx tsc --noEmit clean
  • tests/test_gradescope.py: 25 passed (was 5 failed / 20 passed)
  • Full hermetic backend suite: 1035 passed, 23 skipped
  • Route table now mounts 9 endpoints at a single /api/gradescope/... prefix, including credentials/bu-sso

Context

staging is 239 commits behind main and carries exactly one commit main does not — 82787ca, the one above. Worth deciding separately whether staging should simply be brought up to main rather than maintained as a fork; this PR only repairs the breakage. It also unblocks #535, whose backend job fails on these same 5 tests.

…t a doubled prefix
`82787ca` replaced the finished Gradescope integration with a
`TODO(wire-me)` scaffold and left its tests behind. Nobody saw it because
`ruff` fails before `pytest` in the backend job, so the suite has not run on
staging since 2026-07-10. It is broken three independent ways:
1. The router declares `APIRouter(prefix="/api/gradescope")` and main.py
includes it with the same prefix, so every endpoint is mounted at
`/api/gradescope/api/gradescope/...`. The whole feature 404s on staging.
2. The scaffold calls `table(...).select(...).eq(...).execute()`, but this
repo's `db.connection.table()` is PostgREST-style — `select(columns,
filters=...)`, `update(data, filters)`, `delete(filters)`. There is no
`.eq()` and no `.execute()`, so every handler would AttributeError even
if it were reachable.
3. No rate limiting and no `/credentials/bu-sso` endpoint, both of which
tests/test_gradescope.py requires.
The tests were right; the route was wrong. Restores routes/gradescope.py and
services/gradescope_service.py from main — the version that matches this
branch's own test file AND its db/connection.py, and that production runs.
models/gradescope.py and services/gradescope_sync_service.py are left in
place. Also clears the two lint errors 82787ca left, which are what gate the
suite: the unused pydantic.Field import, and GradescopeConnect's
exhaustive-deps error (useCallback keyed on userId, which additionally fixes
switching user without unmounting keeping the previous account's state).
@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:14 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c74e8e73-12c5-4b4b-93ed-deda62ee3663

📥 Commits

Reviewing files that changed from the base of the PR and between 82787ca and 74597c8.

📒 Files selected for processing (4)
  • backend/models/gradescope.py
  • backend/routes/gradescope.py
  • backend/services/gradescope_service.py
  • frontend/src/components/settings/GradescopeConnect.tsx

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.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit d6a7ce4 into stagingAug 19, 2026
5 checks passed
Sign up for freeto 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

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route - #565

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable
Aug 19, 2026
Merged

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route#565
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

The Backend (pytest) job has not actually run on staging since 2026-07-10

ruff runs beforepytest in the backend job, and 82787ca left an unused-import error behind — so the suite has been skipped, not passing, ever since. Turning the lint step green (see below) makes it run again, and it comes back red on 5 tests in tests/test_gradescope.py.

What 82787ca actually shipped

That commit replaced the finished Gradescope integration with a TODO(wire-me) scaffold (649 lines of routes/gradescope.py, mostly deletions; 413 more from services/gradescope_service.py) and did not update tests/test_gradescope.py. The scaffold is broken three independent ways:

1. Every endpoint is unreachable. The router declares its own prefix andmain.py adds the same one:

# routes/gradescope.py:50router=APIRouter(prefix="/api/gradescope", tags=["gradescope"])
# main.py:167app.include_router(gradescope.router, prefix="/api/gradescope")

Dumping the live route table confirms it:

['POST'] /api/gradescope/api/gradescope/credentials
['GET'] /api/gradescope/api/gradescope/courses
['POST'] /api/gradescope/api/gradescope/sync/{sapling_course_id}

The whole feature 404s on staging today. Some tests "passed" only because they assert 404.

2. It calls a database client that does not exist. The scaffold uses supabase-py chaining:

table("gradescope_credentials").select("*").eq("user_id", user_id).execute()

but this repo's db/connection.py is PostgREST-style — select(columns, filters=...), update(data, filters), delete(filters), upsert(data, on_conflict). There is no .eq() and no .execute(), so every handler would AttributeError even if it were reachable.

3. No rate limiting and no /credentials/bu-sso, both of which tests/test_gradescope.py requires (10/5min on courses and sync, 3/10min on bu-sso, per-user).

The fix

The tests were right; the route was wrong. This restores routes/gradescope.py and services/gradescope_service.py from main — the version that matches this branch's own test file, matches this branch's db/connection.py, and is what production runs. models/gradescope.py and services/gradescope_sync_service.py from 82787ca are left in place.

Also clears the two lint errors that gate the suite:

  • models/gradescope.py — unused pydantic.Field import.
  • settings/GradescopeConnect.tsxreact-hooks/exhaustive-deps error, fixed with useCallback keyed on userId rather than a suppression. That also fixes a real bug the empty dep array hid: switching user without unmounting kept the previous account's Gradescope state.

Verification

  • ruff check . → clean (was 1 error)
  • npx eslint on the component → clean (was 1 error); npx tsc --noEmit clean
  • tests/test_gradescope.py: 25 passed (was 5 failed / 20 passed)
  • Full hermetic backend suite: 1035 passed, 23 skipped
  • Route table now mounts 9 endpoints at a single /api/gradescope/... prefix, including credentials/bu-sso

Context

staging is 239 commits behind main and carries exactly one commit main does not — 82787ca, the one above. Worth deciding separately whether staging should simply be brought up to main rather than maintained as a fork; this PR only repairs the breakage. It also unblocks #535, whose backend job fails on these same 5 tests.

…t a doubled prefix
`82787ca` replaced the finished Gradescope integration with a
`TODO(wire-me)` scaffold and left its tests behind. Nobody saw it because
`ruff` fails before `pytest` in the backend job, so the suite has not run on
staging since 2026-07-10. It is broken three independent ways:
1. The router declares `APIRouter(prefix="/api/gradescope")` and main.py
includes it with the same prefix, so every endpoint is mounted at
`/api/gradescope/api/gradescope/...`. The whole feature 404s on staging.
2. The scaffold calls `table(...).select(...).eq(...).execute()`, but this
repo's `db.connection.table()` is PostgREST-style — `select(columns,
filters=...)`, `update(data, filters)`, `delete(filters)`. There is no
`.eq()` and no `.execute()`, so every handler would AttributeError even
if it were reachable.
3. No rate limiting and no `/credentials/bu-sso` endpoint, both of which
tests/test_gradescope.py requires.
The tests were right; the route was wrong. Restores routes/gradescope.py and
services/gradescope_service.py from main — the version that matches this
branch's own test file AND its db/connection.py, and that production runs.
models/gradescope.py and services/gradescope_sync_service.py are left in
place. Also clears the two lint errors 82787ca left, which are what gate the
suite: the unused pydantic.Field import, and GradescopeConnect's
exhaustive-deps error (useCallback keyed on userId, which additionally fixes
switching user without unmounting keeping the previous account's state).
@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:14 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c74e8e73-12c5-4b4b-93ed-deda62ee3663

📥 Commits

Reviewing files that changed from the base of the PR and between 82787ca and 74597c8.

📒 Files selected for processing (4)
  • backend/models/gradescope.py
  • backend/routes/gradescope.py
  • backend/services/gradescope_service.py
  • frontend/src/components/settings/GradescopeConnect.tsx

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.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit d6a7ce4 into stagingAug 19, 2026
5 checks passed
Sign up for freeto 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

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route - #565

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable
Aug 19, 2026
Merged

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route#565
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

The Backend (pytest) job has not actually run on staging since 2026-07-10

ruff runs beforepytest in the backend job, and 82787ca left an unused-import error behind — so the suite has been skipped, not passing, ever since. Turning the lint step green (see below) makes it run again, and it comes back red on 5 tests in tests/test_gradescope.py.

What 82787ca actually shipped

That commit replaced the finished Gradescope integration with a TODO(wire-me) scaffold (649 lines of routes/gradescope.py, mostly deletions; 413 more from services/gradescope_service.py) and did not update tests/test_gradescope.py. The scaffold is broken three independent ways:

1. Every endpoint is unreachable. The router declares its own prefix andmain.py adds the same one:

# routes/gradescope.py:50router=APIRouter(prefix="/api/gradescope", tags=["gradescope"])
# main.py:167app.include_router(gradescope.router, prefix="/api/gradescope")

Dumping the live route table confirms it:

['POST'] /api/gradescope/api/gradescope/credentials
['GET'] /api/gradescope/api/gradescope/courses
['POST'] /api/gradescope/api/gradescope/sync/{sapling_course_id}

The whole feature 404s on staging today. Some tests "passed" only because they assert 404.

2. It calls a database client that does not exist. The scaffold uses supabase-py chaining:

table("gradescope_credentials").select("*").eq("user_id", user_id).execute()

but this repo's db/connection.py is PostgREST-style — select(columns, filters=...), update(data, filters), delete(filters), upsert(data, on_conflict). There is no .eq() and no .execute(), so every handler would AttributeError even if it were reachable.

3. No rate limiting and no /credentials/bu-sso, both of which tests/test_gradescope.py requires (10/5min on courses and sync, 3/10min on bu-sso, per-user).

The fix

The tests were right; the route was wrong. This restores routes/gradescope.py and services/gradescope_service.py from main — the version that matches this branch's own test file, matches this branch's db/connection.py, and is what production runs. models/gradescope.py and services/gradescope_sync_service.py from 82787ca are left in place.

Also clears the two lint errors that gate the suite:

  • models/gradescope.py — unused pydantic.Field import.
  • settings/GradescopeConnect.tsxreact-hooks/exhaustive-deps error, fixed with useCallback keyed on userId rather than a suppression. That also fixes a real bug the empty dep array hid: switching user without unmounting kept the previous account's Gradescope state.

Verification

  • ruff check . → clean (was 1 error)
  • npx eslint on the component → clean (was 1 error); npx tsc --noEmit clean
  • tests/test_gradescope.py: 25 passed (was 5 failed / 20 passed)
  • Full hermetic backend suite: 1035 passed, 23 skipped
  • Route table now mounts 9 endpoints at a single /api/gradescope/... prefix, including credentials/bu-sso

Context

staging is 239 commits behind main and carries exactly one commit main does not — 82787ca, the one above. Worth deciding separately whether staging should simply be brought up to main rather than maintained as a fork; this PR only repairs the breakage. It also unblocks #535, whose backend job fails on these same 5 tests.

…t a doubled prefix
`82787ca` replaced the finished Gradescope integration with a
`TODO(wire-me)` scaffold and left its tests behind. Nobody saw it because
`ruff` fails before `pytest` in the backend job, so the suite has not run on
staging since 2026-07-10. It is broken three independent ways:
1. The router declares `APIRouter(prefix="/api/gradescope")` and main.py
includes it with the same prefix, so every endpoint is mounted at
`/api/gradescope/api/gradescope/...`. The whole feature 404s on staging.
2. The scaffold calls `table(...).select(...).eq(...).execute()`, but this
repo's `db.connection.table()` is PostgREST-style — `select(columns,
filters=...)`, `update(data, filters)`, `delete(filters)`. There is no
`.eq()` and no `.execute()`, so every handler would AttributeError even
if it were reachable.
3. No rate limiting and no `/credentials/bu-sso` endpoint, both of which
tests/test_gradescope.py requires.
The tests were right; the route was wrong. Restores routes/gradescope.py and
services/gradescope_service.py from main — the version that matches this
branch's own test file AND its db/connection.py, and that production runs.
models/gradescope.py and services/gradescope_sync_service.py are left in
place. Also clears the two lint errors 82787ca left, which are what gate the
suite: the unused pydantic.Field import, and GradescopeConnect's
exhaustive-deps error (useCallback keyed on userId, which additionally fixes
switching user without unmounting keeping the previous account's state).
@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:14 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c74e8e73-12c5-4b4b-93ed-deda62ee3663

📥 Commits

Reviewing files that changed from the base of the PR and between 82787ca and 74597c8.

📒 Files selected for processing (4)
  • backend/models/gradescope.py
  • backend/routes/gradescope.py
  • backend/services/gradescope_service.py
  • frontend/src/components/settings/GradescopeConnect.tsx

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.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit d6a7ce4 into stagingAug 19, 2026
5 checks passed
Sign up for freeto 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

@Jose-Gael-Cruz-Lopez
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route - #565

Merged
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable
Aug 19, 2026
Merged

fix(gradescope): staging serves the whole feature at a doubled prefix; restore the working route#565
Jose-Gael-Cruz-Lopez merged 1 commit into
stagingfrom
fix/staging-gradescope-unreachable

Conversation

@Jose-Gael-Cruz-Lopez

Copy link
Copy Markdown
Member

The Backend (pytest) job has not actually run on staging since 2026-07-10

ruff runs beforepytest in the backend job, and 82787ca left an unused-import error behind — so the suite has been skipped, not passing, ever since. Turning the lint step green (see below) makes it run again, and it comes back red on 5 tests in tests/test_gradescope.py.

What 82787ca actually shipped

That commit replaced the finished Gradescope integration with a TODO(wire-me) scaffold (649 lines of routes/gradescope.py, mostly deletions; 413 more from services/gradescope_service.py) and did not update tests/test_gradescope.py. The scaffold is broken three independent ways:

1. Every endpoint is unreachable. The router declares its own prefix andmain.py adds the same one:

# routes/gradescope.py:50router=APIRouter(prefix="/api/gradescope", tags=["gradescope"])
# main.py:167app.include_router(gradescope.router, prefix="/api/gradescope")

Dumping the live route table confirms it:

['POST'] /api/gradescope/api/gradescope/credentials
['GET'] /api/gradescope/api/gradescope/courses
['POST'] /api/gradescope/api/gradescope/sync/{sapling_course_id}

The whole feature 404s on staging today. Some tests "passed" only because they assert 404.

2. It calls a database client that does not exist. The scaffold uses supabase-py chaining:

table("gradescope_credentials").select("*").eq("user_id", user_id).execute()

but this repo's db/connection.py is PostgREST-style — select(columns, filters=...), update(data, filters), delete(filters), upsert(data, on_conflict). There is no .eq() and no .execute(), so every handler would AttributeError even if it were reachable.

3. No rate limiting and no /credentials/bu-sso, both of which tests/test_gradescope.py requires (10/5min on courses and sync, 3/10min on bu-sso, per-user).

The fix

The tests were right; the route was wrong. This restores routes/gradescope.py and services/gradescope_service.py from main — the version that matches this branch's own test file, matches this branch's db/connection.py, and is what production runs. models/gradescope.py and services/gradescope_sync_service.py from 82787ca are left in place.

Also clears the two lint errors that gate the suite:

  • models/gradescope.py — unused pydantic.Field import.
  • settings/GradescopeConnect.tsxreact-hooks/exhaustive-deps error, fixed with useCallback keyed on userId rather than a suppression. That also fixes a real bug the empty dep array hid: switching user without unmounting kept the previous account's Gradescope state.

Verification

  • ruff check . → clean (was 1 error)
  • npx eslint on the component → clean (was 1 error); npx tsc --noEmit clean
  • tests/test_gradescope.py: 25 passed (was 5 failed / 20 passed)
  • Full hermetic backend suite: 1035 passed, 23 skipped
  • Route table now mounts 9 endpoints at a single /api/gradescope/... prefix, including credentials/bu-sso

Context

staging is 239 commits behind main and carries exactly one commit main does not — 82787ca, the one above. Worth deciding separately whether staging should simply be brought up to main rather than maintained as a fork; this PR only repairs the breakage. It also unblocks #535, whose backend job fails on these same 5 tests.

…t a doubled prefix
`82787ca` replaced the finished Gradescope integration with a
`TODO(wire-me)` scaffold and left its tests behind. Nobody saw it because
`ruff` fails before `pytest` in the backend job, so the suite has not run on
staging since 2026-07-10. It is broken three independent ways:
1. The router declares `APIRouter(prefix="/api/gradescope")` and main.py
includes it with the same prefix, so every endpoint is mounted at
`/api/gradescope/api/gradescope/...`. The whole feature 404s on staging.
2. The scaffold calls `table(...).select(...).eq(...).execute()`, but this
repo's `db.connection.table()` is PostgREST-style — `select(columns,
filters=...)`, `update(data, filters)`, `delete(filters)`. There is no
`.eq()` and no `.execute()`, so every handler would AttributeError even
if it were reachable.
3. No rate limiting and no `/credentials/bu-sso` endpoint, both of which
tests/test_gradescope.py requires.
The tests were right; the route was wrong. Restores routes/gradescope.py and
services/gradescope_service.py from main — the version that matches this
branch's own test file AND its db/connection.py, and that production runs.
models/gradescope.py and services/gradescope_sync_service.py are left in
place. Also clears the two lint errors 82787ca left, which are what gate the
suite: the unused pydantic.Field import, and GradescopeConnect's
exhaustive-deps error (useCallback keyed on userId, which additionally fixes
switching user without unmounting keeping the previous account's state).
@supabase

supabaseBot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

Copy link
Copy Markdown

Warning

Review limit reached

@Jose-Gael-Cruz-Lopez, you've reached your PR review limit, so we couldn't start this review.

Next review available in:14 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c74e8e73-12c5-4b4b-93ed-deda62ee3663

📥 Commits

Reviewing files that changed from the base of the PR and between 82787ca and 74597c8.

📒 Files selected for processing (4)
  • backend/models/gradescope.py
  • backend/routes/gradescope.py
  • backend/services/gradescope_service.py
  • frontend/src/components/settings/GradescopeConnect.tsx

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.

@Jose-Gael-Cruz-Lopez
Jose-Gael-Cruz-Lopez merged commit d6a7ce4 into stagingAug 19, 2026
5 checks passed
Sign up for freeto 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

@Jose-Gael-Cruz-Lopez