Skip to content

feat(bazel): migrate build system to Bazel with full CI#149

Open
tstapler wants to merge 45 commits into
mainfrom
stelekit-bazel
Open

feat(bazel): migrate build system to Bazel with full CI#149
tstapler wants to merge 45 commits into
mainfrom
stelekit-bazel

Conversation

@tstapler

Copy link
Copy Markdown
Owner

Summary

  • Introduces Bazel as the canonical build system for all JVM/Desktop, Android, and WASM/Web targets, replacing the Gradle-only setup
  • All 548 JVM tests and 134 business tests pass under Bazel (//kmp:jvm_tests, //kmp:business_tests)
  • GitHub Actions CI wired up with native caching via setup-bazel@0.19.0 — no third-party BuildBuddy required

Key changes

Build system

  • MODULE.bazel + MODULE.bazel.lock — Bzlmod dependency graph (rules_kotlin, rules_jvm_external, rules_android, Compose Desktop, AndroidX)
  • BUILD.bazel files for all source sets: commonMain, jvmMain, jvmCommonMain, androidMain, androidUnitTest, businessTest, jvmTest, commonMain/resources, generated/sqldelight
  • third_party/patches/rules_kotlin_kmp.patch — patches rules_kotlin to add common_srcs / -Xcommon-sources for KMP expect/actual compilation
  • SQLDelight generated sources checked in under kmp/src/generated/sqldelight/ (see ADR-003)

CI

  • .github/workflows/bazel-ci.yml — four parallel jobs (jvm, android-build, android-tests, web) using bazel-contrib/setup-bazel@0.19.0 with per-job disk-cache isolation, shared repository-cache and external-cache, PR-read-only cache policy
  • permissions: contents: read at workflow level for principle of least privilege
  • Xvfb + --sandbox_add_mount_pair=/tmp/.X11-unix for Compose Desktop tests in the Linux sandbox

Test infrastructure

  • AllJvmTests.kt / AllBusinessTests.kt — JUnit4 @Suite aggregators (required by Bazel's test_class mechanism)
  • ClasspathUtils.kt — atomic JAR resource extractor (temp-dir-then-rename) for demo-graph test fixtures that Bazel packs into JARs
  • user.homeTEST_TMPDIR/java.io.tmpdir in all tests that write temporary files (Bazel sandbox blocks home-dir writes)

Fixes in production code

  • SearchDialog.kt — add modifier: Modifier = Modifier to backward-compat SearchResultRow overload (Compose convention)
  • SqlDelightBlockRepository.kt — smart-cast safety fix for parent_uuid; explicit : Unit return type on walCheckpoint()

Architecture decisions

  • ADR-001: Scope JVM + Android only (iOS stays Gradle)
  • ADR-002: Bzlmod over WORKSPACE (Bazel 9 removed WORKSPACE entirely)
  • ADR-003: Check in SQLDelight generated sources (avoids complex Bazel codegen)
  • ADR-004: BuildBuddy replaced by GitHub Actions native caching

Test plan

  • bazel build //kmp:desktop_app compiles cleanly
  • bazel test //kmp:business_tests — 134 tests pass
  • bazel test //kmp:jvm_tests — 548 tests pass (CI validates; requires Xvfb)
  • bazel build //kmp:android_app --config=android builds APK
  • bazel test //kmp/src/androidUnitTest/kotlin:android_unit_tests --config=android passes
  • bazel build //kmp:web_app produces web_dist.tar.gz
  • CI: all four jobs green on this PR
  • Gradle commands still work (backward compatible for iOS + screenshot tests + benchmarks)

🤖 Generated with Claude Code

tstapler and others added 10 commits May 17, 2026 15:17
Captures requirements, research (stack/features/architecture/pitfalls),
implementation plan (7 epics, 14 stories, 27 tasks), validation plan
(26 test cases, 100% requirement coverage), and 4 ADRs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a complete Bazel build system alongside Gradle for JVM/Desktop,
Android, and Web (WASM/JS via Gradle genrule) targets.

Key components:
- MODULE.bazel: Bzlmod config with rules_kotlin 2.3.20, rules_android
  0.7.1, rules_jvm_external 6.9; Maven lockfile enabled (eliminates
  Coursier resolution on every build — biggest RAM win)
- rules_jvm_external++maven+maven_install.json: pinned lockfile (8 k
  lines, all transitive conflicts resolved)
- BUILD.bazel files: kt_jvm_library/kt_android_library targets for
  commonMain, jvmMain, androidMain, test source sets
- .bazelrc: Bazel server heap capped at 6 GB, BuildBuddy remote cache
  for CI (seed on main, read-only on PRs)
- .github/workflows/bazel-ci.yml: 4-job CI (JVM, Android, Android
  unit tests, Web)
- kmp/src/generated/sqldelight/: SQLDelight-generated Kotlin checked
  in (Bazel uses static sources rather than running code generation)
- .gitignore: add /bazel-* output symlink patterns

WASM/JS: rules_kotlin does not yet support Kotlin/WASM
(rules_kotlin#567); //kmp:web_app delegates to Gradle via genrule
with tags=["local"].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Key changes:
- Patch rules_kotlin via single_version_override to add common_srcs
  attribute, enabling -Xcommon-sources for KMP expect/actual compilation
- Restructure jvmMain compilation: merge commonMain + jvmCommonMain +
  jvmMain sources into one kt_jvm_library with common_srcs=commonMain
- Replace common_jvm/jvm_common_main kt_jvm_library targets with
  filegroup(kt_srcs) — expect-only targets cannot compile standalone
- Exclude JMH benchmarks from jvm_main_lib (Gradle-only, jmh plugin)
- Add associates= to business_tests and jvm_tests for internal access
- Add AllBusinessTests.kt and AllJvmTests.kt JUnit4 suite classes
- Use test_suite in kmp/BUILD.bazel so aliases expose test targets
- Fix SqlDelightBlockRepository smart-cast and SearchDialog signature

bazel test //kmp:business_tests → 134 tests PASSED

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… dirs

- Add --sandbox_add_mount_pair=/tmp/.X11-unix to .bazelrc so Compose
  Desktop tests can connect to X11 inside the Linux sandbox (previously
  DISPLAY was inherited but the socket wasn't mounted)
- Add commonMain/resources BUILD.bazel: java_library with
  resource_strip_prefix so demo-graph/ is packed into JARs correctly
- Add ClasspathUtils.kt: getClasspathDirectory() handles both file://
  (Gradle) and jar: (Bazel) URLs by extracting to TEST_TMPDIR on demand
- Apply getClasspathDirectory() in DemoGraphIntegrationTest and
  DemoGraphCoverageTest (replaces File(url.toURI()) which fails on jar: URIs)
- Replace System.getProperty("user.home") with java.io.tmpdir in
  BacklinkRenamerTest, GraphLoaderTest, GraphWriterTest (sandbox blocks $HOME)
- Wire up common_resources dep in jvmMain BUILD; add env_inherit/tags to
  jvmTest BUILD for display requirements
- Add .bazelrc.user.example, update .gitignore, CI workflow, CLAUDE.md

bazel test //kmp:business_tests → 134 tests PASS
bazel test //kmp:jvm_tests → 548 tests PASS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ClasspathUtils.kt: wrap check-then-extract in synchronized(extractionLock)
  to prevent TOCTOU race if tests ever run in parallel threads
- SearchDialog.kt: add modifier param to backward-compat SearchResultRow
  overload so all Compose composable overloads support modifier composition
- bazel-ci.yml: add mkdir -p /tmp/.X11-unix before xvfb-run so Bazel
  sandbox mount pair is valid even if xvfb hasn't created the socket yet

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ClasspathUtils.kt: atomic extraction via temp-dir-then-rename; cleans up
  on exception so a partial extraction never masquerades as complete
- jvmTest/BUILD.bazel: remove unnecessary business_tests dep (no jvmTest
  file imports businessTest classes; dep was cargo-culted from an earlier
  iteration)
- CLAUDE.md: clarify Bazel is canonical, Gradle is legacy; rename table
  headers accordingly
- README_REGEN.md: fix ADR reference (ADR-001 → ADR-003, the actual
  checked-in-sources decision) and include the file path
- bazel-ci.yml: add timeout-minutes: 30 to all four CI jobs to prevent
  runaway jobs from consuming unlimited runner time

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ache docs

- .bazelrc: enable --remote_cache_compression=zstd for CI (~60% bandwidth
  reduction on BuildBuddy cache payloads for large Compose+AndroidX builds)
- .bazelrc: wire up --bes_backend/--bes_results_url so CI invocations stream
  to BuildBuddy UI for build analytics and invocation history
- .bazelrc.user.example: document --disk_cache option for local developers
  (persistent action cache between sessions, similar benefit to ccache) and
  optional BuildBuddy remote cache for cross-machine sharing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switch from bazel-contrib/setup-bazel@0.9.1 + manual actions/cache + BuildBuddy
to bazel-contrib/setup-bazel@0.19.0 with built-in caching — no third-party
service or API key required.

setup-bazel@0.19.0 provides:
  disk-cache: <name>     — persists compiled build action results per job
  repository-cache: true — shared Maven/artifact download cache (keyed by
                           MODULE.bazel) across all jobs
  external-cache: true   — caches large individual external repos (Compose,
                           AndroidX) separately for efficient invalidation
  cache-save: <bool>     — PRs read-only; main-branch pushes write (prevents
                           cache pollution, replacing --noremote_upload_local_results)

Each job gets its own disk-cache key (jvm / android / android-tests / web)
so compiled outputs don't collide across different build targets.

Removes:
  - All manual actions/cache@v4 steps for ~/.cache/bazel
  - BuildBuddy --remote_cache, --bes_backend, and API key secrets
  - --config=ci / --config=ci-main / --config=ci-pr flags from build commands
  - Entire CI config block from .bazelrc

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add permissions: contents: read at workflow level (principle of least privilege)
- Pass --no-install-recommends to all apt-get install calls (faster installs)
- Gate web artifact upload to push events only (skip on PRs to reduce noise)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New workflow files don't auto-trigger on pull_request events until the
workflow exists on the base branch. workflow_dispatch lets us validate CI
on this branch before merging.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@tstapler tstapler closed this Jun 13, 2026
@tstapler tstapler reopened this Jun 13, 2026
… path conflicts

Conflict resolutions:
- .gitignore: keep Bazel section + add uploads/ from main
- MODULE.bazel: keep our full Bzlmod file (main had a stub)
- SqlDelightBlockRepository: combine main's blockUuid.value with our smart-cast fix
- GraphWriterTest: use java.io.tmpdir (Bazel sandbox safe) with Files.createTempDirectory API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

JVM Load Benchmark (Desktop)

Synthetic in-memory benchmark measuring load performance for the desktop (JVM) app.
Comparing d1846bac (this PR) vs 81c0ef7d (baseline)
Graph config: xlarge — 230 pages

Metric This PR Baseline Delta
Phase 1 TTI ↓ 1ms 1ms 0 (0%)
Phase 2 background ↓ 0ms 0ms 0 (0%)
Phase 3 index ↓ 0ms 0ms 0 (0%)
Total ↓ 1ms 1ms 0 (0%)
Write p95 (baseline) ↓ 4ms 3ms +1ms (+33%) ⚠️
Write p95 (under load) ↓ 1ms n/a
Jank factor ↓ 0.25x n/a
↓ lower is better
Flamegraphs (this PR) **Allocation** — object allocation pressure (JDBC/SQLite churn)

Alloc flamegraph not available

CPU — method-level hotspots by on-CPU time

CPU flamegraph not available

Top SQL queries by total time (this PR) | table:operation | calls | p50 | p99 | max | total | |-----------------|-------|-----|-----|-----|-------| | `blocks_fts:insert` | 2 | 1ms | 1ms | 0ms | 0ms | | `pages:select` | 2 | 1ms | 1ms | 0ms | 0ms |
Top allocation hotspots (this PR) `36.8%` byte[]_[k] `8.6%` java.lang.String_[k] `8.2%` java.util.LinkedHashMap$Entry_[k] `4.4%` int[]_[k] `3.2%` java.lang.Object[]_[k]
Top CPU hotspots (this PR) `94.4%` /usr/lib/x86_64-linux-gnu/libc.so.6 `2.2%` /tmp/sqlite-3.51.3.0-bc8d7fe1-4370-4bb6-b16a-16bd54da2218-libsqlitejdbc.so `0.4%` pthread_cond_signal `0.4%` __libc_pwrite `0.4%` fsync

@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Android Load Benchmark

Instrumented benchmark on an API 30 x86_64 emulator — 500-page synthetic graph.

Comparing d1846bac (this PR) vs 727a22b7 (baseline)
Device: API 30 x86_64 emulator — 530 pages loaded

Graph Load

Metric This PR Baseline Delta
Phase 1 TTI ↓ 61ms 64ms -3ms (-5%) ✅
Phase 3 index ↓ 6494ms 6353ms +141ms (+2%) ⚠️

Interactive Write Latency (during Phase 3)

Metric This PR Baseline Delta
Write p95 (baseline) ↓ 7ms 10ms -3ms (-30%) ✅
Write p95 (during phase 3) ↓ 17ms 22ms -5ms (-23%) ✅
Jank factor ↓ 2.43x 2.2x +0.23x (+10%) ⚠️
Concurrent writes ↑ 32 30 +2ms (+7%) ✅

SAF I/O Overhead (ContentProvider vs direct File read)

Measures Binder IPC cost added by ContentResolver per readFile() call.
Real SAF via ExternalStorageProvider will be higher on device; this is a lower bound.

Metric This PR Baseline Delta
Direct read / file ↓ 0.0ms 0.0ms 0 (0%)
Provider read / file ↓ 0.2ms 0.2ms +0ms (+18%) ⚠️
IPC overhead ratio ↓ 6x 5x +1x (+20%) ⚠️
↓ lower is better · ↑ higher is better

tstapler and others added 14 commits June 13, 2026 15:13
…telist

SQLDelight generated sources were out of sync with main's new queries
(updateBlockFull, insertImageAnnotation, setPageBacklinkCount, etc.),
causing Bazel compilation failures after the merge.

Also fix GraphWriterTest: calling registerGraphRoot() on PlatformFileSystem
before writing, so java.io.tmpdir paths pass JvmFileSystemBase's whitelist.
(user.home is seeded automatically; java.io.tmpdir is not.)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- androidApp/BUILD.bazel: remove desugar_java8_libs — attribute no
  longer exists in current rules_android version

- kmp/src/commonTest/kotlin/BUILD.bazel: new kt_jvm_library target for
  FakeFileSystem so jvmTest can depend on it; fixes unresolved-reference
  compile errors in ImageAnnotationOfflineTest and
  ImageImportServiceIntegrationTest

- kmp/src/jvmTest/kotlin/BUILD.bazel: add common_test_fixtures dep

- BacklinkRenamerTest, GraphLoaderTest: revert java.io.tmpdir → user.home
  (match main); java.io.tmpdir falls outside JvmFileSystemBase whitelist
  without an explicit registerGraphRoot() call — tests were failing with
  AssertionError on every rename/load assertion in Gradle CI

- kmp/BUILD.bazel: fix web genrule to run Gradle from workspace root
  instead of Bazel execroot — resolves "No module with .../wasmJs/main
  found" IllegalStateException caused by Kotlin compiler writing build
  artifacts into the execroot symlink tree rather than the real workspace

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add BuildInfo.kt (commonMain) to hold commit hash at runtime without
  BuildConfig — avoids AGP 8.13.2 + KGP 2.3.21 joint-compilation bug
  where compileDebugJavaWithJavac is absent and BuildConfig.class is
  never on the Kotlin compiler classpath
- Use resValue("string", "git_commit_hash", ...) in androidApp/build.gradle.kts
  and read via getString(R.string.git_commit_hash) in SteleKitApplication
- Add commitHash field to PerfExportReport; PerfExporter reads BuildInfo
- Fix kmp/src/commonTest/kotlin/BUILD.bazel: dep was non-existent
  //kmp/src/commonMain/kotlin:kmp_lib; corrected to jvm_main_lib
- Add exports_files(["src/main/AndroidManifest.xml"]) to androidApp/BUILD.bazel
  so android_local_test in androidUnitTest can reference the manifest
- Add package="dev.stapler.stelekit" to AndroidManifest.xml so Bazel's
  manifest merger can resolve the application package attribute (AGP
  uses namespace= in build.gradle.kts; Bazel's merger still requires
  the manifest attribute)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Main's ca301a1 used BuildConfig.GIT_COMMIT_HASH which doesn't compile
with AGP 8.13.2 + KGP 2.3.21. Our branch uses resValue/R.string which
works. Keep our fixes for all performance files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ackage= rejection

AGP 8.13.2 explicitly rejects any `package` attribute in the source
AndroidManifest.xml ("Setting the namespace via the package attribute
in the source AndroidManifest.xml is no longer supported"). Bazel's
manifest merger, however, requires the package attribute to identify
the application.

Solution: revert the main manifest to have no package attribute (for
Gradle), and create BazelAndroidManifest.xml as a minimal stub with
package="dev.stapler.stelekit" (for Bazel). Both android_binary and
android_local_test in Bazel now reference BazelAndroidManifest.xml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add minSdkVersion=26 to BazelAndroidManifest.xml: without a <uses-sdk>
  element, Bazel defaults to minSdkVersion 23, which is less than the
  required 26 declared by com.google.mlkit.genai.prompt library
- Change --test_output=summary to --test_output=all in bazel-ci.yml so
  failing JVM test details are visible in CI logs (summary mode writes
  to a file on the runner that is not accessible after the run)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bazel's Linux process sandbox creates an isolated /tmp that doesn't
include /tmp/.X11-unix, so JVM tests that touch AWT/Compose fail with
"Can't connect to X11 window server using ':99'" even though
env_inherit=["DISPLAY"] correctly passes the DISPLAY env var.

--sandbox_add_mount_pair=/tmp/.X11-unix bind-mounts the Xvfb socket
directory into the sandbox so tests can reach the virtual display.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Main added BuildInfo.appVersion + set it via BuildConfig.VERSION_NAME,
which is broken on AGP 8.13.2 + KGP 2.3.21 (compileDebugJavaWithJavac
task absent). Use PackageManager to read versionName at runtime instead.
commitHash already uses resValue/R.string for the same reason.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mmit_hash to spans

Main's 84426e3 added app_version/commit_hash columns to the spans table
and updated RestrictedDatabaseQueries.insertSpan to pass 11 args, but the
checked-in generated SteleDatabaseQueries.kt still had the 9-arg signature.
This caused Bazel JVM, Android build, and Android unit tests to all fail.

Re-run: ./gradlew :kmp:generateCommonMainSteleDatabase && rsync ...

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
xvfb-run sets XAUTHORITY=/tmp/.../Xauthority (MIT-MAGIC-COOKIE) so
Xvfb accepts connections. Without it, JVM tests get:
  AWTError: Can't connect to X11 window server using ':99'
even though DISPLAY is correctly set.

Also add --test_env=DISPLAY/XAUTHORITY on the command line as belt-and-
suspenders alongside env_inherit in BUILD.bazel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tual resolution

The previous 3-level chain (common_android → jvm_common_main_android → android_main)
compiled commonMain sources separately without -Xmulti-platform, causing:
  1. 'expect' and 'actual' declarations can be used only in multiplatform projects
  2. @kotlin.time.ExperimentalTime opt-in required (from main's 84426e3)

Mirrors the JVM pattern in jvm_main_lib: compile all source sets (commonMain +
jvmCommonMain + androidMain) in one kt_android_library with kmp_android_kotlinc_opts
(-Xmulti-platform -opt-in=kotlin.time.ExperimentalTime).

Also increase --experimental_ui_max_stdouterr_bytes to 4MiB to expose compile
errors in CI logs instead of silently truncating them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ual resolution

Without common_srcs, the Kotlin compiler treats all sources in android_main
as the same module and rejects 'actual' declarations with:
  'actual object PlatformDispatcher' has no corresponding expected declaration
  platformDispatcher: expect and corresponding actual are declared in the same module

The rules_kotlin_kmp.patch already adds common_srcs to lib_common_attr (shared by
both kt_jvm_library and kt_android_library). Adding common_srcs here passes
-Xcommon-sources=<commonMain files> to the compiler, which marks commonMain
as the KMP common source set containing expect declarations. The compiler then
correctly links expect (in commonMain) with actual (in androidMain) within the
same compilation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Kept our R.string.git_commit_hash / PackageManager.appVersion approach
for BuildInfo initialization (Bazel-compatible), dropping the re-added
BuildConfig.GIT_COMMIT_HASH import from main which breaks the Bazel build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Regenerate kmp/src/generated/sqldelight/ after merging feat/assets, which
added new SQL queries for assets and pending-moves tables (Asset_index,
Pending_asset_moves, selectUnprocessedAssets, insertAsset, insertPendingMove,
and ~30 related generated methods) that were missing in the checked-in sources.

Add org.apache.pdfbox:pdfbox:3.0.4 to MODULE.bazel maven deps and to
jvm_main_lib deps in kmp/src/jvmMain/kotlin/BUILD.bazel so JvmPdfTextExtractor
(new file from feat/assets merge) resolves the org.apache.pdfbox import.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tstapler and others added 20 commits June 14, 2026 10:31
Regenerated rules_jvm_external++maven+maven_install.json via
`REPIN=1 bazel run @maven//:pin` to incorporate the
org.apache.pdfbox:pdfbox:3.0.4 artifact added to MODULE.bazel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds 12 missing Maven artifacts to MODULE.bazel and their corresponding
@maven// deps to the android_main BUILD.bazel target so the Kotlin
compile phase resolves all unresolved references introduced by the
feat/assets and feat/tags merges.

Libraries added:
- com.juul.kable:core-android:0.32.0 (Kable BLE)
- com.tom-roush:pdfbox-android:2.0.27.0 (PDFBox Android)
- com.google.mlkit:image-labeling:17.0.9 (ML Kit Image Labeling)
- com.google.mlkit:text-recognition:16.0.1 (ML Kit Text Recognition)
- com.google.ar:core:1.46.0 (ARCore Depth API)
- androidx.camera:camera-{core,camera2,lifecycle}:1.4.1 (CameraX)
- androidx.lifecycle:lifecycle-process:2.9.4 (CameraX lifecycle dep)
- com.microsoft.onnxruntime:onnxruntime-android:1.20.0 (ONNX Runtime)
- androidx.exifinterface:exifinterface:1.3.7 (EXIF orientation)
- com.squareup.okio:okio-jvm:3.17.0 (Okio, used by commonMain)
- androidx.compose.material:material-icons-extended:1.7.8 (Android icons)

Also fixes AndroidGitRepository.kt missing showDuration(Boolean) override
in the ProgressMonitor anonymous class — JGit 7.x added this method and
Bazel resolves to 7.x for Android (unlike Gradle which uses 5.13.x).

Regenerated rules_jvm_external++maven+maven_install.json via REPIN=1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gradle Android was pinned to JGit 5.13.3 while Bazel resolved 7.3.0.
The `showDuration(Boolean)` override in AndroidGitRepository.kt exists
only in the JGit 7.x ProgressMonitor interface, causing a Gradle Android
compile error ("overrides nothing"). Upgrading the core artifact unblocks
the build; the SSH/JSch module remains at 5.13.3 as it is a separate
artifactId still needed for JschConfigSessionFactory auth.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NoGraphPlaceholder.kt uses dev.stapler.stelekit.R.string.* from
kmp/src/androidMain/res/values/strings.xml. In Bazel, res/ belongs to
the kmp/ package (nearest BUILD ancestor), so the android_library that
generates the R class must be defined in kmp/BUILD.bazel and depended
on from android_main.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rary

rules_android requires manifest attribute when resource_files specified.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…to android_unit_test_lib

- associates = android_main: grants access to internal declarations
  (ANDROID_PRAGMAS, ShadowFileCache) — mirrors jvm_tests/businessTest pattern
- kotlinc_opts = kmp_android_kotlinc_opts: adds ExperimentalTime opt-in
- kotlin_test_junit dep: resolves kotlin.test.assertEquals/assertTrue etc.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…otlin rejects duplication)

rules_kotlin's verify_associates_not_duplicated_in_deps check fails if a
target appears in both associates= and deps=. associates= already provides
the dependency transitively, so remove android_main from deps.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…al_test

android_local_test needs test_class to know what to run — without it Bazel
derives a class name from the target path (androidUnitTest.kotlin.android_unit_tests)
which doesn't exist. Mirrors AllJvmTests pattern used by jvm_tests target.

Suite uses @RunWith(Suite::class) which delegates per-class runners (@RunWith
RobolectricTestRunner) correctly to each test class.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ic-deps.properties lands in test runfiles

android_local_test passes -Drobolectric-deps.properties=../rules_robolectric+/bazel/robolectric-deps.properties
to the JVM but never adds that file to runfiles, causing NoSuchFileException at runtime.

Fix: declare rules_robolectric 4.16.1 in MODULE.bazel (matching our Maven robolectric:4.16) and add
@rules_robolectric//bazel:android-all as a data dep — that target carries robolectric-deps.properties
as data, putting it in the test runfiles at the path the JVM flag points to.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each Bazel CI job now starts bazel-cache-proxy backed by the GitHub Actions
cache API before running Bazel commands. The proxy translates Bazel's HTTP
remote cache protocol into GHA cache v1/v2 API calls (auto-detecting which
version the runner supports).

Benefits over the existing disk-cache-only approach:
- All 4 jobs on the same PR run share a single GHA cache namespace, so
  each subsequent job skips work already done by earlier jobs
- PRs write to their own scoped cache (refs/pull/N/merge) so main's cache
  is never polluted — the existing disk-cache restriction stays in place
- The circuit breaker in bazel-cache-proxy degrades gracefully to a cache
  miss if GHA is unavailable, so builds never fail due to cache issues

The proxy binary is compiled once and cached under bcp-<OS>-<commit> key;
subsequent jobs restore it in ~1s.

Adds a `build:remote-cache` config to .bazelrc for local use with
`bazel-cache-proxy serve` pointed at a disk or S3 backend.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
prost-build requires protoc at compile time to generate Rust bindings from
.proto files. ubuntu-latest runners don't have it pre-installed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Updates to the commit that degrades gracefully when ACTIONS_RUNTIME_TOKEN
is absent instead of panicking at startup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Build completed in ~29 min but the 30-min limit fired during Post Set up
Bazel while uploading the 1.17 GB repository cache. Extra headroom avoids
the false failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ckpoint

Main added selectAllHistogramBuckets, updateBlockForSave, and walCheckpoint
(with override) to the interface; the generated sources needed a refresh and
the duplicate non-override walCheckpoint from the merge resolution needed
removing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- AllPagesScreen + PageRowItem: move modifier before other defaulted params
  to satisfy compose-rules ComposableParamOrder (pre-existing Detekt failure
  on main introduced with the conflict-icon feature)
- GraphLoadTimingTest: raise large-page threshold 2s→5s so CI runner load
  variance doesn't trigger a false failure; 5s still catches the 203-second
  production regression by 40x

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
saveBlocks was calling merge=-200 after every save, including navigation
(loadPageByName). On a 500-page graph, this reads the entire FTS index
each time — adding hundreds of ms per page load.

Fix: remove ftsMerge() from saveBlocks and add compactFtsIndex() to
BlockWriteRepository. indexRemainingPages now calls it once after the
full indexing batch completes. Navigation saves rely on automerge=8
(already restored by ftsAutomergeDefault) for background FTS maintenance.

This makes large-page navigation comfortably under the 2s regression guard
even on a loaded CI runner.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
writeActor.execute requires @DirectRepositoryWrite opt-in and an
Either<DomainError, Unit> return from the lambda.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant