ThomasHeisig's picture
Sync GitHub main 466ae6e87de276549cff5a7ef52c55419843ace7
74523ef verified
Raw History Blame Contribute Delete
22.7 kB
# ============================================================================
# MHRN — Continuous Integration
# ============================================================================
# Runs on push/PR to main/develop, and weekly on Monday 06:00 UTC.
#
# Pipeline stages:
# 1. lint-format — code style, linting, pre-commit
# 2. type-check — static type analysis (mypy + pyright)
# 3. security — SAST / dependency scanning
# 4. tests — full test suite on the canonical Python 3.13 CI runtime
# 5. build — wheel build + install verification
# 6. docker — Docker image build test
# 7. docs — documentation structure check
# ============================================================================
name: Continuous Integration
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
schedule:
- cron: "0 6 * * 1"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
checks: write
pull-requests: write
env:
PYTHONUNBUFFERED: "1"
PIP_NO_WARN_SCRIPT_LOCATION: "1"
PIP_DISABLE_PIP_VERSION_CHECK: "1"
FORCE_COLOR: "1"
defaults:
run:
shell: bash
jobs:
lint-format:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v7
with:
python-version: "3.13"
cache: pip
cache-dependency-path: |
pyproject.toml
requirements.txt
- name: Install project and development tools
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".[dev,docs]"
python -m pip install pre-commit bandit
- name: Black (src + tests + scripts)
run: python -m black --check --diff src tests scripts
- name: Ruff (fast linter + isort)
run: python -m ruff check src/ tests/ scripts/
- name: Wave 4 canonical import boundary
run: python scripts/check_canonical_imports.py
- name: Wave 4 CUDA kernel freeze
run: python scripts/check_cuda_kernel_freeze.py
- name: Pylint error diagnostics and quality threshold
run: python -m pylint --disable=all --enable=E,F --fail-under=9.0 src
- name: Pre-commit hooks (all files)
run: python -m pre_commit run --all-files --show-diff-on-failure
- name: Whitespace & merge-conflict check
run: |
git diff --check
! grep -rP '^(<<<<<<< |>>>>>>> )|^=======$' src/ tests/ scripts/ --include='*.py' --include='*.md' --include='*.yaml' --include='*.yml'
- name: Summary
if: always()
run: |
echo "### Lint & Format: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
wave4-contracts:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v7
with:
python-version: "3.13"
cache: pip
cache-dependency-path: |
pyproject.toml
requirements.txt
- name: Install Wave 4 contract dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".[dev]"
- name: Gate 1 - canonical import direction
run: python scripts/check_canonical_imports.py
- name: Gate 2 - byte-identical CUDA kernel freeze
run: python scripts/check_cuda_kernel_freeze.py
- name: Gate 3 - plasticity semantic boundary
run: python scripts/check_cuda_semantic_boundary.py
- name: Gate 4 - canonical cross-backend parity contract
run: python scripts/check_cuda_parity_contract.py
- name: Wave 4 backend contract tests
run: python -m pytest -q tests/test_cuda_acceleration_extraction.py tests/test_cuda_wave4_backend.py
- name: Summary
if: always()
run: |
echo "### Wave 4 CUDA Contracts: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
echo "Physical CUDA D1/D2 acceptance remains an explicit opt-in hardware run." >> $GITHUB_STEP_SUMMARY
fe-contracts:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v7
with:
python-version: "3.13"
cache: pip
cache-dependency-path: |
pyproject.toml
requirements.txt
- name: Install Frozen-Environment contract dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".[dev]"
- name: Frozen-Environment contract tests
run: |
python -m pytest -q \
tests/test_frozen_environment_contract.py \
tests/test_frozen_environment_backend_adapter.py \
tests/verification/parity/test_frozen_environment_parity.py \
tests/verification/frozen_environment/
- name: FE-1 manifest build and acceptance
run: |
python scripts/build_frozen_environment.py --mode FE-1 --ticks 2 --output /tmp/mhrn-fe1.json
python scripts/run_fe_acceptance.py --manifest /tmp/mhrn-fe1.json
- name: FE-3 CPU/self control and 10x replay
run: |
python scripts/build_frozen_environment.py --mode FE-3 --ticks 2 --target 2 --output /tmp/mhrn-fe3.json
python scripts/run_fe_acceptance.py --manifest /tmp/mhrn-fe3.json --repeats 10
- name: Summary
if: always()
run: |
echo "### Frozen Environment Contracts: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
echo "Physical CPU-vs-CUDA D3 remains a separate hardware acceptance." >> $GITHUB_STEP_SUMMARY
type-check:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v7
with:
python-version: "3.13"
cache: pip
cache-dependency-path: |
pyproject.toml
requirements.txt
- name: Install project and development tools
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".[dev,docs]"
- name: Mypy (full src/)
run: python -m mypy src/
- name: Pyright (pyrightconfig.json scope)
run: python -m pyright
- name: Pyright (integration scope)
run: |
python -m pyright \
src/storage/structural_journal.py \
src/storage/structural_recovery.py \
src/storage/core_restore.py \
src/self_organization/approval.py \
src/self_organization/undo.py \
src/self_organization/plasticity.py \
src/self_organization/coordinator.py \
src/dashboard/structural_api.py \
src/dashboard/operator_bridge.py \
src/dashboard/server.py \
src/runtime/control.py \
src/controller/runtime.py \
src/visualization/structural_heatmap.py
- name: Summary
if: always()
run: |
echo "### Type Check: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
security:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v7
with:
python-version: "3.13"
cache: pip
- name: Install tools
run: |
python -m pip install --upgrade pip
python -m pip install -e ".[docs]" bandit pip-audit
- name: Bandit SAST (src/)
run: python -m bandit -c pyproject.toml -r src/ -ll -f json -o bandit-results.json
- name: Upload Bandit report
if: always()
uses: actions/upload-artifact@v7
with:
name: bandit-results
path: bandit-results.json
- name: pip-audit
run: python -m pip_audit --skip-editable
- name: Summary
if: always()
run: echo "### Security scan completed" >> $GITHUB_STEP_SUMMARY
tests:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
python-version: ["3.13"]
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: |
pyproject.toml
requirements.txt
- name: Install project and dev dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".[dev,docs]"
- name: Smoke tests
run: python -m pytest -m "smoke" -v --tb=short --junit-xml=test-results-smoke.xml
- name: Full test suite (excluding slow)
run: python -m pytest -m "not slow" -v --tb=short --junit-xml=test-results-fast.xml --cov=src --cov-report=xml:coverage.xml --cov-report=term-missing:skip-covered
- name: Slow tests
run: python -m pytest -m "slow" -v --tb=short --junit-xml=test-results-slow.xml
- name: Upload test results
if: always()
uses: actions/upload-artifact@v7
with:
name: test-results-${{ matrix.python-version }}
path: |
test-results-*.xml
coverage.xml
- name: Publish test report
if: always()
uses: dorny/test-reporter@v3
with:
name: pytest-report-${{ matrix.python-version }}
path: test-results-*.xml
reporter: java-junit
fail-on-error: false
only-summary: true
- name: Summary
if: always()
run: |
echo "### Tests (${{ matrix.python-version }})" >> $GITHUB_STEP_SUMMARY
python -m pytest --collect-only -q 2>&1 | tail -1 >> $GITHUB_STEP_SUMMARY || true
browser:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v7
with:
python-version: "3.13"
cache: pip
cache-dependency-path: pyproject.toml
- name: Install browser check dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".[browser,docs]"
# Playwright downloads its own pinned Chromium. The image's unrelated
# Google Chrome APT feed can be mid-publication (hash mismatch); do not
# bypass signature/hash verification or disable Ubuntu security feeds.
for source in /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; do
if [ -f "$source" ] && grep -qF 'dl.google.com/linux/chrome' "$source"; then
sudo mv "$source" "$source.disabled-for-playwright"
fi
done
python -m playwright install --with-deps chromium
- name: Run Chromium dashboard smoke check
run: python scripts/browser_check.py
- name: Set up Node.js 22
uses: actions/setup-node@v7
with:
node-version: "22"
cache: npm
- name: Install dashboard E2E dependencies
run: npm ci
- name: Run dashboard Chromium E2E suite
run: npx playwright install --with-deps chromium && npm run test:e2e
- name: Upload browser reports and failure traces
if: always()
uses: actions/upload-artifact@v7
with:
name: browser-verification
path: |
playwright-report/
test-results/
retention-days: 14
large-storage:
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v7
with:
python-version: "3.13"
cache: pip
cache-dependency-path: |
pyproject.toml
requirements.txt
- name: Install project and development tools
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".[dev]"
- name: Run opt-in large storage tests
env:
BRAIN5D_RUN_LARGE_STORAGE_TESTS: "1"
BRAIN5D_RUN_LARGE_STORAGE_TEST: "1"
run: |
python -m pytest -v --tb=short \
tests/test_b5d_storage.py::test_large_storage_50k_neurons \
tests/test_delta_journal.py::test_large_journal_100k_entries_opt_in \
--junit-xml=large-storage-results.xml
- name: Upload large storage results
if: always()
uses: actions/upload-artifact@v7
with:
name: large-storage-results
path: large-storage-results.xml
- name: Summary
if: always()
run: echo "### Large storage tests completed" >> $GITHUB_STEP_SUMMARY
cuda-ptxas:
runs-on: ubuntu-latest
timeout-minutes: 15
container:
image: nvidia/cuda:12.6.3-devel-ubuntu24.04
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Install Python and project
run: |
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y python3 python3-pip python3-venv
python3 -m venv /opt/mhrn-venv
/opt/mhrn-venv/bin/python -m pip install --upgrade pip setuptools wheel
/opt/mhrn-venv/bin/python -m pip install -e .
/opt/mhrn-venv/bin/python -m pip install pytest
- name: CPU reference determinism and fail-closed CUDA parity
run: |
/opt/mhrn-venv/bin/python -m pytest -q \
tests/test_playground_cuda_determinism.py \
tests/test_playground_cuda_gate_compiler.py \
tests/test_playground_cuda_fail_closed.py
- name: Assemble generated Playground PTX
run: /opt/mhrn-venv/bin/python scripts/validate_playground_ptx.py
- name: Upload measured ptxas artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: playground-ptxas
path: build/playground-ptxas/
retention-days: 14
scientific-integrity:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v7
with:
python-version: "3.13"
cache: pip
cache-dependency-path: |
pyproject.toml
requirements.txt
- name: Install project and development tools
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".[dev,docs]"
- name: Scientific Integrity Gate
run: >-
python -m pytest -q
tests/test_canonical_state.py
tests/test_restore_determinism_abc.py
tests/test_engine_restore.py
tests/test_production_restore.py
tests/test_golden_chain.py
tests/test_research_registry.py
tests/test_ai_boundaries.py
tests/test_ai_governance.py
tests/test_experiment_validity.py
tests/test_connectome_embodiment.py
tests/test_stage1_scientific_contract.py
tests/test_stage1_topology_promotion_contract.py
tests/test_stage1_temporal_order_promotion_contract.py
tests/test_stage1_topology_efficiency_contract.py
tests/test_stage1_reference_replication_contract.py
tests/test_stage1_reference_preflight.py
- name: Connectome design and source integrity
run: python scripts/check_connectome_integrity.py
- name: Summary
if: always()
run: echo "### Scientific Integrity Gate completed" >> $GITHUB_STEP_SUMMARY
catalog-audit:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v7
with:
python-version: "3.13"
cache: pip
cache-dependency-path: pyproject.toml
- name: Install project
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".[dev]"
- name: Generate repository catalog audit report
run: python scripts/generate_catalog_audit_report.py
- name: Upload catalog audit reports
if: always()
uses: actions/upload-artifact@v7
with:
name: catalog-audit-report
path: |
research/generated/CATALOG_AUDIT_REPORT.md
research/generated/CATALOG_AUDIT_REPORT.json
- name: Add catalog audit to job summary
if: always()
run: cat research/generated/CATALOG_AUDIT_REPORT.md >> "$GITHUB_STEP_SUMMARY" || true
build:
runs-on: ubuntu-latest
timeout-minutes: 10
needs: [lint-format, type-check, security, tests]
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v7
with:
python-version: "3.13"
- name: Build wheel
run: |
python -m pip install --upgrade pip build
python -m build
- name: Verify wheel installs cleanly
run: |
python -m pip install dist/*.whl
cd "$(mktemp -d)"
python -c "from src.version import BRAIN5D_VERSION; from src.dashboard import file_rendering; from pathlib import Path; assert Path(file_rendering.__file__).with_name('static').joinpath('file-renderer.js').is_file(); print(BRAIN5D_VERSION)"
- name: Upload wheel artifact
uses: actions/upload-artifact@v7
with:
name: wheel
path: dist/*.whl
- name: Summary
run: |
echo "### Build successful" >> $GITHUB_STEP_SUMMARY
echo "Wheel: $(ls dist/*.whl)" >> $GITHUB_STEP_SUMMARY
docker:
runs-on: ubuntu-latest
timeout-minutes: 15
needs: [build]
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Download wheel artifact
uses: actions/download-artifact@v8
with:
name: wheel
path: dist/
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build Docker image
uses: docker/build-push-action@v7
with:
context: .
load: true
tags: mhrn:ci
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Verify Docker image runs
run: |
docker run --rm mhrn:ci python -c "
from src.core.neuron import Neuron;
from src.core.network import NeuralNetwork;
from src.storage.b5d import B5DReader;
from src.homeostasis.engine import HomeostasisEngine;
print('Docker image OK');
"
- name: Summary
run: |
echo "### Docker build passed" >> $GITHUB_STEP_SUMMARY
echo "Image: mhrn:ci" >> $GITHUB_STEP_SUMMARY
docs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v7
with:
python-version: "3.13"
- name: Install documentation check dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".[dev,docs]"
- name: Check documentation links and consistency
run: |
python scripts/check_doc_consistency.py --check-tests
echo "### Documentation structure" >> $GITHUB_STEP_SUMMARY
find docs/ -name "*.md" -type f | sort | head -50 >> $GITHUB_STEP_SUMMARY || true
ci-status:
if: always()
runs-on: ubuntu-latest
needs: [lint-format, wave4-contracts, fe-contracts, type-check, security, tests, large-storage, cuda-ptxas, scientific-integrity, catalog-audit, browser, build, docker, docs]
steps:
- name: CI Pipeline Summary
run: |
echo "## CI Pipeline Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
declare -A RESULTS
RESULTS["lint-format"]="${{ needs.lint-format.result }}"
RESULTS["wave4-contracts"]="${{ needs.wave4-contracts.result }}"
RESULTS["fe-contracts"]="${{ needs.fe-contracts.result }}"
RESULTS["type-check"]="${{ needs.type-check.result }}"
RESULTS["security"]="${{ needs.security.result }}"
RESULTS["tests"]="${{ needs.tests.result }}"
RESULTS["large-storage"]="${{ needs.large-storage.result }}"
RESULTS["cuda-ptxas"]="${{ needs.cuda-ptxas.result }}"
RESULTS["scientific-integrity"]="${{ needs.scientific-integrity.result }}"
RESULTS["catalog-audit"]="${{ needs.catalog-audit.result }}"
RESULTS["build"]="${{ needs.build.result }}"
RESULTS["docker"]="${{ needs.docker.result }}"
RESULTS["docs"]="${{ needs.docs.result }}"
RESULTS["browser"]="${{ needs.browser.result }}"
ALL_PASSED=true
for JOB in "${!RESULTS[@]}"; do
STATUS="${RESULTS[$JOB]}"
if [ "$STATUS" = "success" ]; then
echo "- **$JOB** — passed" >> $GITHUB_STEP_SUMMARY
elif [ "$STATUS" = "skipped" ] && [ "$JOB" = "large-storage" ]; then
echo "- **$JOB** — skipped" >> $GITHUB_STEP_SUMMARY
else
echo "- **$JOB** — $STATUS" >> $GITHUB_STEP_SUMMARY
ALL_PASSED=false
fi
done
echo "" >> $GITHUB_STEP_SUMMARY
if [ "$ALL_PASSED" = true ]; then
echo "**All CI checks passed!**" >> $GITHUB_STEP_SUMMARY
else
echo "**Some checks did not pass — review logs above.**" >> $GITHUB_STEP_SUMMARY
exit 1
fi