Files
codebase-memory-mcp/.github/workflows/_soak.yml
T
Martin Vogel 4fac943314 ci: green the dry-run smoke gate + ship native windows-arm64
Two release-blockers surfaced once #882 made every smoke leg a required gate
(continue-on-error previously masked them):

- smoke-unix ran the *dynamic* linux binary on ubuntu-22.04 / 22.04-arm, where
  it cannot start (it links glibc 2.38+) -> Phase 1 died. Older-glibc coverage
  is the -portable (static) binary's job and is green via the smoke-linux-portable
  broad legs, so drop the impossible dynamic broad legs (keep macOS).
- the ClamAV scan died on every linux leg: apt auto-starts the clamav-freshclam
  daemon which holds the freshclam log lock, so the manual freshclam failed with
  "Failed to lock the log file ... Resource temporarily unavailable". Stop the
  daemon first.

Also add native ARM64 Windows as a first-class release target -- the one platform
we test (windows-11-arm) but never shipped:
- build-windows-arm64 job (CLANGARM64) producing codebase-memory-mcp[-ui]-windows-arm64.zip
- smoke-windows is now arch-aware: windows-11-arm smokes the NATIVE arm64 binary
  instead of the x86_64 binary under emulation
- a native soak-quick-windows-arm64 leg (no sanitizer -- ASan is unavailable on
  native ARM64 Windows)
- arm64 detection in install.ps1

release.yml already publishes windows-arm64 (asset filter + merge-multiple) and
build_update_url/detect_arch already resolve it; npm/pip/install.sh compute arm64
already. scoop/winget/chocolatey per-version manifests are updated at release time.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-07-06 00:31:40 +02:00

286 lines
11 KiB
YAML

# Reusable: soak tests (quick + ASan, all platforms)
name: Soak
on:
workflow_call:
inputs:
duration_minutes:
description: 'Soak duration in minutes'
type: number
default: 10
run_asan:
description: 'Run ASan soak in addition to quick soak'
type: boolean
default: false
version:
description: 'Version string for build'
type: string
default: ''
permissions:
contents: read
jobs:
soak-quick:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
goos: linux
goarch: amd64
cc: gcc
cxx: g++
- os: ubuntu-24.04-arm
goos: linux
goarch: arm64
cc: gcc
cxx: g++
- os: macos-14
goos: darwin
goarch: arm64
cc: cc
cxx: c++
- os: macos-15-intel
goos: darwin
goarch: amd64
cc: cc
cxx: c++
runs-on: ${{ matrix.os }}
# BUG FIX: this was hard-coded to 30, but the caller (nightly-soak.yml)
# passes duration_minutes: 240. GitHub killed the job at 30 min, so the
# "4h nightly soak" was SILENTLY TRUNCATED to 30 min and never once ran
# multi-hour. Budget must always exceed the passed duration; 300 covers
# the 240-min nightly with headroom (build + analysis + idle phases).
timeout-minutes: 300
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install deps (Linux)
if: startsWith(matrix.os, 'ubuntu')
run: sudo apt-get update && sudo apt-get install -y zlib1g-dev python3 git
- name: Build
run: scripts/build.sh ${{ inputs.version && format('--version {0}', inputs.version) || '' }} CC=${{ matrix.cc }} CXX=${{ matrix.cxx }}
- name: Soak (${{ inputs.duration_minutes }} min)
run: scripts/soak-test.sh build/c/codebase-memory-mcp ${{ inputs.duration_minutes }}
# #581 guard: read-only soak (never reindex/mutate) so any memory growth is
# a query-path leak, not WAL/indexing. Reuses the build above.
- name: Query-leak soak (#581, read-only)
env:
CBM_SOAK_MODE: query-leak
RESULTS_DIR: soak-results-query-leak
run: scripts/soak-test.sh build/c/codebase-memory-mcp ${{ inputs.duration_minutes }} --skip-crash-test
- name: Upload metrics
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: soak-quick-${{ matrix.goos }}-${{ matrix.goarch }}
path: soak-results/
retention-days: 14
- name: Upload query-leak metrics
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: soak-query-leak-${{ matrix.goos }}-${{ matrix.goarch }}
path: soak-results-query-leak/
retention-days: 14
soak-quick-windows:
runs-on: windows-latest
# BUG FIX (same 30→240 mismatch as soak-quick above): the caller passes
# duration_minutes: 240, so a 30-min cap truncated the nightly soak here
# too. 300 covers the 240-min nightly with headroom.
timeout-minutes: 300
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
with:
msystem: CLANG64
path-type: inherit
install: >-
mingw-w64-clang-x86_64-clang
mingw-w64-clang-x86_64-zlib
mingw-w64-clang-x86_64-python3
make
git
coreutils
- name: Build
shell: msys2 {0}
run: scripts/build.sh ${{ inputs.version && format('--version {0}', inputs.version) || '' }} CC=clang CXX=clang++
- name: Soak (${{ inputs.duration_minutes }} min)
shell: msys2 {0}
run: |
BIN=build/c/codebase-memory-mcp
[ -f "${BIN}.exe" ] && BIN="${BIN}.exe"
scripts/soak-test.sh "$BIN" ${{ inputs.duration_minutes }}
# #581 guard on Windows — the platform the bug is reported on.
- name: Query-leak soak (#581, read-only)
shell: msys2 {0}
env:
CBM_SOAK_MODE: query-leak
RESULTS_DIR: soak-results-query-leak
run: |
BIN=build/c/codebase-memory-mcp
[ -f "${BIN}.exe" ] && BIN="${BIN}.exe"
scripts/soak-test.sh "$BIN" ${{ inputs.duration_minutes }} --skip-crash-test
- name: Upload metrics
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: soak-quick-windows-amd64
path: soak-results/
retention-days: 14
- name: Upload query-leak metrics
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: soak-query-leak-windows-amd64
path: soak-results-query-leak/
retention-days: 14
soak-quick-windows-arm64:
# Native ARM64 Windows soak (CLANGARM64, no sanitizer — ASan is unavailable
# on native ARM64 Windows). Builds from source like soak-quick-windows.
runs-on: windows-11-arm
timeout-minutes: 300
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
with:
msystem: CLANGARM64
path-type: inherit
install: >-
mingw-w64-clang-aarch64-clang
mingw-w64-clang-aarch64-zlib
mingw-w64-clang-aarch64-python3
make
git
coreutils
- name: Build
shell: msys2 {0}
run: scripts/build.sh ${{ inputs.version && format('--version {0}', inputs.version) || '' }} CC=clang CXX=clang++
- name: Soak (${{ inputs.duration_minutes }} min)
shell: msys2 {0}
run: |
BIN=build/c/codebase-memory-mcp
[ -f "${BIN}.exe" ] && BIN="${BIN}.exe"
scripts/soak-test.sh "$BIN" ${{ inputs.duration_minutes }}
# #581 guard on Windows — the platform the bug is reported on.
- name: Query-leak soak (#581, read-only)
shell: msys2 {0}
env:
CBM_SOAK_MODE: query-leak
RESULTS_DIR: soak-results-query-leak
run: |
BIN=build/c/codebase-memory-mcp
[ -f "${BIN}.exe" ] && BIN="${BIN}.exe"
scripts/soak-test.sh "$BIN" ${{ inputs.duration_minutes }} --skip-crash-test
- name: Upload metrics
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: soak-quick-windows-arm64
path: soak-results/
retention-days: 14
- name: Upload query-leak metrics
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: soak-query-leak-windows-arm64
path: soak-results-query-leak/
retention-days: 14
soak-asan:
if: ${{ inputs.run_asan }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
goos: linux
goarch: amd64
cc: gcc
cxx: g++
- os: ubuntu-24.04-arm
goos: linux
goarch: arm64
cc: gcc
cxx: g++
- os: macos-14
goos: darwin
goarch: arm64
cc: cc
cxx: c++
- os: macos-15-intel
goos: darwin
goarch: amd64
cc: cc
cxx: c++
runs-on: ${{ matrix.os }}
# ASan soak runs a FIXED 15-min soak (hard-coded below, NOT driven by
# inputs.duration_minutes), but the ASan-instrumented build is slow and
# leak reporting adds teardown time. 60 keeps the budget comfortably above
# the 15-min run so it is never truncated. (Same class of bug as the
# soak-quick 30→240 mismatch above — keep the timeout above the run length.)
timeout-minutes: 240
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install deps (Linux)
if: startsWith(matrix.os, 'ubuntu')
run: sudo apt-get update && sudo apt-get install -y zlib1g-dev python3 git
- name: Build (ASan)
run: |
SANITIZE="-fsanitize=address,undefined -fno-omit-frame-pointer"
scripts/build.sh ${{ inputs.version && format('--version {0}', inputs.version) || '' }} CC=${{ matrix.cc }} CXX=${{ matrix.cxx }} EXTRA_CFLAGS="$SANITIZE" EXTRA_LDFLAGS="$SANITIZE"
- name: ASan soak (15 min)
env:
ASAN_OPTIONS: "detect_leaks=1:halt_on_error=0:log_path=soak-results/asan"
run: scripts/soak-test.sh build/c/codebase-memory-mcp 15
- name: Upload metrics
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: soak-asan-${{ matrix.goos }}-${{ matrix.goarch }}
path: soak-results/
retention-days: 14
soak-asan-windows:
if: ${{ inputs.run_asan }}
runs-on: windows-latest
# FIXED 15-min soak (hard-coded below). MSYS2/Wine + ASan build is the
# slowest path; 60 keeps the budget well above the run length so it is
# never truncated.
timeout-minutes: 240
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
with:
msystem: CLANG64
path-type: inherit
install: >-
mingw-w64-clang-x86_64-clang
mingw-w64-clang-x86_64-zlib
mingw-w64-clang-x86_64-python3
make
git
coreutils
- name: Build (ASan)
shell: msys2 {0}
run: |
SANITIZE="-fsanitize=address,undefined -fno-omit-frame-pointer"
scripts/build.sh ${{ inputs.version && format('--version {0}', inputs.version) || '' }} CC=clang CXX=clang++ EXTRA_CFLAGS="$SANITIZE" EXTRA_LDFLAGS="$SANITIZE"
- name: ASan soak (15 min, no leak detection)
shell: msys2 {0}
env:
ASAN_OPTIONS: "detect_leaks=0:halt_on_error=0:log_path=soak-results/asan"
run: |
BIN=build/c/codebase-memory-mcp
[ -f "${BIN}.exe" ] && BIN="${BIN}.exe"
scripts/soak-test.sh "$BIN" 15
- name: Upload metrics
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: soak-asan-windows-amd64
path: soak-results/
retention-days: 14