Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0473c0e
feat: #253 new branch to reduce noise; adding BE logic to implement c…
tbain Mar 18, 2026
2c0b959
feat: #253 Fixing API tests with regard to count logic changes
tbain Mar 23, 2026
8846805
Merge branch 'main' of https://github.com/openedx/openedx-core into t…
tbain Mar 25, 2026
b01964b
feat: #253 Resolving merge conflict with upstream main branch
tbain Mar 26, 2026
a23afe8
feat: #253 Fixing pylint issues
tbain Mar 26, 2026
3df68ab
feat: #253 Fixing pycodestyle issue
tbain Mar 26, 2026
435808c
feat: #253 Fixing pycodestyle issue
tbain Mar 26, 2026
457313b
feat: #253 Addressing first round Code review comments
tbain Mar 27, 2026
a14c56e
feat: #253 fixing count depth issue and updating appropriate unit tests
tbain Mar 27, 2026
2055a07
feat: #253 fixing spelling errors in comments
tbain Mar 27, 2026
7cf1539
docs: update docstring to reflect Content->Media rename
ormsbee Mar 29, 2026
e28fab7
chore: Upgrade Python requirements (#519)
edx-requirements-bot Mar 30, 2026
c7f6a2b
docs: CBE assessment criteria versioning ADR (#476)
mgwozdz-unicon Mar 30, 2026
939f18c
feat: #253 Fixing code review comments; fix incorrect unit test & fil…
tbain Mar 30, 2026
435f380
feat!: remove tag "descendant_count" to optimize large taxonomies (#517)
bradenmacdonald Mar 31, 2026
c997e66
fix: Make container_type backfill reversible (#528)
kdmccormick Apr 1, 2026
5762c33
feat: #253 adjusting comments per code review feedback
tbain Apr 1, 2026
79be83a
Merge branch 'main' of https://github.com/openedx/openedx-core into t…
tbain Apr 1, 2026
c2f79d2
feat: #253 fixing unit tests to work with upstream updates
tbain Apr 1, 2026
c017e8a
feat: #253 Changing usage_count to being in-mem/python based instead …
tbain Apr 3, 2026
7d42793
feat: #253 Fixing code quality pipeline issues
tbain Apr 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions docs/decisions/0024-competency-criteria-versioning.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
24. How should versioning be handled for CBE competency achievement criteria?
=============================================================================

Context
-------
Course Authors and/or Platform Administrators will be entering the competency achievement criteria rules in Studio that learners are required to meet in order to demonstrate competencies. Depending on the institution, these Course Authors or Platform Administrators may have a variety of job titles, including Instructional Designer, Curriculum Designer, Instructor, LMS Administrator, Faculty, or other Staff.

Typically, only one person would be responsible for entering competency achievement criteria rules in Studio for each course, though this person may change over time. However, entire programs could have many different Course Authors or Platform Administrators with this responsibility.

Typically, institutions and instructional designers do not change the mastery requirements (competency achievement criteria) for their competencies frequently over time. However, the ability to do historical audit logging of changes within Studio can be a valuable feature to those who have mistakenly made changes and want to revert or those who want to experiment with new approaches.

Currently, Open edX always displays the latest edited version of content in the Studio UI and always shows the latest published version of content in the LMS UI, despite having more robust version tracking on the backend (Publishable Entities).

Authoring data (criteria definitions) and runtime learner data (status) have different governance needs. The former is long-lived and typically non-PII, while the latter is user-specific, can be large (learners x criteria/competencies x time), and may require stricter retention and access controls. These differing lifecycles can make deep coupling of authoring and runtime data harder to manage at scale. Performance is also a consideration as computing or resolving versioned criteria for large courses could add overhead in Studio authoring screens or LMS views.

Decision
--------
For the initial implementation, versioning and traceability of competency achievement criteria will be handled with a combination of model history and lifecycle guardrails:

1. Apply ``django-simple-history`` to competency criteria definition moodels/tables:

- ``CompetencyCriteriaGroup``
- ``CompetencyCriteria``
- ``CompetencyRuleProfile``

This provides historical row snapshots and audit metadata for authored criteria definitions, without adopting the full publishable framework for this phase.

2. Do not apply ``django-simple-history`` to ``oel_tagging_tag``, ``oel_tagging_taxonomy``, or ``CompetencyTaxonomy`` in this phase.

These models are treated as non-evaluative display/metadata for competency criteria purposes; edits to names or metadata in these tables are not intended to change evaluation outcomes.

3. ``oel_tagging_objecttag`` associations used by competency criteria follow post-use archive rules:

- Before any related learner status exists, edits and deletes are allowed.
- After any related learner status exists, disassociation/deletion is archive-only (soft delete), not hard delete.
- Archived rows remain queryable so learner status records can continue to be traced back to their source association.

4. Authoring guardrails must warn on potentially impactful edits:

- If a user edits competency criteria definitions or competency object/tag associations after related learner status exists, Studio must display an explicit warning that student statuses have already been set, and these changes will be applied going forward, so existing learner statuses will not be retroactively updated.
- Applying these changes requires explicit user confirmation.

5. Learner status models/tables are append-only history and do not use ``django-simple-history``:

- For ``StudentCompetencyCriteriaStatus``, ``StudentCompetencyCriteriaGroupStatus``, and ``StudentCompetencyStatus``, each status change is stored as a new row with ``created`` as the write timestamp.
- Existing learner status rows are not updated in place.
- Current status is determined by the most recent row for a given learner + target entity (ordered by ``created``, with ``id`` as a tie-breaker).
- Older rows represent the learner status history and remain available for audit/tracing.


Rejected Alternatives
---------------------

1. Defer competency achievement criteria versioning for the initial implementation. Store only the latest authored criteria and expose the latest published state in the LMS, consistent with current Studio/LMS behavior.
- Pros:
- Keeps the initial implementation lightweight
- Cons:
- There is no built-in rollback or audit history
- Adding versioning later will require data migration and careful choices about draft vs published defaults
2. Each model indicates version, status, and audit fields
- Pros:
- Simple and familiar pattern (version + status + created/updated metadata)
- Straightforward queries for the current published state
- Can support rollback by marking an earlier version as published
- Stable identifiers (original_ids) can anchor versions and ease potential future migrations
- Cons:
- Requires custom conventions for versioning across related tables and nested groups
- Lacks shared draft/publish APIs and immutable version objects that other authoring apps can reuse
- Not necessarily consistent with existing patterns in the codebase (though these are already not overly consistent).
3. Publishable framework in openedx-learning
- Pros:
- First-class draft/published semantics with immutable historical versions
- Consistent APIs and patterns shared across other authoring apps
- Cons:
- Requires modeling criteria/groups as publishable entities and wiring Studio/LMS workflows to versioning APIs
- Adds schema and migration complexity for a feature that does not yet require full versioning
4. Append-only audit log table (event history)
- Pros:
- Lightweight way to capture who changed what and when
- Enables basic rollback by replaying or reversing events
- Cons:
- Requires custom tooling to reconstruct past versions
- Does not align with existing publishable versioning patterns
10 changes: 5 additions & 5 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ attrs==26.1.0
# via -r requirements/base.in
billiard==4.2.4
# via celery
celery==5.6.2
celery==5.6.3
# via -r requirements/base.in
certifi==2026.2.25
# via requests
Expand All @@ -35,7 +35,7 @@ click-plugins==1.1.1.2
# via celery
click-repl==0.3.0
# via celery
cryptography==46.0.5
cryptography==46.0.6
# via pyjwt
django==5.2.12
# via
Expand All @@ -60,7 +60,7 @@ django-waffle==5.0.0
# via
# edx-django-utils
# edx-drf-extensions
djangorestframework==3.17.0
djangorestframework==3.17.1
# via
# -r requirements/base.in
# drf-jwt
Expand All @@ -80,7 +80,7 @@ edx-opaque-keys==3.1.0
# via
# edx-drf-extensions
# edx-organizations
edx-organizations==7.3.0
edx-organizations==8.0.0
# via -r requirements/base.in
idna==3.11
# via requests
Expand All @@ -106,7 +106,7 @@ pynacl==1.6.2
# via edx-django-utils
python-dateutil==2.9.0.post0
# via celery
requests==2.32.5
requests==2.33.0
# via edx-drf-extensions
rules==3.5
# via -r requirements/base.in
Expand Down
8 changes: 5 additions & 3 deletions requirements/ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ pluggy==1.6.0
# via tox
pyproject-api==1.10.0
# via tox
python-discovery==1.2.0
# via virtualenv
python-discovery==1.2.1
# via
# tox
# virtualenv
tomli-w==1.2.0
# via tox
tox==4.50.3
tox==4.51.0
# via -r requirements/ci.in
virtualenv==21.2.0
# via tox
23 changes: 12 additions & 11 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ billiard==4.2.4
# via
# -r requirements/quality.txt
# celery
build==1.4.0
build==1.4.2
# via
# -r requirements/pip-tools.txt
# pip-tools
cachetools==7.0.5
# via
# -r requirements/ci.txt
# tox
celery==5.6.2
celery==5.6.3
# via -r requirements/quality.txt
certifi==2026.2.25
# via
Expand All @@ -42,7 +42,7 @@ cffi==2.0.0
# -r requirements/quality.txt
# cryptography
# pynacl
chardet==7.2.0
chardet==7.4.0.post2
# via diff-cover
charset-normalizer==3.4.6
# via
Expand Down Expand Up @@ -90,7 +90,7 @@ coverage[toml]==7.13.5
# via
# -r requirements/quality.txt
# pytest-cov
cryptography==46.0.5
cryptography==46.0.6
# via
# -r requirements/quality.txt
# pyjwt
Expand Down Expand Up @@ -153,7 +153,7 @@ django-waffle==5.0.0
# -r requirements/quality.txt
# edx-django-utils
# edx-drf-extensions
djangorestframework==3.17.0
djangorestframework==3.17.1
# via
# -r requirements/quality.txt
# drf-jwt
Expand Down Expand Up @@ -190,7 +190,7 @@ edx-opaque-keys==3.1.0
# -r requirements/quality.txt
# edx-drf-extensions
# edx-organizations
edx-organizations==7.3.0
edx-organizations==8.0.0
# via -r requirements/quality.txt
filelock==3.25.2
# via
Expand Down Expand Up @@ -293,7 +293,7 @@ mypy-extensions==1.1.0
# mypy
mysqlclient==2.2.8
# via -r requirements/quality.txt
nh3==0.3.3
nh3==0.3.4
# via
# -r requirements/quality.txt
# readme-renderer
Expand Down Expand Up @@ -355,7 +355,7 @@ pycparser==3.0
# cffi
pydocstyle==6.3.0
# via -r requirements/quality.txt
pygments==2.19.2
pygments==2.20.0
# via
# -r requirements/quality.txt
# diff-cover
Expand Down Expand Up @@ -418,9 +418,10 @@ python-dateutil==2.9.0.post0
# -r requirements/quality.txt
# celery
# freezegun
python-discovery==1.2.0
python-discovery==1.2.1
# via
# -r requirements/ci.txt
# tox
# virtualenv
python-slugify==8.0.4
# via
Expand All @@ -435,7 +436,7 @@ readme-renderer==44.0
# via
# -r requirements/quality.txt
# twine
requests==2.32.5
requests==2.33.0
# via
# -r requirements/quality.txt
# edx-drf-extensions
Expand Down Expand Up @@ -496,7 +497,7 @@ tomlkit==0.14.0
# via
# -r requirements/quality.txt
# pylint
tox==4.50.3
tox==4.51.0
# via -r requirements/ci.txt
twine==6.2.0
# via -r requirements/quality.txt
Expand Down
14 changes: 7 additions & 7 deletions requirements/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ billiard==4.2.4
# via
# -r requirements/test.txt
# celery
celery==5.6.2
celery==5.6.3
# via -r requirements/test.txt
certifi==2026.2.25
# via
Expand Down Expand Up @@ -71,7 +71,7 @@ coverage[toml]==7.13.5
# via
# -r requirements/test.txt
# pytest-cov
cryptography==46.0.5
cryptography==46.0.6
# via
# -r requirements/test.txt
# pyjwt
Expand Down Expand Up @@ -121,7 +121,7 @@ django-waffle==5.0.0
# -r requirements/test.txt
# edx-django-utils
# edx-drf-extensions
djangorestframework==3.17.0
djangorestframework==3.17.1
# via
# -r requirements/test.txt
# drf-jwt
Expand Down Expand Up @@ -159,7 +159,7 @@ edx-opaque-keys==3.1.0
# -r requirements/test.txt
# edx-drf-extensions
# edx-organizations
edx-organizations==7.3.0
edx-organizations==8.0.0
# via -r requirements/test.txt
freezegun==1.5.5
# via -r requirements/test.txt
Expand Down Expand Up @@ -214,7 +214,7 @@ mypy-extensions==1.1.0
# mypy
mysqlclient==2.2.8
# via -r requirements/test.txt
nh3==0.3.3
nh3==0.3.4
# via readme-renderer
packaging==26.0
# via
Expand Down Expand Up @@ -251,7 +251,7 @@ pycparser==3.0
# cffi
pydata-sphinx-theme==0.16.1
# via sphinx-book-theme
pygments==2.19.2
pygments==2.20.0
# via
# -r requirements/test.txt
# accessible-pygments
Expand Down Expand Up @@ -298,7 +298,7 @@ pyyaml==6.0.3
# code-annotations
readme-renderer==44.0
# via -r requirements/doc.in
requests==2.32.5
requests==2.33.0
# via
# -r requirements/test.txt
# edx-drf-extensions
Expand Down
2 changes: 1 addition & 1 deletion requirements/pip-tools.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#
# make upgrade
#
build==1.4.0
build==1.4.2
# via pip-tools
click==8.3.1
# via pip-tools
Expand Down
14 changes: 7 additions & 7 deletions requirements/quality.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ billiard==4.2.4
# via
# -r requirements/test.txt
# celery
celery==5.6.2
celery==5.6.3
# via -r requirements/test.txt
certifi==2026.2.25
# via
Expand Down Expand Up @@ -71,7 +71,7 @@ coverage[toml]==7.13.5
# via
# -r requirements/test.txt
# pytest-cov
cryptography==46.0.5
cryptography==46.0.6
# via
# -r requirements/test.txt
# pyjwt
Expand Down Expand Up @@ -123,7 +123,7 @@ django-waffle==5.0.0
# -r requirements/test.txt
# edx-django-utils
# edx-drf-extensions
djangorestframework==3.17.0
djangorestframework==3.17.1
# via
# -r requirements/test.txt
# drf-jwt
Expand Down Expand Up @@ -156,7 +156,7 @@ edx-opaque-keys==3.1.0
# -r requirements/test.txt
# edx-drf-extensions
# edx-organizations
edx-organizations==7.3.0
edx-organizations==8.0.0
# via -r requirements/test.txt
freezegun==1.5.5
# via -r requirements/test.txt
Expand Down Expand Up @@ -232,7 +232,7 @@ mypy-extensions==1.1.0
# mypy
mysqlclient==2.2.8
# via -r requirements/test.txt
nh3==0.3.3
nh3==0.3.4
# via readme-renderer
packaging==26.0
# via
Expand Down Expand Up @@ -271,7 +271,7 @@ pycparser==3.0
# cffi
pydocstyle==6.3.0
# via -r requirements/quality.in
pygments==2.19.2
pygments==2.20.0
# via
# -r requirements/test.txt
# pytest
Expand Down Expand Up @@ -328,7 +328,7 @@ pyyaml==6.0.3
# code-annotations
readme-renderer==44.0
# via twine
requests==2.32.5
requests==2.33.0
# via
# -r requirements/test.txt
# edx-drf-extensions
Expand Down
Loading