Skip to content

Extract Pensive assignment platform integration logic from legacy repository - #572

Open
cycomachead wants to merge 1 commit into
mainfrom
cycomachead/239-extract-pensive-integration/1
Open

Extract Pensive assignment platform integration logic from legacy repository#572
cycomachead wants to merge 1 commit into
mainfrom
cycomachead/239-extract-pensive-integration/1

Conversation

@cycomachead

Copy link
Copy Markdown
Contributor

General Info

Changes

Extracts and implements Pensieve assignment platform integration, ported from the legacy berkeley-cdss/extensions repo, following the existing Gradescope facade pattern end to end. Adds a new LMS row/facade, DB fields, and course settings UI so extensions can be posted to Pensieve.

  • DB entry: Lms row id 3 ("Pensieve") — new PENSIEVE_LMS_ID constant, seed, Lms.PENSIEVE_LMS, and Lms.facade_class mapping. Migration adds enable_pensieve and pensieve_course_url to course_settings.
  • Facade: app/facades/pensieve_facade.rb with get_all_assignments, provision_extension, from_user, assignment_url, backed by lib/lmss/pensieve/ (JSON Client plus Assignment/Override value objects), configured via new PENSIEVE_API_TOKEN env var.
  • Extension posting: Request#approve now handles PensieveFacade (course URL + student email). Since Pensieve only accepts whole days past the original deadline, the facade converts the approved due date into num_days relative to the synced assignment's due date, and refuses to post if the assignment can't be found or the request grants zero days.
  • Course settings UI: new Pensieve card on Course Details (toggle + course URL, mirroring Gradescope). Since Pensieve keys everything by URL, the course URL is stored as external_course_id and assignment URLs as external_assignment_id.
  • Docs: new section in docs/integrations.md and .env.example entry for PENSIEVE_API_TOKEN.

Known gaps / open questions for Pensieve

The old system (src/pensieve.py) only supported a single API call (grant-extension) — there was no assignment sync; staff manually entered Pensieve URLs. To fully support sync, we need from Pensieve:

  1. An API token (PENSIEVE_API_TOKEN, Bearer auth) — the only credential currently used.
  2. An assignment-listing endpoint. None exists today or is documented. get_all_assignments is wired to a proposed, unconfirmed endpoint (GET /api/b2s/v1/external-client/assignments, flagged in lib/lmss/pensieve/client.rb). Until Pensieve confirms a real endpoint/shape, sync is a safe no-op (returns []; the sync job does not disable existing assignments on empty response).

Other semantic limitations to be aware of: extensions are granted in whole days (time-of-day is lost), there's no late/hard due date support (parameter ignored), and extensions can't be read back or revoked via the API (get_assignment_overrides returns []; external_extension_id is only populated if Pensieve happens to return one).

Testing

Added specs for PensieveFacade and Lmss::Pensieve::Client, plus coverage in lms, course_settings, and request specs (approval flow, link creation/update, URL validation). Full suite (749 specs) passes and RuboCop is clean.

Documentation

Added a "Pensieve" section to docs/integrations.md covering setup (API token + course URL) and known limitations (whole-day extensions, no separate late due date).

Checklist

  • Name of branch corresponds to story

Superconductor Ticket Implementation | App Preview | Guided Review

Extract and implement Pensieve assignment platform integration logic from the legacy extensions repository, enabling course syncing, extension requests, and API communication via the Pensieve external-client API.

https://www.superconductor.com/tickets/hDh9FH7DgNTw/implementations/RMTnmfHnNNTP#message_q6JBjRTHrcK8

Co-authored-by: Claude Code <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant