[SCM] PostGIS branch master updated. 3.7.0beta1-206-g80a9286dba

git at osgeo.org git at osgeo.org
Mon Aug 3 02:44:59 PDT 2026


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "PostGIS".

The branch, master has been updated
       via  80a9286dbacc32ce1538d67745a596b0dd93d52a (commit)
       via  d8acbe05c92d928294cfde1dbb65fdb237924b47 (commit)
       via  621c293ed8f2c076c60d015574a33f8054c3b548 (commit)
       via  2dd6482998dbbcca61b2b2363a6361d05dae7a7d (commit)
       via  c2c14b6b6cd6b077c1241d71c9e782de6f5b7bb5 (commit)
       via  21709044eb0dde1bfb1010e5ed0931a10d164470 (commit)
       via  2883c3b7e5ac6b3e3fd9fc409480fbe26d21e0c9 (commit)
       via  a2fbed92cfdb7c9811c86b4c8d436b5655fb07cb (commit)
       via  4248b65e6b8f117116ebbee9bc13e62feacaf9be (commit)
       via  9451df186a4c519d4544babadc1bebab1fb6e2b9 (commit)
       via  1bcca9054b901f289be2c279a4220316fb04cab1 (commit)
      from  1dea1ba1ade42f25d8d28b981eddd857a6710dae (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 80a9286dbacc32ce1538d67745a596b0dd93d52a
Merge: 1dea1ba1ad d8acbe05c9
Author: Darafei Praliaskouski <komzpa at gmail.com>
Date:   Mon Aug 3 02:44:58 2026 -0700

    Merge pull request 'docs: consolidate CI reference and parity notes' (!558) from Komzpa/postgis:ci/docs-reference-parity-20260727 into master
    
    This consolidates the green CI documentation and parity-map pull requests into
    one review surface.
    
    It also closes the native Windows parity question in the CI map: Linux
    Woodpecker's MinGW+Wine job is documented as MinGW ABI/runtime coverage, while
    GitHub Actions MSYS2 and Jenkins Winnie remain authoritative until OSGeo has a
    licensed Windows Woodie agent with an owner.
    
    It adds 64-bit ARM emulation to the existing Woodpecker portability workflow as
    `portability` / `arm64-berrie64-qemu`. The step uses an arm64 Debian manifest
    digest and the QEMU scheduler label so the Docker backend does not accidentally
    pull or schedule an amd64-only run. This is useful emulated ARM regression
    coverage on amd64 hosts, but it is not native Berrie64 parity: native parity
    still needs a registered `linux/arm64` Woodie agent, a host owner, and a
    maintainer decision.
    
    It keeps the dashboard ownership notes from
    https://gitea.osgeo.org/postgis/postgis/pulls/526, the CI image and runner
    provenance page from https://gitea.osgeo.org/postgis/postgis/pulls/527, the
    native arm64 parity workflow and map from
    https://gitea.osgeo.org/postgis/postgis/pulls/553, and the macOS coverage
    decision page from https://gitea.osgeo.org/postgis/postgis/pulls/555. The
    branch preserves the existing commits and authorship, with only conflict
    resolution needed where the separate documentation changes touched the same CI
    inventory page.
    
    This intentionally does not include
    https://gitea.osgeo.org/postgis/postgis/pulls/528. That failure-debugging guide
    is related documentation work, but its current head is red, so folding it into
    this consolidation would discard green CI for a cosmetic reduction.
    
    Supersedes https://gitea.osgeo.org/postgis/postgis/pulls/526
    Supersedes https://gitea.osgeo.org/postgis/postgis/pulls/527
    Supersedes https://gitea.osgeo.org/postgis/postgis/pulls/553
    Supersedes https://gitea.osgeo.org/postgis/postgis/pulls/555
    
    Reviewed-on: https://gitea.osgeo.org/postgis/postgis/pulls/558


commit d8acbe05c92d928294cfde1dbb65fdb237924b47
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Tue Jul 28 05:37:04 2026 +0400

    ci: run arm64 portability before armhf

diff --git a/.woodpecker/portability.yml b/.woodpecker/portability.yml
index 375afe7431..d6aa7accb1 100644
--- a/.woodpecker/portability.yml
+++ b/.woodpecker/portability.yml
@@ -190,19 +190,6 @@ steps:
       - ./autogen.sh
       - *build-and-test
 
-  arm64-berrie64-qemu:
-    image: arm64v8/debian:trixie-slim at sha256:8b5033c95ca60cdffb0e0f4c446e5f714e82d8960a9ef4153c0eaf13e988b0ea
-    pull: true
-    commands:
-      - uname -m | grep -E '^aarch64$'
-      - export PORTABILITY_TIER=arm64-berrie64-qemu
-      - export PORTABILITY_CFLAGS="-O2 -Wall -Werror -fno-omit-frame-pointer"
-      - *prepare-debian
-      - *abi-env
-      - *start-postgresql
-      - ./autogen.sh
-      - *build-and-test
-
   s390x-big-endian-qemu:
     image: s390x/debian at sha256:4b236f9aafe8a6201c6dca29ce78c28e1eb1e314ecedc2cd2c545f9e49d060e3
     pull: true

commit 621c293ed8f2c076c60d015574a33f8054c3b548
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Tue Jul 28 05:25:19 2026 +0400

    ci: run arm64 QEMU in portability workflow

diff --git a/.woodpecker/arm64.yml b/.woodpecker/arm64.yml
deleted file mode 100644
index 29a61ecb3d..0000000000
--- a/.woodpecker/arm64.yml
+++ /dev/null
@@ -1,172 +0,0 @@
-labels:
-  platform: linux/amd64
-  qemu: "true"
-when:
-  - event: [push, cron]
-    branch: [master, stable-*]
-  - event: tag
-
-# Emulated 64-bit ARM coverage for the current Woodpecker fleet.
-#
-# Native arm64 remains the right replacement for Jenkins Berrie64: QEMU does
-# not cover native timing, atomic-operation, kernel, scheduler, or hardware
-# behavior, and garden plus all-upgrades are too expensive under emulation.
-# The current alternative in Woodpecker is no arm64 lane at all, so this job
-# takes the smaller but real signal from the core extension: 64-bit ARM ABI
-# shape, pointer width, alignment-sensitive execution, char signedness, byte
-# order, dependency detection, build correctness, liblwgeom CUnit, extension
-# install, and a targeted SQL regression slice.
-#
-# The OSGeo build-test image is not used here yet. The postgis-docker image
-# stack has proven linux/arm64 build-test images through a local registry round
-# trip, but repo.osgeo.org/postgis/build-test:debian13 is still published as
-# amd64-only. Switch this job to that image after the docker stack lands and a
-# maintainer publishes the multi-architecture tag.
-#
-# Host requirement: the amd64 Woodie agent host must have persistent
-# binfmt_misc handlers for qemu-aarch64 and advertise the qemu scheduler label.
-# On Debian-family hosts this is provided by qemu-user, qemu-user-binfmt, and
-# binfmt-support.
-variables:
-  arm64-deps: &arm64-deps >-
-    autoconf
-    automake
-    bison
-    build-essential
-    ca-certificates
-    file
-    flex
-    git
-    libcurl4-openssl-dev
-    libcunit1-dev
-    libgeos-dev
-    libjson-c-dev
-    libpcre2-dev
-    libproj-dev
-    libprotobuf-c-dev
-    libtool
-    libxml2-dev
-    locales
-    perl
-    pkg-config
-    postgresql-17
-    postgresql-server-dev-17
-    protobuf-c-compiler
-  arm64-test-script: &arm64-test-script |
-    set -eux
-    export DEBIAN_FRONTEND=noninteractive
-    export SRCDIR="$${CI_WORKSPACE}"
-    mkdir -p "$${TMPDIR:-$${SRCDIR}/.tmp/arm64-qemu-tmp}"
-    setup_start="$$(date +%s)"
-    apt-get update
-    apt-get install -y --no-install-recommends $${ARM64_DEPS}
-    rm -rf /var/lib/apt/lists/*
-    setup_end="$$(date +%s)"
-    echo "MEASURE setup_seconds=$$((setup_end - setup_start))"
-
-    cd "$${SRCDIR}"
-    git config --global --add safe.directory "$${SRCDIR}"
-    runuser -u postgres -- git config --global --add safe.directory "$${SRCDIR}"
-    uname -m | grep -E '^aarch64$'
-    cc --version | sed -n '1p'
-    /usr/lib/postgresql/17/bin/pg_config --version
-
-    build_start="$$(date +%s)"
-    ./autogen.sh
-    rm -rf build/arm64-qemu-pg17
-    mkdir -p build/arm64-qemu-pg17
-    cd build/arm64-qemu-pg17
-    ../../configure \
-      --with-library-minor-version \
-      --disable-spellcheck-tests \
-      --without-interrupt-tests \
-      --without-raster \
-      --without-topology \
-      --without-sfcgal \
-      CFLAGS="-O2 -Wall -fno-omit-frame-pointer -Werror"
-    make -j1
-    build_end="$$(date +%s)"
-    echo "MEASURE build_seconds=$$((build_end - build_start))"
-
-    test_start="$$(date +%s)"
-    make -C liblwgeom/cunit check
-    make install
-    chmod -R a+rwX "$${SRCDIR}/build/arm64-qemu-pg17"
-
-    export PATH=/usr/lib/postgresql/17/bin:$${PATH}
-    export PGROOT="$${SRCDIR}/build/arm64-qemu-pgroot"
-    export PGDATA="$${PGROOT}/data"
-    export PGHOST="$${PGROOT}/socket"
-    export PGUSER=postgres
-    export PGDATABASE=postgres
-    rm -rf "$${PGROOT}"
-    mkdir -p "$${PGROOT}"
-    chown postgres:postgres "$${PGROOT}"
-    runuser -u postgres -- mkdir "$${PGDATA}" "$${PGHOST}"
-    runuser -u postgres -- initdb -D "$${PGDATA}" -A trust --no-sync
-    runuser -u postgres -- pg_ctl -D "$${PGDATA}" \
-      -l "$${PGROOT}/postgresql.log" \
-      -o "-F -k $${PGHOST} -c synchronous_commit=off -c full_page_writes=off" \
-      -w start
-    trap 'runuser -u postgres -- pg_ctl -D "$${PGDATA}" -m fast -w stop || true' EXIT
-    psql -c 'select version()' template1
-
-    export RUNTESTFLAGS="-v --extension"
-    runuser -u postgres -- make -C "$${SRCDIR}/build/arm64-qemu-pg17" check-regress \
-      TESTS="$${SRCDIR}/regress/core/regress_index $${SRCDIR}/regress/core/regress_lrs"
-    runuser -u postgres -- make -C "$${SRCDIR}/build/arm64-qemu-pg17" installcheck-base \
-      TESTS="$${SRCDIR}/regress/core/regress_index $${SRCDIR}/regress/core/regress_lrs"
-    test_end="$$(date +%s)"
-    echo "MEASURE test_seconds=$$((test_end - test_start))"
-
-clone:
-  git:
-    image: woodpeckerci/plugin-git
-    settings:
-      depth: 50
-      partial: false
-
-steps:
-  preflight-arm64-binfmt:
-    image: debian:trixie-slim
-    pull: true
-    commands:
-      - |
-        export DEBIAN_FRONTEND=noninteractive
-        dpkg --add-architecture arm64
-        apt-get update
-        mkdir -p "$${CI_WORKSPACE}/.tmp/arm64-binfmt-preflight"
-        cd "$${CI_WORKSPACE}/.tmp/arm64-binfmt-preflight"
-        apt-get download busybox-static:arm64
-        deb="$$(ls -1 busybox-static_*_arm64.deb | tail -n 1)"
-        root="$${PWD}/arm64"
-        mkdir -p "$${root}"
-        dpkg-deb -x "$${deb}" "$${root}"
-
-        if ! output="$$("$${root}/bin/busybox" uname -m 2>&1)"; then
-          echo "Woodie agent host cannot execute arm64 binaries through binfmt_misc/QEMU."
-          echo "Install qemu-user, qemu-user-binfmt, and binfmt-support on the amd64 agent host."
-          echo "Operator check: docker run --rm --platform=linux/arm64 debian:trixie-slim uname -m"
-          echo "Observed error: $${output}"
-          exit 1
-        fi
-
-        if ! printf '%s\n' "$${output}" | grep -Eq '^aarch64$'; then
-          echo "Woodie agent host executed arm64, but uname -m returned unexpected value: $${output}"
-          echo "Operator check: docker run --rm --platform=linux/arm64 debian:trixie-slim uname -m"
-          exit 1
-        fi
-
-        echo "arm64 foreign execution ok: uname -m -> $${output}"
-
-  arm64-qemu-regress:
-    image: arm64v8/debian:trixie-slim at sha256:8b5033c95ca60cdffb0e0f4c446e5f714e82d8960a9ef4153c0eaf13e988b0ea
-    pull: true
-    depends_on: preflight-arm64-binfmt
-    commands:
-      - /bin/sh -ec "$${ARM64_TEST_SCRIPT}"
-
-matrix:
-  include:
-    - ARM64_DEPS: *arm64-deps
-      ARM64_TEST_SCRIPT: *arm64-test-script
diff --git a/.woodpecker/portability.yml b/.woodpecker/portability.yml
index 6b0eced045..375afe7431 100644
--- a/.woodpecker/portability.yml
+++ b/.woodpecker/portability.yml
@@ -15,10 +15,14 @@ when:
 # Tier 1: armhf via arm32v7/debian under QEMU. This mirrors berrie: 32-bit
 # pointers and long, unsigned char, and stricter alignment than amd64.
 #
-# Tier 2: s390x via s390x/debian under QEMU. This is the practical big-endian
+# Tier 2: arm64 via arm64v8/debian under QEMU. This is an emulated stopgap for
+# the Berrie64 class, not native Berrie64 parity. It proves 64-bit ARM build and
+# regression execution while the project has no native linux/arm64 Woodie agent.
+#
+# Tier 3: s390x via s390x/debian under QEMU. This is the practical big-endian
 # target for WKB/EWKB, TWKB, raster byte order, hashes, and integer memcpy paths.
 #
-# Tier 3 was investigated as Debian Ports powerpc: 32-bit, big-endian, unsigned
+# Tier 4 was investigated as Debian Ports powerpc: 32-bit, big-endian, unsigned
 # char. Docker Hub currently has no official linux/ppc Debian manifest, and the
 # only discovered powerpc Debian image is a removed schema-1 image. Keep this
 # tier out of the required pipeline until there is a maintained OCI image or an
@@ -26,9 +30,9 @@ when:
 # the big-endian and unsigned-char parts of the bug class.
 #
 # QEMU depends on persistent binfmt_misc registrations on the amd64 Woodie agent
-# host, so the scheduler label selects hosts where foreign images can start.
-# Without that label, these jobs can silently land on amd64 hosts without
-# emulation and fail before the step commands run.
+# host and the qemu scheduler label. Woodpecker starts the foreign-architecture
+# step image directly; steps do not need a Docker socket or a nested docker run
+# probe.
 variables:
   native-image: &native-image repo.osgeo.org/postgis/build-test:debian13
   prepare-debian: &prepare-debian |
@@ -150,6 +154,28 @@ steps:
       - ./autogen.sh
       - *build-and-test
 
+  arm64-berrie64-qemu:
+    image: arm64v8/debian:trixie-slim at sha256:8b5033c95ca60cdffb0e0f4c446e5f714e82d8960a9ef4153c0eaf13e988b0ea
+    pull: true
+    # Keep this off broad pull-request runs. The emulated arm64 tier preserves
+    # the former standalone arm64 workflow's branch and cron coverage without
+    # making every contributor wait for expensive QEMU regression coverage.
+    when:
+      - event: push
+        branch:
+          - master
+          - stable-*
+      - event: cron
+    commands:
+      - uname -m | grep -E '^aarch64$'
+      - export PORTABILITY_TIER=arm64-berrie64-qemu
+      - export PORTABILITY_CFLAGS="-O2 -Wall -Werror -fno-omit-frame-pointer"
+      - *prepare-debian
+      - *abi-env
+      - *start-postgresql
+      - ./autogen.sh
+      - *build-and-test
+
   armhf-berrie-qemu:
     image: arm32v7/debian at sha256:743aca1ad24c5e48132df88f561f8d1365bfb6da33e006eb44b44fe32a7a30eb
     pull: true
@@ -164,6 +190,19 @@ steps:
       - ./autogen.sh
       - *build-and-test
 
+  arm64-berrie64-qemu:
+    image: arm64v8/debian:trixie-slim at sha256:8b5033c95ca60cdffb0e0f4c446e5f714e82d8960a9ef4153c0eaf13e988b0ea
+    pull: true
+    commands:
+      - uname -m | grep -E '^aarch64$'
+      - export PORTABILITY_TIER=arm64-berrie64-qemu
+      - export PORTABILITY_CFLAGS="-O2 -Wall -Werror -fno-omit-frame-pointer"
+      - *prepare-debian
+      - *abi-env
+      - *start-postgresql
+      - ./autogen.sh
+      - *build-and-test
+
   s390x-big-endian-qemu:
     image: s390x/debian at sha256:4b236f9aafe8a6201c6dca29ce78c28e1eb1e314ecedc2cd2c545f9e49d060e3
     pull: true
diff --git a/doc/development/testing/ci.md b/doc/development/testing/ci.md
index 339624d21a..3193025434 100644
--- a/doc/development/testing/ci.md
+++ b/doc/development/testing/ci.md
@@ -96,7 +96,7 @@ only overlap part of its defect class.
 | Make Dist | Jenkins Debbie | In flight in <https://gitea.osgeo.org/postgis/postgis/pulls/534>. Until that lands, Woodpecker does not check source distribution tarballs. |
 | FreeBSD and Bessie | GitHub Actions FreeBSD and Jenkins Bessie | In flight in <https://gitea.osgeo.org/postgis/postgis/pulls/549>. YAML running on a Linux container is not FreeBSD parity; this needs a FreeBSD VM or agent surface. |
 | 32-bit ARM and extra portability tiers | Jenkins Berrie | Covered by `.woodpecker/portability.yml` from <https://gitea.osgeo.org/postgis/postgis/pulls/516>, with hostile type-default coverage proposed in <https://gitea.osgeo.org/postgis/postgis/pulls/550>. Plain armhf emulation is useful for pointer-width and alignment assumptions, but the valuable tier is the hostile configuration with explicit type, signedness, alignment, and sanitizer probes. |
-| 64-bit ARM | Jenkins Berrie64 | Partly covered by `.woodpecker/arm64.yml` on amd64 agents through QEMU arm64 emulation. This is core-extension build, ABI, CUnit, install, and targeted SQL smoke coverage, not Berrie64 parity. |
+| 64-bit ARM | Jenkins Berrie64 | Partly covered by the `arm64-berrie64-qemu` child in `.woodpecker/portability.yml` on amd64 agents through QEMU arm64 emulation. This is build, ABI, CUnit, install, and focused regression coverage, not Berrie64 parity. |
 | CodeQL | GitHub Actions | In flight as Woodpecker configuration carried separately. Woodpecker can build a CodeQL database and produce SARIF, but GitHub remains authoritative for code-scanning upload, annotations, and alert management unless Woodie artifact retention and SARIF consumption are also configured. |
 | macOS | GitHub Actions macOS | Not coverable by Woodpecker YAML on Linux. See [macOS coverage options](macos-coverage-options.md) for the actual choices, costs, licensing boundary, and current recommendation. |
 | Native Windows MSYS2 and Winnie | GitHub Actions MSYS2 and Jenkins Winnie | Not covered natively by Linux Woodpecker. MinGW+Wine coverage is valuable ABI/runtime coverage but not native Windows parity. A Woodpecker replacement would need a licensed native Windows agent, registered with Woodie and owned like any other CI host. |
@@ -170,15 +170,14 @@ garden and all-upgrades coverage. QEMU can compile and run a smaller smoke
 suite, but it makes the expensive suites too slow and can hide timing,
 atomic-operation, kernel, and native scheduling behavior.
 
-The Woodpecker arm64 workflow is therefore an explicit stopgap, not parity. It
-runs on amd64 agents through QEMU because the current fleet has no registered
-`linux/arm64` agent. The covered signal is still useful for the core extension:
+The `arm64-berrie64-qemu` Woodpecker portability child is therefore an explicit
+stopgap, not parity. It runs on amd64 agents through QEMU because the current
+fleet has no registered `linux/arm64` agent. The covered signal is still useful:
 64-bit ARM ABI shape, pointer width, alignment-sensitive execution, char
 signedness, byte order, dependency detection, build correctness, liblwgeom
-CUnit, extension install, and targeted SQL regressions. It does not cover
-native CPU timing, atomic operations, kernel behavior, scheduler behavior,
-raster, topology, SFCGAL, garden, all-upgrades, or release-grade Berrie64
-evidence.
+CUnit, extension install, and focused regressions. It does not cover native CPU
+timing, atomic operations, kernel behavior, scheduler behavior, garden,
+all-upgrades, or release-grade Berrie64 evidence.
 
 ## Woodie API and Pipeline Approvals
 

commit 2dd6482998dbbcca61b2b2363a6361d05dae7a7d
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Tue Jul 28 05:23:21 2026 +0400

    ci: pin arm64 Woodie QEMU runner

diff --git a/.woodpecker/arm64.yml b/.woodpecker/arm64.yml
index 88a7a867c6..29a61ecb3d 100644
--- a/.woodpecker/arm64.yml
+++ b/.woodpecker/arm64.yml
@@ -1,5 +1,6 @@
 labels:
   platform: linux/amd64
+  qemu: "true"
 when:
   - event: [push, cron]
     branch: [master, stable-*]
@@ -23,8 +24,9 @@ when:
 # maintainer publishes the multi-architecture tag.
 #
 # Host requirement: the amd64 Woodie agent host must have persistent
-# binfmt_misc handlers for qemu-aarch64. On Debian-family hosts this is provided
-# by qemu-user, qemu-user-binfmt, and binfmt-support.
+# binfmt_misc handlers for qemu-aarch64 and advertise the qemu scheduler label.
+# On Debian-family hosts this is provided by qemu-user, qemu-user-binfmt, and
+# binfmt-support.
 variables:
   arm64-deps: &arm64-deps >-
     autoconf
@@ -158,7 +160,7 @@ steps:
         echo "arm64 foreign execution ok: uname -m -> $${output}"
 
   arm64-qemu-regress:
-    image: arm64v8/debian:trixie-slim
+    image: arm64v8/debian:trixie-slim at sha256:8b5033c95ca60cdffb0e0f4c446e5f714e82d8960a9ef4153c0eaf13e988b0ea
     pull: true
     depends_on: preflight-arm64-binfmt
     commands:

commit c2c14b6b6cd6b077c1241d71c9e782de6f5b7bb5
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Mon Jul 27 20:07:33 2026 +0400

    ci: add emulated arm64 smoke coverage

diff --git a/.woodpecker/arm64.yml b/.woodpecker/arm64.yml
index baefb26573..88a7a867c6 100644
--- a/.woodpecker/arm64.yml
+++ b/.woodpecker/arm64.yml
@@ -1,45 +1,104 @@
 labels:
-  platform: linux/arm64
+  platform: linux/amd64
 when:
-  - event: [push, tag, cron]
+  - event: [push, cron]
     branch: [master, stable-*]
   - event: tag
 
-# Native 64-bit ARM coverage for the Berrie64 defect class. This workflow is
-# intentionally not a QEMU job: the garden and all-upgrades suites are expensive
-# under emulation, and emulation is a poor proxy for native ARM64 timing,
-# alignment, atomic, and kernel behavior.
+# Emulated 64-bit ARM coverage for the current Woodpecker fleet.
 #
-# Required infrastructure: a Woodpecker agent registered with
-# platform=linux/arm64. The current OSGeo build-test image is amd64-only, so the
-# workflow starts from Debian's multi-arch base image and installs build
-# dependencies inside the job.
+# Native arm64 remains the right replacement for Jenkins Berrie64: QEMU does
+# not cover native timing, atomic-operation, kernel, scheduler, or hardware
+# behavior, and garden plus all-upgrades are too expensive under emulation.
+# The current alternative in Woodpecker is no arm64 lane at all, so this job
+# takes the smaller but real signal from the core extension: 64-bit ARM ABI
+# shape, pointer width, alignment-sensitive execution, char signedness, byte
+# order, dependency detection, build correctness, liblwgeom CUnit, extension
+# install, and a targeted SQL regression slice.
+#
+# The OSGeo build-test image is not used here yet. The postgis-docker image
+# stack has proven linux/arm64 build-test images through a local registry round
+# trip, but repo.osgeo.org/postgis/build-test:debian13 is still published as
+# amd64-only. Switch this job to that image after the docker stack lands and a
+# maintainer publishes the multi-architecture tag.
+#
+# Host requirement: the amd64 Woodie agent host must have persistent
+# binfmt_misc handlers for qemu-aarch64. On Debian-family hosts this is provided
+# by qemu-user, qemu-user-binfmt, and binfmt-support.
 variables:
-  test-image: &test-image debian:trixie-slim
-  prepare-debian: &prepare-debian |
+  arm64-deps: &arm64-deps >-
+    autoconf
+    automake
+    bison
+    build-essential
+    ca-certificates
+    file
+    flex
+    git
+    libcurl4-openssl-dev
+    libcunit1-dev
+    libgeos-dev
+    libjson-c-dev
+    libpcre2-dev
+    libproj-dev
+    libprotobuf-c-dev
+    libtool
+    libxml2-dev
+    locales
+    perl
+    pkg-config
+    postgresql-17
+    postgresql-server-dev-17
+    protobuf-c-compiler
+  arm64-test-script: &arm64-test-script |
+    set -eux
     export DEBIAN_FRONTEND=noninteractive
+    export SRCDIR="$${CI_WORKSPACE}"
+    mkdir -p "$${TMPDIR:-$${SRCDIR}/.tmp/arm64-qemu-tmp}"
+    setup_start="$$(date +%s)"
     apt-get update
-    apt-get install -y --no-install-recommends \
-      autoconf automake libtool build-essential ca-certificates pkg-config \
-      postgresql postgresql-server-dev-all \
-      libcunit1-dev libgeos-dev libproj-dev proj-bin libgdal-dev libjson-c-dev \
-      libprotobuf-c-dev protobuf-c-compiler libxml2-dev libxml2-utils \
-      xsltproc docbook-xsl docbook-xml gettext zlib1g-dev
+    apt-get install -y --no-install-recommends $${ARM64_DEPS}
     rm -rf /var/lib/apt/lists/*
-  arm64-env: &arm64-env |
-    export SRCDIR=$${CI_WORKSPACE}
-    export BUILDDIR=$${SRCDIR}/build/arm64-berrie64
-    export PG_MAJOR=$$(pg_config --version | awk '{print $$2}' | cut -d. -f1)
-    export PATH=/usr/lib/postgresql/$${PG_MAJOR}/bin:$${PATH}
-    export PGROOT=$$(mktemp -d)
-    export PGDATA=$${PGROOT}/data
-    export PGHOST=$${PGROOT}/socket
+    setup_end="$$(date +%s)"
+    echo "MEASURE setup_seconds=$$((setup_end - setup_start))"
+
+    cd "$${SRCDIR}"
+    git config --global --add safe.directory "$${SRCDIR}"
+    runuser -u postgres -- git config --global --add safe.directory "$${SRCDIR}"
+    uname -m | grep -E '^aarch64$'
+    cc --version | sed -n '1p'
+    /usr/lib/postgresql/17/bin/pg_config --version
+
+    build_start="$$(date +%s)"
+    ./autogen.sh
+    rm -rf build/arm64-qemu-pg17
+    mkdir -p build/arm64-qemu-pg17
+    cd build/arm64-qemu-pg17
+    ../../configure \
+      --with-library-minor-version \
+      --disable-spellcheck-tests \
+      --without-interrupt-tests \
+      --without-raster \
+      --without-topology \
+      --without-sfcgal \
+      CFLAGS="-O2 -Wall -fno-omit-frame-pointer -Werror"
+    make -j1
+    build_end="$$(date +%s)"
+    echo "MEASURE build_seconds=$$((build_end - build_start))"
+
+    test_start="$$(date +%s)"
+    make -C liblwgeom/cunit check
+    make install
+    chmod -R a+rwX "$${SRCDIR}/build/arm64-qemu-pg17"
+
+    export PATH=/usr/lib/postgresql/17/bin:$${PATH}
+    export PGROOT="$${SRCDIR}/build/arm64-qemu-pgroot"
+    export PGDATA="$${PGROOT}/data"
+    export PGHOST="$${PGROOT}/socket"
     export PGUSER=postgres
     export PGDATABASE=postgres
-    uname -m | grep -E '^(aarch64|arm64)$'
-    dpkg-architecture -qDEB_HOST_GNU_TYPE
-    pg_config --version
-  start-postgresql: &start-postgresql |
+    rm -rf "$${PGROOT}"
+    mkdir -p "$${PGROOT}"
     chown postgres:postgres "$${PGROOT}"
     runuser -u postgres -- mkdir "$${PGDATA}" "$${PGHOST}"
     runuser -u postgres -- initdb -D "$${PGDATA}" -A trust --no-sync
@@ -49,18 +108,14 @@ variables:
       -w start
     trap 'runuser -u postgres -- pg_ctl -D "$${PGDATA}" -m fast -w stop || true' EXIT
     psql -c 'select version()' template1
-  build-install-and-check: &build-install-and-check |
-    mkdir -p "$${BUILDDIR}"
-    cd "$${BUILDDIR}"
-    "$${SRCDIR}/configure" \
-      --with-raster \
-      --with-library-minor-version \
-      --without-interrupt-tests \
-      CFLAGS="-O2 -Wall -Werror -fno-omit-frame-pointer"
-    make -j1
-    make check RUNTESTFLAGS="-v"
-    make install
-    make check RUNTESTFLAGS="-v --extension"
+
+    export RUNTESTFLAGS="-v --extension"
+    runuser -u postgres -- make -C "$${SRCDIR}/build/arm64-qemu-pg17" check-regress \
+      TESTS="$${SRCDIR}/regress/core/regress_index $${SRCDIR}/regress/core/regress_lrs"
+    runuser -u postgres -- make -C "$${SRCDIR}/build/arm64-qemu-pg17" installcheck-base \
+      TESTS="$${SRCDIR}/regress/core/regress_index $${SRCDIR}/regress/core/regress_lrs"
+    test_end="$$(date +%s)"
+    echo "MEASURE test_seconds=$$((test_end - test_start))"
 
 clone:
   git:
@@ -70,28 +125,46 @@ clone:
       partial: false
 
 steps:
-  berrie64-native-regress:
-    image: *test-image
+  preflight-arm64-binfmt:
+    image: debian:trixie-slim
     pull: true
     commands:
-      - *prepare-debian
-      - *arm64-env
-      - *start-postgresql
-      - ./autogen.sh
-      - *build-install-and-check
-
-  berrie64-native-garden-upgrades:
-    image: *test-image
-    pull: true
-    depends_on: berrie64-native-regress
-    commands:
-      - *prepare-debian
-      - *arm64-env
-      - *start-postgresql
-      - ./autogen.sh
-      - *build-install-and-check
-      - cd "$${BUILDDIR}"
-      - make garden EXAMPLETEST_CHECK_ENVIRONMENT=no
       - |
-        "$${SRCDIR}/utils/check_all_upgrades.sh" \
-          "$$(grep '^POSTGIS_' "$${SRCDIR}/Version.config" | cut -d= -f2 | paste -sd '.')"
+        export DEBIAN_FRONTEND=noninteractive
+        dpkg --add-architecture arm64
+        apt-get update
+        mkdir -p "$${CI_WORKSPACE}/.tmp/arm64-binfmt-preflight"
+        cd "$${CI_WORKSPACE}/.tmp/arm64-binfmt-preflight"
+        apt-get download busybox-static:arm64
+        deb="$$(ls -1 busybox-static_*_arm64.deb | tail -n 1)"
+        root="$${PWD}/arm64"
+        mkdir -p "$${root}"
+        dpkg-deb -x "$${deb}" "$${root}"
+
+        if ! output="$$("$${root}/bin/busybox" uname -m 2>&1)"; then
+          echo "Woodie agent host cannot execute arm64 binaries through binfmt_misc/QEMU."
+          echo "Install qemu-user, qemu-user-binfmt, and binfmt-support on the amd64 agent host."
+          echo "Operator check: docker run --rm --platform=linux/arm64 debian:trixie-slim uname -m"
+          echo "Observed error: $${output}"
+          exit 1
+        fi
+
+        if ! printf '%s\n' "$${output}" | grep -Eq '^aarch64$'; then
+          echo "Woodie agent host executed arm64, but uname -m returned unexpected value: $${output}"
+          echo "Operator check: docker run --rm --platform=linux/arm64 debian:trixie-slim uname -m"
+          exit 1
+        fi
+
+        echo "arm64 foreign execution ok: uname -m -> $${output}"
+
+  arm64-qemu-regress:
+    image: arm64v8/debian:trixie-slim
+    pull: true
+    depends_on: preflight-arm64-binfmt
+    commands:
+      - /bin/sh -ec "$${ARM64_TEST_SCRIPT}"
+
+matrix:
+  include:
+    - ARM64_DEPS: *arm64-deps
+      ARM64_TEST_SCRIPT: *arm64-test-script
diff --git a/doc/development/testing/ci.md b/doc/development/testing/ci.md
index 54ce16d064..339624d21a 100644
--- a/doc/development/testing/ci.md
+++ b/doc/development/testing/ci.md
@@ -96,7 +96,7 @@ only overlap part of its defect class.
 | Make Dist | Jenkins Debbie | In flight in <https://gitea.osgeo.org/postgis/postgis/pulls/534>. Until that lands, Woodpecker does not check source distribution tarballs. |
 | FreeBSD and Bessie | GitHub Actions FreeBSD and Jenkins Bessie | In flight in <https://gitea.osgeo.org/postgis/postgis/pulls/549>. YAML running on a Linux container is not FreeBSD parity; this needs a FreeBSD VM or agent surface. |
 | 32-bit ARM and extra portability tiers | Jenkins Berrie | Covered by `.woodpecker/portability.yml` from <https://gitea.osgeo.org/postgis/postgis/pulls/516>, with hostile type-default coverage proposed in <https://gitea.osgeo.org/postgis/postgis/pulls/550>. Plain armhf emulation is useful for pointer-width and alignment assumptions, but the valuable tier is the hostile configuration with explicit type, signedness, alignment, and sanitizer probes. |
-| 64-bit ARM | Jenkins Berrie64 | Covered by `.woodpecker/arm64.yml` only when the fleet has a native `linux/arm64` agent. The workflow intentionally has no QEMU fallback. |
+| 64-bit ARM | Jenkins Berrie64 | Partly covered by `.woodpecker/arm64.yml` on amd64 agents through QEMU arm64 emulation. This is core-extension build, ABI, CUnit, install, and targeted SQL smoke coverage, not Berrie64 parity. |
 | CodeQL | GitHub Actions | In flight as Woodpecker configuration carried separately. Woodpecker can build a CodeQL database and produce SARIF, but GitHub remains authoritative for code-scanning upload, annotations, and alert management unless Woodie artifact retention and SARIF consumption are also configured. |
 | macOS | GitHub Actions macOS | Not coverable by Woodpecker YAML on Linux. See [macOS coverage options](macos-coverage-options.md) for the actual choices, costs, licensing boundary, and current recommendation. |
 | Native Windows MSYS2 and Winnie | GitHub Actions MSYS2 and Jenkins Winnie | Not covered natively by Linux Woodpecker. MinGW+Wine coverage is valuable ABI/runtime coverage but not native Windows parity. A Woodpecker replacement would need a licensed native Windows agent, registered with Woodie and owned like any other CI host. |
@@ -166,11 +166,19 @@ and sanitizer settings catch assumptions that amd64 and a plain Berrie rerun do
 not falsify.
 
 The 64-bit lane should be native. Berrie64's value is 64-bit ARM execution plus
-garden and all-upgrades coverage. QEMU can compile and run some smoke tests, but
-it makes the expensive suites too slow and can hide timing, atomic-operation,
-kernel, and native scheduling behavior. The Woodpecker arm64 workflow therefore
-requires a registered `linux/arm64` agent and intentionally avoids an emulated
-fallback.
+garden and all-upgrades coverage. QEMU can compile and run a smaller smoke
+suite, but it makes the expensive suites too slow and can hide timing,
+atomic-operation, kernel, and native scheduling behavior.
+
+The Woodpecker arm64 workflow is therefore an explicit stopgap, not parity. It
+runs on amd64 agents through QEMU because the current fleet has no registered
+`linux/arm64` agent. The covered signal is still useful for the core extension:
+64-bit ARM ABI shape, pointer width, alignment-sensitive execution, char
+signedness, byte order, dependency detection, build correctness, liblwgeom
+CUnit, extension install, and targeted SQL regressions. It does not cover
+native CPU timing, atomic operations, kernel behavior, scheduler behavior,
+raster, topology, SFCGAL, garden, all-upgrades, or release-grade Berrie64
+evidence.
 
 ## Woodie API and Pipeline Approvals
 

commit 21709044eb0dde1bfb1010e5ed0931a10d164470
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Mon Jul 27 18:22:44 2026 +0400

    Document native Windows CI parity verdict

diff --git a/doc/development/testing/ci.md b/doc/development/testing/ci.md
index 77a453a195..54ce16d064 100644
--- a/doc/development/testing/ci.md
+++ b/doc/development/testing/ci.md
@@ -99,7 +99,7 @@ only overlap part of its defect class.
 | 64-bit ARM | Jenkins Berrie64 | Covered by `.woodpecker/arm64.yml` only when the fleet has a native `linux/arm64` agent. The workflow intentionally has no QEMU fallback. |
 | CodeQL | GitHub Actions | In flight as Woodpecker configuration carried separately. Woodpecker can build a CodeQL database and produce SARIF, but GitHub remains authoritative for code-scanning upload, annotations, and alert management unless Woodie artifact retention and SARIF consumption are also configured. |
 | macOS | GitHub Actions macOS | Not coverable by Woodpecker YAML on Linux. See [macOS coverage options](macos-coverage-options.md) for the actual choices, costs, licensing boundary, and current recommendation. |
-| Native Windows MSYS2 and Winnie | GitHub Actions MSYS2 and Jenkins Winnie | Not covered natively by Linux Woodpecker. MinGW+Wine coverage is valuable ABI/runtime coverage but not native Windows parity. |
+| Native Windows MSYS2 and Winnie | GitHub Actions MSYS2 and Jenkins Winnie | Not covered natively by Linux Woodpecker. MinGW+Wine coverage is valuable ABI/runtime coverage but not native Windows parity. A Woodpecker replacement would need a licensed native Windows agent, registered with Woodie and owned like any other CI host. |
 
 The companion inventory and debugging documents are deliberately narrower than
 this parity map. Dashboard ownership, CI image provenance, and failure-debugging
@@ -120,6 +120,34 @@ behavior, Windows CRT, locale and codepage behavior, native threading and file
 locking, DLL search order, and failures where Wine itself may be the broken
 component.
 
+Do not treat a Linux-hosted cross build as closure of the native Windows gap.
+The practical replacement shape is a Windows agent registered with Woodie,
+running either the MSYS2 workflow or the Winnie script family on a licensed
+Windows installation, with an owner who keeps the host patched and credentials
+rotated.
+
+The project investigated Microsoft evaluation VM images as a possible
+zero-cost route for such an agent in July 2026. That investigation downloaded
+the Windows 11 development environment Hyper-V VHDX, converted it for QEMU/KVM,
+and reached the UEFI handoff to Windows Boot Manager. It did not reach a login
+prompt, run PostGIS, or prove an unattended Windows CI path; the attempts ended
+when the driving automation session lost its connection, not because Windows
+refused to boot.
+
+Licensing is the durable blocker for making that experiment a standing CI
+service. Microsoft documents Windows 11 Enterprise evaluation media as a
+90-day evaluation and notes that an expired or unactivated evaluation shuts down
+periodically. The Windows development VM is an evaluation image, not a stable
+renewable CI entitlement. Windows Server evaluation media are similarly trial
+media, with a 180-day duration, while the Windows Server license terms limit
+evaluation software to evaluation, test, or demonstration use and prohibit
+production-environment use after the evaluation period. A legitimate unattended
+PostGIS Windows agent therefore needs OSGeo-provided Windows licensing, such as
+proper Windows Server VM licensing or Windows Enterprise/VDA licensing for a
+desktop VM, plus a named host owner. Until that exists, keep GitHub Actions
+MSYS2 and Jenkins Winnie authoritative for native Windows behavior and describe
+Linux Woodpecker's MinGW+Wine job as MinGW ABI/runtime coverage only.
+
 ### macOS
 
 macOS cannot be covered by Linux containers, Wine, or cross-compilation. Darwin

commit 2883c3b7e5ac6b3e3fd9fc409480fbe26d21e0c9
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Mon Jul 27 14:18:43 2026 +0400

    ci: run arm64 Woodie coverage on stable branches

diff --git a/.woodpecker/arm64.yml b/.woodpecker/arm64.yml
index 68f8f1edf4..baefb26573 100644
--- a/.woodpecker/arm64.yml
+++ b/.woodpecker/arm64.yml
@@ -2,7 +2,7 @@ labels:
   platform: linux/arm64
 when:
   - event: [push, tag, cron]
-    branch: master
+    branch: [master, stable-*]
   - event: tag
 
 # Native 64-bit ARM coverage for the Berrie64 defect class. This workflow is

commit a2fbed92cfdb7c9811c86b4c8d436b5655fb07cb
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Mon Jul 27 11:01:48 2026 +0400

    docs: document macOS CI coverage options

diff --git a/doc/development/environment/macos.md b/doc/development/environment/macos.md
index ac5319fea2..628f54bec9 100644
--- a/doc/development/environment/macos.md
+++ b/doc/development/environment/macos.md
@@ -9,7 +9,10 @@ The current macOS pull-request build is defined in
 `.github/workflows/ci-macos.yml`. Use that workflow as the source of truth when
 checking platform-specific dependencies or flags.
 
-At the time of this note, the job uses `macos-latest`, Homebrew, PostgreSQL 17,
+For the decision about whether Woodpecker should grow native Darwin coverage,
+see [macOS coverage options](../testing/macos-coverage-options.md).
+
+At the time of this note, the job uses `macos-latest`, Homebrew, PostgreSQL 18,
 and clang through ccache. It builds the topology, SFCGAL, and protobuf paths,
 but disables raster, GUI, and interrupt tests:
 
@@ -21,7 +24,7 @@ brew install \
   gdal geos icu4c json-c libpq libxml2 \
   proj protobuf-c sfcgal cunit \
   docbook docbook-xsl \
-  postgresql at 17 gettext
+  postgresql at 18 gettext
 brew link --force gettext
 ```
 
@@ -29,10 +32,10 @@ The workflow exports Homebrew include and library paths before configuring:
 
 ```sh
 export HOMEBREW_PREFIX=/opt/homebrew
-export PATH="${HOMEBREW_PREFIX}/opt/postgresql at 17/bin:${HOMEBREW_PREFIX}/bin:${HOMEBREW_PREFIX}/sbin:${HOMEBREW_PREFIX}/opt/ccache/libexec:${PATH}"
-export PGCONFIG="${HOMEBREW_PREFIX}/opt/postgresql at 17/bin/pg_config"
-export CFLAGS="-I${HOMEBREW_PREFIX}/opt/gettext/include -I${HOMEBREW_PREFIX}/opt/postgresql at 17/include -I${HOMEBREW_PREFIX}/include -Wno-nullability-completeness"
-export LDFLAGS="-L${HOMEBREW_PREFIX}/opt/gettext/lib -L${HOMEBREW_PREFIX}/opt/postgresql at 17/lib"
+export PATH="${HOMEBREW_PREFIX}/opt/postgresql at 18/bin:${HOMEBREW_PREFIX}/bin:${HOMEBREW_PREFIX}/sbin:${HOMEBREW_PREFIX}/opt/ccache/libexec:${PATH}"
+export PGCONFIG="${HOMEBREW_PREFIX}/opt/postgresql at 18/bin/pg_config"
+export CFLAGS="-I${HOMEBREW_PREFIX}/opt/gettext/include -I${HOMEBREW_PREFIX}/opt/postgresql at 18/include -I${HOMEBREW_PREFIX}/include -Wno-nullability-completeness"
+export LDFLAGS="-L${HOMEBREW_PREFIX}/opt/gettext/lib -L${HOMEBREW_PREFIX}/opt/postgresql at 18/lib"
 export CXXFLAGS="-std=c++17"
 export CC="ccache clang"
 export CXX="ccache clang++"
@@ -51,11 +54,11 @@ Then it runs:
   --with-protobuf \
   --with-pgconfig="${PGCONFIG}"
 
-brew services start postgresql at 17
+brew services start postgresql at 18
 make -j"$(sysctl -n hw.logicalcpu)"
 sudo make install
 make -j"$(sysctl -n hw.logicalcpu)" check RUNTESTFLAGS="-v --extension --dumprestore"
-brew services stop postgresql at 17
+brew services stop postgresql at 18
 ```
 
 If local behavior differs from CI, first compare the local Homebrew package
diff --git a/doc/development/testing/_index.md b/doc/development/testing/_index.md
index 8d6f12876e..105e89e37a 100644
--- a/doc/development/testing/_index.md
+++ b/doc/development/testing/_index.md
@@ -168,6 +168,9 @@ Other useful targets:
   full run when the gate is wrong.
 * [CI images and runners](ci-images-runners.md) maps the container image
   families, Woodie agents, and Jenkins worker setup repositories used by CI.
+* [macOS coverage options](macos-coverage-options.md) records why Woodpecker
+  cannot cover Darwin by Linux configuration alone, the real Apple-runner
+  options, and the current recommendation.
 
 ## Garden Checks
 
diff --git a/doc/development/testing/ci.md b/doc/development/testing/ci.md
index 15dfe8294e..77a453a195 100644
--- a/doc/development/testing/ci.md
+++ b/doc/development/testing/ci.md
@@ -98,7 +98,7 @@ only overlap part of its defect class.
 | 32-bit ARM and extra portability tiers | Jenkins Berrie | Covered by `.woodpecker/portability.yml` from <https://gitea.osgeo.org/postgis/postgis/pulls/516>, with hostile type-default coverage proposed in <https://gitea.osgeo.org/postgis/postgis/pulls/550>. Plain armhf emulation is useful for pointer-width and alignment assumptions, but the valuable tier is the hostile configuration with explicit type, signedness, alignment, and sanitizer probes. |
 | 64-bit ARM | Jenkins Berrie64 | Covered by `.woodpecker/arm64.yml` only when the fleet has a native `linux/arm64` agent. The workflow intentionally has no QEMU fallback. |
 | CodeQL | GitHub Actions | In flight as Woodpecker configuration carried separately. Woodpecker can build a CodeQL database and produce SARIF, but GitHub remains authoritative for code-scanning upload, annotations, and alert management unless Woodie artifact retention and SARIF consumption are also configured. |
-| macOS | GitHub Actions macOS | Not coverable by Woodpecker YAML on Linux. Keep GitHub Actions as the Darwin lane, operate an Apple Woodpecker agent, or accept no Darwin coverage. |
+| macOS | GitHub Actions macOS | Not coverable by Woodpecker YAML on Linux. See [macOS coverage options](macos-coverage-options.md) for the actual choices, costs, licensing boundary, and current recommendation. |
 | Native Windows MSYS2 and Winnie | GitHub Actions MSYS2 and Jenkins Winnie | Not covered natively by Linux Woodpecker. MinGW+Wine coverage is valuable ABI/runtime coverage but not native Windows parity. |
 
 The companion inventory and debugging documents are deliberately narrower than
@@ -125,8 +125,10 @@ component.
 macOS cannot be covered by Linux containers, Wine, or cross-compilation. Darwin
 libc, the Mach-O dynamic loader, Homebrew's dependency graph, Apple clang, the
 filesystem, and codesign or SIP-adjacent behavior have to run on macOS to be
-meaningful. The realistic choices are an Apple Woodpecker agent, GitHub Actions
-as the Darwin lane, or no Darwin parity.
+meaningful. The realistic choices are documented in
+[macOS coverage options](macos-coverage-options.md): keep GitHub Actions as the
+Darwin lane, run a hosted or project-owned Apple Woodpecker agent, or accept no
+Darwin coverage.
 
 ### ARM
 
diff --git a/doc/development/testing/macos-coverage-options.md b/doc/development/testing/macos-coverage-options.md
new file mode 100644
index 0000000000..aa4426a755
--- /dev/null
+++ b/doc/development/testing/macos-coverage-options.md
@@ -0,0 +1,118 @@
+---
+title: "macOS Coverage Options"
+date: 2026-07-27
+weight: 11
+geekdocHidden: false
+---
+
+The macOS CI job is not a Woodpecker configuration gap. The current Darwin
+coverage is the GitHub Actions workflow in `.github/workflows/ci-macos.yml`,
+which runs on `macos-latest`, installs dependencies with Homebrew, builds with
+Apple clang and Darwin `make`, installs PostGIS, and runs regression tests with
+extension and dump/restore coverage.
+
+Woodpecker jobs running on Linux cannot substitute for that lane. Containers,
+Wine, and cross-compilation do not exercise Darwin libc, the Mach-O dynamic
+loader, Homebrew's dependency graph, Apple clang, Darwin filesystem behavior, or
+codesign and SIP-adjacent behavior. Real macOS coverage needs macOS on Apple
+hardware.
+
+## Option 1: Keep GitHub Actions Authoritative
+
+This is the recommended default.
+
+PostGIS keeps the current GitHub Actions macOS job as the authoritative Darwin
+signal and does not try to make Woodpecker claim full parity. The project loses
+one property: Woodpecker cannot independently prove every release and pull
+request platform from the OSGeo CI surface alone.
+
+If GitHub Actions is unavailable, if `macos-latest` changes underneath the
+workflow, or if GitHub changes access to macOS runners, the project loses the
+Darwin signal until the workflow is updated or another Apple runner is
+available. That does not by itself block source tarball creation, Debbie release
+jobs, Winnie jobs, or Linux/FreeBSD/ARM Woodpecker coverage, but the release
+greenlight checklist's "all bots are green" check should treat the Darwin row as
+unknown rather than green.
+
+The cost is the existing GitHub Actions dependency. As of 2026-07-27, GitHub's
+published hosted-runner rates list standard macOS at `$0.062` per minute,
+larger macOS at `$0.077` per minute, and M2 Pro larger macOS at `$0.102` per
+minute. Public-repository billing and organization quotas are GitHub account
+policy, not a PostGIS repository setting, so the operational risk is runner
+availability and image churn more than direct per-minute cost in this repo.
+
+## Option 2: Register A Hosted Apple Runner As A Woodpecker Agent
+
+This gives Woodpecker real Darwin coverage, but it creates a standing hosted
+machine to administer.
+
+Representative hosted Apple hardware prices found on 2026-07-27:
+
+| Provider | Representative published price | Third-party agent feasibility |
+| -------- | ------------------------------ | ----------------------------- |
+| MacStadium | M2 Mac mini from `$109` per month; M4 Mac mini from `$149` per month | Suitable in principle. The product is dedicated Apple hardware with root access, a dedicated IP address, and current macOS, so a Woodpecker agent can be installed by the project. |
+| Macly | M4 Mac mini `$99.99` per month or `$14.99` per day | Suitable in principle. The product advertises full SSH/admin access and explicitly says users can install any CI/CD agent. |
+| Scaleway Apple Mac mini | M4 advertised at `EUR 0.22` per hour in Scaleway's product announcement, about `EUR 160.60` for a 730-hour month before tax; the product page describes dedicated Mac minis reachable over remote desktop or SSH | Suitable in principle. The product exposes a dedicated Mac mini and documents runner setup; the project would administer the Woodpecker agent. |
+| AWS EC2 Mac Dedicated Host | `mac2-m2` listed at `$0.878` per host-hour and `mac-m4` listed on the dedicated-host price table; EC2 Mac hosts have a 24-hour minimum allocation | Technically suitable but usually too expensive for always-on open-source CI. It is dedicated Apple hardware presented as EC2 infrastructure, so installing an agent is possible, but the host-hour model makes it a poor fit for a mostly idle PostGIS Darwin lane. |
+| MacinCloud Dedicated Server | Dedicated server advertised from `$49` per month | Possibly suitable only for tiers with full administrator/root access. Shared or managed remote-desktop plans are not enough for an unattended Woodpecker agent. |
+
+The real total is provider cost plus OS patching, Homebrew cache and package
+maintenance, Woodpecker secret handling, runner upgrades, monitoring, and a
+named administrator. If nobody owns those tasks, the hosted runner will become a
+stale red CI row rather than useful parity.
+
+## Option 3: Project-Owned Apple Hardware
+
+A project-owned Mac mini is the usual physical answer. As of 2026-07-27,
+Apple's US shop structured product data listed the Mac mini aggregate low price
+as `$799`, with M4 and M4 Pro configurations available. The CI total is not only
+the purchase price:
+
+* a Mac mini with enough RAM and storage for Homebrew, PostgreSQL, build trees,
+  and ccache;
+* hosting on an OSGeo-administered buildbot network or on a trusted
+  maintainer's desk;
+* outbound network access to `woodie.osgeo.org`, plus a policy for inbound SSH
+  or VPN administration if needed;
+* power, storage replacement, OS upgrades, reboots, and physical recovery;
+* a named administrator who keeps the Woodpecker agent, Homebrew dependencies,
+  and macOS updates current.
+
+OSGeo already hosts buildbots, so this is not a new infrastructure category.
+The decision is whether the incremental Apple-hardware ownership and
+administration cost is worth moving the Darwin signal from GitHub Actions into
+Woodpecker.
+
+## Option 4: Virtualized macOS
+
+Virtualized macOS is only a compliant CI option when it runs on Apple hardware.
+Apple's current macOS license permits up to two additional macOS instances in
+virtual operating system environments on each Apple-branded computer the
+licensee owns or controls and that is already running macOS, for software
+development and testing. The same license language does not permit using those
+virtualized copies for service-bureau, time-sharing, terminal-sharing, relay, or
+similar services.
+
+That permits a project-owned or hosted Apple machine to run macOS VMs for
+isolation and reproducibility, subject to the license and the provider's terms.
+It does not permit a Linux KVM host, ordinary cloud VM, or non-Apple bare-metal
+host to run macOS as a Woodpecker substitute.
+
+## Recommendation
+
+Keep GitHub Actions authoritative for Darwin and record the Woodpecker row as
+not coverable by configuration alone.
+
+The maintainer-disagreeable version of the reasoning is simple: Darwin coverage
+matters, but PostGIS does not currently have enough macOS-specific failure rate
+or release dependency to justify adding a permanent Apple machine and a named
+administrator. The cheapest credible hosted option is about `$100` to `$150` per
+month before maintenance time. A project-owned Mac mini lowers recurring rental
+cost but replaces it with physical hosting and administration. AWS is too
+expensive for an always-on lane. Virtualized macOS is useful only after the
+project already has Apple hardware, so it is not a way around the ownership
+decision.
+
+Revisit this decision if GitHub Actions macOS becomes unavailable for the
+project, if a recurring Darwin-only defect starts escaping releases, or if OSGeo
+accepts a named owner and budget for an Apple Woodpecker agent.

commit 4248b65e6b8f117116ebbee9bc13e62feacaf9be
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Mon Jul 27 09:46:05 2026 +0400

    ci: document parity map and add native arm64 workflow

diff --git a/.woodpecker/arm64.yml b/.woodpecker/arm64.yml
index a37119ad97..68f8f1edf4 100644
--- a/.woodpecker/arm64.yml
+++ b/.woodpecker/arm64.yml
@@ -1,36 +1,34 @@
 labels:
-  platform: linux/amd64
-  qemu: "true"
+  platform: linux/arm64
 when:
-  - event: push
-    branch:
-      - master
-      - stable-*
-  - event: cron
+  - event: [push, tag, cron]
+    branch: master
+  - event: tag
 
-# This workflow gives Woodpecker a 64-bit ARM row matching Jenkins Berrie64.
-# It catches little beyond that platform parity: unlike armhf it exercises the
-# aarch64 64-bit ABI, and unlike s390x it stays little-endian. Keep it off pull
-# requests because arm64 emulation is expensive.
+# Native 64-bit ARM coverage for the Berrie64 defect class. This workflow is
+# intentionally not a QEMU job: the garden and all-upgrades suites are expensive
+# under emulation, and emulation is a poor proxy for native ARM64 timing,
+# alignment, atomic, and kernel behavior.
 #
-# The image is pinned to the linux/arm64/v8 manifest digest. A tag-only pull
-# from an amd64 Docker backend can resolve an amd64 variant and fail before QEMU
-# is involved, so do not replace this with arm64v8/debian:trixie-slim alone.
+# Required infrastructure: a Woodpecker agent registered with
+# platform=linux/arm64. The current OSGeo build-test image is amd64-only, so the
+# workflow starts from Debian's multi-arch base image and installs build
+# dependencies inside the job.
 variables:
-  arm64-image: &arm64-image arm64v8/debian:trixie-slim at sha256:8b5033c95ca60cdffb0e0f4c446e5f714e82d8960a9ef4153c0eaf13e988b0ea
+  test-image: &test-image debian:trixie-slim
   prepare-debian: &prepare-debian |
     export DEBIAN_FRONTEND=noninteractive
     apt-get update
     apt-get install -y --no-install-recommends \
       autoconf automake libtool build-essential ca-certificates pkg-config \
-      bison flex \
       postgresql postgresql-server-dev-all \
-      libcunit1-dev libgeos-dev libproj-dev libgdal-dev libjson-c-dev \
-      libprotobuf-c-dev protobuf-c-compiler libxml2-dev gettext zlib1g-dev
+      libcunit1-dev libgeos-dev libproj-dev proj-bin libgdal-dev libjson-c-dev \
+      libprotobuf-c-dev protobuf-c-compiler libxml2-dev libxml2-utils \
+      xsltproc docbook-xsl docbook-xml gettext zlib1g-dev
     rm -rf /var/lib/apt/lists/*
   arm64-env: &arm64-env |
     export SRCDIR=$${CI_WORKSPACE}
-    export BUILDDIR=$${SRCDIR}/build/arm64-qemu
+    export BUILDDIR=$${SRCDIR}/build/arm64-berrie64
     export PG_MAJOR=$$(pg_config --version | awk '{print $$2}' | cut -d. -f1)
     export PATH=/usr/lib/postgresql/$${PG_MAJOR}/bin:$${PATH}
     export PGROOT=$$(mktemp -d)
@@ -38,7 +36,7 @@ variables:
     export PGHOST=$${PGROOT}/socket
     export PGUSER=postgres
     export PGDATABASE=postgres
-    uname -m
+    uname -m | grep -E '^(aarch64|arm64)$'
     dpkg-architecture -qDEB_HOST_GNU_TYPE
     pg_config --version
   start-postgresql: &start-postgresql |
@@ -51,6 +49,18 @@ variables:
       -w start
     trap 'runuser -u postgres -- pg_ctl -D "$${PGDATA}" -m fast -w stop || true' EXIT
     psql -c 'select version()' template1
+  build-install-and-check: &build-install-and-check |
+    mkdir -p "$${BUILDDIR}"
+    cd "$${BUILDDIR}"
+    "$${SRCDIR}/configure" \
+      --with-raster \
+      --with-library-minor-version \
+      --without-interrupt-tests \
+      CFLAGS="-O2 -Wall -Werror -fno-omit-frame-pointer"
+    make -j1
+    make check RUNTESTFLAGS="-v"
+    make install
+    make check RUNTESTFLAGS="-v --extension"
 
 clone:
   git:
@@ -60,24 +70,28 @@ clone:
       partial: false
 
 steps:
-  build-regress:
-    image: *arm64-image
+  berrie64-native-regress:
+    image: *test-image
     pull: true
     commands:
-      - uname -m | grep -E '^aarch64$'
       - *prepare-debian
       - *arm64-env
       - *start-postgresql
       - ./autogen.sh
-      - mkdir -p "$${BUILDDIR}"
+      - *build-install-and-check
+
+  berrie64-native-garden-upgrades:
+    image: *test-image
+    pull: true
+    depends_on: berrie64-native-regress
+    commands:
+      - *prepare-debian
+      - *arm64-env
+      - *start-postgresql
+      - ./autogen.sh
+      - *build-install-and-check
       - cd "$${BUILDDIR}"
-      - >-
-        "$${SRCDIR}/configure"
-        --with-raster
-        --without-topology
-        --without-sfcgal
-        --without-interrupt-tests
-      - make -j1
-      - make -C liblwgeom check-unit
-      - make install
-      - make -C regress check RUNTESTFLAGS="-v --extension"
+      - make garden EXAMPLETEST_CHECK_ENVIRONMENT=no
+      - |
+        "$${SRCDIR}/utils/check_all_upgrades.sh" \
+          "$$(grep '^POSTGIS_' "$${SRCDIR}/Version.config" | cut -d= -f2 | paste -sd '.')"
diff --git a/doc/development/testing/ci.md b/doc/development/testing/ci.md
index c8cc3fb93c..15dfe8294e 100644
--- a/doc/development/testing/ci.md
+++ b/doc/development/testing/ci.md
@@ -80,6 +80,68 @@ the expensive QA workflow is branch-limited and owns coverage and garden
 checks. Read `.woodpecker/qa.yml` and `.woodpecker/qa-expensive.yml` before
 changing that split.
 
+## CI Parity Map
+
+The repository now keeps CI ownership split across several services. Use this
+map to decide which service is authoritative for a platform-specific failure,
+and whether a Woodpecker workflow is intended to replace another service or
+only overlap part of its defect class.
+
+| Surface | Current authoritative provider | Woodpecker coverage |
+| ------- | ------------------------------ | ------------------- |
+| Linux build and regression checks | Woodpecker and GitHub Actions | Covered on amd64 by `.woodpecker/regress.yml`, `.woodpecker/qa.yml`, and `.woodpecker/qa-expensive.yml`. The Woodpecker matrix is not byte-for-byte identical to GitHub's Docker matrix, but it covers the standard Linux build, CUnit, install, extension-upgrade, cluster-upgrade, sanitizer, standard-conforming-strings-off, coverage, and garden classes. |
+| Codespell | Woodpecker and GitHub Actions | Covered by `.woodpecker/codespell.yml`. GitHub pins a specific `codespell` package version; Woodpecker follows the OSGeo build image unless that workflow is pinned separately. |
+| Contributor credits | Woodpecker and GitHub Actions | Covered by `.woodpecker/contributor-credits.yml`. |
+| Debbie Linux regression classes | Jenkins Debbie and Woodpecker | Mostly covered by Woodpecker's Linux regression and expensive QA workflows. Debbie still remains useful for its exact Jenkins host, dependency, and release-job environment. |
+| Make Dist | Jenkins Debbie | In flight in <https://gitea.osgeo.org/postgis/postgis/pulls/534>. Until that lands, Woodpecker does not check source distribution tarballs. |
+| FreeBSD and Bessie | GitHub Actions FreeBSD and Jenkins Bessie | In flight in <https://gitea.osgeo.org/postgis/postgis/pulls/549>. YAML running on a Linux container is not FreeBSD parity; this needs a FreeBSD VM or agent surface. |
+| 32-bit ARM and extra portability tiers | Jenkins Berrie | Covered by `.woodpecker/portability.yml` from <https://gitea.osgeo.org/postgis/postgis/pulls/516>, with hostile type-default coverage proposed in <https://gitea.osgeo.org/postgis/postgis/pulls/550>. Plain armhf emulation is useful for pointer-width and alignment assumptions, but the valuable tier is the hostile configuration with explicit type, signedness, alignment, and sanitizer probes. |
+| 64-bit ARM | Jenkins Berrie64 | Covered by `.woodpecker/arm64.yml` only when the fleet has a native `linux/arm64` agent. The workflow intentionally has no QEMU fallback. |
+| CodeQL | GitHub Actions | In flight as Woodpecker configuration carried separately. Woodpecker can build a CodeQL database and produce SARIF, but GitHub remains authoritative for code-scanning upload, annotations, and alert management unless Woodie artifact retention and SARIF consumption are also configured. |
+| macOS | GitHub Actions macOS | Not coverable by Woodpecker YAML on Linux. Keep GitHub Actions as the Darwin lane, operate an Apple Woodpecker agent, or accept no Darwin coverage. |
+| Native Windows MSYS2 and Winnie | GitHub Actions MSYS2 and Jenkins Winnie | Not covered natively by Linux Woodpecker. MinGW+Wine coverage is valuable ABI/runtime coverage but not native Windows parity. |
+
+The companion inventory and debugging documents are deliberately narrower than
+this parity map. Dashboard ownership, CI image provenance, and failure-debugging
+procedures should stay in their own sections rather than being repeated here;
+use this section to answer the parity question.
+
+### MinGW And Native Windows
+
+MinGW+Wine coverage is not native Windows coverage. The Woodpecker MinGW+Wine
+workflow cross-compiles PostGIS and dependencies, links Windows binaries and
+DLLs, starts Windows PostgreSQL binaries under Wine, and runs loaders, CUnit,
+and SQL regressions in that environment. That is strong MinGW ABI coverage.
+
+It does not replace GitHub MSYS2 or Winnie. Native Windows remains authoritative
+for NT path handling and path-length behavior, drive-letter and UNC semantics,
+MSYS2 path translation, service registration and Service Control Manager
+behavior, Windows CRT, locale and codepage behavior, native threading and file
+locking, DLL search order, and failures where Wine itself may be the broken
+component.
+
+### macOS
+
+macOS cannot be covered by Linux containers, Wine, or cross-compilation. Darwin
+libc, the Mach-O dynamic loader, Homebrew's dependency graph, Apple clang, the
+filesystem, and codesign or SIP-adjacent behavior have to run on macOS to be
+meaningful. The realistic choices are an Apple Woodpecker agent, GitHub Actions
+as the Darwin lane, or no Darwin parity.
+
+### ARM
+
+Treat 32-bit and 64-bit ARM as separate defect classes. The 32-bit lane is most
+useful when it is hostile: explicit `char` signedness, enum-width, alignment,
+and sanitizer settings catch assumptions that amd64 and a plain Berrie rerun do
+not falsify.
+
+The 64-bit lane should be native. Berrie64's value is 64-bit ARM execution plus
+garden and all-upgrades coverage. QEMU can compile and run some smoke tests, but
+it makes the expensive suites too slow and can hide timing, atomic-operation,
+kernel, and native scheduling behavior. The Woodpecker arm64 workflow therefore
+requires a registered `linux/arm64` agent and intentionally avoids an emulated
+fallback.
+
 ## Woodie API and Pipeline Approvals
 
 Use a Woodie personal access token for the Woodie API and

commit 9451df186a4c519d4544babadc1bebab1fb6e2b9
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Sun Jul 26 18:30:07 2026 +0400

    Document CI image and runner provenance

diff --git a/doc/development/testing/_index.md b/doc/development/testing/_index.md
index c4377cdce8..8d6f12876e 100644
--- a/doc/development/testing/_index.md
+++ b/doc/development/testing/_index.md
@@ -166,6 +166,8 @@ Other useful targets:
 * [Pull request CI gating](ci-gating.md) explains why expensive pull-request
   suites may be skipped, how upgrade ABI decisions are made, and how to force a
   full run when the gate is wrong.
+* [CI images and runners](ci-images-runners.md) maps the container image
+  families, Woodie agents, and Jenkins worker setup repositories used by CI.
 
 ## Garden Checks
 
diff --git a/doc/development/testing/ci-images-runners.md b/doc/development/testing/ci-images-runners.md
new file mode 100644
index 0000000000..1dc0a577f9
--- /dev/null
+++ b/doc/development/testing/ci-images-runners.md
@@ -0,0 +1,75 @@
+---
+title: "CI Images and Runners"
+date: 2026-07-26
+weight: 12
+geekdocHidden: false
+---
+
+PostGIS CI uses two container image families and several runner fleets. Keep
+the dependency details in the image repositories and host setup repositories;
+this page is the navigation map.
+
+## Container Image Families
+
+| Image family | Published at | Owner | Consumers |
+| ------------ | ------------ | ----- | --------- |
+| `postgis/postgis-build-env:*` | Docker Hub | <https://github.com/postgis/postgis-build-env> | GitHub Actions Linux matrix in `.github/workflows/ci.yml` |
+| `repo.osgeo.org/postgis/build-test:*` | OSGeo container registry | <https://gitea.osgeo.org/postgis/postgis-docker> | Woodpecker workflows under `.woodpecker/` |
+
+`postgis/postgis-build-env` has one `Dockerfile` and `build.py`. The script
+builds and pushes the tag matrix used by the GitHub Actions Linux workflow. Its
+README points at the Debbie Jenkins job that runs the regular image build.
+
+`postgis/postgis-docker` owns the Woodpecker build-test images. The
+`build-test/Containerfile.*` files and `build-test/Makefile` define the image
+set, and the repository README documents logging in and pushing to the OSGeo
+registry. At the time this page was written, this repository had build
+instructions and a Debbie helper script, but no checked-in GitHub Actions,
+Woodpecker, GitLab CI, or Jenkinsfile workflow of its own.
+
+An image pull can fail before any PostGIS test starts. Treat registry timeouts,
+manifest failures, and authentication failures as infrastructure failures until
+the failing step has successfully entered a PostGIS build or test command. A
+Docker Hub registry timeout has made the GitHub Actions Linux matrix red before
+without identifying a source defect.
+
+## Runner And Host Repositories
+
+| Runner surface | Owner | What it covers |
+| -------------- | ----- | -------------- |
+| Woodie agents | <https://gitea.osgeo.org/sac/woodpecker-agent-config>, branch `woodie-3` | OSGeo Woodpecker agent startup scripts and deployment notes |
+| Jenkins buildbot hosts | <https://gitea.osgeo.org/postgis/postgis-buildbots> | Linux, Debian, FreeBSD, Raspberry Pi, and Windows worker setup notes |
+| In-tree Jenkins scripts | `ci/debbie/`, `ci/winnie/`, `ci/bessie/`, `ci/berrie*` | Commands run by PostGIS Jenkins jobs and worker labels |
+
+Woodpecker pull-request jobs run on Woodie agents. Agent capacity, Docker
+socket access, `binfmt_misc` handlers, DNS, and registry access are runner
+properties, not PostGIS source properties. If a workflow adds an emulated or
+cross-architecture job, verify the runner preflight in the Woodie agent fleet
+before treating the failure as a test failure.
+
+Jenkins worker setup lives outside this repository in
+`postgis/postgis-buildbots`. That repository still contains historical setup
+notes as well as active worker notes, so use the maintained inventory in
+`utils/docs/ci_status/config.json` and the live Jenkins job labels before
+reviving an old platform. Current 32-bit coverage is the Berrie Raspberry Pi
+worker, which is 32-bit ARM. The old `bessie32` FreeBSD worker is not part of
+the maintained CI inventory; do not rebuild 32-bit FreeBSD coverage from the old badge table
+without fresh maintainer approval and a live worker readback.
+
+## Architecture Coverage
+
+Use the owning workflow or worker label for architecture claims:
+
+* GitHub Actions Linux runs in Docker on GitHub-hosted Linux.
+* GitHub Actions FreeBSD and macOS are owned by their workflow files and only
+  cover the branches where those files exist.
+* Woodpecker jobs currently declare `platform: linux/amd64` unless the
+  workflow says otherwise.
+* Jenkins `berrie` is the maintained 32-bit ARM surface, and `berrie64` is the
+  Raspberry Pi 64-bit surface.
+* Jenkins `bessie` is the maintained FreeBSD surface; `bessie32` is retired
+  from the maintained inventory.
+
+When changing architecture coverage, update the owning workflow or worker job,
+then update [CI inventory standards](ci.md) and
+`utils/docs/ci_status/config.json`.

commit 1bcca9054b901f289be2c279a4220316fb04cab1
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Sun Jul 26 18:29:05 2026 +0400

    Document CI inventory dashboard ownership

diff --git a/doc/development/testing/ci.md b/doc/development/testing/ci.md
index 1181e7945a..c8cc3fb93c 100644
--- a/doc/development/testing/ci.md
+++ b/doc/development/testing/ci.md
@@ -26,10 +26,12 @@ service that owns the behavior:
 | macOS GitHub Actions job | `.github/workflows/ci-macos.yml`; see [macOS development environment](../environment/macos.md) |
 | MSYS2/MinGW GitHub Actions job | `.github/workflows/msys.yml` |
 | GitHub CodeQL, codespell, and contributor-credit jobs | `.github/workflows/codeql.yml`, `.github/workflows/codespell.yml`, and `.github/workflows/contributor-credits.yml` |
+| Woodpecker pull-request and branch pipelines | `.woodpecker/*.yml`, with pipeline status published by Woodie at <https://woodie.osgeo.org/repos/30> |
 | Debbie build, docs, and release jobs | `ci/debbie/`, the Debbie Jenkins jobs, and release-process notes |
 | Winnie Windows jobs | `ci/winnie/` and the Winnie Jenkins jobs |
 | Bessie and Berrie/Berrie64 jobs | `ci/bessie/`, `ci/berrie*`, and the corresponding Jenkins worker labels |
 | Docker build images used by GitHub Actions | `postgis/postgis-build-env` image tags referenced from `.github/workflows/ci.yml` |
+| Docker build images used by Woodpecker | `repo.osgeo.org/postgis/build-test:*` image tags referenced from `.woodpecker/*.yml` |
 | Woodpecker MinGW Wine job | `.woodpecker/mingw-wine.yml` and `ci/woodie/postgis_mingw_wine.sh` |
 
 When a dashboard row describes dependency versions, operating systems, branch
@@ -64,6 +66,20 @@ following overrides:
 The result is clamped to at least `1`, and if memory detection fails the function
 falls back to the CPU-based maximum.
 
+Woodpecker is the CI surface attached to canonical Gitea pull requests. Its
+status contexts are produced from the checked-in `.woodpecker/` workflows, so a
+new Woodpecker job belongs there first, then in the generated dashboard
+inventory described below. Do not document the current split count by hand:
+parallel matrix expansion and retries change the number of published
+`ci/woodpecker/...` contexts for a commit.
+
+On `master`, the maintained Woodpecker workflows include regression, docs,
+tools, codespell, contributor-credit, and QA coverage. The QA workflow runs
+sanitizer and `standard_conforming_strings=off` checks for pull requests, while
+the expensive QA workflow is branch-limited and owns coverage and garden
+checks. Read `.woodpecker/qa.yml` and `.woodpecker/qa-expensive.yml` before
+changing that split.
+
 ## Woodie API and Pipeline Approvals
 
 Use a Woodie personal access token for the Woodie API and
@@ -127,8 +143,10 @@ same check path as the badge URL.
 Update the inventory when any of these change:
 
 * a workflow file under `.github/workflows/`;
+* a workflow file under `.woodpecker/`;
 * a script under `ci/`;
 * a `postgis/postgis-build-env` tag used by the GitHub Actions matrix;
+* a `repo.osgeo.org/postgis/build-test` tag used by a Woodpecker workflow;
 * a Jenkins job, worker label, or badge URL referenced from Trac or website
   dashboards;
 * a supported release branch or support-window row that affects which branches

-----------------------------------------------------------------------

Summary of changes:
 .woodpecker/arm64.yml                             |  83 ---------------
 .woodpecker/portability.yml                       |  36 ++++++-
 doc/development/environment/macos.md              |  19 ++--
 doc/development/testing/_index.md                 |   5 +
 doc/development/testing/ci-images-runners.md      |  75 ++++++++++++++
 doc/development/testing/ci.md                     | 117 +++++++++++++++++++++
 doc/development/testing/macos-coverage-options.md | 118 ++++++++++++++++++++++
 7 files changed, 357 insertions(+), 96 deletions(-)
 delete mode 100644 .woodpecker/arm64.yml
 create mode 100644 doc/development/testing/ci-images-runners.md
 create mode 100644 doc/development/testing/macos-coverage-options.md


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list