Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/architecture/rfcs/complete-state-recovery-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,7 @@ Those measurements are historical evidence, not measurements of a later merge.
| Existing transport limits: 64 MiB private snapshot only for the two manifest checks; normal RPC and worker input 2 MiB; owner stdout 2 Mi characters; saved-audit input 16 MiB | Bound exchanges and historical report decoding without widening ordinary transport | Large-manifest transport and audit-integrity tests cover the path. These independent limits are not additive capacity or proof that every maximum-size audit is publishable. |
| Free destination space at least copied regular-file bytes plus 16 MiB before copying | Refuse a known-insufficient destination before publication | Source check plus failure-cleanup tests; concurrent disk consumption and a successful worst-case space reservation are not guaranteed. |

Source owners: [`state_recovery.py`](../../../loopx/state_recovery.py),
Source owners: [`state_recovery_io.py`](../../../loopx/control_plane/state_recovery_io.py),
[`state_recovery.ts`](../../../loopx/control_plane/state_recovery.ts), and
[`state_recovery_worker.ts`](../../../loopx/control_plane/state_recovery_worker.ts).
Existing [Python recovery cases](../../../tests/test_state_recovery.py) and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ provider、捕获一致性、身份接纳或 M2/M3 重新启用。同条评论
| 既有 transport:仅两项清单检查用 64 MiB private snapshot;普通 RPC 和 worker 输入 2 MiB;owner stdout 2 Mi 字符;历史 audit 输入 16 MiB | 限制传输和历史报告解码,不扩大普通 transport | 大清单 transport 与 audit 完整性测试覆盖路径。独立上限不能相加,也不保证任意最大 audit 均可发布。 |
| 复制前目标剩余空间至少为普通文件复制字节数加 16 MiB | 发布前拒绝已知空间不足 | 有源码检查和失败清理测试;不保证抵御并发磁盘消耗,也不证明最坏空间预留成功。 |

源码 owner 为 [`state_recovery.py`](../../../loopx/state_recovery.py)、
源码 owner 为 [`state_recovery_io.py`](../../../loopx/control_plane/state_recovery_io.py)、
[`state_recovery.ts`](../../../loopx/control_plane/state_recovery.ts) 和
[`state_recovery_worker.ts`](../../../loopx/control_plane/state_recovery_worker.ts)。
既有 [Python 恢复用例](../../../tests/test_state_recovery.py)及
Expand Down
2 changes: 1 addition & 1 deletion examples/semantic-vocabulary-drift-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@
# silently; that is the gap the anchor exists to close.
COVERAGE_ANCHOR = {
"vocabularies": 28,
"owner_symbols": 53,
"owner_symbols": 54,
"literal_scan_fields": 1,
"projections": 1,
"relations": 9,
Expand Down
2 changes: 1 addition & 1 deletion loopx/cli_commands/support_control_backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def handle_backup_state_command(
output_format: FormatSelector,
) -> int:
if getattr(args, "backup_action", None) == "verify":
from ..state_recovery import StateRecoveryError, render_state_recovery_markdown, verify_state_backup
from ..control_plane.state_recovery_io import StateRecoveryError, render_state_recovery_markdown, verify_state_backup

try:
if not all(getattr(args, key, None) for key in ("archive", "manifest", "destination")):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import zlib
from typing import Any, BinaryIO, Iterator, NoReturn

from .control_plane.effect_runtime import _node_executable, effect_runtime_result, effect_runtime_request_scope
from .effect_runtime import _node_executable, effect_runtime_result, effect_runtime_request_scope

MAX_ARCHIVE_BYTES = 128 * 1024 * 1024
MAX_EXPANDED_BYTES = 512 * 1024 * 1024
Expand Down Expand Up @@ -87,7 +87,7 @@ def _runtime(method: str, request: dict[str, Any]) -> dict[str, Any]:
def _audit_owners(request: dict[str, Any]) -> dict[str, Any]:
command = [_node_executable(), "--no-warnings", "--max-old-space-size=512",
"--experimental-sqlite", "--experimental-strip-types",
str(Path(__file__).parent / "control_plane/state_recovery_worker.ts")]
str(Path(__file__).with_name("state_recovery_worker.ts"))]
try:
completed = subprocess.run(command, input=json.dumps(request), text=True, encoding="utf-8",
capture_output=True, timeout=_OWNER_TIMEOUT_SECONDS, check=False)
Expand Down
2 changes: 1 addition & 1 deletion loopx/presentation/state_recovery_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import time
from uuid import uuid4

from ..state_recovery import (
from ..control_plane.state_recovery_io import (
MAX_ARCHIVE_BYTES, MAX_MANIFEST_BYTES, StateRecoveryError,
read_state_recovery_audit, verify_state_backup,
)
Expand Down
2 changes: 1 addition & 1 deletion loopx/semantics/vocabulary_v0.json
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@
},
"coverage_floor": {
"vocabularies": 28,
"owner_symbols": 53,
"owner_symbols": 54,
"literal_scan_fields": 1,
"projections": 1,
"relations": 9,
Expand Down
2 changes: 1 addition & 1 deletion tests/architecture/test_semantic_vocabulary_drift.py
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,7 @@ def test_native_lifecycle_relation_keeps_the_live_owner_and_verification_boundar
smoke = runpy.run_path(str(SMOKE))
registry = smoke['load_registry']()
assert registry['coverage_floor']['vocabularies'] == 28
assert registry['coverage_floor']['owner_symbols'] == 53
assert registry['coverage_floor']['owner_symbols'] == 54
assert registry['coverage_floor']['relations'] == 9
relation = next(row for row in registry['relations']['subsets']
if row['name'] == 'task_lease_lifecycle_decision_operation')
Expand Down
14 changes: 7 additions & 7 deletions tests/test_state_recovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import pytest

from loopx.state_backup import build_state_backup_plan, execute_state_backup_plan
from loopx.state_recovery import StateRecoveryError, read_state_recovery_audit, render_state_recovery_markdown, verify_state_backup
from loopx.control_plane.state_recovery_io import StateRecoveryError, read_state_recovery_audit, render_state_recovery_markdown, verify_state_backup
from tests.control_plane.canonical_authority_fixture import promoted_create_fixture


Expand Down Expand Up @@ -133,7 +133,7 @@ def test_valid_internal_symlink_stays_inert_and_chained_escape_is_refused(tmp_pa


def test_capacity_and_private_input_fail_before_publication(tmp_path, monkeypatch):
import loopx.state_recovery as recovery
import loopx.control_plane.state_recovery_io as recovery

archive, manifest = _backup(tmp_path)
original = archive.stat().st_mode
Expand Down Expand Up @@ -185,7 +185,7 @@ def test_missing_selected_storage_is_unknown_without_creation_or_fallback(tmp_pa
archive, manifest = _backup(tmp_path, provider)
destination = tmp_path / "inert"
original = verify_state_backup(archive=archive, manifest=manifest, destination=destination, execute=True)
from loopx.state_recovery import _audit_owners
from loopx.control_plane.state_recovery_io import _audit_owners

selected = destination / "data/runtime-root/authority" / f"{provider}-v0"
sqlite_files = [path.relative_to(destination / "data").as_posix() for path in selected.glob("*.sqlite")]
Expand Down Expand Up @@ -244,7 +244,7 @@ def test_sqlite_views_are_never_evaluated_as_authority_tables(tmp_path):


def test_offline_worker_timeout_does_not_leave_a_copy_or_stop_shared_runtime(tmp_path, monkeypatch):
import loopx.state_recovery as recovery
import loopx.control_plane.state_recovery_io as recovery
from loopx.control_plane.effect_runtime import effect_runtime_result

archive, manifest = _backup(tmp_path)
Expand Down Expand Up @@ -378,7 +378,7 @@ def unexpected_decode(*_args):

@pytest.mark.parametrize("kind", [tarfile.XHDTYPE, tarfile.XGLTYPE, tarfile.SOLARIS_XHDTYPE])
def test_oversized_pax_variants_are_refused_without_reading_the_body(kind):
from loopx.state_recovery import _scan
from loopx.control_plane.state_recovery_io import _scan

member = tarfile.TarInfo("oversized-pax")
member.type, member.size = kind, 128 * 1024 + 1
Expand All @@ -388,7 +388,7 @@ def test_oversized_pax_variants_are_refused_without_reading_the_body(kind):


def test_malformed_pax_record_length_is_a_bounded_archive_error():
from loopx.state_recovery import _scan
from loopx.control_plane.state_recovery_io import _scan

payload = b"9" * 5000 + b" comment=invalid\n"
member = tarfile.TarInfo("malformed-pax")
Expand All @@ -400,7 +400,7 @@ def test_malformed_pax_record_length_is_a_bounded_archive_error():


def test_failed_publication_cleans_staging_even_when_destination_becomes_occupied(tmp_path, monkeypatch):
import loopx.state_recovery as recovery
import loopx.control_plane.state_recovery_io as recovery

archive, manifest = _backup(tmp_path)
destination = tmp_path / "inert"
Expand Down
Loading