Uh oh!
There was an error while loading. Please reload this page.
Promote staging → production: design-system, agents, calendar rewire, storage lockdown - #305
Conversation
Rewires sync_to_google and export_to_google onto the enrollment-keyed schema: select/write-back scoped by enrollment_id membership instead of the removed user_id column; drops courses!left embed in favour of _course_meta_cached. Updates test_calendar_export_idor.py and test_calendar_sibling_write_scoping.py to assert the new enrollment_id boundary (same IDOR guarantee, new key). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ment schema - routes/documents.py: pass source="syllabus" at both save_assignments_to_db call sites (_save_orchestrator_syllabus and the legacy call_gemini_json path) - tests/test_calendar_routes.py: rewire TestSaveAssignments to include course_id in fixtures and mock enrollment_id_for/user_enrollment_ids; rewire TestGetUpcoming.test_returns_assignments_from_db to the enrollment-keyed row shape (enrollment_id, no user_id/course_id/courses columns); add _tbl helper - tests/test_assignment_notes_encryption.py: supply course_id to test fixtures and mock academics so insert_new_assignments reaches the encryption boundary - tests/test_documents_routes.py: update assert_called_once_with to include source='syllabus' to match the new tagged call Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nrollment-rewire fix(calendar): rewire assignments to the enrollment-keyed schema (dashboard 500)
…legend - Remove r > 10 gate in KnowledgeGraph2D so every concept node shows its name regardless of mastery score (unexplored nodes have r=8, below old threshold) - Capitalize legend labels: mastered/learning/struggling/unexplored → title case - Add react-force-graph-3d (missing from node_modules, caused build error) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…g sticks handleOnboardingComplete POSTed /api/onboarding/profile to the cross-origin NEXT_PUBLIC_API_URL without credentials:'include', so the browser dropped the sapling_session cookie and the backend's require_self returned 401. The onboarding_completed flag never flipped to True — and because the code never checked res.ok, the 401 was swallowed and users were routed to /dashboard as if it worked, then bounced back to "Get Started" on every subsequent sign-in. Switch to the existing submitOnboardingProfile() helper, which goes through the same-origin lib/api.ts fetchJSON path (API_URL='' proxied via the /api/* rewrite, credentials:'include', and an res.ok check that surfaces failures instead of hiding them). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ersistence fix(onboarding): persist completion so users aren't trapped in the Get Started loop
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ate states correct) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…plicate namespace Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rarity + glass-input Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ng-layer host Moves landing + about/careers/privacy/terms under app/(public)/ (URLs unchanged). The layout applies a token-only .public-surface scope so content pages keep the warm paper canvas; the landing retains .landing-page for its mesh visual. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(public)/page.tsx, HowItWorks.tsx, Dialog.tsx: --brand-text1/2 -> --text/--text-dim, --radius-* -> --r-*, --ease-out/in-out -> --ease. Mechanical identifier renames only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ngle namespace Migrates the 3 remaining globals.css --ease-out consumers to --ease, then deletes the temporary :root brand aliases and the .public-surface/.landing-page namespace aliases. Zero retired-token references remain tree-wide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… + dir hygiene) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…/page.tsx The route move shifted the landing page out from under its path-keyed suppression entry, un-suppressing 4 pre-existing grandfathered errors (no-html-link-for-pages, prefer-const x2, react-hooks/immutability). Re-homes the entry to the new path; no code behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rison Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Retire sage --accent -> brighter forest (--brand-forest-bright) for highlight/focus; merge --state-mastery + --grade-a into one --positive status green; add .btn--lg hero size for de-pilled CTAs. Three forest-family greens by role: forest(action) / accent(highlight) / positive(status). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Thin wrappers over the canonical .btn/.chip classes. Button enforces one shape (6px) with variant + size (incl. lg hero size); Toggle is the one segmented control; Chip/Badge collapse the pill/badge zoo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ives - Landing CTAs (Get Started x2, Sign up for Beta) -> <Button size=lg>, de-pilled to sharp 6px, infinite glow removed. - 5 Gradebook modal save/submit buttons -> <Button> (kills hard-coded borderRadius:6). - Study flashcard ratings 10px -> 6px (kept color-coding). - Tokenize orphan #1a5c2a wordmark -> var(--brand-forest) across 8 files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add optional per-option title to <Toggle>; replace the Learn setup mode pills with it. ModelToggle (Fast/Smart) intentionally left as-is — it has a sliding animation, per-option color semantics, and a tooltip that the generic Toggle would degrade. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Flair Badge carries the hue on border + soft bg, keeps text neutral (colored text fails 4.5:1 on several rarity tiers). TitleFlair now wraps Badge instead of inline styles. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…arted CTA De-pilled CTAs hug the text now (lg 13/26 -> 9/18). The closing 'Get Started' under the 'Ready to Start Growing?' hero uses a new xl size so it stays a prominent central focal point; navbar + hero beta stay tight. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bright accent The header button hard-coded background:var(--accent); after accent shifted to the brighter forest, it rendered brighter than every other primary button. Now a proper <Button variant=primary> (--brand-forest), matching the term pills and app buttons. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Family (b) control: a wrapping row of selectable pills for 'All' + N dynamic filters, wrapping the existing <Pill> (with per-option color/icon). Complements <Toggle> (family (a): fixed connected segmented control). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the custom accent-filled pill buttons with the shared <Toggle> (forest-filled active). Keeps SemesterChips' public API; also fixes the prior --accent button fill. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Overview/Chat/Study match/Activity tab row now uses the shared <Toggle>. setTab wiring unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(agents): migrate remaining one-shot LLM calls to Pydantic AI agents (#147)
…mini fallback (#144) calendar_service already extracted via syllabus_extraction_agent as the primary path; the raw-Gemini `parse_syllabus`/`call_gemini_json` fallback was the only remaining seam. Remove it and degrade gracefully instead: - Delete parse_syllabus, the call_gemini_json import, and the now-unused PROMPT_PATH. On agent guardrail-trip or unexpected failure, extract_assignments_from_file now returns _degraded_result (empty assignments + a user-facing warning, no second LLM call) — resilience without a raw Gemini call. - Response contract preserved: {assignments, warnings, raw_text} on every path (success / degrade / empty-text). - notes stay encrypted at the write boundary (insert_new_assignments, encrypt_if_present) per #126 — added a regression test. Tests: rewrote the parse_syllabus-based fallback tests in test_ocr_pipeline.py to assert the graceful degrade; repointed the live fixtures off parse_syllabus onto the agent; added a notes-encryption test. Full suite green (2 pre-existing storage-env failures unrelated). ruff clean. Spec: specs/144-calendar-agent.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uiz-gen fallback (#145) Removes the last raw call_gemini* seams from the quiz surface: - New agents/quiz_context.py (QuizContext: weak_areas, common_mistakes, questions_seen_summary, recommended_difficulty, notes — mirrors quiz_context_update.txt). routes/quiz.py's post-submit background task runs it via run_agent_sync and saves .model_dump() (unchanged context_json shape). - New agents/course_summary.py (CourseSummary.summary). course_context_service's _generate_summary_with_gemini runs it via run_agent_sync and keeps the deterministic template fallback on agent failure (no second LLM call). - Removed _legacy_generate_quiz + the MODEL_LITE/MODEL_SMART/call_gemini_json import. On agent guardrail-trip or failure, generate_quiz now returns 502 instead of a raw-Gemini fallback; the pre-agent 404 (unknown node) is unchanged. _providers registers course_summary (flash) + quiz_context (lite). Coordination: does NOT touch scoring / apply_graph_update / quiz_attempts writes (#128/#129 territory) — only the LLM seams. Tests: rewrote the legacy-fallback quiz tests to degrade-to-502; repointed the submit context-update patches onto quiz_context_agent; removed the obsolete legacy prompt-augmentation + legacy-model tests; added quiz-context save, course-summary success/fallback tests. Full suite 826 passed (2 pre-existing storage-env failures). ruff clean. Spec: specs/145-quiz-course-context-agents.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…_context in submit mocks Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-files + drop anon policies (#304) Closes the last anon storage surface from #231. The rest already shipped: application_resumes is private (backend/service-key via careers.py), issue-report screenshots upload through the auth-gated POST /api/issue-reports/screenshot (service role, size+mime validated; feedback.py), and ReportIssueFlow.tsx no longer uses the anon storage client. Migration 0029 (verified against prod, read-only, before writing): - makes issues-media-files private (application_resumes already private → no-op), - caps it at 5 MB + a mime allowlist matching the upload endpoint, - drops the two anon storage.objects policies ("Allow uploads" INSERT / "Allow public read" SELECT) the app no longer relies on. Safe: uploads use the service role (bypasses storage RLS) and review is via the dashboard / signed URLs, so nothing reads issues-media-files via a public URL. Idempotent across environments (WHERE no-ops on absent buckets; DROP ... IF EXISTS). NOT yet applied to prod — apply via `python -m db.migrate` (see the migration's privilege note re: the storage schema). Also updates docs/security/storage-hardening-plan.md to reflect the shipped state (résumé-PII exposure already closed; only this lockdown remained). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses CodeRabbit review on #286: - Toggle: flexWrap so SemesterChips' dynamic list wraps instead of overflowing horizontally (no effect on fixed-option callers). - Pill: type="button" (stops enclosing-form submit) and aria-pressed to expose active state to assistive tech. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
refactor(frontend): unify CSS token layer + add (public) route group (Phase 1)
The direct-run harness (python3 tests/test_ocr_pipeline.py, documented in the module docstring) had lost its sys.exit(1) and traceback on failure, so a failed run exited 0 and silently reported success. Restore both. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Deploying with |
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs | frontend-staging | f472300 | Jul 02 2026, 06:14 AM |
feat(calendar): syllabus extraction via agent, retire raw-Gemini fallback (#144)
The all-questions-drift branch's comment still described routing to the legacy fallback, which #145 deleted. The RuntimeError is now caught by generate_quiz's bare-except and returned as HTTP 502 (per test_degrades_when_all_questions_drift). Comment-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(quiz): quiz-context + course-summary → agents, retire quiz-gen fallback (#145)
Promote
main(staging) →production. Routine promotion since the last one (PR #241, 2026-06-27). The DB modular redesign already shipped in #241; this batch is 64 real commits (the other 188 are#147no-op checkpoints).What ships
Frontend — design-system / token unification (#286, #294)
Button/Toggle/Chip/Badgeprimitives +FilterPills; migrated high-impact buttons, selectors, and filters across Learn / Gradebook / Calendar / Social / Library / Study / Tree.(public)route group +.public-surfacemarketing layer, pre-auth token de-shadowing, a11y fixes (aria-pressed, neutral Badge text).Backend — one-shot LLM → Pydantic AI agents (#147, #296)
study_guide_agent,social_summary_agent,health_probe_agenton the shared provider +run_agent_syncbridge./api/gemini-test, study-guide generation, and social group summaries routed through agents (502 on failure); failure-contract tests added.Calendar — enrollment rewire (#283)
enrollment_id+ source tag; syllabus saves tagged.Security — storage lockdown (#231, #304)
issues-media-filesprivate, caps size/mime, drops the last anon storage policies. Requires migration0029on the prod DB (see below).Fixes
same-origin-allow-popups), graph unexplored-node labels, local-mode mock data for gradebook detail + chatroom.Prod-side steps (do around merge)
0029to prod —dotenv -f .env.production run -- python -m db.migrate(idempotent; storage hardening only, header notes it was verified read-only against prod).production) + Cloudflare Workers Builds (frontendworker) prod deploys.Verified before opening
main→productionmerges clean (no conflicts).main; no new backend env vars vs. last promotion.0029.🤖 Generated with Claude Code