Release LeanTypeDual 0.3.0 - #145
Merged
Merged
Conversation
…ated release notes
…ated release notes
… display name caching
Captures the 0.1.0 release, the LeanBitLab v4.0.3-v4.0.8 integration, the 0.2.0 cut, the one open task (signed v0.2.0 blocked on runner availability), verified build/test recipes, fork invariants, and the workflow traps encountered (gh account switching, tag-push triggers, the dev->main promotion recipe, apksigner low-API verification).
docs: session handoff
The repo tree moved from C:/Users/mahle/ to C:/Users/mahle/programming/, which left every secondary worktree marked `prunable` -- a relocation artifact, not abandonment. Repaired all 24 with `git worktree repair` and triaged them. Section 11 now records the post-cleanup worktree set: five kept deliberately (PR #106, LeanBitLab PR LeanBitLab#240, three baseline checkouts) and six holding commits that exist on no remote ref. Thirteen fully-merged worktrees were removed (~5.6 GB); every branch was kept, so each is restorable with `git worktree add`. Also documents two traps hit here: never reach for `git worktree prune` when a relocation makes everything look prunable, and `core.longpaths=true` is required or `git worktree remove` dies on deep Gradle build output and leaves a de-registered but half-deleted directory. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a6e8f983-22c2-4f2f-aacd-5316a5924a4d
Backspace appeared dead at the start of a paragraph in rich-text editors (MS Word, Samsung/Google Notes, Docs). Those editors model paragraphs as separate blocks and silently ignore a deleteSurroundingText that would merge two of them, while honouring a real KEYCODE_DEL - which is what other keyboards send. HeliBoard already had a KEYCODE_DEL fallback (8f80c2a) but scoped it to browsers only, so plain multi-line fields never reached it. Upstream v4.1.2 carries the same logic, so this is not fixed by merging upstream. Changes in handleBackspaceEvent: - Route deletion of a '\n' through a key event instead of deleteSurroundingText. Equivalent in a plain EditText. - Broaden the NOT_A_CODE fallback to any editor that hides context, but only when the expected cursor position is > 0, so a genuine document start stays a no-op and we never dispatch key events at apps that react to them (recipient chips, search boxes, web views). - Never chain the accelerated second delete onto a key event: key events take an asynchronous route that ignores batch edits, so a following deleteSurroundingText could race ahead and act on pre-merge text. - Fix a pre-existing bug in the accelerated path, which tested the first code point instead of codePointBeforeCursorToDeleteAgain and could split an emoji. Also present upstream; worth reporting. Tests: the fake InputConnection can now simulate a block-based editor (paragraph-scoped reads, cross-paragraph deletes that report success but do nothing). Also fixes two latent harness bugs: deleteSurroundingText did not clamp to available text (drove selectionStart negative), and setText ignored its own requireIdle parameter. The tap-into-paragraph variant is added as an @ignore'd test: it measures expectedSelectionStart == 0, making it indistinguishable from an empty field, so it needs a device trace before it can be fixed safely. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
#133) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
The removed-worktree list read as if every LeanType-upstream-* worktree was retired. They are a recurring, short-lived category created by the section 10 merge recipe; one (LeanType-upstream-412, merge/upstream-v4.1.2) was in flight when the list was written. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a6e8f983-22c2-4f2f-aacd-5316a5924a4d
Merges 200 upstream commits, pinned at tag SHA 8720abe, covering v4.0.9 through v4.1.2. Conflict decisions: - app/build.gradle.kts -> ours. Fork keeps versionCode 4200 / versionName 0.2.0; never adopt upstream's 4102 / 4.1.2. - README.md, docs/FEATURES.md -> ours. These are fork-identity documents (our badges, two-thumb as the namesake feature, our sponsor links); upstream's carry LeanBitLab branding. - docs/badges/*.svg -> ours, per the fork invariants. - fastlane changelogs/4100.txt -> ours. Upstream happened to reuse the same versionCode; this file is our 0.1.0 release note. - LatinIME.java -> both sides. Kept the fork's SwipeGestureEngine initialize/cancelIndexing alongside upstream's new sInstance tracking and voice manager release. - SettingsValues.java, strings.xml -> both sides. Fork's flag-unknown-words and graduated-trust settings plus upstream's personal-dictionary learning threshold. - DictionaryFacilitatorImpl.kt -> both sides. Kept the fork's blacklist guard against auto-promotion and added upstream's auto-capitalization decapitalize handling for the word actually being added. - ClipboardHistoryManager.kt -> ours. Both sides define updateClipText with different signatures; the fork's returns the deleted entry so the caller can offer undo. - SuggestionStripView.kt -> both sides, with upstream's recycled-view restore cancellation ordered before the fork's uncurated-word dialog so it cannot be skipped by the early return. - ClipboardHistoryView.kt -> theirs per hunk. Upstream adds a clipboard edit mode; the fork side was only reformatting. - MainSettingsScreen.kt @Preview arity updated to the merged 15-parameter signature. Fork invariants verified after the merge: applicationId com.asafmah.leantypedual with its flavor suffixes, version 0.2.0/4200, INTERNET declared only in the standard and standardfull manifests, SwipeGestureEngine wired in LatinIME, the two-thumb module still registered in SettingsContainer, and a single InitializationProvider. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
Both were introduced by automatic conflict resolution and were caught by the fork's own tests, not by the compiler. 1. Whole-word backspace left partial words behind. Upstream 0cf92cf ("prevent single-click backspace from bulk deleting numeric sequences") split the end of the composing-word backspace branch on wasBatchMode: batch mode clears the composing span with commitText("", 1), everything else now calls finishComposingText() followed by deleteTextBeforeCursor(1). The fork's two-thumb whole-word delete also ends with no composing word, but it is not batch mode, so it fell into the new else branch. That is exactly the path its own comment warns against - deleteTextBeforeCursor does not remove the composing region and deletes committed text before it instead, which is the "This is pretty cool" -> "precool" corruption. Five tests caught it. Tracked with an explicit wholeWordDeleted flag so the whole-word and batch paths both clear the span, while upstream's numeric-sequence fix still applies to the ordinary last-character-removed path. 2. Custom layouts stopped restoring after symbol mode. Upstream added `lastCustomIndex = 0` when switching from symbols back to the alphabet. This fork ships persistent custom layout slots that are meant to survive symbol mode, orientation changes and keyboard reloads (0.1.0), and KeyboardStateTest asserts it. Dropped the upstream line. Test suite is back to the documented Windows baseline of 4 ParserTest failures, which pass on Linux CI. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
…edure The signed v0.2.0 release went out on 2026-08-20 with all four APKs, so the document's headline claim -- a single open task blocked on CI runners -- was wrong. Verified against the API before rewriting: the release is published, is marked latest, and carries four signed APKs; Release run 31128748928 succeeded on 2026-08-06 at 22:04 UTC. Section 5 keeps its recipe verbatim because it is still the correct procedure for the next release, but is now framed that way rather than as a blocker, with the outage signature retained so a recurrence is recognised instead of re-debugged. Also refreshes the stale dev SHA in section 1 (2c1c828 -> 6ac372d) and lists the real open items in section 12: device verification of #134 and #137, re-pointing check-upstream-main to v4.1.2, and reporting the emoji accelerated-delete bug upstream. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a6e8f983-22c2-4f2f-aacd-5316a5924a4d
Section 5 was still headed "THE OPEN TASK - publish signed v0.2.0", which is no longer true: v0.2.0 was published on 2026-08-20 with all four signed APKs and is marked latest. The runner outage that blocked it resolved on its own; Release run 31128748928 succeeded and produced the draft. Reframes section 5 from a blocker into the verified release procedure, since the recipe itself is still what the next release should follow, and keeps the outage signature so it is recognised rather than re-debugged. Also refreshes the TL;DR table (v0.2.0 published, current dev head, the four open PRs including #134, #136 and #137) and replaces section 12's "publish v0.2.0" item with the work that is actually outstanding: device verification of #134 and #137, re-pointing LeanType-check-upstream-main to v4.1.2 to re-check the two guarded upstream defects, reporting the emoji accelerated-delete bug upstream, and deciding the fate of the unfinished worktrees whose commits exist on no remote. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
…v4.1.2 Three statements written earlier in this PR went stale within the hour, so they are corrected before merge rather than shipped as fresh staleness: - Section 5 said the two runs stuck in queued could be cancelled; both have since been cancelled, so it now reads as history with the recovery command kept for a recurrence. - Section 11 said check-upstream-main was intentionally pinned at v4.0.8 and should be re-pointed by whoever merges next. It has already been moved to v4.1.2 for PR #137, so it is now described as tracking the tag currently being integrated. - Section 12 listed the re-pointing as an open item. The re-pointing is done; what remains is the re-check itself, which is in flight in #137 where the runTests guards live. Also adds a forward pointer in section 7 so its v4.0.8 reproductions are not read as the current state, and drops the stale cancel-the-zombies chore. Verified against the API before editing: both runs report cancelled, and the worktree HEAD resolves to tag v4.1.2. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a6e8f983-22c2-4f2f-aacd-5316a5924a4d
Both defects recorded in HANDOFF section 7 are fixed by this merge, so
their runTests skip guards are dead weight and were hiding two tests from
CI.
Verified twice rather than assumed:
- On a pristine upstream checkout re-pointed to v4.1.2,
SubtypeTest > subtypeStaysEnabledOnEdits passes (3 tests, 0 failures).
- In this merged tree, both subtypeStaysEnabledOnEdits and
immediateRegexExpansionTriggersForSymbolPrefixedRegex pass on the debug
variant, where the guards do not apply anyway.
Also fixes a latent test-harness bug: setText accepted a requireIdle
parameter and then called handleMessages() without it, so reset()'s
setText("", requireIdle = false) still asserted an idle message queue.
That was harmless until this merge changed JUnit's hash-based method
ordering, after which a different test preceded
"corpus - default mode char-by-char backspace" and left a delayed message
behind, failing it during setup rather than in its own logic.
Debug-variant baseline moves from 4 failures on origin/dev
(tapOnlyCombiningWordDoesNotShowAutospaceIndicatorWhenGestureGateEnabled,
insertLetterIntoWordHangulFails, the regex expansion defect, and the
subtype defect) to 1 - only the long-standing autospace-indicator test
still fails. testOfflineRunTestsUnitTest remains at the documented
4 ParserTest failures that pass on Linux CI.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
Section 7 claimed two tests fail on pristine upstream and are guarded with the runTests skip. Upstream v4.1.2 fixes both, and PR #137 removed the guards, so the section described a state that no longer exists. Verified from the raw JUnit XML rather than taken on report: - pristine v4.1.2 checkout, SubtypeTest = 3 tests / 0 failures, subtypeStaysEnabledOnEdits passing - merged tree, InputLogicTest = 125 tests / 1 failure, with immediateRegexExpansionTriggersForSymbolPrefixedRegex passing - commit e46454e on origin/merge/upstream-v4.1.2 removes exactly those two guards; the guards left elsewhere are unrelated (Linux-only ParserTest ordering, XLinkTest network, dictionary-dependent cases, emoji-data versioning) Section 7 is kept as history rather than deleted, because the reusable lesson is the technique: reproduce a merge failure on a pristine upstream checkout before blaming your own merge. Neither defect needs reporting upstream now, so section 12 keeps only the emoji accelerated-delete report. Section 6's known-failure list is split by baseline, since the merge moved it: 4 debug-variant failures on origin/dev versus 1 on the v4.1.2 branch, v4.1.2 having also fixed insertLetterIntoWordHangulFails. testOfflineRunTestsUnitTest is unchanged at the 4 ParserTest failures that pass on Linux CI. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a6e8f983-22c2-4f2f-aacd-5316a5924a4d
Section 6's closing failure list was inherited from the original handoff and carried forward here without being measured -- the exact staleness this PR exists to remove. Both baselines have now been run on the same Windows machine minutes apart: origin/dev 6ac372d 320 tests, 12 failed v4.1.2 merge branch 324 tests, 5 failed The old list was accurate for dev and wrong for the merge branch, so it is now presented as two measured baselines rather than one blanket claim, with the merge-branch set (autospace-indicator plus the same four ParserTest failures as the CI variant) called out as the current expectation. Attribution is deliberately split. The two section 7 defects and the Hangul case are safely merge-attributable: they are deterministic logic tests and were separately confirmed fixed on a pristine v4.1.2 checkout. XLinkTest makes real network calls and StringUtilsTest depends on bundled emoji-data, so their run-to-run difference is not by itself evidence the merge fixed them, and the document says so rather than claiming the win. Also links the emoji accelerated-delete report (LeanBitLab#423, still present at upstream f0ff166) so it is not filed twice. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a6e8f983-22c2-4f2f-aacd-5316a5924a4d
Splits the seven resolved failures by how confidently each can be credited to the merge, rather than lumping them. Both baselines were run on the same machine minutes apart, which controls for most environment drift but not for a live network call: XLinkTest > otherLinks hits Codeberg and can flip with no code change, so it is explicitly not counted as a fix. StringUtilsTest depends on bundled emoji-data that this merge does update, so it is marked plausible rather than confirmed. Also restates the closing rule around the actual hazard: 12 and 5 are both correct figures for different trees, so neither should be quoted without naming the tree. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a6e8f983-22c2-4f2f-aacd-5316a5924a4d
Section 11 warned that the six unfinished worktrees held commits on no remote ref and that the disk was their only copy. All six have since been pushed to origin as backups, verified: each local tip is in sync with its origin counterpart and git branch -r --contains now resolves for every one. Reframes the risk instead of dropping it, because the backup covers commits and not working trees. LeanType-b7a still has a modified InputLogic.java and LeanType-swipe a modified app/build.gradle.kts plus an untracked app/src/swipetest/, none of which any branch push captured; removing either worktree would still lose them. The other four are clean. Also drops the now-wrong no-tracking-branch note on feat/statistical-swipe-decoder, and rewrites the section 12 item so it reads as triage without a deadline rather than a race against disk failure. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a6e8f983-22c2-4f2f-aacd-5316a5924a4d
Section 6 buried the attribution reasoning in a paragraph and grouped ParserTest > backgroundType with the asset/locale-sensitive cases rather than with the other bundled-data ones. Restructures it as three labelled tiers so a reader can see at a glance which claims are load-bearing: attributable - the two section 7 defects and insertLetterIntoWordHangulFails plausible, unconfirmed - StringUtilsTest x2 and ParserTest > backgroundType not attributable - XLinkTest > otherLinks Also states the control precisely: same-machine, minutes-apart runs cover toolchain, locale and machine state, but not whether a remote host was reachable, which is why the network test is excluded rather than merely hedged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a6e8f983-22c2-4f2f-aacd-5316a5924a4d
Three false conclusions were drawn from Gradle test output in a single session, and none of them was flagged by the test run itself: - Gradle served results from an earlier run because the task was UP-TO-DATE, so a "passing" report described code that never executed. - An ad-hoc XML reader under-counted, reporting 4 failures where there were 12. Under-reporting is the dangerous direction: it looks like good news, and nothing contradicts it. - Failures were attributed to a code change when one of them reaches the network over HTTP and can flip with no code change at all. Each is a habit that has to be remembered, so each is now a check that runs whether or not anyone remembers. tools/check_test_results.py: - refuses to report if any result file predates the run (--started-after) - counts <testcase> elements AND sums the tests=/failures= attributes the suites declare, and refuses to report if the two disagree, so an under-counting reader cannot pass silently - diffs failing test NAMES against a checked-in baseline rather than comparing pass counts - quarantines tests marked `net:` in the baseline, which are reported but never counted as a regression or as an attributable fix Exit codes are distinct: 0 clean, 1 new failures, 2 untrustworthy results. Wired into the Unit tests workflow as the authoritative gate. The Gradle step becomes continue-on-error so the checker decides; it is strictly stronger than the exit code it replaces, since a green Gradle run over stale results now fails. The checker's own tests run in the same job. tools/tests/test_check_test_results.py covers each failure mode with fixtures, including a file holding several <testsuite> elements and one whose declared totals exceed what it lists. Verified against real output: on the results where the ad-hoc reader said 4 failures, the checker reports 320 tests / 12 failed, matching the totals the suites declare. Exit codes confirmed 2 / 0 / 1 for stale, clean, and new-failure runs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
The pycache directories were committed by mistake; ignore them instead. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
Device testing did not confirm the paragraph-merge theory this branch was originally built around, so the unverified behaviour change is parked on `feat/backspace-paragraph-keyevent` and only the provable fixes remain here. On a Samsung SM-S936B, on the unfixed build, both Microsoft Word and Samsung Notes merged paragraphs correctly in every flow tried: typed Enter then backspace, caret moved into the paragraph by tap, empty paragraphs, and a held backspace across the boundary. The premise that those editors ignore deleteSurroundingText across a block boundary is therefore not established, and routing '\n' deletion through KEYCODE_DEL is not justified on this evidence. What remains is independently correct: - The accelerated (held-backspace) second deletion measured its length from codePointBeforeCursor -- the code point read *before* the first deletion -- instead of codePointBeforeCursorToDeleteAgain. When the second character back is a multi-code-point emoji that picks the wrong length and can split it; in the opposite case it can over-delete. Present in upstream v4.1.2 as well, reported as LeanBitLab#423. - Two latent test-harness bugs. deleteSurroundingText did not clamp to the available text and drove selectionStart negative on an empty field. setText accepted a requireIdle parameter and then called handleMessages() without it, so reset() could not tolerate a leftover delayed message -- harmless until adding tests reshuffled JUnit's hash-based ordering, at which point it failed an unrelated test during setup rather than in its own logic. The fake InputConnection can still simulate a block-based editor (paragraph-scoped reads, cross-paragraph deletes that report success while doing nothing). The two tests that assert the parked behaviour are @ignore'd with the device findings recorded, so the hypothesis and the evidence against it stay together. Suite: 324 tests, 4 failed -- the documented Windows-only ParserTest baseline, confirmed with tools/check_test_results.py (#139). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
Merge upstream LeanBitLab/LeanType v4.1.2
docs(handoff): correct worktree paths after tree relocation; v0.2.0 is published
chore(tools): gate test-result analysis instead of trusting it
…paragraph-delete # Conflicts: # CHANGELOG.md
…delete fix(input): correct the accelerated backspace emoji measurement
Version 0.3.0, versionCode 4300 per the fork's offset formula (4000 + major*1000 + minor*100 + patch*10), keeping versionCode monotonic above 0.2.0's 4200 so Android upgrades continue to work. Contents are the LeanBitLab v4.1.2 merge (200 upstream commits from v4.0.9 onwards: clipboard edit mode, voice recognition language selector, personal-dictionary learning threshold, physical-keyboard suggestion shortcuts, localized settings), the two fork regressions that merge would otherwise have introduced, the accelerated-backspace emoji fix, and the test-result gate. Adds fastlane/metadata/android/en-US/changelogs/4300.txt and docs/releasenote/release_notes_v0.3.0.md, renames [Unreleased] to [0.3.0], and records the test-result gate which had not been added to the changelog when it merged. NOT tagged or published: the build has not had real use on a device yet, and device smoke is a release gate this project has never actually executed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
chore(release): prepare LeanTypeDual 0.3.0
Promotes dev to main for the 0.3.0 release. Records both parents but adopts dev's tree verbatim, per the documented promotion recipe: main carries release commits that were never merged back into dev, so a plain merge cannot be created cleanly. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88bd77f-d993-44c5-9efc-c7124f0d825e
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promotes
devtomainfor the 0.3.0 release.Uses the documented promotion recipe:
maincarries release commits that were never merged back intodev, plus files upstream deleted, so GitHub cannot create the merge cleanly. This commit records both parents but adoptsdev's tree verbatim (git read-tree -u --reset origin/dev).Verified:
git diff --stat origin/devis empty — the tree matchesdevexactly — and the commit has two parents.Contents are 0.3.0 / versionCode 4300: the LeanBitLab v4.1.2 merge (200 upstream commits), two fork regressions that merge would otherwise have introduced, the accelerated-backspace emoji fix, and the test-result gate. Signed APKs for this exact content were already built and verified from
chore/release-0.3.0.