personal memory agent
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 .