Skip to content

docs: add Group I — feedback-quality recall scoring to roadmap #781

docs: add Group I — feedback-quality recall scoring to roadmap

docs: add Group I — feedback-quality recall scoring to roadmap #781

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
# Auto-cancel superseded runs on the same ref so a chain of fast-follow
# pushes doesn't pile up zombie in-progress runs that the GitHub backend
# can no longer cancel via API.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
# Pin ruff: an unpinned `pip install ruff` silently upgrades on every
# ruff release, and ruff's lint/format rules drift between minors —
# which spontaneously turns this job red on untouched code. Bump
# deliberately (and run `ruff check --fix && ruff format` once) when raising.
- run: pip install ruff==0.15.15
- run: ruff check src/ tests/
- name: Format check
run: python3 -m ruff format --check src/ tests/
typecheck:
# v3.7.0 M5: typecheck is now blocking (was continue-on-error: true).
# mypy src/ is currently clean — keeping it green is part of the
# release contract.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- run: pip install -e ".[test]"
- run: python -m mypy src/ --ignore-missing-imports
test:
# v3.7.0 M5: every advertised OS/Python combination must pass.
# Python 3.14 was previously continue-on-error; the version is
# now classed as supported in pyproject.toml's classifiers, so the
# CI gate matches.
runs-on: ${{ matrix.os }}
# Python 3.14 is still pre-release as of 2026-05; treat its rows as
# advisory rather than gating until upstream wheels stabilise. The
# 3.10/3.12/3.13 supported rows still gate the workflow.
continue-on-error: ${{ matrix.python-version == '3.14' }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.10", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- run: pip install -e ".[test]"
- name: Unit tests with coverage (ubuntu-3.12 only)
# v4.0.9: coverage instrumentation across 5000+ tests is the
# single biggest contributor to runner memory pressure. The
# cov-fail-under=70 gate matters once per CI run, not 12×
# across the matrix. Run --cov only on the canonical
# ubuntu-3.12 row; other rows run the same test set without
# the instrumentation overhead so they fit in the 7 GB
# GitHub-hosted runner budget.
# v4.0.6: -m "not stress" excludes stress-marked tests that
# OOM-killed ubuntu runners (test_niah and the 5 files
# marked file-level in v4.0.8). Stress tests still run via
# `make test` for pre-release gating.
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
run: python3 -m pytest tests/ --ignore=tests/integration --cov=src --cov-report=xml --cov-report=term-missing --cov-fail-under=70 -x -q -m "not stress" --timeout=120 --timeout-method=thread
env:
PYTHONDONTWRITEBYTECODE: "1"
- name: Unit tests (no coverage, other matrix rows)
if: matrix.os != 'ubuntu-latest' || matrix.python-version != '3.12'
run: python3 -m pytest tests/ --ignore=tests/integration -x -q -m "not stress" --timeout=120 --timeout-method=thread
env:
PYTHONDONTWRITEBYTECODE: "1"
- name: Integration tests
run: python3 -m pytest tests/integration/ -v -m "not stress"
env:
PYTHONDONTWRITEBYTECODE: "1"
- name: Upload coverage report
# Only ubuntu-3.12 generates coverage.xml (see v4.0.9 split above).
if: always() && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: coverage-${{ matrix.os }}-${{ matrix.python-version }}
path: coverage.xml
retention-days: 30
version-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- name: Check version consistency
run: python src/mind_mem/check_version.py
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- run: pip install -e .
- name: Init test workspace
run: python -m mind_mem.init_workspace /tmp/test-workspace
- name: Validate workspace
run: python -m mind_mem.validate_py /tmp/test-workspace
extras-install:
name: ".[${{ matrix.extra }}] installs"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
extra: [mcp, api, embeddings, all]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- name: pip install -e ".[${{ matrix.extra }}]"
run: |
python -m pip install --upgrade pip
python -m pip install -e ".[${{ matrix.extra }}]"
- name: import mind_mem
run: python -c "import mind_mem; print(mind_mem.__name__)"
pinned-requirements:
# v3.7.0 M5 follow-up: requirements-optional.txt only pins three
# top-level packages (onnxruntime / tokenizers / sentence-
# transformers); transitive deps are intentionally resolved by pip.
# ``--require-hashes`` is implicitly enabled for the whole resolve
# whenever ANY line has ``--hash=``, so a plain ``pip install`` of
# this file fails on transitive deps that aren't pinned (the file
# is a "minimum supported set" not a full lockfile). Generating a
# full hashed lockfile (200+ entries) would silently expand the
# file's scope; the audit's M5 intent ("prove the pinned versions
# still resolve on a fresh runner so a yanked wheel breaks the
# release, not prod") is satisfied by:
# 1. ``pip download --no-deps --require-hashes`` — proves all
# three pins still exist on PyPI with the recorded hashes
# 2. ``pip install`` of the same three top-level packages
# *without* the requirements file — proves the version line
# still resolves a working transitive closure
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- name: Verify hashes for pinned wheels (gate against yanked wheels)
run: |
python -m pip install --upgrade pip
python -m pip download --no-deps --require-hashes \
--dest /tmp/hash-verify \
-r requirements-optional.txt
- name: Resolve transitive closure (gate against unsatisfiable deps)
run: |
python -m pip install \
onnxruntime==1.24.2 \
tokenizers==0.22.2 \
sentence-transformers==5.2.3
docker-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 — Node 24
- name: Build runtime image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 — Node 24
with:
context: .
file: deploy/docker/Dockerfile
push: false
load: true
tags: mind-mem:ci
compose-config:
# v3.7.0 M6: prove docker-compose.yml renders cleanly with both the
# default user/db AND an operator override. Pre-3.7.0 the postgres
# healthcheck hardcoded ``pg_isready -U mindmem -d mindmem``, so an
# operator who set POSTGRES_USER / POSTGRES_DB would see a healthy
# postgres container reported as unhealthy. The new healthcheck
# reads the env at probe time; this job validates the YAML still
# interpolates and that the rendered command keeps the env-var
# references intact under both defaults and overrides.
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
scenario:
- name: defaults
user: ""
db: ""
- name: overrides
user: alice
db: factsdb
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: docker compose config
env:
MIND_MEM_TOKEN: ci-token
MIND_MEM_ADMIN_TOKEN: ci-admin
POSTGRES_PASSWORD: ci-pg-pw
POSTGRES_USER: ${{ matrix.scenario.user }}
POSTGRES_DB: ${{ matrix.scenario.db }}
run: |
docker compose -f deploy/docker-compose.yml config > /tmp/rendered.yml
# ``$$VAR`` in compose YAML renders as a literal ``$VAR`` once the
# container shell expands it at probe time. The check confirms the
# healthcheck still references ``POSTGRES_USER`` / ``POSTGRES_DB``
# rather than baked-in literals — the M6 regression we are gating.
grep -F 'pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"' /tmp/rendered.yml
install-smoke:
name: install.sh smoke (${{ matrix.installer }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
installer: [pipx, pip]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- name: Install pipx
if: matrix.installer == 'pipx'
run: |
python -m pip install --upgrade pip
python -m pip install pipx
python -m pipx ensurepath
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: Install package via documented one-liner
# The README tells users to run pipx install "mind-mem[mcp]"
# (or pip --user). This step exercises that exact path on a
# clean runner so a regression there is caught before release.
run: |
if [ "${{ matrix.installer }}" = "pipx" ]; then
pipx install --force ".[mcp]"
else
python -m pip install --user ".[mcp]"
fi
- name: mind-mem-mcp --help (smoke)
run: mind-mem-mcp --help
- name: install.sh wires clients without re-installing
# Run with --no-install so the script just resolves
# mind-mem-mcp on PATH and verifies it. The --claude-code flag
# writes to ~/.claude/mcp.json (created on demand) and avoids
# the interactive client picker.
run: ./install.sh --no-install --workspace /tmp/test-workspace --claude-code