diff --git a/CHANGELOG.md b/CHANGELOG.md index 48fb05287..1a4ebfa91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to solstone (the Python package) will be documented in this Format adapted from [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), aligned with `cmo/brand/changelog-voice.md`. +## [0.4.8] - 2026-06-01 + +### Fixed +- macos setup now tolerates a launchd race where the journal service starts and becomes healthy even though `launchctl kickstart` reports a transient error. setup trusts the supervisor readiness marker, so an upgrade can continue to observer registration instead of stopping at "service up failed". + ## [0.4.7] - 2026-05-31 ### Fixed diff --git a/pyproject.toml b/pyproject.toml index d46f7a656..02a976891 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "solstone" -version = "0.4.7" +version = "0.4.8" description = "Navigate Life Intelligently" readme = "README.md" requires-python = ">=3.12" diff --git a/solstone/think/service.py b/solstone/think/service.py index cec26ffb2..2580b866f 100644 --- a/solstone/think/service.py +++ b/solstone/think/service.py @@ -909,7 +909,10 @@ def _up(port: int = DEFAULT_SERVICE_PORT) -> int: clear_ready() rc = _start() if rc != 0: - return rc + if wait_ready(timeout=READY_TIMEOUT_SECONDS) is None: + return rc + _status() + return 0 if wait_ready(timeout=READY_TIMEOUT_SECONDS) is None: print(_ready_timeout_message(), file=sys.stderr) diff --git a/tests/test_service.py b/tests/test_service.py index 14a56c6b4..09f8b9444 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -501,6 +501,44 @@ class TestUp: wait_ready.assert_called_once_with(timeout=service.READY_TIMEOUT_SECONDS) status.assert_called_once_with() + def test_up_accepts_readiness_when_start_reports_race(self, monkeypatch): + monkeypatch.setattr(service, "_platform", lambda: "darwin") + monkeypatch.setattr(service, "service_is_installed", lambda: True) + monkeypatch.setattr(service, "service_is_running", lambda: False) + start = MagicMock(return_value=1) + clear_ready = MagicMock() + wait_ready = MagicMock(return_value={"pid": 123}) + status = MagicMock(return_value=0) + monkeypatch.setattr(service, "_start", start) + monkeypatch.setattr(service, "clear_ready", clear_ready) + monkeypatch.setattr(service, "wait_ready", wait_ready) + monkeypatch.setattr(service, "_status", status) + + assert service._up(port=5015) == 0 + start.assert_called_once_with() + clear_ready.assert_called_once_with() + wait_ready.assert_called_once_with(timeout=service.READY_TIMEOUT_SECONDS) + status.assert_called_once_with() + + def test_up_preserves_start_failure_without_readiness(self, monkeypatch): + monkeypatch.setattr(service, "_platform", lambda: "darwin") + monkeypatch.setattr(service, "service_is_installed", lambda: True) + monkeypatch.setattr(service, "service_is_running", lambda: False) + start = MagicMock(return_value=7) + clear_ready = MagicMock() + wait_ready = MagicMock(return_value=None) + status = MagicMock(return_value=0) + monkeypatch.setattr(service, "_start", start) + monkeypatch.setattr(service, "clear_ready", clear_ready) + monkeypatch.setattr(service, "wait_ready", wait_ready) + monkeypatch.setattr(service, "_status", status) + + assert service._up(port=5015) == 7 + start.assert_called_once_with() + clear_ready.assert_called_once_with() + wait_ready.assert_called_once_with(timeout=service.READY_TIMEOUT_SECONDS) + status.assert_not_called() + def test_up_already_running_waits_for_readiness(self, monkeypatch): monkeypatch.setattr(service, "_platform", lambda: "linux") monkeypatch.setattr(service, "service_is_installed", lambda: True) diff --git a/uv.lock b/uv.lock index 636ae9571..c26e6abfa 100644 --- a/uv.lock +++ b/uv.lock @@ -4214,7 +4214,7 @@ wheels = [ [[package]] name = "solstone" -version = "0.4.7" +version = "0.4.8" source = { editable = "." } dependencies = [ { name = "anthropic" },