feat: keep banner's link identifier and publish paired sections - #535
Merged
Conversation
The page renders docs/public-catalog-api.md with redcarpet, so the site and the repository cannot say different things. It carries its own layout and style, which keeps it free of an asset build, and it draws the mermaid diagrams in the source. Claude-Session: https://claude.ai/code/session_01843pqxWRkyjz4ai2wZYebw
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Banner tells us which sections a student must register together. We were throwing that away and had no way to pair a lecture with its lab.
What Banner sends
Every search result carries
linkIdentifierandisSectionLinked. The identifier reads as<slot><key>. The first character is the slot, the rest is the key that pairs the sections.A lecture
A1goes with every labB1of the same course. In Fall 2026 Banner marks 684 of 1302 sections as linked.Changes
link_identifierandis_section_linkedtocourses, plus an index on(term_id, subject, course_number, link_identifier).Course#link_slot,Course#link_key, andCourse#linked_sectionsread the pairing.linked_sectionsreturns the active sections of the same course that share the key and sit in a different slot.CatalogImportServicestores both fields. It writes them on update as well as on create, so a re-import teaches existing rows their identifier.linkedobject on every section:required,identifier, andcrns. REST and GraphQL both carry it, anddocs/public-catalog-api.mdexplains it.lib/tasks/backfill.rakeholds two one-time repairs. Both are safe to run again, and both take an optional term UID.backfill:seatsfillsseats_capacityandseats_availablefor rows that have none. It uses thegetEnrollmentInfofix from fix: send term and crn to banner getenrollmentinfo #534.backfill:link_identifiersreads the Banner catalog and writes only the two link columns. It does not touch meeting times or faculty.Without a term UID both tasks work on the terms that hold courses and are not over.
Testing
linkedfield on REST and GraphQL.backfill:link_identifiers[202710]run against a copy of the catalog: 672 rows updated, 583 already correct, 47 CRNs not in the database.backfill:seats[202710]run against the same copy.Public ids
pub_idis the key we already use across our own systems, so the API now publishes it and filters on it.linked.pub_idssits next tolinked.crnsand holds the same partner sections, in the same order.GET /api/v1/catalog/sections?pub_id=crs_kw7coe30and the GraphQLpubIdsfilter both select sections by public id. A public id is unique across every term, so the filter needs no term. A CRN is only unique inside one term.Course.public_id_forandCourse.id_from_public_iddo the work. The public id is derived from the numeric id, not a column, so the filter decodes rather than matches.Seat counts that Banner reports as negative
Banner reports a negative seat count when a section holds more students than its cap, for example -8 of 15. The
coursestable forbids a negative count, so 222 rows failed the seat backfill andCourseDataSyncJobfailed the same way every night under a log-only rescue.LeopardWebServicenow floors the count at zero. A student only needs to read that no seat is left.API reference on the site
GET /docs/apirendersdocs/public-catalog-api.md, so the site and the repository cannot say different things. The page carries its own layout and style, so it needs no asset build, and it draws the mermaid diagrams in the source./docssends a client to it.