# Real multi-hour soak — #581 query-only memory-leak reproducer. # # WHY THIS EXISTS (separate from _soak.yml / nightly-soak.yml): # The nightly path was structurally incapable of running a real long soak: # 1. nightly-soak.yml passes duration_minutes: 240, but _soak.yml's # soak-quick / soak-asan jobs hard-cap `timeout-minutes: 30` (45 for # ASan). GitHub kills the job at 30 min → the "4h" soak NEVER ran past # 30 min. (Fixed in _soak.yml too, but this workflow guarantees the # right budget for the long #581 run.) # 2. scripts/soak-test.sh's default mode reindexes every 2 min; # index_repository triggers cbm_mem_collect (mimalloc page return), # which sweeps the query-only leak — masking #581 even on a long run. # This workflow drives CBM_SOAK_MODE=query-leak, which never reindexes # and never mutates files, so the leak can accumulate and be detected # by soak-test.sh's RSS slope / ratio / ceiling analysis. # # NON-GATING: workflow_dispatch + push to qa/soak-** only. Never a required # check, never blocks a merge. # # CRITICAL: timeout-minutes = duration + 60. A 240-min soak gets ~300 min. name: Soak (multi-hour #581) on: workflow_dispatch: inputs: duration_minutes: description: 'Soak duration in minutes (default: 240 = 4h)' type: number default: 240 mode: description: 'Soak mode (query-leak = #581 detector, no reindex/mutate)' type: choice options: ['default', 'query-leak'] default: 'query-leak' # Iteration convenience: pushing a qa/soak-** branch starts a real run from # that branch's own copy of this file (no main merge needed). Non-gating. push: branches: ['qa/soak-**'] permissions: contents: read jobs: # ── Unix: full matrix (linux amd64+arm64, darwin arm64+amd64) ────────────── soak-unix: strategy: fail-fast: false matrix: include: - os: ubuntu-latest cc: gcc cxx: g++ - os: ubuntu-24.04-arm cc: gcc cxx: g++ - os: macos-14 cc: cc cxx: c++ - os: macos-15-intel cc: cc cxx: c++ runs-on: ${{ matrix.os }} # Fixed budget (NOT the 30 min that silently truncated nightly). 320 min covers # the 240-min default soak + build + analysis. `timeout-minutes` is evaluated at # workflow setup where the `inputs` context is null on push events, so an # inputs-based expression here is a startup failure — keep it a literal. # (A workflow_dispatch run with duration > ~250 min should bump this.) timeout-minutes: 320 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 (prod binary) run: scripts/build.sh CC=${{ matrix.cc }} CXX=${{ matrix.cxx }} - name: Soak env: # On push events there are no inputs → fall back to shell defaults # (240 min / query-leak) so a qa/soak-** push runs the real #581 soak. CBM_SOAK_MODE: ${{ inputs.mode || 'query-leak' }} DURATION_MINUTES: ${{ inputs.duration_minutes || '240' }} run: scripts/soak-test.sh build/c/codebase-memory-mcp "${DURATION_MINUTES}" - name: Upload metrics if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: soak-${{ matrix.os }}-${{ inputs.mode || 'query-leak' }} path: soak-results/ retention-days: 14 # ── Windows: the platform #581 actually crashes on (50+ GB → crash) ─────── soak-windows: runs-on: windows-latest timeout-minutes: 320 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 (prod binary) shell: msys2 {0} run: scripts/build.sh CC=clang CXX=clang++ - name: Soak shell: msys2 {0} env: CBM_SOAK_MODE: ${{ inputs.mode || 'query-leak' }} DURATION_MINUTES: ${{ inputs.duration_minutes || '240' }} run: | BIN=build/c/codebase-memory-mcp [ -f "${BIN}.exe" ] && BIN="${BIN}.exe" scripts/soak-test.sh "$BIN" "${DURATION_MINUTES}" - name: Upload metrics if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: soak-windows-${{ inputs.mode || 'query-leak' }} path: soak-results/ retention-days: 14