docs: ADR: Evolving the library_content block schema - #33231
Conversation
73f8eb5 to
fb316ee
Compare
Rather than implementing V2-library and static-library-reference support in a new block, we will be enhancing the existing `LibraryContentBlock` in-place. Relevant ADR PR: openedx#33231
There was a problem hiding this comment.
This is supposed to auto-map v1 library keys to v2 library keys as part of the migration, right? Will that involve actual content data changes or transparent mapping under the covers?
There was a problem hiding this comment.
Great question. @connorhaugh , do you know what the migration would do with the keys if we ran it today?
There was a problem hiding this comment.
@ormsbee T&L's plan is to update the content in place:
- mgmt command: https://github.com/openedx/edx-platform/blob/master/cms/djangoapps/contentstore/management/commands/replace_v1_lib_refs_with_v2_in_courses.py
- the task that it'll spin up for every course in the system: https://github.com/openedx/edx-platform/blob/master/cms/djangoapps/contentstore/tasks.py#L1034
There was a problem hiding this comment.
that is after they copy every v1 library to a v2 library: https://github.com/openedx/edx-platform/blob/master/cms/djangoapps/contentstore/management/commands/copy_libraries_from_v1_to_v2.py
There was a problem hiding this comment.
@connorhaugh , @ormsbee and I were talking about the destabilization risk that migrating this field in bulk might cause, especially in this event that a backwards migration is needed. Leaving the V1 keys and place and then mapping V1 keys to V2 libraries at runtime might be safer.
I think we can keep the ADR as it is, but if you're open to it, let's all meet after I'm back on Oct 3 and discuss the migration?
There was a problem hiding this comment.
Down to talk more about it, but key concerns which motivated the hard cutover choice:
- How do we handle a dynamic mapping of v1-> v2 keys? we'll have to keep that forever, as string matching won't work (libraries can change names).
- We can prove to ourselves that all keys have been mapped using validation commands.
- KISS
- We're perhaps unaware of certain unstable situations to consider.
There was a problem hiding this comment.
How do we handle a dynamic mapping of v1-> v2 keys? we'll have to keep that forever, as string matching won't work (libraries can change names).
For better or worse, Course/Library keys and UsageKeys never really change though. So if it's possible for us to craft the keys of the v2 library content to map 1:1 with the v1 content in way that makes conversion simple, I think that'll be good enough for what we want.
For any piece of library content that's being used in a course, the course is effectively using its copy of that content when serving things to the student in the LMS. That should be fine, even if the backing v1 library disappears entirely. So I think we can limit our migration to the point at which a user might check for library updates in Studio.
So say there's a CourseWaffleFlag that gates whether a course is forced to use v2 libraries for "update to latest version" functionality.
If the flag is False, then references to v1 and v2 libraries both work, and you can pull an update from either type of library. We switch based on the library key type.
If the flag is True, then for a given course run, Studio maps the v1 library reference to an equivalent v2 library reference. If that v2 library exists, then doing the update step grabs the latest from that v2 library. If that v2 library does not exist, we say there's no library–we ignore the v1 version of it.
I think that gives us a lot more flexibility for dealing with things that might go wrong with the migration process:
- It eliminates the need to update a bunch of v1 library references for courses that aren't actively being worked on.
- We won't distort the meaning of the last published date by mass-publishing every course run.
- If there are individual errors during the upgrade process, they're less likely to put the course into a broken state–because they'd see those problems come up in their Studio draft and be able to discard their changes. We can then fix those v2 libraries as needed.
There was a problem hiding this comment.
@connorhaugh: What are your thoughts on this as a migration strategy? ^
There was a problem hiding this comment.
Consideration: At some point, I think we're going to want to be able to say "I want to select from this identified thing in the library, and potentially get updates from things I haven't selected yet" -- i.e. the equivalent of what happens to the whole library, only with a subset. Not by tags, but as a named collection–particularly if we get into a situation where we are one day mapping multiple v1 libraries into a v2 library.
Maybe we could a field that points to the library block whose children we're selecting for the course, and in the case of "whole library", it points to the root library block?
There was a problem hiding this comment.
@ormsbee Right, makes sense.
So, this?
- field name
root_block - settings scoped
- type is a pair of strings:
(block type, block id) - default is
("library", "library")(the root library block, I think)
That begs the question for me--do V2 libraries even have "library root blocks" the way that V1 libraries do?
There was a problem hiding this comment.
@kdmccormick No, there is no "root block" in v2 libraries. It's not necessary, and we're trying to move away from "everything is an XBlock" to only "component leaves are XBlocks".
There was a problem hiding this comment.
I didn't think so. @ormsbee, I think I'm confused by your suggestion?
There was a problem hiding this comment.
"I want to select from this identified thing in the library, and potentially get updates from things I haven't selected yet"
Auto-updating libraries are out of scope atm, and "updates" proc on library publish, if I understand things correctly, so happy to leave this conversation for another day. I'll add this to the discussion items for kyle & I's weekly sync.
There was a problem hiding this comment.
I assume that whatever field we add here would have a backwards-compatible default, so I think it's safe to leave it out of the ADR for now, and then amend the ADR if/when we decide to add it.
Rather than implementing V2-library and static-library-reference support in a new block, we will be enhancing the existing `LibraryContentBlock` in-place. Relevant ADR PR: openedx#33231
88e7d82 to
bea44bb
Compare
Originally, we planned to add support for V2 libraries and for static (hand-selected) library block reference via new block type: library_sourced. We have since decided that it would be better to add those capabilities in-place to the existing library_content block. This will ease V1->V2 library migration and make adoption of the new features easier for current library users. It will also avoid duplication of logic between two block types, we we fear would be error-prone. For details, see this ADR: #33231 So, we are removing the library_sourced block. This block has existed in edx-platform for a few years now, but was not enabled by default and never officially supported. It was only usable via the experimental V2 content library feature. Operators who added library_sourced blocks to their course will now see them render as `HiddenBlock` instances, i.e.: > ERROR: "library_sourced" is an unknown component type... This should not impact other component types in such courses and should not impact import/export.
bea44bb to
2b31872
Compare
kdmccormick
left a comment
There was a problem hiding this comment.
@connorhaugh This is good to merge at your leisure 👍🏻
|
2U Release Notice: This PR has been deployed to the edX staging environment in preparation for a release to production. |
|
2U Release Notice: This PR has been deployed to the edX production environment. |
1 similar comment
|
2U Release Notice: This PR has been deployed to the edX production environment. |
|
A future evolution to this schema: "Children" with the above proposed usage, will not fly in terms of UX. In the current experience, all "children" are rendered in the "select blocks from library to include in course" UI. Selecting one item would then in theory remove all other children. I'm going to propose a "included" field to cover this use case and build that logic into the first step of the "make selection" process I also may propose another name for "included" |
Rendered: https://github.com/kdmccormick/edx-platform/blob/kdmccormick/library-content-block-adr/xmodule/docs/decisions/0003-library-content-block-schema.rst