Repository navigation
Release 0.85.0 - #4164
Release 0.85.0#4164odlbot wants to merge 27 commits into
Conversation
* Hide edX content files until their release date ContentFile gains a release_date taken from the OLX start dates on the path from the course down to each block, with static assets dated by the earliest dated block that names them and undated if any undated learner-visible file does. Visibility is derived, published AND released, via ContentFile.objects.visible(); readers go through it and a source scan keeps new readers from filtering on published alone. An hourly sweep reindexes runs whose files released since the last sweep, tracked by a durable watermark with an overlap for retries. A partial index on published rows serves the sweep and the API's counts. Ingestion reconciles dates on every archive it downloads; the unpublish_excluded_files backfill dates rows loaded before release dates existed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Undo the escaping layer serialized OLX adds to CDATA Reference sources are now serialized after dropping their dated inline blocks, and serializing escapes CDATA content one more time than the file did. A CDATA link to notes&guide.pdf came out as notes&amp;guide.pdf and no longer matched notes&guide.pdf. Unescape the serialization once so reference text reads as it did when taken straight from the file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Trim release-date code and tests - One _refers_to() for the "names it or declares its video" check that the exclusion scan and asset dating both made - _static_references takes one confirmed flag instead of inline and guess, which were always passed together - Inline _self_paced, shorten key_dates, drop the "Z" replace that fromisoformat handles since 3.11 - Revert the loaders.py reordering and list the stale-file query as a deliberate published reader instead - Shorten docstrings and comments - Tests: fold release_date checks into the existing load, cleanup and deindex tests; merge near-duplicate unpublish, visible/hidden and unparsable-XML dating tests; drop a test of private _build_result Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tighten release-date docstrings and comments Fix ones that were wrong (the 0132 drop comment, a key that maps to None, the self-paced and reconcile docstrings, the source-scan comment), shorten the long test docstrings, and give the tutor import test's row the key of the file it imports, so the test fails if rows are reconciled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Deindex newly unreleased content files before loading reconcile_release_dates runs before extraction, but the reindex only runs after a successful load, so a failed load left newly hidden files in OpenSearch and Qdrant. Dispatch the deindex tasks right away when reconciling hides any visible row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep static assets visible when a reachable static page links them * Match playlist videos on visible content files Main's warehouse playlist sync read published=True directly, which the content-file reader guard rejects. Use visible(), as load_videos_from_content_files does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Require a complete filename match for static asset references * Keep no inline block elements on OlxArchive * Keep the release sweep watermark in a cache table of its own * Match block files on their exact name * Skip transcripts when dating static assets The per-date scan searched every video transcript for asset names, which the undated scan never reads. On MITxT 6.419x (1,236 .srt files) that took key_dates from 1.5s to 31s and added 130 MB; now 4.4s with identical output. * Exempt the unit loader's published query from the visibility guard * Check unreleased files are deindexed with unpublished ones --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* Match asset names with separators collapsed, not deleted Reference matching deleted underscores and punctuation, so a link to lecture1.pdf also counted as a link to lecture_1.pdf. That kept the wrong file ingested, and when only a future-dated block linked lecture_1.pdf, an undated link to lecture1.pdf released it early. Collapse each run of separators to one underscore instead: edX writes a space, +, @ or other punctuation as _, so those spellings still match, but a dropped separator no longer does. Name starts are unchanged: after any separator run except bare underscores. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Let a name start at the start of a reference source A source that begins with "_notes.pdf" kept its leading _ in the index without a name start after it, so it no longer matched the file, which it did before separators were collapsed. Mark both ends of each text as a separator. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Say what the asset name matcher does in its docstrings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* adding fixes for ocr issues and updated test. added new settings for ocr timeout * Keep list markers out of math scoring and on children-only items List item markers are now stored on ContentBlock.list_marker instead of in the content, so a "- " bullet is no longer scored as a math symbol. The marker goes on the item's first text, which is in its kids when the item has no content of its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Don't stack retries on the OCR fallback request A request that batch_completion reports as failed has already used num_retries, so the one-off fallback call now makes a single attempt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fall back to parsed text when full-page OCR fails - A failed full-page OCR request now uses that page's parsed blocks instead of a placeholder, so an LLM outage doesn't empty the file. Failed image regions still get the placeholder. - Drop the extra one-at-a-time retry; batch_completion's num_retries already covers retrying. - Don't count common Symbol/Wingdings private-use bullets (e.g. U+F0B7) as unmappable glyphs. - Add the missing spaces between sentences in OCR_PROMPT. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The search and seat-assignment announcement debounces started a real timer on mount even when nothing had changed. If it fired during a plain await in a test, React logged an act() warning and jest-fail-on-console failed the test. Skip the debounce when the value is already current, and read exported CSV blobs inside act(). Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…4137) * Add warehouse-pull sync tasks for MITx Online courses and programs MIT Learn loads MITx Online from its catalog API every 6 hours. The data platform's integrations__learn__mitxonline_* views now carry what that ETL reads and derives (published and variant runs, prices, status, course numbers, program children with their positions), at parity with Learn. SyncMITxOnlineCoursesTask and SyncMITxOnlineProgramsTask read those views and hand the loaders the same dicts learning_resources.etl.mitxonline builds, following the xPRO tasks from #4054. They no-op until ETLSourceOwnership names the warehouse for mitxonline course and program. The array and nullable timestamp readers move from warehouse_xpro into warehouse_guards now that two sources use them. Claude-Session: https://claude.ai/code/session_01FMtn1X7p2G1xBL6BukdYAn * Build MITx Online full_description from the platform's page sections #4089 builds full_description from the Wagtail pages API's about, what_you_learn, prerequisites and FAQs. ol-data-platform #3050 added those sections to integrations__learn__mitxonline_courses and _programs, with has_catalog_page for whether the pages API lists the page to Learn. The sync tasks run parse_full_description on them, and leave the key out when has_catalog_page is false, as the API ETL does for a page it does not see, so the stored value stays. Claude-Session: https://claude.ai/code/session_01FMtn1X7p2G1xBL6BukdYAn * Read StarRocks booleans as bools in the MITx Online sync StarRocks returns a boolean column as 0 or 1. Passed through, published and certification were stored on the LearningResource as ints, and the loaders' `is False` checks then skip clearing run prices for a resource without a certificate and skip test_mode for an unpublished force-ingest course. The tests also assert the loader configs now. Claude-Session: https://claude.ai/code/session_01FMtn1X7p2G1xBL6BukdYAn * Count MITx Online courses without runs against the unpublish limit The loader unpublishes a course that arrives with no runs, but the course guard kept every course the courses view marks published. The runs come from a separate view, so a runs table built apart from the courses table (e.g. a dbt build that replaced runs and then skipped courses) could unpublish courses without tripping the 10% limit. Only published courses with runs now count as kept. Claude-Session: https://claude.ai/code/session_01FMtn1X7p2G1xBL6BukdYAn * Share the course unpublish-guard rule between MITx Online and xPRO The MITx Online course guard counts a course as kept only when it is published and has runs, since upsert_course_or_program unpublishes a course with no runs. xPRO built its kept set from the published flag alone. This moves the rule into kept_course_ids in warehouse_guards and uses it from both syncs. xPRO's behavior does not change: its transform_course already marks a course published only when it has a priced run, so a course without runs was already counted. The new xPRO test covers that case so the guard keeps holding if the transform's published rule changes. Claude-Session: https://claude.ai/code/session_01FMtn1X7p2G1xBL6BukdYAn
* Check ETL ownership in the remaining legacy entrypoints transcript jobs, Canvas ingestion, the OVS video webhook and the news feeds still write after their source is flipped away from legacy. This adds the ownership check at the top of each, before any call to the source: - Content files and transcripts get keys of their own, content_file and transcript, because they cut over separately from their source's metadata. The podcast transcript job is meant to keep running after podcasts move to the warehouse, and the edX content-file pull is a later cohort than the course pull. - ingest_canvas_course needs canvas course and content_file, since one archive writes both. - The OVS video webhook is the data platform's push, so it writes only while webhook owns ovs video_playlist and video, and returns 409 otherwise. - The content_files delete webhook deletes the course, so it checks the source's course. - The news feeds are keyed by feed and feed type, e.g. mitpe_news/news. when_owned moves to ownership.py so news_events can use it. Claude-Session: https://claude.ai/code/session_01FMtn1X7p2G1xBL6BukdYAn * Write OVS pushes inside writing_as and gate sync_canvas_courses on content files The OVS view checked ownership as the webhook pipeline but wrote after the block, as legacy, so a may_write backstop added to load_video later would skip every push. sync_canvas_courses only queues ingest_canvas_course, which needs canvas course and content_file, so with content_file moved it listed the bucket and queued tasks that all skip. Claude-Session: https://claude.ai/code/session_01FMtn1X7p2G1xBL6BukdYAn * Check content file ownership in load_content_files The ownership module says the batch loaders check may_write as a backstop, but load_content_files had no check, so a caller that skipped the entry check (a shell session, a new pipeline) could still write and unpublish a source's content files after they were cut over. Claude-Session: https://claude.ai/code/session_01FMtn1X7p2G1xBL6BukdYAn * Limit the content-file cutover note to the edX archive sources OCW content files stop at the ocw/course check and Canvas needs both keys, so only the edX archive sources keep their content files on the legacy tasks after a course flip. Claude-Session: https://claude.ai/code/session_01RMmtj45php9G7NJK2nztzp
Claude-Session: https://claude.ai/code/session_01HdviiEJfb4ZNQJKfT2tWj3 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Bump smoot-design to 6.39.0 for the contact-us export * Add contact-us launcher config and support endpoint env var
Claude-Session: https://claude.ai/code/session_019gXXnoXso9aKkBtVYKsMfG Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…nding chips unchanged (#4136) * Pin the homepage trending chips' hover text to the colour they render On smoot 6.38.0 the hover text on the homepage's trending chips is smoot's outlined/outlinedWhite hover colour, Dark Gray 1: smoot's `.MuiChip-clickable:hover` rule (specificity 0,3,0) outranks TrendingChip's `&:hover` (0,2,0), which is also why its background and border overrides need `!important`. The Dark Gray 2 that TrendingChip declared for outlinedWhite never applied, and Explore All (outlined) declared none. smoot's chips are moving to Dark Gray 2 to match the design system's Chips component, but the homepage's trending pills are a separate design. Setting Dark Gray 1 here with `!important` keeps them as they are on either smoot. Measured on local dev against both smoot 6.38.0 and a build with the chip change: every computed colour, border, background, padding and font on all six chips, at rest and on hover, is identical to today. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bump smoot-design to 6.39.1 for the outlined chip fix 6.39.1 is 6.39.0 plus mitodl/smoot-design#279 and nothing else: outlined and outlinedWhite chips draw Dark Gray 2 text, and the close icon sits 4px from the label. ol-components declares smoot as an exact-version peer, so it moves with main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(ai): route azure/ models to Azure OpenAI with workload identity The chat and embedding calls only reach OpenAI with OPENAI_API_KEY. The Azure OpenAI accounts for mit-learn have key auth disabled, and the pods already carry the workload identity env vars for an Entra token (mitodl/ol-infrastructure#6082). This routes a model configured with an "azure/" prefix (the summarizer and credential LLM models, and QDRANT_DENSE_MODEL) to AZURE_OPENAI_ENDPOINT with a bearer token from DefaultAzureCredential. Models without the prefix take the existing path unchanged. The prefix is stripped wherever the base model name matters (tiktoken encoding, the hybrid search model check, the OpenSearch connector) so the Qdrant vector name and size don't change. Claude-Session: https://claude.ai/code/session_019VXBicfWCU41tZBiAzToby * fix(ai): tokenize azure/ chat models like their OpenAI model tiktoken doesn't know "azure/gpt-4o", so token_encoding fell back to LITELLM_TOKEN_ENCODING_NAME (cl100k_base in the deployed envs) instead of o200k_base, and summarizer input was truncated earlier than for the same model without the prefix. This also caps azure-identity below 2 to match the other pins. Claude-Session: https://claude.ai/code/session_019VXBicfWCU41tZBiAzToby
…s to settle (#4148) * fix(test): bump happy-dom to 20.14.6 so MutationObservers survive GC happy-dom 20.3.4 holds each MutationObserver's callback only through a WeakRef (MutationObserverListener), with no strong reference anywhere. A garbage collection frees it and Node.reportMutation silently drops the observer while it is still connected. ProseMirror observes the editor DOM this way, so text typed after a GC lands in the DOM but never reaches editor state. That is the "PATCH never sent" failure of `ArticleEditor autosave › an article that has never been saved is created once, then updated`: no edit, no autosave, `Number of calls: 1`. It only shows under memory pressure (CI runs with coverage and parallel workers), which is why it appears on unrelated PRs. Forcing one gc() after the first save fails the test every time on 20.3.4 and passes on 20.14.6. Fixed upstream in capricorn86/happy-dom#2272, released in 20.11.2. The `^20.1.0` range already admits it, so the lockfile alone kept 20.3.4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(test): wait for autosaves to settle, not just to be sent The `act(...)` failure of `ArticleEditor autosave › an article that has never been saved is created once, then updated` comes from a save landing just after a `waitFor` returns. The tests waited for the request to be recorded; the response settles a moment later, re-rendering the autosave indicator and Publish. React Testing Library turns the act environment back on as a `waitFor` returns, so the toolbar's MutationObserver, reacting to that re-render, sets state outside `act` and jest-fail-on-console fails the test. A second `waitFor` for "Saved" does not help: the gap sits between the two waits (5 of 64 CI-like runs still failed). `waitForSaveToSettle` checks the request, the "Saved" indicator and an enabled Publish in a single `waitFor`, so the save has nothing left to land when it returns. With it, 64 of 64 CI-like runs passed. It replaces the request-sent waits in the three autosave tests that ended on one, and the "Saving..." check that could pass before "Saving..." had rendered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Prevents any future relock from silently downgrading certifi to a version that trusts the compromised eMudhra CAs (e.g. while the 7-day uv cooldown applies). Claude-Session: https://claude.ai/code/session_019gXXnoXso9aKkBtVYKsMfG Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Update dependency @sentry/nextjs to v10.75.2 [SECURITY] * yarn.lock * update sentry/opentelemetry * Revert withSentryConfig import to @sentry/nextjs The @sentry/nextjs/config entrypoint loads @sentry/node, which needs TextDecoder and breaks nextConfig.test.ts under jsdom. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Anastasia Beglova <abeglova@mit.edu> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…n empty state, and a white topic hero (#4133) * Count what each filter control has narrowed by A facet's menu closes over what it selected, so a control reads exactly the same whether or not it is filtering anything: the only record was the chip row above the results, which names the values but sits a long way from the control that set them. The design answers that with a count beside the name -- a 20px red disc with the number in white, between the label and the chevron. Hidden where a facet has narrowed nothing, rather than shown as a nought, a badge reading 0 being a filter announcing that it is not filtering. The menus themselves are untouched: the same rows, checkboxes and counts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Stand the tabs and the applied filters outside the search card The card carries the search box and its facet controls and nothing else. The resource type tabs are drawn below it on the page rather than in it, as the pills the shared tab list draws everywhere else -- white for the one selected, grey for the rest -- with sorting at the far end of the same row, and the applied filters follow them as white pills on the page's own grey. The card itself is plain white behind a red left edge rather than a gradient under a thick pale rule, and its search box is the design's 486px. The banner, the card, the tabs and the filters stand 24px apart, with the results 32px below the last of them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Say what the 8px above the results grid is for The comment described the column's gap as the whole of the space between the filters and the grid, which it is not: the panel adds 8px to it so the results stand 32px off rather than the 24px the rows above them are spaced by. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Gather the search, tabs and filters into one card again The design stacks all three 16px apart behind a single white edge, so the tabs and the applied filters are drawn in the card rather than on the page below it, and the card loses the red edge down its left side. The tabs are underlined headings: the selected one black over a 2px `darkGray2` rule drawn within the row's 42px, the rest `silverGray`, 10px apart. The applied filters lose their outline and their fill -- inside a white card there is nothing for either to separate them from -- and "Clear all filters" is a plain underlined link in `darkGray2` rather than red. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Outline the filter under the pointer, as the design hovers it Hovering a filter draws the outlined pill around it rather than underlining its label. Drawn as an inset shadow: a border would lay the row out 2px wider for as long as the pointer was over it and shunt every filter after it sideways, and the design's stroke sits inside the pill's 32px in any case. The labels and "Clear all filters" are `silverGrayDark`, which is what the design renders them at -- the Chips and Link components declare `darkGray2`, but every instance on the frame overrides it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Redden "Clear all filters" under the pointer Hovering it turns it `red` and leaves the underline standing, rather than dropping the underline and keeping it grey. That is the red the filter counts are drawn in, and the only other thing on the card that is not grey. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Say what came back empty, and offer a way out of it A search its filters emptied showed a bare line of text above nothing. It now draws the design's card: a book glyph in a grey disc, what the search found none of, and a button to drop the filters. The heading names the active tab's results -- "no learning materials match these filters" -- because the other tab may well have some, which "no results" does not distinguish. The button appears only when there is something to clear, read from the same list the chip row draws from so the two cannot disagree. The other layouts keep the line of text: they have a facet sidebar beside them that already offers a way out. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Stand the topic hero on plain white The design no longer runs a photograph across the top of it, so the topic page passes nothing behind the words and the section's own white is the ground. Its spacings tighten with it: 24px under the trail where there was 32, and 40px above the Featured row where there was 64. Both are the topic page's alone. The department design has not been revised to match and is to keep its banner image, so the spacings are a prop rather than the one answer, and the photograph and its wash stay whole -- exported, so they go on compiling until a department passes them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Answer the pointer on the facet dropdowns The facet controls had nothing to show for being hovered, where the tabs beside them darken. They now give the same answer an unselected tab gives: the label to `darkGray2`, with nothing drawn behind it and no change of size. The chevron is named alongside the label because it does not inherit -- Select colours its own icon, so on the label alone the words darkened and the arrow beside them sat unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * new changes * Redraw the filter row and the tabs as the design now has them The applied filters move under a rule inside the search card, led by a "Filtered by" label and drawn as small grey tablets -- 24px, 4px radius, 12px Medium -- in place of the 32px pills, with "Clear all" in red ending the row. The card's foot tightens to 16px to suit the shorter row. The tabs move back out onto the page below the card, on a hairline that runs the row's full width for the selected tab's heavier rule to sit on, and their counts lose the brackets. Sort loses its chrome and is a label and a chevron: the hairline it had is the shared select's own, drawn on the input base rather than on a notched outline, and the icon is sized and inset from a selector of equal weight that lands later -- so both are named from here and the icon's doubled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Redden the cross rather than the tablet on hover The hover variant keeps the tablet's grey and its label and reddens the cross alone, which is the half of it that does anything. The resting cross is `silverGrayDark` rather than the label's near-black, so it is the quieter half until it is pointed at. Replaces a hover invented when the design had no hover state to read. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix the mobile view * Clear out what the redesign left untrue Comments that described the arrangement before the tabs and the applied filters moved: the bar is no longer drawn into a card the results header sits in, the card no longer shares anything with the tabs, and the select's border is no longer holding a box against a gradient the card has not had for two revisions. `Card` in the filter bar is renamed `Row`, which is all it is -- the name was the only reason that paragraph had to explain itself. In the tests, the doc comment on the applied filters had the counts block inserted beneath it and was left heading the wrong tests; it moves down to the block it describes, and now says the row sits under the search box rather than above the results. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Say the facet's count in its name, not only on the disc `aria-label` on a combobox replaces everything drawn inside it, so the disc was never read as part of the control's name -- and naming the disc instead does nothing either, since it is a span with no role, which `aria-label` cannot name. A screen reader heard "Format" whether it was narrowing two things or none. The name now carries the count and the disc is hidden, so the two cannot say different things. The count tests were asserting the drawn text and so had nothing to say about this; one of them now asserts the name. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Ahtesham Quraish <ahtesham.quraish@arbisoft.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
OpenAPI ChangesNo changes detected Unexpected changes? Ensure your branch is up-to-date with |
There was a problem hiding this comment.
Summary
The release adds visibility-aware content lifecycle management, richer course-unit extraction, warehouse synchronization, and Azure OpenAI support across learning resources. It also delivers a redesigned topic search experience, feature-gated Contact Us support, and improved OCR, profiling, and ETL safeguards.
Key Changes
- Content release dates now govern API exposure, indexing, embeddings, vector removal, and scheduled reindexing.
- ETL pipelines build ordered course units, reconcile ownership, and synchronize MITx Online courses and programs safely.
- Azure-prefixed language and embedding models use Azure OpenAI workload identity and provider-specific connection settings.
- Unit resource profiles generate cached, validated, evidence-backed claims from truncated course sources.
- Topic channels receive a plain-white hero and redesigned search filters, tabs, sorting, and empty states.
- Contact Us support becomes available site-wide behind feature flags and configured support endpoints.
All Relevant File Changes (click to expand)
- README.md: Documents the Learn AI support-agent endpoint.
- RELEASE.rst: Adds Version 0.85.0 release notes covering channel, ETL, security, and content changes.
- docker-compose.opensearch.base.yml: Updates the OpenSearch Docker image to 3.3.2.
- docs/how-to/etl-source-cutover.md: Documents ownership cutovers for content, transcripts, OVS, Canvas, news, and warehouse tasks.
- env/frontend.env: Adds the production Learn AI support-agent endpoint.
- env/frontend.local.example.env: Adds the commented local Learn AI support-agent endpoint.
- frontends/main/package.json: Bumps smoot-design, Sentry packages, and happy-dom.
- frontends/main/src/app-pages/ChannelPage/ChannelPage.test.tsx: Updates topic hero tests for the plain-white redesign.
- frontends/main/src/app-pages/ChannelPage/ChannelRedesignTemplate.tsx: Removes topic photography and adds redesigned spacing, typography, and banner exports.
- frontends/main/src/app-pages/ChannelPage/ChannelSearch.test.tsx: Tests facet counts, tab labels, and topic empty states.
- frontends/main/src/app-pages/ChannelPage/ChannelSearch.tsx: Removes obsolete filter-bar placement commentary.
- frontends/main/src/app-pages/ChannelPage/TopicFeaturedCarousel.tsx: Adjusts topic carousel spacing.
- frontends/main/src/app-pages/ChannelPage/TopicSearchFilterBar.tsx: Adds selected-count badges, accessible facet names, and revised filter layout.
- frontends/main/src/app-pages/ContractAdminPage/AssignSeatsSection.tsx: Prevents redundant live-region debounce timers.
- frontends/main/src/app-pages/ContractAdminPage/ContractAdminPage.test.tsx: Wraps CSV Blob reads in act.
- frontends/main/src/app-pages/ContractAdminPage/ContractAdminPage.tsx: Prevents redundant search debounce timers.
- frontends/main/src/app-pages/DashboardPage/DataConsentDialog.tsx: Removes the catch-all data-sharing clause from consent text.
- frontends/main/src/app-pages/HomePage/HomePage.test.tsx: Tests excluding Sloan and Professional Education from featured requests.
- frontends/main/src/app-pages/HomePage/carousels.ts: Excludes Sloan and Professional Education from homepage featured offerors.
- frontends/main/src/app-pages/HonorCodePage/HonorCodePage.tsx: Adds Misrepresentation to Honor Code standards.
- frontends/main/src/app/(site)/layout.tsx: Mounts the feature-gated Contact Us launcher.
- frontends/main/src/app/(site)/page.tsx: Reuses homepage featured-resource parameters during server prefetching.
- frontends/main/src/common/feature_flags.ts: Adds the ContactUs feature flag.
- frontends/main/src/page-components/ContactUsLauncher/ContactUsLauncherGate.test.tsx: Tests Contact Us flags, endpoint, authentication, and settings behavior.
- frontends/main/src/page-components/ContactUsLauncher/ContactUsLauncherGate.tsx: Renders Contact Us when flags and endpoint configuration permit it.
- frontends/main/src/page-components/ContactUsLauncher/contactUsConfig.test.ts: Tests support endpoint settings and optional user email.
- frontends/main/src/page-components/ContactUsLauncher/contactUsConfig.ts: Builds Contact Us chat settings from endpoint and authenticated email.
- frontends/main/src/page-components/HeroSearch/HeroSearch.tsx: Adjusts trending-chip hover colors.
- frontends/main/src/page-components/ResourceCarousel/ResourceCarousel.tsx: Removes mobile carousel top margin.
- frontends/main/src/page-components/SearchDisplay/NoResults.tsx: Adds contextual empty-results card with filter clearing.
- frontends/main/src/page-components/SearchDisplay/ResourceTypeGroupTabs.tsx: Supports unbracketed counts and updated topic tab wording.
- frontends/main/src/page-components/SearchDisplay/SearchDisplay.tsx: Redesigns topic search cards, tabs, sorting, filters, spacing, and empty states.
- frontends/main/src/page-components/SearchDisplay/SelectedFilters.tsx: Redesigns applied-filter rows, chips, labels, and clear-all control.
- frontends/main/src/page-components/SearchDisplay/UniversalAIBanner.tsx: Adjusts mobile banner-link padding.
- frontends/main/src/page-components/SearchDisplay/tabConfigs.ts: Adds empty-state nouns and renames the topic tab.
- frontends/main/src/page-components/TiptapEditor/contentTypes/article/ArticleEditor.happydom.test.tsx: Waits for autosave status and Publish enablement to settle.
- frontends/main/validateEnv.js: Validates the Learn AI support-agent endpoint.
- frontends/ol-components/package.json: Updates the smoot-design peer dependency.
- learning_resources/admin.py: Improves ContentFile administration, filtering, searching, and deferred loading.
- learning_resources/content_summarizer.py: Routes Azure models through Azure OpenAI workload identity.
- learning_resources/content_summarizer_test.py: Tests Azure model routing and unchanged OpenAI validation.
- learning_resources/converters/opendataloader_llm_converter.py: Improves PDF OCR fallback, caching, list flattening, glyph detection, and cleanup.
- learning_resources/converters/opendataloader_llm_converter_test.py: Tests OCR failures, lists, glyph detection, caching, and image optimization.
- learning_resources/credentials.py: Routes Azure credential-metadata models through Azure OpenAI.
- learning_resources/credentials_test.py: Tests Azure and OpenAI credential-metadata model routing.
- learning_resources/etl/edx_shared.py: Adds course-unit loading, archive reuse, overwrite support, and release-date reconciliation.
- learning_resources/etl/edx_shared_test.py: Expands archive ingestion tests for units, dates, failures, and overwrites.
- learning_resources/etl/loaders.py: Persists course units and safeguards content ownership while matching visible videos.
- learning_resources/etl/loaders_test.py: Tests content ownership, visibility, release dates, and unit loading.
- learning_resources/etl/olx.py: Builds OLX units, propagates dates, links assets, and tightens filename matching.
- learning_resources/etl/olx_test.py: Tests OLX dates, units, assets, and missing-file handling.
- learning_resources/etl/ownership.py: Adds content-file and transcript ownership keys with a shared ownership wrapper.
- learning_resources/etl/pipelines.py: Applies shared ownership checks and separately gates OCW content ingestion.
- learning_resources/etl/pipelines_test.py: Tests independently owned OCW content-file ingestion.
- learning_resources/etl/utils.py: Adds archive context management, date reconciliation, unit helpers, and reuse.
- learning_resources/etl/utils_test.py: Tests archive helpers, dates, extraction failures, and content reconciliation.
- learning_resources/etl/warehouse_guards.py: Adds nullable timestamps, warehouse arrays, and kept-course calculations.
- learning_resources/etl/warehouse_media.py: Matches playlists against visible content files.
- learning_resources/etl/warehouse_mitxonline.py: Adds MITx Online warehouse transforms and full-sync loaders.
- learning_resources/etl/warehouse_mitxonline_test.py: Tests MITx Online transformations, ownership, loading, and safety guards.
- learning_resources/etl/warehouse_xpro.py: Reuses warehouse parsing helpers and counts runless courses as unpublished.
- learning_resources/etl/warehouse_xpro_test.py: Tests mass-unpublish protection for courses missing warehouse runs.
- learning_resources/factories.py: Adds Unit and UnitContentFile factories.
- learning_resources/management/commands/backpopulate_mit_edx_files.py: Adds the --overwrite-units option.
- learning_resources/management/commands/backpopulate_mitxonline_files.py: Adds the --overwrite-units option.
- learning_resources/management/commands/backpopulate_oll_files.py: Adds the --overwrite-units option.
- learning_resources/management/commands/backpopulate_xpro_files.py: Adds the --overwrite-units option.
- learning_resources/management/commands/unpublish_excluded_files.py: Reports and dates unreleased files while unpublishing exclusions.
- learning_resources/migrations/0131_unit_unitcontentfile.py: Creates Unit and UnitContentFile models and constraints.
- learning_resources/migrations/0132_contentfile_release_date.py: Adds ContentFile release_date.
- learning_resources/migrations/0133_contentfile_release_date_unreleased_idx.py: Adds a concurrent partial release-date index.
- learning_resources/migrations/0134_resource_profile_configuration_claim_extraction.py: Creates profile models and seeds the unit prompt.
- learning_resources/migrations_test.py: Removes legacy ContentFile deduplication migration tests.
- learning_resources/models.py: Adds content visibility, release dates, units, memberships, profiles, and claim extractions.
- learning_resources/models_test.py: Tests content visibility and reader filtering.
- learning_resources/profiles/init.py: Adds the profiles package description.
- learning_resources/profiles/admin.py: Registers profile configuration and claim extraction administration.
- learning_resources/profiles/prompts.py: Adds the combined unit-claims prompt builder.
- learning_resources/profiles/schemas.py: Defines strict evidence-backed unit extraction schemas.
- learning_resources/profiles/sources.py: Renders ordered unit sources and truncates oversized content.
- learning_resources/profiles/sources_test.py: Tests source truncation and unit source rendering.
- learning_resources/profiles/unit_claims.py: Adds cached, validated, evidence-verified unit claim generation.
- learning_resources/profiles/unit_claims_test.py: Tests claim generation, caching, validation, truncation, and failures.
- learning_resources/profiles/verification.py: Verifies model evidence passages against source text.
- learning_resources/profiles/verification_test.py: Tests exact, fuzzy, unknown, and nested evidence verification.
- learning_resources/tasks.py: Adds release sweeps, ownership gates, overwrite propagation, and MITx Online tasks.
- learning_resources/tasks_test.py: Tests release sweeps, ownership gates, catalog syncs, and overwrite propagation.
- learning_resources/utils.py: Strips Azure prefixes for tokenizer model lookup.
- learning_resources/utils_test.py: Tests Azure-prefixed tokenizer handling.
- learning_resources/views.py: Serves only visible content files through the API.
- learning_resources/views_test.py: Tests unpublished and unreleased content filtering.
- learning_resources_search/api.py: Accepts Azure-prefixed dense models for hybrid search.
- learning_resources_search/api_test.py: Tests hybrid search with Azure-prefixed embeddings.
- learning_resources_search/connection.py: Strips Azure prefixes for OpenSearch connectors.
- learning_resources_search/connection_test.py: Tests Azure-prefixed connector model normalization.
- learning_resources_search/indexing_api.py: Indexes visible files and deindexes hidden files.
- learning_resources_search/indexing_api_test.py: Tests hidden-file indexing and release-date preservation.
- learning_resources_search/plugins.py: Updates indexing comments to distinguish hidden and visible files.
- learning_resources_search/tasks.py: Deindexes hidden content files instead of only unpublished files.
- learning_resources_search/tasks_test.py: Tests deindexing unreleased content files.
- learning_resources_search/utils.py: Limits OpenSearch content-file selection to visible files.
- main/azure_openai.py: Adds Azure OpenAI Entra-token helpers and LiteLLM routing parameters.
- main/azure_openai_test.py: Tests Azure model detection, prefix stripping, and connection settings.
- main/settings.py: Bumps version and adds release sweep, Azure OpenAI, and profile timeout settings.
- main/settings_celery.py: Schedules release sweeps and daily MITx Online warehouse synchronization.
- main/settings_course_etl.py: Requires LaTeX OCR formatting and configures request timeouts and retries.
- main/settings_test.py: Verifies MITx Online warehouse synchronization schedule entries.
- news_events/etl/pipelines.py: Gates news and events pipelines through ETL ownership checks.
- news_events/etl/pipelines_test.py: Tests feed execution under legacy ownership configuration.
- pyproject.toml: Adds Azure Identity and Pydantic dependencies and constrains certifi.
- uv.lock: Locks Azure authentication, security-fixed certifi, and package upgrades.
- vector_search/encoders/litellm.py: Supports Azure-prefixed embeddings with provider parameters and preserved caching.
- vector_search/encoders/litellm_test.py: Tests Azure parameters, hedging, cache keys, and vector naming.
- vector_search/tasks.py: Embedding and removal tasks now process visible and hidden content files.
- vector_search/tasks_test.py: Verifies unreleased exclusion from embeddings and hidden-content removal.
- vector_search/utils.py: Selects visible content files for Qdrant indexing.
- vector_search/utils_test.py: Updates Qdrant selection tests for unreleased visibility.
- webhooks/views.py: Gates OVS writes and course deletion by ETL ownership.
- webhooks/views_test.py: Tests ownership-gated OVS operations and protected course deletion.
💬 Feedback & Commands
Share feedback on my comments with 👍 👎 — I'll stop raising issues you push back on. Think I missed something? Adjust my sensitivity →
5 things I can do →
#optibot review— I'll re-review your latest changes (incremental)#optibot full review— I'll re-review the entire PR from scratch#optibot fix— I'll apply my suggested fixes to your code#optibot compliance— I'll run a compliance check on your changes#optibot release notes— I'll write up release notes for your production release
💡 Tip: I can audit every dependency change before it reaches main — one compromised package can take down your entire system. Try Supply Chain Agent.
|
Optibot: trial review limit reached Your organization has used all 300 code reviews included in your Optibot trial, so this pull request was not reviewed. Upgrade to resume automatic reviews: https://agents.getoptimal.ai/dashboard/billing |
Ahtesham Quraish
renovate[bot]
Arslan Ashraf
Chris Chudzicki
Tobias Macey
Zaman Afzal
Carey P Gumaer
Anastasia Beglova
Matt Bertrand
Shankar Ambady
dependabot[bot]