Release 1.9.1 - #115
Closed
projectdelta6 wants to merge 15 commits into
Closed
Release 1.9.1#115projectdelta6 wants to merge 15 commits into
projectdelta6 wants to merge 15 commits into
Conversation
Central enforces per-month file count, release size and release count from 1 October 2026. One toolbox release is 508 files — about half the monthly file allowance — because 26 modules each carry a full jar/sources/javadoc/pom/module set with signatures and checksums. That, not release count, is our binding constraint: a second release in the same calendar month barely fits and a third cannot. Two things worth writing down before someone reaches the wrong conclusion under time pressure. Same-month point releases need batching, since an August-style 1.8.0 -> 1.8.3 flurry would be over twice the allowance. And splitting the toolbox into separately-published repositories to shrink our footprint would do the opposite: Central scores a multi-module bundle as one release event, so 26 repositories would be 26 events per version, past the limit of 7 immediately. Cross-referenced from "Why one version for all modules", which recommended splitting a module out without noting that cost. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Draft PRs cannot be merged, so the tests-and-coverage job now skips them rather than spending runner minutes. On its own that guard would silently strand any PR opened as a draft: `ready_for_review` is not in the default event type set, so marking such a PR ready fired no event at all and CI would never report on it. Adding the type alongside the guard is what makes the pairing safe. The `event_name` check keeps pushes to main running — on push there is no `event.pull_request`, and a null never equals false in GitHub expressions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sonatype granted uk.co.appoly.droid an OSS exemption, so the commercial-nature classification — which applies regardless of publishing volume and would otherwise require Publisher Pro — does not apply to us. The same response declined to raise the file-count ceiling in substance. It was framed as "enhanced monthly publishing limits" of 7 releases / 80 MB / 1000 files, which is exactly what the Usage Center already showed before the request, sized to a publishing history of a single release. So the earlier note's numbers came from the published defaults rather than our real limits: the file ceiling is 1,000, not ~1,167, and the one-release-per-calendar-month conclusion stands. Recorded because that reply reads as a win on both counts and is easy to mistake for headroom we do not have. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A patch-level move inside the same 2.4 language version, so the metadata version is unchanged and no consumer that resolves 1.9.0 today is affected. The consumer-visible kotlin-stdlib floor moves to 2.4.20, which the dependency graph was already forcing up from 2.1.21 and 2.2.21 transitives. Nothing else needed pinning: the Compose compiler and serialization plugins are version.ref'd to `kotlin` and moved in lockstep, and KSP2's versioning is decoupled from Kotlin, so the 2.3.11 pin still applies across the ten modules that use it plus Room in :app. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Version-only for production code. Every breaking change in beta01 and alpha07 is in the deep-link API — DeepLinkRequest.extras becoming RequestExtras, the factory function removals, DeepLinkMatcher gaining a type parameter — and this module imports no DeepLink* symbol. Two beta01 items did reach us. The new lint requiring Scene implementations to be data classes or implement equals/hashCode is already satisfied: TabsScene implements both explicitly. The contentKey change is the reason for the test edit below. NavEntry.contentKey now defaults to a composite of `key.toString()` and `key::class.toString()`, so the assertion pinning it to DetailScreen(5).toString() failed. Dropped rather than updated to the new format: the preceding assertion already compares contentKey to contentKey, and the backStack assertion above pins that the entry is DetailScreen(5), so identity stays covered without re-arming the same trap on the next release. Asserting on NavEntry.key instead is not an option — it is private in beta01. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Navigator API examples told consumers to wrap the host in a BackHandler that pops when `canPop` and otherwise switches tab. That duplicates `TabsNav3Navigator.pop()`, which `Nav3TabsHost` already wires into `NavDisplay.onBack`, and it intercepts the gesture before NavDisplay sees it, so `predictivePopTransitionSpec` never scrubs — losing the native predictive back this module exists to provide. It also hardcoded HomeTab where `startTab` is configurable and may sit mid-strip. Replaced with a "System back" section documenting the built-in path. Exiting the app needs no handler either: at the start-tab root `canPop` is false and Nav3 disables its back callback, so back falls through to the Activity even though retained tabs keep `backStack.size > 1` — asserted by Nav3PredictiveBackDeviceTest. Genuine per-screen interception now points at NavigationBackHandler from androidx.navigationevent, which arrives transitively via navigation3-ui, shares NavDisplay's dispatcher, and unlike BackHandler exposes gesture progress and cancellation. Also documents the API 33-35 `enableOnBackInvokedCallback` opt-in. It defaults true only on API 36+, and this module's minSdk is 23, so consumers below 36 were silently getting commit-only pops from a module whose headline feature is predictive back. Nothing in the repo mentioned it. The tabs docs are reframed so the per-tab stacks read as the source of truth and `backStack` as the derived projection NavDisplay renders from — which is what the code does, `tabStacks` being what every push/pop mutates. Leading with "flattened into a single backStack" invited the reading that the flat list is the model. A new "Why one NavDisplay" section records why one display rather than one per tab: Nav3 ties all per-entry state to back-stack membership via NavEntryDecorator.onPop and has no retained-but-off-stack concept, so a single display is what makes cross-tab retention possible at all, and it keeps predictive back working across a tab boundary (predictive back being per-NavDisplay) while avoiding a dispatcher per tab. Stale navigation3 version in Requirements corrected alpha07 -> beta01; UpdateReadmeVersions has no nav3 pattern, and that line is prose rather than a dependency block, so it does not self-heal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bug fixes only. A full source diff of both artifacts between beta01 and rc01
turns up exactly two changed files, and no public API change at all — expected,
since rc freezes the API.
NavEntry's `defaultContentKey` moved from `Pair("$key", "${key::class}")` to
`"$key:${key::class}"`. It is @PublishedApi internal but used as a default
constructor argument, so it compiles into NavEntry's own synthetic rather than
inlining into consumers, and there is no binary-compatibility exposure for a
library that ships against one version while its consumers compile against
another. TabsSceneStrategyTest is unaffected: 9ab405b already rewrote those
assertions to compare contentKey to contentKey precisely because beta01 churned
this field once before, so the trap was disarmed ahead of time.
UriDeepLinkMatcher gained duplicate-placeholder validation and a ParsedPattern
refactor. Unreachable here — this module imports no DeepLink* symbol, deep links
being a seeded start stack rather than a URI-pattern framework.
Verified on rc01: the module's 120 JVM tests, koverVerify, and
:app:verifyConsumerKeepRules, plus the full 14-test on-device suite, which is the
part that matters — it covers real predictive-back gestures and Activity
recreation, and `aFreshLaunchDoesNotInheritThePreviousActivitysTabViewModels`
exercises exactly the contentKey identity behaviour rc01 changed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A Compose patch release, not a feature one. Diffing the two BOM POMs artifact-by-artifact (248 entries each), every version that moves goes 1.12.0 -> 1.12.1 across animation, foundation, material, runtime and ui. Nothing else changes, and material3 does not move at all. No API changes to absorb, so this is version-only across the ten modules that apply the platform. The fixes do land where this repo lives, though — runtime-saveable and foundation back ComposeExtensions' serialization-safe MutableState holders, SegmentedControl's drag gestures, and the lazy-list paging extensions. Verified with the full test task across all modules, koverVerify, and :app:verifyConsumerKeepRules. Also re-ran Nav3Navigation's on-device suite: animation and foundation both moved, and predictive-back scrubbing plus rememberSaveable restore across recreation are exactly what they drive. 14/14. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A patch bump with no API change, affecting DateHelperUtil-Room's type converters and S3Uploader-Multipart's upload-state database. The thing worth checking was the exported schemas, since S3Uploader-Multipart writes them to a checked-in schemas/ directory and a codegen change there would mean a migration problem rather than a build problem. Room 2.8.5 regenerates them byte-identically: both v1 and v2 keep the same formatVersion and the same identityHash (9fad5f76... and 2b09eace...), so nothing needed re-checking in and no migration is implied. The DateHelperUtil-Room README change is UpdateReadmeVersions syncing the Room coordinates in its install block during the build, not a hand edit. Verified with the full test task across all modules, koverVerify, and :app:verifyConsumerKeepRules. Worth noting the gap this exposed rather than leaving it implicit: S3Uploader-Multipart has no androidTest source set at all, despite androidTestImplementation(room.testing) and schemas wired into androidTest assets, so a @database(version = 2) with two exported schemas carries no automated migration coverage. Harmless here because the schemas are unchanged, but the next entity change walks into it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Split [versions], [libraries] and [plugins] into three tiers so it is obvious which bumps consumers can see: - PUBLISHED: on a consumer's classpath (api/implementation in a library module, or baked into the AAR by a code generator). Annotated the `api`-exposed ones (FlexiLogger, sandwich, Navigation 3) since a bump there is a breaking-change candidate rather than a routine build tweak. - BUILD/TEST: test and androidTest configurations of the library modules, plus the toolchain. Only CI can break. - DEMO APP: referenced solely by :app. No entries added, removed or re-versioned in the regroup - activityCompose moves to BUILD/TEST, where it belongs: it is the demo app plus one androidTest dependency in Nav3Navigation, not a published dependency. Also drop the `kover` version and plugin alias. A settings plugins block is resolved before the version catalog exists, so settings.gradle.kts could never have read libs.plugins.kover - it hardcodes the version and always has. With no Renovate or Dependabot on this repo, the entry was two lines that could silently disagree with the real version. settings.gradle.kts is now the single source of truth and its comment says why. Remove the commented-out testImplementation(libs.paging.common) from the two Lazy*PagingExtensions modules; the live usages in :app and BaseRepo-Paging are unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
README version references are synced by the UpdateReadmeVersions task during Gradle sync, so they move with the bump rather than being hand-edited. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Testing a change before a release had one path — publish.sh --local — which signs, so it waits on a 1Password unlock for a signature nothing local ever verifies: Gradle does not check signatures on resolve. That makes the everyday iteration loop cost a vault unlock for no benefit, and there was no way to undo an install short of deleting from ~/.m2 by hand. publish-local.sh installs unsigned and needs no credentials, and takes module names to publish a subset while iterating on one module. --signed delegates to publish.sh --local for the cases where the artifact set itself is under test. clear-local-publish.sh removes the install again, optionally for one version. It lists what it will delete and confirms first, and only ever touches the toolbox's own group directory — derived from PUBLISH_GROUP, so a fork clears its own coordinates rather than ours. Both are also shared Android Studio run configurations under .run/, running in the Run window's terminal so the confirmation prompt works there. CONTRIBUTING.md gains the consuming-project half, which was missing entirely: where mavenLocal() goes, why the first resolve needs --refresh-dependencies in both directions, and the escape from version shadowing — a TOOLBOX_VERSION that cannot exist on Central, so no version string means two different things. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two sections each told half the story. "System back" says stop wrapping the host in a BackHandler; "Results" says popWithResult hands a value to the screen underneath. Neither says what happens to a screen doing both — and the answer is that system back routes through NavDisplay's onBack to a plain pop(), so the result is dropped. The back arrow keeps working, the gesture silently stops signalling, and nothing errors. A consumer migrating off BackHandler hits this immediately and has no documented landing place. Documents the host-onBack dispatch: an app-side interface read via navigator.lastItem, so NavDisplay still owns the gesture and the predictive pop transition still scrubs. Notes the navigator must be hoisted with rememberBackStackNav3Navigator, since onBack is built at the call site where LocalNav3Navigator is still the outer navigator rather than the one the host provides. Also warns off the obvious wrong fix — an always-enabled NavigationBackHandler — which intercepts ahead of NavDisplay and loses predictive back, the same regression 2bf651e removed from the tabs examples. That API is for conditional interception, not for carrying a payload out of an unconditional pop. Records why this stays app-side rather than becoming a host default or a Nav3Screen.onPopResult hook: an always-popWithResult(null) default would deliver null to receivers that only wanted explicit results, and the hook is this interface with the library guessing the contract instead of the app declaring it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Drops the release-candidate suffix now the branch is the 1.9.1 release. README version references follow via the UpdateReadmeVersions sync. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jakeeilbeck
reviewed
Sep 15, 2026
jakeeilbeck
left a comment
Contributor
There was a problem hiding this comment.
Clean release PR — no correctness or security issues. Checked the CI draft-guard expression (correct: push still runs, drafts skip), the version-catalog regroup (kover dropping out of the catalog strands nothing — it's pinned directly in settings.gradle.kts), and both new shell scripts. One minor papercut noted inline; nothing blocking.
| case "$arg" in | ||
| --signed|-s) | ||
| info "Delegating to scripts/publish.sh --local for the signed install." | ||
| exec ./scripts/publish.sh --local |
Contributor
There was a problem hiding this comment.
--signed silently discards any module args — publish-local.sh --signed BaseRepo does a full signed publish and ignores BaseRepo. Fine given publish.sh has no subset mode, but worth a one-line warn before the exec so the dropped args aren't a surprise.
jakeeilbeck
approved these changes
Sep 15, 2026
projectdelta6
marked this pull request as draft
September 16, 2026 09:30
Collaborator
Author
|
Holding for BarcodeScanner feature |
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.
Release branch for 1.9.1, the first Central release since 1.9.0.
./scripts/publish.sh --dry-runis green onc4a7e5c— clean,test koverVerify,:app:verifyConsumerKeepRules,publishToMavenLocal, andverifyPublishedVariantResolution --refresh-dependenciesall pass.Dependency bumps
Local-publish tooling
Testing a change before a release had one path —
publish.sh --local— which signs, so it waited on a 1Password unlock for a signature nothing local ever verifies (Gradle does not check signatures on resolve). And there was no way to undo an install short of deleting from~/.m2by hand.scripts/publish-local.sh— unsigned install, no credentials, takes module names to publish a subset while iterating.--signeddelegates topublish.sh --local.scripts/clear-local-publish.sh— removes the install, optionally one version. Lists what it will delete and confirms first; only ever touches the group directory derived fromPUBLISH_GROUP, so a fork clears its own coordinates..run/for both.CONTRIBUTING.mdgains the consuming-project half that was missing entirely: wheremavenLocal()goes, why the first resolve needs--refresh-dependenciesin both directions, and the escape from version shadowing — aTOOLBOX_VERSIONthat cannot exist on Central.Nav3Navigation docs
BackHandlerfor ordinary system back: it duplicates the built-in path and intercepts ahead ofNavDisplay, sopredictivePopTransitionSpecnever scrubs. Points atNavigationBackHandlerfor genuine interception, and documents the API 33–35enableOnBackInvokedCallbackopt-in that nothing in the repo mentioned.popWithResultis child-initiated, so system back routes to a plainpop()and the result is silently dropped — the back arrow keeps working while the gesture stops signalling. Documents the host-onBackdispatch, and records why this stays app-side rather than becoming a host default. Raised by a consumer hitting it during the 1.9.1 adoption.Release notes
Before merging
Releases are immutable — once
1.9.1uploads it can never be corrected, only superseded. And one toolbox release is ~508 files against a 1,000/month Central cap, so a second 1.9.x this calendar month would fit and a third would not.Publishing is manual: merging this does not release anything.
./scripts/publish.shfrommainuploads and then tags.🤖 Generated with Claude Code