ADFA-5368 refactor(identity): publish under org.appdevforall.k2go - #517
Merged
Conversation
Records the decision to publish under org.appdevforall.k2go, the recon behind it, and what it costs. The identifier is a namespace claim; this is an administrative decision rather than a technical necessity, recorded because -- unlike most naming -- it cannot be undone once devices are in the field. The measured part: Android offers no migration between application IDs and a device carries 2.9 GB of installed rootfs, so the cost is (devices) x (a full reinstall). Fewer than ten today, and only ever more. Includes the verification matrix and the boundary this is not: the rename removes no IIAB attribution anywhere.
Mechanical rename of applicationId and namespace, per ADR-5368. 529 source files move from org/iiab/controller to org/appdevforall/k2go, and the compiler is the verifier -- 1637 reference points are not reviewable by eye. Deliberately left alone: the 42 intent-action literals, which are unique-by- convention strings rather than identity and keep working untouched. The manifest's deprecated package= attribute is deleted rather than updated, since AGP takes the namespace from Gradle. The lint baseline has its file paths rewritten rather than regenerated, so the recorded issue set stays exactly what it was instead of silently absorbing whatever lint finds today. Also corrects build.gradle's instrumentation-runner reference, which is printed in a message and would have handed a reader the wrong adb command. Device-verified: a clean install under the new identifier downloads, extracts and boots to HTTP 200.
Two claims in the ADR were wrong, and the runs that found them also changed the changeover plan. Backups are not private: "Make a copy" opens the system document picker and the archive lands in shared storage, so an export/import bridge between identifiers is feasible after all. It still is not worth building -- the round trip needs room for two copies of the library and a human at each device either way -- but the reason is arithmetic, not plumbing. Cloning is the cheap path, and it reshapes the changeover: 4.6 GB moves between two devices over a local hotspot in about six minutes, so the fleet downloads once and clones the rest instead of downloading per device. Adds the result section. Every check passed on device across three Android generations except FileProvider, which stayed structural only because the update server had no newer build to offer. The intent-action literals the rename left alone are now observed inert rather than argued so -- backup, dashboard rebuild and the stop/start cycle all run on the old-named actions.
The updater's install path could not be reached -- the update server had no newer build to offer -- so the FileProvider authority was left confirmed only by inspection. Rebuilding against a local update server would have verified a binary other than the one being merged, so the same mechanism was reached through a door the app already has: the clone screen's "can't scan" fallback runs getUriForFile with the identical call, authority and file class as the updater. The share sheet opened with the APK attached, which a mismatched authority would have prevented by throwing first. Every check in the matrix now passed on device. Firebase remains outstanding and is not an engineering step.
…efactor/ADFA-5368-app-identifier ADFA-5368 merge: main into the identifier rename Nine files conflicted, all with the same shape: main refactored them (ADFA-5339 dashboard update, ADFA-5364 content-admission collapse) while this branch only renamed their package. Verified per file that our side carried no semantic change, then took main's version and reapplied the rename. DashboardCardStateTest arrived at the old package path as a new file and was moved. Tests and lint green.
Section 9 said installing both apps merely stranded 2.9 GB. Device testing showed the second app does not work: liveness is a probe of a fixed loopback port that carries no identity, while the process half of the same question matches our own rootfs path, and the answering services win — so an app whose own box is down reads UP off the other app's server. The old identifier counted the new one's box as its own and deadlocked its install. That makes "uninstall first" a functional requirement rather than hygiene.
…p-identifier main brought K2GO-372 (restore progress, early rejection, disk check) written against the old package. Rename detection carried it onto the new paths; the conflicting hunks were all the same shape — this branch held the pre-K2GO-372 code with renamed packages — so main's side wins throughout. RootfsIdentity and its test arrived as new files inside a renamed directory and moved with their package line. Intent action literals are left as they are, matching this branch's rule of renaming code references only.
…p-identifier main brought K2GO-95: RebuildPhase and RebuildProgress resolve a determinate rebuild bar, and DashboardDetailFragment drives it. The three new files landed in the old dashboard/domain path; that package already exists renamed on this branch, so rename detection placed them correctly and only their package line needed fixing. The only content conflict was the import block the two new domain types were added to.
…p-identifier main brought K2GO-374: a reusable LiveLogPanel, with the module-install and maps logs migrated onto it. Its package is new, so rename detection had nothing to follow and git placed the three new files under the old package with no conflict at all — they had to be moved by hand. LiveLogPanel is a custom view, so the two layouts name it by fully-qualified class: that reference is invisible to the compiler and would only fail when the screen inflates, which is a resource surface this rename had not had until now.
…o the new package The K2GO-374 merge brought DashboardDetailFragment's LiveLogPanel migration in without a conflict, so its two references to the old package came along unmarked and the branch did not compile.
…t the rootfs at its bucket The host was spelled out at eight call sites — four for the rootfs store, four for the APK repo — so moving either meant finding them all, and one lived inside a shell script this app generates as text, where a missed edit is invisible to the compiler. config/DownloadEndpoints owns them now, with the two buckets as separate named constants: they have different names and different lifecycles, and collapsing them would make the next move a search-and-replace again. The rootfs store moves to the k2go-rootfs bucket, which serves from its root (the old host kept an /android/rootfs path; only the static proot-distro base is in a folder). The builder and the two preBuild size tasks follow. The workflow published metalinks naming k2go-download.appdevforall.org/rootfs, a path-based route that was never created: the .meta4 resolved and then the tarball 404'd, with no mirror left to fall back to. Its default now names the bucket that actually holds the artifacts.
main brought the bucket migration: the rootfs artifacts renamed to k2go_, the APK workflows repointed at k2go-apk-repo, the two remaining Node 20 actions, and the transitional sweep landing and then leaving. The only conflict was ROOTFS_PUBLIC_BASE, where the same fix had arrived from both sides — resolved on main's ticket key with this branch's comment, which describes the bucket that exists rather than the path-based route that was never created.
These files are downloaded by people from a public bucket, so they carry the product's name: K2Go-v0.8.0-beta-v8a-release.apk instead of org.appdevforall.k2go-v0.8.0-beta-arm64-v8a-release.apk. The identifier still lives inside the APK, where it belongs. The split's ABI is abbreviated in the same block that already overrides the version code per output, so one place owns the outputs. archivesBaseName cannot do that part: Gradle names outputs after the split. The release manifest finds each APK by filename, so its three patterns move with the rename, now anchored on hyphens — a bare "v8a" would one day match a version string and publish a manifest pointing at the wrong architecture, silently.
The version name carried the branch's Jira key (ADFA-4810), which the project-key move left behind: a K2GO branch no longer matches the ADFA-only pattern and falls through to a slug truncated mid-word — "chore-K2GO-377-d", "fix-K2GO-377-roo". App Distribution already shows the full branch under each build, so the label restated it, and worse. The short SHA stays: it pins the exact commit, which is the one thing the branch name does not.
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.
What
Moves the
applicationIdand the Java namespace fromorg.iiab.controllertoorg.appdevforall.k2go, per ADR-5368. 529 source files move for the rename itself; the compiler isthe verifier. (The full diff is larger — see What else travels with it below.)
Why
The identifier is a reverse-DNS namespace claim — it declares which organisation publishes the app.
android:labelhas said "Knowledge to Go" for a long time; only the technical identifier still saysorg.iiab. This is an administrative decision, not a technical necessity.It is done now because it cannot be done later: Android offers no migration between application
IDs, and a device carries 2.9 GB of installed rootfs, so the cost is (devices in the field) × (a
full reinstall). Fewer than ten today.
What the change contains
applicationId+namespaceinbuild.gradle; 529 files moved toorg/appdevforall/k2go.package=attribute is deleted, not updated — AGP takes thenamespace from Gradle.
set stays exactly what it was instead of silently absorbing whatever lint finds today.
build.gradle's instrumentation-runner reference is corrected; it is printed in a message andwould have handed a reader the wrong
adbcommand.What else travels with it
Four changes landed on this branch after the rename itself, each because it is the same fact
changing:
the rootfs store, four for the APK repo — one of them inside a shell script the app generates as
text, where a missed edit is invisible to the compiler.
config/DownloadEndpointsowns them now,with the two buckets as separate named constants: they have different names and different
lifecycles, and collapsing them would make the next move a search-and-replace again.
K2Go-v0.8.0-beta-v8a-release.apk.The identifier still lives inside the APK, where it belongs. The release manifest finds each APK
by filename, so its three patterns move with the rename.
under every build; the key restated it, and after the project-key move it degraded to a slug
truncated mid-word ("chore-K2GO-377-d"). The short SHA stays — it pins the commit, which is the
one thing the branch name does not.
while still carrying old-package references.
Deliberately left alone
The 42
"org.iiab.controller.SOME_ACTION"intent-action literals. They are unique-by-conventionstrings, not identity, and renaming them is a safe optional follow-up. See check 13 — this is now
observed, not argued.
tools/proot-builder/build_static.shreferencesdata/data/com.termux/…: that is the Termux buildcontainer, not this app. Touching it would break the native-binary build.
Verification — did the change happen
/data/app/org.appdevforall.k2go-…/base.apkarchive/package=removedassembleReleaseon this branch built and signed under the new identityVerification — nothing else changed
Run on two devices: API 28 / kernel 3.18 and API 36 / kernel 6.12.
iiabCLItools/untouchedcom.termuxpaths intactA note on check 10, since it was the one that resisted. The updater's install path could not be
reached: the update server had no newer build to offer, which left the FileProvider authority
confirmed only by inspection. Rebuilding the app against a local update server would have verified a
binary other than the one being merged, so the same mechanism was reached through a door the app
already has — the clone screen's "can't scan the QR code" fallback runs
getUriForFile(ctx, getPackageName() + ".provider", apk)on the installed APK, the identical call,authority and file class as the updater. The share sheet opened with the APK attached; a mismatched
authority would have thrown before it ever appeared.
provider_paths.xmlalso names no packageanywhere, so the rename cannot move a file outside a configured root.
Incidental but reassuring: ADFA-5343's holder mechanism behaved throughout —
holder=INSTALL,holder=DASHBOARD,holder=BACKUP— standing down and releasing cleanly each time.Changeover
a new app, not an update. It is installed by hand.
is answered by probing a fixed loopback port that carries no identity, while the process half of
the same question matches our own rootfs path — so an app whose own box is down reads UP off the
other app's server. Observed on device: the old identifier counted the new one's server as its own
and its install deadlocked. The runbook is uninstall first, and §9 says why. Leaving the old
app also strands its 2.9 GB.
library between two devices in about six minutes.
is reasoned, not observed.
Known gap, tracked separately
Distribution to internal testers is currently failing on a permissions issue that follows from the
new identifier. It is being handled outside this PR and does not affect the release pipeline: that
workflow has no distribution step, and its
assembleReleaseon this branch is what verifiescheck 6.
No server change, no new strings, no UI change.