Files
2026-07-13 13:12:33 +08:00

1424 lines
51 KiB
Python

from __future__ import annotations
import ctypes
import json
import os
import shutil
import sqlite3
import subprocess
import sys
import tomllib
import uuid
from pathlib import Path
import pytest
from opensquilla.recovery import (
AtomicStateUnknownError,
InvalidWorkspaceError,
RecoveryRequiredError,
WorkspaceOverrideError,
choose_workspace,
guard_desktop_profile,
inspect_profile,
reconcile_profile,
)
def _workspace(path: Path, marker: str = "synthetic") -> Path:
path.mkdir(parents=True)
(path / "SOUL.md").write_text(f"{marker}\n", encoding="utf-8")
return path
def _desktop_config(home: Path, *, workspace: Path | None = None, extra: str = "") -> None:
lines = [f"state_dir = {json.dumps(str(home / 'state'))}"]
if workspace is not None:
lines.append(f"workspace_dir = {json.dumps(str(workspace))}")
if extra:
lines.append(extra.rstrip("\n"))
home.mkdir(parents=True, exist_ok=True)
(home / "state").mkdir(exist_ok=True)
(home / "config.toml").write_text("\n".join(lines) + "\n", encoding="utf-8")
def test_offline_cli_ignores_cwd_dotenv_but_reads_profile_override(
tmp_path: Path,
) -> None:
cwd = tmp_path / "cwd"
home = tmp_path / "profile"
cwd.mkdir()
external = _workspace(tmp_path / "profile-workspace")
_workspace(home / "workspace")
_desktop_config(home)
(cwd / ".env").write_text(
f"OPENSQUILLA_GATEWAY_WORKSPACE_DIR={tmp_path / 'wrong-cwd'}\n",
encoding="utf-8",
)
(home / ".env").write_text(
f"OPENSQUILLA_GATEWAY_WORKSPACE_DIR={external}\n",
encoding="utf-8",
)
environment = os.environ.copy()
environment.pop("OPENSQUILLA_GATEWAY_WORKSPACE_DIR", None)
environment["OPENSQUILLA_STATE_DIR"] = str(home)
completed = subprocess.run(
[
sys.executable,
"-m",
"opensquilla.cli.main",
"recovery",
"inspect",
"--home",
str(home),
"--json",
],
cwd=cwd,
env=environment,
text=True,
capture_output=True,
check=False,
)
assert completed.returncode == 0, completed.stderr
payload = json.loads(completed.stdout)
assert payload["effective_workspace"] == str(external)
assert payload["stable_code"] == "workspace_env_override"
@pytest.mark.parametrize(
("profile_kind", "outcome"),
[("desktop-primary", "ready"), ("desktop-recovery", "recovery_profile")],
)
def test_empty_profile_is_safe_to_initialize(
tmp_path: Path,
profile_kind: str,
outcome: str,
) -> None:
home = tmp_path / "not-created"
report = inspect_profile(home, profile_kind=profile_kind)
assert report.outcome == outcome
assert report.stable_code.startswith("fresh_")
assert not home.exists(), "read-only inspection must not create a fresh home"
def test_existing_empty_profile_is_safe_to_initialize(tmp_path: Path) -> None:
home = tmp_path / "empty-profile"
home.mkdir()
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "ready"
assert report.stable_code == "fresh_profile"
assert list(home.iterdir()) == []
@pytest.mark.parametrize("entry_kind", ["file", "directory"])
def test_unknown_only_profile_is_never_seeded_as_fresh(
tmp_path: Path,
entry_kind: str,
) -> None:
home = tmp_path / "unknown-profile"
home.mkdir()
unknown = home / "unknown-layout"
if entry_kind == "file":
unknown.write_text("synthetic unknown profile evidence\n", encoding="utf-8")
else:
unknown.mkdir()
(unknown / "USER.md").write_text("synthetic preserved identity\n", encoding="utf-8")
before = sorted(path.relative_to(home) for path in home.rglob("*"))
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == "unknown_layout"
assert sorted(path.relative_to(home) for path in home.rglob("*")) == before
assert not (home / "workspace").exists()
assert not (home / "state").exists()
def test_unknown_profile_symlink_is_not_followed_or_seeded(tmp_path: Path) -> None:
home = tmp_path / "unknown-profile"
outside = tmp_path / "outside"
home.mkdir()
outside.mkdir()
sentinel = outside / "USER.md"
sentinel.write_text("synthetic preserved identity\n", encoding="utf-8")
linked = home / "unknown-layout"
try:
linked.symlink_to(outside, target_is_directory=True)
except OSError:
pytest.skip("symlink creation is unavailable")
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == "unknown_layout"
assert linked.is_symlink()
assert sentinel.read_text(encoding="utf-8") == "synthetic preserved identity\n"
assert not (home / "workspace").exists()
assert not (home / "state").exists()
@pytest.mark.skipif(sys.platform != "win32", reason="requires a real Windows junction")
def test_unknown_profile_junction_is_not_followed_or_seeded(tmp_path: Path) -> None:
home = tmp_path / "unknown-profile"
outside = tmp_path / "outside"
home.mkdir()
outside.mkdir()
sentinel = outside / "USER.md"
sentinel.write_text("synthetic preserved identity\n", encoding="utf-8")
junction = home / "unknown-layout"
completed = subprocess.run(
["cmd", "/c", "mklink", "/J", str(junction), str(outside)],
text=True,
capture_output=True,
check=False,
)
if completed.returncode != 0:
pytest.skip(f"junction creation is unavailable: {completed.stderr}")
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == "unknown_layout"
assert sentinel.read_text(encoding="utf-8") == "synthetic preserved identity\n"
assert not (home / "workspace").exists()
assert not (home / "state").exists()
@pytest.mark.parametrize(
("override_name", "stable_code"),
[
("OPENSQUILLA_GATEWAY_WORKSPACE_DIR", "effective_state_missing"),
("OPENSQUILLA_GATEWAY_STATE_DIR", "effective_state_missing"),
],
)
def test_empty_primary_with_missing_environment_override_is_not_fresh(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
override_name: str,
stable_code: str,
) -> None:
home = tmp_path / "not-created"
missing = tmp_path / "missing-external"
monkeypatch.setenv(override_name, str(missing))
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == stable_code
assert not home.exists()
assert not missing.exists()
@pytest.mark.parametrize(
("external_role", "stable_code"),
[
("workspace", "recovery_profile_external_workspace"),
("state", "recovery_profile_external_state"),
],
)
def test_recovery_profile_rejects_external_primary_data_roots(
tmp_path: Path,
external_role: str,
stable_code: str,
) -> None:
recovery_home = tmp_path / "recovery-profiles" / str(uuid.uuid4()) / "opensquilla"
primary_home = tmp_path / "opensquilla"
primary_workspace = _workspace(primary_home / "workspace", "primary identity")
primary_state = primary_home / "state"
primary_state.mkdir()
recovery_workspace = _workspace(recovery_home / "workspace", "recovery identity")
recovery_state = recovery_home / "state"
recovery_state.mkdir()
workspace = primary_workspace if external_role == "workspace" else recovery_workspace
state = primary_state if external_role == "state" else recovery_state
(recovery_home / "config.toml").write_text(
f"state_dir = {json.dumps(str(state))}\n"
f"workspace_dir = {json.dumps(str(workspace))}\n",
encoding="utf-8",
)
report = inspect_profile(recovery_home, profile_kind="desktop-recovery")
assert report.outcome == "recovery_required"
assert report.stable_code == stable_code
assert report.effective_workspace is None
assert "continue-recovery-profile" not in report.allowed_actions
assert "create-recovery-profile" in report.allowed_actions
def test_healthy_recovery_profile_cannot_be_repointed_to_external_workspace(
tmp_path: Path,
) -> None:
recovery_home = tmp_path / "recovery-profiles" / str(uuid.uuid4()) / "opensquilla"
canonical_workspace = _workspace(recovery_home / "workspace", "recovery identity")
(recovery_home / "state").mkdir()
_desktop_config(recovery_home, workspace=canonical_workspace)
external_workspace = _workspace(tmp_path / "external-workspace", "external identity")
config_path = recovery_home / "config.toml"
config_before = config_path.read_bytes()
before = inspect_profile(recovery_home, profile_kind="desktop-recovery")
assert before.outcome == "recovery_profile"
assert before.stable_code == "canonical_workspace"
assert "choose-workspace" not in before.allowed_actions
with pytest.raises(InvalidWorkspaceError, match="recovery profile"):
choose_workspace(
recovery_home,
transaction_id=before.transaction_id,
expected_revision=before.revision,
workspace=external_workspace,
profile_kind="desktop-recovery",
)
assert config_path.read_bytes() == config_before
after = inspect_profile(recovery_home, profile_kind="desktop-recovery")
assert after.outcome == "recovery_profile"
assert after.effective_workspace == canonical_workspace
def test_empty_recovery_profile_rejects_ambient_primary_override(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
recovery_home = tmp_path / "recovery-profiles" / str(uuid.uuid4()) / "opensquilla"
primary_workspace = _workspace(tmp_path / "opensquilla" / "workspace")
monkeypatch.setenv("OPENSQUILLA_GATEWAY_WORKSPACE_DIR", str(primary_workspace))
report = inspect_profile(recovery_home, profile_kind="desktop-recovery")
assert report.outcome == "recovery_required"
assert report.stable_code == "recovery_profile_external_workspace"
assert not recovery_home.exists()
def test_recovery_profile_canonical_symlink_cannot_escape_to_primary(
tmp_path: Path,
) -> None:
recovery_home = tmp_path / "recovery-profiles" / str(uuid.uuid4()) / "opensquilla"
recovery_home.mkdir(parents=True)
primary_workspace = _workspace(tmp_path / "opensquilla" / "workspace")
try:
(recovery_home / "workspace").symlink_to(primary_workspace, target_is_directory=True)
except OSError:
pytest.skip("symlink creation is unavailable")
(recovery_home / "state").mkdir()
(recovery_home / "config.toml").write_text(
f"state_dir = {json.dumps(str(recovery_home / 'state'))}\n"
f"workspace_dir = {json.dumps(str(recovery_home / 'workspace'))}\n",
encoding="utf-8",
)
report = inspect_profile(recovery_home, profile_kind="desktop-recovery")
assert report.outcome == "recovery_required"
assert report.stable_code == "recovery_profile_unsafe_workspace"
assert (primary_workspace / "SOUL.md").read_text(encoding="utf-8") == "synthetic\n"
def test_pinned_legacy_workspace_stays_in_place_and_is_attention(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
legacy = _workspace(home / "state" / "workspace", "legacy")
_desktop_config(home, workspace=legacy)
before = inspect_profile(home)
after = reconcile_profile(home)
assert before.outcome == after.outcome == "attention"
assert before.stable_code == after.stable_code == "legacy_workspace_pinned"
assert after.effective_workspace == legacy
assert legacy.is_dir()
assert not (home / "workspace").exists()
def test_dual_workspace_preserves_configured_current_path(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
canonical = _workspace(home / "workspace", "canonical changed")
legacy = _workspace(home / "state" / "workspace", "legacy changed")
_desktop_config(home, workspace=legacy)
report = reconcile_profile(home)
assert report.outcome == "attention"
assert report.stable_code == "workspace_conflict"
assert report.effective_workspace == legacy
assert (canonical / "SOUL.md").read_text(encoding="utf-8") == "canonical changed\n"
assert (legacy / "SOUL.md").read_text(encoding="utf-8") == "legacy changed\n"
def test_clean_proven_legacy_workspace_moves_only_during_reconcile(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
legacy = _workspace(home / "state" / "workspace", "legacy")
_desktop_config(home)
legacy_env = home / "state" / ".env"
legacy_env.write_text("SYNTHETIC=value\n", encoding="utf-8")
inspected = inspect_profile(home)
assert inspected.outcome == "recovery_required"
assert inspected.stable_code == "legacy_workspace_reconcile_available"
assert legacy.is_dir()
assert not (home / "workspace").exists()
reconciled = reconcile_profile(home)
assert reconciled.outcome == "ready"
assert reconciled.effective_workspace == home / "workspace"
assert not legacy.exists()
assert (home / "workspace" / "SOUL.md").read_text(encoding="utf-8") == "legacy\n"
assert not legacy_env.exists()
assert (home / ".env").read_text(encoding="utf-8") == "SYNTHETIC=value\n"
assert (home / "state" / "gateway.pid.lock").is_file()
def test_primary_reconcile_finalizes_v2_marker_without_touching_config_or_database(
tmp_path: Path,
) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
database = home / "state" / "sessions.db"
with sqlite3.connect(database) as connection:
connection.execute("CREATE TABLE synthetic_sessions (id TEXT PRIMARY KEY)")
config_before = (home / "config.toml").read_bytes()
database_before = database.read_bytes()
report = reconcile_profile(home, profile_kind="desktop-primary")
marker = home / "desktop-layout-v2.json"
assert report.outcome == "ready"
assert marker.is_file()
if os.name != "nt":
assert marker.stat().st_mode & 0o777 == 0o600
payload = json.loads(marker.read_text(encoding="utf-8"))
assert payload["schema_version"] == 2
assert payload["moved"] == []
assert (home / "config.toml").read_bytes() == config_before
assert database.read_bytes() == database_before
def test_recovery_or_required_profile_never_writes_primary_compatibility_marker(
tmp_path: Path,
) -> None:
recovery_home = tmp_path / "recovery"
_workspace(recovery_home / "workspace")
_desktop_config(recovery_home)
recovery = reconcile_profile(recovery_home, profile_kind="desktop-recovery")
assert recovery.outcome == "recovery_profile"
assert not (recovery_home / "desktop-layout-v2.json").exists()
unsafe_home = tmp_path / "unsafe"
_desktop_config(unsafe_home, workspace=tmp_path / "missing")
required = reconcile_profile(unsafe_home, profile_kind="desktop-primary")
assert required.outcome == "recovery_required"
assert not (unsafe_home / "desktop-layout-v2.json").exists()
def test_marker_is_not_written_while_any_rc3_role_conflicts(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
(home / "skills").mkdir()
(home / "state" / "skills").mkdir(parents=True)
report = reconcile_profile(home, profile_kind="desktop-primary")
assert report.outcome == "attention"
assert not (home / "desktop-layout-v2.json").exists()
def test_explicit_legacy_workspace_pin_is_safe_for_marker_finalization(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
legacy = _workspace(home / "state" / "workspace")
_desktop_config(home, workspace=legacy)
report = reconcile_profile(home, profile_kind="desktop-primary")
assert report.outcome == "attention"
assert report.stable_code == "legacy_workspace_pinned"
assert (home / "desktop-layout-v2.json").is_file()
assert legacy.is_dir()
def test_unsafe_existing_marker_is_attention_and_never_overwritten(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
outside = tmp_path / "outside-marker.json"
outside.write_text("do not touch\n", encoding="utf-8")
try:
(home / "desktop-layout-v2.json").symlink_to(outside)
except OSError:
pytest.skip("symlink creation is unavailable")
report = reconcile_profile(home, profile_kind="desktop-primary")
assert report.outcome == "attention"
assert report.stable_code == "layout_marker_unsafe"
assert (home / "desktop-layout-v2.json").is_symlink()
assert outside.read_text(encoding="utf-8") == "do not touch\n"
def test_future_layout_marker_schema_is_attention_and_never_reinterpreted(
tmp_path: Path,
) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
marker = home / "desktop-layout-v2.json"
marker_bytes = (
b'{"schema_version":3,"migratedAt":"2099-01-01T00:00:00Z",'
b'"moved":[],"future":"preserve"}\n'
)
marker.write_bytes(marker_bytes)
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "attention"
assert report.stable_code == "layout_marker_unsafe"
assert marker.read_bytes() == marker_bytes
def test_unproven_legacy_directory_is_never_guessed_or_moved(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
legacy = home / "state" / "workspace"
legacy.mkdir(parents=True)
(legacy / "arbitrary.bin").write_bytes(b"synthetic")
_desktop_config(home)
report = reconcile_profile(home)
assert report.outcome == "recovery_required"
assert report.stable_code == "unknown_legacy_layout"
assert legacy.is_dir()
assert not (home / "workspace").exists()
def test_canonical_profile_user_dotenv_under_state_is_not_guessed_as_legacy(
tmp_path: Path,
) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
legacy_env = home / "state" / ".env"
legacy_env.parent.mkdir(exist_ok=True)
legacy_env.write_text("SYNTHETIC_SECRET=not-a-real-secret\n", encoding="utf-8")
report = reconcile_profile(home)
assert report.outcome == "attention"
assert report.stable_code == "legacy_layout_unsafe"
assert legacy_env.is_file()
assert not (home / ".env").exists()
def test_raw_native_move_oserror_returns_recovery_protocol_state(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
import opensquilla.recovery.engine as recovery_engine
home = tmp_path / "opensquilla"
canonical = _workspace(home / "workspace")
_workspace(home / "state" / "workspace", "legacy conflict")
_desktop_config(home, workspace=canonical)
legacy_env = home / "state" / ".env"
legacy_env.parent.mkdir(exist_ok=True)
legacy_env.write_text("SYNTHETIC=value\n", encoding="utf-8")
def fail_move(_source: Path, _destination: Path) -> None:
raise OSError("synthetic native failure")
monkeypatch.setattr(recovery_engine, "native_move_no_replace", fail_move)
report = reconcile_profile(home)
assert report.outcome == "attention"
assert report.stable_code == "layout_reconcile_deferred"
assert legacy_env.is_file()
assert not (home / ".env").exists()
def test_post_move_verification_failure_never_becomes_ready(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
import opensquilla.recovery.engine as recovery_engine
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_workspace(home / "state" / "workspace", "legacy conflict")
_desktop_config(home)
legacy_env = home / "state" / ".env"
legacy_env.parent.mkdir(exist_ok=True)
legacy_env.write_text("SYNTHETIC=value\n", encoding="utf-8")
def move_then_fail(source: Path, destination: Path) -> None:
source.rename(destination)
raise AtomicStateUnknownError("synthetic post-move verification failure")
monkeypatch.setattr(recovery_engine, "native_move_no_replace", move_then_fail)
report = reconcile_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == "atomic_state_unknown"
assert not legacy_env.exists()
assert (home / ".env").is_file()
assert not (home / "desktop-layout-v2.json").exists()
def test_skills_conflict_is_attention_and_never_moved_or_merged(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
legacy = home / "state" / "skills"
current = home / "skills"
legacy.mkdir(parents=True)
current.mkdir()
(legacy / "legacy.txt").write_text("legacy\n", encoding="utf-8")
(current / "current.txt").write_text("current\n", encoding="utf-8")
report = reconcile_profile(home)
assert report.outcome == "attention"
assert report.stable_code == "legacy_layout_conflict"
assert (legacy / "legacy.txt").read_text(encoding="utf-8") == "legacy\n"
assert (current / "current.txt").read_text(encoding="utf-8") == "current\n"
assert not (current / "legacy.txt").exists()
def test_nested_state_conflict_is_attention_and_never_moved(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
nested = home / "state" / "state" / "approvals.json"
current = home / "state" / "approvals.json"
nested.parent.mkdir(parents=True)
nested.write_text("legacy\n", encoding="utf-8")
current.write_text("current\n", encoding="utf-8")
report = reconcile_profile(home)
assert report.outcome == "attention"
assert report.stable_code == "legacy_layout_unsafe"
assert nested.read_text(encoding="utf-8") == "legacy\n"
assert current.read_text(encoding="utf-8") == "current\n"
def test_ancillary_legacy_symlink_is_attention_not_primary_recovery(
tmp_path: Path,
) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
(home / "state").mkdir(exist_ok=True)
outside = tmp_path / "outside-skills"
outside.mkdir()
try:
(home / "state" / "skills").symlink_to(outside, target_is_directory=True)
except OSError:
pytest.skip("symlink creation is unavailable")
report = reconcile_profile(home)
assert report.outcome == "attention"
assert report.stable_code == "legacy_layout_unsafe"
assert (home / "state" / "skills").is_symlink()
assert not (home / "skills").exists()
def test_existing_profile_with_missing_effective_workspace_requires_recovery(
tmp_path: Path,
) -> None:
home = tmp_path / "opensquilla"
_desktop_config(home, workspace=tmp_path / "missing-external")
report = inspect_profile(home)
assert report.outcome == "recovery_required"
assert report.stable_code == "effective_workspace_missing"
assert "choose-workspace" in report.allowed_actions
def test_missing_external_state_blocks_before_a_new_chat_database_can_be_created(
tmp_path: Path,
) -> None:
home = tmp_path / "opensquilla"
workspace = _workspace(home / "workspace")
missing_state = tmp_path / "detached-state"
_desktop_config(home, workspace=workspace)
(home / "config.toml").write_text(
f"state_dir = {json.dumps(str(missing_state))}\n"
f"workspace_dir = {json.dumps(str(workspace))}\n",
encoding="utf-8",
)
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == "effective_state_missing"
assert not missing_state.exists(), "inspection must never seed a replacement state root"
state = next(candidate for candidate in report.candidates if candidate.kind == "state")
assert state.path == missing_state
assert state.exists is False
def test_profile_dotenv_state_override_is_the_authoritative_chat_root(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
external_state = tmp_path / "external-state"
external_state.mkdir()
(home / ".env").write_text(
f"OPENSQUILLA_GATEWAY_STATE_DIR={external_state}\n",
encoding="utf-8",
)
monkeypatch.delenv("OPENSQUILLA_GATEWAY_STATE_DIR", raising=False)
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "ready"
state = next(candidate for candidate in report.candidates if candidate.kind == "state")
assert state.path == external_state
assert state.valid is True
@pytest.mark.parametrize(
("database_setup", "stable_code"),
[
("corrupt", "state_database_invalid"),
("future-schema", "state_schema_too_new"),
],
)
def test_unsafe_session_database_blocks_before_gateway_migrations(
tmp_path: Path,
database_setup: str,
stable_code: str,
) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
database = home / "state" / "sessions.db"
if database_setup == "corrupt":
database.write_bytes(b"not a sqlite database")
else:
with sqlite3.connect(database) as connection:
connection.execute(
"CREATE TABLE _yoyo_migration ("
"migration_hash TEXT PRIMARY KEY, migration_id TEXT, applied_at_utc TEXT)"
)
connection.execute(
"INSERT INTO _yoyo_migration VALUES (?, ?, ?)",
("synthetic", "V999__future", "2026-07-11T00:00:00Z"),
)
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == stable_code
def test_wal_database_without_shm_is_validated_from_private_read_only_source_snapshot(
tmp_path: Path,
) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
database = home / "state" / "sessions.db"
origin = tmp_path / "origin.db"
connection = sqlite3.connect(origin)
try:
assert connection.execute("PRAGMA journal_mode=WAL").fetchone()[0] == "wal"
connection.execute("PRAGMA wal_autocheckpoint=0")
connection.execute("CREATE TABLE synthetic_sessions (id TEXT PRIMARY KEY)")
connection.execute("INSERT INTO synthetic_sessions VALUES ('session-1')")
connection.commit()
origin_wal = origin.with_name(f"{origin.name}-wal")
assert origin_wal.is_file()
shutil.copyfile(origin, database)
shutil.copyfile(origin_wal, database.with_name(f"{database.name}-wal"))
finally:
connection.close()
source_shm = database.with_name(f"{database.name}-shm")
assert not source_shm.exists()
before = {
entry.name: (entry.read_bytes(), entry.stat().st_mode, entry.stat().st_mtime_ns)
for entry in (database, database.with_name(f"{database.name}-wal"))
}
state_before = (home / "state").stat()
report = inspect_profile(home, profile_kind="desktop-primary")
state_after = (home / "state").stat()
after = {
entry.name: (entry.read_bytes(), entry.stat().st_mode, entry.stat().st_mtime_ns)
for entry in (database, database.with_name(f"{database.name}-wal"))
}
assert report.outcome == "ready"
assert before == after
assert state_before.st_mtime_ns == state_after.st_mtime_ns
assert not source_shm.exists(), "inspection must not create SQLite coordination files"
def test_database_snapshot_preserves_binary_sqlite_bytes(tmp_path: Path) -> None:
import opensquilla.recovery.engine as recovery_engine
source = tmp_path / "source.db"
destination = tmp_path / "snapshot.db"
payload = b"before\r\ncontrol-z:\x1a\nafter"
with sqlite3.connect(source) as connection:
connection.execute("CREATE TABLE payloads (value BLOB NOT NULL)")
connection.execute("INSERT INTO payloads VALUES (?)", (payload,))
source_bytes = source.read_bytes()
assert payload in source_bytes
snapshot = recovery_engine._copy_source_file_no_follow(source, destination)
assert destination.read_bytes() == source_bytes
assert recovery_engine._source_snapshot_is_current(snapshot) is True
with sqlite3.connect(f"file:{destination}?mode=ro", uri=True) as connection:
assert connection.execute("PRAGMA quick_check").fetchone() == ("ok",)
assert connection.execute("SELECT value FROM payloads").fetchone() == (payload,)
def test_database_snapshot_requests_binary_mode_for_every_crt_descriptor(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
import opensquilla.recovery.engine as recovery_engine
source = tmp_path / "source.db"
destination = tmp_path / "snapshot.db"
source.write_bytes(b"binary\r\ncontrol-z:\x1a\n")
real_open = os.open
native_binary = int(getattr(os, "O_BINARY", 0))
sentinel_binary = 1 << 30
opened: list[tuple[Path, int]] = []
def tracked_open(
path: str | bytes | os.PathLike[str] | os.PathLike[bytes],
flags: int,
mode: int = 0o777,
*,
dir_fd: int | None = None,
) -> int:
opened.append((Path(path), flags))
native_flags = (flags & ~sentinel_binary) | native_binary
return real_open(path, native_flags, mode, dir_fd=dir_fd)
monkeypatch.setattr(recovery_engine.os, "O_BINARY", sentinel_binary, raising=False)
monkeypatch.setattr(recovery_engine.os, "open", tracked_open)
snapshot = recovery_engine._copy_source_file_no_follow(source, destination)
assert recovery_engine._source_snapshot_is_current(snapshot) is True
assert [path for path, _flags in opened] == [source, destination, source]
assert all(flags & sentinel_binary for _path, flags in opened)
def test_database_snapshot_source_change_fails_closed_without_mutating_source(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
import opensquilla.recovery.engine as recovery_engine
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
database = home / "state" / "sessions.db"
with sqlite3.connect(database) as connection:
connection.execute("CREATE TABLE synthetic_sessions (id TEXT PRIMARY KEY)")
before = database.read_bytes()
monkeypatch.setattr(recovery_engine, "_source_snapshot_is_current", lambda _snapshot: False)
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == "state_database_changed"
assert database.read_bytes() == before
def test_database_wal_symlink_is_never_followed(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
database = home / "state" / "sessions.db"
with sqlite3.connect(database) as connection:
connection.execute("CREATE TABLE synthetic_sessions (id TEXT PRIMARY KEY)")
outside = tmp_path / "outside-wal"
outside.write_bytes(b"synthetic outside bytes")
wal = database.with_name(f"{database.name}-wal")
try:
wal.symlink_to(outside)
except OSError:
pytest.skip("symlink creation is unavailable")
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == "state_database_unsafe_path"
assert outside.read_bytes() == b"synthetic outside bytes"
@pytest.mark.parametrize("unsafe_state", ["future-config", "transaction-incomplete"])
def test_workspace_choice_is_blocked_when_config_mutation_is_not_safe(
tmp_path: Path,
unsafe_state: str,
) -> None:
home = tmp_path / "opensquilla"
selected = _workspace(tmp_path / "selected")
_workspace(home / "workspace")
extra = "config_version = 999" if unsafe_state == "future-config" else ""
_desktop_config(home, extra=extra)
if unsafe_state == "transaction-incomplete":
(tmp_path / ".opensquilla.profile-replace.json").write_text(
'{"schema_version":1,"phase":"prepared"}\n',
encoding="utf-8",
)
config_before = (home / "config.toml").read_bytes()
report = inspect_profile(home)
assert report.outcome == "recovery_required"
assert "choose-workspace" not in report.allowed_actions
with pytest.raises(InvalidWorkspaceError):
choose_workspace(
home,
transaction_id=report.transaction_id,
expected_revision=report.revision,
workspace=selected,
)
assert (home / "config.toml").read_bytes() == config_before
def test_workspace_choice_never_follows_unsafe_profile_home(tmp_path: Path) -> None:
real_home = tmp_path / "real-home"
selected = _workspace(tmp_path / "selected")
_workspace(real_home / "workspace")
_desktop_config(real_home)
linked_home = tmp_path / "linked-home"
try:
linked_home.symlink_to(real_home, target_is_directory=True)
except OSError:
pytest.skip("symlink creation is unavailable")
config_before = (real_home / "config.toml").read_bytes()
report = inspect_profile(linked_home)
assert report.stable_code == "profile_unsafe_path"
assert "choose-workspace" not in report.allowed_actions
with pytest.raises(InvalidWorkspaceError):
choose_workspace(
linked_home,
transaction_id=report.transaction_id,
expected_revision=report.revision,
workspace=selected,
)
assert (real_home / "config.toml").read_bytes() == config_before
@pytest.mark.parametrize(
("config", "stable_code"),
[
(
'workspace_dir = "unterminated\n',
"config_invalid",
),
("config_version = 999\n", "config_schema_too_new"),
],
)
def test_invalid_or_future_config_requires_recovery(
tmp_path: Path,
config: str,
stable_code: str,
) -> None:
home = tmp_path / "opensquilla"
home.mkdir()
(home / "config.toml").write_text(config, encoding="utf-8")
report = inspect_profile(home)
assert report.outcome == "recovery_required"
assert report.stable_code == stable_code
def test_replacement_journal_symlink_is_never_followed(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
_workspace(home / "workspace")
_desktop_config(home)
outside = tmp_path / "outside-journal.json"
outside.write_text('{"phase":"committed"}\n', encoding="utf-8")
journal = home.parent / f".{home.name}.profile-replace.json"
try:
journal.symlink_to(outside)
except OSError:
pytest.skip("symlink creation is unavailable")
report = inspect_profile(home)
assert report.outcome == "recovery_required"
assert report.stable_code == "transaction_incomplete"
assert outside.read_text(encoding="utf-8") == '{"phase":"committed"}\n'
def test_legacy_import_journal_blocks_without_automatic_mutation(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
workspace = _workspace(home / "workspace", "preserved identity")
_desktop_config(home, workspace=workspace)
journal = home.parent / f".{home.name}.import-commit.json"
journal.write_text(
json.dumps(
{
"phase": "target-backed-up",
"target": str(home),
"backup": str(tmp_path / "opensquilla.backup.synthetic"),
"staging": str(tmp_path / ".opensquilla-import-synthetic"),
},
sort_keys=True,
)
+ "\n",
encoding="utf-8",
)
config_before = (home / "config.toml").read_bytes()
identity_before = (workspace / "SOUL.md").read_bytes()
journal_before = journal.read_bytes()
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == "legacy_import_transaction_incomplete"
assert "recover-transaction" not in report.allowed_actions
assert (home / "config.toml").read_bytes() == config_before
assert (workspace / "SOUL.md").read_bytes() == identity_before
assert journal.read_bytes() == journal_before
def test_legacy_import_journal_prevents_missing_target_from_looking_fresh(
tmp_path: Path,
) -> None:
home = tmp_path / "opensquilla"
journal = home.parent / f".{home.name}.import-commit.json"
journal.write_text('{"phase":"target-backed-up"}\n', encoding="utf-8")
before = journal.read_bytes()
report = inspect_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == "legacy_import_transaction_incomplete"
assert not home.exists()
assert journal.read_bytes() == before
@pytest.mark.parametrize("as_file", [False, True])
def test_profile_root_link_or_special_path_fails_closed(
tmp_path: Path,
as_file: bool,
) -> None:
profile = tmp_path / "opensquilla"
if as_file:
profile.write_text("not a profile directory\n", encoding="utf-8")
else:
real = tmp_path / "real-profile"
_workspace(real / "workspace")
_desktop_config(real)
try:
profile.symlink_to(real, target_is_directory=True)
except OSError:
pytest.skip("symlink creation is unavailable")
report = inspect_profile(profile)
assert report.outcome == "recovery_required"
assert report.stable_code == "profile_unsafe_path"
assert report.candidates == ()
def test_choose_workspace_preserves_comments_unknown_keys_and_nested_key(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
legacy = _workspace(home / "state" / "workspace")
selected = _workspace(tmp_path / "selected")
_desktop_config(
home,
workspace=legacy,
extra='unknown_future = "keep"\n\n[agent]\nworkspace_dir = "nested-keep"',
)
config_path = home / "config.toml"
original = config_path.read_text(encoding="utf-8")
config_path.write_text("# owner comment\n" + original, encoding="utf-8")
config_path.chmod(0o640)
before = inspect_profile(home)
after = choose_workspace(
home,
transaction_id=before.transaction_id,
expected_revision=before.revision,
workspace=selected,
)
patched = config_path.read_text(encoding="utf-8")
assert after.effective_workspace == selected
assert "# owner comment" in patched
assert 'unknown_future = "keep"' in patched
assert 'workspace_dir = "nested-keep"' in patched
if os.name != "nt":
assert config_path.stat().st_mode & 0o777 == 0o640
backups = list(home.glob("config.toml.backup.*"))
assert len(backups) == 1
if os.name != "nt":
assert backups[0].stat().st_mode & 0o777 == 0o600
def test_choose_workspace_never_changes_chat_database_bytes_or_identity(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
legacy = _workspace(home / "state" / "workspace")
selected = _workspace(tmp_path / "selected")
_desktop_config(home, workspace=legacy)
database = home / "state" / "sessions.db"
with sqlite3.connect(database) as connection:
connection.execute(
"CREATE TABLE synthetic_chat (id TEXT PRIMARY KEY, transcript TEXT NOT NULL)"
)
connection.execute(
"INSERT INTO synthetic_chat VALUES (?, ?)",
("session-before-workspace-choice", "synthetic transcript stays in state"),
)
before_identity = (database.stat().st_dev, database.stat().st_ino)
before_bytes = database.read_bytes()
inspected = inspect_profile(home)
result = choose_workspace(
home,
transaction_id=inspected.transaction_id,
expected_revision=inspected.revision,
workspace=selected,
)
assert result.effective_workspace == selected
assert (database.stat().st_dev, database.stat().st_ino) == before_identity
assert database.read_bytes() == before_bytes
with sqlite3.connect(f"file:{database}?mode=ro", uri=True) as connection:
assert connection.execute("SELECT id, transcript FROM synthetic_chat").fetchone() == (
"session-before-workspace-choice",
"synthetic transcript stays in state",
)
@pytest.mark.skipif(not hasattr(os, "setxattr"), reason="filesystem xattrs are unavailable")
def test_choose_workspace_preserves_config_extended_attributes(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
legacy = _workspace(home / "state" / "workspace")
selected = _workspace(tmp_path / "selected")
_desktop_config(home, workspace=legacy)
config_path = home / "config.toml"
attribute = "com.opensquilla.synthetic" if sys.platform == "darwin" else "user.opensquilla"
try:
os.setxattr(config_path, attribute, b"preserve", follow_symlinks=False)
except OSError as exc:
pytest.skip(f"test filesystem does not support user xattrs: {exc}")
before = inspect_profile(home)
choose_workspace(
home,
transaction_id=before.transaction_id,
expected_revision=before.revision,
workspace=selected,
)
assert os.getxattr(config_path, attribute, follow_symlinks=False) == b"preserve"
@pytest.mark.skipif(sys.platform != "darwin", reason="macOS ACL regression")
def test_choose_workspace_preserves_macos_config_acl(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
legacy = _workspace(home / "state" / "workspace")
selected = _workspace(tmp_path / "selected")
_desktop_config(home, workspace=legacy)
config_path = home / "config.toml"
subprocess.run(
["chmod", "+a", "everyone allow read", str(config_path)],
check=True,
capture_output=True,
text=True,
)
def acl_lines() -> list[str]:
output = subprocess.run(
["ls", "-led", str(config_path)],
check=True,
capture_output=True,
text=True,
).stdout.splitlines()
return [line.strip() for line in output[1:] if line.strip()]
acl_before = acl_lines()
assert acl_before
before = inspect_profile(home)
choose_workspace(
home,
transaction_id=before.transaction_id,
expected_revision=before.revision,
workspace=selected,
)
assert acl_lines() == acl_before
@pytest.mark.skipif(os.name != "nt", reason="Windows DACL regression")
def test_choose_workspace_preserves_windows_config_dacl(tmp_path: Path) -> None:
from opensquilla.recovery.atomic import _windows_extended_path
home = tmp_path / "opensquilla"
legacy = _workspace(home / "state" / "workspace")
selected = _workspace(tmp_path / "selected")
_desktop_config(home, workspace=legacy)
config_path = home / "config.toml"
subprocess.run(
["icacls", str(config_path), "/inheritance:d"],
check=True,
capture_output=True,
text=True,
)
advapi32 = ctypes.WinDLL("advapi32", use_last_error=True)
get_file_security = advapi32.GetFileSecurityW
get_file_security.argtypes = [
ctypes.c_wchar_p,
ctypes.c_uint32,
ctypes.c_void_p,
ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint32),
]
get_file_security.restype = ctypes.c_int
def dacl_semantics() -> tuple[int, bytes]:
required = ctypes.c_uint32()
get_file_security(
_windows_extended_path(config_path),
0x00000004,
None,
0,
ctypes.byref(required),
)
assert required.value > 0
buffer = ctypes.create_string_buffer(required.value)
assert get_file_security(
_windows_extended_path(config_path),
0x00000004,
buffer,
required.value,
ctypes.byref(required),
)
descriptor = bytes(buffer.raw[: required.value])
control = int.from_bytes(descriptor[2:4], "little")
dacl_offset = int.from_bytes(descriptor[16:20], "little")
# Windows can normalize the AUTO_INHERITED bookkeeping bit when the
# same DACL is attached to a new file. Preserve and compare the access
# entries plus the flags that determine DACL presence/defaulting and
# whether future inheritance is blocked.
access_control_flags = control & 0x100C
dacl = descriptor[dacl_offset:] if dacl_offset else b""
return access_control_flags, dacl
dacl_before = dacl_semantics()
before = inspect_profile(home)
choose_workspace(
home,
transaction_id=before.transaction_id,
expected_revision=before.revision,
workspace=selected,
)
assert dacl_semantics() == dacl_before
def test_workspace_env_override_blocks_config_patch(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
home = tmp_path / "opensquilla"
configured = _workspace(tmp_path / "configured")
selected = _workspace(tmp_path / "selected")
_desktop_config(home, workspace=configured)
original = (home / "config.toml").read_bytes()
monkeypatch.setenv("OPENSQUILLA_GATEWAY_WORKSPACE_DIR", str(configured))
before = inspect_profile(home)
with pytest.raises(WorkspaceOverrideError):
choose_workspace(
home,
transaction_id=before.transaction_id,
expected_revision=before.revision,
workspace=selected,
)
assert (home / "config.toml").read_bytes() == original
def test_config_publication_preserves_a_mutation_in_the_final_cas_window(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
import opensquilla.recovery.config_patch as config_patch
home = tmp_path / "opensquilla"
configured = _workspace(tmp_path / "configured")
selected = _workspace(tmp_path / "selected")
_desktop_config(home, workspace=configured)
before = inspect_profile(home)
config = home / "config.toml"
original_move = config_patch.native_move_no_replace
concurrent_text = config.read_text(encoding="utf-8") + "external_edit = true\n"
def mutate_during_park(source: Path, destination: Path) -> None:
if source == config and destination.name.startswith("config.toml.backup."):
source.write_text(concurrent_text, encoding="utf-8")
original_move(source, destination)
monkeypatch.setattr(config_patch, "native_move_no_replace", mutate_during_park)
with pytest.raises(AtomicStateUnknownError):
choose_workspace(
home,
transaction_id=before.transaction_id,
expected_revision=before.revision,
workspace=selected,
)
journal = config_patch.workspace_patch_journal(home)
payload = json.loads(journal.read_text(encoding="utf-8"))
backup = Path(payload["paths"]["backup"])
staged = Path(payload["paths"]["staged"])
assert not config.exists()
assert backup.read_text(encoding="utf-8") == concurrent_text
assert staged.is_file()
blocked = inspect_profile(home)
assert blocked.outcome == "recovery_required"
assert blocked.stable_code == "workspace_patch_incomplete"
with pytest.raises(AtomicStateUnknownError):
reconcile_profile(home)
assert backup.read_text(encoding="utf-8") == concurrent_text
assert staged.is_file()
def test_crashed_workspace_config_park_is_recovered_without_overwrite(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
import opensquilla.recovery.config_patch as config_patch
class SimulatedCrash(BaseException):
pass
home = tmp_path / "opensquilla"
configured = _workspace(tmp_path / "configured")
selected = _workspace(tmp_path / "selected")
_desktop_config(home, workspace=configured)
config = home / "config.toml"
old_text = config.read_text(encoding="utf-8")
before = inspect_profile(home)
original_move = config_patch.native_move_no_replace
crashed = False
def crash_after_config_park(source: Path, destination: Path) -> None:
nonlocal crashed
original_move(source, destination)
if source == config and destination.name.startswith("config.toml.backup."):
crashed = True
raise SimulatedCrash
monkeypatch.setattr(config_patch, "native_move_no_replace", crash_after_config_park)
with pytest.raises(SimulatedCrash):
choose_workspace(
home,
transaction_id=before.transaction_id,
expected_revision=before.revision,
workspace=selected,
)
assert crashed
blocked = inspect_profile(home)
assert blocked.outcome == "recovery_required"
assert blocked.stable_code == "workspace_patch_incomplete"
recovered = reconcile_profile(home)
assert recovered.outcome == "ready"
assert recovered.effective_workspace == selected
assert tomllib.loads(config.read_text(encoding="utf-8"))["workspace_dir"] == str(selected)
backups = list(home.glob("config.toml.backup.*"))
assert len(backups) == 1
assert backups[0].read_text(encoding="utf-8") == old_text
if os.name != "nt":
assert backups[0].stat().st_mode & 0o777 == 0o600
assert not config_patch.workspace_patch_journal(home).exists()
def test_bootstrap_guard_is_desktop_only(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
_desktop_config(home, workspace=tmp_path / "missing")
monkeypatch.delenv("OPENSQUILLA_PROFILE_KIND", raising=False)
monkeypatch.delenv("OPENSQUILLA_DESKTOP", raising=False)
assert guard_desktop_profile(home) is None
monkeypatch.setenv("OPENSQUILLA_PROFILE_KIND", "desktop-primary")
with pytest.raises(RecoveryRequiredError) as caught:
guard_desktop_profile(home)
assert caught.value.report.stable_code == "effective_workspace_missing"
def test_legacy_profile_dotenv_pin_prevents_workspace_move(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
legacy = _workspace(home / "state" / "workspace", "legacy identity")
_desktop_config(home)
legacy_env = home / "state" / ".env"
legacy_env.write_text(
f"OPENSQUILLA_GATEWAY_WORKSPACE_DIR={legacy}\n",
encoding="utf-8",
)
before = inspect_profile(home, profile_kind="desktop-primary")
assert before.effective_workspace == legacy
assert before.outcome == "recovery_required"
after = reconcile_profile(home, profile_kind="desktop-primary")
assert after.outcome == "attention"
assert after.stable_code == "legacy_workspace_pinned"
assert after.effective_workspace == legacy
assert legacy.is_dir()
assert not (home / "workspace").exists()
assert not legacy_env.exists()
assert (home / ".env").read_text(encoding="utf-8").endswith(f"={legacy}\n")
def test_interpolated_profile_dotenv_override_fails_closed(tmp_path: Path) -> None:
home = tmp_path / "opensquilla"
legacy = _workspace(home / "state" / "workspace")
_desktop_config(home)
legacy_env = home / "state" / ".env"
legacy_env.write_text(
"OPENSQUILLA_GATEWAY_WORKSPACE_DIR=${UNSAFE_DYNAMIC_ROOT}/workspace\n",
encoding="utf-8",
)
report = reconcile_profile(home, profile_kind="desktop-primary")
assert report.outcome == "recovery_required"
assert report.stable_code == "workspace_env_override_unsafe"
assert legacy.is_dir()
assert legacy_env.is_file()
assert not (home / "workspace").exists()
assert not (home / ".env").exists()