Repository navigation
fix(tags): workaround: report tag moves which are no-ops - #22821
Conversation
Report `UnusedTagNotMoved` when the backend fails to move a tag subtree as it is unused. Part of 10397 Workaround for https://redirect.github.com/ankitects/anki/issues/5870 Assisted-by: GPT-6.1-Sol xhigh Assisted-by: GPT-6-Astra xhigh
mikehardy
left a comment
There was a problem hiding this comment.
Assisted-by: grok-4.7
Thank you. The zero-count path was already real for unused tags; this separates that refusal from a move that truly has nothing to do.
Rebased locally onto current main with a clean replay and did not push. Ran lintAll, ktlintCheck, lint-rules:test, jacocoUnitTestReport, and TEST_RELEASE_BUILD emulator tests on emulator-5556 / API35_GAPI; all green.
TagName.withParent takes the leaf after the last :: and returns TagName.build of parent::leaf, or of the leaf alone when the parent is null. moveTagTree uses that as destination and still returns opChangesWithCount { } when destination == tag (folded identity, including the unicase rotation). Otherwise it still calls renameTagTree. requireNotNull replaces the old !! on that build. Callers only pass TagNames, and build is the only constructor, so the leaf is not blank and this does not add a new null path.
moveTag still runs that op inside launchTagOpAndRefresh, then enqueues one message and loadTags runs after it. currentParent is TagName.build(tag.value.substringBeforeLast("::", "")), so a tag with no :: has a null parent. UnusedTagNotMoved is count == 0 && currentParent != newParent. Equality is TagName identity, not spelling, so move uses backend identity to detect an unchanged parent still sees Straße and STRASSE as the same parent and keeps TagMoved(0) with the note and undo stack untouched. unchanged move preserves an available redo moves an already top-level source to null after an undo; both parents are null, so that stays TagMoved(0) and the redo entry remains.
A used subtree still takes the TagMoved(count) branch: moveTag updates descendants on notes expects TagMoved(2), and merging onto an existing subtree expects TagMoved(1). An illegal parent still throws before the enqueue (pendingMessages stays empty). Rename of an unused subtree is unchanged and still queues TagRenamed(0).
some acceptable findings, no action required, just leaving for posterity: Part of 10397 has no #, in the body and the commit, so the epic is not a GitHub issue link; the same-place check re-parses the parent with substringBeforeLast. tag.withParent(newParent) == tag is the predicate moveTagTree already returns on, and it would stay aligned if destination building changes.
Note
Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
Purpose / Description
Workaround an upstream Anki bug; very low priority, just splitting it out so I don't need to think about it any more
Fixes
reparent_tagson an empty subtree ankitects/anki#5870Approach
Report
UnusedTagNotMovedwhen the backend fails to move a tag subtree as it is unused.How Has This Been Tested?
This functionality is not yet exercised in production, test-only
Checklist