You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Let's pick apart two properties of dynamic content:
Variant space: Is the set of possible content based on predefined variants? If not, can the variants be generated from a predefined pool of content? Or, is the space completely undefined, generated on-the-fly at learning time?
Assignment stability: Once a user is assigned a variant, if the content remains stable, does the user's variant assignment generally remain stable too, or is it subject to change based on LMS-side conditions (unstable)? This might actually be a spectrum rather than a dichotomy. Perhaps a more precise question is: What are the conditions under which a user's assignment to a variant could change, and can we listen for the changes?
split test: Predefined variants, mostly-stable assignment (other than: track upgrade, team membership change, et al)
item_bank: Predefined pool (but innumerably large variant space), stable assignment (other than: content sync from library that causes assigned blocks to be removed).
conditional: Predefined variants, unstable assignment (changing an answer to a poll or a problem can update the assignment).
Still need to consider dynamic content which occurs outside of the scope of those blocks.
@ormsbee , @bradenmacdonald We had discussed a "flat" data model, where any given container's dynamic children would be rendered inline with its static children, and some "rules" (defined at the container level or the course level) would decide which dynamic children to hide for any given user. There's appeal to this, but as an authoring data model, I think it falls short in two areas:
Ordering: Dynamic children, particularly for an ItemBank, might need to appear in a different order for different users. But, the dynamic children may be surrounded on either side by static children with a constant order. Imagine a unit like this, where each B is an ItemBank configured to show 2 ordered random items, and each C is a regular component:
If each B were not a node in the authored hierarchy, then I'm not sure how we'd encode that fact that each B1.$x needs to appear in a random position between C0 and C1 and that each B3.$y needs to appear at a random position between C2 and C4.
UI and OLX correspondence: Now, I know that we are in no obligation to make our authored data model match OLX and the Studio UI, both of which currently encode several types of dynamic content as container-like things (<split_test>, <itembank>, etc.). But, I think that we are introducing a certain amount of complexity and surprise by not choosing to make the authoring data model correspond to OLX and the UI. And that additional complexity would need to be seriously justified by some other data modelling benefits, and I'm just not seeing those concrete benefits right now.
With that said, I do think it's natural to encode dynamic children flatly for a learner outline. Particularly, the outline model that @ormsbee is describing in #360 could exclude "dynamic containers", and instead just encode a static version of every outline that any user has seen.
For this reason, I am considering the idea of Pool, which would be a new type of PublishableEntity, but neither a Component nor a Container. It would appear as a node in the content hierarchy for authoring purposes, and it would have an orderless EntityList (or EntityList-like thing) for all its possible children. But, it would not manifest in the content hierarchy for learning purposes; we would have some pluggable subsystem that picks an ordered sub-list for every learner, and concatenates that sub-list into the parent container. (I have more semi-formed thoughts on this that I'd love to talk through today)
@kdmccormick I'm a bit reluctant to add a new "type" alongside container and component, but your points make a lot of sense.
Also, your Pool in the container hierarchy seems to play the exact same role as the DynamicContent placeholder that I had been starting to think about for the purposes of materializing the entire authoring outline hierarchy.
https://github.com/eduNEXT/xblock-extemporaneous-grading - "allows the course author to set a due date and a late due date for a set of components. The learner will only be able to see the content of the components if they are within the established dates."
Thinking out loud, I wonder if replacing non-leaf block types in a backwards compatible way would require 3 separate plugin systems:
A way for operators to plug in rules for selection/restriction of children
A way for operators to plug in custom editors for things above the component level
A way for operators to specify custom parsing logic for a given olx tag (or, a way for operators to specify how to translate legacy olx tags into a "new" well-specified olx schema)
Activity
[-]Selectors Brainstorming[/-][+]Dynamic Content Brainstorming[/+]<conditional>#363<randomize>#364<split_test>#365<item_bank>,<library_content>#366kdmccormick commentedon Aug 21, 2025
Let's pick apart two properties of dynamic content:
Analyzing known dynamic content blocks:
Still need to consider dynamic content which occurs outside of the scope of those blocks.
kdmccormick commentedon Aug 26, 2025
@ormsbee , @bradenmacdonald We had discussed a "flat" data model, where any given container's dynamic children would be rendered inline with its static children, and some "rules" (defined at the container level or the course level) would decide which dynamic children to hide for any given user. There's appeal to this, but as an authoring data model, I think it falls short in two areas:
Ordering: Dynamic children, particularly for an ItemBank, might need to appear in a different order for different users. But, the dynamic children may be surrounded on either side by static children with a constant order. Imagine a unit like this, where each B is an ItemBank configured to show 2 ordered random items, and each C is a regular component:
C0, B1, C2, B3, C4<- author viewC0, B1.3, B1.7, C2, B3.9, B3.1, C4<- learner viewIf each
Bwere not a node in the authored hierarchy, then I'm not sure how we'd encode that fact that eachB1.$xneeds to appear in a random position between C0 and C1 and that eachB3.$yneeds to appear at a random position between C2 and C4.UI and OLX correspondence: Now, I know that we are in no obligation to make our authored data model match OLX and the Studio UI, both of which currently encode several types of dynamic content as container-like things (
<split_test>,<itembank>, etc.). But, I think that we are introducing a certain amount of complexity and surprise by not choosing to make the authoring data model correspond to OLX and the UI. And that additional complexity would need to be seriously justified by some other data modelling benefits, and I'm just not seeing those concrete benefits right now.With that said, I do think it's natural to encode dynamic children flatly for a learner outline. Particularly, the outline model that @ormsbee is describing in #360 could exclude "dynamic containers", and instead just encode a static version of every outline that any user has seen.
For this reason, I am considering the idea of Pool, which would be a new type of PublishableEntity, but neither a Component nor a Container. It would appear as a node in the content hierarchy for authoring purposes, and it would have an orderless EntityList (or EntityList-like thing) for all its possible children. But, it would not manifest in the content hierarchy for learning purposes; we would have some pluggable subsystem that picks an ordered sub-list for every learner, and concatenates that sub-list into the parent container. (I have more semi-formed thoughts on this that I'd love to talk through today)
bradenmacdonald commentedon Aug 26, 2025
@kdmccormick I'm a bit reluctant to add a new "type" alongside container and component, but your points make a lot of sense.
Also, your
Poolin the container hierarchy seems to play the exact same role as theDynamicContentplaceholder that I had been starting to think about for the purposes of materializing the entire authoring outline hierarchy.bradenmacdonald commentedon Sep 5, 2025
As mentioned on another issue, I recently learned about three more examples of dynamic selector use cases:
kdmccormick commentedon Sep 5, 2025
Thanks, those are great to know about.
Thinking out loud, I wonder if replacing non-leaf block types in a backwards compatible way would require 3 separate plugin systems: