From 0f63236669ae77be3f84c9e2fc915132700a56b6 Mon Sep 17 00:00:00 2001 From: Jer Miller Date: Sat, 18 Apr 2026 09:33:20 -0600 Subject: [PATCH] build(make): decouple install-service from test suite, raise pytest timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split `make ci` into `make install-checks` (fast deterministic gates — format, ruff, rename gate, layer-hygiene, mypy) and `make verify` (install-checks + tests). `make ci` still exists and runs the full sequence; `install-service` upgrade now gates on `install-checks` instead of the full `ci` suite, so tests can't flake under real service load and abort the upgrade. Raise global pytest timeout from 5s to 15s and add @pytest.mark.timeout(30) to test_make_skills_idempotent, which is subprocess-heavy and occasionally slow on a quiet box. Co-authored-by: Codex --- INSTALL.md | 2 +- Makefile | 15 +++++++++++---- pyproject.toml | 2 +- tests/test_journal_skill.py | 3 +++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index e3e2e31c1..08a19a3ee 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -97,7 +97,7 @@ then read `solstone-macos/INSTALL.md` and follow it. git pull && make install-service ``` -re-running `make install-service` handles both fresh installs and upgrades. on upgrade it runs the full CI suite first and aborts if anything fails, leaving the installed service untouched. +re-running `make install-service` handles both fresh installs and upgrades. on upgrade it runs fast install-time gates (`make install-checks` — formatting, lint, layer hygiene, mypy) first and aborts if anything fails, leaving the installed service untouched. the full test suite is no longer gated on install, because tests can flake under real service load. for a high-confidence upgrade, run `make verify && make install-service` to execute install-checks plus the test suite before touching the running service. ## done diff --git a/Makefile b/Makefile index ba98aea8c..fc6c3131f 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ # all runs to one path and pytest wipes it on startup, destroying concurrent state. export TMPDIR := /var/tmp -.PHONY: install uninstall test test-apps test-app test-only test-integration test-integration-only test-all format format-check ci clean clean-install coverage watch versions update update-prices pre-commit skills dev all sail sandbox sandbox-stop install-pinchtab verify-browser update-browser-baselines review verify-api update-api-baselines install-service uninstall-service service-logs gate-agents-rename check-layer-hygiene +.PHONY: install uninstall test test-apps test-app test-only test-integration test-integration-only test-all format format-check install-checks ci clean clean-install coverage watch versions update update-prices pre-commit skills dev all sail sandbox sandbox-stop install-pinchtab verify-browser update-browser-baselines review verify verify-api update-api-baselines install-service uninstall-service service-logs gate-agents-rename check-layer-hygiene # Default target - install package in editable mode all: install @@ -386,7 +386,7 @@ install-service: .installed ;; \ up""grade) \ echo "mode: up""grade"; \ - $(MAKE) ci || exit $$?; \ + $(MAKE) install-checks || exit $$?; \ ;; \ fresh) \ echo "mode: fresh install"; \ @@ -455,8 +455,7 @@ clean-install: clean $(MAKE) install # Run continuous integration checks (what CI would run) -ci: .installed - @echo "Running CI checks..." +install-checks: .installed @echo "=== Checking formatting ===" @$(RUFF) format --check . || { echo "Run 'make format' to fix formatting"; exit 1; } @echo "" @@ -472,11 +471,19 @@ ci: .installed @echo "=== Running mypy ===" @$(MYPY) . || true @echo "" + +ci: install-checks @echo "=== Running tests ===" @$(MAKE) test @echo "" @echo "All CI checks passed!" +verify: install-checks + @echo "=== Running tests ===" + @$(MAKE) test + @echo "" + @echo "Verification complete!" + # Watch for changes and run tests (requires pytest-watch) watch: .installed @$(UV) pip show pytest-watch >/dev/null 2>&1 || { echo "Installing pytest-watch..."; $(UV) pip install pytest-watch; } diff --git a/pyproject.toml b/pyproject.toml index b8b4dcb3c..fbfe3ad24 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -142,7 +142,7 @@ python_functions = ["test_*"] markers = [ "integration: marks tests as integration tests (deselect with '-m \"not integration\"')", ] -timeout = 5 +timeout = 15 tmp_path_retention_policy = "none" filterwarnings = [ # Third-party deprecation warnings (Python 3.14+) diff --git a/tests/test_journal_skill.py b/tests/test_journal_skill.py index 7f6caa4ef..bc4b784aa 100644 --- a/tests/test_journal_skill.py +++ b/tests/test_journal_skill.py @@ -7,6 +7,8 @@ import shutil import subprocess from pathlib import Path +import pytest + def _repo_root() -> Path: return Path(__file__).resolve().parent.parent @@ -59,6 +61,7 @@ def test_journal_template_symlinks_resolve_inside_repo(): _assert_inside_repo(path, repo_root) +@pytest.mark.timeout(30) def test_make_skills_idempotent(tmp_path): repo_root = _repo_root() temp_root = tmp_path / "repo" -- 2.51.2