Skip to content
Merged
2 changes: 1 addition & 1 deletion .github/workflows/postgresql-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ permissions:

concurrency:
group: postgresql-integration-${{ github.ref }}
cancel-in-progress: true
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
postgresql-authority:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ permissions:

concurrency:
group: python-tests-${{ github.ref }}
cancel-in-progress: true
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

env:
LOOPX_USAGE_PING: "0"
Expand Down
5 changes: 5 additions & 0 deletions loopx/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ def _is_route_observation(path: Path) -> bool:
return False
if path.name == GLOBAL_REGISTRY_FILENAME + ".lock":
return path.is_file()
# The native effect runtime locks every registry it writes through, so a
# mere lock file must not turn a default root into a second authority.
# Spelled here because file_lock imports this module.
if path.name == GLOBAL_REGISTRY_FILENAME + ".ts-effect.lock":
return path.is_file()
if path.name == "lark-consumers" and path.is_dir():
import re

Expand Down
2 changes: 1 addition & 1 deletion loopx/semantics/project_registry_io_manifest_v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -1959,7 +1959,7 @@
},
{
"site": "loopx/paths.py::<module>.configured_runtime_route::codec_read:load_registry#1",
"line": 262,
"line": 267,
"column": 20,
"kind": "codec_read",
"api": "load_registry",
Expand Down
56 changes: 56 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import importlib
import os
import sys
from pathlib import Path
Expand All @@ -12,10 +13,65 @@
if str(REPO_ROOT) not in sys.path:
sys.path.insert(0, str(REPO_ROOT))

import pytest # noqa: E402

from loopx import paths # noqa: E402
from loopx.canary.runner import SMOKE_SUITE_CHOICES # noqa: E402
from loopx.semantics.production import NPM_DEV_DEPENDENCIES_MISSING # noqa: E402


# Default runtime routes resolve from HOME at import time. A test that writes
# either one leaves state behind, and once both hold state every later implicit
# default route fails as a conflict, so each test gets its own disposable pair.
_DEFAULT_ROUTE_REFERENCES = (
("loopx.paths", "DEFAULT_RUNTIME_ROOT", (".loopx",)),
("loopx.paths", "LEGACY_RUNTIME_ROOT", (".codex", "loopx")),
("loopx.contract", "DEFAULT_RUNTIME_ROOT", (".loopx",)),
("loopx.contract", "LEGACY_RUNTIME_ROOT", (".codex", "loopx")),
("loopx.cli_commands.registry_admin_lifecycle", "DEFAULT_RUNTIME_ROOT", (".loopx",)),
("loopx.cli_commands.registry_admin_lifecycle", "LEGACY_LOCAL_RUNTIME_ROOT", (".codex", "loopx")),
("loopx.control_plane.runtime.local_state_migration", "DEFAULT_RUNTIME_ROOT", (".loopx",)),
("loopx.control_plane.runtime.local_state_migration", "LEGACY_RUNTIME_ROOT", (".codex", "loopx")),
)
_REAL_DEFAULT_ROUTES = (paths.DEFAULT_RUNTIME_ROOT, paths.LEGACY_RUNTIME_ROOT)


@pytest.fixture(autouse=True)
def _isolated_default_runtime_routes(tmp_path_factory, monkeypatch):
home = tmp_path_factory.mktemp("home")
monkeypatch.setenv("HOME", str(home))
monkeypatch.setenv("USERPROFILE", str(home))
monkeypatch.delenv("CODEX_HOME", raising=False)
for module_name, attribute, parts in _DEFAULT_ROUTE_REFERENCES:
monkeypatch.setattr(importlib.import_module(module_name), attribute, home.joinpath(*parts))
yield


def pytest_sessionstart(session) -> None:
# Only routes absent at start are guarded; existing developer state may be
# changed by other local processes during the run.
session.config._loopx_absent_routes = [
root for root in _REAL_DEFAULT_ROUTES if not os.path.lexists(root)
]


def pytest_sessionfinish(session, exitstatus) -> None:
created = [
root for root in getattr(session.config, "_loopx_absent_routes", [])
if os.path.lexists(root)
]
if not created:
return
reporter = session.config.pluginmanager.get_plugin("terminalreporter")
if reporter is not None:
reporter.write_sep("=", "loopx default runtime route leak", red=True)
reporter.write_line(
f"Tests created real default runtime routes {', '.join(map(str, created))}; "
"isolate the writer."
)
session.exitstatus = pytest.ExitCode.TESTS_FAILED


def pytest_addoption(parser) -> None:
group = parser.getgroup("loopx-smoke-suite")
group.addoption(
Expand Down
5 changes: 5 additions & 0 deletions tests/test_chat_codex_goal.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,11 @@ def test_external_queued_message_cannot_activate_local_owner_continuation(
message="/goal start --tokens 1000 Analyze",
origin="lark",
)
# Production dispatch claims the exact queued Turn before starting it.
# Without that claim the execution fence correctly refuses this worker
# before it can evaluate whether the external command is authorized.
claimed = store.claim_next_queued_turn(session["session_id"])
assert claimed is not None and claimed["turn_id"] == turn["turn_id"]
controller._run_turn(
session_id=session["session_id"],
turn_id=turn["turn_id"],
Expand Down
23 changes: 23 additions & 0 deletions tests/test_local_state_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,29 @@ def reparse_lstat(path, *args, **kwargs):
assert paths.configured_runtime_route(runtime_root_override=str(redirected))["status"] == "invalid"


@pytest.mark.parametrize("relative", ["registry.global.json.lock",
"registry.global.json.ts-effect.lock"])
def test_own_registry_locks_do_not_declare_a_second_authority(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, relative: str,
) -> None:
"""A route must not read its own write-locks back as machine state.

Goal configuration locks every candidate runtime registry before writing,
and the native effect runtime locks the same file too. On a fresh machine
those locks are the only entries in the untouched legacy root, so treating
them as state made the first configured Goal fail as a two-root conflict.
"""

source, target = tmp_path / "home" / ".codex" / "loopx", tmp_path / "home" / ".loopx"
monkeypatch.setattr(paths, "LEGACY_RUNTIME_ROOT", source)
monkeypatch.setattr(paths, "DEFAULT_RUNTIME_ROOT", target)
for root in (source, target):
root.mkdir(parents=True)
(root / relative).touch()
assert paths.default_runtime_route()["status"] == "fresh"
assert paths.select_default_runtime_root() == target


def test_global_service_selector_keeps_a_registered_route_amid_real_conflict(tmp_path, monkeypatch):
from loopx.cli_commands.support_control_registry import explicit_global_registry
source, target, projects = _fixture(tmp_path, projects=1)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_skill_delivery_parity.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ def test_packaged_skill_dirs_exist(self):
encoding="utf-8"
).strip() == "global", skill_id

def test_repo_has_seven_skills(self):
assert len(REQUIRED_HOST_SKILL_IDS) == 7 # loopx + 6 packaged
def test_required_skills_match_the_shipped_catalog(self):
assert set(REQUIRED_HOST_SKILL_IDS) == {"loopx", *PACKAGED_HOST_SKILL_IDS}


# -- Skill install readback lifecycle -----------------------------------------
Expand Down
Loading