From 79bdb0b9dabe12728fb8a3f4733d1b52b22bc829 Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:24:03 +0530 Subject: [PATCH 01/15] docs: add durable experiment and issue tracking --- docs/EXPERIMENT_LOG.md | 73 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 docs/EXPERIMENT_LOG.md diff --git a/docs/EXPERIMENT_LOG.md b/docs/EXPERIMENT_LOG.md new file mode 100644 index 0000000000..15ad880059 --- /dev/null +++ b/docs/EXPERIMENT_LOG.md @@ -0,0 +1,73 @@ +# brrrBoard Experiment & Fix History + +This file is the project's durable engineering ledger. + +**Rule:** every attempted bug fix, UI experiment, CI repair, rollback, or workaround that is not obvious from the final code should be recorded here, including failed attempts. Never delete a failed experiment; append the outcome instead. + +## Entry format + +- **Date / build:** YYYY-MM-DD / version or commit +- **Problem:** exact symptom +- **Hypothesis:** suspected root cause +- **Change attempted:** files/functions changed +- **Result:** PASS / FAIL / PARTIAL / REVERTED +- **Evidence:** CI run, APK SHA-256, device/model, logcat, screenshot, etc. +- **Next step:** what should be tried next + +## 2026-10-07 — CI / APK recovery audit + +- **Problem:** main had no active APK workflow; multiple temporary workflows had been created, patched, and then deleted during repeated CI repairs. +- **Hypothesis:** build/release infrastructure had become more fragile than the application code and could not reliably produce a current test APK. +- **Change attempted:** restore one canonical debug-build workflow with full checkout, JDK 17, Gradle setup, persistent debug signing, unit tests, APK verification, artifact upload, and GitHub release publication. +- **Result:** IN PROGRESS — this branch is the validation vehicle. +- **Evidence:** main's latest commits removed `brrrboard-ci-test.yml`, `brrrboard-release.yml`, `brrrboard-signing-bootstrap.yml`, `build-debug-apk.yml`, and `release-apk.yml` after repeated workflow repairs. +- **Next step:** keep the new workflow only if the build/test/signing verification passes. + +## 2026-10-07 — Debug versionCode collision hardening + +- **Problem:** debug `versionCode` used minute-resolution wall-clock time as its fallback. +- **Hypothesis:** two builds produced within the same minute can receive the same `versionCode`, causing Android update/install failures even when the APK is signed correctly. +- **Change attempted:** increase the fallback clock resolution from minutes to seconds while retaining the git-revision-count floor. +- **Result:** IN PROGRESS — requires CI build verification and device update verification. +- **Evidence:** `GitCommitCountValueSource` previously used `System.currentTimeMillis() / 60_000L`. +- **Next step:** install two successive debug APKs over the same package and verify that the second installs as an update without uninstalling. + +## 2026-10-05 — Debug settings crash + +- **Problem:** opening Debug settings crashed with a Compose nested-scroll measurement exception. +- **Root cause confirmed:** a `LazyColumn` was nested inside another vertically scrolling `LazyColumn`. +- **Fix:** render Debug settings directly in the parent `ColumnScope`; make filtering injectable. +- **Result:** FIXED. +- **Evidence:** commit `9c022e9977894c0d4e35b0451f07769843f3977d`. + +## 2026-10-05 — Klipy GIF search returned zero results + +- **Problem:** GIF searches such as cat/dog/hello returned no results. +- **Root cause confirmed:** GIF requests were filtered with `png`, although the GIF endpoint supports gif/webp/jpg/mp4/webm. +- **Fix:** use `gif,webp` for GIF searches while preserving `webp,gif,png` for stickers. +- **Result:** FIXED. +- **Evidence:** commit `65af63a1bd30c566ae2da432dd5916d1f0715be5`. + +## 2026-10-05 — In-keyboard search lifecycle / panel regressions + +- **Problem:** emoji/Klipy search panels could be destroyed or flicker during keyboard element switches. +- **Fix:** guard panel teardown, preserve search-mode state, add transition-state tracking, rebind search listeners/pointer trackers, and fix Klipy Compose lifecycle initialization. +- **Result:** FIXED in source; runtime verification still matters on physical devices. +- **Evidence:** commit `b08e9170dcc618b7a05d920b1b2cb2dfc49a5695`. + +## 2026-08-16 — Frosted Glass compatibility crashes + +- **Problem:** blur effects crashed on older Android versions and some non-bitmap drawable paths could fail. +- **Fix:** gate native blur to Android 12+, harden gradient drawable cropping, validate decoded background bitmaps, and add theme logging/fallbacks. +- **Result:** FIXED in source. +- **Evidence:** commit `4f2daef1d378e4b7ad9f8cd851dbabf3c5ad3b3`. + +## 2026-06-14 to 2026-06-25 — InputConnection / resize / blur stabilization + +- The project went through several related input-lag, cursor-query, resize-overlay, and native-blur fixes. +- **Important:** treat these as regression-sensitive areas; any change here should be accompanied by typing, cursor-movement, resize, and blur tests on a real device. +- **Evidence:** commits `a7dde8aea5d83e5c8a739b44b9e5f251dc624e9f`, `c967f4f891c873fdffa368fa99fd5974379b5724`, `f7b11443feb7a5457c955c6c0c539c18c5185d6d`, `7998fad4ebd8b0499d638c89d0e5ea5888dd2a05`. + +## How to record a failed experiment + +Use the template above even when the change is abandoned. A failed experiment is useful because it prevents repeating the same hypothesis without new evidence. \ No newline at end of file From 0f98638a5a1bf8f87cddf13118040ad7d16d6b27 Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:24:06 +0530 Subject: [PATCH 02/15] docs: add durable experiment and issue tracking --- docs/KNOWN_ISSUES.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 docs/KNOWN_ISSUES.md diff --git a/docs/KNOWN_ISSUES.md b/docs/KNOWN_ISSUES.md new file mode 100644 index 0000000000..83bb32f0df --- /dev/null +++ b/docs/KNOWN_ISSUES.md @@ -0,0 +1,24 @@ +# brrrBoard Known Issues & Audit Notes + +This is the current engineering watchlist. Items are not called fixed until there is evidence from tests or a real device. + +| Area | Status | Finding | +|---|---|---| +| APK CI | **Needs validation** | Main currently lacked an active canonical APK workflow after several workflow create/repair/delete cycles. | +| Debug APK updates | **Hardening applied** | Minute-resolution fallback `versionCode` could collide during rapid rebuilds; fallback was changed to seconds. | +| Runtime keyboard startup | **Needs device validation** | Static source inspection cannot prove IME startup/keyboard-popup behavior on a physical OEM build. | +| Search panels | **High regression sensitivity** | Emoji/Klipy search lifecycle and keyboard switching were recently rewritten; test enter/search/type/switch/exit repeatedly. | +| Frosted Glass | **High OEM sensitivity** | Native blur has Android/Samsung-specific fallback paths; test with blur on/off and Android 12+ plus older API behavior where supported. | +| Clipboard history | **Needs device validation** | Undo/restore and suggestion-dismissal logic was recently changed; test delete → undo, delete → paste, restart, and pinned entries. | +| Settings | **Recently fixed** | Debug settings nested-scroll crash was fixed; regression test the Debug screen and search filtering. | +| Klipy | **Recently fixed** | GIF format filter was corrected; test GIF and sticker search independently. | + +## Evidence standard + +1. **Build evidence:** CI passes tests and produces a non-empty APK. +2. **Install evidence:** APK installs successfully. +3. **Update evidence:** second APK updates the previous install without uninstalling. +4. **Runtime evidence:** affected feature is exercised on the target device. +5. **Regression evidence:** existing related tests still pass. + +Do not mark an issue as fixed solely because the source compiles. \ No newline at end of file From de00709b289e37b9de543321a9c05e700e53fb5b Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:24:10 +0530 Subject: [PATCH 03/15] fix(build): increase debug versionCode resolution to seconds --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a26e7e0f06..ec5b4b3cc9 100755 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -9,7 +9,7 @@ abstract class GitCommitCountValueSource : ValueSource Date: Wed, 7 Oct 2026 10:24:18 +0530 Subject: [PATCH 04/15] ci: restore canonical debug APK build and release --- .github/workflows/brrrboard-build-debug.yml | 107 ++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 .github/workflows/brrrboard-build-debug.yml diff --git a/.github/workflows/brrrboard-build-debug.yml b/.github/workflows/brrrboard-build-debug.yml new file mode 100644 index 0000000000..f5bd641970 --- /dev/null +++ b/.github/workflows/brrrboard-build-debug.yml @@ -0,0 +1,107 @@ +name: brrrBoard — Build Debug APK + +on: + push: + branches: + - main + - 'brrrboard-audit-*' + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: brrrBoard-debug-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 45 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Restore persistent debug signing key + shell: bash + run: | + set -euo pipefail + test -f .github/debug.keystore + mkdir -p "$HOME/.android" + cp .github/debug.keystore "$HOME/.android/debug.keystore" + chmod 600 "$HOME/.android/debug.keystore" + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: temurin + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Build and test + shell: bash + run: | + set -euo pipefail + chmod +x gradlew + ./gradlew --no-daemon --stacktrace testDebugUnitTest assembleDebug + + - name: Verify APK and signing identity + shell: bash + run: | + set -euo pipefail + APK="$(find app/build/outputs/apk/debug -maxdepth 1 -type f -name '*-debug.apk' | head -n 1)" + test -n "$APK" + test -s "$APK" + + APKSIGNER="$(find "$ANDROID_HOME/build-tools" -type f -name apksigner | sort -V | tail -n 1)" + CERT_OUTPUT="$("$APKSIGNER" verify --print-certs "$APK")" + printf '%s\n' "$CERT_OUTPUT" + + EXPECTED_CERT="$(keytool -list -v -keystore .github/debug.keystore -storepass android -alias androiddebugkey | sed -n 's/^.*SHA256:[[:space:]]*//p' | head -n 1 | tr -d ':' | tr '[:lower:]' '[:upper:]')" + ACTUAL_CERT="$(printf '%s\n' "$CERT_OUTPUT" | sed -n 's/^.*SHA-256 digest:[[:space:]]*//p' | head -n 1 | tr -d ':' | tr '[:lower:]' '[:upper:]')" + + test -n "$EXPECTED_CERT" + test -n "$ACTUAL_CERT" + test "$EXPECTED_CERT" = "$ACTUAL_CERT" + + SHA256="$(sha256sum "$APK" | cut -d' ' -f1)" + echo "APK=$APK" >> "$GITHUB_ENV" + echo "SHA256=$SHA256" >> "$GITHUB_ENV" + echo "APK_SIZE=$(stat -c '%s' "$APK")" >> "$GITHUB_ENV" + + echo "APK: $APK" + echo "SHA-256: $SHA256" + ls -lh "$APK" + + - name: Upload debug APK artifact + uses: actions/upload-artifact@v4 + with: + name: brrrBoard-debug-apk-${{ github.sha }} + path: ${{ env.APK }} + if-no-files-found: error + retention-days: 14 + + - name: Publish GitHub release + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + VERSION_NAME="$(sed -n 's/.*versionName = "\([^"]*\)".*/\1/p' app/build.gradle.kts | head -n 1)" + SHORT_SHA="${GITHUB_SHA::7}" + STAMP="$(date -u +'%Y%m%d-%H%M%S')" + + if [ "$GITHUB_REF_NAME" = "main" ]; then + TAG="brrrboard-debug-${STAMP}-${SHORT_SHA}" + TITLE="brrrBoard Debug — ${VERSION_NAME} — ${SHORT_SHA}" + gh release create "$TAG" "$APK" --repo "$GITHUB_REPOSITORY" --target "$GITHUB_SHA" --title "$TITLE" --notes "Verified debug APK. Commit: $GITHUB_SHA. SHA-256: $SHA256. Uses the persistent debug signing key so later debug builds can update the same debug installation." + else + TAG="brrrboard-test-${STAMP}-${SHORT_SHA}" + TITLE="brrrBoard Test Build — ${SHORT_SHA}" + gh release create "$TAG" "$APK" --repo "$GITHUB_REPOSITORY" --target "$GITHUB_SHA" --title "$TITLE" --notes "Audit/test build. Commit: $GITHUB_SHA. SHA-256: $SHA256." --prerelease + fi \ No newline at end of file From 9ae7da637bbb9a179f0fa2628654dc9cb40f2417 Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:28:35 +0530 Subject: [PATCH 05/15] ci: use JDK 21 for SDK 36 Robolectric tests --- .github/workflows/brrrboard-build-debug.yml | 4 ++-- docs/EXPERIMENT_LOG.md | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/brrrboard-build-debug.yml b/.github/workflows/brrrboard-build-debug.yml index f5bd641970..64723bfa0e 100644 --- a/.github/workflows/brrrboard-build-debug.yml +++ b/.github/workflows/brrrboard-build-debug.yml @@ -34,10 +34,10 @@ jobs: cp .github/debug.keystore "$HOME/.android/debug.keystore" chmod 600 "$HOME/.android/debug.keystore" - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: temurin - name: Set up Gradle diff --git a/docs/EXPERIMENT_LOG.md b/docs/EXPERIMENT_LOG.md index 15ad880059..69893aa05c 100644 --- a/docs/EXPERIMENT_LOG.md +++ b/docs/EXPERIMENT_LOG.md @@ -70,4 +70,13 @@ This file is the project's durable engineering ledger. ## How to record a failed experiment -Use the template above even when the change is abandoned. A failed experiment is useful because it prevents repeating the same hypothesis without new evidence. \ No newline at end of file +Use the template above even when the change is abandoned. A failed experiment is useful because it prevents repeating the same hypothesis without new evidence. + +## 2026-10-07 — CI unit-test environment failure (JDK 17 vs Android SDK 36) + +- **Problem:** the canonical build reached `:app:testDebugUnitTest` but 10/17 tests failed before test bodies ran. +- **Root cause confirmed:** Robolectric's SDK 36 support requires Java 21; the workflow was installing Java 17. The failures all surfaced as `UnsupportedOperationException` from `DefaultSdkProvider.java:170`. +- **Change attempted:** first workflow revision intentionally used JDK 17 because the project compiles source/target at Java 17; CI exposed the separate Robolectric runtime requirement. +- **Result:** FAIL — this was a CI/toolchain configuration bug, not evidence that those ten tests are functionally broken. +- **Evidence:** GitHub Actions run `37573697017`; 17 tests completed, 10 failed; failed classes included ParserTest, SubtypeTest, XLinkTest, SparkleDustViewTest, ClipboardImageHistoryClipTest, InputLogicTest, StringUtilsTest, SuggestTest, KlipyHistoryDaoTest, and ToolbarUtilsTest. All reported `UnsupportedOperationException at DefaultSdkProvider.java:170`. +- **Next step:** rerun the complete build with JDK 21; keep Java/Kotlin source compatibility at 17 unless the compiler itself requires a change. From f1f43893b7d44847b8ef0bbf14c48e3192d70e59 Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:28:49 +0530 Subject: [PATCH 06/15] ci: document Robolectric JDK 21 requirement --- .github/workflows/brrrboard-build-debug.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/brrrboard-build-debug.yml b/.github/workflows/brrrboard-build-debug.yml index 64723bfa0e..a65d431ddf 100644 --- a/.github/workflows/brrrboard-build-debug.yml +++ b/.github/workflows/brrrboard-build-debug.yml @@ -37,7 +37,7 @@ jobs: - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: '21' + java-version: '21' # Robolectric SDK 36 requires JDK 21 distribution: temurin - name: Set up Gradle From 00932e75dcb9023bb1624261169fdde4d8e4194e Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:35:43 +0530 Subject: [PATCH 07/15] ci: use intended runTests variant --- .github/workflows/brrrboard-build-debug.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/brrrboard-build-debug.yml b/.github/workflows/brrrboard-build-debug.yml index a65d431ddf..e5b5bf8e0e 100644 --- a/.github/workflows/brrrboard-build-debug.yml +++ b/.github/workflows/brrrboard-build-debug.yml @@ -48,7 +48,7 @@ jobs: run: | set -euo pipefail chmod +x gradlew - ./gradlew --no-daemon --stacktrace testDebugUnitTest assembleDebug + ./gradlew --no-daemon --stacktrace testRunTests assembleDebug - name: Verify APK and signing identity shell: bash From d4007ca26e8df9f40aeaafe0baf88833b6807ce9 Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:42:29 +0530 Subject: [PATCH 08/15] fix(subtypes): clear cached resource subtypes on reload --- .../main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt index 7d1fce4fd8..ffb5592e39 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt @@ -235,6 +235,7 @@ object SubtypeSettings { } private fun loadResourceSubtypes(resources: Resources) { + resourceSubtypesByLocale.clear() getResourceSubtypes(resources).forEach { resourceSubtypesByLocale.getOrPut(it.locale()) { ArrayList(2) }.add(it) } From 55887ac8667e9f54261a42523f49c9484da18a19 Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:42:32 +0530 Subject: [PATCH 09/15] test(subtypes): isolate enabled subtype preferences --- app/src/test/java/helium314/keyboard/SubtypeTest.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/test/java/helium314/keyboard/SubtypeTest.kt b/app/src/test/java/helium314/keyboard/SubtypeTest.kt index 1b3ac8f433..c5b53af803 100644 --- a/app/src/test/java/helium314/keyboard/SubtypeTest.kt +++ b/app/src/test/java/helium314/keyboard/SubtypeTest.kt @@ -59,7 +59,11 @@ class SubtypeTest { @Test fun subtypeStaysEnabledOnEdits() { val prefs = latinIME.prefs() - prefs.edit().putString(Settings.PREF_ADDITIONAL_SUBTYPES, "").apply() // clear it for convenience + prefs.edit() + .putString(Settings.PREF_ADDITIONAL_SUBTYPES, "") + .putString(Settings.PREF_ENABLED_SUBTYPES, "") + .putString(Settings.PREF_SELECTED_SUBTYPE, "") + .apply() // edit enabled resource subtype val from = SubtypeSettings.getResourceSubtypesForLocale("es".constructLocale()).first() From c4c7044bab217a9f3db05663958d27611ca85bba Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:42:37 +0530 Subject: [PATCH 10/15] test(emoji): report exact unsupported asset in CI --- app/src/test/java/helium314/keyboard/latin/StringUtilsTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/test/java/helium314/keyboard/latin/StringUtilsTest.kt b/app/src/test/java/helium314/keyboard/latin/StringUtilsTest.kt index 6d49547803..7c4a08da32 100644 --- a/app/src/test/java/helium314/keyboard/latin/StringUtilsTest.kt +++ b/app/src/test/java/helium314/keyboard/latin/StringUtilsTest.kt @@ -24,6 +24,7 @@ import org.robolectric.annotation.Config import kotlin.system.measureTimeMillis import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertTrue // todo: actually this test could/should be significantly expanded... @RunWith(RobolectricTestRunner::class) @@ -205,7 +206,7 @@ class StringUtilsTest { val brokenDetectionAtStart = listOf("〰️", "〽️", "©️", "®️", "#️⃣", "*️⃣", "0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "㊗️", "㊙️") allEmojis.forEach { if (it == "🀄" || it == "🃏") return@forEach // todo: should be fixed, ideally in the regex - assert(isEmoji(it)) + assertTrue(isEmoji(it), "isEmoji=false for [$it] codePoints=${it.codePoints().toArray().joinToString(","){ "U+" + it.toString(16).uppercase() }}") assert(StringUtils.mightBeEmoji(it.codePointBefore(it.length))) if (it !in brokenDetectionAtStart) assert(StringUtils.mightBeEmoji(it.codePointAt(0))) From 8e4f60e98b8296fecaf3d24f680005804b807fd7 Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:45:18 +0530 Subject: [PATCH 11/15] ci: decouple APK delivery from unit-test gate --- .github/workflows/brrrboard-build-debug.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/brrrboard-build-debug.yml b/.github/workflows/brrrboard-build-debug.yml index e5b5bf8e0e..da7e742301 100644 --- a/.github/workflows/brrrboard-build-debug.yml +++ b/.github/workflows/brrrboard-build-debug.yml @@ -43,12 +43,12 @@ jobs: - name: Set up Gradle uses: gradle/actions/setup-gradle@v4 - - name: Build and test + - name: Build debug APK shell: bash run: | set -euo pipefail chmod +x gradlew - ./gradlew --no-daemon --stacktrace testRunTests assembleDebug + ./gradlew --no-daemon --stacktrace assembleDebug - name: Verify APK and signing identity shell: bash @@ -86,7 +86,23 @@ jobs: if-no-files-found: error retention-days: 14 + - name: Run unit tests + id: unit_tests + continue-on-error: true + shell: bash + run: | + set -euo pipefail + ./gradlew --no-daemon --stacktrace testRunTests + + - name: Fail workflow when tests fail + if: steps.unit_tests.outcome == 'failure' + shell: bash + run: | + echo "Unit tests failed; APK was still built, verified, and published for audit/testing." + exit 1 + - name: Publish GitHub release + if: github.ref_name != 'main' || steps.unit_tests.outcome == 'success' env: GH_TOKEN: ${{ github.token }} shell: bash From fddeb1a03a83b5bbaa13156f2df4f15e7bf105b3 Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:45:57 +0530 Subject: [PATCH 12/15] ci: add independent audit APK delivery workflow --- .github/workflows/brrrboard-apk-only.yml | 84 ++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 .github/workflows/brrrboard-apk-only.yml diff --git a/.github/workflows/brrrboard-apk-only.yml b/.github/workflows/brrrboard-apk-only.yml new file mode 100644 index 0000000000..0a61985022 --- /dev/null +++ b/.github/workflows/brrrboard-apk-only.yml @@ -0,0 +1,84 @@ +name: brrrBoard — APK Only (Audit) + +on: + push: + branches: + - 'brrrboard-audit-*' + +permissions: + contents: write + +jobs: + apk: + runs-on: ubuntu-latest + timeout-minutes: 25 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Restore persistent debug signing key + shell: bash + run: | + set -euo pipefail + test -f .github/debug.keystore + mkdir -p "$HOME/.android" + cp .github/debug.keystore "$HOME/.android/debug.keystore" + chmod 600 "$HOME/.android/debug.keystore" + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: temurin + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Build debug APK + shell: bash + run: | + set -euo pipefail + chmod +x gradlew + ./gradlew --no-daemon --stacktrace assembleDebug + + - name: Verify APK and signing identity + shell: bash + run: | + set -euo pipefail + APK="$(find app/build/outputs/apk/debug -maxdepth 1 -type f -name '*-debug.apk' | head -n 1)" + test -n "$APK" + test -s "$APK" + APKSIGNER="$(find "$ANDROID_HOME/build-tools" -type f -name apksigner | sort -V | tail -n 1)" + CERT_OUTPUT="$("$APKSIGNER" verify --print-certs "$APK")" + EXPECTED_CERT="$(keytool -list -v -keystore .github/debug.keystore -storepass android -alias androiddebugkey | sed -n 's/^.*SHA256:[[:space:]]*//p' | head -n 1 | tr -d ':' | tr '[:lower:]' '[:upper:]')" + ACTUAL_CERT="$(printf '%s\n' "$CERT_OUTPUT" | sed -n 's/^.*SHA-256 digest:[[:space:]]*//p' | head -n 1 | tr -d ':' | tr '[:lower:]' '[:upper:]')" + test -n "$EXPECTED_CERT" + test -n "$ACTUAL_CERT" + test "$EXPECTED_CERT" = "$ACTUAL_CERT" + SHA256="$(sha256sum "$APK" | cut -d' ' -f1)" + echo "APK=$APK" >> "$GITHUB_ENV" + echo "SHA256=$SHA256" >> "$GITHUB_ENV" + echo "APK_SIZE=$(stat -c '%s' "$APK")" >> "$GITHUB_ENV" + echo "APK: $APK" + echo "SHA-256: $SHA256" + + - name: Upload APK artifact + uses: actions/upload-artifact@v4 + with: + name: brrrBoard-debug-apk-${{ github.sha }} + path: ${{ env.APK }} + if-no-files-found: error + retention-days: 14 + + - name: Publish audit release + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + SHORT_SHA="${GITHUB_SHA::7}" + STAMP="$(date -u +'%Y%m%d-%H%M%S')" + TAG="brrrboard-audit-${STAMP}-${SHORT_SHA}" + gh release create "$TAG" "$APK" --repo "$GITHUB_REPOSITORY" --target "$GITHUB_SHA" --title "brrrBoard Audit APK — ${SHORT_SHA}" --notes "APK-only audit build. Commit: $GITHUB_SHA. SHA-256: $SHA256. Built with the tracked persistent debug signing key." --prerelease \ No newline at end of file From 1bb2a38ef6c6af915cd3692888669128752f2724 Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:46:10 +0530 Subject: [PATCH 13/15] ci: trigger independent audit APK workflow --- .github/workflows/brrrboard-apk-only.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/brrrboard-apk-only.yml b/.github/workflows/brrrboard-apk-only.yml index 0a61985022..8a895ac508 100644 --- a/.github/workflows/brrrboard-apk-only.yml +++ b/.github/workflows/brrrboard-apk-only.yml @@ -1,4 +1,4 @@ -name: brrrBoard — APK Only (Audit) +name: brrrBoard — APK Only (Audit) # independent APK delivery path on: push: From f29182aefceaa256e4808dad0aac2e4d0e9765c6 Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:50:00 +0530 Subject: [PATCH 14/15] docs: record APK delivery and regression audit results --- docs/EXPERIMENT_LOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/EXPERIMENT_LOG.md b/docs/EXPERIMENT_LOG.md index 69893aa05c..cc624be3f2 100644 --- a/docs/EXPERIMENT_LOG.md +++ b/docs/EXPERIMENT_LOG.md @@ -80,3 +80,29 @@ Use the template above even when the change is abandoned. A failed experiment is - **Result:** FAIL — this was a CI/toolchain configuration bug, not evidence that those ten tests are functionally broken. - **Evidence:** GitHub Actions run `37573697017`; 17 tests completed, 10 failed; failed classes included ParserTest, SubtypeTest, XLinkTest, SparkleDustViewTest, ClipboardImageHistoryClipTest, InputLogicTest, StringUtilsTest, SuggestTest, KlipyHistoryDaoTest, and ToolbarUtilsTest. All reported `UnsupportedOperationException at DefaultSdkProvider.java:170`. - **Next step:** rerun the complete build with JDK 21; keep Java/Kotlin source compatibility at 17 unless the compiler itself requires a change. + + +## 2026-10-07 — APK-only delivery validation + +- **Problem:** the normal workflow was blocked by the unit-test gate and GitHub Actions became congested by an in-progress run. +- **Change:** added `.github/workflows/brrrboard-apk-only.yml` so APK packaging/signing/upload is independently verifiable and not blocked by tests. +- **Result:** APK **BUILD + SIGNING + ARTIFACT UPLOAD PASS**; GitHub Release publication failed only because the Actions integration received HTTP 403 for the Releases endpoint. +- **Evidence:** workflow run `37575456832`; APK `FrostKeys_2.5.8-debug.apk`; SHA-256 `1b594eff45b0f9b41c290e4c234cd3a77f46229565de70a07d53d6c66ae9873a`. +- **Next step:** test this APK on the target phone; keep release publication separate until repository Actions permissions allow Releases. + +## 2026-10-07 — Subtype cache/test-state investigation + +- **Problem:** `SubtypeTest` failed with `IllegalArgumentException` from `.single()` when resource/enabled subtype collections contained more than one entry. +- **Change:** clear `resourceSubtypesByLocale` before rebuilding resource subtype caches; isolate enabled/selected subtype preferences in the test. +- **Result:** APK compiles with the changes; the full regression workflow has not yet completed after these changes, so this is **PROVISIONAL**, not marked fully fixed. + +## 2026-10-07 — Emoji detector diagnostic + +- **Problem:** `StringUtilsTest.isEmojiDetectsAllAvailableEmojis` still failed under `testRunTests`. +- **Change:** replaced the silent JVM assertion with an assertion that prints the exact failing emoji and code points. +- **Result:** diagnostic patch committed; final detector correction awaits the next successful test run. + +## 2026-10-07 — CI workflow permission finding + +- **Problem:** `gh release create` returned HTTP 403 `Resource not accessible by integration` even though the workflow has `contents: write`. +- **Result:** GitHub Actions artifact upload works; Release API publication is currently blocked by the connected integration's permissions. \ No newline at end of file From 52cbc558b8d518d54dc8a7fcbf0caa4b63b6b1d8 Mon Sep 17 00:00:00 2001 From: Batmancpu Date: Wed, 7 Oct 2026 10:50:16 +0530 Subject: [PATCH 15/15] docs: refresh audit watchlist and APK CI status --- docs/KNOWN_ISSUES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/KNOWN_ISSUES.md b/docs/KNOWN_ISSUES.md index 83bb32f0df..6e0f82e17f 100644 --- a/docs/KNOWN_ISSUES.md +++ b/docs/KNOWN_ISSUES.md @@ -4,8 +4,8 @@ This is the current engineering watchlist. Items are not called fixed until ther | Area | Status | Finding | |---|---|---| -| APK CI | **Needs validation** | Main currently lacked an active canonical APK workflow after several workflow create/repair/delete cycles. | -| Debug APK updates | **Hardening applied** | Minute-resolution fallback `versionCode` could collide during rapid rebuilds; fallback was changed to seconds. | +| APK CI | **Partially recovered** | Canonical build workflow restored; independent audit APK workflow now builds, signs and uploads successfully. GitHub Release API publication is blocked by HTTP 403. | +| Debug APK updates | **Needs device validation** | Fallback `versionCode` now uses seconds rather than minutes; APK signing identity is persistent across debug builds. Device update without uninstall remains to be tested. | | Runtime keyboard startup | **Needs device validation** | Static source inspection cannot prove IME startup/keyboard-popup behavior on a physical OEM build. | | Search panels | **High regression sensitivity** | Emoji/Klipy search lifecycle and keyboard switching were recently rewritten; test enter/search/type/switch/exit repeatedly. | | Frosted Glass | **High OEM sensitivity** | Native blur has Android/Samsung-specific fallback paths; test with blur on/off and Android 12+ plus older API behavior where supported. |