Scope filters should list read-write partitions last
@bjester đang làm issue này rồi.
Từ ngày 21/10/2026.
Đánh giá
Issue này chưa được đánh giá.
Mô tả
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Overview
Make the read and write filters of a Scope list the read-write partitions last, so that deserialization in filter order puts shared records before the records that reference them.
Background & Motivation
#392 streams deserialization one partition prefix at a time, in the order of the sync filter. A record whose FK target is in a later partition gets a deserialization error, because the target is not in the app table yet. The legacy deserialization looped model by model across all partitions, so the order of the filter did not matter before 0.9.0.
The contract in #392 is that the caller gives the partitions in a usable order. But callers do not always write the filter. Kolibri passes Scope.read_filter and Scope.write_filter directly as its pull and push filters, and Scope builds them as the read-write partitions, then the read-only or write-only partitions:
| Scope | Kolibri template order | Scope.read_filter order |
|---|---|---|
single-user |
read: allusers-ro, user-ro:U. read-write: user-rw:U |
user-rw:U, allusers-ro, user-ro:U |
full-facility |
read-write: D |
D |
In the single-user scope, the logs are in user-rw:U and the FacilityUser is in user-ro:U. Morango deserializes the logs first, and they fail on a device that does not have the user yet. With #392 installed, two of Kolibri's Morango integration tests failed for this reason:
SingleUserSyncRegressionsTestCase::test_kolibri_issue_8439SingleUserSyncRegressionsTestCase::test_issue_fixed_in_morango_pull_146
Both tests passed after Kolibri reordered the read filter itself, with the read-only partitions first. That fix puts a Morango detail in Kolibri, and every other implementer would need the same fix.
User Story / Use Case
As a developer of an app that syncs with Morango,
I want the filters thatScopebuilds from my scope definition to keep a usable order,
So that I control the deserialization order through my templates, and do not have to reorder Morango's filters.
Description & Expected Outcomes
Scope.read_filterlists the read-only partitions, then the read-write partitions.Scope.write_filterlists the write-only partitions, then the read-write partitions.- Within each template, the partitions keep the order of the template.
- The order the filter must have for deserialization is documented, so implementers know how to order their templates.
Read-write partitions usually hold the device's own records, such as a user's logs. Those records usually reference shared records in the read-only partitions, such as the user, the facility and the classrooms. The reverse is rare. This order is a convention, not a guarantee. A read-only record that references a read-write record still fails, and Morango cannot detect this case, because it knows the dependencies between models but not between partitions.
Value Add & Impact
- Implementers that pass
Scopefilters directly get a usable deserialization order without extra code. - Kolibri does not need to reorder the read filter of the
single-userscope.
Deliverables & Contracts
Scope.read_filterandScope.write_filterlist the read-write partitions last.- The docstrings of
Scopeand of the stream source describe the order contract. - The
0.9.0section ofCHANGELOG.mdrecords the new order.
Acceptance Criteria
- A test builds a
Scopefrom templates with read-only, write-only and read-write partitions, and checks the order of both filters. - A deserialization test with a filter in the
single-usershape deserializes a record before the records that reference it. - Kolibri's Morango integration tests pass without Kolibri reordering the read filter, including
test_kolibri_issue_8439,test_issue_fixed_in_morango_pull_146andtest_single_user_course_syncing. -
make testpasses on SQLite and PostgreSQL.
Technical Pointers & Architecture
- Target Components / Context:
Scope.__init__inmorango/models/certificates.py.MorangoSource.prefix_conditionsinmorango/sync/stream/source.pydocuments the order contract. - Related Patterns:
Filter.__add__keeps the order of both operands and removes duplicates. - Data Model & Schema Considerations: No model fields or migrations change.
TransferSession.filterstoresstr(filter), so new transfer sessions store the partitions in the new order. - Resilience & Failure Modes: The comparisons we found do not depend on order. These are
Filter.is_subset_of, which the server uses to validate a requested filter, andFilter.__eq__, whichmorango/sync/context.pyand Kolibri use. Check for any other code that compares filter strings.
Notes & Tradeoffs
- Dependencies: Related to #392. Do this before
0.9.0ships, because0.9.0is the first release in which the filter order matters. - Testing Requirements:
tests/testapp/tests/test_api.pytakes the first partition of aread_filterwith.split()[0]. Its scope has no read-write partitions, so the change does not affect it, but check similar tests. - Tradeoffs & Alternatives Considered:
- Kolibri reorders the filter itself. This works, and the Kolibri integration tests pass with it, but each implementer must know how
Scopecombines the templates. - Morango sorts the partition prefixes. #392 tried this before release. It broke
test_single_user_course_syncing, where the classroom partitions sort before the user partitions they reference. - Morango deserializes model by model across all partitions, with one query that combines the prefixes, as the legacy code did. This makes the order irrelevant, but we do not want to combine many prefixes into one query expression.
- Kolibri reorders the filter itself. This works, and the Kolibri integration tests pass with it, but each implementer must know how
- Compatibility & Migrations: Devices on older Morango versions do not depend on the filter order, so mixed-version syncs are not affected.
Metadata
Complexity: Low
Target Branch: release-v0.9.x
Labels: TAG: tech update / debt
AI Usage
Drafted with Claude Code while we investigated Kolibri integration test failures against #392. Claude traced the failures to the order of Scope.read_filter, and tested a Kolibri-side reorder that made the tests pass. I rejected a Morango-side fix that combined the prefixes into one query, and chose to track the Scope change in this issue instead of in #392.
- Ngôn ngữ chính
- Python
- Star
- 15
- Fork
- 23
- Merge trung bình
- 2 ngày 8 giờ
- Pull request đã merge (30 ngày)
- 5
Chuẩn bị môi trường
- Có Dockerfile hoặc tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của learningequality/morango
-
DEV: dev-ops DEV: distributions DOCS: developer
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 78/100
learningequality/morango#387 ·
-
DEV: backend DEV: dev-ops TAG: unit tests
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
learningequality/morango#385 ·
-
DEV: backend P0 - critical TAG: tech update / debt TAG: unit tests
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
learningequality/morango#364 ·
-
Remove the deferred FK validation API and unused backend bulk helpersCó thể đã có người làm @bjester đã nhận 3 ngày trước. Đang mởTAG: tech update / debt
learningequality/morango#396 · 1 người được giao ·
-
dependencies DEV: dev-ops TAG: dependencies
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 1/100
learningequality/morango#395 ·
Tất cả issue của learningequality/morango
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
khuisman/mcp-gee-sweet#1166 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
lugassawan/swe-workbench#823 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
gramaziokohler/compas_timber#870 ·
-
security-scan-failure
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
semantica-agi/semantica#2089 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
autowarefoundation/autoware_carla_scenario#500 ·
Maintainer thường phản hồi trong vòng 1 ngày