
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.

Overview
Move PinnedDeviceViewSet — migrated to the serializer-derived pattern in #14292 — from kolibri/core/discovery/api.py into kolibri/core/discovery/viewsets/pinned_device.py, with PinnedDeviceSerializer inline. As the last issue touching the discovery app's API modules, it also moves the remaining non-migrating code into the package and deletes api.py and serializers.py, per the File Organization convention in #14036.
Complexity: Low
Target branch: develop
Context
PinnedDeviceViewSet lives in kolibri/core/discovery/api.py with PinnedDeviceSerializer in serializers.py; its migration to the serializer-derived pattern lands via #14292 (PR #14818), so this is a pure relocation with no serialization changes.
The rest of the discovery API is residue that moves as-is: NetworkLocationViewSet and its Dynamic/Static subclasses (with NetworkLocationSerializer), and NetworkLocationFacilitiesView (with its inline _RemoteFacilityPicturePasswordSerializer/_RemoteFacilitySerializer) — per #14036, the latter never uses the ValuesViewset serialization path (it makes live HTTP requests).
The Change
Create the kolibri/core/discovery/viewsets/ package (empty __init__.py) and move PinnedDeviceViewSet with PinnedDeviceSerializer inline into kolibri/core/discovery/viewsets/pinned_device.py, and the network-location residue (viewsets, serializers, and NetworkLocationFacilitiesView) into one module per domain. Land each relocation as a pure-move commit, separate from import updates. Update imports (api_urls.py, tests, cross-references), then delete api.py and serializers.py.
Moving code breaks GitHub blame (local git blame -C -C still works), so digest the history the move obscures:
- Run blame over the code being moved; flag hunks whose purpose isn't evident from the code or tests (odd guards, magic orderings, special cases).
- Chase each flagged hunk to its originating PR/issue; where the rationale is non-obvious and load-bearing, carry it forward as a code comment citing the reference.
- Where the rationale turns out to be obsolete, flag the code for removal — but as a pure move, this PR should not remove it; raise it for follow-up instead.
Out of Scope
Acceptance Criteria
Testing
- Run the benchmark for
PinnedDeviceViewSet, baseline with the old dotted path, comparison with the new one:
python integration_testing/scripts/viewset_serialization_benchmark.py \
kolibri.core.discovery.api.PinnedDeviceViewSet \
--inherit-kolibri-home -o pinned_device_baseline.json
# ... move ...
python integration_testing/scripts/viewset_serialization_benchmark.py \
kolibri.core.discovery.viewsets.pinned_device.PinnedDeviceViewSet \
--inherit-kolibri-home --compare pinned_device_baseline.json
- The comparison must pass; include the before/after output in the PR description.
- Benchmark data setup (run via
kolibri manage shell before benchmarking):
from kolibri.core.discovery.models import PinnedDevice
import uuid
for i in range(100):
PinnedDevice.objects.get_or_create(
instance_id=uuid.uuid4(),
)
AI usage
Drafted with AI assistance (Claude Code) from an interactive design discussion, section by section, with review and final edits by @rtibbles. Module contents, serialization paths, and the benchmark setup (carried over from #14292) were verified against the codebase during drafting.
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Overview
Move
PinnedDeviceViewSet— migrated to the serializer-derived pattern in #14292 — fromkolibri/core/discovery/api.pyintokolibri/core/discovery/viewsets/pinned_device.py, withPinnedDeviceSerializerinline. As the last issue touching the discovery app's API modules, it also moves the remaining non-migrating code into the package and deletesapi.pyandserializers.py, per the File Organization convention in #14036.Complexity: Low
Target branch: develop
Context
PinnedDeviceViewSetlives inkolibri/core/discovery/api.pywithPinnedDeviceSerializerinserializers.py; its migration to the serializer-derived pattern lands via #14292 (PR #14818), so this is a pure relocation with no serialization changes.The rest of the discovery API is residue that moves as-is:
NetworkLocationViewSetand itsDynamic/Staticsubclasses (withNetworkLocationSerializer), andNetworkLocationFacilitiesView(with its inline_RemoteFacilityPicturePasswordSerializer/_RemoteFacilitySerializer) — per #14036, the latter never uses the ValuesViewset serialization path (it makes live HTTP requests).The Change
Create the
kolibri/core/discovery/viewsets/package (empty__init__.py) and movePinnedDeviceViewSetwithPinnedDeviceSerializerinline intokolibri/core/discovery/viewsets/pinned_device.py, and the network-location residue (viewsets, serializers, andNetworkLocationFacilitiesView) into one module per domain. Land each relocation as a pure-move commit, separate from import updates. Update imports (api_urls.py, tests, cross-references), then deleteapi.pyandserializers.py.Moving code breaks GitHub blame (local
git blame -C -Cstill works), so digest the history the move obscures:Out of Scope
NetworkLocationFacilitiesViewnever uses the ValuesViewset serialization pathAcceptance Criteria
kolibri/core/discovery/viewsets/pinned_device.pycontainsPinnedDeviceViewSetwithPinnedDeviceSerializerinline; the network-location residue lives in the package, one module per domainapi.pyandserializers.pyare deleted, with all references updated (api_urls.py, tests)PinnedDeviceViewSet(data hash match + no performance regression)Testing
PinnedDeviceViewSet, baseline with the old dotted path, comparison with the new one:python integration_testing/scripts/viewset_serialization_benchmark.py \ kolibri.core.discovery.api.PinnedDeviceViewSet \ --inherit-kolibri-home -o pinned_device_baseline.json # ... move ... python integration_testing/scripts/viewset_serialization_benchmark.py \ kolibri.core.discovery.viewsets.pinned_device.PinnedDeviceViewSet \ --inherit-kolibri-home --compare pinned_device_baseline.jsonkolibri manage shellbefore benchmarking):AI usage
Drafted with AI assistance (Claude Code) from an interactive design discussion, section by section, with review and final edits by @rtibbles. Module contents, serialization paths, and the benchmark setup (carried over from #14292) were verified against the codebase during drafting.