From a014d16e93d3edd63c31df8d17bfba0fdd71b0e6 Mon Sep 17 00:00:00 2001 From: Giuseppe Maggio Date: Wed, 16 Sep 2026 11:26:37 +0200 Subject: [PATCH 1/6] ci: give a restored chromium stage its cache directories back Stage 2 of run 35075286983 died at ninja edge 2077 with ninja: job failed with status 1: python3 ../../third_party/dawn/tools/generate-sources-gn.py gen failed to initialize build cache at /home/pmos/.cache/go-build: mkdir /home/pmos/.cache/go-build: file exists That path is a symlink pmbootstrap makes to /mnt/pmbootstrap/go/gocache, a directory inside the cache_go bind mount. Both the symlink and the directory are created by pmb.chroot.init(), but only on the way that creates the chroot: for one that exists it mounts and returns. chromium-state.sh stores the prep layer with --exclude='./cache_*/*', so the cache directories are restored empty and gocache is not restored at all. Every stage that re-enters the work directory therefore has a dangling /home/pmos/.cache/go-build, and Go's os.MkdirAll() on a dangling symlink returns EEXIST: stat() fails, mkdir() then hits the symlink. Go prints "not a directory" for a regular file and succeeds on a missing one, so this message only ever means the symlink. The three cargo directories under cache_rust are missing for the same reason. Stage 1 was not spared, it just stopped at edge 1206 before any Go action ran. Recreate the missing targets in enter(), after pmb.chroot.init(), which is where this script already redoes what run_abuild() sets up. Only the missing ones: a target that is there but wrong keeps failing where it is used, instead of being quietly replaced here. The caches stay out of the stored state: ninja records a finished Go action in .ninja_log, so no later stage reruns it, and a build cache that is only used within one stage is not worth 2 GB of release assets. Assisted-by: Claude --- .github/CHROMIUM.md | 8 ++++++++ .github/scripts/chromium-stage.py | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/.github/CHROMIUM.md b/.github/CHROMIUM.md index 57df3f159a..a260f8a3e1 100644 --- a/.github/CHROMIUM.md +++ b/.github/CHROMIUM.md @@ -71,6 +71,14 @@ special case. itself, not by guessing from exit codes. - **mtimes:** tar's `posix` format keeps mtimes to the nanosecond, the resolution samurai compares. +- **Caches are not state:** the prep layer stores the work directory without + the contents of `cache_*`; they are rebuildable, and the go, rust and + ccache directories would only make the layer bigger. pmbootstrap creates + the directories that `/home/pmos`'s cache symlinks point at only when it + creates a chroot, so a restored stage recreates the missing ones before + abuild runs (`enter()` in `scripts/chromium-stage.py`). Without that, + `/home/pmos/.cache/go-build` dangles and the build's Go actions fail with + "failed to initialize build cache". - **A frozen toolchain:** - Alpine edge changes daily. Every stage restores the chroots that prep installed, so all objects are compiled by one clang against one set of diff --git a/.github/scripts/chromium-stage.py b/.github/scripts/chromium-stage.py index 5f56603111..971438528b 100755 --- a/.github/scripts/chromium-stage.py +++ b/.github/scripts/chromium-stage.py @@ -133,6 +133,22 @@ def enter() -> tuple[CrossCompile, dict]: chroot = cross.build_chroot(ARCH) pmb.chroot.init(chroot) pmb.build.other.configure_abuild(chroot) + # pmbootstrap creates the directories that /home/pmos's cache symlinks + # point at only while it creates a chroot; init() returns early for one + # that exists. chromium-state.sh stores the prep layer without the cache + # contents (--exclude='./cache_*/*'), so in a restored chroot the targets + # that live *inside* a cache bind mount are gone and their symlinks + # dangle: /home/pmos/.cache/go-build -> /mnt/pmbootstrap/go/gocache (and + # the three cargo ones). os.MkdirAll() returns EEXIST on a dangling + # symlink, which is Go's "failed to initialize build cache at + # /home/pmos/.cache/go-build: ... file exists" that broke dawn's + # generate_sources in run 35075286983. Recreate only what is missing: a + # target that exists as something else still fails where it is used. + for target in pmb.config.chroot_home_symlinks: + if not (chroot / target).is_dir(): + print(f"::notice::recreating the cache directory {target}", flush=True) + pmb.chroot.root(["mkdir", "-p", target], chroot) + pmb.chroot.root(["chown", "pmos:pmos", target], chroot) # What pmb.build.backend.run_abuild() sets up before running abuild. if cross == CrossCompile.CROSS_NATIVE2: pmb.helpers.mount.bind(cross.host_chroot(ARCH).path, chroot / "mnt/sysroot", umount=True) From b28cbc1709214a1bb219b9e742c367d11fbdbd70 Mon Sep 17 00:00:00 2001 From: Giuseppe Maggio Date: Wed, 16 Sep 2026 11:31:20 +0200 Subject: [PATCH 2/6] ci: let a restored chromium stage write its apks Not observed yet: only the package stage writes to $WORK/packages, and no run has reached it. run_abuild() chowns $WORK/packages to the chroot's build user (12345), but only on the branch that creates the directory. In a restored work directory it exists, and it belongs to the runner's uid: the prep container's exit trap in run-pmbootstrap.sh hands /work/packages back to HOST_UID so the runner can read it, and that is the owner the prep layer was tarred with and restores to. abuild runs as pmos and would get EACCES writing the apk into $REPODEST/pmos/aarch64, after however many hours the package stage spent on check. Do what run_abuild() does, in enter(), where this script already redoes its setup. The container's exit trap still hands the directory back to the runner for the upload step. Assisted-by: Claude --- .github/scripts/chromium-stage.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/scripts/chromium-stage.py b/.github/scripts/chromium-stage.py index 971438528b..6a5c5922cd 100755 --- a/.github/scripts/chromium-stage.py +++ b/.github/scripts/chromium-stage.py @@ -149,6 +149,14 @@ def enter() -> tuple[CrossCompile, dict]: print(f"::notice::recreating the cache directory {target}", flush=True) pmb.chroot.root(["mkdir", "-p", target], chroot) pmb.chroot.root(["chown", "pmos:pmos", target], chroot) + # run_abuild() gives $WORK/packages to the chroot's build user, but only + # when it creates the directory. The restored one exists and belongs to + # the runner: run-pmbootstrap.sh hands the work directory back to + # HOST_UID when the prep container exits, and the layer keeps that owner. + # abuild (uid 12345) writes the apks there in the package stage. + uid = pmb.config.chroot_uid_user + subprocess.run(["sudo", "chown", "-R", f"{uid}:{uid}", str(context.config.work / "packages")], + check=True) # What pmb.build.backend.run_abuild() sets up before running abuild. if cross == CrossCompile.CROSS_NATIVE2: pmb.helpers.mount.bind(cross.host_chroot(ARCH).path, chroot / "mnt/sysroot", umount=True) From 1547de086b79ef8684f7f53271af9f09e1ee96cf Mon Sep 17 00:00:00 2001 From: Giuseppe Maggio Date: Wed, 16 Sep 2026 13:06:21 +0200 Subject: [PATCH 3/6] device-google-taimen: use the ngl GTK4 renderer, not the legacy gl one Symbolic icons from the on-disk Adwaita theme drew as solid white quads in a GTK4 header on this device, while icons compiled into GTK itself rendered fine -- which looks like a broken icon theme and is not one. It is the renderer. Measured on one binary in one session: six consecutive captures under GSK_RENDERER=gl were byte-identical squares, and both ngl and cairo drew the icons correctly. Every icon name resolved on disk, so nothing was missing. This is not the a5xx S-order GMEM corruption either. That one flickers frame to frame, and its fix is installed here -- mesa 26.2.2-r51, mapped by both phoc and the app. The gl pin dated from a comment reading "the default ngl/vulkan renderer path is not what this device wants", which conflated two things: Turnip rejecting a5xx is a Vulkan problem, handled by the VK_LOADER_DRIVERS_DISABLE line right below, and ngl does not use Vulkan. No measurement was ever recorded for preferring gl. ngl is what postmarketOS ships as its general Adreno + GTK4 workaround. Assisted-by: Claude --- device/testing/device-google-taimen/APKBUILD | 2 +- .../device-google-taimen/taimen-gsk.conf | 23 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/device/testing/device-google-taimen/APKBUILD b/device/testing/device-google-taimen/APKBUILD index 4eb9f1bae8..1e12a89941 100644 --- a/device/testing/device-google-taimen/APKBUILD +++ b/device/testing/device-google-taimen/APKBUILD @@ -3,7 +3,7 @@ maintainer="Giuseppe Maggio " pkgname=device-google-taimen pkgdesc="Google Pixel 2 XL" pkgver=1 -pkgrel=55 +pkgrel=56 url="https://postmarketos.org" license="MIT" arch="aarch64" diff --git a/device/testing/device-google-taimen/taimen-gsk.conf b/device/testing/device-google-taimen/taimen-gsk.conf index 0cd45137c3..6309b04bdf 100644 --- a/device/testing/device-google-taimen/taimen-gsk.conf +++ b/device/testing/device-google-taimen/taimen-gsk.conf @@ -1,8 +1,25 @@ # GTK4 rendering on an Adreno 540. # -# GSK_RENDERER=gl: the default ngl/vulkan renderer path is not what this device -# wants; GL is, and GL works well here (GL_RENDERER: FD540, OpenGL ES 3.1). -GSK_RENDERER=gl +# GSK_RENDERER=ngl, which is what postmarketOS ships as its general Adreno + +# GTK4 workaround. +# +# This said `gl` until 2026-09-16, on the reasoning that "the default +# ngl/vulkan renderer path is not what this device wants". That conflated two +# separate things: the Vulkan problem is that Turnip rejects a5xx outright, and +# it is handled by VK_LOADER_DRIVERS_DISABLE below. ngl does not use Vulkan at +# all, so nothing about the a5xx Vulkan situation argued for the legacy `gl` +# renderer, and no measurement was recorded for that choice. +# +# What forced the change: under `gl`, symbolic icons in Obscura's header drew +# as solid white quads (alarm-symbolic, preferences-system-symbolic), while +# icons compiled into GTK itself (open-menu-symbolic) rendered fine. Measured +# 2026-09-16 on the same binary and session: six consecutive captures under +# `gl` were byte-identical squares; `ngl` and `cairo` both render the icons +# correctly. The icon files were all present on the device, so this was the +# renderer, NOT a missing icon theme and NOT the a5xx GMEM bin-order +# corruption fixed in mesa r51 -- that one flickered frame to frame, and r51 +# is installed and mapped by both phoc and the app. +GSK_RENDERER=ngl # VK_LOADER_DRIVERS_DISABLE: Turnip covers a6xx and newer. The A540 is a5xx and # never will be supported -- it rejects the device outright: From ae34e9190d9951786afc1d412f6b0c4fffdb67f4 Mon Sep 17 00:00:00 2001 From: Giuseppe Maggio Date: Wed, 30 Sep 2026 14:12:47 +0200 Subject: [PATCH 4/6] ci: refresh branch checks and verified source metadata Assisted-by: Codex --- .github/workflows/build.yml | 2 +- .github/workflows/ci.yml | 6 +++--- device/testing/device-google-taimen/APKBUILD | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78de9f53d5..a521dc6556 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -249,6 +249,6 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 5 steps: - - uses: porthole-dev/.github/actions/ci-passed@06b66d018629f11ebf2e305940855793dbc0b775 # v1.0.0 + - uses: porthole-dev/.github/actions/ci-passed@3bc877e480b528778a6522e396a04f6b2b86884d # v1.0.0 with: results: ${{ join(needs.*.result, ' ') }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 843f0bf34f..1f15a71396 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 5 steps: - - uses: porthole-dev/.github/actions/commit-check@06b66d018629f11ebf2e305940855793dbc0b775 # v1.0.0 + - uses: porthole-dev/.github/actions/commit-check@3bc877e480b528778a6522e396a04f6b2b86884d # v1.0.0 lint: name: Lint APKBUILDs @@ -88,7 +88,7 @@ jobs: with: sparse-checkout: .github persist-credentials: false - - uses: porthole-dev/.github/actions/workflow-lint@06b66d018629f11ebf2e305940855793dbc0b775 # v1.0.0 + - uses: porthole-dev/.github/actions/workflow-lint@3bc877e480b528778a6522e396a04f6b2b86884d # v1.0.0 ci-passed: name: CI passed @@ -97,6 +97,6 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 5 steps: - - uses: porthole-dev/.github/actions/ci-passed@06b66d018629f11ebf2e305940855793dbc0b775 # v1.0.0 + - uses: porthole-dev/.github/actions/ci-passed@3bc877e480b528778a6522e396a04f6b2b86884d # v1.0.0 with: results: ${{ join(needs.*.result, ' ') }} diff --git a/device/testing/device-google-taimen/APKBUILD b/device/testing/device-google-taimen/APKBUILD index 1e12a89941..0f6f390078 100644 --- a/device/testing/device-google-taimen/APKBUILD +++ b/device/testing/device-google-taimen/APKBUILD @@ -605,7 +605,7 @@ eab9f64855751288d2fb07b9fce20c02cdcb89671b561e4e16bf741d5c6b695b250f9ee4b7374bb3 fe7a7ea7bc5410ce6076ba12252ce43f5f26c24d9c92d98f5969ca861c45dad109e3e75dfe7a647a268aa5a5e15dfdf63d87e2f46b63b071d3110933a0f96e3c taimen-ambient-nudge.service 2d33b8083613f9be530f3901655042aad569e735e20208743ed3b605192787775151171e5ad3ae43f8e04a7fd8bccc037fd6450df4fc2d6fa54cf1054ae9fb29 taimen-perf.rules 4d627702857106f4166b011185a7e26573b14f78d833fb21d1be5decda87188a1c2e8d9774f647fe3602205730960fa0522ed95e9a42dcf5278dbc6edff6fa9b taimen-perf.conf -099af1a90fb815ae24831cca5e167f46f53aa9b50517d0d44abe2613aa904545dd3259d9aad8f2f2075130e76ff91dc8081ab719f115f7e0a4b4884f83ab0b78 taimen-gsk.conf +804cc7c384891324003ed6078ebcba12a4c3d8ffb64dc1a70972d26bd3603b372df3bd0f273319f309ff8cd6868ec3e33f3b388b963931189ed33efca79bf9bf taimen-gsk.conf affcfc2eea5afff6b57bdcdcc8173ca30585a088a5d47c38410076d5e3c101ef11506f06a9e2a6b516afa24d6b932a1a6d8549c1f99b848b8121597cae33f28a taimen-av1.conf 12344eff61f411b2c3dfe1d24dd18cd4892321f6236ccd696bfc00c044e7649fb110e47f49bf0f499c14a5e5747433418b276e4261d03387b760cb7d56c984cb taimen-webkit.conf 0cfab60cdd0189965cb0b3902bfc2c3f510d6c1df5499dba97e8cbe35b52b3ad0590278ac952a4cb32f81a4a1ab575cc682717714493e7584435e7ca2e397dc0 taimen-chromium.conf From 1247e60b970c9fc7c6391473eef2aa050b2e672d Mon Sep 17 00:00:00 2001 From: Giuseppe Maggio Date: Wed, 30 Sep 2026 15:19:44 +0200 Subject: [PATCH 5/6] ci: evaluate commits on maintained feature branches Assisted-by: Codex --- .github/workflows/build.yml | 2 +- .github/workflows/ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a521dc6556..17de64d434 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ name: Build on: push: - branches: [taimen-bringup] + branches: ["**"] pull_request: branches: [taimen-bringup] merge_group: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f15a71396..927834c1d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ name: CI on: push: - branches: [taimen-bringup] + branches: ["**"] pull_request: branches: [taimen-bringup] merge_group: From 22df22c95caf1e4edf17ead3f1e80c5dff303d4a Mon Sep 17 00:00:00 2001 From: Giuseppe Maggio Date: Wed, 30 Sep 2026 15:22:52 +0200 Subject: [PATCH 6/6] ci: describe shared action pins without stale version tags Assisted-by: Codex --- .github/workflows/build.yml | 2 +- .github/workflows/ci.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 17de64d434..e4be8edd31 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -249,6 +249,6 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 5 steps: - - uses: porthole-dev/.github/actions/ci-passed@3bc877e480b528778a6522e396a04f6b2b86884d # v1.0.0 + - uses: porthole-dev/.github/actions/ci-passed@3bc877e480b528778a6522e396a04f6b2b86884d # shared release automation with: results: ${{ join(needs.*.result, ' ') }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 927834c1d3..f98798c966 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 5 steps: - - uses: porthole-dev/.github/actions/commit-check@3bc877e480b528778a6522e396a04f6b2b86884d # v1.0.0 + - uses: porthole-dev/.github/actions/commit-check@3bc877e480b528778a6522e396a04f6b2b86884d # shared release automation lint: name: Lint APKBUILDs @@ -88,7 +88,7 @@ jobs: with: sparse-checkout: .github persist-credentials: false - - uses: porthole-dev/.github/actions/workflow-lint@3bc877e480b528778a6522e396a04f6b2b86884d # v1.0.0 + - uses: porthole-dev/.github/actions/workflow-lint@3bc877e480b528778a6522e396a04f6b2b86884d # shared release automation ci-passed: name: CI passed @@ -97,6 +97,6 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 5 steps: - - uses: porthole-dev/.github/actions/ci-passed@3bc877e480b528778a6522e396a04f6b2b86884d # v1.0.0 + - uses: porthole-dev/.github/actions/ci-passed@3bc877e480b528778a6522e396a04f6b2b86884d # shared release automation with: results: ${{ join(needs.*.result, ' ') }}