personal memory agent
0

Configure Feed

Select the types of activity you want to include in your feed.

solstone / Makefile
41 kB 909 lines
1# solstone Makefile 2# Python-based AI-driven desktop journaling toolkit 3 4# Route pytest tmp dirs to /var/tmp (disk) instead of default /tmp (tmpfs/RAM). 5# Each top-level pytest invocation gets its own --basetemp so concurrent runs 6# in different worktrees do not share /var/tmp/pytest-of-$USER/pytest-N/. The 7# basetemp is created at recipe runtime (not parse time) and removed via shell 8# trap on exit, so non-test make targets don't leak empty dirs and test runs 9# don't leak full ones. PYTEST_BASETEMP_INIT must be on the same recipe shell 10# line as PYTEST_BASETEMP_FLAG (each recipe line is its own shell). Do not 11# re-add --basetemp to pyproject — it would pin all runs to one path and 12# pytest wipes it on startup, destroying concurrent state. 13export TMPDIR := /var/tmp 14PYTEST_BASETEMP_INIT := BASETEMP=$$(mktemp -d /var/tmp/solstone-pytest-XXXXXX); trap 'rm -rf "$$BASETEMP"' EXIT INT TERM; 15PYTEST_BASETEMP_FLAG := --basetemp "$$BASETEMP" 16 17.PHONY: install hopper-install uninstall test test-cov test-integration test-performance test-app test-only format format-check install-checks ci clean clean-install coverage watch versions update update-prices preflight pre-commit skills render-packaging check-rust-fmt check-rust-msrv check-rust-clippy check-rust-test check-rust-ios check-rust-deny check-release-advisory-liveness check-rust-release-manifest audit openapi check-openapi check-openapi-observer-client-contract contract check-contract journal-resolution-vectors check-journal-resolution-vectors build-native-sol-grammar-oracle check-native-sol-grammar-oracle build-native-sol-root-contract check-native-sol-root-contract check-core-sdist-compile-inputs build-native-sol-journal-host-commands check-native-sol-journal-host-commands build-journal-access-rejection-inventory check-journal-access-rejection-inventory check-native-sol-python-manifest build-native-sol-inventory check-native-sol-inventory check-native-sol-architecture check-native-sol-contract-routes check-native-sol-conformance check-native-sol-coverage check-native-sol-no-python-spawn check-native-sol-compat check-native-sol-docs-links check-removed-time-parser-ready dev all sandbox sandbox-stop install-models parakeet-helper parakeet-helper-clean wheel-macos wheel-macos-clean verify verify-api verify-schemathesis update-api-baselines eval-schemas service-logs check-layer-hygiene check-api-conventions check-journal-io-access check-journal-io-mechanic check-journal-config-owner check-call-http-only check-no-legacy-chat check-channel-adapter-scrub check-brain-health-cutover check-tools-http-only check-access-imports-clean check-convey-bind-imports-clean check-schema-bounds check-thin-base-install check-extras-consistency check-cogitate-prompts smoke-cogitate release release-test publish-release publish-release-test FORCE 18 19# Default target - install package in editable mode 20all: install 21 22# Virtual environment directory 23VENV := .venv 24VENV_BIN := $(VENV)/bin 25VENV_PY := $(VENV_BIN)/python 26PYTHON := $(VENV_PY) 27RUST_MANIFEST := core/Cargo.toml 28IOS_TARGET := aarch64-apple-ios 29REQUIRE_CARGO := command -v cargo >/dev/null 2>&1 || { echo "cargo is required for Rust checks; install cargo and retry" >&2; exit 1; } 30REQUIRE_RUSTUP := command -v rustup >/dev/null 2>&1 || { echo "rustup is required for the iOS gate; install rustup and retry" >&2; exit 1; } 31# Pick the GPU (CUDA) journal runtime only on x86_64 NVIDIA hosts. The 32# CUDA bundle resolves onnxruntime-gpu, which ships NO aarch64 wheel on PyPI, so 33# an aarch64 NVIDIA host (e.g. DGX Spark / GB10) that auto-selected `cuda` would 34# die in the `.installed` `uv sync` below — before the per-arch `install` guard 35# (which correctly skips non-x86_64 Linux) ever runs. Gating on x86_64 also 36# keeps this coherent with the STT arch decision (aarch64-linux uses the 37# parakeet.cpp CPU/Vulkan bundle). Everything non-x86_64 falls to the CPU 38# `journal-cpu` group, whose onnxruntime has aarch64 wheels. 39JOURNAL_VARIANT ?= $(shell if [ "$$(uname -m)" = "x86_64" ] && nvidia-smi -L >/dev/null 2>&1; then echo cuda; else echo cpu; fi) 40 41# Dev install groups: install exactly ONE journal leaf for this host. 42# `journal-cpu` and `journal-cuda` select the same journal stack and differ only 43# in the ONNX runtime package, so NEVER install both and NEVER use all optional 44# dependency groups: 45# - `journal-cpu` pulls onnxruntime; `journal-cuda` pulls onnxruntime-gpu. Both 46# packages own the SAME onnxruntime/ import dir and clobber each other -> 47# `import onnxruntime` fails (ModuleNotFoundError) even though uv still 48# lists it installed. Surfaces as `journal install-models` dying with "No 49# module named 'onnxruntime'". 50# - on Darwin, resolving the CUDA group also forces cuda's nvidia-* wheels, 51# which have no arm64 builds, so `uv sync` errors out outright. 52# Pick the GPU group only on NVIDIA hosts; everyone else gets the CPU group. 53JOURNAL_GROUP := $(if $(filter cuda,$(JOURNAL_VARIANT)),journal-cuda,journal-cpu) 54 55# Require uv only for goals that actually use it. `preflight` is a pure 56# stdlib readiness battery and `install` runs preflight as its own fail-fast 57# pre-step, so neither should abort at parse time when uv is absent — they 58# report uv-absence themselves. test/ci/etc. still abort early. 59UV := $(shell command -v uv 2>/dev/null) 60UV_OPTIONAL_GOALS := preflight install render-packaging check-rust-fmt check-rust-msrv check-rust-clippy check-rust-test check-rust-ios check-rust-deny audit 61ifndef UV 62ifneq ($(filter-out $(UV_OPTIONAL_GOALS),$(MAKECMDGOALS)),) 63$(error uv is not installed. Install it: curl -LsSf https://astral.sh/uv/install.sh | sh) 64endif 65endif 66 67# User bin directory for symlink (standard location, usually already in PATH) 68USER_BIN := $(HOME)/.local/bin 69 70.python-version-hash: FORCE 71 @tmp_file=$$(mktemp); \ 72 python3 -c "import sys; print(sys.version_info[:2])" > "$$tmp_file"; \ 73 if [ ! -f $@ ] || ! cmp -s "$$tmp_file" $@; then mv "$$tmp_file" $@; else rm -f "$$tmp_file"; fi 74 75# The native `solstone-core` binary is built by maturin from Rust sources that 76# live OUTSIDE its package directory — packages/solstone-core/pyproject.toml 77# points maturin at ../../core. So none of `.installed`'s other prerequisites 78# move when native code changes: `.installed` stays satisfied, `uv sync` never 79# runs, and .venv/bin/solstone-core keeps serving whatever was built at first 80# install. Every Python test and check that shells out to that binary then 81# exercises stale native bytes while reporting green. This stamp puts the Rust 82# tree into the prerequisite chain; the `cache-keys` block in 83# packages/solstone-core/pyproject.toml is what makes the `uv sync` this 84# triggers actually rebuild. Hashed by content, not mtime, so a checkout or a 85# touch that changes nothing does not force a reinstall. core/target/ is 86# deliberately absent — the build writes it, so keying on it never settles. 87.rust-core-hash: FORCE 88 @tmp_file=$$(mktemp); \ 89 python3 -c 'import hashlib, pathlib; root = pathlib.Path("core"); pats = ("Cargo.toml", "Cargo.lock", "crates/**/Cargo.toml", "crates/**/*.rs", "fixtures/**/*"); paths = sorted({p for pat in pats for p in root.glob(pat) if p.is_file()}); print(hashlib.sha256(b"".join(str(p).encode() + b"\0" + p.read_bytes() + b"\0" for p in paths)).hexdigest())' > "$$tmp_file"; \ 90 if [ ! -f $@ ] || ! cmp -s "$$tmp_file" $@; then mv "$$tmp_file" $@; else rm -f "$$tmp_file"; fi 91 92# Marker file to track installation 93.installed: pyproject.toml packages/*/pyproject.toml uv.lock .python-version-hash .rust-core-hash 94 python3 scripts/render_packaging.py 95 $(MAKE) preflight 96 @echo "Installing package with uv..." 97 $(UV) sync --group dev --group $(JOURNAL_GROUP) 98 @# Python 3.14+ needs onnxruntime from nightly (not yet on PyPI) 99 @OS_NAME=$$(uname -s); \ 100 PY_MINOR=$$($(PYTHON) -c "import sys; print(sys.version_info.minor)"); \ 101 if [ "$$OS_NAME" = "Darwin" ] && [ "$$PY_MINOR" -ge 14 ]; then \ 102 echo "Python 3.14+ detected - installing onnxruntime from nightly feed..."; \ 103 $(UV) pip install --pre --no-deps --index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/ORT-Nightly/pypi/simple/ onnxruntime; \ 104 fi 105 @# The `--group $(JOURNAL_GROUP)` sync above already pulls the right 106 @# ONNX runtime package (journal-cpu = CPU, journal-cuda = GPU). 107 @$(MAKE) --no-print-directory skills 108 @touch .installed 109 110# Generate lock file if missing 111uv.lock: pyproject.toml packages/*/pyproject.toml 112 python3 scripts/render_packaging.py 113 $(UV) lock 114 115# Install package in editable mode with isolated venv 116install: .installed 117 @(cd /tmp && $(CURDIR)/$(VENV_BIN)/python -c "from solstone.think.sol_compat_cli import main") 2>/dev/null || { \ 118 echo ">>> re-registering editable install"; \ 119 $(UV) pip install -e . --no-deps; \ 120 if (cd /tmp && $(CURDIR)/$(VENV_BIN)/python -c "from solstone.think.sol_compat_cli import main"); then \ 121 echo ">>> re-registered successfully"; \ 122 else \ 123 echo ">>> editable install still broken; run make clean-install"; \ 124 exit 1; \ 125 fi; \ 126 } 127 @OS_NAME=$$(uname -s); \ 128 ARCH=$$(uname -m); \ 129 if [ "$$OS_NAME" = "Darwin" ] && [ "$$ARCH" = "arm64" ]; then \ 130 $(MAKE) parakeet-helper || { echo 'parakeet install: helper build failed' >&2; exit 1; }; \ 131 elif [ "$$OS_NAME" = "Linux" ]; then \ 132 if [ "$$ARCH" = "x86_64" ]; then \ 133 echo "journal install: JOURNAL_GROUP=$(JOURNAL_GROUP)"; \ 134 $(UV) sync --group dev --group $(JOURNAL_GROUP) || { echo "journal install: uv sync --group dev --group $(JOURNAL_GROUP) failed" >&2; exit 1; }; \ 135 if [ "$(JOURNAL_VARIANT)" = "cuda" ]; then \ 136 $(UV) sync --group dev --group $(JOURNAL_GROUP) --reinstall-package onnxruntime-gpu || { echo "journal install: failed to force-reinstall onnxruntime-gpu" >&2; exit 1; }; \ 137 $(VENV_PY) -c "import onnxruntime as ort; ort.preload_dlls(cuda=True, cudnn=True); assert 'CUDAExecutionProvider' in ort.get_available_providers(), 'CUDAExecutionProvider missing after install'; print('journal install: CUDA runtime ready')" || { echo "journal install: CUDA runtime validation failed" >&2; exit 1; }; \ 138 fi; \ 139 else \ 140 echo "journal install: skipping unsupported Linux arch $$ARCH"; \ 141 fi; \ 142 else \ 143 echo "parakeet install: unsupported host '$$OS_NAME/$$ARCH'; supported: darwin/arm64, linux/x86_64" >&2; \ 144 exit 1; \ 145 fi 146 @touch .installed 147 @$(VENV_BIN)/journal install-models || { echo "journal install-models failed" >&2; exit 1; } 148 149# Lean lode bootstrap: build only the base dependency layer (.installed) that 150# `make ci` needs — venv + dev/host journal deps + skills. Runtime/model 151# provisioning (parakeet build, forced onnxruntime-gpu reinstall + CUDA 152# validation, journal install-models) is intentionally deferred to `install`. 153hopper-install: .installed 154 155# Stdlib-only install-readiness battery — runs before `.venv`/`uv` exist; a 156# blocker failure exits non-zero. Also wired as the first step of `.installed`. 157preflight: 158 python3 scripts/preflight.py 159 160render-packaging: 161 python3 scripts/render_packaging.py 162 163check-rust-fmt: 164 @$(REQUIRE_CARGO) 165 cargo fmt --manifest-path $(RUST_MANIFEST) --all -- --check 166 167check-rust-msrv: 168 @$(REQUIRE_CARGO) 169 @python3 scripts/check_release_preflight.py msrv --toolchain 1.95.0 170 RUSTUP_TOOLCHAIN=1.95.0 cargo check --manifest-path $(RUST_MANIFEST) --workspace --locked 171 172check-rust-clippy: 173 @$(REQUIRE_CARGO) 174 cargo clippy --manifest-path $(RUST_MANIFEST) --workspace --all-targets --locked -- -D warnings 175 176check-rust-test: 177 @$(REQUIRE_CARGO) 178 cargo test --manifest-path $(RUST_MANIFEST) --workspace --locked 179 180check-rust-ios: 181 @$(REQUIRE_CARGO) 182 @$(REQUIRE_RUSTUP) 183 @rustup target list --installed 2>/dev/null | grep -qx "$(IOS_TARGET)" || { echo "Rust target $(IOS_TARGET) is required for the iOS gate; run rustup target add $(IOS_TARGET)" >&2; exit 1; } 184 cargo check --manifest-path $(RUST_MANIFEST) --workspace --exclude solstone-core --exclude solstone-core-indexer-store --lib --target $(IOS_TARGET) --locked 185 186check-rust-deny: 187 @$(REQUIRE_CARGO) 188 @python3 scripts/check_release_preflight.py cargo-deny 189 cargo deny --manifest-path $(RUST_MANIFEST) --locked --offline check bans licenses sources 190 191audit: 192 @$(REQUIRE_CARGO) 193 @python3 scripts/check_release_preflight.py cargo-deny >&2 194 @python3 scripts/advisory_mirror_audit.py --bundle "$(AUDIT_ADVISORY_BUNDLE)" --receipt "$(AUDIT_ADVISORY_RECEIPT)" --pubkey "$(AUDIT_ADVISORY_PUBKEY)" --locator "$(AUDIT_ADVISORY_LOCATOR)" 195 196# Setup skill symlinks 197skills: 198 @$(VENV_BIN)/python scripts/build_skill_references.py 199 @$(VENV_BIN)/sol skills install --project journal --agent all 200 201# Start local dev stack against fixture journal (no observers, no daily processing) 202dev: .installed 203 $(TEST_ENV) PATH=$(CURDIR)/$(VENV_BIN):$$PATH $(VENV_BIN)/journal supervisor 0 --no-daily 204 205# Start sandbox stack: fixture copy + background supervisor + readiness wait 206sandbox: .installed 207 @# Fail if sandbox already running 208 @if [ -f .sandbox.pid ] && kill -0 $$(cat .sandbox.pid) 2>/dev/null; then \ 209 echo "Sandbox already running (PID $$(cat .sandbox.pid))"; \ 210 echo "Run 'make sandbox-stop' first."; \ 211 exit 1; \ 212 fi 213 @# Clean up stale state from a previous crashed sandbox 214 @if [ -f .sandbox.journal ]; then \ 215 rm -rf "$$(cat .sandbox.journal)" 2>/dev/null; \ 216 rm -f .sandbox.pid .sandbox.journal; \ 217 fi 218 @# Copy fixtures to temp dir 219 @SANDBOX_JOURNAL=$$(mktemp -d /tmp/solstone-sandbox-XXXXXX); \ 220 cp -r tests/fixtures/journal/* "$$SANDBOX_JOURNAL/"; \ 221 echo "$$SANDBOX_JOURNAL" > .sandbox.journal; \ 222 echo "Sandbox journal: $$SANDBOX_JOURNAL"; \ 223 : "Boot supervisor in background"; \ 224 SOLSTONE_JOURNAL="$$SANDBOX_JOURNAL" SANDBOX_PATH="$(CURDIR)/$(VENV_BIN):$$PATH" SANDBOX_LOG="$$SANDBOX_JOURNAL/health/service.log" JOURNAL_BIN="$(CURDIR)/$(VENV_BIN)/journal" \ 225 $(VENV_PY) scripts/start_sandbox_supervisor.py > .sandbox.pid; \ 226 echo "Supervisor PID: $$(cat .sandbox.pid)"; \ 227 : "Poll for readiness"; \ 228 echo "Waiting for services..."; \ 229 READY=false; \ 230 for i in $$(seq 1 20); do \ 231 if SOLSTONE_JOURNAL="$$SANDBOX_JOURNAL" $(VENV_BIN)/journal health > /dev/null 2>&1; then \ 232 READY=true; \ 233 break; \ 234 fi; \ 235 sleep 1; \ 236 done; \ 237 if [ "$$READY" = "false" ]; then \ 238 echo "Readiness timeout - killing supervisor"; \ 239 kill $$(cat .sandbox.pid) 2>/dev/null || true; \ 240 rm -rf "$$SANDBOX_JOURNAL" .sandbox.pid .sandbox.journal; \ 241 exit 1; \ 242 fi; \ 243 CONVEY_PORT=$$(cat "$$SANDBOX_JOURNAL/health/convey.port" 2>/dev/null); \ 244 echo ""; \ 245 echo "Sandbox is ready!"; \ 246 echo " Convey: http://localhost:$$CONVEY_PORT/"; \ 247 echo " Journal: $$SANDBOX_JOURNAL"; \ 248 echo " Stop: make sandbox-stop" 249 250# Stop sandbox: terminate supervisor, clean up temp dir and state files 251sandbox-stop: 252 @if [ ! -f .sandbox.pid ]; then \ 253 echo "No sandbox running."; \ 254 exit 0; \ 255 fi; \ 256 PID=$$(cat .sandbox.pid); \ 257 echo "Stopping supervisor (PID $$PID)..."; \ 258 kill "$$PID" 2>/dev/null || true; \ 259 : "Wait up to 5s for clean shutdown"; \ 260 for i in $$(seq 1 10); do \ 261 kill -0 "$$PID" 2>/dev/null || break; \ 262 sleep 0.5; \ 263 done; \ 264 kill -9 "$$PID" 2>/dev/null || true; \ 265 if [ -f .sandbox.journal ]; then \ 266 SANDBOX_JOURNAL=$$(cat .sandbox.journal); \ 267 rm -rf "$$SANDBOX_JOURNAL"; \ 268 echo "Removed $$SANDBOX_JOURNAL"; \ 269 fi; \ 270 rm -f .sandbox.pid .sandbox.journal; \ 271 echo "Sandbox stopped." 272 273.PHONY: sandbox-seed-observers 274sandbox-seed-observers: ## Seed 4 sample observers into the running sandbox journal 275 @test -s .sandbox.journal || (echo "No sandbox running. Run 'make sandbox' first." && exit 1) 276 @SOLSTONE_JOURNAL=$$(cat .sandbox.journal) $(VENV_BIN)/python tests/fixtures/seed_observers.py 277 278# Verify API baselines against running sandbox 279verify-api: .installed 280 @echo "Verifying API baselines (sandbox)..." 281 @$(MAKE) sandbox 282 @SANDBOX_JOURNAL=$$(cat .sandbox.journal); \ 283 CONVEY_PORT=$$(cat "$$SANDBOX_JOURNAL/health/convey.port"); \ 284 RESULT=0; \ 285 SOLSTONE_JOURNAL="$$SANDBOX_JOURNAL" $(VENV_BIN)/journal indexer --rescan-full > /dev/null; \ 286 SOLSTONE_JOURNAL="$$SANDBOX_JOURNAL" $(VENV_BIN)/python tests/verify_api.py verify --base-url "http://localhost:$$CONVEY_PORT" || RESULT=$$?; \ 287 $(MAKE) sandbox-stop; \ 288 exit $$RESULT 289 290# tests/conftest.py overwrites SOLSTONE_JOURNAL; pass sandbox via a private env var. 291verify-schemathesis: .installed ## Run Schemathesis read allowlist against disposable live sandbox 292 @echo "Verifying OpenAPI contract with Schemathesis (disposable live sandbox)..." 293 @$(MAKE) sandbox 294 @SANDBOX_JOURNAL=$$(cat .sandbox.journal); \ 295 RESULT=0; \ 296 SOLSTONE_SCHEMATHESIS_JOURNAL="$$SANDBOX_JOURNAL" \ 297 SOLSTONE_SCHEMATHESIS_LIVE=1 \ 298 $(VENV_BIN)/pytest tests/test_openapi_schemathesis.py -q || RESULT=$$?; \ 299 $(MAKE) sandbox-stop; \ 300 exit $$RESULT 301 302eval-schemas: .installed 303 $(VENV_BIN)/python tests/eval_schemas.py 304 305# Regenerate API baseline files. By default uses the deterministic Flask 306# test-client path (frozen time). For sandbox-only endpoints (graph, search, 307# badge-count, updated-days), pass SANDBOX=1 to regenerate from the live 308# sandbox — these rely on the indexer and real clock. 309update-api-baselines: .installed 310 @if [ "$(SANDBOX)" = "1" ]; then \ 311 echo "Updating API baselines (sandbox, includes sandbox-only endpoints)..."; \ 312 $(MAKE) sandbox; \ 313 SANDBOX_JOURNAL=$$(cat .sandbox.journal); \ 314 CONVEY_PORT=$$(cat "$$SANDBOX_JOURNAL/health/convey.port"); \ 315 RESULT=0; \ 316 SOLSTONE_JOURNAL="$$SANDBOX_JOURNAL" $(VENV_BIN)/journal indexer --rescan-full > /dev/null; \ 317 SOLSTONE_JOURNAL="$$SANDBOX_JOURNAL" $(VENV_BIN)/python tests/verify_api.py update --base-url "http://localhost:$$CONVEY_PORT" || RESULT=$$?; \ 318 $(MAKE) sandbox-stop; \ 319 exit $$RESULT; \ 320 else \ 321 echo "Updating API baselines (test client)..."; \ 322 $(VENV_BIN)/python tests/verify_api.py update; \ 323 fi 324 325 326# Install and verify local ML models 327install-models: 328 @test -x "$(VENV_BIN)/sol" || { echo "missing $(VENV_BIN)/sol; run make install first" >&2; exit 1; } 329 $(VENV_BIN)/journal install-models 330 331# Build the parakeet helper binary (macOS/arm64 only, requires Xcode CLT) 332parakeet-helper: 333 cd solstone/observe/transcribe/parakeet_helper && swift build -c release 334 @echo "built: $$(pwd)/solstone/observe/transcribe/parakeet_helper/.build/release/parakeet-helper" 335 336# Remove parakeet helper build artifacts 337parakeet-helper-clean: 338 rm -rf solstone/observe/transcribe/parakeet_helper/.build solstone/observe/transcribe/parakeet_helper/.swiftpm solstone/observe/transcribe/parakeet_helper/Package.resolved 339 340# Build a signed/notarized macOS Apple Silicon platform wheel 341# (Darwin/arm64 only; requires Xcode CLT, Developer ID cert, and the 342# `sol-pbc-notary` notarytool keychain profile in sol-signing.keychain-db). 343# `uv build` runs in its own PEP 517 isolated env, so this target intentionally 344# does not depend on `.installed` — the wheel build is fully decoupled from 345# the dev venv install state. 346ifeq ($(shell uname -s)/$(shell uname -m),Darwin/arm64) 347wheel-macos: parakeet-helper 348 @ROOT_FACTS=$$(mktemp); \ 349 trap 'rm -f "$$ROOT_FACTS"' EXIT; \ 350 echo "==> signing and notarizing parakeet-helper"; \ 351 ./scripts/sign-and-notarize-helper.sh solstone/observe/transcribe/parakeet_helper/.build/release/parakeet-helper > "$$ROOT_FACTS"; \ 352 echo "==> staging helper into _bin/"; \ 353 mkdir -p solstone/observe/transcribe/parakeet_helper/_bin; \ 354 cp solstone/observe/transcribe/parakeet_helper/.build/release/parakeet-helper solstone/observe/transcribe/parakeet_helper/_bin/parakeet-helper; \ 355 echo "==> building macosx_14_0_arm64 platform wheel"; \ 356 rm -rf build/ *.egg-info/; \ 357 $(UV) build --wheel -C--build-option=--plat-name=macosx_14_0_arm64; \ 358 ROOT_MAC_WHEEL=$$(ls dist/solstone-*-macosx_14_0_arm64.whl); \ 359 SOURCE_COMMIT=$$(git rev-parse HEAD); \ 360 CORE_LOCK_SHA256=$$(shasum -a 256 core/Cargo.lock | awk '{print $$1}'); \ 361 python3 -m scripts.record_macos_native_wheel --role root --wheel "$$ROOT_MAC_WHEEL" --signing-facts "$$ROOT_FACTS" --source-commit "$$SOURCE_COMMIT" --core-lock-sha256 "$$CORE_LOCK_SHA256" --out dist/macos-native-root.json 362 @echo "==> building macosx_14_0_arm64 solstone-core wheel" 363 MACOSX_DEPLOYMENT_TARGET=14.0 MATURIN_PEP517_ARGS="--locked --target aarch64-apple-darwin" $(UV) build --package solstone-core --wheel 364 @echo "==> signing and notarizing solstone-core" 365 @CORE_MAC_WHEEL=$$(ls dist/solstone_core-*-macosx_14_0_arm64.whl); \ 366 CORE_FACTS=$$(mktemp); \ 367 CORE_TMP=$$(mktemp -d); \ 368 trap 'rm -rf "$$CORE_TMP" "$$CORE_FACTS"' EXIT; \ 369 python3 -m zipfile -e "$$CORE_MAC_WHEEL" "$$CORE_TMP"; \ 370 for name in solstone-core; do \ 371 CORE_BINARY=$$(find "$$CORE_TMP" -path "*.data/scripts/$$name" -type f -print -quit); \ 372 test -n "$$CORE_BINARY" || { echo "missing $$name binary in $$CORE_MAC_WHEEL" >&2; exit 1; }; \ 373 echo "==> signing and notarizing $$name"; \ 374 ./scripts/sign-and-notarize-helper.sh "$$CORE_BINARY" > "$$CORE_TMP/$$name.signing-facts.json"; \ 375 done; \ 376 python3 -c 'import json, sys; from pathlib import Path; root = Path(sys.argv[1]); out = Path(sys.argv[2]); names = ("solstone-core",); payload = {"members": {name: json.loads((root / f"{name}.signing-facts.json").read_text()) for name in names}}; out.write_text(json.dumps(payload, sort_keys=True) + "\n")' "$$CORE_TMP" "$$CORE_FACTS"; \ 377 python3 scripts/repack_wheel_record.py "$$CORE_TMP" "$$CORE_MAC_WHEEL"; \ 378 SOURCE_COMMIT=$$(git rev-parse HEAD); \ 379 CORE_LOCK_SHA256=$$(shasum -a 256 core/Cargo.lock | awk '{print $$1}'); \ 380 python3 -m scripts.record_macos_native_wheel --role core --wheel "$$CORE_MAC_WHEEL" --signing-facts "$$CORE_FACTS" --source-commit "$$SOURCE_COMMIT" --core-lock-sha256 "$$CORE_LOCK_SHA256" --out dist/macos-native-core.json 381else 382wheel-macos: 383 @echo "wheel-macos: only supported on Darwin/arm64 (got $(shell uname -s)/$(shell uname -m))" >&2 384 @exit 1 385endif 386 387# Remove the staged helper copy that wheel-macos installs into _bin/ 388wheel-macos-clean: 389 rm -rf solstone/observe/transcribe/parakeet_helper/_bin 390 391# Test environment - use fixtures journal for all tests 392TEST_ENV = SOLSTONE_JOURNAL=tests/fixtures/journal 393 394# Venv tool shortcuts 395PYTEST := $(VENV_BIN)/pytest 396RUFF := $(VENV_BIN)/ruff 397 398# Keep the default full-suite fan-out LOW: this box runs many concurrent 399# sessions/lodes each invoking `make test`, and their worker pools multiply — 400# concurrent 8-worker suites OOM'd the box on 2026-07-03 (systemd-oomd killed 401# the hub daemon, hopper, and several agent sessions). Override with 402# `make PYTEST_MAX_WORKERS=16 test` on a dedicated/idle box. 403PYTEST_MAX_WORKERS ?= 2 404PYTEST_XDIST_ARGS := -n auto --maxprocesses $(PYTEST_MAX_WORKERS) --dist loadgroup 405PYTEST_UNIT_ARGS := -m "not integration and not performance" 406 407# Check formatting without modifying files — gates `make test` 408format-check: .installed 409 @$(RUFF) format --check . || { echo "Run 'make format' to fix formatting"; exit 1; } 410 411# Run all unit tests — core (tests/) + every app (solstone/apps/*/tests/). 412# xdist lives here, not in pyproject addopts, so bare pytest / pytest-watch / 413# IDE runs stay serial. 414test: .installed format-check 415 @echo "Running unit tests (core + apps)..." 416 $(PYTEST_BASETEMP_INIT) $(TEST_ENV) $(PYTEST) $(PYTEST_BASETEMP_FLAG) tests/ solstone/apps/ -q $(PYTEST_UNIT_ARGS) $(PYTEST_XDIST_ARGS) 417 418# Same suite with full-repo coverage (operator opt-in; used by verify). 419test-cov: .installed format-check 420 @echo "Running unit tests with coverage (core + apps)..." 421 $(PYTEST_BASETEMP_INIT) $(TEST_ENV) $(PYTEST) $(PYTEST_BASETEMP_FLAG) tests/ solstone/apps/ -q --cov=. $(PYTEST_UNIT_ARGS) $(PYTEST_XDIST_ARGS) 422 423# Real external-process probes are valuable operator validation, not unit CI. 424test-integration: .installed format-check 425 @echo "Running integration tests..." 426 $(PYTEST_BASETEMP_INIT) $(TEST_ENV) $(PYTEST) $(PYTEST_BASETEMP_FLAG) tests/ solstone/apps/ -q -m integration $(PYTEST_XDIST_ARGS) 427 428# Wall-clock thresholds are intentionally opt-in so loaded hosts do not make CI flaky. 429test-performance: .installed format-check 430 @echo "Running performance tests..." 431 $(PYTEST_BASETEMP_INIT) $(TEST_ENV) $(PYTEST) $(PYTEST_BASETEMP_FLAG) tests/ solstone/apps/ -q -m performance 432 433# Run a single app's tests 434test-app: .installed 435 @if [ -z "$(APP)" ]; then \ 436 echo "Usage: make test-app APP=<app_name>"; \ 437 echo "Example: make test-app APP=todos"; \ 438 exit 1; \ 439 fi 440 $(PYTEST_BASETEMP_INIT) PYTHONPATH=$(CURDIR) $(TEST_ENV) $(PYTEST) $(PYTEST_BASETEMP_FLAG) solstone/apps/$(APP)/tests/ -v 441 442# Run specific test file or pattern 443test-only: .installed 444 @if [ -z "$(TEST)" ]; then \ 445 echo "Usage: make test-only TEST=<test_file_or_pattern>"; \ 446 echo "Example: make test-only TEST=tests/test_utils.py"; \ 447 echo "Example: make test-only TEST=\"-k test_function_name\""; \ 448 exit 1; \ 449 fi 450 $(PYTEST_BASETEMP_INIT) $(TEST_ENV) $(PYTEST) $(PYTEST_BASETEMP_FLAG) $(TEST) 451 452# Auto-format and fix code, then report any remaining issues 453format: .installed 454 @echo "Formatting and fixing code with ruff..." 455 @$(RUFF) format . 456 @$(RUFF) check --fix . 457 @echo "" 458 @echo "Checking for remaining issues..." 459 @if $(RUFF) check .; then \ 460 echo ""; \ 461 echo "All clean!"; \ 462 else \ 463 echo ""; \ 464 echo "Issues above need manual fixes."; \ 465 fi 466 467# Clean build artifacts and cache files 468clean: 469 @echo "Cleaning build artifacts and cache files..." 470 rm -rf build/ dist/ *.egg-info/ 471 rm -rf .pytest_cache/ .coverage 472 rm -rf journal/.agents/ journal/.claude/ 473 find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true 474 find . -type f -name "*.pyc" -delete 475 find . -type f -name "*.pyo" -delete 476 find . -type f -name ".DS_Store" -delete 477 rm -f .installed 478 479# Follow installed service logs 480service-logs: 481 $(VENV_BIN)/journal service logs -f 482 483uninstall: 484 @echo "Error: 'make uninstall' is disabled. Use 'journal service uninstall', 'sol skills uninstall', and 'python -m solstone.think.install_guard uninstall' to remove installed user artifacts, or 'make clean-install' to rebuild the local dev environment." >&2 485 @exit 1 486 487FORCE: 488 489# Clean everything and reinstall 490clean-install: clean 491 rm -rf $(VENV) .installed 492 $(MAKE) install 493 494# Run continuous integration checks (what CI would run) 495install-checks: .installed 496 @echo "=== Checking formatting ===" 497 @$(RUFF) format --check . || { echo "Run 'make format' to fix formatting"; exit 1; } 498 @echo "" 499 @echo "=== Running ruff ===" 500 @$(RUFF) check . || { echo "Run 'make format' to auto-fix"; exit 1; } 501 @echo "" 502 @echo "=== Running layer-hygiene check ===" 503 @$(MAKE) check-layer-hygiene 504 @echo "" 505 @echo "=== Running API-conventions check ===" 506 @$(MAKE) check-api-conventions 507 @echo "" 508 @echo "=== Running journal-io access check ===" 509 @$(MAKE) check-journal-io-access 510 @echo "" 511 @echo "=== Running journal-io mechanic check ===" 512 @$(MAKE) check-journal-io-mechanic 513 @echo "" 514 @echo "=== Running journal-config owner check ===" 515 @$(MAKE) check-journal-config-owner 516 @echo "" 517 @echo "=== Running provider-install owner check ===" 518 @$(MAKE) check-provider-install-owner 519 @echo "" 520 @echo "=== Running provider-start-command check ===" 521 @$(MAKE) check-provider-start-commands 522 @echo "=== Running legacy-chat surface check ===" 523 @$(MAKE) check-no-legacy-chat 524 @echo "" 525 @echo "=== Running channel-adapter scrub check ===" 526 @$(MAKE) check-channel-adapter-scrub 527 @echo "" 528 @echo "=== Running brain-health cutover check ===" 529 @$(MAKE) check-brain-health-cutover 530 @echo "" 531 @echo "=== Running schema-bounds check ===" 532 @$(MAKE) check-schema-bounds 533 @echo "" 534 @echo "=== Running rust release-manifest check ===" 535 @$(MAKE) check-rust-release-manifest 536 @echo "=== Running access-imports-clean check ===" 537 @$(MAKE) check-access-imports-clean 538 @echo "" 539 @echo "=== Running convey-bind-imports-clean check ===" 540 @$(MAKE) check-convey-bind-imports-clean 541 @echo "" 542 @echo "=== Running cogitate-prompt check ===" 543 @$(MAKE) check-cogitate-prompts 544 @echo "" 545 @echo "=== Checking native sol grammar oracle ===" 546 @$(MAKE) check-native-sol-grammar-oracle 547 @echo "" 548 @echo "=== Checking native sol root contract ===" 549 @$(MAKE) check-native-sol-root-contract 550 @echo "" 551 @echo "=== Checking core sdist compile inputs ===" 552 @$(MAKE) check-core-sdist-compile-inputs 553 @echo "" 554 @echo "=== Checking native sol journal-host command inventory ===" 555 @$(MAKE) check-native-sol-journal-host-commands 556 @echo "" 557 @echo "=== Checking journal access rejection inventory ===" 558 @$(MAKE) check-journal-access-rejection-inventory 559 @echo "" 560 @echo "=== Checking native sol docs links ===" 561 @$(MAKE) check-native-sol-docs-links 562 @echo "" 563 @echo "=== Checking removed time parser readiness ===" 564 @$(MAKE) check-removed-time-parser-ready 565 @echo "" 566 @echo "=== Checking native sol Python manifest ===" 567 @$(MAKE) check-native-sol-python-manifest 568 @echo "" 569 @echo "=== Checking native sol inventory ===" 570 @$(MAKE) check-native-sol-inventory 571 @echo "" 572 @echo "=== Running native sol architecture check ===" 573 @$(MAKE) check-native-sol-architecture 574 @echo "" 575 @echo "=== Checking generated skill references ===" 576 @$(MAKE) check-skill-references 577 @echo "" 578 @echo "=== Checking native sol contract-route coverage ===" 579 @$(MAKE) check-native-sol-contract-routes 580 @echo "" 581 @echo "=== Checking native sol four-way conformance ===" 582 @$(MAKE) check-native-sol-conformance 583 @echo "" 584 @echo "=== Checking native sol parity coverage ===" 585 @$(MAKE) check-native-sol-coverage 586 @echo "" 587 @echo "=== Checking native sol no-python-spawn invariant ===" 588 @$(MAKE) check-native-sol-no-python-spawn 589 @echo "" 590 @echo "=== Checking native sol compatibility boundary ===" 591 @$(MAKE) check-native-sol-compat 592 @echo "" 593 @echo "=== Checking OpenAPI contract ===" 594 @$(MAKE) check-openapi 595 @echo "" 596 @echo "=== Checking journal format contract ===" 597 @$(MAKE) check-contract 598 @echo "" 599 @echo "=== Checking core fixtures ===" 600 @$(MAKE) check-core-fixtures 601 @echo "" 602 @echo "=== Checking packaging render ===" 603 @python3 scripts/render_packaging.py --check 604 @echo "" 605 @echo "=== Checking journal resolution vectors ===" 606 @$(MAKE) check-journal-resolution-vectors 607 @echo "" 608 @echo "=== Running rust format check ===" 609 @$(MAKE) check-rust-fmt 610 @echo "" 611 @echo "=== Running rust MSRV check ===" 612 @$(MAKE) check-rust-msrv 613 @echo "" 614 @echo "=== Running rust clippy check ===" 615 @$(MAKE) check-rust-clippy 616 @echo "" 617 @echo "=== Running rust test check ===" 618 @$(MAKE) check-rust-test 619 @echo "" 620 @echo "=== Running rust iOS check ===" 621 @$(MAKE) check-rust-ios 622 @echo "" 623 @echo "=== Running rust dependency policy check ===" 624 @$(MAKE) check-rust-deny 625 @echo "" 626 @echo "=== Running release advisory liveness check ===" 627 @$(MAKE) check-release-advisory-liveness 628 @echo "" 629 @echo "=== Checking transparency minisign ===" 630 @$(MAKE) check-transparency-minisign 631 @echo "" 632 @echo "=== Checking extras consistency ===" 633 @$(VENV_BIN)/python scripts/check_extras_consistency.py 634 @echo "" 635 636ci: install-checks 637 @echo "=== Running tests ===" 638 @$(MAKE) test 639 @echo "" 640 @echo "All CI checks passed; evidence classes:" 641 @echo " GNU-host checks: fmt, MSRV, clippy, tests, dependency policy" 642 @echo " iOS cross-target canary: check-rust-ios" 643 644verify: install-checks 645 @echo "=== Running tests ===" 646 @$(MAKE) test-cov 647 @echo "" 648 @echo "Verification complete!" 649 650# Watch for changes and run tests (requires pytest-watch) 651watch: .installed 652 @$(UV) pip show pytest-watch >/dev/null 2>&1 || { echo "Installing pytest-watch..."; $(UV) pip install pytest-watch; } 653 $(VENV_BIN)/ptw -- -q 654 655# Generate HTML coverage report (core + apps) 656coverage: .installed 657 $(PYTEST_BASETEMP_INIT) $(TEST_ENV) $(PYTEST) $(PYTEST_BASETEMP_FLAG) tests/ solstone/apps/ $(PYTEST_UNIT_ARGS) --cov=. --cov-report=html --cov-report=term 658 @echo "Coverage report generated in htmlcov/index.html" 659 660# Update all dependencies to latest versions and refresh genai-prices 661update: .installed 662 @echo "Updating all dependencies to latest versions..." 663 $(UV) lock -U 664 $(UV) sync 665 @echo "Done. All packages updated to latest." 666 667# Update genai-prices to get latest model pricing data 668# Run this when adding new models or if pricing tests fail 669update-prices: .installed 670 @echo "Updating genai-prices to latest version..." 671 $(UV) lock -P genai-prices 672 $(UV) sync 673 @echo "Done. Re-run tests to verify model pricing support." 674 675# Show installed package versions 676versions: .installed 677 @echo "=== Python version ===" 678 $(PYTHON) --version 679 @echo "" 680 @echo "=== Key package versions ===" 681 @$(UV) pip list | grep -E "^(pytest|ruff|Flask|numpy|Pillow|openai|anthropic)" || true 682 683# Install pre-commit hooks (if using pre-commit) 684pre-commit: .installed 685 @$(UV) pip show pre-commit >/dev/null 2>&1 || { echo "Installing pre-commit..."; $(UV) pip install pre-commit; } 686 $(VENV_BIN)/pre-commit install 687 @echo "Pre-commit hooks installed!" 688 689# Low-bar layer-hygiene check (see docs/coding-standards.md § Layer Hygiene) 690check-layer-hygiene: .installed 691 $(VENV_BIN)/python scripts/check_layer_hygiene.py 692 693# HTTP API conventions check (see docs/CONVEY.md § HTTP API conventions) 694check-api-conventions: .installed 695 $(VENV_BIN)/python scripts/check_api_conventions.py 696 697# Journal-io write-primitive access check (see AGENTS.md §7 L2) 698check-journal-io-access: .installed 699 $(VENV_BIN)/python scripts/check_journal_io_access.py 700 701# Journal raw-mechanic check (see AGENTS.md §7 L2) 702check-journal-io-mechanic: .installed 703 $(VENV_BIN)/python scripts/check_journal_io_mechanic.py 704 705# Journal config owner transaction boundary gate 706check-journal-config-owner: .installed 707 $(VENV_BIN)/python scripts/check_journal_config_owner.py 708 709# Provider install ownership boundary gate 710check-provider-install-owner: .installed 711 $(VENV_BIN)/python scripts/check_provider_install_owner.py 712 713# Provider runtime start-command boundary gate 714check-provider-start-commands: .installed 715 $(VENV_BIN)/python scripts/check_provider_start_commands.py 716 717# Removed chat surfaces stay out of tracked Python, HTML, and JavaScript. 718check-no-legacy-chat: .installed 719 $(VENV_BIN)/python scripts/check_no_legacy_chat.py 720 721# Release channel adapter scrub gate 722check-channel-adapter-scrub: .installed 723 $(VENV_BIN)/python scripts/check_channel_adapter_scrub.py 724 725# Brain health cutover guard 726check-brain-health-cutover: .installed 727 $(VENV_BIN)/python scripts/check_brain_health_cutover.py 728 729# Generation schema bounds ratchet 730check-schema-bounds: .installed 731 $(VENV_BIN)/python scripts/check_schema_bounds.py 732 733# Rust release-manifest schema, semantic, determinism, and transaction gate 734check-rust-release-manifest: .installed 735 $(VENV_BIN)/python scripts/check_rust_release_manifest.py 736 737# Package dependency and script ownership consistency gate 738check-extras-consistency: .installed 739 $(VENV_BIN)/python scripts/check_extras_consistency.py 740 741# Thin sol access surface import-clean gate (fast meta_path simulation; in ci) 742check-access-imports-clean: .installed 743 $(VENV_BIN)/python scripts/check_access_imports_clean.py 744 745# Convey bind path import-clean gate 746check-convey-bind-imports-clean: .installed 747 $(VENV_BIN)/python scripts/check_convey_bind_imports_clean.py 748 749# Faithful thin-base gate: build a fresh venv with the REAL base partition (no 750# extras) and assert the access surface imports clean against it. Heavier than 751# check-access-imports-clean (does a real install) — operator/release opt-in, 752# NOT part of `make ci` (which uses the fast simulation above). 753check-thin-base-install: 754 python3 scripts/check_access_imports_clean.py --real-install 755 756# Cogitate-prompt static gate (prompts use only on-contract command forms) 757check-cogitate-prompts: .installed 758 $(VENV_BIN)/python scripts/check_cogitate_prompts.py 759 760# Generated router skill references gate 761check-skill-references: .installed 762 $(VENV_BIN)/python scripts/build_skill_references.py --check 763 764openapi: 765 $(VENV_BIN)/python scripts/build_openapi_contract.py 766 767check-openapi: .installed 768 $(VENV_BIN)/python scripts/check_openapi_contract.py 769 $(VENV_BIN)/python scripts/build_openapi_contract.py --check 770 $(MAKE) check-openapi-observer-client-contract 771 772check-openapi-observer-client-contract: .installed 773 $(VENV_BIN)/python scripts/check_observer_client_contract_bundle.py 774 775journal-resolution-vectors: 776 $(VENV_BIN)/python scripts/build_journal_resolution_vectors.py 777 778check-journal-resolution-vectors: .installed 779 $(VENV_BIN)/python scripts/build_journal_resolution_vectors.py --check 780 781build-native-sol-grammar-oracle: .installed 782 $(VENV_BIN)/python scripts/build_native_sol_authority_grammar.py 783 784check-native-sol-grammar-oracle: .installed 785 $(VENV_BIN)/python scripts/check_native_sol_grammar_oracle.py 786 $(VENV_BIN)/python scripts/build_native_sol_authority_grammar.py --check 787 788build-native-sol-root-contract: 789 python3 scripts/build_native_sol_root_contract.py 790 791check-native-sol-root-contract: 792 python3 scripts/check_native_sol_root_contract.py 793 794check-core-sdist-compile-inputs: 795 python3 scripts/check_core_sdist_compile_inputs.py 796 797build-native-sol-journal-host-commands: 798 python3 scripts/build_native_sol_journal_host_commands.py 799 800check-native-sol-journal-host-commands: 801 python3 scripts/build_native_sol_journal_host_commands.py --check 802 803build-journal-access-rejection-inventory: 804 python3 scripts/build_journal_access_rejection_inventory.py 805 806check-journal-access-rejection-inventory: 807 python3 scripts/build_journal_access_rejection_inventory.py --check 808 809check-native-sol-python-manifest: 810 python3 scripts/check_native_sol_python_manifest.py 811 812build-native-sol-inventory: .installed 813 $(VENV_BIN)/python scripts/build_native_sol_inventory.py 814 815check-native-sol-inventory: .installed 816 $(VENV_BIN)/python scripts/build_native_sol_inventory.py --check 817 818check-native-sol-architecture: 819 python3 scripts/check_native_sol_architecture.py 820 821check-native-sol-contract-routes: .installed 822 $(VENV_BIN)/python scripts/check_native_sol_contract_routes.py 823 824check-native-sol-conformance: .installed 825 $(VENV_BIN)/python scripts/check_native_sol_conformance.py 826 827check-native-sol-coverage: .installed 828 $(VENV_BIN)/python scripts/check_native_sol_coverage.py 829 830check-native-sol-no-python-spawn: 831 python3 scripts/check_native_sol_no_python_spawn.py 832 833check-native-sol-compat: .installed 834 $(VENV_BIN)/python scripts/check_native_sol_compat.py 835 836check-native-sol-docs-links: 837 python3 scripts/check_native_sol_docs_links.py 838 839check-removed-time-parser-ready: 840 python3 scripts/check_removed_time_parser_ready.py 841 842contract: 843 $(VENV_BIN)/python -m solstone.think.contract_cli build 844 845check-contract: .installed 846 $(VENV_BIN)/python -m solstone.think.contract_cli check 847 $(VENV_BIN)/python -m solstone.think.contract_cli build --check 848 849core-fixtures: 850 $(VENV_BIN)/python scripts/build_core_fixtures.py 851 852check-core-fixtures: .installed 853 $(VENV_BIN)/python scripts/build_core_fixtures.py --check 854 855check-release-advisory-liveness: .installed 856 $(VENV_BIN)/python scripts/check_release_advisory_liveness.py 857 858# Re-run the live four-backend integrated-façade cogitate smoke. Spawns an 859# external runner script against this venv so the real openhands-sdk Agent path 860# is exercised end-to-end. Requires real API keys in env (`ANTHROPIC_API_KEY`, 861# `OPENAI_API_KEY`, `GOOGLE_API_KEY`) and `llama-server` on PATH for the `local` 862# backend. Catches v1.23-style Agent schema regressions that the openhands-fake 863# unit tests cannot. Set COGITATE_SMOKE_RUNNER=/path/to/script to point at the 864# runner; there is no default. 865COGITATE_SMOKE_RUNNER ?= 866 867smoke-cogitate: .installed 868 @test -f "$(COGITATE_SMOKE_RUNNER)" || { echo "cogitate smoke runner not found: $(COGITATE_SMOKE_RUNNER)" >&2; echo "set COGITATE_SMOKE_RUNNER=/path/to/script to override" >&2; exit 1; } 869 $(VENV_PY) "$(COGITATE_SMOKE_RUNNER)" 870 871# Operator-opt-in install-state smoke: drives the real install primitives 872# (real uv Popen for bundled providers, real httpx for local llama-server + 873# GGUF download, real huggingface_hub for MLX snapshot) against a tmp 874# journal_config and asserts canonical phase transitions, byte-count 875# surfacing, and post-restart state persistence. Hits the same code paths 876# the dashboard hits, end-to-end. Heavier than `make test` because it does 877# real network fetches; lighter than `make smoke-cogitate` because it does 878# not require API keys or a running supervisor. 879smoke-install-providers: .installed 880 @echo "Running install-state integration smoke..." 881 $(PYTEST_BASETEMP_INIT) $(TEST_ENV) $(PYTEST) $(PYTEST_BASETEMP_FLAG) \ 882 solstone/apps/settings/tests/test_providers_payload_extended.py \ 883 -v --tb=short --timeout=120 884 885release: ## Locked publication entrypoint 886 @bash scripts/release.sh 887 888release-test: ## Locked test-publication entrypoint 889 @bash scripts/release.sh --test 890 891.PHONY: check-transparency-minisign 892check-transparency-minisign: .installed 893 $(VENV_BIN)/python scripts/check_transparency_minisign.py 894 895.PHONY: publish-release publish-release-test publish-transparency resign-transparency-pointer 896publish-release: .installed 897 @test -n "$(RELEASE_DIR)" || { echo "publish-release: set RELEASE_DIR=<retained ready dir>" >&2; exit 1; } 898 RELEASE_DIR="$(RELEASE_DIR)" $(VENV_BIN)/python scripts/release_publish.py --mode production --root . 899 900publish-release-test: .installed 901 @test -n "$(RELEASE_DIR)" || { echo "publish-release-test: set RELEASE_DIR=<retained ready dir>" >&2; exit 1; } 902 RELEASE_DIR="$(RELEASE_DIR)" $(VENV_BIN)/python scripts/release_publish.py --mode test --root . 903 904publish-transparency: .installed 905 @test -n "$(RELEASE_DIR)" || { echo "publish-transparency: set RELEASE_DIR=<retained ready dir>" >&2; exit 1; } 906 RELEASE_DIR="$(RELEASE_DIR)" SOURCE_COMMIT="$(SOURCE_COMMIT)" $(VENV_BIN)/python scripts/transparency_publish.py publish --root . 907 908resign-transparency-pointer: .installed 909 $(VENV_BIN)/python scripts/transparency_publish.py resign-transparency-pointer --root .